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