mirror of
https://github.com/documenso/documenso
synced 2026-04-21 13:27:18 +00:00
fix: resolve follow-up issues from oxlint migration
This commit is contained in:
parent
ae02169e97
commit
835c55e2ca
68 changed files with 433 additions and 430 deletions
|
|
@ -12,11 +12,14 @@
|
|||
"dependencies": {
|
||||
"@documenso/prisma": "*",
|
||||
"luxon": "^3.7.2",
|
||||
"next": "15.5.12"
|
||||
"next": "15.5.12",
|
||||
"react": "^18",
|
||||
"react-dom": "^18"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20",
|
||||
"@types/react": "18.3.27",
|
||||
"@types/react-dom": "^18",
|
||||
"typescript": "5.6.2"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
166
package-lock.json
generated
166
package-lock.json
generated
|
|
@ -39,6 +39,8 @@
|
|||
"@ts-rest/core": "^3.52.1",
|
||||
"@ts-rest/open-api": "^3.52.1",
|
||||
"@ts-rest/serverless": "^3.52.1",
|
||||
"@types/react": "18.3.27",
|
||||
"@types/react-dom": "^18",
|
||||
"dotenv": "^17.2.3",
|
||||
"dotenv-cli": "^11.0.0",
|
||||
"husky": "^9.1.7",
|
||||
|
|
@ -57,6 +59,7 @@
|
|||
"prisma-extension-kysely": "^3.0.0",
|
||||
"prisma-json-types-generator": "^3.6.2",
|
||||
"prisma-kysely": "^2.3.0",
|
||||
"react-dom": "^18",
|
||||
"rimraf": "^6.1.2",
|
||||
"superjson": "^2.2.5",
|
||||
"syncpack": "^14.0.0-alpha.27",
|
||||
|
|
@ -100,6 +103,26 @@
|
|||
"typescript": "^5.9.3"
|
||||
}
|
||||
},
|
||||
"apps/docs/node_modules/@types/react": {
|
||||
"version": "19.2.14",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz",
|
||||
"integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"csstype": "^3.2.2"
|
||||
}
|
||||
},
|
||||
"apps/docs/node_modules/@types/react-dom": {
|
||||
"version": "19.2.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz",
|
||||
"integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@types/react": "^19.2.0"
|
||||
}
|
||||
},
|
||||
"apps/docs/node_modules/react": {
|
||||
"version": "19.2.4",
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz",
|
||||
|
|
@ -109,31 +132,38 @@
|
|||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"apps/docs/node_modules/typescript": {
|
||||
"version": "5.9.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
|
||||
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
"apps/docs/node_modules/react-dom": {
|
||||
"version": "19.2.4",
|
||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz",
|
||||
"integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"scheduler": "^0.27.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.17"
|
||||
"peerDependencies": {
|
||||
"react": "^19.2.4"
|
||||
}
|
||||
},
|
||||
"apps/docs/node_modules/scheduler": {
|
||||
"version": "0.27.0",
|
||||
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz",
|
||||
"integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"apps/openpage-api": {
|
||||
"name": "@documenso/openpage-api",
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"@documenso/prisma": "*",
|
||||
"luxon": "^3.7.2",
|
||||
"next": "15.5.12"
|
||||
"next": "15.5.12",
|
||||
"react": "^18",
|
||||
"react-dom": "^18"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20",
|
||||
"@types/react": "18.3.27",
|
||||
"@types/react-dom": "^18",
|
||||
"typescript": "5.6.2"
|
||||
}
|
||||
},
|
||||
|
|
@ -147,17 +177,6 @@
|
|||
"undici-types": "~6.21.0"
|
||||
}
|
||||
},
|
||||
"apps/openpage-api/node_modules/@types/react": {
|
||||
"version": "18.3.27",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.27.tgz",
|
||||
"integrity": "sha512-cisd7gxkzjBKU2GgdYrTdtQx1SORymWyaAFhaxQPK9bYO9ot3Y5OikQRvY0VYQtvwjeQnizCINJAenh/V7MK2w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/prop-types": "*",
|
||||
"csstype": "^3.2.2"
|
||||
}
|
||||
},
|
||||
"apps/openpage-api/node_modules/nanoid": {
|
||||
"version": "3.3.11",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
|
||||
|
|
@ -362,27 +381,6 @@
|
|||
"undici-types": "~6.21.0"
|
||||
}
|
||||
},
|
||||
"apps/remix/node_modules/@types/react": {
|
||||
"version": "18.3.27",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.27.tgz",
|
||||
"integrity": "sha512-cisd7gxkzjBKU2GgdYrTdtQx1SORymWyaAFhaxQPK9bYO9ot3Y5OikQRvY0VYQtvwjeQnizCINJAenh/V7MK2w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/prop-types": "*",
|
||||
"csstype": "^3.2.2"
|
||||
}
|
||||
},
|
||||
"apps/remix/node_modules/@types/react-dom": {
|
||||
"version": "18.3.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz",
|
||||
"integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@types/react": "^18.0.0"
|
||||
}
|
||||
},
|
||||
"apps/remix/node_modules/lucide-react": {
|
||||
"version": "0.554.0",
|
||||
"resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.554.0.tgz",
|
||||
|
|
@ -392,19 +390,6 @@
|
|||
"react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||
}
|
||||
},
|
||||
"apps/remix/node_modules/react-dom": {
|
||||
"version": "18.3.1",
|
||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
|
||||
"integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"scheduler": "^0.23.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^18.3.1"
|
||||
}
|
||||
},
|
||||
"apps/remix/node_modules/tailwindcss": {
|
||||
"version": "3.4.19",
|
||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.19.tgz",
|
||||
|
|
@ -13465,26 +13450,26 @@
|
|||
"version": "15.7.15",
|
||||
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz",
|
||||
"integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/react": {
|
||||
"version": "19.2.14",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz",
|
||||
"integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==",
|
||||
"version": "18.3.27",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.27.tgz",
|
||||
"integrity": "sha512-cisd7gxkzjBKU2GgdYrTdtQx1SORymWyaAFhaxQPK9bYO9ot3Y5OikQRvY0VYQtvwjeQnizCINJAenh/V7MK2w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/prop-types": "*",
|
||||
"csstype": "^3.2.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/react-dom": {
|
||||
"version": "19.2.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz",
|
||||
"integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==",
|
||||
"version": "18.3.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz",
|
||||
"integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@types/react": "^19.2.0"
|
||||
"@types/react": "^18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/resolve": {
|
||||
|
|
@ -24659,23 +24644,18 @@
|
|||
}
|
||||
},
|
||||
"node_modules/react-dom": {
|
||||
"version": "19.2.4",
|
||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz",
|
||||
"integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==",
|
||||
"version": "18.3.1",
|
||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
|
||||
"integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"scheduler": "^0.27.0"
|
||||
"loose-envify": "^1.1.0",
|
||||
"scheduler": "^0.23.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^19.2.4"
|
||||
"react": "^18.3.1"
|
||||
}
|
||||
},
|
||||
"node_modules/react-dom/node_modules/scheduler": {
|
||||
"version": "0.27.0",
|
||||
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz",
|
||||
"integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/react-draggable": {
|
||||
"version": "4.4.6",
|
||||
"resolved": "https://registry.npmjs.org/react-draggable/-/react-draggable-4.4.6.tgz",
|
||||
|
|
@ -29762,27 +29742,6 @@
|
|||
"typescript": "5.6.2"
|
||||
}
|
||||
},
|
||||
"packages/ui/node_modules/@types/react": {
|
||||
"version": "18.3.27",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.27.tgz",
|
||||
"integrity": "sha512-cisd7gxkzjBKU2GgdYrTdtQx1SORymWyaAFhaxQPK9bYO9ot3Y5OikQRvY0VYQtvwjeQnizCINJAenh/V7MK2w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/prop-types": "*",
|
||||
"csstype": "^3.2.2"
|
||||
}
|
||||
},
|
||||
"packages/ui/node_modules/@types/react-dom": {
|
||||
"version": "18.3.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz",
|
||||
"integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@types/react": "^18.0.0"
|
||||
}
|
||||
},
|
||||
"packages/ui/node_modules/lucide-react": {
|
||||
"version": "0.554.0",
|
||||
"resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.554.0.tgz",
|
||||
|
|
@ -29792,19 +29751,6 @@
|
|||
"react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||
}
|
||||
},
|
||||
"packages/ui/node_modules/react-dom": {
|
||||
"version": "18.3.1",
|
||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
|
||||
"integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"scheduler": "^0.23.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^18.3.1"
|
||||
}
|
||||
},
|
||||
"packages/ui/node_modules/tailwind-merge": {
|
||||
"version": "1.14.0",
|
||||
"resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-1.14.0.tgz",
|
||||
|
|
|
|||
|
|
@ -76,12 +76,15 @@
|
|||
"prisma-extension-kysely": "^3.0.0",
|
||||
"prisma-json-types-generator": "^3.6.2",
|
||||
"prisma-kysely": "^2.3.0",
|
||||
"react-dom": "^18",
|
||||
"rimraf": "^6.1.2",
|
||||
"superjson": "^2.2.5",
|
||||
"syncpack": "^14.0.0-alpha.27",
|
||||
"turbo": "^1.13.4",
|
||||
"vite": "^7.2.4",
|
||||
"vite-plugin-static-copy": "^3.1.4",
|
||||
"@types/react": "18.3.27",
|
||||
"@types/react-dom": "^18",
|
||||
"zod-openapi": "^4.2.4",
|
||||
"zod-prisma-types": "3.3.5"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -189,7 +189,7 @@ export const ApiContractV1Implementation = tsr.router(ApiContractV1, {
|
|||
fields: parsedMetaFields,
|
||||
},
|
||||
};
|
||||
} catch (err) {
|
||||
} catch {
|
||||
return {
|
||||
status: 404,
|
||||
body: {
|
||||
|
|
@ -276,7 +276,7 @@ export const ApiContractV1Implementation = tsr.router(ApiContractV1, {
|
|||
status: 200,
|
||||
body: { downloadUrl: url },
|
||||
};
|
||||
} catch (err) {
|
||||
} catch {
|
||||
return {
|
||||
status: 500,
|
||||
body: {
|
||||
|
|
@ -341,7 +341,7 @@ export const ApiContractV1Implementation = tsr.router(ApiContractV1, {
|
|||
completedAt: deletedDocument.completedAt,
|
||||
},
|
||||
};
|
||||
} catch (err) {
|
||||
} catch {
|
||||
return {
|
||||
status: 404,
|
||||
body: {
|
||||
|
|
@ -478,7 +478,7 @@ export const ApiContractV1Implementation = tsr.router(ApiContractV1, {
|
|||
})),
|
||||
},
|
||||
};
|
||||
} catch (err) {
|
||||
} catch {
|
||||
return {
|
||||
status: 404,
|
||||
body: {
|
||||
|
|
@ -593,7 +593,7 @@ export const ApiContractV1Implementation = tsr.router(ApiContractV1, {
|
|||
template: fullTemplate,
|
||||
},
|
||||
};
|
||||
} catch (err) {
|
||||
} catch {
|
||||
return {
|
||||
status: 404,
|
||||
body: {
|
||||
|
|
@ -637,7 +637,7 @@ export const ApiContractV1Implementation = tsr.router(ApiContractV1, {
|
|||
updatedAt: deletedTemplate.updatedAt,
|
||||
},
|
||||
};
|
||||
} catch (err) {
|
||||
} catch {
|
||||
return {
|
||||
status: 404,
|
||||
body: {
|
||||
|
|
@ -1077,7 +1077,7 @@ export const ApiContractV1Implementation = tsr.router(ApiContractV1, {
|
|||
message: 'Document resend successfully initiated',
|
||||
},
|
||||
};
|
||||
} catch (err) {
|
||||
} catch {
|
||||
return {
|
||||
status: 500,
|
||||
body: {
|
||||
|
|
@ -1185,7 +1185,7 @@ export const ApiContractV1Implementation = tsr.router(ApiContractV1, {
|
|||
signingUrl: `${NEXT_PUBLIC_WEBAPP_URL()}/sign/${newRecipient.token}`,
|
||||
},
|
||||
};
|
||||
} catch (err) {
|
||||
} catch {
|
||||
return {
|
||||
status: 500,
|
||||
body: {
|
||||
|
|
|
|||
|
|
@ -54,13 +54,11 @@ export class MailChannelsTransport implements Transport<SentMessageInfo> {
|
|||
const mailCc = this.toMailChannelsAddresses(mail.data.cc);
|
||||
const mailBcc = this.toMailChannelsAddresses(mail.data.bcc);
|
||||
|
||||
const from: MailChannelsAddress =
|
||||
typeof mail.data.from === 'string'
|
||||
? { email: mail.data.from }
|
||||
: {
|
||||
email: mail.data.from?.address,
|
||||
name: mail.data.from?.name,
|
||||
};
|
||||
const [from] = this.toMailChannelsAddresses(mail.data.from);
|
||||
|
||||
if (!from) {
|
||||
return callback(new Error('Missing required field "from"'), null);
|
||||
}
|
||||
|
||||
const requestHeaders: Record<string, string> = {
|
||||
'Content-Type': 'application/json',
|
||||
|
|
@ -70,56 +68,15 @@ export class MailChannelsTransport implements Transport<SentMessageInfo> {
|
|||
requestHeaders['X-Auth-Token'] = this._options.apiKey;
|
||||
}
|
||||
|
||||
fetch(this._options.endpoint, {
|
||||
method: 'POST',
|
||||
headers: requestHeaders,
|
||||
body: JSON.stringify({
|
||||
from: from,
|
||||
subject: mail.data.subject,
|
||||
personalizations: [
|
||||
{
|
||||
to: mailTo,
|
||||
cc: mailCc.length > 0 ? mailCc : undefined,
|
||||
bcc: mailBcc.length > 0 ? mailBcc : undefined,
|
||||
dkim_domain: env('NEXT_PRIVATE_MAILCHANNELS_DKIM_DOMAIN') || undefined,
|
||||
dkim_selector: env('NEXT_PRIVATE_MAILCHANNELS_DKIM_SELECTOR') || undefined,
|
||||
dkim_private_key: env('NEXT_PRIVATE_MAILCHANNELS_DKIM_PRIVATE_KEY') || undefined,
|
||||
},
|
||||
],
|
||||
content: [
|
||||
{
|
||||
type: 'text/plain',
|
||||
value: mail.data.text?.toString('utf-8') ?? '',
|
||||
},
|
||||
{
|
||||
type: 'text/html',
|
||||
value: mail.data.html?.toString('utf-8') ?? '',
|
||||
},
|
||||
],
|
||||
}),
|
||||
})
|
||||
.then((res) => {
|
||||
if (res.status >= 200 && res.status <= 299) {
|
||||
return callback(null, {
|
||||
messageId: '',
|
||||
envelope: {
|
||||
from: mail.data.from,
|
||||
to: mail.data.to,
|
||||
},
|
||||
accepted: mail.data.to,
|
||||
rejected: [],
|
||||
pending: [],
|
||||
});
|
||||
}
|
||||
|
||||
res
|
||||
.json()
|
||||
.then((data) => callback(new Error(`MailChannels error: ${data.message}`), null))
|
||||
.catch((err) => callback(err, null));
|
||||
})
|
||||
.catch((err) => {
|
||||
return callback(err, null);
|
||||
});
|
||||
void this.sendMailRequest({
|
||||
callback,
|
||||
from,
|
||||
mail,
|
||||
mailBcc,
|
||||
mailCc,
|
||||
mailTo,
|
||||
requestHeaders,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -154,4 +111,72 @@ export class MailChannelsTransport implements Transport<SentMessageInfo> {
|
|||
},
|
||||
];
|
||||
}
|
||||
|
||||
private async sendMailRequest({
|
||||
callback,
|
||||
from,
|
||||
mail,
|
||||
mailBcc,
|
||||
mailCc,
|
||||
mailTo,
|
||||
requestHeaders,
|
||||
}: {
|
||||
callback: (_err: Error | null, _info: SentMessageInfo) => void;
|
||||
from: MailChannelsAddress;
|
||||
mail: MailMessage;
|
||||
mailBcc: Array<MailChannelsAddress>;
|
||||
mailCc: Array<MailChannelsAddress>;
|
||||
mailTo: Array<MailChannelsAddress>;
|
||||
requestHeaders: Record<string, string>;
|
||||
}) {
|
||||
try {
|
||||
const response = await fetch(this._options.endpoint, {
|
||||
method: 'POST',
|
||||
headers: requestHeaders,
|
||||
body: JSON.stringify({
|
||||
from,
|
||||
subject: mail.data.subject,
|
||||
personalizations: [
|
||||
{
|
||||
to: mailTo,
|
||||
cc: mailCc.length > 0 ? mailCc : undefined,
|
||||
bcc: mailBcc.length > 0 ? mailBcc : undefined,
|
||||
dkim_domain: env('NEXT_PRIVATE_MAILCHANNELS_DKIM_DOMAIN') || undefined,
|
||||
dkim_selector: env('NEXT_PRIVATE_MAILCHANNELS_DKIM_SELECTOR') || undefined,
|
||||
dkim_private_key: env('NEXT_PRIVATE_MAILCHANNELS_DKIM_PRIVATE_KEY') || undefined,
|
||||
},
|
||||
],
|
||||
content: [
|
||||
{
|
||||
type: 'text/plain',
|
||||
value: mail.data.text?.toString('utf-8') ?? '',
|
||||
},
|
||||
{
|
||||
type: 'text/html',
|
||||
value: mail.data.html?.toString('utf-8') ?? '',
|
||||
},
|
||||
],
|
||||
}),
|
||||
});
|
||||
|
||||
if (response.status >= 200 && response.status <= 299) {
|
||||
return callback(null, {
|
||||
messageId: '',
|
||||
envelope: {
|
||||
from: mail.data.from,
|
||||
to: mail.data.to,
|
||||
},
|
||||
accepted: mail.data.to,
|
||||
rejected: [],
|
||||
pending: [],
|
||||
});
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
return callback(new Error(`MailChannels error: ${data.message}`), null);
|
||||
} catch (error) {
|
||||
return callback(error instanceof Error ? error : new Error('Failed to send email'), null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ export function useAnalytics() {
|
|||
*
|
||||
* @param eventFlag The event to check against feature flags to determine whether tracking is enabled.
|
||||
*/
|
||||
const startSessionRecording = (eventFlag?: string) => {
|
||||
const startSessionRecording = (_eventFlag?: string) => {
|
||||
return;
|
||||
// const isSessionRecordingEnabled = featureFlags.getFlag(FEATURE_FLAG_GLOBAL_SESSION_RECORDING);
|
||||
// const isSessionRecordingEnabledForEvent = Boolean(eventFlag && featureFlags.getFlag(eventFlag));
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ export function useCopyShareLink({ onSuccess, onError }: UseCopyShareLinkOptions
|
|||
}
|
||||
|
||||
onSuccess?.();
|
||||
} catch (e) {
|
||||
} catch {
|
||||
onError?.();
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -14,13 +14,16 @@ export function useCopyToClipboard(): [CopiedValue, CopyFn] {
|
|||
return false;
|
||||
}
|
||||
|
||||
const isClipboardApiSupported = Boolean(typeof ClipboardItem && navigator.clipboard.write);
|
||||
const isClipboardApiSupported =
|
||||
typeof ClipboardItem !== 'undefined' && typeof navigator.clipboard.write === 'function';
|
||||
|
||||
// Try to save to clipboard then save it in the state if worked
|
||||
try {
|
||||
isClipboardApiSupported
|
||||
? await handleClipboardApiCopy(text, blobType)
|
||||
: await handleWriteTextCopy(text);
|
||||
if (isClipboardApiSupported) {
|
||||
await handleClipboardApiCopy(text, blobType);
|
||||
} else {
|
||||
await handleWriteTextCopy(text);
|
||||
}
|
||||
|
||||
setCopiedText(await text);
|
||||
return true;
|
||||
|
|
@ -41,7 +44,7 @@ export function useCopyToClipboard(): [CopiedValue, CopyFn] {
|
|||
const handleClipboardApiCopy = async (value: CopyValue, blobType = 'text/plain') => {
|
||||
try {
|
||||
await navigator.clipboard.write([new ClipboardItem({ [blobType]: value })]);
|
||||
} catch (e) {
|
||||
} catch {
|
||||
// Fallback attempt.
|
||||
await handleWriteTextCopy(value);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -251,7 +251,7 @@ export const useEditorFields = ({
|
|||
|
||||
const getFieldByFormId = useCallback(
|
||||
(formId: string): TLocalField | undefined => {
|
||||
return localFields.find((field) => field.formId === formId) as TLocalField | undefined;
|
||||
return localFields.find((field) => field.formId === formId);
|
||||
},
|
||||
[localFields],
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/* eslint-disable @typescript-eslint/consistent-type-assertions */
|
||||
import { RefObject, useEffect, useState } from 'react';
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
/**
|
||||
* Calculate the width and height of a text element.
|
||||
|
|
|
|||
|
|
@ -276,7 +276,7 @@ export const EnvelopeEditorProvider = ({
|
|||
[envelope.recipients],
|
||||
);
|
||||
|
||||
const { refetch: reloadEnvelope, isLoading: isReloadingEnvelope } = trpc.envelope.get.useQuery(
|
||||
const { refetch: reloadEnvelope, isLoading: _isReloadingEnvelope } = trpc.envelope.get.useQuery(
|
||||
{
|
||||
envelopeId: envelope.id,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -189,7 +189,7 @@ export const EnvelopeRenderProvider = ({
|
|||
}, [envelope.envelopeItems]);
|
||||
|
||||
const recipientIds = useMemo(
|
||||
() => recipients.map((recipient) => recipient.id).sort(),
|
||||
() => recipients.map((recipient) => recipient.id).sort((left, right) => left - right),
|
||||
[recipients],
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -170,5 +170,8 @@ export const convertToLocalSystemFormat = (
|
|||
};
|
||||
|
||||
export const isValidDateFormat = (dateFormat: unknown): dateFormat is ValidDateFormat => {
|
||||
return VALID_DATE_FORMAT_VALUES.includes(dateFormat as ValidDateFormat);
|
||||
return (
|
||||
typeof dateFormat === 'string' &&
|
||||
VALID_DATE_FORMAT_VALUES.some((validDateFormat) => validDateFormat === dateFormat)
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -73,4 +73,5 @@ export const SUPPORTED_LANGUAGES: Record<string, SupportedLanguage> = {
|
|||
} satisfies Record<SupportedLanguageCodes, SupportedLanguage>;
|
||||
|
||||
export const isValidLanguageCode = (code: unknown): code is SupportedLanguageCodes =>
|
||||
SUPPORTED_LANGUAGE_CODES.includes(code as SupportedLanguageCodes);
|
||||
typeof code === 'string' &&
|
||||
SUPPORTED_LANGUAGE_CODES.some((languageCode) => languageCode === code);
|
||||
|
|
|
|||
|
|
@ -91,11 +91,11 @@ export class InngestJobProvider extends BaseJobProvider {
|
|||
return {
|
||||
wait: step.sleep,
|
||||
logger: {
|
||||
info: ctx.logger.info,
|
||||
debug: ctx.logger.debug,
|
||||
error: ctx.logger.error,
|
||||
warn: ctx.logger.warn,
|
||||
log: ctx.logger.info,
|
||||
info: (...args) => ctx.logger.info(...args),
|
||||
debug: (...args) => ctx.logger.debug(...args),
|
||||
error: (...args) => ctx.logger.error(...args),
|
||||
warn: (...args) => ctx.logger.warn(...args),
|
||||
log: (...args) => ctx.logger.info(...args),
|
||||
},
|
||||
runTask: async (cacheKey, callback) => {
|
||||
const result = await step.run(cacheKey, callback);
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import type { TExecuteWebhookJobDefinition } from './execute-webhook';
|
|||
|
||||
export const run = async ({
|
||||
payload,
|
||||
io,
|
||||
io: _io,
|
||||
}: {
|
||||
payload: TExecuteWebhookJobDefinition;
|
||||
io: JobRunIO;
|
||||
|
|
@ -28,10 +28,11 @@ export const run = async ({
|
|||
createdAt: new Date().toISOString(),
|
||||
webhookEndpoint: url,
|
||||
};
|
||||
const requestBody: Prisma.InputJsonValue = JSON.parse(JSON.stringify(payloadData));
|
||||
|
||||
const response = await fetch(url, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(payloadData),
|
||||
body: JSON.stringify(requestBody),
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Documenso-Secret': secret ?? '',
|
||||
|
|
@ -44,7 +45,7 @@ export const run = async ({
|
|||
|
||||
try {
|
||||
responseBody = JSON.parse(body);
|
||||
} catch (err) {
|
||||
} catch {
|
||||
responseBody = body;
|
||||
}
|
||||
|
||||
|
|
@ -53,7 +54,7 @@ export const run = async ({
|
|||
url,
|
||||
event,
|
||||
status: response.ok ? WebhookCallStatus.SUCCESS : WebhookCallStatus.FAILED,
|
||||
requestBody: payloadData as Prisma.InputJsonValue,
|
||||
requestBody,
|
||||
responseCode: response.status,
|
||||
responseBody,
|
||||
responseHeaders: Object.fromEntries(response.headers.entries()),
|
||||
|
|
|
|||
|
|
@ -91,9 +91,13 @@ export const adminFindUnsealedDocuments = async ({
|
|||
]);
|
||||
|
||||
const count = Number(countResult[0]?.count ?? 0);
|
||||
const formattedData: AdminUnsealedDocument[] = data.map((document) => ({
|
||||
...document,
|
||||
id: String(document.id),
|
||||
}));
|
||||
|
||||
return {
|
||||
data: data as unknown as AdminUnsealedDocument[],
|
||||
data: formattedData,
|
||||
count,
|
||||
currentPage: Math.max(page, 1),
|
||||
perPage,
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ export type TeamInsights = {
|
|||
|
||||
export type UserInsights = {
|
||||
id: number;
|
||||
name: string;
|
||||
name: string | null;
|
||||
email: string;
|
||||
documentCount: number;
|
||||
signedDocumentCount: number;
|
||||
|
|
@ -98,7 +98,7 @@ export async function getOrganisationDetailedInsights({
|
|||
case 'documents':
|
||||
return await getDocumentInsights(organisationId, offset, perPage, createdAtFrom);
|
||||
default:
|
||||
throw new Error(`Invalid view: ${view}`);
|
||||
throw new Error('Invalid view');
|
||||
}
|
||||
})();
|
||||
|
||||
|
|
@ -149,9 +149,14 @@ async function getTeamInsights(
|
|||
|
||||
const [teams, countResult] = await Promise.all([teamsQuery.execute(), countQuery.execute()]);
|
||||
const count = Number(countResult[0]?.count || 0);
|
||||
const teamInsights: TeamInsights[] = teams.map((team) => ({
|
||||
...team,
|
||||
memberCount: Number(team.memberCount),
|
||||
documentCount: Number(team.documentCount),
|
||||
}));
|
||||
|
||||
return {
|
||||
teams: teams as TeamInsights[],
|
||||
teams: teamInsights,
|
||||
users: [],
|
||||
documents: [],
|
||||
totalPages: Math.ceil(Number(count) / perPage),
|
||||
|
|
@ -208,10 +213,15 @@ async function getUserInsights(
|
|||
|
||||
const [users, countResult] = await Promise.all([usersQuery.execute(), countQuery.execute()]);
|
||||
const count = Number(countResult[0]?.count || 0);
|
||||
const userInsights: UserInsights[] = users.map((user) => ({
|
||||
...user,
|
||||
documentCount: Number(user.documentCount),
|
||||
signedDocumentCount: Number(user.signedDocumentCount),
|
||||
}));
|
||||
|
||||
return {
|
||||
teams: [],
|
||||
users: users as UserInsights[],
|
||||
users: userInsights,
|
||||
documents: [],
|
||||
totalPages: Math.ceil(Number(count) / perPage),
|
||||
};
|
||||
|
|
@ -223,18 +233,13 @@ async function getDocumentInsights(
|
|||
perPage: number,
|
||||
createdAtFrom: Date | null,
|
||||
): Promise<OrganisationDetailedInsights> {
|
||||
let documentsQuery = kyselyPrisma.$kysely
|
||||
const documentsQuery = kyselyPrisma.$kysely
|
||||
.selectFrom('Envelope as e')
|
||||
.innerJoin('Team as t', 'e.teamId', 't.id')
|
||||
.where('t.organisationId', '=', organisationId)
|
||||
.where('e.deletedAt', 'is', null)
|
||||
.where(() => sql`e.type = ${EnvelopeType.DOCUMENT}::"EnvelopeType"`);
|
||||
|
||||
if (createdAtFrom) {
|
||||
documentsQuery = documentsQuery.where('e.createdAt', '>=', createdAtFrom);
|
||||
}
|
||||
|
||||
documentsQuery = documentsQuery
|
||||
.where(() => sql`e.type = ${EnvelopeType.DOCUMENT}::"EnvelopeType"`)
|
||||
.$if(!!createdAtFrom, (qb) => qb.where('e.createdAt', '>=', createdAtFrom!))
|
||||
.select([
|
||||
'e.id as id',
|
||||
'e.title as title',
|
||||
|
|
@ -247,33 +252,33 @@ async function getDocumentInsights(
|
|||
.limit(perPage)
|
||||
.offset(offset);
|
||||
|
||||
let countQuery = kyselyPrisma.$kysely
|
||||
const countQuery = kyselyPrisma.$kysely
|
||||
.selectFrom('Envelope as e')
|
||||
.innerJoin('Team as t', 'e.teamId', 't.id')
|
||||
.where('t.organisationId', '=', organisationId)
|
||||
.where('e.deletedAt', 'is', null)
|
||||
.where(() => sql`e.type = ${EnvelopeType.DOCUMENT}::"EnvelopeType"`);
|
||||
|
||||
if (createdAtFrom) {
|
||||
countQuery = countQuery.where('e.createdAt', '>=', createdAtFrom);
|
||||
}
|
||||
|
||||
countQuery = countQuery.select(({ fn }) => [fn.countAll().as('count')]);
|
||||
.where(() => sql`e.type = ${EnvelopeType.DOCUMENT}::"EnvelopeType"`)
|
||||
.$if(!!createdAtFrom, (qb) => qb.where('e.createdAt', '>=', createdAtFrom!))
|
||||
.select(sql<number>`count(*)`.as('count'));
|
||||
|
||||
const [documents, countResult] = await Promise.all([
|
||||
documentsQuery.execute(),
|
||||
countQuery.execute(),
|
||||
countQuery.executeTakeFirst(),
|
||||
]);
|
||||
|
||||
const count = Number((countResult[0] as { count: number })?.count || 0);
|
||||
const count = Number(countResult?.count || 0);
|
||||
const documentInsights: DocumentInsights[] = documents.map((document) => ({
|
||||
title: document.title,
|
||||
status: document.status,
|
||||
createdAt: document.createdAt,
|
||||
completedAt: document.completedAt,
|
||||
teamName: document.teamName,
|
||||
id: String(document.id),
|
||||
}));
|
||||
|
||||
return {
|
||||
teams: [],
|
||||
users: [],
|
||||
documents: documents.map((doc) => ({
|
||||
...doc,
|
||||
id: String((doc as { id: number }).id),
|
||||
})) as DocumentInsights[],
|
||||
documents: documentInsights,
|
||||
totalPages: Math.ceil(Number(count) / perPage),
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ export type PdfToImagesOptions = {
|
|||
export const pdfToImages = async (pdfBytes: Uint8Array, options: PdfToImagesOptions = {}) => {
|
||||
const { scale = 2 } = options;
|
||||
|
||||
const task = await pdfjsLib.getDocument({
|
||||
const task = pdfjsLib.getDocument({
|
||||
data: pdfBytes,
|
||||
CanvasFactory: SkiaCanvasFactory,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import { omit } from 'remeda';
|
|||
import { prisma } from '@documenso/prisma';
|
||||
|
||||
import { AppError, AppErrorCode } from '../../errors/app-error';
|
||||
import { ZFieldMetaSchema } from '../../types/field-meta';
|
||||
import {
|
||||
ZWebhookDocumentSchema,
|
||||
mapEnvelopeToWebhookDocumentPayload,
|
||||
|
|
@ -158,7 +159,7 @@ export const duplicateEnvelope = async ({ id, userId, teamId }: DuplicateEnvelop
|
|||
height: field.height,
|
||||
customText: '',
|
||||
inserted: false,
|
||||
fieldMeta: field.fieldMeta as PrismaJson.FieldMeta,
|
||||
fieldMeta: field.fieldMeta ? ZFieldMetaSchema.parse(field.fieldMeta) : undefined,
|
||||
})),
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ export type GetRecipientEnvelopeByTokenOptions = {
|
|||
export const getEnvelopeForDirectTemplateSigning = async ({
|
||||
token,
|
||||
userId,
|
||||
accessAuth,
|
||||
accessAuth: _accessAuth,
|
||||
}: GetRecipientEnvelopeByTokenOptions): Promise<EnvelopeForSigningResponse> => {
|
||||
if (!token) {
|
||||
throw new AppError(AppErrorCode.NOT_FOUND, {
|
||||
|
|
|
|||
|
|
@ -193,12 +193,12 @@ export const updateEnvelope = async ({
|
|||
isDeepEqual(documentGlobalActionAuth, newGlobalActionAuth);
|
||||
const isDocumentVisibilitySame =
|
||||
data.visibility === undefined || data.visibility === envelope.visibility;
|
||||
const isFolderSame = data.folderId === undefined || data.folderId === envelope.folderId;
|
||||
const isTemplateTypeSame =
|
||||
const _isFolderSame = data.folderId === undefined || data.folderId === envelope.folderId;
|
||||
const _isTemplateTypeSame =
|
||||
data.templateType === undefined || data.templateType === envelope.templateType;
|
||||
const isPublicDescriptionSame =
|
||||
const _isPublicDescriptionSame =
|
||||
data.publicDescription === undefined || data.publicDescription === envelope.publicDescription;
|
||||
const isPublicTitleSame =
|
||||
const _isPublicTitleSame =
|
||||
data.publicTitle === undefined || data.publicTitle === envelope.publicTitle;
|
||||
|
||||
const auditLogs: CreateDocumentAuditLogDataResponse[] = [];
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ Konva.Util['createCanvasElement'] = () => {
|
|||
get: () => node,
|
||||
});
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||
return node as unknown as HTMLCanvasElement;
|
||||
};
|
||||
|
||||
|
|
@ -34,6 +35,7 @@ Konva.Util.createImageElement = () => {
|
|||
const node = new Image();
|
||||
node.toString = () => '[object HTMLImageElement]';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||
return node as unknown as HTMLImageElement;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import { NEXT_PRIVATE_INTERNAL_WEBAPP_URL } from '../../constants/app';
|
|||
* Adds a rejection stamp to each page of a PDF document.
|
||||
* The stamp is placed in the center of the page.
|
||||
*/
|
||||
export async function addRejectionStampToPdf(pdf: PDF, reason: string): Promise<PDF> {
|
||||
export async function addRejectionStampToPdf(pdf: PDF, _reason: string): Promise<PDF> {
|
||||
const pages = pdf.getPages();
|
||||
|
||||
const fontBytes = await fetch(`${NEXT_PRIVATE_INTERNAL_WEBAPP_URL()}/fonts/noto-sans.ttf`).then(
|
||||
|
|
|
|||
|
|
@ -694,10 +694,10 @@ const setTextFieldFontSize = (textField: PDFTextField, font: PDFFont, fontSize:
|
|||
|
||||
try {
|
||||
textField.setFontSize(fontSize);
|
||||
} catch (err) {
|
||||
} catch {
|
||||
let da = textField.acroField.getDefaultAppearance() ?? '';
|
||||
|
||||
da += `\n ${setFontAndSize(font.name, fontSize)}`;
|
||||
da += `\n ${String(setFontAndSize(font.name, fontSize))}`;
|
||||
|
||||
textField.acroField.setDefaultAppearance(da);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ const parser = new UAParser();
|
|||
const textMutedForegroundLight = '#929DAE';
|
||||
const textForeground = '#000';
|
||||
const textMutedForeground = '#64748B';
|
||||
const textBase = 10;
|
||||
const _textBase = 10;
|
||||
const textSm = 9;
|
||||
const textXs = 8;
|
||||
const fontMedium = '500';
|
||||
|
|
|
|||
|
|
@ -75,13 +75,13 @@ const getDevice = (userAgent?: string | null): string => {
|
|||
return `${result.os.name} - ${result.browser.name} ${result.browser.version}`;
|
||||
};
|
||||
|
||||
const textMutedForegroundLight = '#929DAE';
|
||||
const textForeground = '#000';
|
||||
const _textMutedForegroundLight = '#929DAE';
|
||||
const _textForeground = '#000';
|
||||
const textMutedForeground = '#64748B';
|
||||
const textRejectedRed = '#dc2626';
|
||||
const textBase = 10;
|
||||
const textSm = 9;
|
||||
const textXs = 8;
|
||||
const _textXs = 8;
|
||||
const fontMedium = '500';
|
||||
|
||||
const columnWidthPercentages = [30, 30, 40];
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ export const setAvatarImage = async ({
|
|||
userId,
|
||||
target,
|
||||
bytes,
|
||||
requestMetadata,
|
||||
requestMetadata: _requestMetadata,
|
||||
}: SetAvatarImageOptions) => {
|
||||
let oldAvatarImageId: string | null = null;
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ export const testCredentialsHandler = async (req: Request) => {
|
|||
return Response.json({
|
||||
name: result.team?.name ?? result.user.name,
|
||||
});
|
||||
} catch (err) {
|
||||
} catch {
|
||||
return Response.json(
|
||||
{
|
||||
message: 'Internal Server Error',
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@ export const deleteTeamEmail = async ({ userId, userEmail, teamId }: DeleteTeamE
|
|||
html,
|
||||
text,
|
||||
});
|
||||
} catch (e) {
|
||||
} catch {
|
||||
// Todo: Teams - Alert us.
|
||||
// We don't want to prevent a user from revoking access because an email could not be sent.
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ export const deletedServiceAccountEmail = () => {
|
|||
const { hostname } = new URL(process.env.NEXT_PUBLIC_WEBAPP_URL || 'http://localhost:3000');
|
||||
|
||||
return `deleted-account@${hostname}`;
|
||||
} catch (error) {
|
||||
} catch {
|
||||
return LEGACY_DELETED_ACCOUNT_EMAIL;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ export const legacyServiceAccountEmail = () => {
|
|||
const { hostname } = new URL(process.env.NEXT_PUBLIC_WEBAPP_URL || 'http://localhost:3000');
|
||||
|
||||
return `serviceaccount@${hostname}`;
|
||||
} catch (error) {
|
||||
} catch {
|
||||
return LEGACY_SERVICE_ACCOUNT_EMAIL;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -545,5 +545,5 @@ export const generateSampleWebhookPayload = (
|
|||
};
|
||||
}
|
||||
|
||||
throw new Error(`Unsupported event type: ${event}`);
|
||||
throw new Error('Unsupported event type');
|
||||
};
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ export const validateApiToken = async ({ authorization }: ValidateApiTokenOption
|
|||
}
|
||||
|
||||
return await getApiTokenByToken({ token });
|
||||
} catch (err) {
|
||||
} catch {
|
||||
throw new Error(`Failed to validate API token`);
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -418,5 +418,3 @@ export const ZEnvelopeFieldAndMetaSchema = z.discriminatedUnion('type', [
|
|||
fieldMeta: ZDropdownFieldMeta.optional().default(FIELD_DROPDOWN_META_DEFAULT_VALUES),
|
||||
}),
|
||||
]);
|
||||
|
||||
type TEnvelopeFieldAndMeta = z.infer<typeof ZEnvelopeFieldAndMetaSchema>;
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ export const MIN_FIELD_WIDTH_PX = 36;
|
|||
|
||||
export type FieldToRender = Pick<
|
||||
Field,
|
||||
'envelopeItemId' | 'recipientId' | 'type' | 'page' | 'customText' | 'inserted' | 'recipientId'
|
||||
'envelopeItemId' | 'recipientId' | 'type' | 'page' | 'customText' | 'inserted'
|
||||
> & {
|
||||
renderId: string; // A unique ID for the field in the render.
|
||||
width: number;
|
||||
|
|
|
|||
|
|
@ -30,7 +30,8 @@ export const renderCheckboxFieldElement = (
|
|||
|
||||
const { fieldWidth, fieldHeight } = calculateFieldPosition(field, pageWidth, pageHeight);
|
||||
|
||||
const checkboxMeta: TCheckboxFieldMeta | null = (field.fieldMeta as TCheckboxFieldMeta) || null;
|
||||
const checkboxMeta: TCheckboxFieldMeta | null =
|
||||
field.fieldMeta?.type === 'checkbox' ? field.fieldMeta : null;
|
||||
const checkboxValues = checkboxMeta?.values || [];
|
||||
|
||||
const isFirstRender = !pageLayer.findOne(`#${field.renderId}`);
|
||||
|
|
@ -131,6 +132,7 @@ export const renderCheckboxFieldElement = (
|
|||
});
|
||||
|
||||
const checkedValues: number[] = field.customText ? parseCheckboxCustomText(field.customText) : [];
|
||||
const isReadOnly = checkboxMeta?.readOnly ?? false;
|
||||
|
||||
checkboxValues.forEach(({ value, checked }, index) => {
|
||||
const isCheckboxChecked = match(mode)
|
||||
|
|
@ -138,7 +140,7 @@ export const renderCheckboxFieldElement = (
|
|||
.with('sign', () => checkedValues.includes(index))
|
||||
.with('export', () => {
|
||||
// If it's read-only, check the originally checked state.
|
||||
if (checkboxMeta.readOnly) {
|
||||
if (isReadOnly) {
|
||||
return checked;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -54,7 +54,8 @@ export const renderDropdownFieldElement = (
|
|||
|
||||
const { fieldWidth, fieldHeight } = calculateFieldPosition(field, pageWidth, pageHeight);
|
||||
|
||||
const dropdownMeta: TDropdownFieldMeta | null = (field.fieldMeta as TDropdownFieldMeta) || null;
|
||||
const dropdownMeta: TDropdownFieldMeta | null =
|
||||
field.fieldMeta?.type === 'dropdown' ? field.fieldMeta : null;
|
||||
|
||||
let selectedValue = translations?.[FieldType.DROPDOWN] || 'Select Option';
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ export type FieldRenderMode = 'edit' | 'sign' | 'export';
|
|||
|
||||
export type FieldToRender = Pick<
|
||||
Field,
|
||||
'envelopeItemId' | 'recipientId' | 'type' | 'page' | 'customText' | 'inserted' | 'recipientId'
|
||||
'envelopeItemId' | 'recipientId' | 'type' | 'page' | 'customText' | 'inserted'
|
||||
> & {
|
||||
renderId: string; // A unique ID for the field in the render.
|
||||
width: number;
|
||||
|
|
|
|||
|
|
@ -20,12 +20,29 @@ import { calculateFieldPosition } from './field-renderer';
|
|||
|
||||
const DEFAULT_TEXT_X_PADDING = 6;
|
||||
|
||||
const getGenericTextFieldMeta = (field: FieldToRender): GenericTextFieldTypeMetas | undefined => {
|
||||
const fieldMeta = field.fieldMeta;
|
||||
|
||||
if (
|
||||
fieldMeta?.type === 'initials' ||
|
||||
fieldMeta?.type === 'name' ||
|
||||
fieldMeta?.type === 'email' ||
|
||||
fieldMeta?.type === 'date' ||
|
||||
fieldMeta?.type === 'text' ||
|
||||
fieldMeta?.type === 'number'
|
||||
) {
|
||||
return fieldMeta;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
};
|
||||
|
||||
const upsertFieldText = (field: FieldToRender, options: RenderFieldElementOptions): Konva.Text => {
|
||||
const { pageWidth, pageHeight, mode = 'edit', pageLayer, translations } = options;
|
||||
|
||||
const { fieldWidth, fieldHeight } = calculateFieldPosition(field, pageWidth, pageHeight);
|
||||
|
||||
const fieldMeta = field.fieldMeta as GenericTextFieldTypeMetas | undefined;
|
||||
const fieldMeta = getGenericTextFieldMeta(field);
|
||||
|
||||
const fieldTypeName = translations?.[field.type] || field.type;
|
||||
|
||||
|
|
|
|||
|
|
@ -27,7 +27,8 @@ export const renderRadioFieldElement = (
|
|||
) => {
|
||||
const { pageWidth, pageHeight, pageLayer, mode, color } = options;
|
||||
|
||||
const radioMeta: TRadioFieldMeta | null = (field.fieldMeta as TRadioFieldMeta) || null;
|
||||
const radioMeta: TRadioFieldMeta | null =
|
||||
field.fieldMeta?.type === 'radio' ? field.fieldMeta : null;
|
||||
const radioValues = radioMeta?.values || [];
|
||||
|
||||
const isFirstRender = !pageLayer.findOne(`#${field.renderId}`);
|
||||
|
|
@ -122,6 +123,7 @@ export const renderRadioFieldElement = (
|
|||
});
|
||||
|
||||
const { fieldWidth, fieldHeight } = calculateFieldPosition(field, pageWidth, pageHeight);
|
||||
const isReadOnly = radioMeta?.readOnly ?? false;
|
||||
|
||||
radioValues.forEach(({ value, checked }, index) => {
|
||||
const isRadioValueChecked = match(mode)
|
||||
|
|
@ -129,7 +131,7 @@ export const renderRadioFieldElement = (
|
|||
.with('sign', () => index.toString() === field.customText)
|
||||
.with('export', () => {
|
||||
// If it's read-only, check the originally checked state.
|
||||
if (radioMeta.readOnly) {
|
||||
if (isReadOnly) {
|
||||
return checked;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ export type GetFileOptions = {
|
|||
*
|
||||
* - Lucas, 2025-11-04
|
||||
*/
|
||||
const getFile = async ({ type, data }: GetFileOptions) => {
|
||||
const _getFile = async ({ type, data }: GetFileOptions) => {
|
||||
return await match(type)
|
||||
.with(DocumentDataType.BYTES, () => getFileFromBytes(data))
|
||||
.with(DocumentDataType.BYTES_64, () => getFileFromBytes64(data))
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ export const getEnvelopeItemPdfUrl = (options: EnvelopeItemPdfUrlOptions) => {
|
|||
const version = options.version;
|
||||
|
||||
return token
|
||||
? `${NEXT_PUBLIC_WEBAPP_URL()}/api/files/token/${token}/envelopeItem/${id}/download/${version}${presignToken ? `?presignToken=${presignToken}` : ''}`
|
||||
? `${NEXT_PUBLIC_WEBAPP_URL()}/api/files/token/${token}/envelopeItem/${id}/download/${version}`
|
||||
: `${NEXT_PUBLIC_WEBAPP_URL()}/api/files/envelope/${envelopeId}/envelopeItem/${id}/download/${version}`;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -53,8 +53,8 @@ export const validateFieldsUninserted = (): boolean => {
|
|||
const innerDiv = element.querySelector('div');
|
||||
const hasError = innerDiv?.getAttribute('data-error') === 'true';
|
||||
|
||||
if (hasError) {
|
||||
errorElements.push(element as HTMLElement);
|
||||
if (hasError && element instanceof HTMLElement) {
|
||||
errorElements.push(element);
|
||||
} else {
|
||||
element.removeAttribute('data-error');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -151,7 +151,7 @@ export const updateOrganisationMemberRoleRoute = adminProcedure
|
|||
return;
|
||||
}
|
||||
|
||||
const targetRole = role as OrganisationMemberRole;
|
||||
const targetRole: OrganisationMemberRole = role;
|
||||
|
||||
if (currentOrganisationRole === targetRole) {
|
||||
throw new AppError(AppErrorCode.INVALID_REQUEST, {
|
||||
|
|
|
|||
|
|
@ -30,8 +30,6 @@ export const accessAuthRequest2FAEmailRoute = procedure
|
|||
|
||||
assertRateLimit(rateLimitResult);
|
||||
|
||||
const user = ctx.user;
|
||||
|
||||
// Get document and recipient by token
|
||||
const envelope = await prisma.envelope.findFirst({
|
||||
where: {
|
||||
|
|
|
|||
|
|
@ -174,7 +174,7 @@ export const folderRouter = router({
|
|||
folderId: parentId,
|
||||
type,
|
||||
});
|
||||
} catch (error) {
|
||||
} catch {
|
||||
throw new AppError(AppErrorCode.NOT_FOUND, {
|
||||
message: 'Parent folder not found',
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { Prisma, WebhookCallStatus, WebhookTriggerEvents } from '@prisma/client';
|
||||
import type { Prisma, WebhookCallStatus, WebhookTriggerEvents } from '@prisma/client';
|
||||
|
||||
import { TEAM_MEMBER_ROLE_PERMISSIONS_MAP } from '@documenso/lib/constants/teams';
|
||||
import { AppError, AppErrorCode } from '@documenso/lib/errors/app-error';
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
import { Prisma, WebhookCallStatus, WebhookTriggerEvents } from '@prisma/client';
|
||||
import { Prisma, WebhookCallStatus } from '@prisma/client';
|
||||
|
||||
import { TEAM_MEMBER_ROLE_PERMISSIONS_MAP } from '@documenso/lib/constants/teams';
|
||||
import { AppError, AppErrorCode } from '@documenso/lib/errors/app-error';
|
||||
import type { FindResultResponse } from '@documenso/lib/types/search-params';
|
||||
import { buildTeamWhereQuery } from '@documenso/lib/utils/teams';
|
||||
import { prisma } from '@documenso/prisma';
|
||||
|
||||
|
|
@ -62,7 +61,7 @@ export const resendWebhookCallRoute = authenticatedProcedure
|
|||
|
||||
try {
|
||||
responseBody = JSON.parse(body);
|
||||
} catch (err) {
|
||||
} catch {
|
||||
responseBody = body;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import { WebhookCallStatus, WebhookTriggerEvents } from '@prisma/client';
|
||||
import { z } from 'zod';
|
||||
|
||||
import WebhookCallSchema from '@documenso/prisma/generated/zod/modelSchema/WebhookCallSchema';
|
||||
|
|
|
|||
|
|
@ -39,17 +39,13 @@ export const DocumentGlobalAuthAccessSelect = ({
|
|||
})),
|
||||
];
|
||||
|
||||
// Convert string array to Option array for MultiSelect
|
||||
const selectedOptions =
|
||||
(value
|
||||
?.map((val) => authOptions.find((option) => option.value === val))
|
||||
.filter(Boolean) as Option[]) || [];
|
||||
const getSelectedOptions = (selectedValues?: string[]) =>
|
||||
selectedValues
|
||||
?.map((selectedValue) => authOptions.find((option) => option.value === selectedValue))
|
||||
.filter((option): option is Option => option !== undefined) ?? [];
|
||||
|
||||
// Convert default value to Option array
|
||||
const defaultOptions =
|
||||
(defaultValue
|
||||
?.map((val) => authOptions.find((option) => option.value === val))
|
||||
.filter(Boolean) as Option[]) || [];
|
||||
const selectedOptions = getSelectedOptions(value);
|
||||
const defaultOptions = getSelectedOptions(defaultValue);
|
||||
|
||||
const handleChange = (options: Option[]) => {
|
||||
const values = options.map((option) => option.value);
|
||||
|
|
@ -79,7 +75,7 @@ export const DocumentGlobalAuthAccessTooltip = () => (
|
|||
<InfoIcon className="mx-2 h-4 w-4" />
|
||||
</TooltipTrigger>
|
||||
|
||||
<TooltipContent className="max-w-md space-y-2 p-4 text-foreground">
|
||||
<TooltipContent className="text-foreground max-w-md space-y-2 p-4">
|
||||
<h2>
|
||||
<strong>
|
||||
<Trans>Document access</Trans>
|
||||
|
|
|
|||
|
|
@ -39,17 +39,13 @@ export const DocumentGlobalAuthActionSelect = ({
|
|||
})),
|
||||
];
|
||||
|
||||
// Convert string array to Option array for MultiSelect
|
||||
const selectedOptions =
|
||||
(value
|
||||
?.map((val) => authOptions.find((option) => option.value === val))
|
||||
.filter(Boolean) as Option[]) || [];
|
||||
const getSelectedOptions = (selectedValues?: string[]) =>
|
||||
selectedValues
|
||||
?.map((selectedValue) => authOptions.find((option) => option.value === selectedValue))
|
||||
.filter((option): option is Option => option !== undefined) ?? [];
|
||||
|
||||
// Convert default value to Option array
|
||||
const defaultOptions =
|
||||
(defaultValue
|
||||
?.map((val) => authOptions.find((option) => option.value === val))
|
||||
.filter(Boolean) as Option[]) || [];
|
||||
const selectedOptions = getSelectedOptions(value);
|
||||
const defaultOptions = getSelectedOptions(defaultValue);
|
||||
|
||||
const handleChange = (options: Option[]) => {
|
||||
const values = options.map((option) => option.value);
|
||||
|
|
@ -79,7 +75,7 @@ export const DocumentGlobalAuthActionTooltip = () => (
|
|||
<InfoIcon className="mx-2 h-4 w-4" />
|
||||
</TooltipTrigger>
|
||||
|
||||
<TooltipContent className="max-w-md space-y-2 p-4 text-foreground">
|
||||
<TooltipContent className="text-foreground max-w-md space-y-2 p-4">
|
||||
<h2>
|
||||
<Trans>Global recipient action authentication</Trans>
|
||||
</h2>
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ export function EnvelopeRecipientFieldTooltip({
|
|||
field,
|
||||
showFieldStatus = false,
|
||||
showRecipientTooltip = false,
|
||||
showRecipientColors = false,
|
||||
showRecipientColors: _showRecipientColors = false,
|
||||
}: EnvelopeRecipientFieldTooltipProps) {
|
||||
const { t } = useLingui();
|
||||
|
||||
|
|
@ -145,7 +145,7 @@ export function EnvelopeRecipientFieldTooltip({
|
|||
>
|
||||
<PopoverHover
|
||||
trigger={
|
||||
<Avatar className="absolute -left-3 -top-3 z-50 h-6 w-6 border-2 border-solid border-gray-200/50 transition-colors hover:border-gray-200">
|
||||
<Avatar className="absolute -top-3 -left-3 z-50 h-6 w-6 border-2 border-solid border-gray-200/50 transition-colors hover:border-gray-200">
|
||||
<AvatarFallback className="bg-neutral-50 text-xs text-gray-400">
|
||||
{extractInitials(field.recipient.name || field.recipient.email)}
|
||||
</AvatarFallback>
|
||||
|
|
@ -191,12 +191,12 @@ export function EnvelopeRecipientFieldTooltip({
|
|||
</span>
|
||||
</p>
|
||||
|
||||
<p className="mt-1 text-center text-xs text-muted-foreground">
|
||||
<p className="text-muted-foreground mt-1 text-center text-xs">
|
||||
{getRecipientDisplayText(field.recipient)}
|
||||
</p>
|
||||
|
||||
<button
|
||||
className="absolute right-0 top-0 my-1 p-2 focus:outline-none focus-visible:ring-0"
|
||||
className="absolute top-0 right-0 my-1 p-2 focus:outline-none focus-visible:ring-0"
|
||||
onClick={() => setHideField(true)}
|
||||
title="Hide field"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -43,17 +43,13 @@ export const RecipientActionAuthSelect = ({
|
|||
})),
|
||||
];
|
||||
|
||||
// Convert string array to Option array for MultiSelect
|
||||
const selectedOptions =
|
||||
(value
|
||||
?.map((val) => authOptions.find((option) => option.value === val))
|
||||
.filter(Boolean) as Option[]) || [];
|
||||
const getSelectedOptions = (selectedValues?: string[]) =>
|
||||
selectedValues
|
||||
?.map((selectedValue) => authOptions.find((option) => option.value === selectedValue))
|
||||
.filter((option): option is Option => option !== undefined) ?? [];
|
||||
|
||||
// Convert default value to Option array
|
||||
const defaultOptions =
|
||||
(defaultValue
|
||||
?.map((val) => authOptions.find((option) => option.value === val))
|
||||
.filter(Boolean) as Option[]) || [];
|
||||
const selectedOptions = getSelectedOptions(value);
|
||||
const defaultOptions = getSelectedOptions(defaultValue);
|
||||
|
||||
const handleChange = (options: Option[]) => {
|
||||
const values = options.map((option) => option.value);
|
||||
|
|
@ -76,14 +72,14 @@ export const RecipientActionAuthSelect = ({
|
|||
|
||||
<Tooltip>
|
||||
<TooltipTrigger
|
||||
className={cn('absolute right-2 top-1/2 -translate-y-1/2', {
|
||||
className={cn('absolute top-1/2 right-2 -translate-y-1/2', {
|
||||
'right-8': selectedOptions.length > 0,
|
||||
})}
|
||||
>
|
||||
<InfoIcon className="h-4 w-4" />
|
||||
</TooltipTrigger>
|
||||
|
||||
<TooltipContent className="max-w-md p-4 text-foreground">
|
||||
<TooltipContent className="text-foreground max-w-md p-4">
|
||||
<h2>
|
||||
<strong>
|
||||
<Trans>Recipient action authentication</Trans>
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ function getBaseFontSize(): number {
|
|||
}
|
||||
|
||||
return parsed;
|
||||
} catch (error) {
|
||||
} catch {
|
||||
// Fallback to browser default if anything goes wrong
|
||||
return 16;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -101,7 +101,7 @@ export const AddFieldsFormPartial = ({
|
|||
onAutoSave,
|
||||
canGoBack = false,
|
||||
isDocumentPdfLoaded,
|
||||
teamId,
|
||||
teamId: _teamId,
|
||||
}: AddFieldsFormProps) => {
|
||||
const { toast } = useToast();
|
||||
const { _ } = useLingui();
|
||||
|
|
@ -535,22 +535,6 @@ export const AddFieldsFormPartial = ({
|
|||
);
|
||||
}, [recipients]);
|
||||
|
||||
const recipientsByRole = useMemo(() => {
|
||||
const recipientsByRole: Record<RecipientRole, Recipient[]> = {
|
||||
CC: [],
|
||||
VIEWER: [],
|
||||
SIGNER: [],
|
||||
APPROVER: [],
|
||||
ASSISTANT: [],
|
||||
};
|
||||
|
||||
recipients.forEach((recipient) => {
|
||||
recipientsByRole[recipient.role].push(recipient);
|
||||
});
|
||||
|
||||
return recipientsByRole;
|
||||
}, [recipients]);
|
||||
|
||||
const handleAdvancedSettings = () => {
|
||||
setShowAdvancedSettings((prev) => !prev);
|
||||
};
|
||||
|
|
@ -623,10 +607,10 @@ export const AddFieldsFormPartial = ({
|
|||
{selectedField && (
|
||||
<div
|
||||
className={cn(
|
||||
'dark:text-muted-background pointer-events-none fixed z-50 flex cursor-pointer flex-col items-center justify-center rounded-[2px] bg-white text-muted-foreground ring-2 transition duration-200 [container-type:size]',
|
||||
'dark:text-muted-background text-muted-foreground [container-type:size] pointer-events-none fixed z-50 flex cursor-pointer flex-col items-center justify-center rounded-[2px] bg-white ring-2 transition duration-200',
|
||||
selectedSignerStyles?.base,
|
||||
{
|
||||
'-rotate-6 scale-90 opacity-50 dark:bg-black/20': !isFieldWithinBounds,
|
||||
'scale-90 -rotate-6 opacity-50 dark:bg-black/20': !isFieldWithinBounds,
|
||||
'dark:text-black/60': isFieldWithinBounds,
|
||||
},
|
||||
)}
|
||||
|
|
@ -703,7 +687,7 @@ export const AddFieldsFormPartial = ({
|
|||
selectedRecipient={selectedSigner}
|
||||
onSelectedRecipientChange={setSelectedSigner}
|
||||
recipients={recipients}
|
||||
className="mb-12 mt-2"
|
||||
className="mt-2 mb-12"
|
||||
/>
|
||||
)}
|
||||
|
||||
|
|
@ -725,7 +709,7 @@ export const AddFieldsFormPartial = ({
|
|||
<CardContent className="flex flex-col items-center justify-center px-6 py-4">
|
||||
<p
|
||||
className={cn(
|
||||
'flex items-center justify-center gap-x-1.5 font-signature text-lg font-normal text-muted-foreground group-data-[selected]:text-foreground',
|
||||
'font-signature text-muted-foreground group-data-[selected]:text-foreground flex items-center justify-center gap-x-1.5 text-lg font-normal',
|
||||
)}
|
||||
>
|
||||
<Trans>Signature</Trans>
|
||||
|
|
@ -749,7 +733,7 @@ export const AddFieldsFormPartial = ({
|
|||
<CardContent className="flex flex-col items-center justify-center px-6 py-4">
|
||||
<p
|
||||
className={cn(
|
||||
'flex items-center justify-center gap-x-1.5 text-sm font-normal text-muted-foreground group-data-[selected]:text-foreground',
|
||||
'text-muted-foreground group-data-[selected]:text-foreground flex items-center justify-center gap-x-1.5 text-sm font-normal',
|
||||
)}
|
||||
>
|
||||
<Contact className="h-4 w-4" />
|
||||
|
|
@ -774,7 +758,7 @@ export const AddFieldsFormPartial = ({
|
|||
<CardContent className="flex flex-col items-center justify-center px-6 py-4">
|
||||
<p
|
||||
className={cn(
|
||||
'flex items-center justify-center gap-x-1.5 text-sm font-normal text-muted-foreground group-data-[selected]:text-foreground',
|
||||
'text-muted-foreground group-data-[selected]:text-foreground flex items-center justify-center gap-x-1.5 text-sm font-normal',
|
||||
)}
|
||||
>
|
||||
<Mail className="h-4 w-4" />
|
||||
|
|
@ -799,7 +783,7 @@ export const AddFieldsFormPartial = ({
|
|||
<CardContent className="p-4">
|
||||
<p
|
||||
className={cn(
|
||||
'flex items-center justify-center gap-x-1.5 text-sm font-normal text-muted-foreground group-data-[selected]:text-foreground',
|
||||
'text-muted-foreground group-data-[selected]:text-foreground flex items-center justify-center gap-x-1.5 text-sm font-normal',
|
||||
)}
|
||||
>
|
||||
<User className="h-4 w-4" />
|
||||
|
|
@ -824,7 +808,7 @@ export const AddFieldsFormPartial = ({
|
|||
<CardContent className="p-4">
|
||||
<p
|
||||
className={cn(
|
||||
'flex items-center justify-center gap-x-1.5 text-sm font-normal text-muted-foreground group-data-[selected]:text-foreground',
|
||||
'text-muted-foreground group-data-[selected]:text-foreground flex items-center justify-center gap-x-1.5 text-sm font-normal',
|
||||
)}
|
||||
>
|
||||
<CalendarDays className="h-4 w-4" />
|
||||
|
|
@ -849,7 +833,7 @@ export const AddFieldsFormPartial = ({
|
|||
<CardContent className="p-4">
|
||||
<p
|
||||
className={cn(
|
||||
'flex items-center justify-center gap-x-1.5 text-sm font-normal text-muted-foreground group-data-[selected]:text-foreground',
|
||||
'text-muted-foreground group-data-[selected]:text-foreground flex items-center justify-center gap-x-1.5 text-sm font-normal',
|
||||
)}
|
||||
>
|
||||
<Type className="h-4 w-4" />
|
||||
|
|
@ -874,7 +858,7 @@ export const AddFieldsFormPartial = ({
|
|||
<CardContent className="p-4">
|
||||
<p
|
||||
className={cn(
|
||||
'flex items-center justify-center gap-x-1.5 text-sm font-normal text-muted-foreground group-data-[selected]:text-foreground',
|
||||
'text-muted-foreground group-data-[selected]:text-foreground flex items-center justify-center gap-x-1.5 text-sm font-normal',
|
||||
)}
|
||||
>
|
||||
<Hash className="h-4 w-4" />
|
||||
|
|
@ -899,7 +883,7 @@ export const AddFieldsFormPartial = ({
|
|||
<CardContent className="p-4">
|
||||
<p
|
||||
className={cn(
|
||||
'flex items-center justify-center gap-x-1.5 text-sm font-normal text-muted-foreground group-data-[selected]:text-foreground',
|
||||
'text-muted-foreground group-data-[selected]:text-foreground flex items-center justify-center gap-x-1.5 text-sm font-normal',
|
||||
)}
|
||||
>
|
||||
<Disc className="h-4 w-4" />
|
||||
|
|
@ -924,7 +908,7 @@ export const AddFieldsFormPartial = ({
|
|||
<CardContent className="p-4">
|
||||
<p
|
||||
className={cn(
|
||||
'flex items-center justify-center gap-x-1.5 text-sm font-normal text-muted-foreground group-data-[selected]:text-foreground',
|
||||
'text-muted-foreground group-data-[selected]:text-foreground flex items-center justify-center gap-x-1.5 text-sm font-normal',
|
||||
)}
|
||||
>
|
||||
<CheckSquare className="h-4 w-4" />
|
||||
|
|
@ -949,7 +933,7 @@ export const AddFieldsFormPartial = ({
|
|||
<CardContent className="p-4">
|
||||
<p
|
||||
className={cn(
|
||||
'flex items-center justify-center gap-x-1.5 text-sm font-normal text-muted-foreground group-data-[selected]:text-foreground',
|
||||
'text-muted-foreground group-data-[selected]:text-foreground flex items-center justify-center gap-x-1.5 text-sm font-normal',
|
||||
)}
|
||||
>
|
||||
<ChevronDown className="h-4 w-4" />
|
||||
|
|
|
|||
|
|
@ -242,7 +242,7 @@ export const AddSettingsFormPartial = ({
|
|||
<InfoIcon className="mx-2 h-4 w-4" />
|
||||
</TooltipTrigger>
|
||||
|
||||
<TooltipContent className="max-w-md space-y-2 p-4 text-foreground">
|
||||
<TooltipContent className="text-foreground max-w-md space-y-2 p-4">
|
||||
<Trans>
|
||||
Controls the language for the document, including the language to be used
|
||||
for email notifications, and the final certificate that is generated and
|
||||
|
|
@ -361,11 +361,11 @@ export const AddSettingsFormPartial = ({
|
|||
|
||||
<Accordion type="multiple" className="mt-6">
|
||||
<AccordionItem value="advanced-options" className="border-none">
|
||||
<AccordionTrigger className="mb-2 rounded border px-3 py-2 text-left text-foreground hover:bg-neutral-200/30 hover:no-underline">
|
||||
<AccordionTrigger className="text-foreground mb-2 rounded border px-3 py-2 text-left hover:bg-neutral-200/30 hover:no-underline">
|
||||
<Trans>Advanced Options</Trans>
|
||||
</AccordionTrigger>
|
||||
|
||||
<AccordionContent className="-mx-1 px-1 pt-2 text-sm leading-relaxed text-muted-foreground">
|
||||
<AccordionContent className="text-muted-foreground -mx-1 px-1 pt-2 text-sm leading-relaxed">
|
||||
<div className="flex flex-col space-y-6">
|
||||
<FormField
|
||||
control={form.control}
|
||||
|
|
@ -379,7 +379,7 @@ export const AddSettingsFormPartial = ({
|
|||
<InfoIcon className="mx-2 h-4 w-4" />
|
||||
</TooltipTrigger>
|
||||
|
||||
<TooltipContent className="max-w-xs text-muted-foreground">
|
||||
<TooltipContent className="text-muted-foreground max-w-xs">
|
||||
<Trans>
|
||||
Add an external ID to the document. This can be used to identify
|
||||
the document in external systems.
|
||||
|
|
@ -418,7 +418,7 @@ export const AddSettingsFormPartial = ({
|
|||
field.onChange(value);
|
||||
void handleAutoSave();
|
||||
}}
|
||||
className="w-full bg-background"
|
||||
className="bg-background w-full"
|
||||
emptySelectionPlaceholder={t`Select signature types`}
|
||||
/>
|
||||
</FormControl>
|
||||
|
|
@ -481,7 +481,10 @@ export const AddSettingsFormPartial = ({
|
|||
options={TIME_ZONES}
|
||||
{...field}
|
||||
onChange={(value) => {
|
||||
value && field.onChange(value);
|
||||
if (value) {
|
||||
field.onChange(value);
|
||||
}
|
||||
|
||||
void handleAutoSave();
|
||||
}}
|
||||
value={field.value}
|
||||
|
|
@ -506,7 +509,7 @@ export const AddSettingsFormPartial = ({
|
|||
<InfoIcon className="mx-2 h-4 w-4" />
|
||||
</TooltipTrigger>
|
||||
|
||||
<TooltipContent className="max-w-xs text-muted-foreground">
|
||||
<TooltipContent className="text-muted-foreground max-w-xs">
|
||||
<Trans>
|
||||
Add a URL to redirect the user to once the document is signed
|
||||
</Trans>
|
||||
|
|
|
|||
|
|
@ -69,8 +69,8 @@ export type AddSubjectFormProps = {
|
|||
|
||||
export const AddSubjectFormPartial = ({
|
||||
documentFlow,
|
||||
recipients: recipients,
|
||||
fields: fields,
|
||||
recipients,
|
||||
fields,
|
||||
document,
|
||||
onSubmit,
|
||||
onAutoSave,
|
||||
|
|
@ -323,7 +323,7 @@ export const AddSubjectFormPartial = ({
|
|||
<TooltipTrigger>
|
||||
<InfoIcon className="mx-2 h-4 w-4" />
|
||||
</TooltipTrigger>
|
||||
<TooltipContent className="p-4 text-muted-foreground">
|
||||
<TooltipContent className="text-muted-foreground p-4">
|
||||
<DocumentSendEmailMessageHelper />
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
|
|
@ -331,7 +331,7 @@ export const AddSubjectFormPartial = ({
|
|||
|
||||
<FormControl>
|
||||
<Textarea
|
||||
className="mt-2 h-16 resize-none bg-background"
|
||||
className="bg-background mt-2 h-16 resize-none"
|
||||
{...field}
|
||||
maxLength={5000}
|
||||
/>
|
||||
|
|
@ -360,7 +360,7 @@ export const AddSubjectFormPartial = ({
|
|||
className="rounded-lg border"
|
||||
>
|
||||
{document.status === DocumentStatus.DRAFT ? (
|
||||
<div className="py-16 text-center text-sm text-muted-foreground">
|
||||
<div className="text-muted-foreground py-16 text-center text-sm">
|
||||
<p>
|
||||
<Trans>We won't send anything to notify recipients.</Trans>
|
||||
</p>
|
||||
|
|
@ -373,7 +373,7 @@ export const AddSubjectFormPartial = ({
|
|||
</p>
|
||||
</div>
|
||||
) : (
|
||||
<ul className="divide-y text-muted-foreground">
|
||||
<ul className="text-muted-foreground divide-y">
|
||||
{recipients.length === 0 && (
|
||||
<li className="flex flex-col items-center justify-center py-6 text-sm">
|
||||
<Trans>No recipients</Trans>
|
||||
|
|
@ -388,10 +388,10 @@ export const AddSubjectFormPartial = ({
|
|||
<AvatarWithText
|
||||
avatarFallback={recipient.email.slice(0, 1).toUpperCase()}
|
||||
primaryText={
|
||||
<p className="text-sm text-muted-foreground">{recipient.email}</p>
|
||||
<p className="text-muted-foreground text-sm">{recipient.email}</p>
|
||||
}
|
||||
secondaryText={
|
||||
<p className="text-xs text-muted-foreground/70">
|
||||
<p className="text-muted-foreground/70 text-xs">
|
||||
{_(RECIPIENT_ROLES_DESCRIPTION[recipient.role].roleName)}
|
||||
</p>
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ export type DocumentUploadButtonProps = {
|
|||
};
|
||||
|
||||
export const DocumentUploadButton = ({
|
||||
className,
|
||||
className: _className,
|
||||
loading,
|
||||
onDrop,
|
||||
onDropRejected,
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ export interface FieldSelectorProps {
|
|||
}
|
||||
|
||||
export const FieldSelector = ({
|
||||
className,
|
||||
className: _className,
|
||||
selectedField,
|
||||
onSelectedFieldChange,
|
||||
disabled = false,
|
||||
|
|
@ -104,10 +104,10 @@ export const FieldSelector = ({
|
|||
)}
|
||||
>
|
||||
<CardContent className="relative flex items-center justify-center gap-x-2 px-6 py-4">
|
||||
{Icon && <Icon className="h-4 w-4 text-muted-foreground" />}
|
||||
{Icon && <Icon className="text-muted-foreground h-4 w-4" />}
|
||||
<span
|
||||
className={cn(
|
||||
'text-sm text-muted-foreground group-data-[selected]:text-foreground',
|
||||
'text-muted-foreground group-data-[selected]:text-foreground text-sm',
|
||||
field.type === FieldType.SIGNATURE && 'invisible',
|
||||
)}
|
||||
>
|
||||
|
|
@ -115,7 +115,7 @@ export const FieldSelector = ({
|
|||
</span>
|
||||
|
||||
{field.type === FieldType.SIGNATURE && (
|
||||
<div className="absolute inset-0 flex items-center justify-center font-signature text-lg text-muted-foreground">
|
||||
<div className="font-signature text-muted-foreground absolute inset-0 flex items-center justify-center text-lg">
|
||||
<Trans>Signature</Trans>
|
||||
</div>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import { cn } from '../../lib/utils';
|
|||
|
||||
export type FormErrorMessageProps = {
|
||||
className?: string;
|
||||
error: { message?: string } | undefined | unknown;
|
||||
error: unknown;
|
||||
};
|
||||
|
||||
const isErrorWithMessage = (error: unknown): error is { message?: string } => {
|
||||
|
|
|
|||
|
|
@ -99,17 +99,24 @@ function transToGroupOption(options: Option[], groupBy?: string) {
|
|||
|
||||
const groupOption: GroupOption = {};
|
||||
options.forEach((option) => {
|
||||
const key = (option[groupBy] as string) || '';
|
||||
const groupValue = option[groupBy];
|
||||
const key = typeof groupValue === 'string' ? groupValue : groupValue ? String(groupValue) : '';
|
||||
|
||||
if (!groupOption[key]) {
|
||||
groupOption[key] = [];
|
||||
}
|
||||
|
||||
groupOption[key].push(option);
|
||||
});
|
||||
return groupOption;
|
||||
}
|
||||
|
||||
function removePickedOption(groupOption: GroupOption, picked: Option[]) {
|
||||
const cloneOption = JSON.parse(JSON.stringify(groupOption)) as GroupOption;
|
||||
const cloneOption: GroupOption = {};
|
||||
|
||||
for (const [key, value] of Object.entries(groupOption)) {
|
||||
cloneOption[key] = [...value];
|
||||
}
|
||||
|
||||
for (const [key, value] of Object.entries(cloneOption)) {
|
||||
cloneOption[key] = value.filter((val) => !picked.find((p) => p.value === val.value));
|
||||
|
|
@ -186,11 +193,17 @@ const MultiSelect = ({
|
|||
const debouncedSearchTerm = useDebounce(inputValue, delay || 500);
|
||||
|
||||
const handleClickOutside = (event: MouseEvent | TouchEvent) => {
|
||||
const target = event.target;
|
||||
|
||||
if (!(target instanceof Node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
dropdownRef.current &&
|
||||
!dropdownRef.current.contains(event.target as Node) &&
|
||||
!dropdownRef.current.contains(target) &&
|
||||
inputRef.current &&
|
||||
!inputRef.current.contains(event.target as Node)
|
||||
!inputRef.current.contains(target)
|
||||
) {
|
||||
setOpen(false);
|
||||
inputRef.current.blur();
|
||||
|
|
@ -408,7 +421,7 @@ const MultiSelect = ({
|
|||
>
|
||||
<div
|
||||
className={cn(
|
||||
'has-aria-invalid:ring-destructive/20 dark:has-aria-invalid:ring-destructive/40 has-aria-invalid:border-destructive has-disabled:pointer-events-none has-disabled:cursor-not-allowed has-disabled:opacity-50 relative min-h-[38px] rounded-md border border-input text-sm outline-none transition-[color,box-shadow] focus-within:border-ring focus-within:ring-[3px] focus-within:ring-ring/50',
|
||||
'has-aria-invalid:ring-destructive/20 dark:has-aria-invalid:ring-destructive/40 has-aria-invalid:border-destructive border-input focus-within:border-ring focus-within:ring-ring/50 relative min-h-[38px] rounded-md border text-sm transition-[color,box-shadow] outline-none focus-within:ring-[3px] has-disabled:pointer-events-none has-disabled:cursor-not-allowed has-disabled:opacity-50',
|
||||
{
|
||||
'p-1': selected.length !== 0,
|
||||
'cursor-text': !disabled && selected.length !== 0,
|
||||
|
|
@ -427,7 +440,7 @@ const MultiSelect = ({
|
|||
<div
|
||||
key={option.value}
|
||||
className={cn(
|
||||
'animate-fadeIn data-fixed:pe-2 relative inline-flex h-7 cursor-default items-center rounded-md border bg-background pe-7 pl-2 ps-2 text-xs font-medium text-secondary-foreground transition-all hover:bg-background disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50',
|
||||
'animate-fadeIn bg-background text-secondary-foreground hover:bg-background relative inline-flex h-7 cursor-default items-center rounded-md border ps-2 pe-7 pl-2 text-xs font-medium transition-all disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 data-fixed:pe-2',
|
||||
badgeClassName,
|
||||
)}
|
||||
data-fixed={option.fixed}
|
||||
|
|
@ -435,7 +448,7 @@ const MultiSelect = ({
|
|||
>
|
||||
{option.label}
|
||||
<button
|
||||
className="absolute -inset-y-px -end-px flex size-7 items-center justify-center rounded-e-md border border-transparent p-0 text-muted-foreground/80 outline-none transition-[color,box-shadow] hover:text-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50"
|
||||
className="text-muted-foreground/80 hover:text-foreground focus-visible:border-ring focus-visible:ring-ring/50 absolute -inset-y-px -end-px flex size-7 items-center justify-center rounded-e-md border border-transparent p-0 transition-[color,box-shadow] outline-none focus-visible:ring-[3px]"
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Enter') {
|
||||
handleUnselect(option);
|
||||
|
|
@ -478,7 +491,7 @@ const MultiSelect = ({
|
|||
}}
|
||||
placeholder={hidePlaceholderWhenSelected && selected.length !== 0 ? '' : placeholder}
|
||||
className={cn(
|
||||
'flex-1 bg-transparent outline-none placeholder:text-muted-foreground/70 disabled:cursor-not-allowed',
|
||||
'placeholder:text-muted-foreground/70 flex-1 bg-transparent outline-none disabled:cursor-not-allowed',
|
||||
{
|
||||
'w-full': hidePlaceholderWhenSelected,
|
||||
'px-3 py-2': selected.length === 0,
|
||||
|
|
@ -494,7 +507,7 @@ const MultiSelect = ({
|
|||
onChange?.(selected.filter((s) => s.fixed));
|
||||
}}
|
||||
className={cn(
|
||||
'absolute end-0 top-0 flex size-9 items-center justify-center rounded-md border border-transparent text-muted-foreground/80 outline-none transition-[color,box-shadow] hover:text-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50',
|
||||
'text-muted-foreground/80 hover:text-foreground focus-visible:border-ring focus-visible:ring-ring/50 absolute end-0 top-0 flex size-9 items-center justify-center rounded-md border border-transparent transition-[color,box-shadow] outline-none focus-visible:ring-[3px]',
|
||||
(hideClearAllButton ||
|
||||
disabled ||
|
||||
selected.length < 1 ||
|
||||
|
|
@ -510,7 +523,7 @@ const MultiSelect = ({
|
|||
<div className="relative">
|
||||
<div
|
||||
className={cn(
|
||||
'absolute top-2 z-10 w-full overflow-hidden rounded-md border border-input',
|
||||
'border-input absolute top-2 z-10 w-full overflow-hidden rounded-md border',
|
||||
'data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95',
|
||||
!open && 'hidden',
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -51,24 +51,18 @@ export const RecipientSelector = ({
|
|||
}, [recipients]);
|
||||
|
||||
const recipientsByRoleToDisplay = useMemo(() => {
|
||||
return Object.entries(recipientsByRole)
|
||||
.filter(
|
||||
([role]) =>
|
||||
role !== RecipientRole.CC &&
|
||||
role !== RecipientRole.VIEWER &&
|
||||
role !== RecipientRole.ASSISTANT,
|
||||
)
|
||||
.map(
|
||||
([role, roleRecipients]) =>
|
||||
[
|
||||
role,
|
||||
sortBy(
|
||||
roleRecipients,
|
||||
[(r) => r.signingOrder || Number.MAX_SAFE_INTEGER, 'asc'],
|
||||
[(r) => r.id, 'asc'],
|
||||
),
|
||||
] as [RecipientRole, Recipient[]],
|
||||
);
|
||||
return [RecipientRole.SIGNER, RecipientRole.APPROVER].map((role) => {
|
||||
const roleRecipients = recipientsByRole[role];
|
||||
|
||||
return [
|
||||
role,
|
||||
sortBy(
|
||||
roleRecipients,
|
||||
[(r) => r.signingOrder || Number.MAX_SAFE_INTEGER, 'asc'],
|
||||
[(r) => r.id, 'asc'],
|
||||
),
|
||||
] satisfies [RecipientRole, Recipient[]];
|
||||
});
|
||||
}, [recipientsByRole]);
|
||||
|
||||
const getRecipientLabel = useCallback(
|
||||
|
|
@ -101,7 +95,7 @@ export const RecipientSelector = ({
|
|||
variant="outline"
|
||||
role="combobox"
|
||||
className={cn(
|
||||
'justify-between bg-background font-normal text-muted-foreground hover:text-foreground',
|
||||
'bg-background text-muted-foreground hover:text-foreground justify-between font-normal',
|
||||
getRecipientColorStyles(
|
||||
Math.max(
|
||||
recipients.findIndex((r) => r.id === selectedRecipient?.id),
|
||||
|
|
@ -126,21 +120,21 @@ export const RecipientSelector = ({
|
|||
<CommandInput />
|
||||
|
||||
<CommandEmpty>
|
||||
<span className="inline-block px-4 text-muted-foreground">
|
||||
<span className="text-muted-foreground inline-block px-4">
|
||||
<Trans>No recipient matching this description was found.</Trans>
|
||||
</span>
|
||||
</CommandEmpty>
|
||||
|
||||
{recipientsByRoleToDisplay.map(([role, roleRecipients], roleIndex) => (
|
||||
<CommandGroup key={roleIndex}>
|
||||
<div className="mb-1 ml-2 mt-2 text-xs font-medium text-muted-foreground">
|
||||
<div className="text-muted-foreground mt-2 mb-1 ml-2 text-xs font-medium">
|
||||
{_(RECIPIENT_ROLES_DESCRIPTION[role].roleNamePlural)}
|
||||
</div>
|
||||
|
||||
{roleRecipients.length === 0 && (
|
||||
<div
|
||||
key={`${role}-empty`}
|
||||
className="px-4 pb-4 pt-2.5 text-center text-xs text-muted-foreground/80"
|
||||
className="text-muted-foreground/80 px-4 pt-2.5 pb-4 text-center text-xs"
|
||||
>
|
||||
<Trans>No recipients with this role</Trans>
|
||||
</div>
|
||||
|
|
@ -168,7 +162,7 @@ export const RecipientSelector = ({
|
|||
disabled={recipient.signingStatus !== SigningStatus.NOT_SIGNED}
|
||||
>
|
||||
<span
|
||||
className={cn('truncate text-foreground/70', {
|
||||
className={cn('text-foreground/70 truncate', {
|
||||
'text-foreground/80': recipient.id === selectedRecipient?.id,
|
||||
})}
|
||||
>
|
||||
|
|
@ -190,7 +184,7 @@ export const RecipientSelector = ({
|
|||
<Info className="ml-2 h-4 w-4" />
|
||||
</TooltipTrigger>
|
||||
|
||||
<TooltipContent className="max-w-xs text-muted-foreground">
|
||||
<TooltipContent className="text-muted-foreground max-w-xs">
|
||||
<Trans>
|
||||
This document has already been sent to this recipient. You can no longer
|
||||
edit this recipient.
|
||||
|
|
|
|||
|
|
@ -172,7 +172,9 @@ export class Canvas {
|
|||
event.preventDefault();
|
||||
}
|
||||
|
||||
event.buttons === 1 && this.onMouseDown(event);
|
||||
if (event.buttons === 1) {
|
||||
this.onMouseDown(event);
|
||||
}
|
||||
}
|
||||
|
||||
private onMouseLeave(event: MouseEvent): void {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import type { MessageDescriptor } from '@lingui/core';
|
|||
import { Trans, useLingui } from '@lingui/react/macro';
|
||||
import { motion } from 'framer-motion';
|
||||
|
||||
import { parseMessageDescriptor } from '@documenso/lib/utils/i18n';
|
||||
import { Dialog, DialogClose, DialogContent, DialogFooter } from '@documenso/ui/primitives/dialog';
|
||||
|
||||
import { cn } from '../../lib/utils';
|
||||
|
|
@ -45,7 +44,7 @@ export const SignaturePadDialog = ({
|
|||
return (
|
||||
<div
|
||||
className={cn(
|
||||
'relative block aspect-signature-pad w-full select-none rounded-lg border bg-background',
|
||||
'aspect-signature-pad bg-background relative block w-full rounded-lg border select-none',
|
||||
className,
|
||||
{
|
||||
'pointer-events-none opacity-50': disabled,
|
||||
|
|
@ -140,7 +139,11 @@ export const SignaturePadDialog = ({
|
|||
}}
|
||||
>
|
||||
{dialogConfirmText ? (
|
||||
parseMessageDescriptor(i18n._, dialogConfirmText)
|
||||
typeof dialogConfirmText === 'string' ? (
|
||||
dialogConfirmText
|
||||
) : (
|
||||
i18n._(dialogConfirmText)
|
||||
)
|
||||
) : (
|
||||
<Trans>Next</Trans>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ export const Stepper: FC<StepperProps> = ({
|
|||
|
||||
const nextStep = () => {
|
||||
if (currentStep < totalSteps) {
|
||||
void handleStepChange(currentStep + 1);
|
||||
handleStepChange(currentStep + 1);
|
||||
} else {
|
||||
void handleComplete();
|
||||
}
|
||||
|
|
@ -72,7 +72,7 @@ export const Stepper: FC<StepperProps> = ({
|
|||
|
||||
const previousStep = () => {
|
||||
if (currentStep > 1) {
|
||||
void handleStepChange(currentStep - 1);
|
||||
handleStepChange(currentStep - 1);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ export const AddTemplateFieldsFormPartial = ({
|
|||
fields,
|
||||
onSubmit,
|
||||
onAutoSave,
|
||||
teamId,
|
||||
teamId: _teamId,
|
||||
}: AddTemplateFieldsFormProps) => {
|
||||
const { _ } = useLingui();
|
||||
const { toast } = useToast();
|
||||
|
|
@ -581,10 +581,10 @@ export const AddTemplateFieldsFormPartial = ({
|
|||
{selectedField && (
|
||||
<div
|
||||
className={cn(
|
||||
'dark:text-muted-background pointer-events-none fixed z-50 flex cursor-pointer flex-col items-center justify-center rounded-[2px] bg-white text-muted-foreground ring-2 transition duration-200 [container-type:size]',
|
||||
'dark:text-muted-background text-muted-foreground [container-type:size] pointer-events-none fixed z-50 flex cursor-pointer flex-col items-center justify-center rounded-[2px] bg-white ring-2 transition duration-200',
|
||||
selectedSignerStyles?.base,
|
||||
{
|
||||
'-rotate-6 scale-90 opacity-50 dark:bg-black/20': !isFieldWithinBounds,
|
||||
'scale-90 -rotate-6 opacity-50 dark:bg-black/20': !isFieldWithinBounds,
|
||||
'dark:text-black/60': isFieldWithinBounds,
|
||||
},
|
||||
)}
|
||||
|
|
@ -650,7 +650,7 @@ export const AddTemplateFieldsFormPartial = ({
|
|||
variant="outline"
|
||||
role="combobox"
|
||||
className={cn(
|
||||
'mb-12 mt-2 justify-between bg-background font-normal text-muted-foreground hover:text-foreground',
|
||||
'bg-background text-muted-foreground hover:text-foreground mt-2 mb-12 justify-between font-normal',
|
||||
selectedSignerStyles?.comboxBoxTrigger,
|
||||
)}
|
||||
>
|
||||
|
|
@ -681,7 +681,7 @@ export const AddTemplateFieldsFormPartial = ({
|
|||
<CommandInput />
|
||||
|
||||
<CommandEmpty>
|
||||
<span className="inline-block px-4 text-muted-foreground">
|
||||
<span className="text-muted-foreground inline-block px-4">
|
||||
<Trans>No recipient matching this description was found.</Trans>
|
||||
</span>
|
||||
</CommandEmpty>
|
||||
|
|
@ -689,14 +689,14 @@ export const AddTemplateFieldsFormPartial = ({
|
|||
{/* Note: This is duplicated in `add-fields.tsx` */}
|
||||
{recipientsByRoleToDisplay.map(([role, roleRecipients], roleIndex) => (
|
||||
<CommandGroup key={roleIndex}>
|
||||
<div className="mb-1 ml-2 mt-2 text-xs font-medium text-muted-foreground">
|
||||
<div className="text-muted-foreground mt-2 mb-1 ml-2 text-xs font-medium">
|
||||
{_(RECIPIENT_ROLES_DESCRIPTION[role].roleNamePlural)}
|
||||
</div>
|
||||
|
||||
{roleRecipients.length === 0 && (
|
||||
<div
|
||||
key={`${role}-empty`}
|
||||
className="px-4 pb-4 pt-2.5 text-center text-xs text-muted-foreground/80"
|
||||
className="text-muted-foreground/80 px-4 pt-2.5 pb-4 text-center text-xs"
|
||||
>
|
||||
<Trans>No recipients with this role</Trans>
|
||||
</div>
|
||||
|
|
@ -720,7 +720,7 @@ export const AddTemplateFieldsFormPartial = ({
|
|||
}}
|
||||
>
|
||||
<span
|
||||
className={cn('truncate text-foreground/70', {
|
||||
className={cn('text-foreground/70 truncate', {
|
||||
'text-foreground/80': recipient === selectedSigner,
|
||||
})}
|
||||
>
|
||||
|
|
@ -768,7 +768,7 @@ export const AddTemplateFieldsFormPartial = ({
|
|||
<CardContent className="flex flex-col items-center justify-center px-6 py-4">
|
||||
<p
|
||||
className={cn(
|
||||
'flex items-center justify-center gap-x-1.5 font-signature text-lg font-normal text-muted-foreground group-data-[selected]:text-foreground',
|
||||
'font-signature text-muted-foreground group-data-[selected]:text-foreground flex items-center justify-center gap-x-1.5 text-lg font-normal',
|
||||
)}
|
||||
>
|
||||
<Trans>Signature</Trans>
|
||||
|
|
@ -793,7 +793,7 @@ export const AddTemplateFieldsFormPartial = ({
|
|||
<CardContent className="flex flex-col items-center justify-center px-6 py-4">
|
||||
<p
|
||||
className={cn(
|
||||
'flex items-center justify-center gap-x-1.5 text-sm font-normal text-muted-foreground group-data-[selected]:text-foreground',
|
||||
'text-muted-foreground group-data-[selected]:text-foreground flex items-center justify-center gap-x-1.5 text-sm font-normal',
|
||||
)}
|
||||
>
|
||||
<Contact className="h-4 w-4" />
|
||||
|
|
@ -819,7 +819,7 @@ export const AddTemplateFieldsFormPartial = ({
|
|||
<CardContent className="p-4">
|
||||
<p
|
||||
className={cn(
|
||||
'flex items-center justify-center gap-x-1.5 text-sm font-normal text-muted-foreground group-data-[selected]:text-foreground',
|
||||
'text-muted-foreground group-data-[selected]:text-foreground flex items-center justify-center gap-x-1.5 text-sm font-normal',
|
||||
)}
|
||||
>
|
||||
<Mail className="h-4 w-4" />
|
||||
|
|
@ -845,7 +845,7 @@ export const AddTemplateFieldsFormPartial = ({
|
|||
<CardContent className="p-4">
|
||||
<p
|
||||
className={cn(
|
||||
'flex items-center justify-center gap-x-1.5 text-sm font-normal text-muted-foreground group-data-[selected]:text-foreground',
|
||||
'text-muted-foreground group-data-[selected]:text-foreground flex items-center justify-center gap-x-1.5 text-sm font-normal',
|
||||
)}
|
||||
>
|
||||
<User className="h-4 w-4" />
|
||||
|
|
@ -871,7 +871,7 @@ export const AddTemplateFieldsFormPartial = ({
|
|||
<CardContent className="p-4">
|
||||
<p
|
||||
className={cn(
|
||||
'flex items-center justify-center gap-x-1.5 text-sm font-normal text-muted-foreground group-data-[selected]:text-foreground',
|
||||
'text-muted-foreground group-data-[selected]:text-foreground flex items-center justify-center gap-x-1.5 text-sm font-normal',
|
||||
)}
|
||||
>
|
||||
<CalendarDays className="h-4 w-4" />
|
||||
|
|
@ -897,7 +897,7 @@ export const AddTemplateFieldsFormPartial = ({
|
|||
<CardContent className="p-4">
|
||||
<p
|
||||
className={cn(
|
||||
'flex items-center justify-center gap-x-1.5 text-sm font-normal text-muted-foreground group-data-[selected]:text-foreground',
|
||||
'text-muted-foreground group-data-[selected]:text-foreground flex items-center justify-center gap-x-1.5 text-sm font-normal',
|
||||
)}
|
||||
>
|
||||
<Type className="h-4 w-4" />
|
||||
|
|
@ -923,7 +923,7 @@ export const AddTemplateFieldsFormPartial = ({
|
|||
<CardContent className="p-4">
|
||||
<p
|
||||
className={cn(
|
||||
'flex items-center justify-center gap-x-1.5 text-sm font-normal text-muted-foreground group-data-[selected]:text-foreground',
|
||||
'text-muted-foreground group-data-[selected]:text-foreground flex items-center justify-center gap-x-1.5 text-sm font-normal',
|
||||
)}
|
||||
>
|
||||
<Hash className="h-4 w-4" />
|
||||
|
|
@ -949,7 +949,7 @@ export const AddTemplateFieldsFormPartial = ({
|
|||
<CardContent className="p-4">
|
||||
<p
|
||||
className={cn(
|
||||
'flex items-center justify-center gap-x-1.5 text-sm font-normal text-muted-foreground group-data-[selected]:text-foreground',
|
||||
'text-muted-foreground group-data-[selected]:text-foreground flex items-center justify-center gap-x-1.5 text-sm font-normal',
|
||||
)}
|
||||
>
|
||||
<Disc className="h-4 w-4" />
|
||||
|
|
@ -975,7 +975,7 @@ export const AddTemplateFieldsFormPartial = ({
|
|||
<CardContent className="p-4">
|
||||
<p
|
||||
className={cn(
|
||||
'flex items-center justify-center gap-x-1.5 text-sm font-normal text-muted-foreground group-data-[selected]:text-foreground',
|
||||
'text-muted-foreground group-data-[selected]:text-foreground flex items-center justify-center gap-x-1.5 text-sm font-normal',
|
||||
)}
|
||||
>
|
||||
<CheckSquare className="h-4 w-4" />
|
||||
|
|
@ -1001,7 +1001,7 @@ export const AddTemplateFieldsFormPartial = ({
|
|||
<CardContent className="p-4">
|
||||
<p
|
||||
className={cn(
|
||||
'flex items-center justify-center gap-x-1.5 text-sm font-normal text-muted-foreground group-data-[selected]:text-foreground',
|
||||
'text-muted-foreground group-data-[selected]:text-foreground flex items-center justify-center gap-x-1.5 text-sm font-normal',
|
||||
)}
|
||||
>
|
||||
<ChevronDown className="h-4 w-4" />
|
||||
|
|
|
|||
|
|
@ -239,7 +239,7 @@ export const AddTemplateSettingsFormPartial = ({
|
|||
<InfoIcon className="mx-2 h-4 w-4" />
|
||||
</TooltipTrigger>
|
||||
|
||||
<TooltipContent className="max-w-md space-y-2 p-4 text-foreground">
|
||||
<TooltipContent className="text-foreground max-w-md space-y-2 p-4">
|
||||
Controls the language for the document, including the language to be used
|
||||
for email notifications, and the final certificate that is generated and
|
||||
attached to the document.
|
||||
|
|
@ -337,7 +337,7 @@ export const AddTemplateSettingsFormPartial = ({
|
|||
<InfoIcon className="mx-2 h-4 w-4" />
|
||||
</TooltipTrigger>
|
||||
|
||||
<TooltipContent className="max-w-md space-y-2 p-4 text-foreground">
|
||||
<TooltipContent className="text-foreground max-w-md space-y-2 p-4">
|
||||
<h2>
|
||||
<strong>
|
||||
<Trans>Document Distribution Method</Trans>
|
||||
|
|
@ -423,7 +423,7 @@ export const AddTemplateSettingsFormPartial = ({
|
|||
field.onChange(value);
|
||||
void handleAutoSave();
|
||||
}}
|
||||
className="w-full bg-background"
|
||||
className="bg-background w-full"
|
||||
emptySelectionPlaceholder={t`Select signature types`}
|
||||
/>
|
||||
</FormControl>
|
||||
|
|
@ -463,11 +463,11 @@ export const AddTemplateSettingsFormPartial = ({
|
|||
{distributionMethod === DocumentDistributionMethod.EMAIL && (
|
||||
<Accordion type="multiple">
|
||||
<AccordionItem value="email-options" className="border-none">
|
||||
<AccordionTrigger className="rounded border px-3 py-2 text-left text-foreground hover:bg-neutral-200/30 hover:no-underline">
|
||||
<AccordionTrigger className="text-foreground rounded border px-3 py-2 text-left hover:bg-neutral-200/30 hover:no-underline">
|
||||
<Trans>Email Options</Trans>
|
||||
</AccordionTrigger>
|
||||
|
||||
<AccordionContent className="-mx-1 px-1 pt-4 text-sm leading-relaxed text-muted-foreground [&>div]:pb-0">
|
||||
<AccordionContent className="text-muted-foreground -mx-1 px-1 pt-4 text-sm leading-relaxed [&>div]:pb-0">
|
||||
<div className="flex flex-col space-y-6">
|
||||
{organisation.organisationClaim.flags.emailDomains && (
|
||||
<FormField
|
||||
|
|
@ -566,7 +566,7 @@ export const AddTemplateSettingsFormPartial = ({
|
|||
<TooltipTrigger>
|
||||
<InfoIcon className="mx-2 h-4 w-4" />
|
||||
</TooltipTrigger>
|
||||
<TooltipContent className="p-4 text-muted-foreground">
|
||||
<TooltipContent className="text-muted-foreground p-4">
|
||||
<DocumentSendEmailMessageHelper />
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
|
|
@ -574,7 +574,7 @@ export const AddTemplateSettingsFormPartial = ({
|
|||
|
||||
<FormControl>
|
||||
<Textarea
|
||||
className="h-16 resize-none bg-background"
|
||||
className="bg-background h-16 resize-none"
|
||||
{...field}
|
||||
maxLength={5000}
|
||||
onBlur={handleAutoSave}
|
||||
|
|
@ -603,11 +603,11 @@ export const AddTemplateSettingsFormPartial = ({
|
|||
|
||||
<Accordion type="multiple">
|
||||
<AccordionItem value="advanced-options" className="border-none">
|
||||
<AccordionTrigger className="rounded border px-3 py-2 text-left text-foreground hover:bg-neutral-200/30 hover:no-underline">
|
||||
<AccordionTrigger className="text-foreground rounded border px-3 py-2 text-left hover:bg-neutral-200/30 hover:no-underline">
|
||||
<Trans>Advanced Options</Trans>
|
||||
</AccordionTrigger>
|
||||
|
||||
<AccordionContent className="-mx-1 px-1 pt-4 text-sm leading-relaxed text-muted-foreground">
|
||||
<AccordionContent className="text-muted-foreground -mx-1 px-1 pt-4 text-sm leading-relaxed">
|
||||
<div className="flex flex-col space-y-6">
|
||||
<FormField
|
||||
control={form.control}
|
||||
|
|
@ -621,7 +621,7 @@ export const AddTemplateSettingsFormPartial = ({
|
|||
<InfoIcon className="mx-2 h-4 w-4" />
|
||||
</TooltipTrigger>
|
||||
|
||||
<TooltipContent className="max-w-xs text-muted-foreground">
|
||||
<TooltipContent className="text-muted-foreground max-w-xs">
|
||||
<Trans>
|
||||
Add an external ID to the template. This can be used to identify
|
||||
in external systems.
|
||||
|
|
@ -695,7 +695,10 @@ export const AddTemplateSettingsFormPartial = ({
|
|||
options={TIME_ZONES}
|
||||
{...field}
|
||||
onChange={(value) => {
|
||||
value && field.onChange(value);
|
||||
if (value) {
|
||||
field.onChange(value);
|
||||
}
|
||||
|
||||
void handleAutoSave();
|
||||
}}
|
||||
/>
|
||||
|
|
@ -718,7 +721,7 @@ export const AddTemplateSettingsFormPartial = ({
|
|||
<InfoIcon className="mx-2 h-4 w-4" />
|
||||
</TooltipTrigger>
|
||||
|
||||
<TooltipContent className="max-w-xs text-muted-foreground">
|
||||
<TooltipContent className="text-muted-foreground max-w-xs">
|
||||
<Trans>
|
||||
Add a URL to redirect the user to once the document is signed
|
||||
</Trans>
|
||||
|
|
|
|||
Loading…
Reference in a new issue