mirror of
https://github.com/documenso/documenso.git
synced 2025-11-10 12:32:34 +10:00
Compare commits
15 Commits
v1.8.1-rc.
...
v1.8.1-rc.
| Author | SHA1 | Date | |
|---|---|---|---|
| b3ccb3d26f | |||
| b17370c153 | |||
| 0c53f5b061 | |||
| ed6157de80 | |||
| 5e08d0cffb | |||
| 5565aff7a3 | |||
| 428acf4ac3 | |||
| f4b1e5104e | |||
| a687064a42 | |||
| 8ec69388a5 | |||
| f3da11b3e7 | |||
| fc84ee8ec2 | |||
| 4282a96ee7 | |||
| 2aae7435f8 | |||
| bdd33bd335 |
@ -500,8 +500,35 @@ Now you can make a `POST` request to the `/api/v1/documents/{documentId}/fields`
|
|||||||
value, this is the value that will be used to sign the field.
|
value, this is the value that will be used to sign the field.
|
||||||
</Callout>
|
</Callout>
|
||||||
|
|
||||||
|
<Callout type="warning">
|
||||||
|
It's important to pass the `type` in the `fieldMeta` property for the advanced fields. [Read more
|
||||||
|
here](#a-note-on-advanced-fields)
|
||||||
|
</Callout>
|
||||||
|
|
||||||
A successful request will return a JSON response with the newly added fields. The image below illustrates the fields added to the document via the API.
|
A successful request will return a JSON response with the newly added fields. The image below illustrates the fields added to the document via the API.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
</Steps>
|
</Steps>
|
||||||
|
|
||||||
|
#### A Note on Advanced Fields
|
||||||
|
|
||||||
|
The advanced fields are: text, checkbox, radio, number, and select. Whenever you append any of these advanced fields to a document, you need to pass the `type` in the `fieldMeta` property:
|
||||||
|
|
||||||
|
```json
|
||||||
|
...
|
||||||
|
"fieldMeta": {
|
||||||
|
"type": "text",
|
||||||
|
}
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
Replace the `text` value with the corresponding field type:
|
||||||
|
|
||||||
|
- For the `TEXT` field it should be `text`.
|
||||||
|
- For the `CHECKBOX` field it should be `checkbox`.
|
||||||
|
- For the `RADIO` field it should be `radio`.
|
||||||
|
- For the `NUMBER` field it should be `number`.
|
||||||
|
- For the `SELECT` field it should be `select`. (check this before merge)
|
||||||
|
|
||||||
|
You must pass this property at all times, even if you don't need to set any other properties. If you don't, the endpoint will throw an error.
|
||||||
|
|||||||
@ -20,6 +20,7 @@ Documenso supports Webhooks and allows you to subscribe to the following events:
|
|||||||
- `document.opened`
|
- `document.opened`
|
||||||
- `document.signed`
|
- `document.signed`
|
||||||
- `document.completed`
|
- `document.completed`
|
||||||
|
- `document.rejected`
|
||||||
|
|
||||||
## Create a webhook subscription
|
## Create a webhook subscription
|
||||||
|
|
||||||
@ -36,7 +37,7 @@ Clicking on the "**Create Webhook**" button opens a modal to create a new webhoo
|
|||||||
To create a new webhook subscription, you need to provide the following information:
|
To create a new webhook subscription, you need to provide the following information:
|
||||||
|
|
||||||
- Enter the webhook URL that will receive the event payload.
|
- Enter the webhook URL that will receive the event payload.
|
||||||
- Select the event(s) you want to subscribe to: `document.created`, `document.sent`, `document.opened`, `document.signed`, `document.completed`.
|
- Select the event(s) you want to subscribe to: `document.created`, `document.sent`, `document.opened`, `document.signed`, `document.completed`, `document.rejected`.
|
||||||
- Optionally, you can provide a secret key that will be used to sign the payload. This key will be included in the `X-Documenso-Secret` header of the request.
|
- Optionally, you can provide a secret key that will be used to sign the payload. This key will be included in the `X-Documenso-Secret` header of the request.
|
||||||
|
|
||||||

|

|
||||||
@ -53,45 +54,55 @@ You can edit or delete your webhook subscriptions by clicking the "**Edit**" or
|
|||||||
|
|
||||||
The payload sent to the webhook URL contains the following fields:
|
The payload sent to the webhook URL contains the following fields:
|
||||||
|
|
||||||
| Field | Type | Description |
|
| Field | Type | Description |
|
||||||
| -------------------------------------------- | --------- | ---------------------------------------------------- |
|
| -------------------------------------------- | --------- | ----------------------------------------------------- |
|
||||||
| `event` | string | The type of event that triggered the webhook. |
|
| `event` | string | The type of event that triggered the webhook. |
|
||||||
| `payload.id` | number | The id of the document. |
|
| `payload.id` | number | The id of the document. |
|
||||||
| `payload.userId` | number | The id of the user who owns the document. |
|
| `payload.externalId` | string? | External identifier for the document. |
|
||||||
| `payload.authOptions` | json? | Authentication options for the document. |
|
| `payload.userId` | number | The id of the user who owns the document. |
|
||||||
| `payload.formValues` | json? | Form values for the document. |
|
| `payload.authOptions` | json? | Authentication options for the document. |
|
||||||
| `payload.title` | string | The name of the document. |
|
| `payload.formValues` | json? | Form values for the document. |
|
||||||
| `payload.status` | string | The current status of the document. |
|
| `payload.visibility` | string | Document visibility (e.g., EVERYONE). |
|
||||||
| `payload.documentDataId` | string | The identifier for the document data. |
|
| `payload.title` | string | The title of the document. |
|
||||||
| `payload.createdAt` | datetime | The creation date and time of the document. |
|
| `payload.status` | string | The current status of the document. |
|
||||||
| `payload.updatedAt` | datetime | The last update date and time of the document. |
|
| `payload.documentDataId` | string | The identifier for the document data. |
|
||||||
| `payload.completedAt` | datetime? | The completion date and time of the document. |
|
| `payload.createdAt` | datetime | The creation date and time of the document. |
|
||||||
| `payload.deletedAt` | datetime? | The deletion date and time of the document. |
|
| `payload.updatedAt` | datetime | The last update date and time of the document. |
|
||||||
| `payload.teamId` | number? | The id of the team. |
|
| `payload.completedAt` | datetime? | The completion date and time of the document. |
|
||||||
| `payload.documentData.id` | string | The id of the document data. |
|
| `payload.deletedAt` | datetime? | The deletion date and time of the document. |
|
||||||
| `payload.documentData.type` | string | The type of the document data. |
|
| `payload.teamId` | number? | The id of the team if document belongs to a team. |
|
||||||
| `payload.documentData.data` | string | The data of the document. |
|
| `payload.templateId` | number? | The id of the template if created from template. |
|
||||||
| `payload.documentData.initialData` | string | The initial data of the document. |
|
| `payload.source` | string | The source of the document (e.g., DOCUMENT, TEMPLATE) |
|
||||||
| `payload.Recipient[].id` | number | The id of the recipient. |
|
| `payload.documentMeta.id` | string | The id of the document metadata. |
|
||||||
| `payload.Recipient[].documentId` | number? | The id the document associated with the recipient. |
|
| `payload.documentMeta.subject` | string? | The subject of the document. |
|
||||||
| `payload.Recipient[].templateId` | number? | The template identifier for the recipient. |
|
| `payload.documentMeta.message` | string? | The message associated with the document. |
|
||||||
| `payload.Recipient[].email` | string | The email address of the recipient. |
|
| `payload.documentMeta.timezone` | string | The timezone setting for the document. |
|
||||||
| `payload.Recipient[].name` | string | The name of the recipient. |
|
| `payload.documentMeta.password` | string? | The password protection if set. |
|
||||||
| `payload.Recipient[].token` | string | The token associated with the recipient. |
|
| `payload.documentMeta.dateFormat` | string | The date format used in the document. |
|
||||||
| `payload.Recipient[].expired` | datetime? | The expiration status of the recipient. |
|
| `payload.documentMeta.redirectUrl` | string? | The URL to redirect after signing. |
|
||||||
| `payload.Recipient[].signedAt` | datetime? | The date and time the recipient signed the document. |
|
| `payload.documentMeta.signingOrder` | string | The signing order (e.g., PARALLEL, SEQUENTIAL). |
|
||||||
| `payload.Recipient[].authOptions.accessAuth` | json? | Access authentication options. |
|
| `payload.documentMeta.typedSignatureEnabled` | boolean | Whether typed signatures are enabled. |
|
||||||
| `payload.Recipient[].authOptions.actionAuth` | json? | Action authentication options. |
|
| `payload.documentMeta.language` | string | The language of the document. |
|
||||||
| `payload.Recipient[].role` | string | The role of the recipient. |
|
| `payload.documentMeta.distributionMethod` | string | The method of distributing the document. |
|
||||||
| `payload.Recipient[].readStatus` | string | The read status of the document by the recipient. |
|
| `payload.documentMeta.emailSettings` | json? | Email notification settings. |
|
||||||
| `payload.Recipient[].signingStatus` | string | The signing status of the recipient. |
|
| `payload.Recipient[].id` | number | The id of the recipient. |
|
||||||
| `payload.Recipient[].sendStatus` | string | The send status of the document to the recipient. |
|
| `payload.Recipient[].documentId` | number? | The id of the document for this recipient. |
|
||||||
| `createdAt` | datetime | The creation date and time of the webhook event. |
|
| `payload.Recipient[].templateId` | number? | The template id if from a template. |
|
||||||
| `webhookEndpoint` | string | The endpoint URL where the webhook is sent. |
|
| `payload.Recipient[].email` | string | The email address of the recipient. |
|
||||||
|
| `payload.Recipient[].name` | string | The name of the recipient. |
|
||||||
## Webhook event payload example
|
| `payload.Recipient[].token` | string | The unique token for this recipient. |
|
||||||
|
| `payload.Recipient[].documentDeletedAt` | datetime? | When the document was deleted for this recipient. |
|
||||||
When an event that you have subscribed to occurs, Documenso will send a POST request to the specified webhook URL with a payload containing information about the event.
|
| `payload.Recipient[].expired` | datetime? | When the recipient's access expired. |
|
||||||
|
| `payload.Recipient[].signedAt` | datetime? | When the recipient signed the document. |
|
||||||
|
| `payload.Recipient[].authOptions` | json? | Authentication options for this recipient. |
|
||||||
|
| `payload.Recipient[].signingOrder` | number? | The order in which this recipient should sign. |
|
||||||
|
| `payload.Recipient[].rejectionReason` | string? | The reason if the recipient rejected the document. |
|
||||||
|
| `payload.Recipient[].role` | string | The role of the recipient (e.g., SIGNER, VIEWER). |
|
||||||
|
| `payload.Recipient[].readStatus` | string | Whether the recipient has read the document. |
|
||||||
|
| `payload.Recipient[].signingStatus` | string | The signing status of this recipient. |
|
||||||
|
| `payload.Recipient[].sendStatus` | string | The sending status for this recipient. |
|
||||||
|
| `createdAt` | datetime | The creation date and time of the webhook event. |
|
||||||
|
| `webhookEndpoint` | string | The endpoint URL where the webhook is sent. |
|
||||||
|
|
||||||
## Example payloads
|
## Example payloads
|
||||||
|
|
||||||
@ -104,9 +115,11 @@ Example payload for the `document.created` event:
|
|||||||
"event": "DOCUMENT_CREATED",
|
"event": "DOCUMENT_CREATED",
|
||||||
"payload": {
|
"payload": {
|
||||||
"id": 10,
|
"id": 10,
|
||||||
|
"externalId": null,
|
||||||
"userId": 1,
|
"userId": 1,
|
||||||
"authOptions": null,
|
"authOptions": null,
|
||||||
"formValues": null,
|
"formValues": null,
|
||||||
|
"visibility": "EVERYONE",
|
||||||
"title": "documenso.pdf",
|
"title": "documenso.pdf",
|
||||||
"status": "DRAFT",
|
"status": "DRAFT",
|
||||||
"documentDataId": "hs8qz1ktr9204jn7mg6c5dxy0",
|
"documentDataId": "hs8qz1ktr9204jn7mg6c5dxy0",
|
||||||
@ -114,7 +127,43 @@ Example payload for the `document.created` event:
|
|||||||
"updatedAt": "2024-04-22T11:44:43.341Z",
|
"updatedAt": "2024-04-22T11:44:43.341Z",
|
||||||
"completedAt": null,
|
"completedAt": null,
|
||||||
"deletedAt": null,
|
"deletedAt": null,
|
||||||
"teamId": null
|
"teamId": null,
|
||||||
|
"templateId": null,
|
||||||
|
"source": "DOCUMENT",
|
||||||
|
"documentMeta": {
|
||||||
|
"id": "doc_meta_123",
|
||||||
|
"subject": "Please sign this document",
|
||||||
|
"message": "Hello, please review and sign this document.",
|
||||||
|
"timezone": "UTC",
|
||||||
|
"password": null,
|
||||||
|
"dateFormat": "MM/DD/YYYY",
|
||||||
|
"redirectUrl": null,
|
||||||
|
"signingOrder": "PARALLEL",
|
||||||
|
"typedSignatureEnabled": true,
|
||||||
|
"language": "en",
|
||||||
|
"distributionMethod": "EMAIL",
|
||||||
|
"emailSettings": null
|
||||||
|
},
|
||||||
|
"Recipient": [
|
||||||
|
{
|
||||||
|
"id": 52,
|
||||||
|
"documentId": 10,
|
||||||
|
"templateId": null,
|
||||||
|
"email": "signer@documenso.com",
|
||||||
|
"name": "John Doe",
|
||||||
|
"token": "vbT8hi3jKQmrFP_LN1WcS",
|
||||||
|
"documentDeletedAt": null,
|
||||||
|
"expired": null,
|
||||||
|
"signedAt": null,
|
||||||
|
"authOptions": null,
|
||||||
|
"signingOrder": 1,
|
||||||
|
"rejectionReason": null,
|
||||||
|
"role": "SIGNER",
|
||||||
|
"readStatus": "NOT_OPENED",
|
||||||
|
"signingStatus": "NOT_SIGNED",
|
||||||
|
"sendStatus": "NOT_SENT"
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"createdAt": "2024-04-22T11:44:44.779Z",
|
"createdAt": "2024-04-22T11:44:44.779Z",
|
||||||
"webhookEndpoint": "https://mywebhooksite.com/mywebhook"
|
"webhookEndpoint": "https://mywebhooksite.com/mywebhook"
|
||||||
@ -128,9 +177,11 @@ Example payload for the `document.sent` event:
|
|||||||
"event": "DOCUMENT_SENT",
|
"event": "DOCUMENT_SENT",
|
||||||
"payload": {
|
"payload": {
|
||||||
"id": 10,
|
"id": 10,
|
||||||
|
"externalId": null,
|
||||||
"userId": 1,
|
"userId": 1,
|
||||||
"authOptions": null,
|
"authOptions": null,
|
||||||
"formValues": null,
|
"formValues": null,
|
||||||
|
"visibility": "EVERYONE",
|
||||||
"title": "documenso.pdf",
|
"title": "documenso.pdf",
|
||||||
"status": "PENDING",
|
"status": "PENDING",
|
||||||
"documentDataId": "hs8qz1ktr9204jn7mg6c5dxy0",
|
"documentDataId": "hs8qz1ktr9204jn7mg6c5dxy0",
|
||||||
@ -139,6 +190,22 @@ Example payload for the `document.sent` event:
|
|||||||
"completedAt": null,
|
"completedAt": null,
|
||||||
"deletedAt": null,
|
"deletedAt": null,
|
||||||
"teamId": null,
|
"teamId": null,
|
||||||
|
"templateId": null,
|
||||||
|
"source": "DOCUMENT",
|
||||||
|
"documentMeta": {
|
||||||
|
"id": "doc_meta_123",
|
||||||
|
"subject": "Please sign this document",
|
||||||
|
"message": "Hello, please review and sign this document.",
|
||||||
|
"timezone": "UTC",
|
||||||
|
"password": null,
|
||||||
|
"dateFormat": "MM/DD/YYYY",
|
||||||
|
"redirectUrl": null,
|
||||||
|
"signingOrder": "PARALLEL",
|
||||||
|
"typedSignatureEnabled": true,
|
||||||
|
"language": "en",
|
||||||
|
"distributionMethod": "EMAIL",
|
||||||
|
"emailSettings": null
|
||||||
|
},
|
||||||
"Recipient": [
|
"Recipient": [
|
||||||
{
|
{
|
||||||
"id": 52,
|
"id": 52,
|
||||||
@ -147,12 +214,12 @@ Example payload for the `document.sent` event:
|
|||||||
"email": "signer2@documenso.com",
|
"email": "signer2@documenso.com",
|
||||||
"name": "Signer 2",
|
"name": "Signer 2",
|
||||||
"token": "vbT8hi3jKQmrFP_LN1WcS",
|
"token": "vbT8hi3jKQmrFP_LN1WcS",
|
||||||
|
"documentDeletedAt": null,
|
||||||
"expired": null,
|
"expired": null,
|
||||||
"signedAt": null,
|
"signedAt": null,
|
||||||
"authOptions": {
|
"authOptions": null,
|
||||||
"accessAuth": null,
|
"signingOrder": 1,
|
||||||
"actionAuth": null
|
"rejectionReason": null,
|
||||||
},
|
|
||||||
"role": "VIEWER",
|
"role": "VIEWER",
|
||||||
"readStatus": "NOT_OPENED",
|
"readStatus": "NOT_OPENED",
|
||||||
"signingStatus": "NOT_SIGNED",
|
"signingStatus": "NOT_SIGNED",
|
||||||
@ -165,12 +232,12 @@ Example payload for the `document.sent` event:
|
|||||||
"email": "signer1@documenso.com",
|
"email": "signer1@documenso.com",
|
||||||
"name": "Signer 1",
|
"name": "Signer 1",
|
||||||
"token": "HkrptwS42ZBXdRKj1TyUo",
|
"token": "HkrptwS42ZBXdRKj1TyUo",
|
||||||
|
"documentDeletedAt": null,
|
||||||
"expired": null,
|
"expired": null,
|
||||||
"signedAt": null,
|
"signedAt": null,
|
||||||
"authOptions": {
|
"authOptions": null,
|
||||||
"accessAuth": null,
|
"signingOrder": 2,
|
||||||
"actionAuth": null
|
"rejectionReason": null,
|
||||||
},
|
|
||||||
"role": "SIGNER",
|
"role": "SIGNER",
|
||||||
"readStatus": "NOT_OPENED",
|
"readStatus": "NOT_OPENED",
|
||||||
"signingStatus": "NOT_SIGNED",
|
"signingStatus": "NOT_SIGNED",
|
||||||
@ -190,9 +257,11 @@ Example payload for the `document.opened` event:
|
|||||||
"event": "DOCUMENT_OPENED",
|
"event": "DOCUMENT_OPENED",
|
||||||
"payload": {
|
"payload": {
|
||||||
"id": 10,
|
"id": 10,
|
||||||
|
"externalId": null,
|
||||||
"userId": 1,
|
"userId": 1,
|
||||||
"authOptions": null,
|
"authOptions": null,
|
||||||
"formValues": null,
|
"formValues": null,
|
||||||
|
"visibility": "EVERYONE",
|
||||||
"title": "documenso.pdf",
|
"title": "documenso.pdf",
|
||||||
"status": "PENDING",
|
"status": "PENDING",
|
||||||
"documentDataId": "hs8qz1ktr9204jn7mg6c5dxy0",
|
"documentDataId": "hs8qz1ktr9204jn7mg6c5dxy0",
|
||||||
@ -201,6 +270,22 @@ Example payload for the `document.opened` event:
|
|||||||
"completedAt": null,
|
"completedAt": null,
|
||||||
"deletedAt": null,
|
"deletedAt": null,
|
||||||
"teamId": null,
|
"teamId": null,
|
||||||
|
"templateId": null,
|
||||||
|
"source": "DOCUMENT",
|
||||||
|
"documentMeta": {
|
||||||
|
"id": "doc_meta_123",
|
||||||
|
"subject": "Please sign this document",
|
||||||
|
"message": "Hello, please review and sign this document.",
|
||||||
|
"timezone": "UTC",
|
||||||
|
"password": null,
|
||||||
|
"dateFormat": "MM/DD/YYYY",
|
||||||
|
"redirectUrl": null,
|
||||||
|
"signingOrder": "PARALLEL",
|
||||||
|
"typedSignatureEnabled": true,
|
||||||
|
"language": "en",
|
||||||
|
"distributionMethod": "EMAIL",
|
||||||
|
"emailSettings": null
|
||||||
|
},
|
||||||
"Recipient": [
|
"Recipient": [
|
||||||
{
|
{
|
||||||
"id": 52,
|
"id": 52,
|
||||||
@ -209,24 +294,18 @@ Example payload for the `document.opened` event:
|
|||||||
"email": "signer2@documenso.com",
|
"email": "signer2@documenso.com",
|
||||||
"name": "Signer 2",
|
"name": "Signer 2",
|
||||||
"token": "vbT8hi3jKQmrFP_LN1WcS",
|
"token": "vbT8hi3jKQmrFP_LN1WcS",
|
||||||
|
"documentDeletedAt": null,
|
||||||
"expired": null,
|
"expired": null,
|
||||||
"signedAt": null,
|
"signedAt": null,
|
||||||
"authOptions": {
|
"authOptions": null,
|
||||||
"accessAuth": null,
|
"signingOrder": 1,
|
||||||
"actionAuth": null
|
"rejectionReason": null,
|
||||||
},
|
|
||||||
"role": "VIEWER",
|
"role": "VIEWER",
|
||||||
"readStatus": "OPENED",
|
"readStatus": "OPENED",
|
||||||
"signingStatus": "NOT_SIGNED",
|
"signingStatus": "NOT_SIGNED",
|
||||||
"sendStatus": "SENT"
|
"sendStatus": "SENT"
|
||||||
}
|
}
|
||||||
],
|
]
|
||||||
"documentData": {
|
|
||||||
"id": "hs8qz1ktr9204jn7mg6c5dxy0",
|
|
||||||
"type": "S3_PATH",
|
|
||||||
"data": "9753/xzqrshtlpokm/documenso.pdf",
|
|
||||||
"initialData": "9753/xzqrshtlpokm/documenso.pdf"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"createdAt": "2024-04-22T11:50:26.174Z",
|
"createdAt": "2024-04-22T11:50:26.174Z",
|
||||||
"webhookEndpoint": "https://mywebhooksite.com/mywebhook"
|
"webhookEndpoint": "https://mywebhooksite.com/mywebhook"
|
||||||
@ -240,9 +319,11 @@ Example payload for the `document.signed` event:
|
|||||||
"event": "DOCUMENT_SIGNED",
|
"event": "DOCUMENT_SIGNED",
|
||||||
"payload": {
|
"payload": {
|
||||||
"id": 10,
|
"id": 10,
|
||||||
|
"externalId": null,
|
||||||
"userId": 1,
|
"userId": 1,
|
||||||
"authOptions": null,
|
"authOptions": null,
|
||||||
"formValues": null,
|
"formValues": null,
|
||||||
|
"visibility": "EVERYONE",
|
||||||
"title": "documenso.pdf",
|
"title": "documenso.pdf",
|
||||||
"status": "COMPLETED",
|
"status": "COMPLETED",
|
||||||
"documentDataId": "hs8qz1ktr9204jn7mg6c5dxy0",
|
"documentDataId": "hs8qz1ktr9204jn7mg6c5dxy0",
|
||||||
@ -251,6 +332,22 @@ Example payload for the `document.signed` event:
|
|||||||
"completedAt": "2024-04-22T11:52:05.707Z",
|
"completedAt": "2024-04-22T11:52:05.707Z",
|
||||||
"deletedAt": null,
|
"deletedAt": null,
|
||||||
"teamId": null,
|
"teamId": null,
|
||||||
|
"templateId": null,
|
||||||
|
"source": "DOCUMENT",
|
||||||
|
"documentMeta": {
|
||||||
|
"id": "doc_meta_123",
|
||||||
|
"subject": "Please sign this document",
|
||||||
|
"message": "Hello, please review and sign this document.",
|
||||||
|
"timezone": "UTC",
|
||||||
|
"password": null,
|
||||||
|
"dateFormat": "MM/DD/YYYY",
|
||||||
|
"redirectUrl": null,
|
||||||
|
"signingOrder": "PARALLEL",
|
||||||
|
"typedSignatureEnabled": true,
|
||||||
|
"language": "en",
|
||||||
|
"distributionMethod": "EMAIL",
|
||||||
|
"emailSettings": null
|
||||||
|
},
|
||||||
"Recipient": [
|
"Recipient": [
|
||||||
{
|
{
|
||||||
"id": 51,
|
"id": 51,
|
||||||
@ -259,12 +356,15 @@ Example payload for the `document.signed` event:
|
|||||||
"email": "signer1@documenso.com",
|
"email": "signer1@documenso.com",
|
||||||
"name": "Signer 1",
|
"name": "Signer 1",
|
||||||
"token": "HkrptwS42ZBXdRKj1TyUo",
|
"token": "HkrptwS42ZBXdRKj1TyUo",
|
||||||
|
"documentDeletedAt": null,
|
||||||
"expired": null,
|
"expired": null,
|
||||||
"signedAt": "2024-04-22T11:52:05.688Z",
|
"signedAt": "2024-04-22T11:52:05.688Z",
|
||||||
"authOptions": {
|
"authOptions": {
|
||||||
"accessAuth": null,
|
"accessAuth": null,
|
||||||
"actionAuth": null
|
"actionAuth": null
|
||||||
},
|
},
|
||||||
|
"signingOrder": 1,
|
||||||
|
"rejectionReason": null,
|
||||||
"role": "SIGNER",
|
"role": "SIGNER",
|
||||||
"readStatus": "OPENED",
|
"readStatus": "OPENED",
|
||||||
"signingStatus": "SIGNED",
|
"signingStatus": "SIGNED",
|
||||||
@ -284,9 +384,11 @@ Example payload for the `document.completed` event:
|
|||||||
"event": "DOCUMENT_COMPLETED",
|
"event": "DOCUMENT_COMPLETED",
|
||||||
"payload": {
|
"payload": {
|
||||||
"id": 10,
|
"id": 10,
|
||||||
|
"externalId": null,
|
||||||
"userId": 1,
|
"userId": 1,
|
||||||
"authOptions": null,
|
"authOptions": null,
|
||||||
"formValues": null,
|
"formValues": null,
|
||||||
|
"visibility": "EVERYONE",
|
||||||
"title": "documenso.pdf",
|
"title": "documenso.pdf",
|
||||||
"status": "COMPLETED",
|
"status": "COMPLETED",
|
||||||
"documentDataId": "hs8qz1ktr9204jn7mg6c5dxy0",
|
"documentDataId": "hs8qz1ktr9204jn7mg6c5dxy0",
|
||||||
@ -295,11 +397,21 @@ Example payload for the `document.completed` event:
|
|||||||
"completedAt": "2024-04-22T11:52:05.707Z",
|
"completedAt": "2024-04-22T11:52:05.707Z",
|
||||||
"deletedAt": null,
|
"deletedAt": null,
|
||||||
"teamId": null,
|
"teamId": null,
|
||||||
"documentData": {
|
"templateId": null,
|
||||||
"id": "hs8qz1ktr9204jn7mg6c5dxy0",
|
"source": "DOCUMENT",
|
||||||
"type": "S3_PATH",
|
"documentMeta": {
|
||||||
"data": "bk9p1h7x0s3m/documenso-signed.pdf",
|
"id": "doc_meta_123",
|
||||||
"initialData": "9753/xzqrshtlpokm/documenso.pdf"
|
"subject": "Please sign this document",
|
||||||
|
"message": "Hello, please review and sign this document.",
|
||||||
|
"timezone": "UTC",
|
||||||
|
"password": null,
|
||||||
|
"dateFormat": "MM/DD/YYYY",
|
||||||
|
"redirectUrl": null,
|
||||||
|
"signingOrder": "PARALLEL",
|
||||||
|
"typedSignatureEnabled": true,
|
||||||
|
"language": "en",
|
||||||
|
"distributionMethod": "EMAIL",
|
||||||
|
"emailSettings": null
|
||||||
},
|
},
|
||||||
"Recipient": [
|
"Recipient": [
|
||||||
{
|
{
|
||||||
@ -309,12 +421,15 @@ Example payload for the `document.completed` event:
|
|||||||
"email": "signer2@documenso.com",
|
"email": "signer2@documenso.com",
|
||||||
"name": "Signer 2",
|
"name": "Signer 2",
|
||||||
"token": "vbT8hi3jKQmrFP_LN1WcS",
|
"token": "vbT8hi3jKQmrFP_LN1WcS",
|
||||||
|
"documentDeletedAt": null,
|
||||||
"expired": null,
|
"expired": null,
|
||||||
"signedAt": "2024-04-22T11:51:10.055Z",
|
"signedAt": "2024-04-22T11:51:10.055Z",
|
||||||
"authOptions": {
|
"authOptions": {
|
||||||
"accessAuth": null,
|
"accessAuth": null,
|
||||||
"actionAuth": null
|
"actionAuth": null
|
||||||
},
|
},
|
||||||
|
"signingOrder": 1,
|
||||||
|
"rejectionReason": null,
|
||||||
"role": "VIEWER",
|
"role": "VIEWER",
|
||||||
"readStatus": "OPENED",
|
"readStatus": "OPENED",
|
||||||
"signingStatus": "SIGNED",
|
"signingStatus": "SIGNED",
|
||||||
@ -327,12 +442,15 @@ Example payload for the `document.completed` event:
|
|||||||
"email": "signer1@documenso.com",
|
"email": "signer1@documenso.com",
|
||||||
"name": "Signer 1",
|
"name": "Signer 1",
|
||||||
"token": "HkrptwS42ZBXdRKj1TyUo",
|
"token": "HkrptwS42ZBXdRKj1TyUo",
|
||||||
|
"documentDeletedAt": null,
|
||||||
"expired": null,
|
"expired": null,
|
||||||
"signedAt": "2024-04-22T11:52:05.688Z",
|
"signedAt": "2024-04-22T11:52:05.688Z",
|
||||||
"authOptions": {
|
"authOptions": {
|
||||||
"accessAuth": null,
|
"accessAuth": null,
|
||||||
"actionAuth": null
|
"actionAuth": null
|
||||||
},
|
},
|
||||||
|
"signingOrder": 2,
|
||||||
|
"rejectionReason": null,
|
||||||
"role": "SIGNER",
|
"role": "SIGNER",
|
||||||
"readStatus": "OPENED",
|
"readStatus": "OPENED",
|
||||||
"signingStatus": "SIGNED",
|
"signingStatus": "SIGNED",
|
||||||
@ -345,6 +463,71 @@ Example payload for the `document.completed` event:
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Example payload for the `document.rejected` event:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"event": "DOCUMENT_REJECTED",
|
||||||
|
"payload": {
|
||||||
|
"id": 10,
|
||||||
|
"externalId": null,
|
||||||
|
"userId": 1,
|
||||||
|
"authOptions": null,
|
||||||
|
"formValues": null,
|
||||||
|
"visibility": "EVERYONE",
|
||||||
|
"title": "documenso.pdf",
|
||||||
|
"status": "PENDING",
|
||||||
|
"documentDataId": "hs8qz1ktr9204jn7mg6c5dxy0",
|
||||||
|
"createdAt": "2024-04-22T11:44:43.341Z",
|
||||||
|
"updatedAt": "2024-04-22T11:48:07.569Z",
|
||||||
|
"completedAt": null,
|
||||||
|
"deletedAt": null,
|
||||||
|
"teamId": null,
|
||||||
|
"templateId": null,
|
||||||
|
"source": "DOCUMENT",
|
||||||
|
"documentMeta": {
|
||||||
|
"id": "doc_meta_123",
|
||||||
|
"subject": "Please sign this document",
|
||||||
|
"message": "Hello, please review and sign this document.",
|
||||||
|
"timezone": "UTC",
|
||||||
|
"password": null,
|
||||||
|
"dateFormat": "MM/DD/YYYY",
|
||||||
|
"redirectUrl": null,
|
||||||
|
"signingOrder": "PARALLEL",
|
||||||
|
"typedSignatureEnabled": true,
|
||||||
|
"language": "en",
|
||||||
|
"distributionMethod": "EMAIL",
|
||||||
|
"emailSettings": null
|
||||||
|
},
|
||||||
|
"Recipient": [
|
||||||
|
{
|
||||||
|
"id": 52,
|
||||||
|
"documentId": 10,
|
||||||
|
"templateId": null,
|
||||||
|
"email": "signer@documenso.com",
|
||||||
|
"name": "Signer",
|
||||||
|
"token": "vbT8hi3jKQmrFP_LN1WcS",
|
||||||
|
"documentDeletedAt": null,
|
||||||
|
"expired": null,
|
||||||
|
"signedAt": "2024-04-22T11:48:07.569Z",
|
||||||
|
"authOptions": {
|
||||||
|
"accessAuth": null,
|
||||||
|
"actionAuth": null
|
||||||
|
},
|
||||||
|
"signingOrder": 1,
|
||||||
|
"rejectionReason": "I do not agree with the terms",
|
||||||
|
"role": "SIGNER",
|
||||||
|
"readStatus": "OPENED",
|
||||||
|
"signingStatus": "REJECTED",
|
||||||
|
"sendStatus": "SENT"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"createdAt": "2024-04-22T11:48:07.945Z",
|
||||||
|
"webhookEndpoint": "https://mywebhooksite.com/mywebhook"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Availability
|
## Availability
|
||||||
|
|
||||||
Webhooks are available to individual users and teams.
|
Webhooks are available to individual users and teams.
|
||||||
|
|||||||
@ -10,7 +10,6 @@
|
|||||||
"signing-documents": "Signing Documents",
|
"signing-documents": "Signing Documents",
|
||||||
"templates": "Templates",
|
"templates": "Templates",
|
||||||
"direct-links": "Direct Signing Links",
|
"direct-links": "Direct Signing Links",
|
||||||
"document-visibility": "Document Visibility",
|
|
||||||
"teams": "Teams",
|
"teams": "Teams",
|
||||||
"-- Legal Overview": {
|
"-- Legal Overview": {
|
||||||
"type": "separator",
|
"type": "separator",
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"general-settings": "General Settings",
|
"preferences": "Preferences",
|
||||||
"document-visibility": "Document Visibility",
|
"document-visibility": "Document Visibility",
|
||||||
"sender-details": "Email Sender Details"
|
"sender-details": "Email Sender Details",
|
||||||
|
"branding-preferences": "Branding Preferences"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,16 @@
|
|||||||
|
---
|
||||||
|
title: Branding Preferences
|
||||||
|
description: Learn how to set the branding preferences for your team account.
|
||||||
|
---
|
||||||
|
|
||||||
|
# Branding Preferences
|
||||||
|
|
||||||
|
You can set the branding preferences for your team account by going to the **Branding Preferences** tab in the team's settings dashboard.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
On this page, you can:
|
||||||
|
|
||||||
|
- **Upload a Logo** - Upload your team's logo to be displayed instead of the default Documenso logo.
|
||||||
|
- **Set the Brand Website** - Enter the URL of your team's website to be displayed in the email communications sent by the team.
|
||||||
|
- **Add Additional Brand Details** - You can add additional information to display at the bottom of the emails sent by the team. This can include contact information, social media links, and other relevant details.
|
||||||
@ -13,9 +13,9 @@ The default document visibility option allows you to control who can view and ac
|
|||||||
- **Managers and above** - The document is visible to team members with the role of _Manager or above_ and _Admin_.
|
- **Managers and above** - The document is visible to team members with the role of _Manager or above_ and _Admin_.
|
||||||
- **Admin only** - The document is only visible to the team's admins.
|
- **Admin only** - The document is only visible to the team's admins.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
The default document visibility is set to "_EVERYONE_" by default. You can change this setting by going to the [team's general settings page](/users/teams/general-settings) and selecting a different visibility option.
|
The default document visibility is set to "_EVERYONE_" by default. You can change this setting by going to the [team's general preferences page](/users/teams/preferences) and selecting a different visibility option.
|
||||||
|
|
||||||
<Callout type="warning">
|
<Callout type="warning">
|
||||||
If the team member uploading the document has a role lower than the default document visibility,
|
If the team member uploading the document has a role lower than the default document visibility,
|
||||||
|
|||||||
@ -1,15 +0,0 @@
|
|||||||
---
|
|
||||||
title: General Settings
|
|
||||||
description: Learn how to manage your team's General settings.
|
|
||||||
---
|
|
||||||
|
|
||||||
# General Settings
|
|
||||||
|
|
||||||
You can manage your team's general settings by clicking on the **General Settings** tab in the team's settings dashboard.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
The general settings page allows you to update the following settings:
|
|
||||||
|
|
||||||
- **Document Visibility** - Set the default visibility of the documents created by team members. Learn more about [document visibility](/users/teams/document-visibility).
|
|
||||||
- **Sender Details** - Set whether the sender's name should be included in the emails sent by the team. Learn more about [sender details](/users/teams/sender-details).
|
|
||||||
19
apps/documentation/pages/users/teams/preferences.mdx
Normal file
19
apps/documentation/pages/users/teams/preferences.mdx
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
---
|
||||||
|
title: Preferences
|
||||||
|
description: Learn how to manage your team's global preferences.
|
||||||
|
---
|
||||||
|
|
||||||
|
# Preferences
|
||||||
|
|
||||||
|
You can manage your team's global preferences by clicking on the **Preferences** tab in the team's settings dashboard.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
The preferences page allows you to update the following settings:
|
||||||
|
|
||||||
|
- **Document Visibility** - Set the default visibility of the documents created by team members. Learn more about [document visibility](/users/teams/document-visibility).
|
||||||
|
- **Default Document Language** - This setting allows you to set the default language for the documents uploaded in the team account. The default language is used as the default language in the email communications with the document recipients. You can change the language for individual documents when uploading them.
|
||||||
|
- **Sender Details** - Set whether the sender's name should be included in the emails sent by the team. Learn more about [sender details](/users/teams/sender-details).
|
||||||
|
- **Typed Signature** - It controls whether the document recipients can sign the documents with a typed signature or not. If enabled, the recipients can sign the document using either a drawn or a typed signature. If disabled, the recipients can only sign the documents usign a drawn signature. This setting can also be changed for individual documents when uploading them.
|
||||||
|
- **Include the Signing Certificate** - This setting controls whether the signing certificate should be included in the signed documents. If enabled, the signing certificate is included in the signed documents. If disabled, the signing certificate is not included in the signed documents. Regardless of this setting, the signing certificate is always available in the document's audit log page.
|
||||||
|
- **Branding Preferences** - Set the branding preferences and defaults for the team account. Learn more about [branding preferences](/users/teams/branding-preferences).
|
||||||
BIN
apps/documentation/public/teams/team-branding-preferences.webp
Normal file
BIN
apps/documentation/public/teams/team-branding-preferences.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 79 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 99 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 98 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 128 KiB |
BIN
apps/documentation/public/teams/team-preferences.webp
Normal file
BIN
apps/documentation/public/teams/team-preferences.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 165 KiB |
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@documenso/marketing",
|
"name": "@documenso/marketing",
|
||||||
"version": "1.8.1-rc.4",
|
"version": "1.8.1-rc.9",
|
||||||
"private": true,
|
"private": true,
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@documenso/web",
|
"name": "@documenso/web",
|
||||||
"version": "1.8.1-rc.4",
|
"version": "1.8.1-rc.9",
|
||||||
"private": true,
|
"private": true,
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@ -0,0 +1,169 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { useEffect, useMemo, useState, useTransition } from 'react';
|
||||||
|
|
||||||
|
import { msg } from '@lingui/macro';
|
||||||
|
import { useLingui } from '@lingui/react';
|
||||||
|
import { ChevronDownIcon as CaretSortIcon, Loader } from 'lucide-react';
|
||||||
|
|
||||||
|
import { useDebouncedValue } from '@documenso/lib/client-only/hooks/use-debounced-value';
|
||||||
|
import { useUpdateSearchParams } from '@documenso/lib/client-only/hooks/use-update-search-params';
|
||||||
|
import type { DataTableColumnDef } from '@documenso/ui/primitives/data-table';
|
||||||
|
import { DataTable } from '@documenso/ui/primitives/data-table';
|
||||||
|
import { DataTablePagination } from '@documenso/ui/primitives/data-table-pagination';
|
||||||
|
import { Input } from '@documenso/ui/primitives/input';
|
||||||
|
|
||||||
|
export type SigningVolume = {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
signingVolume: number;
|
||||||
|
createdAt: Date;
|
||||||
|
planId: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type LeaderboardTableProps = {
|
||||||
|
signingVolume: SigningVolume[];
|
||||||
|
totalPages: number;
|
||||||
|
perPage: number;
|
||||||
|
page: number;
|
||||||
|
sortBy: 'name' | 'createdAt' | 'signingVolume';
|
||||||
|
sortOrder: 'asc' | 'desc';
|
||||||
|
};
|
||||||
|
|
||||||
|
export const LeaderboardTable = ({
|
||||||
|
signingVolume,
|
||||||
|
totalPages,
|
||||||
|
perPage,
|
||||||
|
page,
|
||||||
|
sortBy,
|
||||||
|
sortOrder,
|
||||||
|
}: LeaderboardTableProps) => {
|
||||||
|
const { _, i18n } = useLingui();
|
||||||
|
|
||||||
|
const [isPending, startTransition] = useTransition();
|
||||||
|
const updateSearchParams = useUpdateSearchParams();
|
||||||
|
const [searchString, setSearchString] = useState('');
|
||||||
|
const debouncedSearchString = useDebouncedValue(searchString, 1000);
|
||||||
|
|
||||||
|
const columns = useMemo(() => {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
header: () => (
|
||||||
|
<div
|
||||||
|
className="flex cursor-pointer items-center"
|
||||||
|
onClick={() => handleColumnSort('name')}
|
||||||
|
>
|
||||||
|
{_(msg`Name`)}
|
||||||
|
<CaretSortIcon className="ml-2 h-4 w-4" />
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
accessorKey: 'name',
|
||||||
|
cell: ({ row }) => {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<a
|
||||||
|
className="text-primary underline"
|
||||||
|
href={`https://dashboard.stripe.com/subscriptions/${row.original.planId}`}
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
{row.getValue('name')}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
size: 250,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
header: () => (
|
||||||
|
<div
|
||||||
|
className="flex cursor-pointer items-center"
|
||||||
|
onClick={() => handleColumnSort('signingVolume')}
|
||||||
|
>
|
||||||
|
{_(msg`Signing Volume`)}
|
||||||
|
<CaretSortIcon className="ml-2 h-4 w-4" />
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
accessorKey: 'signingVolume',
|
||||||
|
cell: ({ row }) => <div>{Number(row.getValue('signingVolume'))}</div>,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
header: () => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className="flex cursor-pointer items-center"
|
||||||
|
onClick={() => handleColumnSort('createdAt')}
|
||||||
|
>
|
||||||
|
{_(msg`Created`)}
|
||||||
|
<CaretSortIcon className="ml-2 h-4 w-4" />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
accessorKey: 'createdAt',
|
||||||
|
cell: ({ row }) => i18n.date(row.original.createdAt),
|
||||||
|
},
|
||||||
|
] satisfies DataTableColumnDef<SigningVolume>[];
|
||||||
|
}, [sortOrder]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
startTransition(() => {
|
||||||
|
updateSearchParams({
|
||||||
|
search: debouncedSearchString,
|
||||||
|
page: 1,
|
||||||
|
perPage,
|
||||||
|
sortBy,
|
||||||
|
sortOrder,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [debouncedSearchString]);
|
||||||
|
|
||||||
|
const onPaginationChange = (page: number, perPage: number) => {
|
||||||
|
startTransition(() => {
|
||||||
|
updateSearchParams({
|
||||||
|
page,
|
||||||
|
perPage,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
setSearchString(e.target.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleColumnSort = (column: 'name' | 'createdAt' | 'signingVolume') => {
|
||||||
|
startTransition(() => {
|
||||||
|
updateSearchParams({
|
||||||
|
sortBy: column,
|
||||||
|
sortOrder: sortOrder === 'asc' ? 'desc' : 'asc',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="relative">
|
||||||
|
<Input
|
||||||
|
className="my-6 flex flex-row gap-4"
|
||||||
|
type="text"
|
||||||
|
placeholder={_(msg`Search by name or email`)}
|
||||||
|
value={searchString}
|
||||||
|
onChange={handleChange}
|
||||||
|
/>
|
||||||
|
<DataTable
|
||||||
|
columns={columns}
|
||||||
|
data={signingVolume}
|
||||||
|
perPage={perPage}
|
||||||
|
currentPage={page}
|
||||||
|
totalPages={totalPages}
|
||||||
|
onPaginationChange={onPaginationChange}
|
||||||
|
>
|
||||||
|
{(table) => <DataTablePagination additionalInformation="VisibleCount" table={table} />}
|
||||||
|
</DataTable>
|
||||||
|
|
||||||
|
{isPending && (
|
||||||
|
<div className="absolute inset-0 flex items-center justify-center bg-white/50">
|
||||||
|
<Loader className="h-8 w-8 animate-spin text-gray-500" />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -0,0 +1,25 @@
|
|||||||
|
'use server';
|
||||||
|
|
||||||
|
import { getRequiredServerComponentSession } from '@documenso/lib/next-auth/get-server-component-session';
|
||||||
|
import { isAdmin } from '@documenso/lib/next-auth/guards/is-admin';
|
||||||
|
import { getSigningVolume } from '@documenso/lib/server-only/admin/get-signing-volume';
|
||||||
|
|
||||||
|
type SearchOptions = {
|
||||||
|
search: string;
|
||||||
|
page: number;
|
||||||
|
perPage: number;
|
||||||
|
sortBy: 'name' | 'createdAt' | 'signingVolume';
|
||||||
|
sortOrder: 'asc' | 'desc';
|
||||||
|
};
|
||||||
|
|
||||||
|
export async function search({ search, page, perPage, sortBy, sortOrder }: SearchOptions) {
|
||||||
|
const { user } = await getRequiredServerComponentSession();
|
||||||
|
|
||||||
|
if (!isAdmin(user)) {
|
||||||
|
throw new Error('Unauthorized');
|
||||||
|
}
|
||||||
|
|
||||||
|
const results = await getSigningVolume({ search, page, perPage, sortBy, sortOrder });
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
60
apps/web/src/app/(dashboard)/admin/leaderboard/page.tsx
Normal file
60
apps/web/src/app/(dashboard)/admin/leaderboard/page.tsx
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
import { Trans } from '@lingui/macro';
|
||||||
|
|
||||||
|
import { setupI18nSSR } from '@documenso/lib/client-only/providers/i18n.server';
|
||||||
|
import { getRequiredServerComponentSession } from '@documenso/lib/next-auth/get-server-component-session';
|
||||||
|
import { isAdmin } from '@documenso/lib/next-auth/guards/is-admin';
|
||||||
|
|
||||||
|
import { LeaderboardTable } from './data-table-leaderboard';
|
||||||
|
import { search } from './fetch-leaderboard.actions';
|
||||||
|
|
||||||
|
type AdminLeaderboardProps = {
|
||||||
|
searchParams?: {
|
||||||
|
search?: string;
|
||||||
|
page?: number;
|
||||||
|
perPage?: number;
|
||||||
|
sortBy?: 'name' | 'createdAt' | 'signingVolume';
|
||||||
|
sortOrder?: 'asc' | 'desc';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default async function Leaderboard({ searchParams = {} }: AdminLeaderboardProps) {
|
||||||
|
await setupI18nSSR();
|
||||||
|
|
||||||
|
const { user } = await getRequiredServerComponentSession();
|
||||||
|
|
||||||
|
if (!isAdmin(user)) {
|
||||||
|
throw new Error('Unauthorized');
|
||||||
|
}
|
||||||
|
|
||||||
|
const page = Number(searchParams.page) || 1;
|
||||||
|
const perPage = Number(searchParams.perPage) || 10;
|
||||||
|
const searchString = searchParams.search || '';
|
||||||
|
const sortBy = searchParams.sortBy || 'signingVolume';
|
||||||
|
const sortOrder = searchParams.sortOrder || 'desc';
|
||||||
|
|
||||||
|
const { leaderboard: signingVolume, totalPages } = await search({
|
||||||
|
search: searchString,
|
||||||
|
page,
|
||||||
|
perPage,
|
||||||
|
sortBy,
|
||||||
|
sortOrder,
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h2 className="text-4xl font-semibold">
|
||||||
|
<Trans>Signing Volume</Trans>
|
||||||
|
</h2>
|
||||||
|
<div className="mt-8">
|
||||||
|
<LeaderboardTable
|
||||||
|
signingVolume={signingVolume}
|
||||||
|
totalPages={totalPages}
|
||||||
|
page={page}
|
||||||
|
perPage={perPage}
|
||||||
|
sortBy={sortBy}
|
||||||
|
sortOrder={sortOrder}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -6,7 +6,7 @@ import Link from 'next/link';
|
|||||||
import { usePathname } from 'next/navigation';
|
import { usePathname } from 'next/navigation';
|
||||||
|
|
||||||
import { Trans } from '@lingui/macro';
|
import { Trans } from '@lingui/macro';
|
||||||
import { BarChart3, FileStack, Settings, Users, Wallet2 } from 'lucide-react';
|
import { BarChart3, FileStack, Settings, Trophy, Users, Wallet2 } from 'lucide-react';
|
||||||
|
|
||||||
import { cn } from '@documenso/ui/lib/utils';
|
import { cn } from '@documenso/ui/lib/utils';
|
||||||
import { Button } from '@documenso/ui/primitives/button';
|
import { Button } from '@documenso/ui/primitives/button';
|
||||||
@ -80,6 +80,20 @@ export const AdminNav = ({ className, ...props }: AdminNavProps) => {
|
|||||||
</Link>
|
</Link>
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
className={cn(
|
||||||
|
'justify-start md:w-full',
|
||||||
|
pathname?.startsWith('/admin/leaderboard') && 'bg-secondary',
|
||||||
|
)}
|
||||||
|
asChild
|
||||||
|
>
|
||||||
|
<Link href="/admin/leaderboard">
|
||||||
|
<Trophy className="mr-2 h-5 w-5" />
|
||||||
|
<Trans>Leaderboard</Trans>
|
||||||
|
</Link>
|
||||||
|
</Button>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
className={cn(
|
className={cn(
|
||||||
|
|||||||
@ -41,7 +41,7 @@ export default async function BillingSettingsPage() {
|
|||||||
|
|
||||||
const [subscriptions, prices, primaryAccountPlanPrices] = await Promise.all([
|
const [subscriptions, prices, primaryAccountPlanPrices] = await Promise.all([
|
||||||
getSubscriptionsByUserId({ userId: user.id }),
|
getSubscriptionsByUserId({ userId: user.id }),
|
||||||
getPricesByInterval({ plan: STRIPE_PLAN_TYPE.REGULAR }),
|
getPricesByInterval({ plans: [STRIPE_PLAN_TYPE.REGULAR, STRIPE_PLAN_TYPE.PLATFORM] }),
|
||||||
getPrimaryAccountPlanPrices(),
|
getPrimaryAccountPlanPrices(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|||||||
@ -80,7 +80,7 @@ export default async function EmbedSignDocumentPage({ params }: EmbedSignDocumen
|
|||||||
return (
|
return (
|
||||||
<EmbedAuthenticateView
|
<EmbedAuthenticateView
|
||||||
email={user?.email || recipient.email}
|
email={user?.email || recipient.email}
|
||||||
returnTo={`/embed/direct/${token}`}
|
returnTo={`/embed/sign/${token}`}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -78,13 +78,14 @@ async function middleware(req: NextRequest): Promise<NextResponse> {
|
|||||||
if (req.nextUrl.pathname.startsWith('/embed')) {
|
if (req.nextUrl.pathname.startsWith('/embed')) {
|
||||||
const res = NextResponse.next();
|
const res = NextResponse.next();
|
||||||
|
|
||||||
|
const origin = req.headers.get('Origin') ?? '*';
|
||||||
|
|
||||||
// Allow third parties to iframe the document.
|
// Allow third parties to iframe the document.
|
||||||
res.headers.set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
|
res.headers.set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
|
||||||
res.headers.set('Access-Control-Allow-Origin', '*');
|
res.headers.set('Access-Control-Allow-Origin', origin);
|
||||||
res.headers.set('Content-Security-Policy', 'frame-ancestors *');
|
res.headers.set('Content-Security-Policy', `frame-ancestors ${origin}`);
|
||||||
res.headers.set('Referrer-Policy', 'strict-origin-when-cross-origin');
|
res.headers.set('Referrer-Policy', 'strict-origin-when-cross-origin');
|
||||||
res.headers.set('X-Content-Type-Options', 'nosniff');
|
res.headers.set('X-Content-Type-Options', 'nosniff');
|
||||||
res.headers.set('X-Frame-Options', 'ALLOW-ALL');
|
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|||||||
8
package-lock.json
generated
8
package-lock.json
generated
@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "@documenso/root",
|
"name": "@documenso/root",
|
||||||
"version": "1.8.1-rc.4",
|
"version": "1.8.1-rc.9",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "@documenso/root",
|
"name": "@documenso/root",
|
||||||
"version": "1.8.1-rc.4",
|
"version": "1.8.1-rc.9",
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
"apps/*",
|
"apps/*",
|
||||||
"packages/*"
|
"packages/*"
|
||||||
@ -77,7 +77,7 @@
|
|||||||
},
|
},
|
||||||
"apps/marketing": {
|
"apps/marketing": {
|
||||||
"name": "@documenso/marketing",
|
"name": "@documenso/marketing",
|
||||||
"version": "1.8.1-rc.4",
|
"version": "1.8.1-rc.9",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@documenso/assets": "*",
|
"@documenso/assets": "*",
|
||||||
@ -438,7 +438,7 @@
|
|||||||
},
|
},
|
||||||
"apps/web": {
|
"apps/web": {
|
||||||
"name": "@documenso/web",
|
"name": "@documenso/web",
|
||||||
"version": "1.8.1-rc.4",
|
"version": "1.8.1-rc.9",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@documenso/api": "*",
|
"@documenso/api": "*",
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "1.8.1-rc.4",
|
"version": "1.8.1-rc.9",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "turbo run build",
|
"build": "turbo run build",
|
||||||
"build:web": "turbo run build --filter=@documenso/web",
|
"build:web": "turbo run build --filter=@documenso/web",
|
||||||
|
|||||||
@ -244,18 +244,10 @@ export const ApiContractV1Implementation = createNextRoute(ApiContractV1, {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const dateFormat = body.meta.dateFormat
|
const dateFormat = body.meta.dateFormat
|
||||||
? DATE_FORMATS.find((format) => format.label === body.meta.dateFormat)
|
? DATE_FORMATS.find((format) => format.value === body.meta.dateFormat)
|
||||||
: DATE_FORMATS.find((format) => format.value === DEFAULT_DOCUMENT_DATE_FORMAT);
|
: DATE_FORMATS.find((format) => format.value === DEFAULT_DOCUMENT_DATE_FORMAT);
|
||||||
const timezone = body.meta.timezone
|
|
||||||
? TIME_ZONES.find((tz) => tz === body.meta.timezone)
|
|
||||||
: DEFAULT_DOCUMENT_TIME_ZONE;
|
|
||||||
|
|
||||||
const isDateFormatValid = body.meta.dateFormat
|
if (body.meta.dateFormat && !dateFormat) {
|
||||||
? DATE_FORMATS.some((format) => format.label === dateFormat?.label)
|
|
||||||
: true;
|
|
||||||
const isTimeZoneValid = body.meta.timezone ? TIME_ZONES.includes(String(timezone)) : true;
|
|
||||||
|
|
||||||
if (!isDateFormatValid) {
|
|
||||||
return {
|
return {
|
||||||
status: 400,
|
status: 400,
|
||||||
body: {
|
body: {
|
||||||
@ -264,6 +256,12 @@ export const ApiContractV1Implementation = createNextRoute(ApiContractV1, {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const timezone = body.meta.timezone
|
||||||
|
? TIME_ZONES.find((tz) => tz === body.meta.timezone)
|
||||||
|
: DEFAULT_DOCUMENT_TIME_ZONE;
|
||||||
|
|
||||||
|
const isTimeZoneValid = body.meta.timezone ? TIME_ZONES.includes(String(timezone)) : true;
|
||||||
|
|
||||||
if (!isTimeZoneValid) {
|
if (!isTimeZoneValid) {
|
||||||
return {
|
return {
|
||||||
status: 400,
|
status: 400,
|
||||||
|
|||||||
@ -12,10 +12,10 @@ export type GetPricesByIntervalOptions = {
|
|||||||
/**
|
/**
|
||||||
* Filter products by their meta 'plan' attribute.
|
* Filter products by their meta 'plan' attribute.
|
||||||
*/
|
*/
|
||||||
plan?: STRIPE_PLAN_TYPE.COMMUNITY | STRIPE_PLAN_TYPE.REGULAR;
|
plans?: STRIPE_PLAN_TYPE[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getPricesByInterval = async ({ plan }: GetPricesByIntervalOptions = {}) => {
|
export const getPricesByInterval = async ({ plans }: GetPricesByIntervalOptions = {}) => {
|
||||||
let { data: prices } = await stripe.prices.search({
|
let { data: prices } = await stripe.prices.search({
|
||||||
query: `active:'true' type:'recurring'`,
|
query: `active:'true' type:'recurring'`,
|
||||||
expand: ['data.product'],
|
expand: ['data.product'],
|
||||||
@ -27,7 +27,8 @@ export const getPricesByInterval = async ({ plan }: GetPricesByIntervalOptions =
|
|||||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||||
const product = price.product as Stripe.Product;
|
const product = price.product as Stripe.Product;
|
||||||
|
|
||||||
const filter = !plan || product.metadata?.plan === plan;
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||||
|
const filter = !plans || plans.includes(product.metadata?.plan as STRIPE_PLAN_TYPE);
|
||||||
|
|
||||||
// Filter out prices for products that are not active.
|
// Filter out prices for products that are not active.
|
||||||
return product.active && filter;
|
return product.active && filter;
|
||||||
|
|||||||
@ -21,6 +21,7 @@ import { insertFieldInPDF } from '../../../server-only/pdf/insert-field-in-pdf';
|
|||||||
import { normalizeSignatureAppearances } from '../../../server-only/pdf/normalize-signature-appearances';
|
import { normalizeSignatureAppearances } from '../../../server-only/pdf/normalize-signature-appearances';
|
||||||
import { triggerWebhook } from '../../../server-only/webhooks/trigger/trigger-webhook';
|
import { triggerWebhook } from '../../../server-only/webhooks/trigger/trigger-webhook';
|
||||||
import { DOCUMENT_AUDIT_LOG_TYPE } from '../../../types/document-audit-logs';
|
import { DOCUMENT_AUDIT_LOG_TYPE } from '../../../types/document-audit-logs';
|
||||||
|
import { ZWebhookDocumentSchema } from '../../../types/webhook-payload';
|
||||||
import { ZRequestMetadataSchema } from '../../../universal/extract-request-metadata';
|
import { ZRequestMetadataSchema } from '../../../universal/extract-request-metadata';
|
||||||
import { getFile } from '../../../universal/upload/get-file';
|
import { getFile } from '../../../universal/upload/get-file';
|
||||||
import { putPdfFile } from '../../../universal/upload/put-file';
|
import { putPdfFile } from '../../../universal/upload/put-file';
|
||||||
@ -249,13 +250,14 @@ export const SEAL_DOCUMENT_JOB_DEFINITION = {
|
|||||||
},
|
},
|
||||||
include: {
|
include: {
|
||||||
documentData: true,
|
documentData: true,
|
||||||
|
documentMeta: true,
|
||||||
Recipient: true,
|
Recipient: true,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
await triggerWebhook({
|
await triggerWebhook({
|
||||||
event: WebhookTriggerEvents.DOCUMENT_COMPLETED,
|
event: WebhookTriggerEvents.DOCUMENT_COMPLETED,
|
||||||
data: updatedDocument,
|
data: ZWebhookDocumentSchema.parse(updatedDocument),
|
||||||
userId: updatedDocument.userId,
|
userId: updatedDocument.userId,
|
||||||
teamId: updatedDocument.teamId ?? undefined,
|
teamId: updatedDocument.teamId ?? undefined,
|
||||||
});
|
});
|
||||||
|
|||||||
@ -26,6 +26,10 @@ import { extractNextAuthRequestMetadata } from '../universal/extract-request-met
|
|||||||
import { getAuthenticatorOptions } from '../utils/authenticator';
|
import { getAuthenticatorOptions } from '../utils/authenticator';
|
||||||
import { ErrorCode } from './error-codes';
|
import { ErrorCode } from './error-codes';
|
||||||
|
|
||||||
|
const useSecureCookies =
|
||||||
|
process.env.NODE_ENV === 'production' && String(process.env.NEXTAUTH_URL).startsWith('https://');
|
||||||
|
const cookiePrefix = useSecureCookies ? '__Secure-' : '';
|
||||||
|
|
||||||
export const NEXT_AUTH_OPTIONS: AuthOptions = {
|
export const NEXT_AUTH_OPTIONS: AuthOptions = {
|
||||||
adapter: PrismaAdapter(prisma),
|
adapter: PrismaAdapter(prisma),
|
||||||
secret: process.env.NEXTAUTH_SECRET ?? 'secret',
|
secret: process.env.NEXTAUTH_SECRET ?? 'secret',
|
||||||
@ -431,5 +435,53 @@ export const NEXT_AUTH_OPTIONS: AuthOptions = {
|
|||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
cookies: {
|
||||||
|
sessionToken: {
|
||||||
|
name: `${cookiePrefix}next-auth.session-token`,
|
||||||
|
options: {
|
||||||
|
httpOnly: true,
|
||||||
|
sameSite: useSecureCookies ? 'none' : 'lax',
|
||||||
|
path: '/',
|
||||||
|
secure: useSecureCookies,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
callbackUrl: {
|
||||||
|
name: `${cookiePrefix}next-auth.callback-url`,
|
||||||
|
options: {
|
||||||
|
sameSite: useSecureCookies ? 'none' : 'lax',
|
||||||
|
path: '/',
|
||||||
|
secure: useSecureCookies,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
csrfToken: {
|
||||||
|
// Default to __Host- for CSRF token for additional protection if using useSecureCookies
|
||||||
|
// NB: The `__Host-` prefix is stricter than the `__Secure-` prefix.
|
||||||
|
name: `${cookiePrefix}next-auth.csrf-token`,
|
||||||
|
options: {
|
||||||
|
httpOnly: true,
|
||||||
|
sameSite: useSecureCookies ? 'none' : 'lax',
|
||||||
|
path: '/',
|
||||||
|
secure: useSecureCookies,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
pkceCodeVerifier: {
|
||||||
|
name: `${cookiePrefix}next-auth.pkce.code_verifier`,
|
||||||
|
options: {
|
||||||
|
httpOnly: true,
|
||||||
|
sameSite: useSecureCookies ? 'none' : 'lax',
|
||||||
|
path: '/',
|
||||||
|
secure: useSecureCookies,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
state: {
|
||||||
|
name: `${cookiePrefix}next-auth.state`,
|
||||||
|
options: {
|
||||||
|
httpOnly: true,
|
||||||
|
sameSite: useSecureCookies ? 'none' : 'lax',
|
||||||
|
path: '/',
|
||||||
|
secure: useSecureCookies,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
// Note: `events` are handled in `apps/web/src/pages/api/auth/[...nextauth].ts` to allow access to the request.
|
// Note: `events` are handled in `apps/web/src/pages/api/auth/[...nextauth].ts` to allow access to the request.
|
||||||
};
|
};
|
||||||
|
|||||||
148
packages/lib/server-only/admin/get-signing-volume.ts
Normal file
148
packages/lib/server-only/admin/get-signing-volume.ts
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
import { prisma } from '@documenso/prisma';
|
||||||
|
import { Prisma } from '@documenso/prisma/client';
|
||||||
|
|
||||||
|
export type SigningVolume = {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
signingVolume: number;
|
||||||
|
createdAt: Date;
|
||||||
|
planId: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type GetSigningVolumeOptions = {
|
||||||
|
search?: string;
|
||||||
|
page?: number;
|
||||||
|
perPage?: number;
|
||||||
|
sortBy?: 'name' | 'createdAt' | 'signingVolume';
|
||||||
|
sortOrder?: 'asc' | 'desc';
|
||||||
|
};
|
||||||
|
|
||||||
|
export async function getSigningVolume({
|
||||||
|
search = '',
|
||||||
|
page = 1,
|
||||||
|
perPage = 10,
|
||||||
|
sortBy = 'signingVolume',
|
||||||
|
sortOrder = 'desc',
|
||||||
|
}: GetSigningVolumeOptions) {
|
||||||
|
const whereClause = Prisma.validator<Prisma.SubscriptionWhereInput>()({
|
||||||
|
status: 'ACTIVE',
|
||||||
|
OR: [
|
||||||
|
{
|
||||||
|
User: {
|
||||||
|
OR: [
|
||||||
|
{ name: { contains: search, mode: 'insensitive' } },
|
||||||
|
{ email: { contains: search, mode: 'insensitive' } },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
team: {
|
||||||
|
name: { contains: search, mode: 'insensitive' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
const orderByClause = getOrderByClause({ sortBy, sortOrder });
|
||||||
|
|
||||||
|
const [subscriptions, totalCount] = await Promise.all([
|
||||||
|
prisma.subscription.findMany({
|
||||||
|
where: whereClause,
|
||||||
|
include: {
|
||||||
|
User: {
|
||||||
|
include: {
|
||||||
|
Document: {
|
||||||
|
where: {
|
||||||
|
status: 'COMPLETED',
|
||||||
|
deletedAt: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
team: {
|
||||||
|
include: {
|
||||||
|
document: {
|
||||||
|
where: {
|
||||||
|
status: 'COMPLETED',
|
||||||
|
deletedAt: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
orderBy: orderByClause,
|
||||||
|
skip: Math.max(page - 1, 0) * perPage,
|
||||||
|
take: perPage,
|
||||||
|
}),
|
||||||
|
prisma.subscription.count({
|
||||||
|
where: whereClause,
|
||||||
|
}),
|
||||||
|
]);
|
||||||
|
|
||||||
|
const leaderboardWithVolume: SigningVolume[] = subscriptions.map((subscription) => {
|
||||||
|
const name =
|
||||||
|
subscription.User?.name || subscription.team?.name || subscription.User?.email || 'Unknown';
|
||||||
|
|
||||||
|
const userSignedDocs = subscription.User?.Document?.length || 0;
|
||||||
|
const teamSignedDocs = subscription.team?.document?.length || 0;
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: subscription.id,
|
||||||
|
name,
|
||||||
|
signingVolume: userSignedDocs + teamSignedDocs,
|
||||||
|
createdAt: subscription.createdAt,
|
||||||
|
planId: subscription.planId,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
leaderboard: leaderboardWithVolume,
|
||||||
|
totalPages: Math.ceil(totalCount / perPage),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function getOrderByClause(options: {
|
||||||
|
sortBy: string;
|
||||||
|
sortOrder: 'asc' | 'desc';
|
||||||
|
}): Prisma.SubscriptionOrderByWithRelationInput | Prisma.SubscriptionOrderByWithRelationInput[] {
|
||||||
|
const { sortBy, sortOrder } = options;
|
||||||
|
|
||||||
|
if (sortBy === 'name') {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
User: {
|
||||||
|
name: sortOrder,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
team: {
|
||||||
|
name: sortOrder,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sortBy === 'createdAt') {
|
||||||
|
return {
|
||||||
|
createdAt: sortOrder,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default: sort by signing volume
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
User: {
|
||||||
|
Document: {
|
||||||
|
_count: sortOrder,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
team: {
|
||||||
|
document: {
|
||||||
|
_count: sortOrder,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
@ -13,6 +13,7 @@ import { WebhookTriggerEvents } from '@documenso/prisma/client';
|
|||||||
|
|
||||||
import { jobs } from '../../jobs/client';
|
import { jobs } from '../../jobs/client';
|
||||||
import type { TRecipientActionAuth } from '../../types/document-auth';
|
import type { TRecipientActionAuth } from '../../types/document-auth';
|
||||||
|
import { ZWebhookDocumentSchema } from '../../types/webhook-payload';
|
||||||
import { getIsRecipientsTurnToSign } from '../recipient/get-is-recipient-turn';
|
import { getIsRecipientsTurnToSign } from '../recipient/get-is-recipient-turn';
|
||||||
import { triggerWebhook } from '../webhooks/trigger/trigger-webhook';
|
import { triggerWebhook } from '../webhooks/trigger/trigger-webhook';
|
||||||
import { sendPendingEmail } from './send-pending-email';
|
import { sendPendingEmail } from './send-pending-email';
|
||||||
@ -203,11 +204,19 @@ export const completeDocumentWithToken = async ({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const updatedDocument = await getDocument({ token, documentId });
|
const updatedDocument = await prisma.document.findFirstOrThrow({
|
||||||
|
where: {
|
||||||
|
id: document.id,
|
||||||
|
},
|
||||||
|
include: {
|
||||||
|
documentMeta: true,
|
||||||
|
Recipient: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
await triggerWebhook({
|
await triggerWebhook({
|
||||||
event: WebhookTriggerEvents.DOCUMENT_SIGNED,
|
event: WebhookTriggerEvents.DOCUMENT_SIGNED,
|
||||||
data: updatedDocument,
|
data: ZWebhookDocumentSchema.parse(updatedDocument),
|
||||||
userId: updatedDocument.userId,
|
userId: updatedDocument.userId,
|
||||||
teamId: updatedDocument.teamId ?? undefined,
|
teamId: updatedDocument.teamId ?? undefined,
|
||||||
});
|
});
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import { DocumentSource, DocumentVisibility, WebhookTriggerEvents } from '@docum
|
|||||||
import type { Team, TeamGlobalSettings } from '@documenso/prisma/client';
|
import type { Team, TeamGlobalSettings } from '@documenso/prisma/client';
|
||||||
import { TeamMemberRole } from '@documenso/prisma/client';
|
import { TeamMemberRole } from '@documenso/prisma/client';
|
||||||
|
|
||||||
|
import { ZWebhookDocumentSchema } from '../../types/webhook-payload';
|
||||||
import { triggerWebhook } from '../webhooks/trigger/trigger-webhook';
|
import { triggerWebhook } from '../webhooks/trigger/trigger-webhook';
|
||||||
|
|
||||||
export type CreateDocumentOptions = {
|
export type CreateDocumentOptions = {
|
||||||
@ -135,13 +136,27 @@ export const createDocument = async ({
|
|||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const createdDocument = await tx.document.findFirst({
|
||||||
|
where: {
|
||||||
|
id: document.id,
|
||||||
|
},
|
||||||
|
include: {
|
||||||
|
documentMeta: true,
|
||||||
|
Recipient: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!createdDocument) {
|
||||||
|
throw new Error('Document not found');
|
||||||
|
}
|
||||||
|
|
||||||
await triggerWebhook({
|
await triggerWebhook({
|
||||||
event: WebhookTriggerEvents.DOCUMENT_CREATED,
|
event: WebhookTriggerEvents.DOCUMENT_CREATED,
|
||||||
data: document,
|
data: ZWebhookDocumentSchema.parse(createdDocument),
|
||||||
userId,
|
userId,
|
||||||
teamId,
|
teamId,
|
||||||
});
|
});
|
||||||
|
|
||||||
return document;
|
return createdDocument;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@ -3,10 +3,13 @@ import { TRPCError } from '@trpc/server';
|
|||||||
|
|
||||||
import { jobs } from '@documenso/lib/jobs/client';
|
import { jobs } from '@documenso/lib/jobs/client';
|
||||||
import { prisma } from '@documenso/prisma';
|
import { prisma } from '@documenso/prisma';
|
||||||
|
import { WebhookTriggerEvents } from '@documenso/prisma/client';
|
||||||
|
|
||||||
import { DOCUMENT_AUDIT_LOG_TYPE } from '../../types/document-audit-logs';
|
import { DOCUMENT_AUDIT_LOG_TYPE } from '../../types/document-audit-logs';
|
||||||
|
import { ZWebhookDocumentSchema } from '../../types/webhook-payload';
|
||||||
import type { RequestMetadata } from '../../universal/extract-request-metadata';
|
import type { RequestMetadata } from '../../universal/extract-request-metadata';
|
||||||
import { createDocumentAuditLogData } from '../../utils/document-audit-logs';
|
import { createDocumentAuditLogData } from '../../utils/document-audit-logs';
|
||||||
|
import { triggerWebhook } from '../webhooks/trigger/trigger-webhook';
|
||||||
|
|
||||||
export type RejectDocumentWithTokenOptions = {
|
export type RejectDocumentWithTokenOptions = {
|
||||||
token: string;
|
token: string;
|
||||||
@ -31,6 +34,8 @@ export async function rejectDocumentWithToken({
|
|||||||
Document: {
|
Document: {
|
||||||
include: {
|
include: {
|
||||||
User: true,
|
User: true,
|
||||||
|
Recipient: true,
|
||||||
|
documentMeta: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -45,8 +50,6 @@ export async function rejectDocumentWithToken({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the audit log entry before updating the recipient
|
|
||||||
|
|
||||||
// Update the recipient status to rejected
|
// Update the recipient status to rejected
|
||||||
const [updatedRecipient] = await prisma.$transaction([
|
const [updatedRecipient] = await prisma.$transaction([
|
||||||
prisma.recipient.update({
|
prisma.recipient.update({
|
||||||
@ -88,5 +91,28 @@ export async function rejectDocumentWithToken({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Get the updated document with all recipients
|
||||||
|
const updatedDocument = await prisma.document.findFirst({
|
||||||
|
where: {
|
||||||
|
id: document.id,
|
||||||
|
},
|
||||||
|
include: {
|
||||||
|
Recipient: true,
|
||||||
|
documentMeta: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!updatedDocument) {
|
||||||
|
throw new Error('Document not found after update');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trigger webhook for document rejection
|
||||||
|
await triggerWebhook({
|
||||||
|
event: WebhookTriggerEvents.DOCUMENT_REJECTED,
|
||||||
|
data: ZWebhookDocumentSchema.parse(updatedDocument),
|
||||||
|
userId: document.userId,
|
||||||
|
teamId: document.teamId ?? undefined,
|
||||||
|
});
|
||||||
|
|
||||||
return updatedRecipient;
|
return updatedRecipient;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import { DocumentStatus, RecipientRole, SigningStatus } from '@documenso/prisma/
|
|||||||
import { WebhookTriggerEvents } from '@documenso/prisma/client';
|
import { WebhookTriggerEvents } from '@documenso/prisma/client';
|
||||||
import { signPdf } from '@documenso/signing';
|
import { signPdf } from '@documenso/signing';
|
||||||
|
|
||||||
|
import { ZWebhookDocumentSchema } from '../../types/webhook-payload';
|
||||||
import type { RequestMetadata } from '../../universal/extract-request-metadata';
|
import type { RequestMetadata } from '../../universal/extract-request-metadata';
|
||||||
import { getFile } from '../../universal/upload/get-file';
|
import { getFile } from '../../universal/upload/get-file';
|
||||||
import { putPdfFile } from '../../universal/upload/put-file';
|
import { putPdfFile } from '../../universal/upload/put-file';
|
||||||
@ -199,13 +200,14 @@ export const sealDocument = async ({
|
|||||||
},
|
},
|
||||||
include: {
|
include: {
|
||||||
documentData: true,
|
documentData: true,
|
||||||
|
documentMeta: true,
|
||||||
Recipient: true,
|
Recipient: true,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
await triggerWebhook({
|
await triggerWebhook({
|
||||||
event: WebhookTriggerEvents.DOCUMENT_COMPLETED,
|
event: WebhookTriggerEvents.DOCUMENT_COMPLETED,
|
||||||
data: updatedDocument,
|
data: ZWebhookDocumentSchema.parse(updatedDocument),
|
||||||
userId: document.userId,
|
userId: document.userId,
|
||||||
teamId: document.teamId ?? undefined,
|
teamId: document.teamId ?? undefined,
|
||||||
});
|
});
|
||||||
|
|||||||
@ -14,6 +14,7 @@ import { WebhookTriggerEvents } from '@documenso/prisma/client';
|
|||||||
|
|
||||||
import { jobs } from '../../jobs/client';
|
import { jobs } from '../../jobs/client';
|
||||||
import { extractDerivedDocumentEmailSettings } from '../../types/document-email';
|
import { extractDerivedDocumentEmailSettings } from '../../types/document-email';
|
||||||
|
import { ZWebhookDocumentSchema } from '../../types/webhook-payload';
|
||||||
import { getFile } from '../../universal/upload/get-file';
|
import { getFile } from '../../universal/upload/get-file';
|
||||||
import { insertFormValuesInPdf } from '../pdf/insert-form-values-in-pdf';
|
import { insertFormValuesInPdf } from '../pdf/insert-form-values-in-pdf';
|
||||||
import { triggerWebhook } from '../webhooks/trigger/trigger-webhook';
|
import { triggerWebhook } from '../webhooks/trigger/trigger-webhook';
|
||||||
@ -236,6 +237,7 @@ export const sendDocument = async ({
|
|||||||
status: DocumentStatus.PENDING,
|
status: DocumentStatus.PENDING,
|
||||||
},
|
},
|
||||||
include: {
|
include: {
|
||||||
|
documentMeta: true,
|
||||||
Recipient: true,
|
Recipient: true,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -243,7 +245,7 @@ export const sendDocument = async ({
|
|||||||
|
|
||||||
await triggerWebhook({
|
await triggerWebhook({
|
||||||
event: WebhookTriggerEvents.DOCUMENT_SENT,
|
event: WebhookTriggerEvents.DOCUMENT_SENT,
|
||||||
data: updatedDocument,
|
data: ZWebhookDocumentSchema.parse(updatedDocument),
|
||||||
userId,
|
userId,
|
||||||
teamId,
|
teamId,
|
||||||
});
|
});
|
||||||
|
|||||||
@ -6,8 +6,8 @@ import { ReadStatus } from '@documenso/prisma/client';
|
|||||||
import { WebhookTriggerEvents } from '@documenso/prisma/client';
|
import { WebhookTriggerEvents } from '@documenso/prisma/client';
|
||||||
|
|
||||||
import type { TDocumentAccessAuthTypes } from '../../types/document-auth';
|
import type { TDocumentAccessAuthTypes } from '../../types/document-auth';
|
||||||
|
import { ZWebhookDocumentSchema } from '../../types/webhook-payload';
|
||||||
import { triggerWebhook } from '../webhooks/trigger/trigger-webhook';
|
import { triggerWebhook } from '../webhooks/trigger/trigger-webhook';
|
||||||
import { getDocumentAndRecipientByToken } from './get-document-by-token';
|
|
||||||
|
|
||||||
export type ViewedDocumentOptions = {
|
export type ViewedDocumentOptions = {
|
||||||
token: string;
|
token: string;
|
||||||
@ -63,11 +63,23 @@ export const viewedDocument = async ({
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
const document = await getDocumentAndRecipientByToken({ token, requireAccessAuth: false });
|
const document = await prisma.document.findFirst({
|
||||||
|
where: {
|
||||||
|
id: documentId,
|
||||||
|
},
|
||||||
|
include: {
|
||||||
|
documentMeta: true,
|
||||||
|
Recipient: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!document) {
|
||||||
|
throw new Error('Document not found');
|
||||||
|
}
|
||||||
|
|
||||||
await triggerWebhook({
|
await triggerWebhook({
|
||||||
event: WebhookTriggerEvents.DOCUMENT_OPENED,
|
event: WebhookTriggerEvents.DOCUMENT_OPENED,
|
||||||
data: document,
|
data: ZWebhookDocumentSchema.parse(document),
|
||||||
userId: document.userId,
|
userId: document.userId,
|
||||||
teamId: document.teamId ?? undefined,
|
teamId: document.teamId ?? undefined,
|
||||||
});
|
});
|
||||||
|
|||||||
@ -31,6 +31,7 @@ import { DOCUMENT_AUDIT_LOG_TYPE } from '../../types/document-audit-logs';
|
|||||||
import type { TRecipientActionAuthTypes } from '../../types/document-auth';
|
import type { TRecipientActionAuthTypes } from '../../types/document-auth';
|
||||||
import { DocumentAccessAuth, ZRecipientAuthOptionsSchema } from '../../types/document-auth';
|
import { DocumentAccessAuth, ZRecipientAuthOptionsSchema } from '../../types/document-auth';
|
||||||
import { ZFieldMetaSchema } from '../../types/field-meta';
|
import { ZFieldMetaSchema } from '../../types/field-meta';
|
||||||
|
import { ZWebhookDocumentSchema } from '../../types/webhook-payload';
|
||||||
import type { RequestMetadata } from '../../universal/extract-request-metadata';
|
import type { RequestMetadata } from '../../universal/extract-request-metadata';
|
||||||
import type { CreateDocumentAuditLogDataResponse } from '../../utils/document-audit-logs';
|
import type { CreateDocumentAuditLogDataResponse } from '../../utils/document-audit-logs';
|
||||||
import { createDocumentAuditLogData } from '../../utils/document-audit-logs';
|
import { createDocumentAuditLogData } from '../../utils/document-audit-logs';
|
||||||
@ -591,7 +592,7 @@ export const createDocumentFromDirectTemplate = async ({
|
|||||||
requestMetadata,
|
requestMetadata,
|
||||||
});
|
});
|
||||||
|
|
||||||
const updatedDocument = await prisma.document.findFirstOrThrow({
|
const createdDocument = await prisma.document.findFirstOrThrow({
|
||||||
where: {
|
where: {
|
||||||
id: documentId,
|
id: documentId,
|
||||||
},
|
},
|
||||||
@ -603,9 +604,9 @@ export const createDocumentFromDirectTemplate = async ({
|
|||||||
|
|
||||||
await triggerWebhook({
|
await triggerWebhook({
|
||||||
event: WebhookTriggerEvents.DOCUMENT_SIGNED,
|
event: WebhookTriggerEvents.DOCUMENT_SIGNED,
|
||||||
data: updatedDocument,
|
data: ZWebhookDocumentSchema.parse(createdDocument),
|
||||||
userId: updatedDocument.userId,
|
userId: template.userId,
|
||||||
teamId: updatedDocument.teamId ?? undefined,
|
teamId: template.teamId ?? undefined,
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('[CREATE_DOCUMENT_FROM_DIRECT_TEMPLATE]:', err);
|
console.error('[CREATE_DOCUMENT_FROM_DIRECT_TEMPLATE]:', err);
|
||||||
|
|||||||
@ -18,6 +18,7 @@ import { DOCUMENT_AUDIT_LOG_TYPE } from '../../types/document-audit-logs';
|
|||||||
import { ZRecipientAuthOptionsSchema } from '../../types/document-auth';
|
import { ZRecipientAuthOptionsSchema } from '../../types/document-auth';
|
||||||
import type { TDocumentEmailSettings } from '../../types/document-email';
|
import type { TDocumentEmailSettings } from '../../types/document-email';
|
||||||
import { ZFieldMetaSchema } from '../../types/field-meta';
|
import { ZFieldMetaSchema } from '../../types/field-meta';
|
||||||
|
import { ZWebhookDocumentSchema } from '../../types/webhook-payload';
|
||||||
import type { RequestMetadata } from '../../universal/extract-request-metadata';
|
import type { RequestMetadata } from '../../universal/extract-request-metadata';
|
||||||
import { createDocumentAuditLogData } from '../../utils/document-audit-logs';
|
import { createDocumentAuditLogData } from '../../utils/document-audit-logs';
|
||||||
import {
|
import {
|
||||||
@ -291,9 +292,23 @@ export const createDocumentFromTemplate = async ({
|
|||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const createdDocument = await tx.document.findFirst({
|
||||||
|
where: {
|
||||||
|
id: document.id,
|
||||||
|
},
|
||||||
|
include: {
|
||||||
|
documentMeta: true,
|
||||||
|
Recipient: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!createdDocument) {
|
||||||
|
throw new Error('Document not found');
|
||||||
|
}
|
||||||
|
|
||||||
await triggerWebhook({
|
await triggerWebhook({
|
||||||
event: WebhookTriggerEvents.DOCUMENT_CREATED,
|
event: WebhookTriggerEvents.DOCUMENT_CREATED,
|
||||||
data: document,
|
data: ZWebhookDocumentSchema.parse(createdDocument),
|
||||||
userId,
|
userId,
|
||||||
teamId,
|
teamId,
|
||||||
});
|
});
|
||||||
|
|||||||
@ -60,14 +60,19 @@ msgstr "{0} von {1} Zeile(n) ausgewählt."
|
|||||||
|
|
||||||
#: packages/lib/jobs/definitions/emails/send-signing-email.ts:136
|
#: packages/lib/jobs/definitions/emails/send-signing-email.ts:136
|
||||||
#: packages/lib/server-only/document/resend-document.tsx:137
|
#: packages/lib/server-only/document/resend-document.tsx:137
|
||||||
msgid "{0} on behalf of {1} has invited you to {recipientActionVerb} the document \"{2}\"."
|
msgid "{0} on behalf of \"{1}\" has invited you to {recipientActionVerb} the document \"{2}\"."
|
||||||
msgstr "{0} hat dich im Namen von {1} eingeladen, das Dokument \"{2}\" {recipientActionVerb}."
|
msgstr ""
|
||||||
|
|
||||||
|
#: packages/lib/jobs/definitions/emails/send-signing-email.ts:136
|
||||||
|
#: packages/lib/server-only/document/resend-document.tsx:137
|
||||||
|
#~ msgid "{0} on behalf of {1} has invited you to {recipientActionVerb} the document \"{2}\"."
|
||||||
|
#~ msgstr "{0} hat dich im Namen von {1} eingeladen, das Dokument \"{2}\" {recipientActionVerb}."
|
||||||
|
|
||||||
#: packages/email/template-components/template-document-invite.tsx:51
|
#: packages/email/template-components/template-document-invite.tsx:51
|
||||||
#~ msgid "{0}<0/>\"{documentName}\""
|
#~ msgid "{0}<0/>\"{documentName}\""
|
||||||
#~ msgstr "{0}<0/>\"{documentName}\""
|
#~ msgstr "{0}<0/>\"{documentName}\""
|
||||||
|
|
||||||
#: packages/email/templates/document-invite.tsx:94
|
#: packages/email/templates/document-invite.tsx:95
|
||||||
msgid "{inviterName} <0>({inviterEmail})</0>"
|
msgid "{inviterName} <0>({inviterEmail})</0>"
|
||||||
msgstr "{inviterName} <0>({inviterEmail})</0>"
|
msgstr "{inviterName} <0>({inviterEmail})</0>"
|
||||||
|
|
||||||
@ -87,7 +92,7 @@ msgstr "{inviterName} hat dich eingeladen, {0}<0/>\"{documentName}\""
|
|||||||
msgid "{inviterName} has invited you to {action} {documentName}"
|
msgid "{inviterName} has invited you to {action} {documentName}"
|
||||||
msgstr "{inviterName} hat dich eingeladen, {action} {documentName}"
|
msgstr "{inviterName} hat dich eingeladen, {action} {documentName}"
|
||||||
|
|
||||||
#: packages/email/templates/document-invite.tsx:106
|
#: packages/email/templates/document-invite.tsx:108
|
||||||
msgid "{inviterName} has invited you to {action} the document \"{documentName}\"."
|
msgid "{inviterName} has invited you to {action} the document \"{documentName}\"."
|
||||||
msgstr "{inviterName} hat Sie eingeladen, das Dokument \"{documentName}\" {action}."
|
msgstr "{inviterName} hat Sie eingeladen, das Dokument \"{documentName}\" {action}."
|
||||||
|
|
||||||
@ -100,16 +105,24 @@ msgid "{inviterName} has removed you from the document<0/>\"{documentName}\""
|
|||||||
msgstr "{inviterName} hat dich aus dem Dokument<0/>\"{documentName}\" entfernt"
|
msgstr "{inviterName} hat dich aus dem Dokument<0/>\"{documentName}\" entfernt"
|
||||||
|
|
||||||
#: packages/email/template-components/template-document-invite.tsx:63
|
#: packages/email/template-components/template-document-invite.tsx:63
|
||||||
msgid "{inviterName} on behalf of {teamName} has invited you to {0}"
|
msgid "{inviterName} on behalf of \"{teamName}\" has invited you to {0}"
|
||||||
msgstr "{inviterName} im Namen von {teamName} hat Sie eingeladen, {0}"
|
msgstr ""
|
||||||
|
|
||||||
|
#: packages/email/templates/document-invite.tsx:45
|
||||||
|
msgid "{inviterName} on behalf of \"{teamName}\" has invited you to {action} {documentName}"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: packages/email/template-components/template-document-invite.tsx:63
|
||||||
|
#~ msgid "{inviterName} on behalf of {teamName} has invited you to {0}"
|
||||||
|
#~ msgstr "{inviterName} im Namen von {teamName} hat Sie eingeladen, {0}"
|
||||||
|
|
||||||
#: packages/email/template-components/template-document-invite.tsx:49
|
#: packages/email/template-components/template-document-invite.tsx:49
|
||||||
#~ msgid "{inviterName} on behalf of {teamName} has invited you to {0}<0/>\"{documentName}\""
|
#~ msgid "{inviterName} on behalf of {teamName} has invited you to {0}<0/>\"{documentName}\""
|
||||||
#~ msgstr "{inviterName} on behalf of {teamName} has invited you to {0}<0/>\"{documentName}\""
|
#~ msgstr "{inviterName} on behalf of {teamName} has invited you to {0}<0/>\"{documentName}\""
|
||||||
|
|
||||||
#: packages/email/templates/document-invite.tsx:45
|
#: packages/email/templates/document-invite.tsx:45
|
||||||
msgid "{inviterName} on behalf of {teamName} has invited you to {action} {documentName}"
|
#~ msgid "{inviterName} on behalf of {teamName} has invited you to {action} {documentName}"
|
||||||
msgstr "{inviterName} hat dich im Namen von {teamName} eingeladen, {action} {documentName}"
|
#~ msgstr "{inviterName} hat dich im Namen von {teamName} eingeladen, {action} {documentName}"
|
||||||
|
|
||||||
#: packages/email/templates/team-join.tsx:67
|
#: packages/email/templates/team-join.tsx:67
|
||||||
msgid "{memberEmail} joined the following team"
|
msgid "{memberEmail} joined the following team"
|
||||||
@ -568,7 +581,7 @@ msgstr "Unterschrift löschen"
|
|||||||
|
|
||||||
#: packages/ui/primitives/document-flow/add-signature.tsx:394
|
#: packages/ui/primitives/document-flow/add-signature.tsx:394
|
||||||
msgid "Click to insert field"
|
msgid "Click to insert field"
|
||||||
msgstr "Klicken, um das Feld einzufügen"
|
msgstr "Klicken, um das Feld auszufüllen"
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/missing-signature-field-dialog.tsx:44
|
#: packages/ui/primitives/document-flow/missing-signature-field-dialog.tsx:44
|
||||||
msgid "Close"
|
msgid "Close"
|
||||||
@ -711,7 +724,7 @@ msgid "Document created"
|
|||||||
msgstr "Dokument erstellt"
|
msgstr "Dokument erstellt"
|
||||||
|
|
||||||
#: packages/email/templates/document-created-from-direct-template.tsx:32
|
#: packages/email/templates/document-created-from-direct-template.tsx:32
|
||||||
#: packages/lib/server-only/template/create-document-from-direct-template.ts:573
|
#: packages/lib/server-only/template/create-document-from-direct-template.ts:574
|
||||||
msgid "Document created from direct template"
|
msgid "Document created from direct template"
|
||||||
msgstr "Dokument erstellt aus direkter Vorlage"
|
msgstr "Dokument erstellt aus direkter Vorlage"
|
||||||
|
|
||||||
|
|||||||
@ -51,16 +51,16 @@ msgstr "\"{placeholderEmail}\" im Namen von \"{0}\" hat Sie eingeladen, \"Beispi
|
|||||||
#~ msgstr "\"{teamUrl}\" hat Sie eingeladen, \"Beispieldokument\" zu unterschreiben."
|
#~ msgstr "\"{teamUrl}\" hat Sie eingeladen, \"Beispieldokument\" zu unterschreiben."
|
||||||
|
|
||||||
#: apps/web/src/app/(signing)/sign/[token]/signing-page-view.tsx:83
|
#: apps/web/src/app/(signing)/sign/[token]/signing-page-view.tsx:83
|
||||||
msgid "({0}) has invited you to approve this document"
|
#~ msgid "({0}) has invited you to approve this document"
|
||||||
msgstr "({0}) hat dich eingeladen, dieses Dokument zu genehmigen"
|
#~ msgstr "({0}) hat dich eingeladen, dieses Dokument zu genehmigen"
|
||||||
|
|
||||||
#: apps/web/src/app/(signing)/sign/[token]/signing-page-view.tsx:80
|
#: apps/web/src/app/(signing)/sign/[token]/signing-page-view.tsx:80
|
||||||
msgid "({0}) has invited you to sign this document"
|
#~ msgid "({0}) has invited you to sign this document"
|
||||||
msgstr "({0}) hat dich eingeladen, dieses Dokument zu unterzeichnen"
|
#~ msgstr "({0}) hat dich eingeladen, dieses Dokument zu unterzeichnen"
|
||||||
|
|
||||||
#: apps/web/src/app/(signing)/sign/[token]/signing-page-view.tsx:77
|
#: apps/web/src/app/(signing)/sign/[token]/signing-page-view.tsx:77
|
||||||
msgid "({0}) has invited you to view this document"
|
#~ msgid "({0}) has invited you to view this document"
|
||||||
msgstr "({0}) hat dich eingeladen, dieses Dokument zu betrachten"
|
#~ msgstr "({0}) hat dich eingeladen, dieses Dokument zu betrachten"
|
||||||
|
|
||||||
#: apps/web/src/app/(signing)/sign/[token]/text-field.tsx:313
|
#: apps/web/src/app/(signing)/sign/[token]/text-field.tsx:313
|
||||||
msgid "{0, plural, one {(1 character over)} other {(# characters over)}}"
|
msgid "{0, plural, one {(1 character over)} other {(# characters over)}}"
|
||||||
@ -944,7 +944,7 @@ msgstr "Klicken Sie, um den Signatur-Link zu kopieren, um ihn an den Empfänger
|
|||||||
#: apps/web/src/app/embed/direct/[[...url]]/client.tsx:456
|
#: apps/web/src/app/embed/direct/[[...url]]/client.tsx:456
|
||||||
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:335
|
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:335
|
||||||
msgid "Click to insert field"
|
msgid "Click to insert field"
|
||||||
msgstr "Klicken Sie, um das Feld einzufügen"
|
msgstr "Klicken Sie, um das Feld auszufüllen"
|
||||||
|
|
||||||
#: apps/web/src/app/(dashboard)/templates/new-template-dialog.tsx:126
|
#: apps/web/src/app/(dashboard)/templates/new-template-dialog.tsx:126
|
||||||
#: apps/web/src/app/(dashboard)/templates/use-template-dialog.tsx:389
|
#: apps/web/src/app/(dashboard)/templates/use-template-dialog.tsx:389
|
||||||
@ -964,7 +964,7 @@ msgstr "Schließen"
|
|||||||
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:325
|
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:325
|
||||||
#: apps/web/src/components/forms/v2/signup.tsx:534
|
#: apps/web/src/components/forms/v2/signup.tsx:534
|
||||||
msgid "Complete"
|
msgid "Complete"
|
||||||
msgstr "Vollständig"
|
msgstr "Abschließen"
|
||||||
|
|
||||||
#: apps/web/src/app/(signing)/sign/[token]/sign-dialog.tsx:69
|
#: apps/web/src/app/(signing)/sign/[token]/sign-dialog.tsx:69
|
||||||
msgid "Complete Approval"
|
msgid "Complete Approval"
|
||||||
@ -1206,6 +1206,7 @@ msgid "Create your account and start using state-of-the-art document signing. Op
|
|||||||
msgstr "Erstellen Sie Ihr Konto und beginnen Sie mit dem modernen Dokumentensignieren. Offenes und schönes Signieren liegt in Ihrer Reichweite."
|
msgstr "Erstellen Sie Ihr Konto und beginnen Sie mit dem modernen Dokumentensignieren. Offenes und schönes Signieren liegt in Ihrer Reichweite."
|
||||||
|
|
||||||
#: apps/web/src/app/(dashboard)/admin/documents/document-results.tsx:62
|
#: apps/web/src/app/(dashboard)/admin/documents/document-results.tsx:62
|
||||||
|
#: apps/web/src/app/(dashboard)/admin/leaderboard/data-table-leaderboard.tsx:96
|
||||||
#: apps/web/src/app/(dashboard)/documents/[id]/document-page-view-information.tsx:35
|
#: apps/web/src/app/(dashboard)/documents/[id]/document-page-view-information.tsx:35
|
||||||
#: apps/web/src/app/(dashboard)/documents/data-table.tsx:54
|
#: apps/web/src/app/(dashboard)/documents/data-table.tsx:54
|
||||||
#: apps/web/src/app/(dashboard)/settings/security/passkeys/user-passkeys-data-table.tsx:65
|
#: apps/web/src/app/(dashboard)/settings/security/passkeys/user-passkeys-data-table.tsx:65
|
||||||
@ -1245,6 +1246,11 @@ msgstr "Aktuelles Passwort"
|
|||||||
msgid "Current plan: {0}"
|
msgid "Current plan: {0}"
|
||||||
msgstr "Aktueller Plan: {0}"
|
msgstr "Aktueller Plan: {0}"
|
||||||
|
|
||||||
|
#: apps/web/src/app/(dashboard)/admin/leaderboard/data-table-leaderboard.tsx:94
|
||||||
|
#: apps/web/src/app/(dashboard)/admin/leaderboard/leaderboard-table.tsx:94
|
||||||
|
#~ msgid "Customer Type"
|
||||||
|
#~ msgstr ""
|
||||||
|
|
||||||
#: apps/web/src/app/(dashboard)/settings/billing/billing-plans.tsx:28
|
#: apps/web/src/app/(dashboard)/settings/billing/billing-plans.tsx:28
|
||||||
msgid "Daily"
|
msgid "Daily"
|
||||||
msgstr "Täglich"
|
msgstr "Täglich"
|
||||||
@ -1988,6 +1994,18 @@ msgstr "Zum Eigentümer gehen"
|
|||||||
msgid "Go to your <0>public profile settings</0> to add documents."
|
msgid "Go to your <0>public profile settings</0> to add documents."
|
||||||
msgstr "Gehen Sie zu Ihren <0>öffentlichen Profileinstellungen</0>, um Dokumente hinzuzufügen."
|
msgstr "Gehen Sie zu Ihren <0>öffentlichen Profileinstellungen</0>, um Dokumente hinzuzufügen."
|
||||||
|
|
||||||
|
#: apps/web/src/app/(signing)/sign/[token]/signing-page-view.tsx:107
|
||||||
|
msgid "has invited you to approve this document"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: apps/web/src/app/(signing)/sign/[token]/signing-page-view.tsx:98
|
||||||
|
msgid "has invited you to sign this document"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: apps/web/src/app/(signing)/sign/[token]/signing-page-view.tsx:89
|
||||||
|
msgid "has invited you to view this document"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: apps/web/src/app/(dashboard)/settings/profile/page.tsx:29
|
#: apps/web/src/app/(dashboard)/settings/profile/page.tsx:29
|
||||||
msgid "Here you can edit your personal details."
|
msgid "Here you can edit your personal details."
|
||||||
msgstr "Hier können Sie Ihre persönlichen Daten bearbeiten."
|
msgstr "Hier können Sie Ihre persönlichen Daten bearbeiten."
|
||||||
@ -2204,6 +2222,10 @@ msgstr "Zuletzt aktualisiert am"
|
|||||||
msgid "Last used"
|
msgid "Last used"
|
||||||
msgstr "Zuletzt verwendet"
|
msgstr "Zuletzt verwendet"
|
||||||
|
|
||||||
|
#: apps/web/src/app/(dashboard)/admin/nav.tsx:93
|
||||||
|
msgid "Leaderboard"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: apps/web/src/components/(teams)/dialogs/leave-team-dialog.tsx:111
|
#: apps/web/src/components/(teams)/dialogs/leave-team-dialog.tsx:111
|
||||||
#: apps/web/src/components/(teams)/tables/current-user-teams-data-table.tsx:117
|
#: apps/web/src/components/(teams)/tables/current-user-teams-data-table.tsx:117
|
||||||
msgid "Leave"
|
msgid "Leave"
|
||||||
@ -2411,6 +2433,7 @@ msgid "My templates"
|
|||||||
msgstr "Meine Vorlagen"
|
msgstr "Meine Vorlagen"
|
||||||
|
|
||||||
#: apps/web/src/app/(dashboard)/admin/documents/[id]/recipient-item.tsx:148
|
#: apps/web/src/app/(dashboard)/admin/documents/[id]/recipient-item.tsx:148
|
||||||
|
#: apps/web/src/app/(dashboard)/admin/leaderboard/data-table-leaderboard.tsx:56
|
||||||
#: apps/web/src/app/(dashboard)/admin/users/[id]/page.tsx:99
|
#: apps/web/src/app/(dashboard)/admin/users/[id]/page.tsx:99
|
||||||
#: apps/web/src/app/(dashboard)/admin/users/data-table-users.tsx:66
|
#: apps/web/src/app/(dashboard)/admin/users/data-table-users.tsx:66
|
||||||
#: apps/web/src/app/(dashboard)/settings/security/passkeys/user-passkeys-data-table-actions.tsx:144
|
#: apps/web/src/app/(dashboard)/settings/security/passkeys/user-passkeys-data-table-actions.tsx:144
|
||||||
@ -2524,6 +2547,18 @@ msgstr "Nichts zu tun"
|
|||||||
msgid "Number"
|
msgid "Number"
|
||||||
msgstr "Nummer"
|
msgstr "Nummer"
|
||||||
|
|
||||||
|
#: apps/web/src/app/(signing)/sign/[token]/signing-page-view.tsx:103
|
||||||
|
msgid "on behalf of \"{0}\" has invited you to approve this document"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: apps/web/src/app/(signing)/sign/[token]/signing-page-view.tsx:94
|
||||||
|
msgid "on behalf of \"{0}\" has invited you to sign this document"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: apps/web/src/app/(signing)/sign/[token]/signing-page-view.tsx:85
|
||||||
|
msgid "on behalf of \"{0}\" has invited you to view this document"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: apps/web/src/components/(dashboard)/settings/webhooks/create-webhook-dialog.tsx:128
|
#: apps/web/src/components/(dashboard)/settings/webhooks/create-webhook-dialog.tsx:128
|
||||||
msgid "On this page, you can create a new webhook."
|
msgid "On this page, you can create a new webhook."
|
||||||
msgstr "Auf dieser Seite können Sie einen neuen Webhook erstellen."
|
msgstr "Auf dieser Seite können Sie einen neuen Webhook erstellen."
|
||||||
@ -3105,6 +3140,7 @@ msgstr "Suchen"
|
|||||||
msgid "Search by document title"
|
msgid "Search by document title"
|
||||||
msgstr "Nach Dokumenttitel suchen"
|
msgstr "Nach Dokumenttitel suchen"
|
||||||
|
|
||||||
|
#: apps/web/src/app/(dashboard)/admin/leaderboard/data-table-leaderboard.tsx:147
|
||||||
#: apps/web/src/app/(dashboard)/admin/users/data-table-users.tsx:144
|
#: apps/web/src/app/(dashboard)/admin/users/data-table-users.tsx:144
|
||||||
msgid "Search by name or email"
|
msgid "Search by name or email"
|
||||||
msgstr "Nach Name oder E-Mail suchen"
|
msgstr "Nach Name oder E-Mail suchen"
|
||||||
@ -3369,6 +3405,11 @@ msgstr "Unterzeichnungslinks wurden für dieses Dokument erstellt."
|
|||||||
msgid "Signing up..."
|
msgid "Signing up..."
|
||||||
msgstr "Registrierung..."
|
msgstr "Registrierung..."
|
||||||
|
|
||||||
|
#: apps/web/src/app/(dashboard)/admin/leaderboard/data-table-leaderboard.tsx:82
|
||||||
|
#: apps/web/src/app/(dashboard)/admin/leaderboard/page.tsx:46
|
||||||
|
msgid "Signing Volume"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: apps/web/src/app/(profile)/p/[url]/page.tsx:109
|
#: apps/web/src/app/(profile)/p/[url]/page.tsx:109
|
||||||
msgid "Since {0}"
|
msgid "Since {0}"
|
||||||
msgstr "Seit {0}"
|
msgstr "Seit {0}"
|
||||||
@ -3377,7 +3418,7 @@ msgstr "Seit {0}"
|
|||||||
msgid "Site Banner"
|
msgid "Site Banner"
|
||||||
msgstr "Website Banner"
|
msgstr "Website Banner"
|
||||||
|
|
||||||
#: apps/web/src/app/(dashboard)/admin/nav.tsx:93
|
#: apps/web/src/app/(dashboard)/admin/nav.tsx:107
|
||||||
#: apps/web/src/app/(dashboard)/admin/site-settings/page.tsx:26
|
#: apps/web/src/app/(dashboard)/admin/site-settings/page.tsx:26
|
||||||
msgid "Site Settings"
|
msgid "Site Settings"
|
||||||
msgstr "Website Einstellungen"
|
msgstr "Website Einstellungen"
|
||||||
|
|||||||
@ -55,14 +55,19 @@ msgstr "{0} of {1} row(s) selected."
|
|||||||
|
|
||||||
#: packages/lib/jobs/definitions/emails/send-signing-email.ts:136
|
#: packages/lib/jobs/definitions/emails/send-signing-email.ts:136
|
||||||
#: packages/lib/server-only/document/resend-document.tsx:137
|
#: packages/lib/server-only/document/resend-document.tsx:137
|
||||||
msgid "{0} on behalf of {1} has invited you to {recipientActionVerb} the document \"{2}\"."
|
msgid "{0} on behalf of \"{1}\" has invited you to {recipientActionVerb} the document \"{2}\"."
|
||||||
msgstr "{0} on behalf of {1} has invited you to {recipientActionVerb} the document \"{2}\"."
|
msgstr "{0} on behalf of \"{1}\" has invited you to {recipientActionVerb} the document \"{2}\"."
|
||||||
|
|
||||||
|
#: packages/lib/jobs/definitions/emails/send-signing-email.ts:136
|
||||||
|
#: packages/lib/server-only/document/resend-document.tsx:137
|
||||||
|
#~ msgid "{0} on behalf of {1} has invited you to {recipientActionVerb} the document \"{2}\"."
|
||||||
|
#~ msgstr "{0} on behalf of {1} has invited you to {recipientActionVerb} the document \"{2}\"."
|
||||||
|
|
||||||
#: packages/email/template-components/template-document-invite.tsx:51
|
#: packages/email/template-components/template-document-invite.tsx:51
|
||||||
#~ msgid "{0}<0/>\"{documentName}\""
|
#~ msgid "{0}<0/>\"{documentName}\""
|
||||||
#~ msgstr "{0}<0/>\"{documentName}\""
|
#~ msgstr "{0}<0/>\"{documentName}\""
|
||||||
|
|
||||||
#: packages/email/templates/document-invite.tsx:94
|
#: packages/email/templates/document-invite.tsx:95
|
||||||
msgid "{inviterName} <0>({inviterEmail})</0>"
|
msgid "{inviterName} <0>({inviterEmail})</0>"
|
||||||
msgstr "{inviterName} <0>({inviterEmail})</0>"
|
msgstr "{inviterName} <0>({inviterEmail})</0>"
|
||||||
|
|
||||||
@ -82,7 +87,7 @@ msgstr "{inviterName} has invited you to {0}<0/>\"{documentName}\""
|
|||||||
msgid "{inviterName} has invited you to {action} {documentName}"
|
msgid "{inviterName} has invited you to {action} {documentName}"
|
||||||
msgstr "{inviterName} has invited you to {action} {documentName}"
|
msgstr "{inviterName} has invited you to {action} {documentName}"
|
||||||
|
|
||||||
#: packages/email/templates/document-invite.tsx:106
|
#: packages/email/templates/document-invite.tsx:108
|
||||||
msgid "{inviterName} has invited you to {action} the document \"{documentName}\"."
|
msgid "{inviterName} has invited you to {action} the document \"{documentName}\"."
|
||||||
msgstr "{inviterName} has invited you to {action} the document \"{documentName}\"."
|
msgstr "{inviterName} has invited you to {action} the document \"{documentName}\"."
|
||||||
|
|
||||||
@ -95,16 +100,24 @@ msgid "{inviterName} has removed you from the document<0/>\"{documentName}\""
|
|||||||
msgstr "{inviterName} has removed you from the document<0/>\"{documentName}\""
|
msgstr "{inviterName} has removed you from the document<0/>\"{documentName}\""
|
||||||
|
|
||||||
#: packages/email/template-components/template-document-invite.tsx:63
|
#: packages/email/template-components/template-document-invite.tsx:63
|
||||||
msgid "{inviterName} on behalf of {teamName} has invited you to {0}"
|
msgid "{inviterName} on behalf of \"{teamName}\" has invited you to {0}"
|
||||||
msgstr "{inviterName} on behalf of {teamName} has invited you to {0}"
|
msgstr "{inviterName} on behalf of \"{teamName}\" has invited you to {0}"
|
||||||
|
|
||||||
|
#: packages/email/templates/document-invite.tsx:45
|
||||||
|
msgid "{inviterName} on behalf of \"{teamName}\" has invited you to {action} {documentName}"
|
||||||
|
msgstr "{inviterName} on behalf of \"{teamName}\" has invited you to {action} {documentName}"
|
||||||
|
|
||||||
|
#: packages/email/template-components/template-document-invite.tsx:63
|
||||||
|
#~ msgid "{inviterName} on behalf of {teamName} has invited you to {0}"
|
||||||
|
#~ msgstr "{inviterName} on behalf of {teamName} has invited you to {0}"
|
||||||
|
|
||||||
#: packages/email/template-components/template-document-invite.tsx:49
|
#: packages/email/template-components/template-document-invite.tsx:49
|
||||||
#~ msgid "{inviterName} on behalf of {teamName} has invited you to {0}<0/>\"{documentName}\""
|
#~ msgid "{inviterName} on behalf of {teamName} has invited you to {0}<0/>\"{documentName}\""
|
||||||
#~ msgstr "{inviterName} on behalf of {teamName} has invited you to {0}<0/>\"{documentName}\""
|
#~ msgstr "{inviterName} on behalf of {teamName} has invited you to {0}<0/>\"{documentName}\""
|
||||||
|
|
||||||
#: packages/email/templates/document-invite.tsx:45
|
#: packages/email/templates/document-invite.tsx:45
|
||||||
msgid "{inviterName} on behalf of {teamName} has invited you to {action} {documentName}"
|
#~ msgid "{inviterName} on behalf of {teamName} has invited you to {action} {documentName}"
|
||||||
msgstr "{inviterName} on behalf of {teamName} has invited you to {action} {documentName}"
|
#~ msgstr "{inviterName} on behalf of {teamName} has invited you to {action} {documentName}"
|
||||||
|
|
||||||
#: packages/email/templates/team-join.tsx:67
|
#: packages/email/templates/team-join.tsx:67
|
||||||
msgid "{memberEmail} joined the following team"
|
msgid "{memberEmail} joined the following team"
|
||||||
@ -706,7 +719,7 @@ msgid "Document created"
|
|||||||
msgstr "Document created"
|
msgstr "Document created"
|
||||||
|
|
||||||
#: packages/email/templates/document-created-from-direct-template.tsx:32
|
#: packages/email/templates/document-created-from-direct-template.tsx:32
|
||||||
#: packages/lib/server-only/template/create-document-from-direct-template.ts:573
|
#: packages/lib/server-only/template/create-document-from-direct-template.ts:574
|
||||||
msgid "Document created from direct template"
|
msgid "Document created from direct template"
|
||||||
msgstr "Document created from direct template"
|
msgstr "Document created from direct template"
|
||||||
|
|
||||||
|
|||||||
@ -46,16 +46,16 @@ msgstr "\"{placeholderEmail}\" on behalf of \"{0}\" has invited you to sign \"ex
|
|||||||
#~ msgstr "\"{teamUrl}\" has invited you to sign \"example document\"."
|
#~ msgstr "\"{teamUrl}\" has invited you to sign \"example document\"."
|
||||||
|
|
||||||
#: apps/web/src/app/(signing)/sign/[token]/signing-page-view.tsx:83
|
#: apps/web/src/app/(signing)/sign/[token]/signing-page-view.tsx:83
|
||||||
msgid "({0}) has invited you to approve this document"
|
#~ msgid "({0}) has invited you to approve this document"
|
||||||
msgstr "({0}) has invited you to approve this document"
|
#~ msgstr "({0}) has invited you to approve this document"
|
||||||
|
|
||||||
#: apps/web/src/app/(signing)/sign/[token]/signing-page-view.tsx:80
|
#: apps/web/src/app/(signing)/sign/[token]/signing-page-view.tsx:80
|
||||||
msgid "({0}) has invited you to sign this document"
|
#~ msgid "({0}) has invited you to sign this document"
|
||||||
msgstr "({0}) has invited you to sign this document"
|
#~ msgstr "({0}) has invited you to sign this document"
|
||||||
|
|
||||||
#: apps/web/src/app/(signing)/sign/[token]/signing-page-view.tsx:77
|
#: apps/web/src/app/(signing)/sign/[token]/signing-page-view.tsx:77
|
||||||
msgid "({0}) has invited you to view this document"
|
#~ msgid "({0}) has invited you to view this document"
|
||||||
msgstr "({0}) has invited you to view this document"
|
#~ msgstr "({0}) has invited you to view this document"
|
||||||
|
|
||||||
#: apps/web/src/app/(signing)/sign/[token]/text-field.tsx:313
|
#: apps/web/src/app/(signing)/sign/[token]/text-field.tsx:313
|
||||||
msgid "{0, plural, one {(1 character over)} other {(# characters over)}}"
|
msgid "{0, plural, one {(1 character over)} other {(# characters over)}}"
|
||||||
@ -1201,6 +1201,7 @@ msgid "Create your account and start using state-of-the-art document signing. Op
|
|||||||
msgstr "Create your account and start using state-of-the-art document signing. Open and beautiful signing is within your grasp."
|
msgstr "Create your account and start using state-of-the-art document signing. Open and beautiful signing is within your grasp."
|
||||||
|
|
||||||
#: apps/web/src/app/(dashboard)/admin/documents/document-results.tsx:62
|
#: apps/web/src/app/(dashboard)/admin/documents/document-results.tsx:62
|
||||||
|
#: apps/web/src/app/(dashboard)/admin/leaderboard/data-table-leaderboard.tsx:96
|
||||||
#: apps/web/src/app/(dashboard)/documents/[id]/document-page-view-information.tsx:35
|
#: apps/web/src/app/(dashboard)/documents/[id]/document-page-view-information.tsx:35
|
||||||
#: apps/web/src/app/(dashboard)/documents/data-table.tsx:54
|
#: apps/web/src/app/(dashboard)/documents/data-table.tsx:54
|
||||||
#: apps/web/src/app/(dashboard)/settings/security/passkeys/user-passkeys-data-table.tsx:65
|
#: apps/web/src/app/(dashboard)/settings/security/passkeys/user-passkeys-data-table.tsx:65
|
||||||
@ -1240,6 +1241,11 @@ msgstr "Current Password"
|
|||||||
msgid "Current plan: {0}"
|
msgid "Current plan: {0}"
|
||||||
msgstr "Current plan: {0}"
|
msgstr "Current plan: {0}"
|
||||||
|
|
||||||
|
#: apps/web/src/app/(dashboard)/admin/leaderboard/data-table-leaderboard.tsx:94
|
||||||
|
#: apps/web/src/app/(dashboard)/admin/leaderboard/leaderboard-table.tsx:94
|
||||||
|
#~ msgid "Customer Type"
|
||||||
|
#~ msgstr "Customer Type"
|
||||||
|
|
||||||
#: apps/web/src/app/(dashboard)/settings/billing/billing-plans.tsx:28
|
#: apps/web/src/app/(dashboard)/settings/billing/billing-plans.tsx:28
|
||||||
msgid "Daily"
|
msgid "Daily"
|
||||||
msgstr "Daily"
|
msgstr "Daily"
|
||||||
@ -1983,6 +1989,18 @@ msgstr "Go to owner"
|
|||||||
msgid "Go to your <0>public profile settings</0> to add documents."
|
msgid "Go to your <0>public profile settings</0> to add documents."
|
||||||
msgstr "Go to your <0>public profile settings</0> to add documents."
|
msgstr "Go to your <0>public profile settings</0> to add documents."
|
||||||
|
|
||||||
|
#: apps/web/src/app/(signing)/sign/[token]/signing-page-view.tsx:107
|
||||||
|
msgid "has invited you to approve this document"
|
||||||
|
msgstr "has invited you to approve this document"
|
||||||
|
|
||||||
|
#: apps/web/src/app/(signing)/sign/[token]/signing-page-view.tsx:98
|
||||||
|
msgid "has invited you to sign this document"
|
||||||
|
msgstr "has invited you to sign this document"
|
||||||
|
|
||||||
|
#: apps/web/src/app/(signing)/sign/[token]/signing-page-view.tsx:89
|
||||||
|
msgid "has invited you to view this document"
|
||||||
|
msgstr "has invited you to view this document"
|
||||||
|
|
||||||
#: apps/web/src/app/(dashboard)/settings/profile/page.tsx:29
|
#: apps/web/src/app/(dashboard)/settings/profile/page.tsx:29
|
||||||
msgid "Here you can edit your personal details."
|
msgid "Here you can edit your personal details."
|
||||||
msgstr "Here you can edit your personal details."
|
msgstr "Here you can edit your personal details."
|
||||||
@ -2199,6 +2217,10 @@ msgstr "Last updated at"
|
|||||||
msgid "Last used"
|
msgid "Last used"
|
||||||
msgstr "Last used"
|
msgstr "Last used"
|
||||||
|
|
||||||
|
#: apps/web/src/app/(dashboard)/admin/nav.tsx:93
|
||||||
|
msgid "Leaderboard"
|
||||||
|
msgstr "Leaderboard"
|
||||||
|
|
||||||
#: apps/web/src/components/(teams)/dialogs/leave-team-dialog.tsx:111
|
#: apps/web/src/components/(teams)/dialogs/leave-team-dialog.tsx:111
|
||||||
#: apps/web/src/components/(teams)/tables/current-user-teams-data-table.tsx:117
|
#: apps/web/src/components/(teams)/tables/current-user-teams-data-table.tsx:117
|
||||||
msgid "Leave"
|
msgid "Leave"
|
||||||
@ -2406,6 +2428,7 @@ msgid "My templates"
|
|||||||
msgstr "My templates"
|
msgstr "My templates"
|
||||||
|
|
||||||
#: apps/web/src/app/(dashboard)/admin/documents/[id]/recipient-item.tsx:148
|
#: apps/web/src/app/(dashboard)/admin/documents/[id]/recipient-item.tsx:148
|
||||||
|
#: apps/web/src/app/(dashboard)/admin/leaderboard/data-table-leaderboard.tsx:56
|
||||||
#: apps/web/src/app/(dashboard)/admin/users/[id]/page.tsx:99
|
#: apps/web/src/app/(dashboard)/admin/users/[id]/page.tsx:99
|
||||||
#: apps/web/src/app/(dashboard)/admin/users/data-table-users.tsx:66
|
#: apps/web/src/app/(dashboard)/admin/users/data-table-users.tsx:66
|
||||||
#: apps/web/src/app/(dashboard)/settings/security/passkeys/user-passkeys-data-table-actions.tsx:144
|
#: apps/web/src/app/(dashboard)/settings/security/passkeys/user-passkeys-data-table-actions.tsx:144
|
||||||
@ -2519,6 +2542,18 @@ msgstr "Nothing to do"
|
|||||||
msgid "Number"
|
msgid "Number"
|
||||||
msgstr "Number"
|
msgstr "Number"
|
||||||
|
|
||||||
|
#: apps/web/src/app/(signing)/sign/[token]/signing-page-view.tsx:103
|
||||||
|
msgid "on behalf of \"{0}\" has invited you to approve this document"
|
||||||
|
msgstr "on behalf of \"{0}\" has invited you to approve this document"
|
||||||
|
|
||||||
|
#: apps/web/src/app/(signing)/sign/[token]/signing-page-view.tsx:94
|
||||||
|
msgid "on behalf of \"{0}\" has invited you to sign this document"
|
||||||
|
msgstr "on behalf of \"{0}\" has invited you to sign this document"
|
||||||
|
|
||||||
|
#: apps/web/src/app/(signing)/sign/[token]/signing-page-view.tsx:85
|
||||||
|
msgid "on behalf of \"{0}\" has invited you to view this document"
|
||||||
|
msgstr "on behalf of \"{0}\" has invited you to view this document"
|
||||||
|
|
||||||
#: apps/web/src/components/(dashboard)/settings/webhooks/create-webhook-dialog.tsx:128
|
#: apps/web/src/components/(dashboard)/settings/webhooks/create-webhook-dialog.tsx:128
|
||||||
msgid "On this page, you can create a new webhook."
|
msgid "On this page, you can create a new webhook."
|
||||||
msgstr "On this page, you can create a new webhook."
|
msgstr "On this page, you can create a new webhook."
|
||||||
@ -3100,6 +3135,7 @@ msgstr "Search"
|
|||||||
msgid "Search by document title"
|
msgid "Search by document title"
|
||||||
msgstr "Search by document title"
|
msgstr "Search by document title"
|
||||||
|
|
||||||
|
#: apps/web/src/app/(dashboard)/admin/leaderboard/data-table-leaderboard.tsx:147
|
||||||
#: apps/web/src/app/(dashboard)/admin/users/data-table-users.tsx:144
|
#: apps/web/src/app/(dashboard)/admin/users/data-table-users.tsx:144
|
||||||
msgid "Search by name or email"
|
msgid "Search by name or email"
|
||||||
msgstr "Search by name or email"
|
msgstr "Search by name or email"
|
||||||
@ -3364,6 +3400,11 @@ msgstr "Signing links have been generated for this document."
|
|||||||
msgid "Signing up..."
|
msgid "Signing up..."
|
||||||
msgstr "Signing up..."
|
msgstr "Signing up..."
|
||||||
|
|
||||||
|
#: apps/web/src/app/(dashboard)/admin/leaderboard/data-table-leaderboard.tsx:82
|
||||||
|
#: apps/web/src/app/(dashboard)/admin/leaderboard/page.tsx:46
|
||||||
|
msgid "Signing Volume"
|
||||||
|
msgstr "Signing Volume"
|
||||||
|
|
||||||
#: apps/web/src/app/(profile)/p/[url]/page.tsx:109
|
#: apps/web/src/app/(profile)/p/[url]/page.tsx:109
|
||||||
msgid "Since {0}"
|
msgid "Since {0}"
|
||||||
msgstr "Since {0}"
|
msgstr "Since {0}"
|
||||||
@ -3372,7 +3413,7 @@ msgstr "Since {0}"
|
|||||||
msgid "Site Banner"
|
msgid "Site Banner"
|
||||||
msgstr "Site Banner"
|
msgstr "Site Banner"
|
||||||
|
|
||||||
#: apps/web/src/app/(dashboard)/admin/nav.tsx:93
|
#: apps/web/src/app/(dashboard)/admin/nav.tsx:107
|
||||||
#: apps/web/src/app/(dashboard)/admin/site-settings/page.tsx:26
|
#: apps/web/src/app/(dashboard)/admin/site-settings/page.tsx:26
|
||||||
msgid "Site Settings"
|
msgid "Site Settings"
|
||||||
msgstr "Site Settings"
|
msgstr "Site Settings"
|
||||||
|
|||||||
@ -60,14 +60,19 @@ msgstr "{0} de {1} fila(s) seleccionada."
|
|||||||
|
|
||||||
#: packages/lib/jobs/definitions/emails/send-signing-email.ts:136
|
#: packages/lib/jobs/definitions/emails/send-signing-email.ts:136
|
||||||
#: packages/lib/server-only/document/resend-document.tsx:137
|
#: packages/lib/server-only/document/resend-document.tsx:137
|
||||||
msgid "{0} on behalf of {1} has invited you to {recipientActionVerb} the document \"{2}\"."
|
msgid "{0} on behalf of \"{1}\" has invited you to {recipientActionVerb} the document \"{2}\"."
|
||||||
msgstr "{0} en nombre de {1} te ha invitado a {recipientActionVerb} el documento \"{2}\"."
|
msgstr ""
|
||||||
|
|
||||||
|
#: packages/lib/jobs/definitions/emails/send-signing-email.ts:136
|
||||||
|
#: packages/lib/server-only/document/resend-document.tsx:137
|
||||||
|
#~ msgid "{0} on behalf of {1} has invited you to {recipientActionVerb} the document \"{2}\"."
|
||||||
|
#~ msgstr "{0} en nombre de {1} te ha invitado a {recipientActionVerb} el documento \"{2}\"."
|
||||||
|
|
||||||
#: packages/email/template-components/template-document-invite.tsx:51
|
#: packages/email/template-components/template-document-invite.tsx:51
|
||||||
#~ msgid "{0}<0/>\"{documentName}\""
|
#~ msgid "{0}<0/>\"{documentName}\""
|
||||||
#~ msgstr "{0}<0/>\"{documentName}\""
|
#~ msgstr "{0}<0/>\"{documentName}\""
|
||||||
|
|
||||||
#: packages/email/templates/document-invite.tsx:94
|
#: packages/email/templates/document-invite.tsx:95
|
||||||
msgid "{inviterName} <0>({inviterEmail})</0>"
|
msgid "{inviterName} <0>({inviterEmail})</0>"
|
||||||
msgstr "{inviterName} <0>({inviterEmail})</0>"
|
msgstr "{inviterName} <0>({inviterEmail})</0>"
|
||||||
|
|
||||||
@ -87,7 +92,7 @@ msgstr "{inviterName} te ha invitado a {0}<0/>\"{documentName}\""
|
|||||||
msgid "{inviterName} has invited you to {action} {documentName}"
|
msgid "{inviterName} has invited you to {action} {documentName}"
|
||||||
msgstr "{inviterName} te ha invitado a {action} {documentName}"
|
msgstr "{inviterName} te ha invitado a {action} {documentName}"
|
||||||
|
|
||||||
#: packages/email/templates/document-invite.tsx:106
|
#: packages/email/templates/document-invite.tsx:108
|
||||||
msgid "{inviterName} has invited you to {action} the document \"{documentName}\"."
|
msgid "{inviterName} has invited you to {action} the document \"{documentName}\"."
|
||||||
msgstr "{inviterName} te ha invitado a {action} el documento \"{documentName}\"."
|
msgstr "{inviterName} te ha invitado a {action} el documento \"{documentName}\"."
|
||||||
|
|
||||||
@ -100,16 +105,24 @@ msgid "{inviterName} has removed you from the document<0/>\"{documentName}\""
|
|||||||
msgstr "{inviterName} te ha eliminado del documento<0/>\"{documentName}\""
|
msgstr "{inviterName} te ha eliminado del documento<0/>\"{documentName}\""
|
||||||
|
|
||||||
#: packages/email/template-components/template-document-invite.tsx:63
|
#: packages/email/template-components/template-document-invite.tsx:63
|
||||||
msgid "{inviterName} on behalf of {teamName} has invited you to {0}"
|
msgid "{inviterName} on behalf of \"{teamName}\" has invited you to {0}"
|
||||||
msgstr "{inviterName} en nombre de {teamName} te ha invitado a {0}"
|
msgstr ""
|
||||||
|
|
||||||
|
#: packages/email/templates/document-invite.tsx:45
|
||||||
|
msgid "{inviterName} on behalf of \"{teamName}\" has invited you to {action} {documentName}"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: packages/email/template-components/template-document-invite.tsx:63
|
||||||
|
#~ msgid "{inviterName} on behalf of {teamName} has invited you to {0}"
|
||||||
|
#~ msgstr "{inviterName} en nombre de {teamName} te ha invitado a {0}"
|
||||||
|
|
||||||
#: packages/email/template-components/template-document-invite.tsx:49
|
#: packages/email/template-components/template-document-invite.tsx:49
|
||||||
#~ msgid "{inviterName} on behalf of {teamName} has invited you to {0}<0/>\"{documentName}\""
|
#~ msgid "{inviterName} on behalf of {teamName} has invited you to {0}<0/>\"{documentName}\""
|
||||||
#~ msgstr "{inviterName} on behalf of {teamName} has invited you to {0}<0/>\"{documentName}\""
|
#~ msgstr "{inviterName} on behalf of {teamName} has invited you to {0}<0/>\"{documentName}\""
|
||||||
|
|
||||||
#: packages/email/templates/document-invite.tsx:45
|
#: packages/email/templates/document-invite.tsx:45
|
||||||
msgid "{inviterName} on behalf of {teamName} has invited you to {action} {documentName}"
|
#~ msgid "{inviterName} on behalf of {teamName} has invited you to {action} {documentName}"
|
||||||
msgstr "{inviterName} en nombre de {teamName} te ha invitado a {action} {documentName}"
|
#~ msgstr "{inviterName} en nombre de {teamName} te ha invitado a {action} {documentName}"
|
||||||
|
|
||||||
#: packages/email/templates/team-join.tsx:67
|
#: packages/email/templates/team-join.tsx:67
|
||||||
msgid "{memberEmail} joined the following team"
|
msgid "{memberEmail} joined the following team"
|
||||||
@ -711,7 +724,7 @@ msgid "Document created"
|
|||||||
msgstr "Documento creado"
|
msgstr "Documento creado"
|
||||||
|
|
||||||
#: packages/email/templates/document-created-from-direct-template.tsx:32
|
#: packages/email/templates/document-created-from-direct-template.tsx:32
|
||||||
#: packages/lib/server-only/template/create-document-from-direct-template.ts:573
|
#: packages/lib/server-only/template/create-document-from-direct-template.ts:574
|
||||||
msgid "Document created from direct template"
|
msgid "Document created from direct template"
|
||||||
msgstr "Documento creado a partir de plantilla directa"
|
msgstr "Documento creado a partir de plantilla directa"
|
||||||
|
|
||||||
|
|||||||
@ -51,16 +51,16 @@ msgstr "\"{placeholderEmail}\" en nombre de \"{0}\" te ha invitado a firmar \"do
|
|||||||
#~ msgstr "\"{teamUrl}\" te ha invitado a firmar \"ejemplo de documento\"."
|
#~ msgstr "\"{teamUrl}\" te ha invitado a firmar \"ejemplo de documento\"."
|
||||||
|
|
||||||
#: apps/web/src/app/(signing)/sign/[token]/signing-page-view.tsx:83
|
#: apps/web/src/app/(signing)/sign/[token]/signing-page-view.tsx:83
|
||||||
msgid "({0}) has invited you to approve this document"
|
#~ msgid "({0}) has invited you to approve this document"
|
||||||
msgstr "({0}) te ha invitado a aprobar este documento"
|
#~ msgstr "({0}) te ha invitado a aprobar este documento"
|
||||||
|
|
||||||
#: apps/web/src/app/(signing)/sign/[token]/signing-page-view.tsx:80
|
#: apps/web/src/app/(signing)/sign/[token]/signing-page-view.tsx:80
|
||||||
msgid "({0}) has invited you to sign this document"
|
#~ msgid "({0}) has invited you to sign this document"
|
||||||
msgstr "({0}) te ha invitado a firmar este documento"
|
#~ msgstr "({0}) te ha invitado a firmar este documento"
|
||||||
|
|
||||||
#: apps/web/src/app/(signing)/sign/[token]/signing-page-view.tsx:77
|
#: apps/web/src/app/(signing)/sign/[token]/signing-page-view.tsx:77
|
||||||
msgid "({0}) has invited you to view this document"
|
#~ msgid "({0}) has invited you to view this document"
|
||||||
msgstr "({0}) te ha invitado a ver este documento"
|
#~ msgstr "({0}) te ha invitado a ver este documento"
|
||||||
|
|
||||||
#: apps/web/src/app/(signing)/sign/[token]/text-field.tsx:313
|
#: apps/web/src/app/(signing)/sign/[token]/text-field.tsx:313
|
||||||
msgid "{0, plural, one {(1 character over)} other {(# characters over)}}"
|
msgid "{0, plural, one {(1 character over)} other {(# characters over)}}"
|
||||||
@ -1206,6 +1206,7 @@ msgid "Create your account and start using state-of-the-art document signing. Op
|
|||||||
msgstr "Crea tu cuenta y comienza a utilizar la firma de documentos de última generación. La firma abierta y hermosa está al alcance de tu mano."
|
msgstr "Crea tu cuenta y comienza a utilizar la firma de documentos de última generación. La firma abierta y hermosa está al alcance de tu mano."
|
||||||
|
|
||||||
#: apps/web/src/app/(dashboard)/admin/documents/document-results.tsx:62
|
#: apps/web/src/app/(dashboard)/admin/documents/document-results.tsx:62
|
||||||
|
#: apps/web/src/app/(dashboard)/admin/leaderboard/data-table-leaderboard.tsx:96
|
||||||
#: apps/web/src/app/(dashboard)/documents/[id]/document-page-view-information.tsx:35
|
#: apps/web/src/app/(dashboard)/documents/[id]/document-page-view-information.tsx:35
|
||||||
#: apps/web/src/app/(dashboard)/documents/data-table.tsx:54
|
#: apps/web/src/app/(dashboard)/documents/data-table.tsx:54
|
||||||
#: apps/web/src/app/(dashboard)/settings/security/passkeys/user-passkeys-data-table.tsx:65
|
#: apps/web/src/app/(dashboard)/settings/security/passkeys/user-passkeys-data-table.tsx:65
|
||||||
@ -1988,6 +1989,18 @@ msgstr "Ir al propietario"
|
|||||||
msgid "Go to your <0>public profile settings</0> to add documents."
|
msgid "Go to your <0>public profile settings</0> to add documents."
|
||||||
msgstr "Ve a tu <0>configuración de perfil público</0> para agregar documentos."
|
msgstr "Ve a tu <0>configuración de perfil público</0> para agregar documentos."
|
||||||
|
|
||||||
|
#: apps/web/src/app/(signing)/sign/[token]/signing-page-view.tsx:107
|
||||||
|
msgid "has invited you to approve this document"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: apps/web/src/app/(signing)/sign/[token]/signing-page-view.tsx:98
|
||||||
|
msgid "has invited you to sign this document"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: apps/web/src/app/(signing)/sign/[token]/signing-page-view.tsx:89
|
||||||
|
msgid "has invited you to view this document"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: apps/web/src/app/(dashboard)/settings/profile/page.tsx:29
|
#: apps/web/src/app/(dashboard)/settings/profile/page.tsx:29
|
||||||
msgid "Here you can edit your personal details."
|
msgid "Here you can edit your personal details."
|
||||||
msgstr "Aquí puedes editar tus datos personales."
|
msgstr "Aquí puedes editar tus datos personales."
|
||||||
@ -2204,6 +2217,10 @@ msgstr "Última actualización el"
|
|||||||
msgid "Last used"
|
msgid "Last used"
|
||||||
msgstr "Último uso"
|
msgstr "Último uso"
|
||||||
|
|
||||||
|
#: apps/web/src/app/(dashboard)/admin/nav.tsx:93
|
||||||
|
msgid "Leaderboard"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: apps/web/src/components/(teams)/dialogs/leave-team-dialog.tsx:111
|
#: apps/web/src/components/(teams)/dialogs/leave-team-dialog.tsx:111
|
||||||
#: apps/web/src/components/(teams)/tables/current-user-teams-data-table.tsx:117
|
#: apps/web/src/components/(teams)/tables/current-user-teams-data-table.tsx:117
|
||||||
msgid "Leave"
|
msgid "Leave"
|
||||||
@ -2411,6 +2428,7 @@ msgid "My templates"
|
|||||||
msgstr "Mis plantillas"
|
msgstr "Mis plantillas"
|
||||||
|
|
||||||
#: apps/web/src/app/(dashboard)/admin/documents/[id]/recipient-item.tsx:148
|
#: apps/web/src/app/(dashboard)/admin/documents/[id]/recipient-item.tsx:148
|
||||||
|
#: apps/web/src/app/(dashboard)/admin/leaderboard/data-table-leaderboard.tsx:56
|
||||||
#: apps/web/src/app/(dashboard)/admin/users/[id]/page.tsx:99
|
#: apps/web/src/app/(dashboard)/admin/users/[id]/page.tsx:99
|
||||||
#: apps/web/src/app/(dashboard)/admin/users/data-table-users.tsx:66
|
#: apps/web/src/app/(dashboard)/admin/users/data-table-users.tsx:66
|
||||||
#: apps/web/src/app/(dashboard)/settings/security/passkeys/user-passkeys-data-table-actions.tsx:144
|
#: apps/web/src/app/(dashboard)/settings/security/passkeys/user-passkeys-data-table-actions.tsx:144
|
||||||
@ -2524,6 +2542,18 @@ msgstr "Nada que hacer"
|
|||||||
msgid "Number"
|
msgid "Number"
|
||||||
msgstr "Número"
|
msgstr "Número"
|
||||||
|
|
||||||
|
#: apps/web/src/app/(signing)/sign/[token]/signing-page-view.tsx:103
|
||||||
|
msgid "on behalf of \"{0}\" has invited you to approve this document"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: apps/web/src/app/(signing)/sign/[token]/signing-page-view.tsx:94
|
||||||
|
msgid "on behalf of \"{0}\" has invited you to sign this document"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: apps/web/src/app/(signing)/sign/[token]/signing-page-view.tsx:85
|
||||||
|
msgid "on behalf of \"{0}\" has invited you to view this document"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: apps/web/src/components/(dashboard)/settings/webhooks/create-webhook-dialog.tsx:128
|
#: apps/web/src/components/(dashboard)/settings/webhooks/create-webhook-dialog.tsx:128
|
||||||
msgid "On this page, you can create a new webhook."
|
msgid "On this page, you can create a new webhook."
|
||||||
msgstr "En esta página, puedes crear un nuevo webhook."
|
msgstr "En esta página, puedes crear un nuevo webhook."
|
||||||
@ -3105,6 +3135,7 @@ msgstr "Buscar"
|
|||||||
msgid "Search by document title"
|
msgid "Search by document title"
|
||||||
msgstr "Buscar por título del documento"
|
msgstr "Buscar por título del documento"
|
||||||
|
|
||||||
|
#: apps/web/src/app/(dashboard)/admin/leaderboard/data-table-leaderboard.tsx:147
|
||||||
#: apps/web/src/app/(dashboard)/admin/users/data-table-users.tsx:144
|
#: apps/web/src/app/(dashboard)/admin/users/data-table-users.tsx:144
|
||||||
msgid "Search by name or email"
|
msgid "Search by name or email"
|
||||||
msgstr "Buscar por nombre o correo electrónico"
|
msgstr "Buscar por nombre o correo electrónico"
|
||||||
@ -3369,6 +3400,11 @@ msgstr "Se han generado enlaces de firma para este documento."
|
|||||||
msgid "Signing up..."
|
msgid "Signing up..."
|
||||||
msgstr "Registrándose..."
|
msgstr "Registrándose..."
|
||||||
|
|
||||||
|
#: apps/web/src/app/(dashboard)/admin/leaderboard/data-table-leaderboard.tsx:82
|
||||||
|
#: apps/web/src/app/(dashboard)/admin/leaderboard/page.tsx:46
|
||||||
|
msgid "Signing Volume"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: apps/web/src/app/(profile)/p/[url]/page.tsx:109
|
#: apps/web/src/app/(profile)/p/[url]/page.tsx:109
|
||||||
msgid "Since {0}"
|
msgid "Since {0}"
|
||||||
msgstr "Desde {0}"
|
msgstr "Desde {0}"
|
||||||
@ -3377,7 +3413,7 @@ msgstr "Desde {0}"
|
|||||||
msgid "Site Banner"
|
msgid "Site Banner"
|
||||||
msgstr "Banner del sitio"
|
msgstr "Banner del sitio"
|
||||||
|
|
||||||
#: apps/web/src/app/(dashboard)/admin/nav.tsx:93
|
#: apps/web/src/app/(dashboard)/admin/nav.tsx:107
|
||||||
#: apps/web/src/app/(dashboard)/admin/site-settings/page.tsx:26
|
#: apps/web/src/app/(dashboard)/admin/site-settings/page.tsx:26
|
||||||
msgid "Site Settings"
|
msgid "Site Settings"
|
||||||
msgstr "Configuraciones del sitio"
|
msgstr "Configuraciones del sitio"
|
||||||
|
|||||||
@ -60,14 +60,19 @@ msgstr "{0} sur {1} ligne(s) sélectionnée(s)."
|
|||||||
|
|
||||||
#: packages/lib/jobs/definitions/emails/send-signing-email.ts:136
|
#: packages/lib/jobs/definitions/emails/send-signing-email.ts:136
|
||||||
#: packages/lib/server-only/document/resend-document.tsx:137
|
#: packages/lib/server-only/document/resend-document.tsx:137
|
||||||
msgid "{0} on behalf of {1} has invited you to {recipientActionVerb} the document \"{2}\"."
|
msgid "{0} on behalf of \"{1}\" has invited you to {recipientActionVerb} the document \"{2}\"."
|
||||||
msgstr "{0} au nom de {1} vous a invité à {recipientActionVerb} le document \"{2}\"."
|
msgstr ""
|
||||||
|
|
||||||
|
#: packages/lib/jobs/definitions/emails/send-signing-email.ts:136
|
||||||
|
#: packages/lib/server-only/document/resend-document.tsx:137
|
||||||
|
#~ msgid "{0} on behalf of {1} has invited you to {recipientActionVerb} the document \"{2}\"."
|
||||||
|
#~ msgstr "{0} au nom de {1} vous a invité à {recipientActionVerb} le document \"{2}\"."
|
||||||
|
|
||||||
#: packages/email/template-components/template-document-invite.tsx:51
|
#: packages/email/template-components/template-document-invite.tsx:51
|
||||||
#~ msgid "{0}<0/>\"{documentName}\""
|
#~ msgid "{0}<0/>\"{documentName}\""
|
||||||
#~ msgstr "{0}<0/>\"{documentName}\""
|
#~ msgstr "{0}<0/>\"{documentName}\""
|
||||||
|
|
||||||
#: packages/email/templates/document-invite.tsx:94
|
#: packages/email/templates/document-invite.tsx:95
|
||||||
msgid "{inviterName} <0>({inviterEmail})</0>"
|
msgid "{inviterName} <0>({inviterEmail})</0>"
|
||||||
msgstr "{inviterName} <0>({inviterEmail})</0>"
|
msgstr "{inviterName} <0>({inviterEmail})</0>"
|
||||||
|
|
||||||
@ -87,7 +92,7 @@ msgstr "{inviterName} vous a invité à {0}<0/>\"{documentName}\""
|
|||||||
msgid "{inviterName} has invited you to {action} {documentName}"
|
msgid "{inviterName} has invited you to {action} {documentName}"
|
||||||
msgstr "{inviterName} vous a invité à {action} {documentName}"
|
msgstr "{inviterName} vous a invité à {action} {documentName}"
|
||||||
|
|
||||||
#: packages/email/templates/document-invite.tsx:106
|
#: packages/email/templates/document-invite.tsx:108
|
||||||
msgid "{inviterName} has invited you to {action} the document \"{documentName}\"."
|
msgid "{inviterName} has invited you to {action} the document \"{documentName}\"."
|
||||||
msgstr "{inviterName} vous a invité à {action} le document \"{documentName}\"."
|
msgstr "{inviterName} vous a invité à {action} le document \"{documentName}\"."
|
||||||
|
|
||||||
@ -100,16 +105,24 @@ msgid "{inviterName} has removed you from the document<0/>\"{documentName}\""
|
|||||||
msgstr "{inviterName} vous a retiré du document<0/>\"{documentName}\""
|
msgstr "{inviterName} vous a retiré du document<0/>\"{documentName}\""
|
||||||
|
|
||||||
#: packages/email/template-components/template-document-invite.tsx:63
|
#: packages/email/template-components/template-document-invite.tsx:63
|
||||||
msgid "{inviterName} on behalf of {teamName} has invited you to {0}"
|
msgid "{inviterName} on behalf of \"{teamName}\" has invited you to {0}"
|
||||||
msgstr "{inviterName} au nom de {teamName} vous a invité à {0}"
|
msgstr ""
|
||||||
|
|
||||||
|
#: packages/email/templates/document-invite.tsx:45
|
||||||
|
msgid "{inviterName} on behalf of \"{teamName}\" has invited you to {action} {documentName}"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: packages/email/template-components/template-document-invite.tsx:63
|
||||||
|
#~ msgid "{inviterName} on behalf of {teamName} has invited you to {0}"
|
||||||
|
#~ msgstr "{inviterName} au nom de {teamName} vous a invité à {0}"
|
||||||
|
|
||||||
#: packages/email/template-components/template-document-invite.tsx:49
|
#: packages/email/template-components/template-document-invite.tsx:49
|
||||||
#~ msgid "{inviterName} on behalf of {teamName} has invited you to {0}<0/>\"{documentName}\""
|
#~ msgid "{inviterName} on behalf of {teamName} has invited you to {0}<0/>\"{documentName}\""
|
||||||
#~ msgstr "{inviterName} on behalf of {teamName} has invited you to {0}<0/>\"{documentName}\""
|
#~ msgstr "{inviterName} on behalf of {teamName} has invited you to {0}<0/>\"{documentName}\""
|
||||||
|
|
||||||
#: packages/email/templates/document-invite.tsx:45
|
#: packages/email/templates/document-invite.tsx:45
|
||||||
msgid "{inviterName} on behalf of {teamName} has invited you to {action} {documentName}"
|
#~ msgid "{inviterName} on behalf of {teamName} has invited you to {action} {documentName}"
|
||||||
msgstr "{inviterName} au nom de {teamName} vous a invité à {action} {documentName}"
|
#~ msgstr "{inviterName} au nom de {teamName} vous a invité à {action} {documentName}"
|
||||||
|
|
||||||
#: packages/email/templates/team-join.tsx:67
|
#: packages/email/templates/team-join.tsx:67
|
||||||
msgid "{memberEmail} joined the following team"
|
msgid "{memberEmail} joined the following team"
|
||||||
@ -711,7 +724,7 @@ msgid "Document created"
|
|||||||
msgstr "Document créé"
|
msgstr "Document créé"
|
||||||
|
|
||||||
#: packages/email/templates/document-created-from-direct-template.tsx:32
|
#: packages/email/templates/document-created-from-direct-template.tsx:32
|
||||||
#: packages/lib/server-only/template/create-document-from-direct-template.ts:573
|
#: packages/lib/server-only/template/create-document-from-direct-template.ts:574
|
||||||
msgid "Document created from direct template"
|
msgid "Document created from direct template"
|
||||||
msgstr "Document créé à partir d'un modèle direct"
|
msgstr "Document créé à partir d'un modèle direct"
|
||||||
|
|
||||||
|
|||||||
@ -51,16 +51,16 @@ msgstr "\"{placeholderEmail}\" au nom de \"{0}\" vous a invité à signer \"exem
|
|||||||
#~ msgstr "\"{teamUrl}\" vous a invité à signer \"example document\"."
|
#~ msgstr "\"{teamUrl}\" vous a invité à signer \"example document\"."
|
||||||
|
|
||||||
#: apps/web/src/app/(signing)/sign/[token]/signing-page-view.tsx:83
|
#: apps/web/src/app/(signing)/sign/[token]/signing-page-view.tsx:83
|
||||||
msgid "({0}) has invited you to approve this document"
|
#~ msgid "({0}) has invited you to approve this document"
|
||||||
msgstr "({0}) vous a invité à approuver ce document"
|
#~ msgstr "({0}) vous a invité à approuver ce document"
|
||||||
|
|
||||||
#: apps/web/src/app/(signing)/sign/[token]/signing-page-view.tsx:80
|
#: apps/web/src/app/(signing)/sign/[token]/signing-page-view.tsx:80
|
||||||
msgid "({0}) has invited you to sign this document"
|
#~ msgid "({0}) has invited you to sign this document"
|
||||||
msgstr "({0}) vous a invité à signer ce document"
|
#~ msgstr "({0}) vous a invité à signer ce document"
|
||||||
|
|
||||||
#: apps/web/src/app/(signing)/sign/[token]/signing-page-view.tsx:77
|
#: apps/web/src/app/(signing)/sign/[token]/signing-page-view.tsx:77
|
||||||
msgid "({0}) has invited you to view this document"
|
#~ msgid "({0}) has invited you to view this document"
|
||||||
msgstr "({0}) vous a invité à consulter ce document"
|
#~ msgstr "({0}) vous a invité à consulter ce document"
|
||||||
|
|
||||||
#: apps/web/src/app/(signing)/sign/[token]/text-field.tsx:313
|
#: apps/web/src/app/(signing)/sign/[token]/text-field.tsx:313
|
||||||
msgid "{0, plural, one {(1 character over)} other {(# characters over)}}"
|
msgid "{0, plural, one {(1 character over)} other {(# characters over)}}"
|
||||||
@ -1206,6 +1206,7 @@ msgid "Create your account and start using state-of-the-art document signing. Op
|
|||||||
msgstr "Créez votre compte et commencez à utiliser la signature de documents à la pointe de la technologie. Une signature ouverte et magnifique est à votre portée."
|
msgstr "Créez votre compte et commencez à utiliser la signature de documents à la pointe de la technologie. Une signature ouverte et magnifique est à votre portée."
|
||||||
|
|
||||||
#: apps/web/src/app/(dashboard)/admin/documents/document-results.tsx:62
|
#: apps/web/src/app/(dashboard)/admin/documents/document-results.tsx:62
|
||||||
|
#: apps/web/src/app/(dashboard)/admin/leaderboard/data-table-leaderboard.tsx:96
|
||||||
#: apps/web/src/app/(dashboard)/documents/[id]/document-page-view-information.tsx:35
|
#: apps/web/src/app/(dashboard)/documents/[id]/document-page-view-information.tsx:35
|
||||||
#: apps/web/src/app/(dashboard)/documents/data-table.tsx:54
|
#: apps/web/src/app/(dashboard)/documents/data-table.tsx:54
|
||||||
#: apps/web/src/app/(dashboard)/settings/security/passkeys/user-passkeys-data-table.tsx:65
|
#: apps/web/src/app/(dashboard)/settings/security/passkeys/user-passkeys-data-table.tsx:65
|
||||||
@ -1988,6 +1989,18 @@ msgstr "Aller au propriétaire"
|
|||||||
msgid "Go to your <0>public profile settings</0> to add documents."
|
msgid "Go to your <0>public profile settings</0> to add documents."
|
||||||
msgstr "Allez à vos <0>paramètres de profil public</0> pour ajouter des documents."
|
msgstr "Allez à vos <0>paramètres de profil public</0> pour ajouter des documents."
|
||||||
|
|
||||||
|
#: apps/web/src/app/(signing)/sign/[token]/signing-page-view.tsx:107
|
||||||
|
msgid "has invited you to approve this document"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: apps/web/src/app/(signing)/sign/[token]/signing-page-view.tsx:98
|
||||||
|
msgid "has invited you to sign this document"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: apps/web/src/app/(signing)/sign/[token]/signing-page-view.tsx:89
|
||||||
|
msgid "has invited you to view this document"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: apps/web/src/app/(dashboard)/settings/profile/page.tsx:29
|
#: apps/web/src/app/(dashboard)/settings/profile/page.tsx:29
|
||||||
msgid "Here you can edit your personal details."
|
msgid "Here you can edit your personal details."
|
||||||
msgstr "Ici, vous pouvez modifier vos coordonnées personnelles."
|
msgstr "Ici, vous pouvez modifier vos coordonnées personnelles."
|
||||||
@ -2204,6 +2217,10 @@ msgstr "Dernière mise à jour à"
|
|||||||
msgid "Last used"
|
msgid "Last used"
|
||||||
msgstr "Dernière utilisation"
|
msgstr "Dernière utilisation"
|
||||||
|
|
||||||
|
#: apps/web/src/app/(dashboard)/admin/nav.tsx:93
|
||||||
|
msgid "Leaderboard"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: apps/web/src/components/(teams)/dialogs/leave-team-dialog.tsx:111
|
#: apps/web/src/components/(teams)/dialogs/leave-team-dialog.tsx:111
|
||||||
#: apps/web/src/components/(teams)/tables/current-user-teams-data-table.tsx:117
|
#: apps/web/src/components/(teams)/tables/current-user-teams-data-table.tsx:117
|
||||||
msgid "Leave"
|
msgid "Leave"
|
||||||
@ -2411,6 +2428,7 @@ msgid "My templates"
|
|||||||
msgstr "Mes modèles"
|
msgstr "Mes modèles"
|
||||||
|
|
||||||
#: apps/web/src/app/(dashboard)/admin/documents/[id]/recipient-item.tsx:148
|
#: apps/web/src/app/(dashboard)/admin/documents/[id]/recipient-item.tsx:148
|
||||||
|
#: apps/web/src/app/(dashboard)/admin/leaderboard/data-table-leaderboard.tsx:56
|
||||||
#: apps/web/src/app/(dashboard)/admin/users/[id]/page.tsx:99
|
#: apps/web/src/app/(dashboard)/admin/users/[id]/page.tsx:99
|
||||||
#: apps/web/src/app/(dashboard)/admin/users/data-table-users.tsx:66
|
#: apps/web/src/app/(dashboard)/admin/users/data-table-users.tsx:66
|
||||||
#: apps/web/src/app/(dashboard)/settings/security/passkeys/user-passkeys-data-table-actions.tsx:144
|
#: apps/web/src/app/(dashboard)/settings/security/passkeys/user-passkeys-data-table-actions.tsx:144
|
||||||
@ -2524,6 +2542,18 @@ msgstr "Rien à faire"
|
|||||||
msgid "Number"
|
msgid "Number"
|
||||||
msgstr "Numéro"
|
msgstr "Numéro"
|
||||||
|
|
||||||
|
#: apps/web/src/app/(signing)/sign/[token]/signing-page-view.tsx:103
|
||||||
|
msgid "on behalf of \"{0}\" has invited you to approve this document"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: apps/web/src/app/(signing)/sign/[token]/signing-page-view.tsx:94
|
||||||
|
msgid "on behalf of \"{0}\" has invited you to sign this document"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: apps/web/src/app/(signing)/sign/[token]/signing-page-view.tsx:85
|
||||||
|
msgid "on behalf of \"{0}\" has invited you to view this document"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: apps/web/src/components/(dashboard)/settings/webhooks/create-webhook-dialog.tsx:128
|
#: apps/web/src/components/(dashboard)/settings/webhooks/create-webhook-dialog.tsx:128
|
||||||
msgid "On this page, you can create a new webhook."
|
msgid "On this page, you can create a new webhook."
|
||||||
msgstr "Sur cette page, vous pouvez créer un nouveau webhook."
|
msgstr "Sur cette page, vous pouvez créer un nouveau webhook."
|
||||||
@ -3105,6 +3135,7 @@ msgstr "Recherche"
|
|||||||
msgid "Search by document title"
|
msgid "Search by document title"
|
||||||
msgstr "Recherche par titre de document"
|
msgstr "Recherche par titre de document"
|
||||||
|
|
||||||
|
#: apps/web/src/app/(dashboard)/admin/leaderboard/data-table-leaderboard.tsx:147
|
||||||
#: apps/web/src/app/(dashboard)/admin/users/data-table-users.tsx:144
|
#: apps/web/src/app/(dashboard)/admin/users/data-table-users.tsx:144
|
||||||
msgid "Search by name or email"
|
msgid "Search by name or email"
|
||||||
msgstr "Recherche par nom ou e-mail"
|
msgstr "Recherche par nom ou e-mail"
|
||||||
@ -3369,6 +3400,11 @@ msgstr "Des liens de signature ont été générés pour ce document."
|
|||||||
msgid "Signing up..."
|
msgid "Signing up..."
|
||||||
msgstr "Inscription en cours..."
|
msgstr "Inscription en cours..."
|
||||||
|
|
||||||
|
#: apps/web/src/app/(dashboard)/admin/leaderboard/data-table-leaderboard.tsx:82
|
||||||
|
#: apps/web/src/app/(dashboard)/admin/leaderboard/page.tsx:46
|
||||||
|
msgid "Signing Volume"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: apps/web/src/app/(profile)/p/[url]/page.tsx:109
|
#: apps/web/src/app/(profile)/p/[url]/page.tsx:109
|
||||||
msgid "Since {0}"
|
msgid "Since {0}"
|
||||||
msgstr "Depuis {0}"
|
msgstr "Depuis {0}"
|
||||||
@ -3377,7 +3413,7 @@ msgstr "Depuis {0}"
|
|||||||
msgid "Site Banner"
|
msgid "Site Banner"
|
||||||
msgstr "Bannière du site"
|
msgstr "Bannière du site"
|
||||||
|
|
||||||
#: apps/web/src/app/(dashboard)/admin/nav.tsx:93
|
#: apps/web/src/app/(dashboard)/admin/nav.tsx:107
|
||||||
#: apps/web/src/app/(dashboard)/admin/site-settings/page.tsx:26
|
#: apps/web/src/app/(dashboard)/admin/site-settings/page.tsx:26
|
||||||
msgid "Site Settings"
|
msgid "Site Settings"
|
||||||
msgstr "Paramètres du site"
|
msgstr "Paramètres du site"
|
||||||
|
|||||||
80
packages/lib/types/webhook-payload.ts
Normal file
80
packages/lib/types/webhook-payload.ts
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
import { z } from 'zod';
|
||||||
|
|
||||||
|
import {
|
||||||
|
DocumentDistributionMethod,
|
||||||
|
DocumentSigningOrder,
|
||||||
|
DocumentSource,
|
||||||
|
DocumentStatus,
|
||||||
|
DocumentVisibility,
|
||||||
|
ReadStatus,
|
||||||
|
RecipientRole,
|
||||||
|
SendStatus,
|
||||||
|
SigningStatus,
|
||||||
|
} from '@documenso/prisma/client';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Schema for recipient data in webhook payloads.
|
||||||
|
*/
|
||||||
|
export const ZWebhookRecipientSchema = z.object({
|
||||||
|
id: z.number(),
|
||||||
|
documentId: z.number().nullable(),
|
||||||
|
templateId: z.number().nullable(),
|
||||||
|
email: z.string(),
|
||||||
|
name: z.string(),
|
||||||
|
token: z.string(),
|
||||||
|
documentDeletedAt: z.date().nullable(),
|
||||||
|
expired: z.date().nullable(),
|
||||||
|
signedAt: z.date().nullable(),
|
||||||
|
authOptions: z.any().nullable(),
|
||||||
|
signingOrder: z.number().nullable(),
|
||||||
|
rejectionReason: z.string().nullable(),
|
||||||
|
role: z.nativeEnum(RecipientRole),
|
||||||
|
readStatus: z.nativeEnum(ReadStatus),
|
||||||
|
signingStatus: z.nativeEnum(SigningStatus),
|
||||||
|
sendStatus: z.nativeEnum(SendStatus),
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Schema for document meta in webhook payloads.
|
||||||
|
*/
|
||||||
|
export const ZWebhookDocumentMetaSchema = z.object({
|
||||||
|
id: z.string(),
|
||||||
|
subject: z.string().nullable(),
|
||||||
|
message: z.string().nullable(),
|
||||||
|
timezone: z.string(),
|
||||||
|
password: z.string().nullable(),
|
||||||
|
dateFormat: z.string(),
|
||||||
|
redirectUrl: z.string().nullable(),
|
||||||
|
signingOrder: z.nativeEnum(DocumentSigningOrder),
|
||||||
|
typedSignatureEnabled: z.boolean(),
|
||||||
|
language: z.string(),
|
||||||
|
distributionMethod: z.nativeEnum(DocumentDistributionMethod),
|
||||||
|
emailSettings: z.any().nullable(),
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Schema for document data in webhook payloads.
|
||||||
|
*/
|
||||||
|
export const ZWebhookDocumentSchema = z.object({
|
||||||
|
id: z.number(),
|
||||||
|
externalId: z.string().nullable(),
|
||||||
|
userId: z.number(),
|
||||||
|
authOptions: z.any().nullable(),
|
||||||
|
formValues: z.any().nullable(),
|
||||||
|
visibility: z.nativeEnum(DocumentVisibility),
|
||||||
|
title: z.string(),
|
||||||
|
status: z.nativeEnum(DocumentStatus),
|
||||||
|
documentDataId: z.string(),
|
||||||
|
createdAt: z.date(),
|
||||||
|
updatedAt: z.date(),
|
||||||
|
completedAt: z.date().nullable(),
|
||||||
|
deletedAt: z.date().nullable(),
|
||||||
|
teamId: z.number().nullable(),
|
||||||
|
templateId: z.number().nullable(),
|
||||||
|
source: z.nativeEnum(DocumentSource),
|
||||||
|
documentMeta: ZWebhookDocumentMetaSchema.nullable(),
|
||||||
|
Recipient: z.array(ZWebhookRecipientSchema),
|
||||||
|
});
|
||||||
|
|
||||||
|
export type TWebhookRecipient = z.infer<typeof ZWebhookRecipientSchema>;
|
||||||
|
export type TWebhookDocument = z.infer<typeof ZWebhookDocumentSchema>;
|
||||||
@ -0,0 +1,2 @@
|
|||||||
|
-- AlterEnum
|
||||||
|
ALTER TYPE "WebhookTriggerEvents" ADD VALUE 'DOCUMENT_REJECTED';
|
||||||
@ -162,6 +162,7 @@ enum WebhookTriggerEvents {
|
|||||||
DOCUMENT_OPENED
|
DOCUMENT_OPENED
|
||||||
DOCUMENT_SIGNED
|
DOCUMENT_SIGNED
|
||||||
DOCUMENT_COMPLETED
|
DOCUMENT_COMPLETED
|
||||||
|
DOCUMENT_REJECTED
|
||||||
}
|
}
|
||||||
|
|
||||||
model Webhook {
|
model Webhook {
|
||||||
|
|||||||
@ -6,7 +6,7 @@ import { useEffect, useMemo, useRef, useState } from 'react';
|
|||||||
import { Caveat } from 'next/font/google';
|
import { Caveat } from 'next/font/google';
|
||||||
|
|
||||||
import { Trans } from '@lingui/macro';
|
import { Trans } from '@lingui/macro';
|
||||||
import { Undo2 } from 'lucide-react';
|
import { Undo2, Upload } from 'lucide-react';
|
||||||
import type { StrokeOptions } from 'perfect-freehand';
|
import type { StrokeOptions } from 'perfect-freehand';
|
||||||
import { getStroke } from 'perfect-freehand';
|
import { getStroke } from 'perfect-freehand';
|
||||||
|
|
||||||
@ -33,6 +33,64 @@ const fontCaveat = Caveat({
|
|||||||
|
|
||||||
const DPI = 2;
|
const DPI = 2;
|
||||||
|
|
||||||
|
const isBase64Image = (value: string) => value.startsWith('data:image/png;base64,');
|
||||||
|
|
||||||
|
const loadImage = async (file: File | undefined): Promise<HTMLImageElement> => {
|
||||||
|
if (!file) {
|
||||||
|
throw new Error('No file selected');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!file.type.startsWith('image/')) {
|
||||||
|
throw new Error('Invalid file type');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file.size > 5 * 1024 * 1024) {
|
||||||
|
throw new Error('Image size should be less than 5MB');
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const img = new Image();
|
||||||
|
const objectUrl = URL.createObjectURL(file);
|
||||||
|
|
||||||
|
img.onload = () => {
|
||||||
|
URL.revokeObjectURL(objectUrl);
|
||||||
|
resolve(img);
|
||||||
|
};
|
||||||
|
|
||||||
|
img.onerror = () => {
|
||||||
|
URL.revokeObjectURL(objectUrl);
|
||||||
|
reject(new Error('Failed to load image'));
|
||||||
|
};
|
||||||
|
|
||||||
|
img.src = objectUrl;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const loadImageOntoCanvas = (
|
||||||
|
image: HTMLImageElement,
|
||||||
|
canvas: HTMLCanvasElement,
|
||||||
|
ctx: CanvasRenderingContext2D,
|
||||||
|
): ImageData => {
|
||||||
|
const scale = Math.min((canvas.width * 0.8) / image.width, (canvas.height * 0.8) / image.height);
|
||||||
|
|
||||||
|
const x = (canvas.width - image.width * scale) / 2;
|
||||||
|
const y = (canvas.height - image.height * scale) / 2;
|
||||||
|
|
||||||
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||||
|
|
||||||
|
ctx.save();
|
||||||
|
ctx.imageSmoothingEnabled = true;
|
||||||
|
ctx.imageSmoothingQuality = 'high';
|
||||||
|
|
||||||
|
ctx.drawImage(image, x, y, image.width * scale, image.height * scale);
|
||||||
|
|
||||||
|
ctx.restore();
|
||||||
|
|
||||||
|
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
|
||||||
|
|
||||||
|
return imageData;
|
||||||
|
};
|
||||||
|
|
||||||
export type SignaturePadProps = Omit<HTMLAttributes<HTMLCanvasElement>, 'onChange'> & {
|
export type SignaturePadProps = Omit<HTMLAttributes<HTMLCanvasElement>, 'onChange'> & {
|
||||||
onChange?: (_signatureDataUrl: string | null) => void;
|
onChange?: (_signatureDataUrl: string | null) => void;
|
||||||
containerClassName?: string;
|
containerClassName?: string;
|
||||||
@ -52,12 +110,15 @@ export const SignaturePad = ({
|
|||||||
}: SignaturePadProps) => {
|
}: SignaturePadProps) => {
|
||||||
const $el = useRef<HTMLCanvasElement>(null);
|
const $el = useRef<HTMLCanvasElement>(null);
|
||||||
const $imageData = useRef<ImageData | null>(null);
|
const $imageData = useRef<ImageData | null>(null);
|
||||||
|
const $fileInput = useRef<HTMLInputElement>(null);
|
||||||
|
|
||||||
const [isPressed, setIsPressed] = useState(false);
|
const [isPressed, setIsPressed] = useState(false);
|
||||||
const [lines, setLines] = useState<Point[][]>([]);
|
const [lines, setLines] = useState<Point[][]>([]);
|
||||||
const [currentLine, setCurrentLine] = useState<Point[]>([]);
|
const [currentLine, setCurrentLine] = useState<Point[]>([]);
|
||||||
const [selectedColor, setSelectedColor] = useState('black');
|
const [selectedColor, setSelectedColor] = useState('black');
|
||||||
const [typedSignature, setTypedSignature] = useState(defaultValue ?? '');
|
const [typedSignature, setTypedSignature] = useState(
|
||||||
|
defaultValue && !isBase64Image(defaultValue) ? defaultValue : '',
|
||||||
|
);
|
||||||
|
|
||||||
const perfectFreehandOptions = useMemo(() => {
|
const perfectFreehandOptions = useMemo(() => {
|
||||||
const size = $el.current ? Math.min($el.current.height, $el.current.width) * 0.03 : 10;
|
const size = $el.current ? Math.min($el.current.height, $el.current.width) * 0.03 : 10;
|
||||||
@ -80,6 +141,14 @@ export const SignaturePad = ({
|
|||||||
|
|
||||||
setIsPressed(true);
|
setIsPressed(true);
|
||||||
|
|
||||||
|
if (typedSignature) {
|
||||||
|
setTypedSignature('');
|
||||||
|
if ($el.current) {
|
||||||
|
const ctx = $el.current.getContext('2d');
|
||||||
|
ctx?.clearRect(0, 0, $el.current.width, $el.current.height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const point = Point.fromEvent(event, DPI, $el.current);
|
const point = Point.fromEvent(event, DPI, $el.current);
|
||||||
|
|
||||||
setCurrentLine([point]);
|
setCurrentLine([point]);
|
||||||
@ -193,6 +262,10 @@ export const SignaturePad = ({
|
|||||||
$imageData.current = null;
|
$imageData.current = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($fileInput.current) {
|
||||||
|
$fileInput.current.value = '';
|
||||||
|
}
|
||||||
|
|
||||||
onChange?.(null);
|
onChange?.(null);
|
||||||
|
|
||||||
setTypedSignature('');
|
setTypedSignature('');
|
||||||
@ -255,12 +328,30 @@ export const SignaturePad = ({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleImageUpload = async (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
try {
|
||||||
|
const img = await loadImage(event.target.files?.[0]);
|
||||||
|
|
||||||
|
if (!$el.current) return;
|
||||||
|
|
||||||
|
const ctx = $el.current.getContext('2d');
|
||||||
|
if (!ctx) return;
|
||||||
|
|
||||||
|
$imageData.current = loadImageOntoCanvas(img, $el.current, ctx);
|
||||||
|
onChange?.($el.current.toDataURL());
|
||||||
|
|
||||||
|
setLines([]);
|
||||||
|
setCurrentLine([]);
|
||||||
|
setTypedSignature('');
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (typedSignature.trim() !== '') {
|
if (typedSignature.trim() !== '' && !isBase64Image(typedSignature)) {
|
||||||
renderTypedSignature();
|
renderTypedSignature();
|
||||||
onChange?.(typedSignature);
|
onChange?.(typedSignature);
|
||||||
} else {
|
|
||||||
onClearClick();
|
|
||||||
}
|
}
|
||||||
}, [typedSignature, selectedColor]);
|
}, [typedSignature, selectedColor]);
|
||||||
|
|
||||||
@ -370,6 +461,26 @@ export const SignaturePad = ({
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
<div className="text-foreground absolute left-3 top-3 filter">
|
||||||
|
<div
|
||||||
|
className="focus-visible:ring-ring ring-offset-background text-muted-foreground/60 hover:text-muted-foreground flex cursor-pointer flex-row gap-2 rounded-full p-0 text-[0.688rem] focus-visible:outline-none focus-visible:ring-2"
|
||||||
|
onClick={() => $fileInput.current?.click()}
|
||||||
|
>
|
||||||
|
<Input
|
||||||
|
ref={$fileInput}
|
||||||
|
type="file"
|
||||||
|
accept="image/*"
|
||||||
|
className="hidden"
|
||||||
|
onChange={handleImageUpload}
|
||||||
|
disabled={disabled}
|
||||||
|
/>
|
||||||
|
<Upload className="h-4 w-4" />
|
||||||
|
<span>
|
||||||
|
<Trans>Upload Signature</Trans>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="text-foreground absolute right-2 top-2 filter">
|
<div className="text-foreground absolute right-2 top-2 filter">
|
||||||
<Select defaultValue={selectedColor} onValueChange={(value) => setSelectedColor(value)}>
|
<Select defaultValue={selectedColor} onValueChange={(value) => setSelectedColor(value)}>
|
||||||
<SelectTrigger className="h-auto w-auto border-none p-0.5">
|
<SelectTrigger className="h-auto w-auto border-none p-0.5">
|
||||||
|
|||||||
Reference in New Issue
Block a user