refactor: split actions into use cases and repositories #3
+8
-1
@@ -13,4 +13,11 @@ NODE_ENV=production
|
||||
DEMO_MODE=false
|
||||
DOMAIN=localhost
|
||||
AUTH_TRUST_HOST="http://localhost"
|
||||
AUTH_SECRET=your_secret_key_here
|
||||
AUTH_SECRET=your_secret_key_here
|
||||
|
||||
# ADMIN BOOTSTRAP
|
||||
ADMIN_BOOTSTRAP_ENABLED=true
|
||||
ADMIN_USERNAME=admin
|
||||
ADMIN_EMAIL=admin@localhost
|
||||
ADMIN_NAME=Administrator
|
||||
ADMIN_PASSWORD=change-me
|
||||
+6
-2
@@ -18,7 +18,7 @@
|
||||
/out/
|
||||
|
||||
# prisma
|
||||
generated/
|
||||
src/generated
|
||||
|
||||
# production
|
||||
/build
|
||||
@@ -44,4 +44,8 @@ yarn-error.log*
|
||||
next-env.d.ts
|
||||
|
||||
# vscode
|
||||
!.vscode
|
||||
!.vscode
|
||||
|
||||
# Local Pi runtime state
|
||||
.atl/
|
||||
.pi
|
||||
Vendored
+13
-10
@@ -1,12 +1,15 @@
|
||||
{
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.organizeImports.biome": "explicit",
|
||||
"source.fixAll.biome": "explicit"
|
||||
},
|
||||
"[json]": {
|
||||
"editor.defaultFormatter": "vscode.json-language-features"
|
||||
},
|
||||
"[jsonc]": {
|
||||
"editor.defaultFormatter": "vscode.json-language-features"
|
||||
}
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.organizeImports.biome": "explicit",
|
||||
"source.fixAll.biome": "explicit"
|
||||
},
|
||||
"[json]": {
|
||||
"editor.defaultFormatter": "vscode.json-language-features"
|
||||
},
|
||||
"[jsonc]": {
|
||||
"editor.defaultFormatter": "biomejs.biome"
|
||||
},
|
||||
"[typescript]": {
|
||||
"editor.defaultFormatter": "biomejs.biome"
|
||||
},
|
||||
}
|
||||
+1
-1
@@ -39,4 +39,4 @@ COPY --from=builder /app/.next/static ./.next/static
|
||||
|
||||
EXPOSE ${PORT}
|
||||
|
||||
CMD ["bun", "run", "start"]
|
||||
CMD ["sh", "-c", "bun run db:deploy && bun run db:seed && bun run start"]
|
||||
+64
-64
@@ -1,66 +1,66 @@
|
||||
{
|
||||
"$schema": "./node_modules/@biomejs/biome/configuration_schema.json",
|
||||
"vcs": {
|
||||
"enabled": true,
|
||||
"clientKind": "git",
|
||||
"useIgnoreFile": true,
|
||||
"defaultBranch": "main"
|
||||
},
|
||||
"files": {
|
||||
"includes": [
|
||||
"**",
|
||||
"!**/ node_modules",
|
||||
"!**/ .next",
|
||||
"!src/generated/prisma",
|
||||
"!src/components/ui",
|
||||
"!src/styles"
|
||||
],
|
||||
"ignoreUnknown": false
|
||||
},
|
||||
"formatter": {
|
||||
"enabled": true,
|
||||
"formatWithErrors": false,
|
||||
"indentStyle": "space",
|
||||
"indentWidth": 2,
|
||||
"lineEnding": "lf",
|
||||
"lineWidth": 80,
|
||||
"attributePosition": "auto",
|
||||
"bracketSameLine": false,
|
||||
"bracketSpacing": true,
|
||||
"expand": "auto",
|
||||
"useEditorconfig": true
|
||||
},
|
||||
"linter": {
|
||||
"enabled": true,
|
||||
"rules": {
|
||||
"recommended": true
|
||||
}
|
||||
},
|
||||
"javascript": {
|
||||
"formatter": {
|
||||
"jsxQuoteStyle": "double",
|
||||
"quoteProperties": "asNeeded",
|
||||
"trailingCommas": "all",
|
||||
"semicolons": "asNeeded",
|
||||
"arrowParentheses": "always",
|
||||
"bracketSameLine": false,
|
||||
"quoteStyle": "double",
|
||||
"attributePosition": "auto",
|
||||
"bracketSpacing": true
|
||||
}
|
||||
},
|
||||
"html": {
|
||||
"formatter": {
|
||||
"indentScriptAndStyle": false,
|
||||
"selfCloseVoidElements": "always"
|
||||
}
|
||||
},
|
||||
"assist": {
|
||||
"enabled": true,
|
||||
"actions": {
|
||||
"source": {
|
||||
"organizeImports": "on"
|
||||
}
|
||||
}
|
||||
}
|
||||
"$schema": "./node_modules/@biomejs/biome/configuration_schema.json",
|
||||
"vcs": {
|
||||
"enabled": true,
|
||||
"clientKind": "git",
|
||||
"useIgnoreFile": true,
|
||||
"defaultBranch": "main"
|
||||
},
|
||||
"files": {
|
||||
"includes": [
|
||||
"**",
|
||||
"!**/ node_modules",
|
||||
"!**/ .next",
|
||||
"!src/generated/prisma",
|
||||
"!src/components/ui",
|
||||
"!src/styles"
|
||||
],
|
||||
"ignoreUnknown": false
|
||||
},
|
||||
"formatter": {
|
||||
"enabled": true,
|
||||
"formatWithErrors": false,
|
||||
"indentStyle": "space",
|
||||
"indentWidth": 2,
|
||||
"lineEnding": "lf",
|
||||
"lineWidth": 80,
|
||||
"attributePosition": "auto",
|
||||
"bracketSameLine": false,
|
||||
"bracketSpacing": true,
|
||||
"expand": "auto",
|
||||
"useEditorconfig": true
|
||||
},
|
||||
"linter": {
|
||||
"enabled": true,
|
||||
"rules": {
|
||||
"recommended": true
|
||||
}
|
||||
},
|
||||
"javascript": {
|
||||
"formatter": {
|
||||
"jsxQuoteStyle": "double",
|
||||
"quoteProperties": "asNeeded",
|
||||
"trailingCommas": "all",
|
||||
"semicolons": "asNeeded",
|
||||
"arrowParentheses": "always",
|
||||
"bracketSameLine": false,
|
||||
"quoteStyle": "double",
|
||||
"attributePosition": "auto",
|
||||
"bracketSpacing": true
|
||||
}
|
||||
},
|
||||
"html": {
|
||||
"formatter": {
|
||||
"indentScriptAndStyle": false,
|
||||
"selfCloseVoidElements": "always"
|
||||
}
|
||||
},
|
||||
"assist": {
|
||||
"enabled": true,
|
||||
"actions": {
|
||||
"source": {
|
||||
"organizeImports": "on"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,8 @@
|
||||
"dependencies": {
|
||||
"@base-ui/react": "^1.4.1",
|
||||
"@hookform/resolvers": "^5.2.2",
|
||||
"@prisma/client": "^6.10.1",
|
||||
"@prisma/adapter-pg": "^7.8.0",
|
||||
"@prisma/client": "^7.8.0",
|
||||
"@radix-ui/react-checkbox": "^1.3.2",
|
||||
"@radix-ui/react-collapsible": "^1.1.11",
|
||||
"@radix-ui/react-dialog": "^1.1.14",
|
||||
@@ -19,11 +20,13 @@
|
||||
"bcryptjs": "^3.0.2",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"lucide-react": "^1.11.0",
|
||||
"dotenv": "^17.4.2",
|
||||
"lucide-react": "^1.17.0",
|
||||
"next": "^16.2.4",
|
||||
"next-auth": "^5.0.0-beta.28",
|
||||
"next-themes": "^0.4.6",
|
||||
"papaparse": "^5.5.3",
|
||||
"radix-ui": "^1.4.3",
|
||||
"react": "^19.2.5",
|
||||
"react-dom": "^19.2.5",
|
||||
"react-hook-form": "^7.74.0",
|
||||
@@ -38,7 +41,7 @@
|
||||
"@types/node": "^24.0.3",
|
||||
"@types/react": "^19.1.8",
|
||||
"@types/react-dom": "^19.1.6",
|
||||
"prisma": "^6.10.1",
|
||||
"prisma": "^7.8.0",
|
||||
"tailwindcss": "^4.1.10",
|
||||
"tw-animate-css": "^1.3.4",
|
||||
"typescript": "^5.8.3",
|
||||
@@ -85,6 +88,12 @@
|
||||
|
||||
"@date-fns/tz": ["@date-fns/tz@1.4.1", "", {}, "sha512-P5LUNhtbj6YfI3iJjw5EL9eUAG6OitD0W3fWQcpQjDRc/QIsL0tRNuO1PcDvPccWL1fSTXXdE1ds+l95DV/OFA=="],
|
||||
|
||||
"@electric-sql/pglite": ["@electric-sql/pglite@0.4.1", "", {}, "sha512-mZ9NzzUSYPOCnxHH1oAHPRzoMFJHY472raDKwXl/+6oPbpdJ7g8LsCN4FSaIIfkiCKHhb3iF/Zqo3NYxaIhU7Q=="],
|
||||
|
||||
"@electric-sql/pglite-socket": ["@electric-sql/pglite-socket@0.1.1", "", { "peerDependencies": { "@electric-sql/pglite": "0.4.1" }, "bin": { "pglite-server": "dist/scripts/server.js" } }, "sha512-p2hoXw3Z3LQHwTeikdZNsFBOvXGqKY2hk51BBw+8NKND8eoH+8LFOtW9Z8CQKmTJ2qqGYu82ipqiyFZOTTXNfw=="],
|
||||
|
||||
"@electric-sql/pglite-tools": ["@electric-sql/pglite-tools@0.3.1", "", { "peerDependencies": { "@electric-sql/pglite": "0.4.1" } }, "sha512-C+T3oivmy9bpQvSxVqXA1UDY8cB9Eb9vZHL9zxWwEUfDixbXv4G3r2LjoTdR33LD8aomR3O9ZXEO3XEwr/cUCA=="],
|
||||
|
||||
"@emnapi/runtime": ["@emnapi/runtime@1.10.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA=="],
|
||||
|
||||
"@floating-ui/core": ["@floating-ui/core@1.7.5", "", { "dependencies": { "@floating-ui/utils": "^0.2.11" } }, "sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ=="],
|
||||
@@ -95,6 +104,8 @@
|
||||
|
||||
"@floating-ui/utils": ["@floating-ui/utils@0.2.11", "", {}, "sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg=="],
|
||||
|
||||
"@hono/node-server": ["@hono/node-server@1.19.11", "", { "peerDependencies": { "hono": "^4" } }, "sha512-dr8/3zEaB+p0D2n/IUrlPF1HZm586qgJNXK1a9fhg/PzdtkK7Ksd5l312tJX2yBuALqDYBlG20QEbayqPyxn+g=="],
|
||||
|
||||
"@hookform/resolvers": ["@hookform/resolvers@5.2.2", "", { "dependencies": { "@standard-schema/utils": "^0.3.0" }, "peerDependencies": { "react-hook-form": "^7.55.0" } }, "sha512-A/IxlMLShx3KjV/HeTcTfaMxdwy690+L/ZADoeaTltLx+CVuzkeVIPuybK3jrRfw7YZnmdKsVVHAlEPIAEUNlA=="],
|
||||
|
||||
"@img/colour": ["@img/colour@1.1.0", "", {}, "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ=="],
|
||||
@@ -159,6 +170,8 @@
|
||||
|
||||
"@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.25", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ=="],
|
||||
|
||||
"@kurkle/color": ["@kurkle/color@0.3.4", "", {}, "sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w=="],
|
||||
|
||||
"@next/env": ["@next/env@16.2.4", "", {}, "sha512-dKkkOzOSwFYe5RX6y26fZgkSpVAlIOJKQHIiydQcrWH6y/97+RceSOAdjZ14Qa3zLduVUy0TXcn+EiM6t4rPgw=="],
|
||||
|
||||
"@next/swc-darwin-arm64": ["@next/swc-darwin-arm64@16.2.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-OXTFFox5EKN1Ym08vfrz+OXxmCcEjT4SFMbNRsWZE99dMqt2Kcusl5MqPXcW232RYkMLQTy0hqgAMEsfEd/l2A=="],
|
||||
@@ -179,24 +192,50 @@
|
||||
|
||||
"@panva/hkdf": ["@panva/hkdf@1.2.1", "", {}, "sha512-6oclG6Y3PiDFcoyk8srjLfVKyMfVCKJ27JwNPViuXziFpmdz+MZnZN/aKY0JGXgYuO/VghU0jcOAZgWXZ1Dmrw=="],
|
||||
|
||||
"@prisma/client": ["@prisma/client@6.10.1", "", { "peerDependencies": { "prisma": "*", "typescript": ">=5.1.0" }, "optionalPeers": ["prisma", "typescript"] }, "sha512-Re4pMlcUsQsUTAYMK7EJ4Bw2kg3WfZAAlr8GjORJaK4VOP6LxRQUQ1TuLnxcF42XqGkWQ36q5CQF1yVadANQ6w=="],
|
||||
"@prisma/adapter-pg": ["@prisma/adapter-pg@7.8.0", "", { "dependencies": { "@prisma/driver-adapter-utils": "7.8.0", "@types/pg": "^8.16.0", "pg": "^8.16.3", "postgres-array": "3.0.4" } }, "sha512-ygb3UkerK3v8MDpXVgCISdRNDozpxh6+JVJgiIGbSr5KBgz10LLf5ejUskPGoXlsIjxsOu6nuy1JVQr2EKGSlg=="],
|
||||
|
||||
"@prisma/config": ["@prisma/config@6.10.1", "", { "dependencies": { "jiti": "2.4.2" } }, "sha512-kz4/bnqrOrzWo8KzYguN0cden4CzLJJ+2VSpKtF8utHS3l1JS0Lhv6BLwpOX6X9yNreTbZQZwewb+/BMPDCIYQ=="],
|
||||
"@prisma/client": ["@prisma/client@7.8.0", "", { "dependencies": { "@prisma/client-runtime-utils": "7.8.0" }, "peerDependencies": { "prisma": "*", "typescript": ">=5.4.0" }, "optionalPeers": ["prisma", "typescript"] }, "sha512-HFp3Dawv/3sU3JtlPha90IB+48lS7zHiH4LKZPjmcE8YH5P9DOXGPvo8dqOtO7MqLDd1p2hOWMcFlRT1DMblHw=="],
|
||||
|
||||
"@prisma/debug": ["@prisma/debug@6.10.1", "", {}, "sha512-k2YT53cWxv9OLjW4zSYTZ6Z7j0gPfCzcr2Mj99qsuvlxr8WAKSZ2NcSR0zLf/mP4oxnYG842IMj3utTgcd7CaA=="],
|
||||
"@prisma/client-runtime-utils": ["@prisma/client-runtime-utils@7.8.0", "", {}, "sha512-5NQZztQ0oY/ADFkmd9gPuweH5A1/CCY8YQPorLLO0Mu6a87mY5gsnDkzmFmIHs9NFaLnZojzgddFVN4RpKYrdw=="],
|
||||
|
||||
"@prisma/engines": ["@prisma/engines@6.10.1", "", { "dependencies": { "@prisma/debug": "6.10.1", "@prisma/engines-version": "6.10.1-1.9b628578b3b7cae625e8c927178f15a170e74a9c", "@prisma/fetch-engine": "6.10.1", "@prisma/get-platform": "6.10.1" } }, "sha512-Q07P5rS2iPwk2IQr/rUQJ42tHjpPyFcbiH7PXZlV81Ryr9NYIgdxcUrwgVOWVm5T7ap02C0dNd1dpnNcSWig8A=="],
|
||||
"@prisma/config": ["@prisma/config@7.8.0", "", { "dependencies": { "c12": "3.3.4", "deepmerge-ts": "7.1.5", "effect": "3.20.0", "empathic": "2.0.0" } }, "sha512-HFESzd9rx2ZQxlK+TL7tu1HPvCqrHiL6LCxYykI2c34mvaUuIVVl3lYuicJD/MNnzgPnyeBEMlK4WTomJCV5jw=="],
|
||||
|
||||
"@prisma/engines-version": ["@prisma/engines-version@6.10.1-1.9b628578b3b7cae625e8c927178f15a170e74a9c", "", {}, "sha512-ZJFTsEqapiTYVzXya6TUKYDFnSWCNegfUiG5ik9fleQva5Sk3DNyyUi7X1+0ZxWFHwHDr6BZV5Vm+iwP+LlciA=="],
|
||||
"@prisma/debug": ["@prisma/debug@7.8.0", "", {}, "sha512-p+QZReysDUqXC+mk17q9a+Y/qzh4c2KYliDK30buYUyfrGeTGSyfmc0AIrJRhZJrLHhRiJa9Au/J72h3C+szvA=="],
|
||||
|
||||
"@prisma/fetch-engine": ["@prisma/fetch-engine@6.10.1", "", { "dependencies": { "@prisma/debug": "6.10.1", "@prisma/engines-version": "6.10.1-1.9b628578b3b7cae625e8c927178f15a170e74a9c", "@prisma/get-platform": "6.10.1" } }, "sha512-clmbG/Jgmrc/n6Y77QcBmAUlq9LrwI9Dbgy4pq5jeEARBpRCWJDJ7PWW1P8p0LfFU0i5fsyO7FqRzRB8mkdS4g=="],
|
||||
"@prisma/dev": ["@prisma/dev@0.24.3", "", { "dependencies": { "@electric-sql/pglite": "0.4.1", "@electric-sql/pglite-socket": "0.1.1", "@electric-sql/pglite-tools": "0.3.1", "@hono/node-server": "1.19.11", "@prisma/get-platform": "7.2.0", "@prisma/query-plan-executor": "7.2.0", "@prisma/streams-local": "0.1.2", "foreground-child": "3.3.1", "get-port-please": "3.2.0", "hono": "^4.12.8", "http-status-codes": "2.3.0", "pathe": "2.0.3", "proper-lockfile": "4.1.2", "remeda": "2.33.4", "std-env": "3.10.0", "valibot": "1.2.0", "zeptomatch": "2.1.0" } }, "sha512-ffHlQuKXZiaDt9Go0OnCTdJZrHxK0k7omJKNV86/VjpsXu5EIHZLK0T7JSWgvNlJwh56kW9JFu9v0qJciFzepg=="],
|
||||
|
||||
"@prisma/get-platform": ["@prisma/get-platform@6.10.1", "", { "dependencies": { "@prisma/debug": "6.10.1" } }, "sha512-4CY5ndKylcsce9Mv+VWp5obbR2/86SHOLVV053pwIkhVtT9C9A83yqiqI/5kJM9T1v1u1qco/bYjDKycmei9HA=="],
|
||||
"@prisma/driver-adapter-utils": ["@prisma/driver-adapter-utils@7.8.0", "", { "dependencies": { "@prisma/debug": "7.8.0" } }, "sha512-/Q13o0ZT0rjc1Xk0Q9KhZYwuq2EW/vSbWUBKfgEKkaCuB/Sg6bqnjmTZqC5cD4d6y1vfFAEwBRzfzoSMIVJ55A=="],
|
||||
|
||||
"@prisma/engines": ["@prisma/engines@7.8.0", "", { "dependencies": { "@prisma/debug": "7.8.0", "@prisma/engines-version": "7.8.0-6.3c6e192761c0362d496ed980de936e2f3cebcd3a", "@prisma/fetch-engine": "7.8.0", "@prisma/get-platform": "7.8.0" } }, "sha512-jx3rCnNNrt5uzbkKlegtQ2GZHxSlihMCzutgT/BP6UIDF1r9tDI39hV/0T/cHZgzJ3ELbuQPXlVZy+Y1n0pcgw=="],
|
||||
|
||||
"@prisma/engines-version": ["@prisma/engines-version@7.8.0-6.3c6e192761c0362d496ed980de936e2f3cebcd3a", "", {}, "sha512-fJPQxCkLgA5EayWaW8eArgCvjJ+N+Kz3VyeNKMEeYiQC4alNkxRKFVAGxv/ZUzuJISKqdw+zGeDbS6mn6RCPOA=="],
|
||||
|
||||
"@prisma/fetch-engine": ["@prisma/fetch-engine@7.8.0", "", { "dependencies": { "@prisma/debug": "7.8.0", "@prisma/engines-version": "7.8.0-6.3c6e192761c0362d496ed980de936e2f3cebcd3a", "@prisma/get-platform": "7.8.0" } }, "sha512-gwB0Euiz/DDRyxFRpLXYlK3RfaZUj1c5dAYMuhZYfApg7arknJlcb9bIsOHDppJmbqYaVA+yBIiFMDBfprsNPQ=="],
|
||||
|
||||
"@prisma/get-platform": ["@prisma/get-platform@7.2.0", "", { "dependencies": { "@prisma/debug": "7.2.0" } }, "sha512-k1V0l0Td1732EHpAfi2eySTezyllok9dXb6UQanajkJQzPUGi3vO2z7jdkz67SypFTdmbnyGYxvEvYZdZsMAVA=="],
|
||||
|
||||
"@prisma/query-plan-executor": ["@prisma/query-plan-executor@7.2.0", "", {}, "sha512-EOZmNzcV8uJ0mae3DhTsiHgoNCuu1J9mULQpGCh62zN3PxPTd+qI9tJvk5jOst8WHKQNwJWR3b39t0XvfBB0WQ=="],
|
||||
|
||||
"@prisma/streams-local": ["@prisma/streams-local@0.1.2", "", { "dependencies": { "ajv": "^8.12.0", "better-result": "^2.7.0", "env-paths": "^3.0.0", "proper-lockfile": "^4.1.2" } }, "sha512-l49yTxKKF2odFxaAXTmwmkBKL3+bVQ1tFOooGifu4xkdb9NMNLxHj27XAhTylWZod8I+ISGM5erU1xcl/oBCtg=="],
|
||||
|
||||
"@prisma/studio-core": ["@prisma/studio-core@0.27.3", "", { "dependencies": { "@radix-ui/react-toggle": "1.1.10", "chart.js": "4.5.1" }, "peerDependencies": { "@types/react": "^18.0.0 || ^19.0.0", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" } }, "sha512-AADjNFPdsrglxHQVTmHFqv6DuKQZ5WY4p5/gVFY017twvNrSwpLJ9lqUbYYxEu2W7nbvVxTZA8deJ8LseNALsw=="],
|
||||
|
||||
"@radix-ui/number": ["@radix-ui/number@1.1.1", "", {}, "sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g=="],
|
||||
|
||||
"@radix-ui/primitive": ["@radix-ui/primitive@1.1.2", "", {}, "sha512-XnbHrrprsNqZKQhStrSwgRUQzoCI1glLzdw79xiZPoofhGICeZRSQ3dIxAKH1gb3OHfNf4d6f+vAv3kil2eggA=="],
|
||||
|
||||
"@radix-ui/react-accessible-icon": ["@radix-ui/react-accessible-icon@1.1.7", "", { "dependencies": { "@radix-ui/react-visually-hidden": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-XM+E4WXl0OqUJFovy6GjmxxFyx9opfCAIUku4dlKRd5YEPqt4kALOkQOp0Of6reHuUkJuiPBEc5k0o4z4lTC8A=="],
|
||||
|
||||
"@radix-ui/react-accordion": ["@radix-ui/react-accordion@1.2.12", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collapsible": "1.1.12", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-T4nygeh9YE9dLRPhAHSeOZi7HBXo+0kYIPJXayZfvWOWA0+n3dESrZbjfDPUABkUNym6Hd+f2IR113To8D2GPA=="],
|
||||
|
||||
"@radix-ui/react-alert-dialog": ["@radix-ui/react-alert-dialog@1.1.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dialog": "1.1.15", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-oTVLkEw5GpdRe29BqJ0LSDFWI3qu0vR1M0mUkOQWDIUnY/QIkLpgDMWuKxP94c2NAC2LGcgVhG1ImF3jkZ5wXw=="],
|
||||
|
||||
"@radix-ui/react-arrow": ["@radix-ui/react-arrow@1.1.7", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w=="],
|
||||
|
||||
"@radix-ui/react-aspect-ratio": ["@radix-ui/react-aspect-ratio@1.1.7", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Yq6lvO9HQyPwev1onK1daHCHqXVLzPhSVjmsNjCa2Zcxy2f7uJD2itDtxknv6FzAKCwD1qQkeVDmX/cev13n/g=="],
|
||||
|
||||
"@radix-ui/react-avatar": ["@radix-ui/react-avatar@1.1.10", "", { "dependencies": { "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-is-hydrated": "0.1.0", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-V8piFfWapM5OmNCXTzVQY+E1rDa53zY+MQ4Y7356v4fFz6vqCyUtIz2rUD44ZEdwg78/jKmMJHj07+C/Z/rcog=="],
|
||||
|
||||
"@radix-ui/react-checkbox": ["@radix-ui/react-checkbox@1.3.2", "", { "dependencies": { "@radix-ui/primitive": "1.1.2", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-presence": "1.1.4", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-use-size": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-yd+dI56KZqawxKZrJ31eENUwqc1QSqg4OZ15rybGjF2ZNwMO+wCyHzAVLRp9qoYJf7kYy0YpZ2b0JCzJ42HZpA=="],
|
||||
|
||||
"@radix-ui/react-collapsible": ["@radix-ui/react-collapsible@1.1.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.2", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-presence": "1.1.4", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-2qrRsVGSCYasSz1RFOorXwl0H7g7J1frQtgpQgYrt+MOidtPAINHn9CPovQXb83r8ahapdx3Tu0fa/pdFFSdPg=="],
|
||||
@@ -207,6 +246,8 @@
|
||||
|
||||
"@radix-ui/react-context": ["@radix-ui/react-context@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA=="],
|
||||
|
||||
"@radix-ui/react-context-menu": ["@radix-ui/react-context-menu@2.2.16", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-menu": "2.1.16", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-O8morBEW+HsVG28gYDZPTrT9UUovQUlJue5YO836tiTJhuIWBm/zQHc7j388sHWtdH/xUZurK9olD2+pcqx5ww=="],
|
||||
|
||||
"@radix-ui/react-dialog": ["@radix-ui/react-dialog@1.1.14", "", { "dependencies": { "@radix-ui/primitive": "1.1.2", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.10", "@radix-ui/react-focus-guards": "1.1.2", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.4", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-controllable-state": "1.2.2", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-+CpweKjqpzTmwRwcYECQcNYbI8V9VSQt0SNFKeEBLgfucbsLssU6Ppq7wUdNXEGb573bMjFhVjKVll8rmV6zMw=="],
|
||||
|
||||
"@radix-ui/react-direction": ["@radix-ui/react-direction@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw=="],
|
||||
@@ -219,10 +260,26 @@
|
||||
|
||||
"@radix-ui/react-focus-scope": ["@radix-ui/react-focus-scope@1.1.7", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw=="],
|
||||
|
||||
"@radix-ui/react-form": ["@radix-ui/react-form@0.1.8", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-label": "2.1.7", "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-QM70k4Zwjttifr5a4sZFts9fn8FzHYvQ5PiB19O2HsYibaHSVt9fH9rzB0XZo/YcM+b7t/p7lYCT/F5eOeF5yQ=="],
|
||||
|
||||
"@radix-ui/react-hover-card": ["@radix-ui/react-hover-card@1.1.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-qgTkjNT1CfKMoP0rcasmlH2r1DAiYicWsDsufxl940sT2wHNEWWv6FMWIQXWhVdmC1d/HYfbhQx60KYyAtKxjg=="],
|
||||
|
||||
"@radix-ui/react-id": ["@radix-ui/react-id@1.1.1", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg=="],
|
||||
|
||||
"@radix-ui/react-label": ["@radix-ui/react-label@2.1.7", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-YT1GqPSL8kJn20djelMX7/cTRp/Y9w5IZHvfxQTVHrOqa2yMl7i/UfMqKRU5V7mEyKTrUVgJXhNQPVCG8PBLoQ=="],
|
||||
|
||||
"@radix-ui/react-menu": ["@radix-ui/react-menu@2.1.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.2", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-dismissable-layer": "1.1.10", "@radix-ui/react-focus-guards": "1.1.2", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-popper": "1.2.7", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.4", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.10", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-callback-ref": "1.1.1", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-tVlmA3Vb9n8SZSd+YSbuFR66l87Wiy4du+YE+0hzKQEANA+7cWKH1WgqcEX4pXqxUFQKrWQGHdvEfw00TjFiew=="],
|
||||
|
||||
"@radix-ui/react-menubar": ["@radix-ui/react-menubar@1.1.16", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-menu": "2.1.16", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-EB1FktTz5xRRi2Er974AUQZWg2yVBb1yjip38/lgwtCVRd3a+maUoGHN/xs9Yv8SY8QwbSEb+YrxGadVWbEutA=="],
|
||||
|
||||
"@radix-ui/react-navigation-menu": ["@radix-ui/react-navigation-menu@1.2.14", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-visually-hidden": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-YB9mTFQvCOAQMHU+C/jVl96WmuWeltyUEpRJJky51huhds5W2FQr1J8D/16sQlf0ozxkPK8uF3niQMdUwZPv5w=="],
|
||||
|
||||
"@radix-ui/react-one-time-password-field": ["@radix-ui/react-one-time-password-field@0.1.8", "", { "dependencies": { "@radix-ui/number": "1.1.1", "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-is-hydrated": "0.1.0", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-ycS4rbwURavDPVjCb5iS3aG4lURFDILi6sKI/WITUMZ13gMmn/xGjpLoqBAalhJaDk8I3UbCM5GzKHrnzwHbvg=="],
|
||||
|
||||
"@radix-ui/react-password-toggle-field": ["@radix-ui/react-password-toggle-field@0.1.3", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-is-hydrated": "0.1.0" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-/UuCrDBWravcaMix4TdT+qlNdVwOM1Nck9kWx/vafXsdfj1ChfhOdfi3cy9SGBpWgTXwYCuboT/oYpJy3clqfw=="],
|
||||
|
||||
"@radix-ui/react-popover": ["@radix-ui/react-popover@1.1.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-controllable-state": "1.2.2", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-kr0X2+6Yy/vJzLYJUPCZEc8SfQcf+1COFoAqauJm74umQhta9M7lNJHP7QQS3vkvcGLQUbWpMzwrXYwrYztHKA=="],
|
||||
|
||||
"@radix-ui/react-popper": ["@radix-ui/react-popper@1.2.7", "", { "dependencies": { "@floating-ui/react-dom": "^2.0.0", "@radix-ui/react-arrow": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-rect": "1.1.1", "@radix-ui/react-use-size": "1.1.1", "@radix-ui/rect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-IUFAccz1JyKcf/RjB552PlWwxjeCJB8/4KxT7EhBHOJM+mN7LdW+B3kacJXILm32xawcMMjb2i0cIZpo+f9kiQ=="],
|
||||
|
||||
"@radix-ui/react-portal": ["@radix-ui/react-portal@1.1.9", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ=="],
|
||||
@@ -231,12 +288,34 @@
|
||||
|
||||
"@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="],
|
||||
|
||||
"@radix-ui/react-roving-focus": ["@radix-ui/react-roving-focus@1.1.10", "", { "dependencies": { "@radix-ui/primitive": "1.1.2", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-dT9aOXUen9JSsxnMPv/0VqySQf5eDQ6LCk5Sw28kamz8wSOW2bJdlX2Bg5VUIIcV+6XlHpWTIuTPCf/UNIyq8Q=="],
|
||||
"@radix-ui/react-progress": ["@radix-ui/react-progress@1.1.7", "", { "dependencies": { "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-vPdg/tF6YC/ynuBIJlk1mm7Le0VgW6ub6J2UWnTQ7/D23KXcPI1qy+0vBkgKgd38RCMJavBXpB83HPNFMTb0Fg=="],
|
||||
|
||||
"@radix-ui/react-radio-group": ["@radix-ui/react-radio-group@1.3.8", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-use-size": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-VBKYIYImA5zsxACdisNQ3BjCBfmbGH3kQlnFVqlWU4tXwjy7cGX8ta80BcrO+WJXIn5iBylEH3K6ZTlee//lgQ=="],
|
||||
|
||||
"@radix-ui/react-roving-focus": ["@radix-ui/react-roving-focus@1.1.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA=="],
|
||||
|
||||
"@radix-ui/react-scroll-area": ["@radix-ui/react-scroll-area@1.2.10", "", { "dependencies": { "@radix-ui/number": "1.1.1", "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-tAXIa1g3sM5CGpVT0uIbUx/U3Gs5N8T52IICuCtObaos1S8fzsrPXG5WObkQN3S6NVl6wKgPhAIiBGbWnvc97A=="],
|
||||
|
||||
"@radix-ui/react-select": ["@radix-ui/react-select@2.2.6", "", { "dependencies": { "@radix-ui/number": "1.1.1", "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-visually-hidden": "1.2.3", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-I30RydO+bnn2PQztvo25tswPH+wFBjehVGtmagkU78yMdwTwVf12wnAOF+AeP8S2N8xD+5UPbGhkUfPyvT+mwQ=="],
|
||||
|
||||
"@radix-ui/react-separator": ["@radix-ui/react-separator@1.1.7", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-0HEb8R9E8A+jZjvmFCy/J4xhbXy3TV+9XSnGJ3KvTtjlIUy/YQ/p6UYZvi7YbeoeXdyU9+Y3scizK6hkY37baA=="],
|
||||
|
||||
"@radix-ui/react-slider": ["@radix-ui/react-slider@1.3.6", "", { "dependencies": { "@radix-ui/number": "1.1.1", "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-use-size": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-JPYb1GuM1bxfjMRlNLE+BcmBC8onfCi60Blk7OBqi2MLTFdS+8401U4uFjnwkOr49BLmXxLC6JHkvAsx5OJvHw=="],
|
||||
|
||||
"@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
|
||||
|
||||
"@radix-ui/react-switch": ["@radix-ui/react-switch@1.2.6", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-use-size": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-bByzr1+ep1zk4VubeEVViV592vu2lHE2BZY5OnzehZqOOgogN80+mNtCqPkhn2gklJqOpxWgPoYTSnhBCqpOXQ=="],
|
||||
|
||||
"@radix-ui/react-tabs": ["@radix-ui/react-tabs@1.1.13", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A=="],
|
||||
|
||||
"@radix-ui/react-toast": ["@radix-ui/react-toast@1.2.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-visually-hidden": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-3OSz3TacUWy4WtOXV38DggwxoqJK4+eDkNMl5Z/MJZaoUPaP4/9lf81xXMe1I2ReTAptverZUpbPY4wWwWyL5g=="],
|
||||
|
||||
"@radix-ui/react-toggle": ["@radix-ui/react-toggle@1.1.10", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-lS1odchhFTeZv3xwHH31YPObmJn8gOg7Lq12inrr0+BH/l3Tsq32VfjqH1oh80ARM3mlkfMic15n0kg4sD1poQ=="],
|
||||
|
||||
"@radix-ui/react-toggle-group": ["@radix-ui/react-toggle-group@1.1.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-toggle": "1.1.10", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-5umnS0T8JQzQT6HbPyO7Hh9dgd82NmS36DQr+X/YJ9ctFNCiiQd6IJAYYZ33LUwm8M+taCz5t2ui29fHZc4Y6Q=="],
|
||||
|
||||
"@radix-ui/react-toolbar": ["@radix-ui/react-toolbar@1.1.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-separator": "1.1.7", "@radix-ui/react-toggle-group": "1.1.11" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-4ol06/1bLoFu1nwUqzdD4Y5RZ9oDdKeiHIsntug54Hcr1pgaHiPqHFEaXI1IFP/EsOfROQZ8Mig9VTIRza6Tjg=="],
|
||||
|
||||
"@radix-ui/react-tooltip": ["@radix-ui/react-tooltip@1.2.7", "", { "dependencies": { "@radix-ui/primitive": "1.1.2", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.10", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-popper": "1.2.7", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.4", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-visually-hidden": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Ap+fNYwKTYJ9pzqW+Xe2HtMRbQ/EeWkj2qykZ6SuEV4iS/o1bZI5ssJbk4D2r8XuDuOBVz/tIx2JObtuqU+5Zw=="],
|
||||
|
||||
"@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg=="],
|
||||
@@ -247,6 +326,8 @@
|
||||
|
||||
"@radix-ui/react-use-escape-keydown": ["@radix-ui/react-use-escape-keydown@1.1.1", "", { "dependencies": { "@radix-ui/react-use-callback-ref": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g=="],
|
||||
|
||||
"@radix-ui/react-use-is-hydrated": ["@radix-ui/react-use-is-hydrated@0.1.0", "", { "dependencies": { "use-sync-external-store": "^1.5.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-U+UORVEq+cTnRIaostJv9AGdV3G6Y+zbVd+12e18jQ5A3c0xL03IhnHuiU4UV69wolOQp5GfR58NW/EgdQhwOA=="],
|
||||
|
||||
"@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ=="],
|
||||
|
||||
"@radix-ui/react-use-previous": ["@radix-ui/react-use-previous@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ=="],
|
||||
@@ -259,6 +340,8 @@
|
||||
|
||||
"@radix-ui/rect": ["@radix-ui/rect@1.1.1", "", {}, "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw=="],
|
||||
|
||||
"@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
||||
|
||||
"@standard-schema/utils": ["@standard-schema/utils@0.3.0", "", {}, "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g=="],
|
||||
|
||||
"@swc/helpers": ["@swc/helpers@0.5.15", "", { "dependencies": { "tslib": "^2.8.0" } }, "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g=="],
|
||||
@@ -297,18 +380,32 @@
|
||||
|
||||
"@types/papaparse": ["@types/papaparse@5.3.16", "", { "dependencies": { "@types/node": "*" } }, "sha512-T3VuKMC2H0lgsjI9buTB3uuKj3EMD2eap1MOuEQuBQ44EnDx/IkGhU6EwiTf9zG3za4SKlmwKAImdDKdNnCsXg=="],
|
||||
|
||||
"@types/pg": ["@types/pg@8.20.0", "", { "dependencies": { "@types/node": "*", "pg-protocol": "*", "pg-types": "^2.2.0" } }, "sha512-bEPFOaMAHTEP1EzpvHTbmwR8UsFyHSKsRisLIHVMXnpNefSbGA1bD6CVy+qKjGSqmZqNqBDV2azOBo8TgkcVow=="],
|
||||
|
||||
"@types/react": ["@types/react@19.1.8", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-AwAfQ2Wa5bCx9WP8nZL2uMZWod7J7/JSplxbTmBQ5ms6QpqNYm672H0Vu9ZVKVngQ+ii4R/byguVEUZQyeg44g=="],
|
||||
|
||||
"@types/react-dom": ["@types/react-dom@19.1.6", "", { "peerDependencies": { "@types/react": "^19.0.0" } }, "sha512-4hOiT/dwO8Ko0gV1m/TJZYk3y0KBnY9vzDh7W+DH17b2HFSOGgdj33dhihPeuy3l0q23+4e+hoXHV6hCC4dCXw=="],
|
||||
|
||||
"ajv": ["ajv@8.20.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA=="],
|
||||
|
||||
"aria-hidden": ["aria-hidden@1.2.6", "", { "dependencies": { "tslib": "^2.0.0" } }, "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA=="],
|
||||
|
||||
"aws-ssl-profiles": ["aws-ssl-profiles@1.1.2", "", {}, "sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g=="],
|
||||
|
||||
"baseline-browser-mapping": ["baseline-browser-mapping@2.10.23", "", { "bin": { "baseline-browser-mapping": "dist/cli.cjs" } }, "sha512-xwVXGqevyKPsiuQdLj+dZMVjidjJV508TBqexND5HrF89cGdCYCJFB3qhcxRHSeMctdCfbR1jrxBajhDy7o29g=="],
|
||||
|
||||
"bcryptjs": ["bcryptjs@3.0.2", "", { "bin": { "bcrypt": "bin/bcrypt" } }, "sha512-k38b3XOZKv60C4E2hVsXTolJWfkGRMbILBIe2IBITXciy5bOsTKot5kDrf3ZfufQtQOUN5mXceUEpU1rTl9Uog=="],
|
||||
|
||||
"better-result": ["better-result@2.9.2", "", {}, "sha512-WIFoBPCdnTOdk9inkE1ZRvCZ4P0CpSkAiLlchC65N7n9DcjZ3NhqkBOlafzpOVnO8ixyi37kicmSJ3ENhPZl7Q=="],
|
||||
|
||||
"c12": ["c12@3.3.4", "", { "dependencies": { "chokidar": "^5.0.0", "confbox": "^0.2.4", "defu": "^6.1.6", "dotenv": "^17.3.1", "exsolve": "^1.0.8", "giget": "^3.2.0", "jiti": "^2.6.1", "ohash": "^2.0.11", "pathe": "^2.0.3", "perfect-debounce": "^2.1.0", "pkg-types": "^2.3.0", "rc9": "^3.0.1" }, "peerDependencies": { "magicast": "*" }, "optionalPeers": ["magicast"] }, "sha512-cM0ApFQSBXuourJejzwv/AuPRvAxordTyParRVcHjjtXirtkzM0uK2L9TTn9s0cXZbG7E55jCivRQzoxYmRAlA=="],
|
||||
|
||||
"caniuse-lite": ["caniuse-lite@1.0.30001723", "", {}, "sha512-1R/elMjtehrFejxwmexeXAtae5UO9iSyFn6G/I806CYC/BLyyBk1EPhrKBkWhy6wM6Xnm47dSJQec+tLJ39WHw=="],
|
||||
|
||||
"chart.js": ["chart.js@4.5.1", "", { "dependencies": { "@kurkle/color": "^0.3.0" } }, "sha512-GIjfiT9dbmHRiYi6Nl2yFCq7kkwdkp1W/lp2J99rX0yo9tgJGn3lKQATztIjb5tVtevcBtIdICNWqlq5+E8/Pw=="],
|
||||
|
||||
"chokidar": ["chokidar@5.0.0", "", { "dependencies": { "readdirp": "^5.0.0" } }, "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw=="],
|
||||
|
||||
"chownr": ["chownr@3.0.0", "", {}, "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g=="],
|
||||
|
||||
"class-variance-authority": ["class-variance-authority@0.7.1", "", { "dependencies": { "clsx": "^2.1.1" } }, "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg=="],
|
||||
@@ -317,24 +414,76 @@
|
||||
|
||||
"clsx": ["clsx@2.1.1", "", {}, "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="],
|
||||
|
||||
"confbox": ["confbox@0.2.4", "", {}, "sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ=="],
|
||||
|
||||
"cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="],
|
||||
|
||||
"csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="],
|
||||
|
||||
"date-fns": ["date-fns@4.1.0", "", {}, "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg=="],
|
||||
|
||||
"deepmerge-ts": ["deepmerge-ts@7.1.5", "", {}, "sha512-HOJkrhaYsweh+W+e74Yn7YStZOilkoPb6fycpwNLKzSPtruFs48nYis0zy5yJz1+ktUhHxoRDJ27RQAWLIJVJw=="],
|
||||
|
||||
"defu": ["defu@6.1.7", "", {}, "sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ=="],
|
||||
|
||||
"denque": ["denque@2.1.0", "", {}, "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw=="],
|
||||
|
||||
"destr": ["destr@2.0.5", "", {}, "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA=="],
|
||||
|
||||
"detect-libc": ["detect-libc@2.0.4", "", {}, "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA=="],
|
||||
|
||||
"detect-node-es": ["detect-node-es@1.1.0", "", {}, "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ=="],
|
||||
|
||||
"dotenv": ["dotenv@17.4.2", "", {}, "sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw=="],
|
||||
|
||||
"effect": ["effect@3.20.0", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "fast-check": "^3.23.1" } }, "sha512-qMLfDJscrNG8p/aw+IkT9W7fgj50Z4wG5bLBy0Txsxz8iUHjDIkOgO3SV0WZfnQbNG2VJYb0b+rDLMrhM4+Krw=="],
|
||||
|
||||
"empathic": ["empathic@2.0.0", "", {}, "sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA=="],
|
||||
|
||||
"enhanced-resolve": ["enhanced-resolve@5.18.1", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" } }, "sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg=="],
|
||||
|
||||
"env-paths": ["env-paths@3.0.0", "", {}, "sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A=="],
|
||||
|
||||
"exsolve": ["exsolve@1.0.8", "", {}, "sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA=="],
|
||||
|
||||
"fast-check": ["fast-check@3.23.2", "", { "dependencies": { "pure-rand": "^6.1.0" } }, "sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A=="],
|
||||
|
||||
"fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="],
|
||||
|
||||
"fast-uri": ["fast-uri@3.1.2", "", {}, "sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ=="],
|
||||
|
||||
"foreground-child": ["foreground-child@3.3.1", "", { "dependencies": { "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" } }, "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw=="],
|
||||
|
||||
"generate-function": ["generate-function@2.3.1", "", { "dependencies": { "is-property": "^1.0.2" } }, "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ=="],
|
||||
|
||||
"get-nonce": ["get-nonce@1.0.1", "", {}, "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q=="],
|
||||
|
||||
"get-port-please": ["get-port-please@3.2.0", "", {}, "sha512-I9QVvBw5U/hw3RmWpYKRumUeaDgxTPd401x364rLmWBJcOQ753eov1eTgzDqRG9bqFIfDc7gfzcQEWrUri3o1A=="],
|
||||
|
||||
"giget": ["giget@3.2.0", "", { "bin": { "giget": "dist/cli.mjs" } }, "sha512-GvHTWcykIR/fP8cj8dMpuMMkvaeJfPvYnhq0oW+chSeIr+ldX21ifU2Ms6KBoyKZQZmVaUAAhQ2EZ68KJF8a7A=="],
|
||||
|
||||
"graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="],
|
||||
|
||||
"grammex": ["grammex@3.1.12", "", {}, "sha512-6ufJOsSA7LcQehIJNCO7HIBykfM7DXQual0Ny780/DEcJIpBlHRvcqEBWGPYd7hrXL2GJ3oJI1MIhaXjWmLQOQ=="],
|
||||
|
||||
"graphmatch": ["graphmatch@1.1.1", "", {}, "sha512-5ykVn/EXM1hF0XCaWh05VbYvEiOL2lY1kBxZtaYsyvjp7cmWOU1XsAdfQBwClraEofXDT197lFbXOEVMHpvQOg=="],
|
||||
|
||||
"hono": ["hono@4.12.18", "", {}, "sha512-RWzP96k/yv0PQfyXnWjs6zot20TqfpfsNXhOnev8d1InAxubW93L11/oNUc3tQqn2G0bSdAOBpX+2uDFHV7kdQ=="],
|
||||
|
||||
"http-status-codes": ["http-status-codes@2.3.0", "", {}, "sha512-RJ8XvFvpPM/Dmc5SV+dC4y5PCeOhT3x1Hq0NU3rjGeg5a/CqlhZ7uudknPwZFz4aeAXDcbAyaeP7GAo9lvngtA=="],
|
||||
|
||||
"iconv-lite": ["iconv-lite@0.7.2", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw=="],
|
||||
|
||||
"is-property": ["is-property@1.0.2", "", {}, "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g=="],
|
||||
|
||||
"isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="],
|
||||
|
||||
"jiti": ["jiti@2.4.2", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A=="],
|
||||
|
||||
"jose": ["jose@6.0.11", "", {}, "sha512-QxG7EaliDARm1O1S8BGakqncGT9s25bKL1WSf6/oa17Tkqwi8D2ZNglqCF+DsYF88/rV66Q/Q2mFAy697E1DUg=="],
|
||||
|
||||
"json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="],
|
||||
|
||||
"lightningcss": ["lightningcss@1.30.1", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-darwin-arm64": "1.30.1", "lightningcss-darwin-x64": "1.30.1", "lightningcss-freebsd-x64": "1.30.1", "lightningcss-linux-arm-gnueabihf": "1.30.1", "lightningcss-linux-arm64-gnu": "1.30.1", "lightningcss-linux-arm64-musl": "1.30.1", "lightningcss-linux-x64-gnu": "1.30.1", "lightningcss-linux-x64-musl": "1.30.1", "lightningcss-win32-arm64-msvc": "1.30.1", "lightningcss-win32-x64-msvc": "1.30.1" } }, "sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg=="],
|
||||
|
||||
"lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.30.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ=="],
|
||||
@@ -357,7 +506,11 @@
|
||||
|
||||
"lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.30.1", "", { "os": "win32", "cpu": "x64" }, "sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg=="],
|
||||
|
||||
"lucide-react": ["lucide-react@1.11.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-UOhjdztXCgdBReRcIhsvz2siIBogfv/lhJEIViCpLt924dO+GDms9T7DNoucI23s6kEPpe988m5N0D2ajnzb2g=="],
|
||||
"long": ["long@5.3.2", "", {}, "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA=="],
|
||||
|
||||
"lru.min": ["lru.min@1.1.4", "", {}, "sha512-DqC6n3QQ77zdFpCMASA1a3Jlb64Hv2N2DciFGkO/4L9+q/IpIAuRlKOvCXabtRW6cQf8usbmM6BE/TOPysCdIA=="],
|
||||
|
||||
"lucide-react": ["lucide-react@1.17.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-9FA9evdox/JQL5PT57fdA1x/yg8T7knJ98+zjTL3UfKza6pflQUUh3XtaQIHKvnsJw1lmsEyHVlt5jchYxOQ5w=="],
|
||||
|
||||
"magic-string": ["magic-string@0.30.17", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0" } }, "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA=="],
|
||||
|
||||
@@ -367,6 +520,10 @@
|
||||
|
||||
"mkdirp": ["mkdirp@3.0.1", "", { "bin": { "mkdirp": "dist/cjs/src/bin.js" } }, "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg=="],
|
||||
|
||||
"mysql2": ["mysql2@3.15.3", "", { "dependencies": { "aws-ssl-profiles": "^1.1.1", "denque": "^2.1.0", "generate-function": "^2.3.1", "iconv-lite": "^0.7.0", "long": "^5.2.1", "lru.min": "^1.0.0", "named-placeholders": "^1.1.3", "seq-queue": "^0.0.5", "sqlstring": "^2.3.2" } }, "sha512-FBrGau0IXmuqg4haEZRBfHNWB5mUARw6hNwPDXXGg0XzVJ50mr/9hb267lvpVMnhZ1FON3qNd4Xfcez1rbFwSg=="],
|
||||
|
||||
"named-placeholders": ["named-placeholders@1.1.6", "", { "dependencies": { "lru.min": "^1.1.0" } }, "sha512-Tz09sEL2EEuv5fFowm419c1+a/jSMiBjI9gHxVLrVdbUkkNUUfjsVYs9pVZu5oCon/kmRh9TfLEObFtkVxmY0w=="],
|
||||
|
||||
"nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="],
|
||||
|
||||
"next": ["next@16.2.4", "", { "dependencies": { "@next/env": "16.2.4", "@swc/helpers": "0.5.15", "baseline-browser-mapping": "^2.9.19", "caniuse-lite": "^1.0.30001579", "postcss": "8.4.31", "styled-jsx": "5.1.6" }, "optionalDependencies": { "@next/swc-darwin-arm64": "16.2.4", "@next/swc-darwin-x64": "16.2.4", "@next/swc-linux-arm64-gnu": "16.2.4", "@next/swc-linux-arm64-musl": "16.2.4", "@next/swc-linux-x64-gnu": "16.2.4", "@next/swc-linux-x64-musl": "16.2.4", "@next/swc-win32-arm64-msvc": "16.2.4", "@next/swc-win32-x64-msvc": "16.2.4", "sharp": "^0.34.5" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", "@playwright/test": "^1.51.1", "babel-plugin-react-compiler": "*", "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "sass": "^1.3.0" }, "optionalPeers": ["@opentelemetry/api", "@playwright/test", "babel-plugin-react-compiler", "sass"], "bin": { "next": "dist/bin/next" } }, "sha512-kPvz56wF5frc+FxlHI5qnklCzbq53HTwORaWBGdT0vNoKh1Aya9XC8aPauH4NJxqtzbWsS5mAbctm4cr+EkQ2Q=="],
|
||||
@@ -377,17 +534,61 @@
|
||||
|
||||
"oauth4webapi": ["oauth4webapi@3.5.3", "", {}, "sha512-2bnHosmBLAQpXNBLOvaJMyMkr4Yya5ohE5Q9jqyxiN+aa7GFCzvDN1RRRMrp0NkfqRR2MTaQNkcSUCCjILD9oQ=="],
|
||||
|
||||
"ohash": ["ohash@2.0.11", "", {}, "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ=="],
|
||||
|
||||
"papaparse": ["papaparse@5.5.3", "", {}, "sha512-5QvjGxYVjxO59MGU2lHVYpRWBBtKHnlIAcSe1uNFCkkptUh63NFRj0FJQm7nR67puEruUci/ZkjmEFrjCAyP4A=="],
|
||||
|
||||
"path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="],
|
||||
|
||||
"pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="],
|
||||
|
||||
"perfect-debounce": ["perfect-debounce@2.1.0", "", {}, "sha512-LjgdTytVFXeUgtHZr9WYViYSM/g8MkcTPYDlPa3cDqMirHjKiSZPYd6DoL7pK8AJQr+uWkQvCjHNdiMqsrJs+g=="],
|
||||
|
||||
"pg": ["pg@8.20.0", "", { "dependencies": { "pg-connection-string": "^2.12.0", "pg-pool": "^3.13.0", "pg-protocol": "^1.13.0", "pg-types": "2.2.0", "pgpass": "1.0.5" }, "optionalDependencies": { "pg-cloudflare": "^1.3.0" }, "peerDependencies": { "pg-native": ">=3.0.1" }, "optionalPeers": ["pg-native"] }, "sha512-ldhMxz2r8fl/6QkXnBD3CR9/xg694oT6DZQ2s6c/RI28OjtSOpxnPrUCGOBJ46RCUxcWdx3p6kw/xnDHjKvaRA=="],
|
||||
|
||||
"pg-cloudflare": ["pg-cloudflare@1.3.0", "", {}, "sha512-6lswVVSztmHiRtD6I8hw4qP/nDm1EJbKMRhf3HCYaqud7frGysPv7FYJ5noZQdhQtN2xJnimfMtvQq21pdbzyQ=="],
|
||||
|
||||
"pg-connection-string": ["pg-connection-string@2.12.0", "", {}, "sha512-U7qg+bpswf3Cs5xLzRqbXbQl85ng0mfSV/J0nnA31MCLgvEaAo7CIhmeyrmJpOr7o+zm0rXK+hNnT5l9RHkCkQ=="],
|
||||
|
||||
"pg-int8": ["pg-int8@1.0.1", "", {}, "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw=="],
|
||||
|
||||
"pg-pool": ["pg-pool@3.13.0", "", { "peerDependencies": { "pg": ">=8.0" } }, "sha512-gB+R+Xud1gLFuRD/QgOIgGOBE2KCQPaPwkzBBGC9oG69pHTkhQeIuejVIk3/cnDyX39av2AxomQiyPT13WKHQA=="],
|
||||
|
||||
"pg-protocol": ["pg-protocol@1.13.0", "", {}, "sha512-zzdvXfS6v89r6v7OcFCHfHlyG/wvry1ALxZo4LqgUoy7W9xhBDMaqOuMiF3qEV45VqsN6rdlcehHrfDtlCPc8w=="],
|
||||
|
||||
"pg-types": ["pg-types@2.2.0", "", { "dependencies": { "pg-int8": "1.0.1", "postgres-array": "~2.0.0", "postgres-bytea": "~1.0.0", "postgres-date": "~1.0.4", "postgres-interval": "^1.1.0" } }, "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA=="],
|
||||
|
||||
"pgpass": ["pgpass@1.0.5", "", { "dependencies": { "split2": "^4.1.0" } }, "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug=="],
|
||||
|
||||
"picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="],
|
||||
|
||||
"pkg-types": ["pkg-types@2.3.1", "", { "dependencies": { "confbox": "^0.2.4", "exsolve": "^1.0.8", "pathe": "^2.0.3" } }, "sha512-y+ichcgc2LrADuhLNAx8DFjVfgz91pRxfZdI3UDhxHvcVEZsenLO+7XaU5vOp0u/7V/wZ+plyuQxtrDlZJ+yeg=="],
|
||||
|
||||
"postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="],
|
||||
|
||||
"postgres": ["postgres@3.4.7", "", {}, "sha512-Jtc2612XINuBjIl/QTWsV5UvE8UHuNblcO3vVADSrKsrc6RqGX6lOW1cEo3CM2v0XG4Nat8nI+YM7/f26VxXLw=="],
|
||||
|
||||
"postgres-array": ["postgres-array@3.0.4", "", {}, "sha512-nAUSGfSDGOaOAEGwqsRY27GPOea7CNipJPOA7lPbdEpx5Kg3qzdP0AaWC5MlhTWV9s4hFX39nomVZ+C4tnGOJQ=="],
|
||||
|
||||
"postgres-bytea": ["postgres-bytea@1.0.1", "", {}, "sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ=="],
|
||||
|
||||
"postgres-date": ["postgres-date@1.0.7", "", {}, "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q=="],
|
||||
|
||||
"postgres-interval": ["postgres-interval@1.2.0", "", { "dependencies": { "xtend": "^4.0.0" } }, "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ=="],
|
||||
|
||||
"preact": ["preact@10.24.3", "", {}, "sha512-Z2dPnBnMUfyQfSQ+GBdsGa16hz35YmLmtTLhM169uW944hYL6xzTYkJjC07j+Wosz733pMWx0fgON3JNw1jJQA=="],
|
||||
|
||||
"preact-render-to-string": ["preact-render-to-string@6.5.11", "", { "peerDependencies": { "preact": ">=10" } }, "sha512-ubnauqoGczeGISiOh6RjX0/cdaF8v/oDXIjO85XALCQjwQP+SB4RDXXtvZ6yTYSjG+PC1QRP2AhPgCEsM2EvUw=="],
|
||||
|
||||
"prisma": ["prisma@6.10.1", "", { "dependencies": { "@prisma/config": "6.10.1", "@prisma/engines": "6.10.1" }, "peerDependencies": { "typescript": ">=5.1.0" }, "optionalPeers": ["typescript"], "bin": { "prisma": "build/index.js" } }, "sha512-khhlC/G49E4+uyA3T3H5PRBut486HD2bDqE2+rvkU0pwk9IAqGFacLFUyIx9Uw+W2eCtf6XGwsp+/strUwMNPw=="],
|
||||
"prisma": ["prisma@7.8.0", "", { "dependencies": { "@prisma/config": "7.8.0", "@prisma/dev": "0.24.3", "@prisma/engines": "7.8.0", "@prisma/studio-core": "0.27.3", "mysql2": "3.15.3", "postgres": "3.4.7" }, "peerDependencies": { "better-sqlite3": ">=9.0.0", "typescript": ">=5.4.0" }, "optionalPeers": ["better-sqlite3", "typescript"], "bin": { "prisma": "build/index.js" } }, "sha512-yfN4yrw7HV9kEJhoy1+jgah0jafEIQsf7uWouSsM8MvJtlubsk+kM7AIBWZ8+GJl74Yj3c+nbYqBkMOxtsZ3Lw=="],
|
||||
|
||||
"proper-lockfile": ["proper-lockfile@4.1.2", "", { "dependencies": { "graceful-fs": "^4.2.4", "retry": "^0.12.0", "signal-exit": "^3.0.2" } }, "sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA=="],
|
||||
|
||||
"pure-rand": ["pure-rand@6.1.0", "", {}, "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA=="],
|
||||
|
||||
"radix-ui": ["radix-ui@1.4.3", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-accessible-icon": "1.1.7", "@radix-ui/react-accordion": "1.2.12", "@radix-ui/react-alert-dialog": "1.1.15", "@radix-ui/react-arrow": "1.1.7", "@radix-ui/react-aspect-ratio": "1.1.7", "@radix-ui/react-avatar": "1.1.10", "@radix-ui/react-checkbox": "1.3.3", "@radix-ui/react-collapsible": "1.1.12", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-context-menu": "2.2.16", "@radix-ui/react-dialog": "1.1.15", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-dropdown-menu": "2.1.16", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-form": "0.1.8", "@radix-ui/react-hover-card": "1.1.15", "@radix-ui/react-label": "2.1.7", "@radix-ui/react-menu": "2.1.16", "@radix-ui/react-menubar": "1.1.16", "@radix-ui/react-navigation-menu": "1.2.14", "@radix-ui/react-one-time-password-field": "0.1.8", "@radix-ui/react-password-toggle-field": "0.1.3", "@radix-ui/react-popover": "1.1.15", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-progress": "1.1.7", "@radix-ui/react-radio-group": "1.3.8", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-scroll-area": "1.2.10", "@radix-ui/react-select": "2.2.6", "@radix-ui/react-separator": "1.1.7", "@radix-ui/react-slider": "1.3.6", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-switch": "1.2.6", "@radix-ui/react-tabs": "1.1.13", "@radix-ui/react-toast": "1.2.15", "@radix-ui/react-toggle": "1.1.10", "@radix-ui/react-toggle-group": "1.1.11", "@radix-ui/react-toolbar": "1.1.11", "@radix-ui/react-tooltip": "1.2.8", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-escape-keydown": "1.1.1", "@radix-ui/react-use-is-hydrated": "0.1.0", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-size": "1.1.1", "@radix-ui/react-visually-hidden": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-aWizCQiyeAenIdUbqEpXgRA1ya65P13NKn/W8rWkcN0OPkRDxdBVLWnIEDsS2RpwCK2nobI7oMUSmexzTDyAmA=="],
|
||||
|
||||
"rc9": ["rc9@3.0.1", "", { "dependencies": { "defu": "^6.1.6", "destr": "^2.0.5" } }, "sha512-gMDyleLWVE+i6Sgtc0QbbY6pEKqYs97NGi6isHQPqYlLemPoO8dxQ3uGi0f4NiP98c+jMW6cG1Kx9dDwfvqARQ=="],
|
||||
|
||||
"react": ["react@19.2.5", "", {}, "sha512-llUJLzz1zTUBrskt2pwZgLq59AemifIftw4aB7JxOqf1HY2FDaGDxgwpAPVzHU1kdWabH7FauP4i1oEeer2WCA=="],
|
||||
|
||||
@@ -401,18 +602,42 @@
|
||||
|
||||
"react-style-singleton": ["react-style-singleton@2.2.3", "", { "dependencies": { "get-nonce": "^1.0.0", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ=="],
|
||||
|
||||
"readdirp": ["readdirp@5.0.0", "", {}, "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ=="],
|
||||
|
||||
"remeda": ["remeda@2.33.4", "", {}, "sha512-ygHswjlc/opg2VrtiYvUOPLjxjtdKvjGz1/plDhkG66hjNjFr1xmfrs2ClNFo/E6TyUFiwYNh53bKV26oBoMGQ=="],
|
||||
|
||||
"require-from-string": ["require-from-string@2.0.2", "", {}, "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="],
|
||||
|
||||
"reselect": ["reselect@5.1.1", "", {}, "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w=="],
|
||||
|
||||
"retry": ["retry@0.12.0", "", {}, "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow=="],
|
||||
|
||||
"safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="],
|
||||
|
||||
"scheduler": ["scheduler@0.27.0", "", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="],
|
||||
|
||||
"semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="],
|
||||
|
||||
"seq-queue": ["seq-queue@0.0.5", "", {}, "sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q=="],
|
||||
|
||||
"sharp": ["sharp@0.34.5", "", { "dependencies": { "@img/colour": "^1.0.0", "detect-libc": "^2.1.2", "semver": "^7.7.3" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.34.5", "@img/sharp-darwin-x64": "0.34.5", "@img/sharp-libvips-darwin-arm64": "1.2.4", "@img/sharp-libvips-darwin-x64": "1.2.4", "@img/sharp-libvips-linux-arm": "1.2.4", "@img/sharp-libvips-linux-arm64": "1.2.4", "@img/sharp-libvips-linux-ppc64": "1.2.4", "@img/sharp-libvips-linux-riscv64": "1.2.4", "@img/sharp-libvips-linux-s390x": "1.2.4", "@img/sharp-libvips-linux-x64": "1.2.4", "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", "@img/sharp-libvips-linuxmusl-x64": "1.2.4", "@img/sharp-linux-arm": "0.34.5", "@img/sharp-linux-arm64": "0.34.5", "@img/sharp-linux-ppc64": "0.34.5", "@img/sharp-linux-riscv64": "0.34.5", "@img/sharp-linux-s390x": "0.34.5", "@img/sharp-linux-x64": "0.34.5", "@img/sharp-linuxmusl-arm64": "0.34.5", "@img/sharp-linuxmusl-x64": "0.34.5", "@img/sharp-wasm32": "0.34.5", "@img/sharp-win32-arm64": "0.34.5", "@img/sharp-win32-ia32": "0.34.5", "@img/sharp-win32-x64": "0.34.5" } }, "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg=="],
|
||||
|
||||
"shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="],
|
||||
|
||||
"shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="],
|
||||
|
||||
"signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="],
|
||||
|
||||
"sonner": ["sonner@2.0.7", "", { "peerDependencies": { "react": "^18.0.0 || ^19.0.0 || ^19.0.0-rc", "react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-rc" } }, "sha512-W6ZN4p58k8aDKA4XPcx2hpIQXBRAgyiWVkYhT7CvK6D3iAu7xjvVyhQHg2/iaKJZ1XVJ4r7XuwGL+WGEK37i9w=="],
|
||||
|
||||
"source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="],
|
||||
|
||||
"split2": ["split2@4.2.0", "", {}, "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg=="],
|
||||
|
||||
"sqlstring": ["sqlstring@2.3.3", "", {}, "sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg=="],
|
||||
|
||||
"std-env": ["std-env@3.10.0", "", {}, "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg=="],
|
||||
|
||||
"styled-jsx": ["styled-jsx@5.1.6", "", { "dependencies": { "client-only": "0.0.1" }, "peerDependencies": { "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0" } }, "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA=="],
|
||||
|
||||
"tailwind-merge": ["tailwind-merge@3.3.1", "", {}, "sha512-gBXpgUm/3rp1lMZZrM/w7D8GKqshif0zAymAhbCyIt8KMe+0v9DQ7cdYLR4FHH/cKpdTXb+A/tKKU3eolfsI+g=="],
|
||||
@@ -439,12 +664,112 @@
|
||||
|
||||
"use-sync-external-store": ["use-sync-external-store@1.6.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w=="],
|
||||
|
||||
"valibot": ["valibot@1.2.0", "", { "peerDependencies": { "typescript": ">=5" }, "optionalPeers": ["typescript"] }, "sha512-mm1rxUsmOxzrwnX5arGS+U4T25RdvpPjPN4yR0u9pUBov9+zGVtO84tif1eY4r6zWxVxu3KzIyknJy3rxfRZZg=="],
|
||||
|
||||
"which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="],
|
||||
|
||||
"xtend": ["xtend@4.0.2", "", {}, "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="],
|
||||
|
||||
"yallist": ["yallist@5.0.0", "", {}, "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw=="],
|
||||
|
||||
"zeptomatch": ["zeptomatch@2.1.0", "", { "dependencies": { "grammex": "^3.1.11", "graphmatch": "^1.1.0" } }, "sha512-KiGErG2J0G82LSpniV0CtIzjlJ10E04j02VOudJsPyPwNZgGnRKQy7I1R7GMyg/QswnE4l7ohSGrQbQbjXPPDA=="],
|
||||
|
||||
"zod": ["zod@4.3.6", "", {}, "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg=="],
|
||||
|
||||
"@prisma/engines/@prisma/get-platform": ["@prisma/get-platform@7.8.0", "", { "dependencies": { "@prisma/debug": "7.8.0" } }, "sha512-WlxgRGnolL8VH2EmkH1R/DkKNr/mVdS3G2h42IZFFZ3eUrH9OT6t73kIOSlkkrv50wG123Iq8d96ufv5LlZktw=="],
|
||||
|
||||
"@prisma/fetch-engine/@prisma/get-platform": ["@prisma/get-platform@7.8.0", "", { "dependencies": { "@prisma/debug": "7.8.0" } }, "sha512-WlxgRGnolL8VH2EmkH1R/DkKNr/mVdS3G2h42IZFFZ3eUrH9OT6t73kIOSlkkrv50wG123Iq8d96ufv5LlZktw=="],
|
||||
|
||||
"@prisma/get-platform/@prisma/debug": ["@prisma/debug@7.2.0", "", {}, "sha512-YSGTiSlBAVJPzX4ONZmMotL+ozJwQjRmZweQNIq/ER0tQJKJynNkRB3kyvt37eOfsbMCXk3gnLF6J9OJ4QWftw=="],
|
||||
|
||||
"@radix-ui/react-accordion/@radix-ui/primitive": ["@radix-ui/primitive@1.1.3", "", {}, "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg=="],
|
||||
|
||||
"@radix-ui/react-accordion/@radix-ui/react-collapsible": ["@radix-ui/react-collapsible@1.1.12", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Uu+mSh4agx2ib1uIGPP4/CKNULyajb3p92LsVXmH2EHVMTfZWpll88XJ0j4W0z3f8NK1eYl1+Mf/szHPmcHzyA=="],
|
||||
|
||||
"@radix-ui/react-alert-dialog/@radix-ui/primitive": ["@radix-ui/primitive@1.1.3", "", {}, "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg=="],
|
||||
|
||||
"@radix-ui/react-alert-dialog/@radix-ui/react-dialog": ["@radix-ui/react-dialog@1.1.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-controllable-state": "1.2.2", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw=="],
|
||||
|
||||
"@radix-ui/react-context-menu/@radix-ui/primitive": ["@radix-ui/primitive@1.1.3", "", {}, "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg=="],
|
||||
|
||||
"@radix-ui/react-context-menu/@radix-ui/react-menu": ["@radix-ui/react-menu@2.1.16", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-callback-ref": "1.1.1", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-72F2T+PLlphrqLcAotYPp0uJMr5SjP5SL01wfEspJbru5Zs5vQaSHb4VB3ZMJPimgHHCHG7gMOeOB9H3Hdmtxg=="],
|
||||
|
||||
"@radix-ui/react-form/@radix-ui/primitive": ["@radix-ui/primitive@1.1.3", "", {}, "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg=="],
|
||||
|
||||
"@radix-ui/react-hover-card/@radix-ui/primitive": ["@radix-ui/primitive@1.1.3", "", {}, "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg=="],
|
||||
|
||||
"@radix-ui/react-hover-card/@radix-ui/react-dismissable-layer": ["@radix-ui/react-dismissable-layer@1.1.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-escape-keydown": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg=="],
|
||||
|
||||
"@radix-ui/react-hover-card/@radix-ui/react-popper": ["@radix-ui/react-popper@1.2.8", "", { "dependencies": { "@floating-ui/react-dom": "^2.0.0", "@radix-ui/react-arrow": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-rect": "1.1.1", "@radix-ui/react-use-size": "1.1.1", "@radix-ui/rect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw=="],
|
||||
|
||||
"@radix-ui/react-hover-card/@radix-ui/react-presence": ["@radix-ui/react-presence@1.1.5", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ=="],
|
||||
|
||||
"@radix-ui/react-menu/@radix-ui/react-roving-focus": ["@radix-ui/react-roving-focus@1.1.10", "", { "dependencies": { "@radix-ui/primitive": "1.1.2", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-dT9aOXUen9JSsxnMPv/0VqySQf5eDQ6LCk5Sw28kamz8wSOW2bJdlX2Bg5VUIIcV+6XlHpWTIuTPCf/UNIyq8Q=="],
|
||||
|
||||
"@radix-ui/react-menubar/@radix-ui/primitive": ["@radix-ui/primitive@1.1.3", "", {}, "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg=="],
|
||||
|
||||
"@radix-ui/react-menubar/@radix-ui/react-menu": ["@radix-ui/react-menu@2.1.16", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-callback-ref": "1.1.1", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-72F2T+PLlphrqLcAotYPp0uJMr5SjP5SL01wfEspJbru5Zs5vQaSHb4VB3ZMJPimgHHCHG7gMOeOB9H3Hdmtxg=="],
|
||||
|
||||
"@radix-ui/react-navigation-menu/@radix-ui/primitive": ["@radix-ui/primitive@1.1.3", "", {}, "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg=="],
|
||||
|
||||
"@radix-ui/react-navigation-menu/@radix-ui/react-dismissable-layer": ["@radix-ui/react-dismissable-layer@1.1.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-escape-keydown": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg=="],
|
||||
|
||||
"@radix-ui/react-navigation-menu/@radix-ui/react-presence": ["@radix-ui/react-presence@1.1.5", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ=="],
|
||||
|
||||
"@radix-ui/react-one-time-password-field/@radix-ui/primitive": ["@radix-ui/primitive@1.1.3", "", {}, "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg=="],
|
||||
|
||||
"@radix-ui/react-password-toggle-field/@radix-ui/primitive": ["@radix-ui/primitive@1.1.3", "", {}, "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg=="],
|
||||
|
||||
"@radix-ui/react-popover/@radix-ui/primitive": ["@radix-ui/primitive@1.1.3", "", {}, "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg=="],
|
||||
|
||||
"@radix-ui/react-popover/@radix-ui/react-dismissable-layer": ["@radix-ui/react-dismissable-layer@1.1.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-escape-keydown": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg=="],
|
||||
|
||||
"@radix-ui/react-popover/@radix-ui/react-focus-guards": ["@radix-ui/react-focus-guards@1.1.3", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw=="],
|
||||
|
||||
"@radix-ui/react-popover/@radix-ui/react-popper": ["@radix-ui/react-popper@1.2.8", "", { "dependencies": { "@floating-ui/react-dom": "^2.0.0", "@radix-ui/react-arrow": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-rect": "1.1.1", "@radix-ui/react-use-size": "1.1.1", "@radix-ui/rect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw=="],
|
||||
|
||||
"@radix-ui/react-popover/@radix-ui/react-presence": ["@radix-ui/react-presence@1.1.5", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ=="],
|
||||
|
||||
"@radix-ui/react-popper/@floating-ui/react-dom": ["@floating-ui/react-dom@2.1.3", "", { "dependencies": { "@floating-ui/dom": "^1.0.0" }, "peerDependencies": { "react": ">=16.8.0", "react-dom": ">=16.8.0" } }, "sha512-huMBfiU9UnQ2oBwIhgzyIiSpVgvlDstU8CX0AF+wS+KzmYMs0J2a3GwuFHV1Lz+jlrQGeC1fF+Nv0QoumyV0bA=="],
|
||||
|
||||
"@radix-ui/react-radio-group/@radix-ui/primitive": ["@radix-ui/primitive@1.1.3", "", {}, "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg=="],
|
||||
|
||||
"@radix-ui/react-radio-group/@radix-ui/react-presence": ["@radix-ui/react-presence@1.1.5", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ=="],
|
||||
|
||||
"@radix-ui/react-roving-focus/@radix-ui/primitive": ["@radix-ui/primitive@1.1.3", "", {}, "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg=="],
|
||||
|
||||
"@radix-ui/react-scroll-area/@radix-ui/primitive": ["@radix-ui/primitive@1.1.3", "", {}, "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg=="],
|
||||
|
||||
"@radix-ui/react-scroll-area/@radix-ui/react-presence": ["@radix-ui/react-presence@1.1.5", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ=="],
|
||||
|
||||
"@radix-ui/react-select/@radix-ui/primitive": ["@radix-ui/primitive@1.1.3", "", {}, "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg=="],
|
||||
|
||||
"@radix-ui/react-select/@radix-ui/react-dismissable-layer": ["@radix-ui/react-dismissable-layer@1.1.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-escape-keydown": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg=="],
|
||||
|
||||
"@radix-ui/react-select/@radix-ui/react-focus-guards": ["@radix-ui/react-focus-guards@1.1.3", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw=="],
|
||||
|
||||
"@radix-ui/react-select/@radix-ui/react-popper": ["@radix-ui/react-popper@1.2.8", "", { "dependencies": { "@floating-ui/react-dom": "^2.0.0", "@radix-ui/react-arrow": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-rect": "1.1.1", "@radix-ui/react-use-size": "1.1.1", "@radix-ui/rect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw=="],
|
||||
|
||||
"@radix-ui/react-slider/@radix-ui/primitive": ["@radix-ui/primitive@1.1.3", "", {}, "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg=="],
|
||||
|
||||
"@radix-ui/react-switch/@radix-ui/primitive": ["@radix-ui/primitive@1.1.3", "", {}, "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg=="],
|
||||
|
||||
"@radix-ui/react-tabs/@radix-ui/primitive": ["@radix-ui/primitive@1.1.3", "", {}, "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg=="],
|
||||
|
||||
"@radix-ui/react-tabs/@radix-ui/react-presence": ["@radix-ui/react-presence@1.1.5", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ=="],
|
||||
|
||||
"@radix-ui/react-toast/@radix-ui/primitive": ["@radix-ui/primitive@1.1.3", "", {}, "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg=="],
|
||||
|
||||
"@radix-ui/react-toast/@radix-ui/react-dismissable-layer": ["@radix-ui/react-dismissable-layer@1.1.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-escape-keydown": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg=="],
|
||||
|
||||
"@radix-ui/react-toast/@radix-ui/react-presence": ["@radix-ui/react-presence@1.1.5", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ=="],
|
||||
|
||||
"@radix-ui/react-toggle/@radix-ui/primitive": ["@radix-ui/primitive@1.1.3", "", {}, "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg=="],
|
||||
|
||||
"@radix-ui/react-toggle-group/@radix-ui/primitive": ["@radix-ui/primitive@1.1.3", "", {}, "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg=="],
|
||||
|
||||
"@radix-ui/react-toolbar/@radix-ui/primitive": ["@radix-ui/primitive@1.1.3", "", {}, "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg=="],
|
||||
|
||||
"@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.4.3", "", { "dependencies": { "@emnapi/wasi-threads": "1.0.2", "tslib": "^2.4.0" }, "bundled": true }, "sha512-4m62DuCE07lw01soJwPiBGC0nAww0Q+RY70VZ+n49yDIO13yyinhbWCeNnaob0lakDtWQzSdtNWzJeOJt2ma+g=="],
|
||||
|
||||
"@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.4.3", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ=="],
|
||||
@@ -459,10 +784,62 @@
|
||||
|
||||
"@types/papaparse/@types/node": ["@types/node@20.19.1", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-jJD50LtlD2dodAEO653i3YF04NWak6jN3ky+Ri3Em3mGR39/glWiboM/IePaRbgwSfqM1TpGXfAg8ohn/4dTgA=="],
|
||||
|
||||
"c12/jiti": ["jiti@2.7.0", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ=="],
|
||||
|
||||
"next/postcss": ["postcss@8.4.31", "", { "dependencies": { "nanoid": "^3.3.6", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" } }, "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ=="],
|
||||
|
||||
"pg-types/postgres-array": ["postgres-array@2.0.0", "", {}, "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA=="],
|
||||
|
||||
"proper-lockfile/signal-exit": ["signal-exit@3.0.7", "", {}, "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="],
|
||||
|
||||
"radix-ui/@radix-ui/primitive": ["@radix-ui/primitive@1.1.3", "", {}, "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg=="],
|
||||
|
||||
"radix-ui/@radix-ui/react-checkbox": ["@radix-ui/react-checkbox@1.3.3", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-use-size": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-wBbpv+NQftHDdG86Qc0pIyXk5IR3tM8Vd0nWLKDcX8nNn4nXFOFwsKuqw2okA/1D/mpaAkmuyndrPJTYDNZtFw=="],
|
||||
|
||||
"radix-ui/@radix-ui/react-collapsible": ["@radix-ui/react-collapsible@1.1.12", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Uu+mSh4agx2ib1uIGPP4/CKNULyajb3p92LsVXmH2EHVMTfZWpll88XJ0j4W0z3f8NK1eYl1+Mf/szHPmcHzyA=="],
|
||||
|
||||
"radix-ui/@radix-ui/react-dialog": ["@radix-ui/react-dialog@1.1.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-controllable-state": "1.2.2", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw=="],
|
||||
|
||||
"radix-ui/@radix-ui/react-dismissable-layer": ["@radix-ui/react-dismissable-layer@1.1.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-escape-keydown": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg=="],
|
||||
|
||||
"radix-ui/@radix-ui/react-dropdown-menu": ["@radix-ui/react-dropdown-menu@2.1.16", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-menu": "2.1.16", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-1PLGQEynI/3OX/ftV54COn+3Sud/Mn8vALg2rWnBLnRaGtJDduNW/22XjlGgPdpcIbiQxjKtb7BkcjP00nqfJw=="],
|
||||
|
||||
"radix-ui/@radix-ui/react-focus-guards": ["@radix-ui/react-focus-guards@1.1.3", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw=="],
|
||||
|
||||
"radix-ui/@radix-ui/react-menu": ["@radix-ui/react-menu@2.1.16", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-callback-ref": "1.1.1", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-72F2T+PLlphrqLcAotYPp0uJMr5SjP5SL01wfEspJbru5Zs5vQaSHb4VB3ZMJPimgHHCHG7gMOeOB9H3Hdmtxg=="],
|
||||
|
||||
"radix-ui/@radix-ui/react-popper": ["@radix-ui/react-popper@1.2.8", "", { "dependencies": { "@floating-ui/react-dom": "^2.0.0", "@radix-ui/react-arrow": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-rect": "1.1.1", "@radix-ui/react-use-size": "1.1.1", "@radix-ui/rect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw=="],
|
||||
|
||||
"radix-ui/@radix-ui/react-presence": ["@radix-ui/react-presence@1.1.5", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ=="],
|
||||
|
||||
"radix-ui/@radix-ui/react-tooltip": ["@radix-ui/react-tooltip@1.2.8", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-visually-hidden": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-tY7sVt1yL9ozIxvmbtN5qtmH2krXcBCfjEiCgKGLqunJHvgvZG2Pcl2oQ3kbcZARb1BGEHdkLzcYGO8ynVlieg=="],
|
||||
|
||||
"sharp/detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="],
|
||||
|
||||
"@radix-ui/react-accordion/@radix-ui/react-collapsible/@radix-ui/react-presence": ["@radix-ui/react-presence@1.1.5", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ=="],
|
||||
|
||||
"@radix-ui/react-alert-dialog/@radix-ui/react-dialog/@radix-ui/react-dismissable-layer": ["@radix-ui/react-dismissable-layer@1.1.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-escape-keydown": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg=="],
|
||||
|
||||
"@radix-ui/react-alert-dialog/@radix-ui/react-dialog/@radix-ui/react-focus-guards": ["@radix-ui/react-focus-guards@1.1.3", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw=="],
|
||||
|
||||
"@radix-ui/react-alert-dialog/@radix-ui/react-dialog/@radix-ui/react-presence": ["@radix-ui/react-presence@1.1.5", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ=="],
|
||||
|
||||
"@radix-ui/react-context-menu/@radix-ui/react-menu/@radix-ui/react-dismissable-layer": ["@radix-ui/react-dismissable-layer@1.1.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-escape-keydown": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg=="],
|
||||
|
||||
"@radix-ui/react-context-menu/@radix-ui/react-menu/@radix-ui/react-focus-guards": ["@radix-ui/react-focus-guards@1.1.3", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw=="],
|
||||
|
||||
"@radix-ui/react-context-menu/@radix-ui/react-menu/@radix-ui/react-popper": ["@radix-ui/react-popper@1.2.8", "", { "dependencies": { "@floating-ui/react-dom": "^2.0.0", "@radix-ui/react-arrow": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-rect": "1.1.1", "@radix-ui/react-use-size": "1.1.1", "@radix-ui/rect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw=="],
|
||||
|
||||
"@radix-ui/react-context-menu/@radix-ui/react-menu/@radix-ui/react-presence": ["@radix-ui/react-presence@1.1.5", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ=="],
|
||||
|
||||
"@radix-ui/react-menubar/@radix-ui/react-menu/@radix-ui/react-dismissable-layer": ["@radix-ui/react-dismissable-layer@1.1.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-escape-keydown": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg=="],
|
||||
|
||||
"@radix-ui/react-menubar/@radix-ui/react-menu/@radix-ui/react-focus-guards": ["@radix-ui/react-focus-guards@1.1.3", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw=="],
|
||||
|
||||
"@radix-ui/react-menubar/@radix-ui/react-menu/@radix-ui/react-popper": ["@radix-ui/react-popper@1.2.8", "", { "dependencies": { "@floating-ui/react-dom": "^2.0.0", "@radix-ui/react-arrow": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-rect": "1.1.1", "@radix-ui/react-use-size": "1.1.1", "@radix-ui/rect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw=="],
|
||||
|
||||
"@radix-ui/react-menubar/@radix-ui/react-menu/@radix-ui/react-presence": ["@radix-ui/react-presence@1.1.5", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ=="],
|
||||
|
||||
"@radix-ui/react-popper/@floating-ui/react-dom/@floating-ui/dom": ["@floating-ui/dom@1.7.1", "", { "dependencies": { "@floating-ui/core": "^1.7.1", "@floating-ui/utils": "^0.2.9" } }, "sha512-cwsmW/zyw5ltYTUeeYJ60CnQuPqmGwuGVhG9w0PRaRKkAyi38BT5CKrpIbb+jtahSwUl04cWzSx9ZOIxeS6RsQ=="],
|
||||
|
||||
"@types/papaparse/@types/node/undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="],
|
||||
|
||||
+2
-2
@@ -5,7 +5,7 @@
|
||||
"tsx": true,
|
||||
"tailwind": {
|
||||
"config": "",
|
||||
"css": "src/app/globals.css",
|
||||
"css": "src/styles/globals.css",
|
||||
"baseColor": "zinc",
|
||||
"cssVariables": true,
|
||||
"prefix": ""
|
||||
@@ -18,4 +18,4 @@
|
||||
"hooks": "@/hooks"
|
||||
},
|
||||
"iconLibrary": "lucide"
|
||||
}
|
||||
}
|
||||
@@ -37,6 +37,11 @@ services:
|
||||
DOMAIN: ${DOMAIN}
|
||||
AUTH_TRUST_HOST: ${AUTH_TRUST_HOST}
|
||||
AUTH_SECRET: ${AUTH_SECRET}
|
||||
ADMIN_BOOTSTRAP_ENABLED: ${ADMIN_BOOTSTRAP_ENABLED:-"true"}
|
||||
ADMIN_USERNAME: ${ADMIN_USERNAME:-"admin"}
|
||||
ADMIN_EMAIL: ${ADMIN_EMAIL:-"admin@localhost"}
|
||||
ADMIN_NAME: ${ADMIN_NAME:-"Administrator"}
|
||||
ADMIN_PASSWORD: ${ADMIN_PASSWORD}
|
||||
DATABASE_URL: postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB}?schema=public
|
||||
depends_on:
|
||||
- db
|
||||
|
||||
+9
-7
@@ -2,6 +2,8 @@
|
||||
"name": "stock-manager",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"packageManager": "bun@1.3.14",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "next dev --turbopack",
|
||||
"build": "next build",
|
||||
@@ -14,16 +16,14 @@
|
||||
"db:migrate:reset": "bunx prisma migrate reset",
|
||||
"db:deploy": "bunx prisma migrate deploy",
|
||||
"db:generate": "bunx prisma generate",
|
||||
"db:seed": "bunx --bun prisma db seed",
|
||||
"db:studio": "bunx prisma studio"
|
||||
},
|
||||
"prisma": {
|
||||
"schema": "src/prisma/schema.prisma",
|
||||
"seed": "bun src/prisma/seed.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@base-ui/react": "^1.4.1",
|
||||
"@hookform/resolvers": "^5.2.2",
|
||||
"@prisma/client": "^6.10.1",
|
||||
"@prisma/adapter-pg": "^7.8.0",
|
||||
"@prisma/client": "^7.8.0",
|
||||
"@radix-ui/react-checkbox": "^1.3.2",
|
||||
"@radix-ui/react-collapsible": "^1.1.11",
|
||||
"@radix-ui/react-dialog": "^1.1.14",
|
||||
@@ -35,11 +35,13 @@
|
||||
"bcryptjs": "^3.0.2",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"lucide-react": "^1.11.0",
|
||||
"dotenv": "^17.4.2",
|
||||
"lucide-react": "^1.17.0",
|
||||
"next": "^16.2.4",
|
||||
"next-auth": "^5.0.0-beta.28",
|
||||
"next-themes": "^0.4.6",
|
||||
"papaparse": "^5.5.3",
|
||||
"radix-ui": "^1.4.3",
|
||||
"react": "^19.2.5",
|
||||
"react-dom": "^19.2.5",
|
||||
"react-hook-form": "^7.74.0",
|
||||
@@ -54,7 +56,7 @@
|
||||
"@types/node": "^24.0.3",
|
||||
"@types/react": "^19.1.8",
|
||||
"@types/react-dom": "^19.1.6",
|
||||
"prisma": "^6.10.1",
|
||||
"prisma": "^7.8.0",
|
||||
"tailwindcss": "^4.1.10",
|
||||
"tw-animate-css": "^1.3.4",
|
||||
"typescript": "^5.8.3"
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
import "dotenv/config"
|
||||
import { defineConfig, env } from "prisma/config"
|
||||
|
||||
export default defineConfig({
|
||||
schema: "prisma/schema.prisma",
|
||||
migrations: {
|
||||
path: "prisma/migrations",
|
||||
seed: "bun ./prisma/seed.ts",
|
||||
},
|
||||
datasource: {
|
||||
url: env("DATABASE_URL"),
|
||||
},
|
||||
})
|
||||
@@ -0,0 +1,80 @@
|
||||
import { fileURLToPath } from "node:url"
|
||||
import { getPasswordHash } from "@/lib/security"
|
||||
import prisma from "../src/lib/prisma"
|
||||
|
||||
type BootstrapAdminInput = {
|
||||
username: string
|
||||
email: string
|
||||
name: string
|
||||
password: string
|
||||
}
|
||||
|
||||
function getBootstrapAdminInput(): BootstrapAdminInput {
|
||||
const isProduction = process.env.NODE_ENV === "production"
|
||||
|
||||
const username = process.env.ADMIN_USERNAME ?? "admin"
|
||||
const email = process.env.ADMIN_EMAIL ?? "admin@localhost"
|
||||
const name = process.env.ADMIN_NAME ?? "Administrator"
|
||||
const password = process.env.ADMIN_PASSWORD
|
||||
|
||||
if (isProduction && !password) {
|
||||
throw new Error("ADMIN_PASSWORD is required to bootstrap an admin user")
|
||||
}
|
||||
|
||||
return {
|
||||
username,
|
||||
email,
|
||||
name,
|
||||
password: password ?? "admin",
|
||||
}
|
||||
}
|
||||
|
||||
export async function bootstrapAdmin(client: typeof prisma) {
|
||||
const enabled = process.env.ADMIN_BOOTSTRAP_ENABLED !== "false"
|
||||
const existingAdmin = await client.user.findFirst({
|
||||
where: {
|
||||
role: "ADMIN",
|
||||
isActive: true,
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
},
|
||||
})
|
||||
|
||||
if (existingAdmin || !enabled) return
|
||||
|
||||
const admin = getBootstrapAdminInput()
|
||||
|
||||
await client.user.upsert({
|
||||
where: {
|
||||
email: admin.email,
|
||||
},
|
||||
update: {
|
||||
role: "ADMIN",
|
||||
isActive: true,
|
||||
},
|
||||
create: {
|
||||
name: admin.name,
|
||||
username: admin.username,
|
||||
email: admin.email,
|
||||
role: "ADMIN",
|
||||
password: await getPasswordHash(admin.password),
|
||||
isActive: true,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
async function main() {
|
||||
try {
|
||||
await bootstrapAdmin(prisma)
|
||||
} finally {
|
||||
await prisma.$disconnect()
|
||||
}
|
||||
}
|
||||
|
||||
if (process.argv[1] === fileURLToPath(import.meta.url)) {
|
||||
main().catch((error) => {
|
||||
console.error(error)
|
||||
process.exit(1)
|
||||
})
|
||||
}
|
||||
-3
@@ -146,9 +146,6 @@ CREATE INDEX "Category_name_idx" ON "Category"("name");
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Item_categoryId_idx" ON "Item"("categoryId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Item_name_idx" ON "Item"("name");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Asset_serialNumber_key" ON "Asset"("serialNumber");
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Item_name_key" ON "Item"("name");
|
||||
@@ -0,0 +1,184 @@
|
||||
// This is your Prisma schema file,
|
||||
// learn more about the docs: https://pris.ly/d/prisma-schema
|
||||
|
||||
// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions?
|
||||
// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init
|
||||
|
||||
generator client {
|
||||
provider = "prisma-client"
|
||||
output = "../src/generated/prisma"
|
||||
binaryTargets = ["native", "debian-openssl-1.1.x"]
|
||||
}
|
||||
|
||||
datasource db {
|
||||
provider = "postgresql"
|
||||
}
|
||||
|
||||
enum UserRole {
|
||||
ADMIN
|
||||
MANAGER
|
||||
STAFF
|
||||
VIEWER
|
||||
}
|
||||
|
||||
model User {
|
||||
id String @id @default(uuid())
|
||||
username String @unique
|
||||
name String
|
||||
email String @unique
|
||||
password String
|
||||
role UserRole @default(STAFF)
|
||||
isActive Boolean @default(true)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
movements Movement[]
|
||||
assignments Assignment[]
|
||||
}
|
||||
|
||||
enum RecipientDepartment {
|
||||
IT
|
||||
ENGINEERING
|
||||
LOGISTICS
|
||||
TRAFFIC
|
||||
DRIVER
|
||||
ADMINISTRATION
|
||||
SALES
|
||||
OTHER
|
||||
}
|
||||
|
||||
model Recipient {
|
||||
id String @id @default(uuid())
|
||||
username String @unique
|
||||
firstName String
|
||||
lastName String
|
||||
department RecipientDepartment?
|
||||
email String? @unique
|
||||
phone String?
|
||||
isActive Boolean @default(true)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
assignments Assignment[]
|
||||
movements Movement[]
|
||||
|
||||
@@index([lastName, firstName])
|
||||
@@index([department])
|
||||
}
|
||||
|
||||
model Category {
|
||||
id String @id @default(uuid())
|
||||
name String @unique
|
||||
description String?
|
||||
isActive Boolean @default(true)
|
||||
items Item[]
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@index([name])
|
||||
}
|
||||
|
||||
enum ItemStatus {
|
||||
AVAILABLE
|
||||
ASSIGNED
|
||||
RESERVED
|
||||
IN_REPAIR
|
||||
BROKEN
|
||||
STOLEN
|
||||
DISPOSED
|
||||
}
|
||||
|
||||
model Item {
|
||||
id String @id @default(uuid())
|
||||
name String @unique
|
||||
description String?
|
||||
categoryId String
|
||||
category Category @relation(fields: [categoryId], references: [id])
|
||||
stock Int @default(0)
|
||||
minStock Int?
|
||||
maxStock Int?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
deletedAt DateTime?
|
||||
movements Movement[]
|
||||
assignments Assignment[]
|
||||
assets Asset[]
|
||||
|
||||
@@index([categoryId])
|
||||
}
|
||||
|
||||
model Asset {
|
||||
id String @id @default(uuid())
|
||||
itemId String?
|
||||
item Item? @relation(fields: [itemId], references: [id])
|
||||
serialNumber String @unique
|
||||
deliveryNote String?
|
||||
status ItemStatus @default(AVAILABLE)
|
||||
notes String?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
movements Movement[]
|
||||
assignment Assignment?
|
||||
|
||||
@@index([serialNumber])
|
||||
@@index([itemId])
|
||||
@@index([status])
|
||||
}
|
||||
|
||||
model Assignment {
|
||||
id String @id @default(uuid())
|
||||
quantity Int?
|
||||
notes String?
|
||||
itemId String?
|
||||
item Item? @relation(fields: [itemId], references: [id])
|
||||
assetId String? @unique
|
||||
asset Asset? @relation(fields: [assetId], references: [id])
|
||||
recipientId String?
|
||||
recipient Recipient? @relation(fields: [recipientId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
||||
assignmentDate DateTime @default(now())
|
||||
returnDate DateTime?
|
||||
createdBy String
|
||||
createdUser User @relation(fields: [createdBy], references: [id])
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
movement Movement[]
|
||||
|
||||
@@index([itemId])
|
||||
@@index([assetId])
|
||||
@@index([recipientId])
|
||||
@@index([createdBy])
|
||||
}
|
||||
|
||||
enum MovementType {
|
||||
IN
|
||||
OUT
|
||||
ASSIGNMENT
|
||||
RETURN
|
||||
ADJUSTMENT
|
||||
DELETED
|
||||
}
|
||||
|
||||
model Movement {
|
||||
id String @id @default(uuid())
|
||||
type MovementType @default(IN)
|
||||
quantity Int
|
||||
details String?
|
||||
notes String?
|
||||
itemId String?
|
||||
item Item? @relation(fields: [itemId], references: [id])
|
||||
assetId String?
|
||||
asset Asset? @relation(fields: [assetId], references: [id])
|
||||
previousStock Int?
|
||||
newStock Int?
|
||||
recipientId String?
|
||||
recipient Recipient? @relation(fields: [recipientId], references: [id])
|
||||
assignmentId String?
|
||||
assignment Assignment? @relation(fields: [assignmentId], references: [id])
|
||||
userId String
|
||||
user User @relation(fields: [userId], references: [id])
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
@@index([itemId])
|
||||
@@index([assetId])
|
||||
@@index([recipientId])
|
||||
@@index([type])
|
||||
@@index([userId])
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import prisma from "../src/lib/prisma"
|
||||
|
||||
import { bootstrapAdmin } from "./bootstrap-admin"
|
||||
|
||||
async function main() {
|
||||
await bootstrapAdmin(prisma)
|
||||
}
|
||||
|
||||
main()
|
||||
.then(async () => {
|
||||
await prisma.$disconnect()
|
||||
})
|
||||
.catch(async (e) => {
|
||||
console.error(e)
|
||||
await prisma.$disconnect()
|
||||
process.exit(1)
|
||||
})
|
||||
@@ -0,0 +1,93 @@
|
||||
"use server"
|
||||
|
||||
import { revalidatePath } from "next/cache"
|
||||
import { flattenError } from "zod"
|
||||
import {
|
||||
type CreateAssetFormType,
|
||||
createAssetSchema,
|
||||
type UpdateAssetFormType,
|
||||
updateAssetSchema,
|
||||
} from "@/schemas/asset.schema"
|
||||
import { getAuthenticatedUserId } from "@/services/auth.service"
|
||||
import {
|
||||
createAssetUseCase,
|
||||
updateAssetUseCase,
|
||||
} from "@/use-cases/asset.use-cases"
|
||||
|
||||
export async function createAssetAction(formData: CreateAssetFormType) {
|
||||
try {
|
||||
const validatedFields = createAssetSchema.safeParse(formData)
|
||||
|
||||
if (!validatedFields.success) {
|
||||
return {
|
||||
errors: flattenError(validatedFields.error).fieldErrors,
|
||||
}
|
||||
}
|
||||
|
||||
const userId = await getAuthenticatedUserId()
|
||||
|
||||
const result = await createAssetUseCase({
|
||||
...validatedFields.data,
|
||||
actorId: userId,
|
||||
})
|
||||
|
||||
if (!result.success) {
|
||||
return result
|
||||
}
|
||||
|
||||
revalidatePath("/inventory/assets")
|
||||
revalidatePath("/inventory/items")
|
||||
revalidatePath("/assignments")
|
||||
revalidatePath("/movements")
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: "Asset created successfully",
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Database error:", error)
|
||||
return {
|
||||
success: false,
|
||||
message: "Error creating asset",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function updateAssetAction(formData: UpdateAssetFormType) {
|
||||
const validatedFields = updateAssetSchema.safeParse(formData)
|
||||
|
||||
if (!validatedFields.success) {
|
||||
return {
|
||||
errors: flattenError(validatedFields.error).fieldErrors,
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const userId = await getAuthenticatedUserId()
|
||||
|
||||
const result = await updateAssetUseCase({
|
||||
...validatedFields.data,
|
||||
actorId: userId,
|
||||
})
|
||||
|
||||
if (!result.success) {
|
||||
return result
|
||||
}
|
||||
|
||||
revalidatePath("/inventory/assets")
|
||||
revalidatePath("/inventory/items")
|
||||
revalidatePath("/assignments")
|
||||
revalidatePath("/movements")
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: "Asset updated successfully",
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Database error:", error)
|
||||
return {
|
||||
success: false,
|
||||
message: "Error updating asset",
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
"use server"
|
||||
|
||||
import { revalidatePath } from "next/cache"
|
||||
import { getAuthenticatedUserId } from "@/services/auth.service"
|
||||
import {
|
||||
createAssignmentUseCase,
|
||||
returnAssignmentUseCase,
|
||||
updateAssignmentUseCase,
|
||||
} from "@/use-cases/assignment.use-cases"
|
||||
|
||||
import {
|
||||
assignmentSchema,
|
||||
type CreateAssignmentFormType,
|
||||
type ReturnAssignmentFormType,
|
||||
type UpdateAssignmentFormType,
|
||||
updateAssignmentSchema,
|
||||
} from "@/schemas/assignment.schema"
|
||||
|
||||
export async function createAssignment(formData: CreateAssignmentFormType) {
|
||||
const createdBy = await getAuthenticatedUserId()
|
||||
|
||||
const validatedFields = assignmentSchema.safeParse({
|
||||
...formData,
|
||||
createdBy,
|
||||
})
|
||||
|
||||
if (!validatedFields.success) {
|
||||
return {
|
||||
success: false,
|
||||
errors: validatedFields.error.flatten().fieldErrors,
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await createAssignmentUseCase({
|
||||
...validatedFields.data,
|
||||
actorId: createdBy,
|
||||
})
|
||||
|
||||
if (!result.success) {
|
||||
return result
|
||||
}
|
||||
|
||||
revalidatePath("/assignments")
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: "Assignment created successfully",
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Database error:", error)
|
||||
return {
|
||||
success: false,
|
||||
errors: { error: ["Error creating assignment"] },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function updateAssignment(formData: UpdateAssignmentFormType) {
|
||||
const validatedFields = updateAssignmentSchema.safeParse(formData)
|
||||
|
||||
if (!validatedFields.success) {
|
||||
return {
|
||||
success: false,
|
||||
errors: validatedFields.error.flatten().fieldErrors,
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const createdBy = await getAuthenticatedUserId()
|
||||
|
||||
const result = await updateAssignmentUseCase({
|
||||
...validatedFields.data,
|
||||
actorId: createdBy,
|
||||
})
|
||||
|
||||
if (!result.success) {
|
||||
return result
|
||||
}
|
||||
|
||||
revalidatePath("/assignments")
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: "Assignment updated successfully",
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Database error:", error)
|
||||
return {
|
||||
success: false,
|
||||
errors: { error: ["Error updating assignment"] },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function returnAssignment(formData: ReturnAssignmentFormType) {
|
||||
const { id } = formData
|
||||
const userId = await getAuthenticatedUserId()
|
||||
|
||||
const result = await returnAssignmentUseCase({
|
||||
id,
|
||||
actorId: userId,
|
||||
})
|
||||
|
||||
if (!result.success) {
|
||||
return {
|
||||
...result,
|
||||
message: "Error returning assignment",
|
||||
}
|
||||
}
|
||||
|
||||
revalidatePath("/assignments")
|
||||
|
||||
return {
|
||||
success: true as const,
|
||||
message: "Assignment returned successfully",
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
import { AuthError } from "next-auth"
|
||||
|
||||
import { signIn } from "@/lib/auth"
|
||||
import type { SignInFormType } from "@/lib/schemas/auth.schemas"
|
||||
import type { SignInFormType } from "@/schemas/auth.schema"
|
||||
|
||||
export async function signInAction(values: SignInFormType) {
|
||||
const { username, password } = values
|
||||
@@ -7,8 +7,12 @@ import {
|
||||
createCategorySchema,
|
||||
type UpdateCategoryFormType,
|
||||
updateCategorySchema,
|
||||
} from "@/lib/schemas/category.schemas"
|
||||
import { CategoryService } from "@/services/category.service"
|
||||
} from "@/schemas/category.schema"
|
||||
import {
|
||||
createCategoryUseCase,
|
||||
deleteCategoryUseCase,
|
||||
updateCategoryUseCase,
|
||||
} from "@/use-cases/category.use-cases"
|
||||
|
||||
export async function createCategoryAction(formData: CreateCategoryFormType) {
|
||||
const validatedFields = createCategorySchema.safeParse(formData)
|
||||
@@ -21,21 +25,12 @@ export async function createCategoryAction(formData: CreateCategoryFormType) {
|
||||
}
|
||||
|
||||
try {
|
||||
const existingCategory = await CategoryService.findByName(
|
||||
validatedFields.data.name,
|
||||
)
|
||||
const result = await createCategoryUseCase(validatedFields.data)
|
||||
|
||||
if (existingCategory) {
|
||||
return {
|
||||
success: false,
|
||||
errors: {
|
||||
name: ["Category already exists"],
|
||||
},
|
||||
}
|
||||
if (!result.success) {
|
||||
return result
|
||||
}
|
||||
|
||||
await CategoryService.create(validatedFields.data)
|
||||
|
||||
revalidatePath("/inventory/categories")
|
||||
|
||||
return {
|
||||
@@ -64,36 +59,13 @@ export async function updateCategoryAction(formData: UpdateCategoryFormType) {
|
||||
}
|
||||
}
|
||||
|
||||
const { id, name } = validatedFields.data
|
||||
|
||||
try {
|
||||
const existingCategory = await CategoryService.findById(id)
|
||||
const result = await updateCategoryUseCase(validatedFields.data)
|
||||
|
||||
if (!existingCategory) {
|
||||
return {
|
||||
success: false,
|
||||
errors: { id: ["Category not found"] },
|
||||
}
|
||||
if (!result.success) {
|
||||
return result
|
||||
}
|
||||
|
||||
if (existingCategory.name === name) {
|
||||
return {
|
||||
success: false,
|
||||
errors: { name: ["Category name is the same as the old one"] },
|
||||
}
|
||||
}
|
||||
|
||||
if (await CategoryService.findByName(name)) {
|
||||
return {
|
||||
success: false,
|
||||
errors: { name: ["Category already exists"] },
|
||||
}
|
||||
}
|
||||
|
||||
await CategoryService.update(id, {
|
||||
name,
|
||||
})
|
||||
|
||||
revalidatePath("/inventory/categories")
|
||||
|
||||
return {
|
||||
@@ -113,40 +85,27 @@ export async function deleteCategoryAction(formData: FormData) {
|
||||
const { id } = Object.fromEntries(formData) as { id: string }
|
||||
|
||||
try {
|
||||
const existingCategory = await CategoryService.findAllWithItemsCount()
|
||||
const category = existingCategory.find((category) => category.id === id)
|
||||
const result = await deleteCategoryUseCase(id)
|
||||
|
||||
if (!category) {
|
||||
if (!result.success) {
|
||||
return {
|
||||
success: false,
|
||||
errors: {
|
||||
id: ["Category not found"],
|
||||
},
|
||||
...result,
|
||||
message: "Failed to delete category",
|
||||
}
|
||||
}
|
||||
|
||||
if (category._count.items && category._count.items > 0) {
|
||||
return {
|
||||
success: false,
|
||||
errors: {
|
||||
id: ["Category has items"],
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
await CategoryService.delete(id)
|
||||
|
||||
revalidatePath("/inventory/categories")
|
||||
|
||||
return {
|
||||
success: true,
|
||||
success: true as const,
|
||||
message: "Category deleted successfully",
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Database error:", error)
|
||||
return {
|
||||
success: false,
|
||||
success: false as const,
|
||||
message: "Failed to delete category",
|
||||
errors: {},
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,8 +4,15 @@ import { revalidatePath } from "next/cache"
|
||||
import Papa from "papaparse"
|
||||
import { flattenError } from "zod"
|
||||
|
||||
import { type ImportFormType, importSchema } from "@/lib/schemas/import.schemas"
|
||||
import type { CreateMovementFormType } from "@/lib/schemas/movement.schemas"
|
||||
import { type ImportFormType, importSchema } from "@/schemas/import.schema"
|
||||
import type { CreateMovementFormType } from "@/schemas/movement.schema"
|
||||
import { AssetService } from "@/services/asset.service"
|
||||
import { AssignmentService } from "@/services/assignment.service"
|
||||
import { getAuthenticatedUserId } from "@/services/auth.service"
|
||||
import { CategoryService } from "@/services/category.service"
|
||||
import { ItemService } from "@/services/item.service"
|
||||
import { MovementService } from "@/services/movement.service"
|
||||
import { RecipientService } from "@/services/recipient.service"
|
||||
import type {
|
||||
Asset,
|
||||
Assignment,
|
||||
@@ -13,13 +20,7 @@ import type {
|
||||
ImportItem,
|
||||
Item,
|
||||
Recipient,
|
||||
} from "@/lib/types"
|
||||
import { AssetService } from "@/services/asset.service"
|
||||
import { AssignmentService } from "@/services/assignment.service"
|
||||
import { CategoryService } from "@/services/category.service"
|
||||
import { ItemService } from "@/services/item.service"
|
||||
import { MovementService } from "@/services/movement.service"
|
||||
import { RecipientService } from "@/services/recipient.service"
|
||||
} from "@/types"
|
||||
|
||||
export async function importItems(formData: ImportFormType) {
|
||||
const validatedFields = importSchema.safeParse(formData)
|
||||
@@ -31,6 +32,7 @@ export async function importItems(formData: ImportFormType) {
|
||||
}
|
||||
|
||||
const { file, categoryId } = validatedFields.data
|
||||
const userId = await getAuthenticatedUserId()
|
||||
|
||||
if (!file) {
|
||||
return {
|
||||
@@ -313,6 +315,7 @@ export async function importItems(formData: ImportFormType) {
|
||||
assetId: newAsset?.id || "",
|
||||
recipientId: newRecipient?.id || "",
|
||||
assignmentDate: new Date(),
|
||||
createdBy: userId,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -332,7 +335,10 @@ export async function importItems(formData: ImportFormType) {
|
||||
movementData.recipientId = newRecipient.id
|
||||
}
|
||||
|
||||
await MovementService.create(movementData)
|
||||
await MovementService.create({
|
||||
...movementData,
|
||||
userId,
|
||||
})
|
||||
}
|
||||
|
||||
revalidatePath("/inventory/items")
|
||||
@@ -0,0 +1,116 @@
|
||||
"use server"
|
||||
|
||||
import { revalidatePath } from "next/cache"
|
||||
import {
|
||||
type CreateItemFormType,
|
||||
createItemSchema,
|
||||
type UpdateItemFormType,
|
||||
updateItemSchema,
|
||||
} from "@/schemas/item.schema"
|
||||
import { getAuthenticatedUserId } from "@/services/auth.service"
|
||||
import {
|
||||
createItemUseCase,
|
||||
deleteItemUseCase,
|
||||
updateItemUseCase,
|
||||
} from "@/use-cases/item.use-cases"
|
||||
|
||||
export async function createItemAction(formData: CreateItemFormType) {
|
||||
const validatedFields = createItemSchema.safeParse(formData)
|
||||
|
||||
if (!validatedFields.success) {
|
||||
return {
|
||||
errors: validatedFields.error.flatten().fieldErrors,
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const userId = await getAuthenticatedUserId()
|
||||
|
||||
const result = await createItemUseCase({
|
||||
...validatedFields.data,
|
||||
actorId: userId,
|
||||
})
|
||||
|
||||
if (!result.success) {
|
||||
return result
|
||||
}
|
||||
|
||||
revalidatePath("/inventory/items")
|
||||
revalidatePath("/movements")
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: "Item created successfully!",
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Database error:", error)
|
||||
return {
|
||||
error: "Error creating item",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function updateItemAction(formData: UpdateItemFormType) {
|
||||
const validatedFields = updateItemSchema.safeParse(formData)
|
||||
|
||||
if (!validatedFields.success) {
|
||||
return {
|
||||
errors: validatedFields.error.flatten().fieldErrors,
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const userId = await getAuthenticatedUserId()
|
||||
|
||||
const result = await updateItemUseCase({
|
||||
...validatedFields.data,
|
||||
actorId: userId,
|
||||
})
|
||||
|
||||
if (!result.success) {
|
||||
return result
|
||||
}
|
||||
|
||||
revalidatePath("/inventory/items")
|
||||
revalidatePath("/movements")
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: "Item updated successfully!",
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Database error:", error)
|
||||
return {
|
||||
error: "Failed to update item",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function deleteItemAction(formData: FormData) {
|
||||
const { id } = Object.fromEntries(formData) as { id: string }
|
||||
|
||||
try {
|
||||
const result = await deleteItemUseCase(id)
|
||||
|
||||
if (!result.success) {
|
||||
return {
|
||||
...result,
|
||||
message: "Failed to delete item",
|
||||
}
|
||||
}
|
||||
|
||||
revalidatePath("/inventory/items")
|
||||
|
||||
return {
|
||||
success: true as const,
|
||||
message: "Item deleted successfully!",
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Database error:", error)
|
||||
return {
|
||||
success: false as const,
|
||||
message: "Failed to delete item",
|
||||
errors: {},
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
"use server"
|
||||
|
||||
import { revalidatePath } from "next/cache"
|
||||
|
||||
import {
|
||||
type CreateRecipientFormType,
|
||||
createRecipientSchema,
|
||||
type UpdateRecipientFormType,
|
||||
updateRecipientSchema,
|
||||
} from "@/schemas/recipient.schema"
|
||||
import {
|
||||
createRecipientUseCase,
|
||||
updateRecipientUseCase,
|
||||
} from "@/use-cases/recipient.use-cases"
|
||||
|
||||
export async function createNewRecipient(formData: CreateRecipientFormType) {
|
||||
const validatedFields = createRecipientSchema.safeParse(formData)
|
||||
|
||||
if (!validatedFields.success) {
|
||||
return {
|
||||
success: false,
|
||||
errors: validatedFields.error.flatten().fieldErrors,
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await createRecipientUseCase(validatedFields.data)
|
||||
|
||||
if (!result.success) {
|
||||
return result
|
||||
}
|
||||
|
||||
revalidatePath("/recipients")
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: "Recipient created successfully",
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Database error:", error)
|
||||
return {
|
||||
message: "Failed to create recipient",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function updateRecipient(formData: UpdateRecipientFormType) {
|
||||
const validatedFields = updateRecipientSchema.safeParse(formData)
|
||||
|
||||
if (!validatedFields.success) {
|
||||
return {
|
||||
success: false,
|
||||
errors: validatedFields.error.flatten().fieldErrors,
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await updateRecipientUseCase(validatedFields.data)
|
||||
|
||||
if (!result.success) {
|
||||
return result
|
||||
}
|
||||
|
||||
revalidatePath("/recipients")
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: "Recipient updated successfully",
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Database error:", error)
|
||||
return {
|
||||
message: "Failed to update recipient",
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
"use server"
|
||||
|
||||
import { revalidatePath } from "next/cache"
|
||||
import { flattenError } from "zod"
|
||||
|
||||
import {
|
||||
type CreateUserFormType,
|
||||
createUserSchema,
|
||||
type ResetUserPasswordFormType,
|
||||
resetUserPasswordSchema,
|
||||
type SetUserActiveFormType,
|
||||
setUserActiveSchema,
|
||||
type UpdateUserFormType,
|
||||
updateUserSchema,
|
||||
} from "@/schemas/user.schema"
|
||||
import { requireRole } from "@/services/auth.service"
|
||||
import {
|
||||
createUserUseCase,
|
||||
resetUserPasswordUseCase,
|
||||
setUserActiveUseCase,
|
||||
updateUserUseCase,
|
||||
} from "@/use-cases/user.use-cases"
|
||||
|
||||
const USERS_PATH = "/admin/users"
|
||||
|
||||
export async function createUserAction(formData: CreateUserFormType) {
|
||||
await requireRole("ADMIN")
|
||||
|
||||
const validatedFields = createUserSchema.safeParse(formData)
|
||||
|
||||
if (!validatedFields.success) {
|
||||
return {
|
||||
success: false,
|
||||
errors: validatedFields.error.flatten().fieldErrors,
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await createUserUseCase(validatedFields.data)
|
||||
|
||||
if (!result.success) {
|
||||
return result
|
||||
}
|
||||
|
||||
revalidatePath(USERS_PATH)
|
||||
|
||||
return { success: true, message: "User created successfully" }
|
||||
} catch (error) {
|
||||
console.error("Database error:", error)
|
||||
return { success: false, message: "Failed to create user" }
|
||||
}
|
||||
}
|
||||
|
||||
export async function updateUserAction(formData: UpdateUserFormType) {
|
||||
const session = await requireRole("ADMIN")
|
||||
|
||||
const validatedFields = updateUserSchema.safeParse(formData)
|
||||
|
||||
if (!validatedFields.success) {
|
||||
return {
|
||||
success: false,
|
||||
errors: flattenError(validatedFields.error).fieldErrors,
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await updateUserUseCase({
|
||||
...validatedFields.data,
|
||||
actorId: session.user.id,
|
||||
})
|
||||
|
||||
if (!result.success) {
|
||||
return result
|
||||
}
|
||||
|
||||
revalidatePath(USERS_PATH)
|
||||
|
||||
return { success: true, message: "User updated successfully" }
|
||||
} catch (error) {
|
||||
console.error("Database error:", error)
|
||||
return { success: false, message: "Failed to update user" }
|
||||
}
|
||||
}
|
||||
|
||||
export async function setUserActiveAction(formData: SetUserActiveFormType) {
|
||||
const session = await requireRole("ADMIN")
|
||||
|
||||
const validatedFields = setUserActiveSchema.safeParse(formData)
|
||||
|
||||
if (!validatedFields.success) {
|
||||
return {
|
||||
success: false,
|
||||
errors: flattenError(validatedFields.error).fieldErrors,
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await setUserActiveUseCase({
|
||||
...validatedFields.data,
|
||||
actorId: session.user.id,
|
||||
})
|
||||
|
||||
if (!result.success) {
|
||||
return result
|
||||
}
|
||||
|
||||
revalidatePath(USERS_PATH)
|
||||
|
||||
return { success: true, message: "User status updated successfully" }
|
||||
} catch (error) {
|
||||
console.error("Database error:", error)
|
||||
return { success: false, message: "Failed to update user status" }
|
||||
}
|
||||
}
|
||||
|
||||
export async function resetUserPasswordAction(
|
||||
formData: ResetUserPasswordFormType,
|
||||
) {
|
||||
await requireRole("ADMIN")
|
||||
|
||||
const validatedFields = resetUserPasswordSchema.safeParse(formData)
|
||||
|
||||
if (!validatedFields.success) {
|
||||
return {
|
||||
success: false,
|
||||
errors: validatedFields.error.flatten().fieldErrors,
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await resetUserPasswordUseCase(validatedFields.data)
|
||||
|
||||
if (!result.success) {
|
||||
return result
|
||||
}
|
||||
|
||||
revalidatePath(USERS_PATH)
|
||||
|
||||
return { success: true, message: "Password reset successfully" }
|
||||
} catch (error) {
|
||||
console.error("Database error:", error)
|
||||
return { success: false, message: "Failed to reset password" }
|
||||
}
|
||||
}
|
||||
@@ -4,10 +4,9 @@ import { zodResolver } from "@hookform/resolvers/zod"
|
||||
import { useRouter, useSearchParams } from "next/navigation"
|
||||
import { useState } from "react"
|
||||
import { useForm } from "react-hook-form"
|
||||
|
||||
import { signInAction } from "@/actions/auth.actions"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { signInAction } from "@/lib/actions/auth.actions"
|
||||
import { type SignInFormType, signInSchema } from "@/lib/schemas/auth.schemas"
|
||||
import { type SignInFormType, signInSchema } from "@/schemas/auth.schema"
|
||||
|
||||
export default function SignInForm() {
|
||||
const router = useRouter()
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
import type { ReactNode } from "react"
|
||||
|
||||
import { requireRole } from "@/services/auth.service"
|
||||
|
||||
export default async function AdminLayout({
|
||||
children,
|
||||
}: {
|
||||
children: ReactNode
|
||||
}) {
|
||||
await requireRole("ADMIN")
|
||||
|
||||
return children
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
import { notFound } from "next/navigation"
|
||||
|
||||
import { getUserProfileById } from "@/services/user.service"
|
||||
|
||||
import EditUserForm from "../../_components/edit.user.form"
|
||||
import ResetUserPasswordForm from "../../_components/reset.user.password.form"
|
||||
|
||||
export default async function EditUserPage({
|
||||
params,
|
||||
}: {
|
||||
params: Promise<{ userId: string }>
|
||||
}) {
|
||||
const { userId } = await params
|
||||
const user = await getUserProfileById(userId)
|
||||
|
||||
if (!user) {
|
||||
notFound()
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-8">
|
||||
<div className="flex items-center justify-between gap-4">
|
||||
<h1 className="text-2xl font-bold">Edit User</h1>
|
||||
</div>
|
||||
<EditUserForm user={user} />
|
||||
<section className="flex flex-col gap-4 border-t pt-6">
|
||||
<h2 className="text-xl font-semibold">Reset password</h2>
|
||||
<ResetUserPasswordForm userId={user.id} />
|
||||
</section>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
"use client"
|
||||
|
||||
import { zodResolver } from "@hookform/resolvers/zod"
|
||||
import { useRouter } from "next/navigation"
|
||||
import type { UseFormRegisterReturn } from "react-hook-form"
|
||||
import { useForm } from "react-hook-form"
|
||||
import { toast } from "sonner"
|
||||
import { updateUserAction } from "@/actions/user.actions"
|
||||
import { SubmitButton } from "@/components/forms/submitButton"
|
||||
import {
|
||||
type UpdateUserFormType,
|
||||
updateUserSchema,
|
||||
} from "@/schemas/user.schema"
|
||||
import type { UserWithoutPassword } from "@/services/user.service"
|
||||
|
||||
export default function EditUserForm({ user }: { user: UserWithoutPassword }) {
|
||||
const router = useRouter()
|
||||
const {
|
||||
register,
|
||||
handleSubmit,
|
||||
setError,
|
||||
formState: { errors, isSubmitting, isSubmitSuccessful },
|
||||
} = useForm<UpdateUserFormType>({
|
||||
resolver: zodResolver(updateUserSchema),
|
||||
defaultValues: {
|
||||
id: user.id,
|
||||
name: user.name,
|
||||
username: user.username,
|
||||
email: user.email,
|
||||
role: user.role,
|
||||
isActive: user.isActive,
|
||||
},
|
||||
})
|
||||
|
||||
const onSubmit = async (formData: UpdateUserFormType) => {
|
||||
const response = await updateUserAction(formData)
|
||||
|
||||
if (response?.errors) {
|
||||
Object.entries(response.errors).forEach(([fieldName, messages]) => {
|
||||
messages.forEach((message: string) => {
|
||||
setError(fieldName as keyof UpdateUserFormType, {
|
||||
type: "server",
|
||||
message,
|
||||
})
|
||||
toast.error(message)
|
||||
})
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if (response?.success) {
|
||||
toast.success(response.message)
|
||||
router.push("/admin/users")
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<form className="flex flex-col gap-4" onSubmit={handleSubmit(onSubmit)}>
|
||||
<input type="hidden" {...register("id")} />
|
||||
<UserTextInput
|
||||
error={errors.name?.message}
|
||||
id="name"
|
||||
label="Name"
|
||||
placeholder="Full name"
|
||||
register={register("name")}
|
||||
/>
|
||||
<UserTextInput
|
||||
error={errors.username?.message}
|
||||
id="username"
|
||||
label="Username"
|
||||
placeholder="username"
|
||||
register={register("username")}
|
||||
/>
|
||||
<UserTextInput
|
||||
error={errors.email?.message}
|
||||
id="email"
|
||||
label="Email"
|
||||
placeholder="user@example.com"
|
||||
register={register("email")}
|
||||
type="email"
|
||||
/>
|
||||
<div className="flex flex-col gap-2">
|
||||
<label htmlFor="role" className="mb-2 block text-lg">
|
||||
Role
|
||||
</label>
|
||||
<select
|
||||
id="role"
|
||||
{...register("role")}
|
||||
className="w-full rounded-lg border px-4 py-2"
|
||||
>
|
||||
<option value="ADMIN">Admin</option>
|
||||
<option value="MANAGER">Manager</option>
|
||||
<option value="STAFF">Staff</option>
|
||||
<option value="VIEWER">Viewer</option>
|
||||
</select>
|
||||
</div>
|
||||
<label className="flex items-center gap-2">
|
||||
<input type="checkbox" {...register("isActive")} />
|
||||
Active user
|
||||
</label>
|
||||
<SubmitButton
|
||||
isSubmitting={isSubmitting}
|
||||
isSubmitSuccessful={isSubmitSuccessful}
|
||||
>
|
||||
Update User
|
||||
</SubmitButton>
|
||||
</form>
|
||||
)
|
||||
}
|
||||
|
||||
function UserTextInput({
|
||||
error,
|
||||
id,
|
||||
label,
|
||||
placeholder,
|
||||
register,
|
||||
type = "text",
|
||||
}: {
|
||||
error?: string
|
||||
id: string
|
||||
label: string
|
||||
placeholder: string
|
||||
register: UseFormRegisterReturn
|
||||
type?: string
|
||||
}) {
|
||||
return (
|
||||
<div className="flex flex-col gap-2">
|
||||
<label htmlFor={id} className="mb-2 block text-lg">
|
||||
{label}
|
||||
</label>
|
||||
<input
|
||||
type={type}
|
||||
id={id}
|
||||
placeholder={placeholder}
|
||||
{...register}
|
||||
className={`w-full rounded-lg border px-4 py-2 ${error ? "border-error" : ""}`}
|
||||
/>
|
||||
{error && <p className="text-error">{error}</p>}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
"use client"
|
||||
|
||||
import { zodResolver } from "@hookform/resolvers/zod"
|
||||
import { useRouter } from "next/navigation"
|
||||
import type { UseFormRegisterReturn } from "react-hook-form"
|
||||
import { useForm } from "react-hook-form"
|
||||
import { toast } from "sonner"
|
||||
import { createUserAction } from "@/actions/user.actions"
|
||||
import { SubmitButton } from "@/components/forms/submitButton"
|
||||
import {
|
||||
type CreateUserFormType,
|
||||
createUserSchema,
|
||||
} from "@/schemas/user.schema"
|
||||
|
||||
export default function NewUserForm() {
|
||||
const router = useRouter()
|
||||
const {
|
||||
register,
|
||||
handleSubmit,
|
||||
setError,
|
||||
formState: { errors, isSubmitting, isSubmitSuccessful },
|
||||
} = useForm<CreateUserFormType>({
|
||||
resolver: zodResolver(createUserSchema),
|
||||
defaultValues: {
|
||||
role: "STAFF",
|
||||
isActive: true,
|
||||
},
|
||||
})
|
||||
|
||||
const onSubmit = async (formData: CreateUserFormType) => {
|
||||
const response = await createUserAction(formData)
|
||||
|
||||
if (response?.errors) {
|
||||
Object.entries(response.errors).forEach(([fieldName, messages]) => {
|
||||
messages.forEach((message: string) => {
|
||||
setError(fieldName as keyof CreateUserFormType, {
|
||||
type: "server",
|
||||
message,
|
||||
})
|
||||
toast.error(message)
|
||||
})
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if (response?.success) {
|
||||
toast.success(response.message)
|
||||
router.push("/admin/users")
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<form className="flex flex-col gap-4" onSubmit={handleSubmit(onSubmit)}>
|
||||
<UserTextInput
|
||||
error={errors.name?.message}
|
||||
id="name"
|
||||
label="Name"
|
||||
placeholder="Full name"
|
||||
register={register("name")}
|
||||
/>
|
||||
<UserTextInput
|
||||
error={errors.username?.message}
|
||||
id="username"
|
||||
label="Username"
|
||||
placeholder="username"
|
||||
register={register("username")}
|
||||
/>
|
||||
<UserTextInput
|
||||
error={errors.email?.message}
|
||||
id="email"
|
||||
label="Email"
|
||||
placeholder="user@example.com"
|
||||
register={register("email")}
|
||||
type="email"
|
||||
/>
|
||||
<UserTextInput
|
||||
error={errors.password?.message}
|
||||
id="password"
|
||||
label="Password"
|
||||
placeholder="Minimum 8 characters"
|
||||
register={register("password")}
|
||||
type="password"
|
||||
/>
|
||||
<RoleSelect register={register("role")} />
|
||||
<SubmitButton
|
||||
isSubmitting={isSubmitting}
|
||||
isSubmitSuccessful={isSubmitSuccessful}
|
||||
>
|
||||
Create User
|
||||
</SubmitButton>
|
||||
</form>
|
||||
)
|
||||
}
|
||||
|
||||
function UserTextInput({
|
||||
error,
|
||||
id,
|
||||
label,
|
||||
placeholder,
|
||||
register,
|
||||
type = "text",
|
||||
}: {
|
||||
error?: string
|
||||
id: string
|
||||
label: string
|
||||
placeholder: string
|
||||
register: UseFormRegisterReturn
|
||||
type?: string
|
||||
}) {
|
||||
return (
|
||||
<div className="flex flex-col gap-2">
|
||||
<label htmlFor={id} className="mb-2 block text-lg">
|
||||
{label}
|
||||
</label>
|
||||
<input
|
||||
type={type}
|
||||
id={id}
|
||||
placeholder={placeholder}
|
||||
{...register}
|
||||
className={`w-full rounded-lg border px-4 py-2 ${error ? "border-error" : ""}`}
|
||||
/>
|
||||
{error && <p className="text-error">{error}</p>}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function RoleSelect({ register }: { register: UseFormRegisterReturn }) {
|
||||
return (
|
||||
<div className="flex flex-col gap-2">
|
||||
<label htmlFor="role" className="mb-2 block text-lg">
|
||||
Role
|
||||
</label>
|
||||
<select
|
||||
id="role"
|
||||
{...register}
|
||||
className="w-full rounded-lg border px-4 py-2"
|
||||
>
|
||||
<option value="ADMIN">Admin</option>
|
||||
<option value="MANAGER">Manager</option>
|
||||
<option value="STAFF">Staff</option>
|
||||
<option value="VIEWER">Viewer</option>
|
||||
</select>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
"use client"
|
||||
|
||||
import { zodResolver } from "@hookform/resolvers/zod"
|
||||
import { useForm } from "react-hook-form"
|
||||
import { toast } from "sonner"
|
||||
import { resetUserPasswordAction } from "@/actions/user.actions"
|
||||
import { SubmitButton } from "@/components/forms/submitButton"
|
||||
import {
|
||||
type ResetUserPasswordFormType,
|
||||
resetUserPasswordSchema,
|
||||
} from "@/schemas/user.schema"
|
||||
|
||||
export default function ResetUserPasswordForm({ userId }: { userId: string }) {
|
||||
const {
|
||||
register,
|
||||
handleSubmit,
|
||||
reset,
|
||||
setError,
|
||||
formState: { errors, isSubmitting, isSubmitSuccessful },
|
||||
} = useForm<ResetUserPasswordFormType>({
|
||||
resolver: zodResolver(resetUserPasswordSchema),
|
||||
defaultValues: {
|
||||
id: userId,
|
||||
},
|
||||
})
|
||||
|
||||
const onSubmit = async (formData: ResetUserPasswordFormType) => {
|
||||
const response = await resetUserPasswordAction(formData)
|
||||
|
||||
if (response?.errors) {
|
||||
Object.entries(response.errors).forEach(([fieldName, messages]) => {
|
||||
messages.forEach((message: string) => {
|
||||
setError(fieldName as keyof ResetUserPasswordFormType, {
|
||||
type: "server",
|
||||
message,
|
||||
})
|
||||
toast.error(message)
|
||||
})
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if (response?.success) {
|
||||
toast.success(response.message)
|
||||
reset({ id: userId, password: "" })
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<form className="flex flex-col gap-4" onSubmit={handleSubmit(onSubmit)}>
|
||||
<input type="hidden" {...register("id")} />
|
||||
<div className="flex flex-col gap-2">
|
||||
<label htmlFor="password" className="mb-2 block text-lg">
|
||||
New password
|
||||
</label>
|
||||
<input
|
||||
type="password"
|
||||
id="password"
|
||||
placeholder="Minimum 8 characters"
|
||||
{...register("password")}
|
||||
className={`w-full rounded-lg border px-4 py-2 ${errors.password ? "border-error" : ""}`}
|
||||
/>
|
||||
{errors.password && (
|
||||
<p className="text-error">{errors.password.message}</p>
|
||||
)}
|
||||
</div>
|
||||
<SubmitButton
|
||||
isSubmitting={isSubmitting}
|
||||
isSubmitSuccessful={isSubmitSuccessful}
|
||||
>
|
||||
Reset Password
|
||||
</SubmitButton>
|
||||
</form>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
import NewUserForm from "../_components/new.user.form"
|
||||
|
||||
export default function NewUserPage() {
|
||||
return (
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="flex items-center justify-between gap-4">
|
||||
<h1 className="text-2xl font-bold">New User</h1>
|
||||
</div>
|
||||
<NewUserForm />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
import { Pencil } from "lucide-react"
|
||||
import Link from "next/link"
|
||||
|
||||
import PageHeader from "@/components/common/pageheader"
|
||||
import PaginationButtons from "@/components/common/pagination"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { getUsers } from "@/services/user.service"
|
||||
|
||||
export default async function UsersPage(props: {
|
||||
searchParams?: Promise<{
|
||||
page?: string
|
||||
search?: string
|
||||
}>
|
||||
}) {
|
||||
const searchParams = await props.searchParams
|
||||
const currentPage = searchParams?.page ? parseInt(searchParams.page, 10) : 1
|
||||
const search = searchParams?.search || ""
|
||||
const { data: users, totalPages } = await getUsers({
|
||||
page: currentPage,
|
||||
pageSize: 10,
|
||||
search,
|
||||
})
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-4">
|
||||
<PageHeader
|
||||
title="Users"
|
||||
link="/admin/users/new"
|
||||
search={search}
|
||||
data={users}
|
||||
/>
|
||||
{users.length === 0 && currentPage === 1 && (
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="flex items-center justify-between gap-4">
|
||||
No users found.
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{users.length > 0 && (
|
||||
<div className="overflow-x-auto">
|
||||
<table className="text-muted-foreground w-full text-left text-sm">
|
||||
<thead className="border-b">
|
||||
<tr>
|
||||
<th scope="col" className="p-4">
|
||||
Name
|
||||
</th>
|
||||
<th scope="col" className="p-4">
|
||||
Username
|
||||
</th>
|
||||
<th scope="col" className="p-4">
|
||||
Email
|
||||
</th>
|
||||
<th scope="col" className="p-4">
|
||||
Role
|
||||
</th>
|
||||
<th scope="col" className="p-4">
|
||||
Status
|
||||
</th>
|
||||
<th scope="col" className="p-4">
|
||||
Actions
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{users.map((user) => (
|
||||
<tr key={user.id} className="border-b">
|
||||
<td className="p-4">{user.name}</td>
|
||||
<td className="p-4">{user.username}</td>
|
||||
<td className="p-4">{user.email}</td>
|
||||
<td className="p-4">{user.role}</td>
|
||||
<td className="p-4">
|
||||
{user.isActive ? "Active" : "Inactive"}
|
||||
</td>
|
||||
<td className="p-4">
|
||||
<Link href={`/admin/users/${user.id}/edit`} passHref>
|
||||
<Button variant="outline" size="icon">
|
||||
<Pencil />
|
||||
</Button>
|
||||
</Link>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
<tfoot className="border-t">
|
||||
<tr>
|
||||
<td colSpan={6} className="p-4 text-center text-sm">
|
||||
<PaginationButtons totalPages={totalPages} />
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
+5
-5
@@ -1,18 +1,18 @@
|
||||
import type { UpdateAssignmentFormType } from "@/lib/schemas/assignment.schemas"
|
||||
import type { Item } from "@/lib/types"
|
||||
import type { UpdateAssignmentFormType } from "@/schemas/assignment.schema"
|
||||
import { AssetService } from "@/services/asset.service"
|
||||
import { AssignmentService } from "@/services/assignment.service"
|
||||
import { ItemService } from "@/services/item.service"
|
||||
import { RecipientService } from "@/services/recipient.service"
|
||||
import type { Item } from "@/types"
|
||||
|
||||
import AssignmentForm from "../../_components/edit.assignment.form"
|
||||
export default async function EditAssignmentPage({
|
||||
params,
|
||||
}: {
|
||||
params: Promise<{ assignamentId: string }>
|
||||
params: Promise<{ assignmentId: string }>
|
||||
}) {
|
||||
const { assignamentId } = await params
|
||||
const assignment = await AssignmentService.findById(assignamentId)
|
||||
const { assignmentId } = await params
|
||||
const assignment = await AssignmentService.findById(assignmentId)
|
||||
const recipients = await RecipientService.findAll()
|
||||
const items = await ItemService.findAllWithStock()
|
||||
const assets = await AssetService.findAll()
|
||||
@@ -4,14 +4,13 @@ import { zodResolver } from "@hookform/resolvers/zod"
|
||||
import { useRouter } from "next/navigation"
|
||||
import { useForm } from "react-hook-form"
|
||||
import { toast } from "sonner"
|
||||
|
||||
import { updateAssignment } from "@/actions/assignment.actions"
|
||||
import { SubmitButton } from "@/components/forms/submitButton"
|
||||
import { updateAssignment } from "@/lib/actions/assignament.actions"
|
||||
import {
|
||||
type UpdateAssignmentFormType,
|
||||
updateAssignmentSchema,
|
||||
} from "@/lib/schemas/assignment.schemas"
|
||||
import type { Asset, Item, Recipient } from "@/lib/types"
|
||||
} from "@/schemas/assignment.schema"
|
||||
import type { Asset, Item, Recipient } from "@/types"
|
||||
|
||||
interface Props {
|
||||
recipients: Recipient[]
|
||||
|
||||
@@ -5,14 +5,13 @@ import { useRouter } from "next/navigation"
|
||||
import { useMemo } from "react"
|
||||
import { useForm } from "react-hook-form"
|
||||
import { toast } from "sonner"
|
||||
|
||||
import { createAssignment } from "@/actions/assignment.actions"
|
||||
import { SubmitButton } from "@/components/forms/submitButton"
|
||||
import { createAssignment } from "@/lib/actions/assignament.actions"
|
||||
import {
|
||||
type CreateAssignmentFormType,
|
||||
createAssignmentSchema,
|
||||
} from "@/lib/schemas/assignment.schemas"
|
||||
import type { Asset, Item, Recipient } from "@/lib/types"
|
||||
} from "@/schemas/assignment.schema"
|
||||
import type { Asset, Item, Recipient } from "@/types"
|
||||
|
||||
interface Props {
|
||||
recipients: Recipient[]
|
||||
|
||||
@@ -4,10 +4,9 @@ import { ArrowLeft } from "lucide-react"
|
||||
import { useRouter } from "next/navigation"
|
||||
import { useTransition } from "react"
|
||||
import { toast } from "sonner"
|
||||
|
||||
import { returnAssignment } from "@/actions/assignment.actions"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { returnAssignment } from "@/lib/actions/assignament.actions"
|
||||
import type { ReturnAssignmentFormType } from "@/lib/schemas/assignment.schemas"
|
||||
import type { ReturnAssignmentFormType } from "@/schemas/assignment.schema"
|
||||
|
||||
export default function ReturnButton({
|
||||
assignmentId,
|
||||
|
||||
@@ -46,6 +46,9 @@ export default async function AssignmentsPage(props: {
|
||||
<th scope="col" className="p-4">
|
||||
Serial Number
|
||||
</th>
|
||||
<th scope="col" className="p-4">
|
||||
Quantity
|
||||
</th>
|
||||
<th scope="col" className="p-4">
|
||||
Actions
|
||||
</th>
|
||||
@@ -74,6 +77,9 @@ export default async function AssignmentsPage(props: {
|
||||
<td className="p-4">
|
||||
{assignment?.asset?.serialNumber || "N/A"}
|
||||
</td>
|
||||
<td className="p-4">
|
||||
{assignment?.quantity}
|
||||
</td>
|
||||
<td className="p-4">
|
||||
<div className="flex gap-2">
|
||||
<Link
|
||||
@@ -92,7 +98,7 @@ export default async function AssignmentsPage(props: {
|
||||
</tbody>
|
||||
<tfoot className="border-t">
|
||||
<tr>
|
||||
<td colSpan={4} className="p-4 text-center text-sm">
|
||||
<td colSpan={5} className="p-4 text-center text-sm">
|
||||
<PaginationButtons totalPages={totalPages} />
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -5,11 +5,10 @@ import { useRouter } from "next/navigation"
|
||||
import type { ChangeEvent } from "react"
|
||||
import { useForm } from "react-hook-form"
|
||||
import { toast } from "sonner"
|
||||
|
||||
import { importItems } from "@/actions/import.actions"
|
||||
import { SubmitButton } from "@/components/forms/submitButton"
|
||||
import { importItems } from "@/lib/actions/import.actions"
|
||||
import { type ImportFormType, importSchema } from "@/lib/schemas/import.schemas"
|
||||
import type { CategorySummary } from "@/lib/types"
|
||||
import { type ImportFormType, importSchema } from "@/schemas/import.schema"
|
||||
import type { CategorySummary } from "@/types"
|
||||
|
||||
export default function ImportForm({
|
||||
categories,
|
||||
|
||||
@@ -15,7 +15,7 @@ export default async function ImportPage() {
|
||||
<h1 className="text-2xl font-bold">Mass Import</h1>
|
||||
</div>
|
||||
<div className="flex items-center justify-end gap-4">
|
||||
{ENVIRONMENT === "demo" && (
|
||||
{(ENVIRONMENT === "development" || ENVIRONMENT === "demo") && (
|
||||
<Link href="/sample_data.csv" download>
|
||||
<Button variant="outline">
|
||||
<Download />
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
"use server"
|
||||
|
||||
import type { AssetWithAssignment } from "@/lib/types"
|
||||
import { AssetService } from "@/services/asset.service"
|
||||
import { ItemService } from "@/services/item.service"
|
||||
import { RecipientService } from "@/services/recipient.service"
|
||||
import type { AssetWithAssignment } from "@/types"
|
||||
|
||||
import EditAssetForm from "../../_components/edit.asset.form"
|
||||
|
||||
|
||||
@@ -4,20 +4,19 @@ import { zodResolver } from "@hookform/resolvers/zod"
|
||||
import { useRouter } from "next/navigation"
|
||||
import { useForm } from "react-hook-form"
|
||||
import { toast } from "sonner"
|
||||
|
||||
import { updateAssetAction } from "@/actions/asset.actions"
|
||||
import { SubmitButton } from "@/components/forms/submitButton"
|
||||
import { ItemStatus } from "@/generated/prisma/client"
|
||||
import { updateAssetAction } from "@/lib/actions/asset.actions"
|
||||
import { ITEM_STATUS } from "@/lib/constants"
|
||||
import {
|
||||
type UpdateAssetFormType,
|
||||
updateAssetSchema,
|
||||
} from "@/lib/schemas/asset.schemas"
|
||||
} from "@/schemas/asset.schema"
|
||||
import type {
|
||||
AssetWithAssignment,
|
||||
Item,
|
||||
Recipient,
|
||||
UpdateAssetStatus,
|
||||
} from "@/lib/types"
|
||||
} from "@/types"
|
||||
|
||||
interface EditAssetFormProps {
|
||||
asset: AssetWithAssignment
|
||||
@@ -42,11 +41,11 @@ export default function EditAssetForm({
|
||||
resolver: zodResolver(updateAssetSchema),
|
||||
defaultValues: {
|
||||
id: asset.id,
|
||||
itemId: asset.itemId ?? "",
|
||||
itemId: asset.itemId ?? undefined,
|
||||
serialNumber: asset.serialNumber,
|
||||
deliveryNote: asset.deliveryNote ?? "",
|
||||
deliveryNote: asset.deliveryNote ?? undefined,
|
||||
status: asset.status as UpdateAssetStatus,
|
||||
recipientId: asset.assignment?.recipientId ?? "",
|
||||
recipientId: asset.assignment?.recipientId ?? undefined,
|
||||
},
|
||||
shouldFocusError: true,
|
||||
mode: "onSubmit",
|
||||
@@ -138,7 +137,7 @@ export default function EditAssetForm({
|
||||
className="w-full rounded-lg border px-4 py-2"
|
||||
>
|
||||
<option value="">Select a status</option>
|
||||
{Object.values(ItemStatus).map((status) => (
|
||||
{Object.values(ITEM_STATUS).map((status) => (
|
||||
<option key={status} value={status}>
|
||||
{status}
|
||||
</option>
|
||||
|
||||
@@ -4,15 +4,14 @@ import { zodResolver } from "@hookform/resolvers/zod"
|
||||
import { useRouter } from "next/navigation"
|
||||
import { useForm } from "react-hook-form"
|
||||
import { toast } from "sonner"
|
||||
|
||||
import { createAssetAction } from "@/actions/asset.actions"
|
||||
import { SubmitButton } from "@/components/forms/submitButton"
|
||||
import { ItemStatus } from "@/generated/prisma/client"
|
||||
import { createAssetAction } from "@/lib/actions/asset.actions"
|
||||
import { ITEM_STATUS } from "@/lib/constants"
|
||||
import {
|
||||
type CreateAssetFormType,
|
||||
createAssetSchema,
|
||||
} from "@/lib/schemas/asset.schemas"
|
||||
import type { ItemWithoutStock, Recipient } from "@/lib/types"
|
||||
} from "@/schemas/asset.schema"
|
||||
import type { ItemWithoutStock, Recipient } from "@/types"
|
||||
|
||||
interface NewAssetFormProps {
|
||||
items: ItemWithoutStock[]
|
||||
@@ -123,7 +122,7 @@ export default function NewAssetForm({ items, recipients }: NewAssetFormProps) {
|
||||
className="w-full rounded-lg border px-4 py-2"
|
||||
>
|
||||
<option value="">Select a status</option>
|
||||
{Object.values(ItemStatus).map((status) => (
|
||||
{Object.values(ITEM_STATUS).map((status) => (
|
||||
<option key={status} value={status}>
|
||||
{status}
|
||||
</option>
|
||||
|
||||
@@ -4,9 +4,8 @@ import { Trash } from "lucide-react"
|
||||
import { useRouter } from "next/navigation"
|
||||
import { useTransition } from "react"
|
||||
import { toast } from "sonner"
|
||||
|
||||
import { deleteCategoryAction } from "@/actions/category.actions"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { deleteCategoryAction } from "@/lib/actions/category.actions"
|
||||
|
||||
export default function DeleteCategoryButton({
|
||||
categoryId,
|
||||
|
||||
@@ -4,14 +4,13 @@ import { zodResolver } from "@hookform/resolvers/zod"
|
||||
import { useRouter } from "next/navigation"
|
||||
import { useForm } from "react-hook-form"
|
||||
import { toast } from "sonner"
|
||||
|
||||
import { updateCategoryAction } from "@/actions/category.actions"
|
||||
import { SubmitButton } from "@/components/forms/submitButton"
|
||||
import { updateCategoryAction } from "@/lib/actions/category.actions"
|
||||
import {
|
||||
type UpdateCategoryFormType,
|
||||
updateCategorySchema,
|
||||
} from "@/lib/schemas/category.schemas"
|
||||
import type { CategorySummary } from "@/lib/types"
|
||||
} from "@/schemas/category.schema"
|
||||
import type { CategorySummary } from "@/types"
|
||||
|
||||
export default function EditCategoryForm({
|
||||
category,
|
||||
|
||||
@@ -4,13 +4,12 @@ import { zodResolver } from "@hookform/resolvers/zod"
|
||||
import { useRouter } from "next/navigation"
|
||||
import { useForm } from "react-hook-form"
|
||||
import { toast } from "sonner"
|
||||
|
||||
import { createCategoryAction } from "@/actions/category.actions"
|
||||
import { SubmitButton } from "@/components/forms/submitButton"
|
||||
import { createCategoryAction } from "@/lib/actions/category.actions"
|
||||
import {
|
||||
type CreateCategoryFormType,
|
||||
createCategorySchema,
|
||||
} from "@/lib/schemas/category.schemas"
|
||||
} from "@/schemas/category.schema"
|
||||
|
||||
export default function NewCategoryForm() {
|
||||
const router = useRouter()
|
||||
|
||||
@@ -4,9 +4,8 @@ import { Trash } from "lucide-react"
|
||||
import { useRouter } from "next/navigation"
|
||||
import { useTransition } from "react"
|
||||
import { toast } from "sonner"
|
||||
|
||||
import { deleteItemAction } from "@/actions/item.actions"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { deleteItemAction } from "@/lib/actions/item.actions"
|
||||
|
||||
export default function DeleteItemButton({ itemId }: { itemId: string }) {
|
||||
const router = useRouter()
|
||||
|
||||
@@ -4,14 +4,13 @@ import { zodResolver } from "@hookform/resolvers/zod"
|
||||
import { useRouter } from "next/navigation"
|
||||
import { useForm } from "react-hook-form"
|
||||
import { toast } from "sonner"
|
||||
|
||||
import { createItemAction } from "@/actions/item.actions"
|
||||
import { SubmitButton } from "@/components/forms/submitButton"
|
||||
import { createItemAction } from "@/lib/actions/item.actions"
|
||||
import {
|
||||
type CreateItemFormType,
|
||||
createItemSchema,
|
||||
} from "@/lib/schemas/item.schemas"
|
||||
import type { CategorySummary } from "@/lib/types"
|
||||
} from "@/schemas/item.schema"
|
||||
import type { CategorySummary } from "@/types"
|
||||
|
||||
export default function NewItemForm({
|
||||
categories,
|
||||
|
||||
@@ -4,14 +4,13 @@ import { zodResolver } from "@hookform/resolvers/zod"
|
||||
import { useRouter } from "next/navigation"
|
||||
import { useForm } from "react-hook-form"
|
||||
import { toast } from "sonner"
|
||||
|
||||
import { updateItemAction } from "@/actions/item.actions"
|
||||
import { SubmitButton } from "@/components/forms/submitButton"
|
||||
import { updateItemAction } from "@/lib/actions/item.actions"
|
||||
import {
|
||||
type UpdateItemFormType,
|
||||
updateItemSchema,
|
||||
} from "@/lib/schemas/item.schemas"
|
||||
import type { CategorySummary, ItemWithAssetCount } from "@/lib/types"
|
||||
} from "@/schemas/item.schema"
|
||||
import type { CategorySummary, ItemWithAssetCount } from "@/types"
|
||||
|
||||
export default function UpdateItemForm({
|
||||
categories,
|
||||
|
||||
@@ -3,15 +3,18 @@ import { Toaster } from "sonner"
|
||||
import Navbar from "@/components/layout/navbar"
|
||||
import AppSidebar from "@/components/layout/sidebar"
|
||||
import { SidebarProvider } from "@/components/ui/sidebar"
|
||||
import { auth } from "@/lib/auth"
|
||||
|
||||
export default async function LayoutDashboard({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode
|
||||
}) {
|
||||
const session = await auth()
|
||||
|
||||
return (
|
||||
<SidebarProvider>
|
||||
<AppSidebar />
|
||||
<AppSidebar userRole={session?.user.role} />
|
||||
<main className="w-full">
|
||||
<Navbar />
|
||||
<div className="flex-1 p-6">{children}</div>
|
||||
|
||||
@@ -4,19 +4,18 @@ import { zodResolver } from "@hookform/resolvers/zod"
|
||||
import { useRouter } from "next/navigation"
|
||||
import { useForm } from "react-hook-form"
|
||||
import { toast } from "sonner"
|
||||
|
||||
import { SubmitButton } from "@/components/forms/submitButton"
|
||||
import { RecipientDepartment } from "@/generated/prisma/client"
|
||||
import {
|
||||
createNewRecipient,
|
||||
updateRecipient,
|
||||
} from "@/lib/actions/recipient.actions"
|
||||
} from "@/actions/recipient.actions"
|
||||
import { SubmitButton } from "@/components/forms/submitButton"
|
||||
import { RECIPIENT_DEPARTMENTS } from "@/lib/constants"
|
||||
import {
|
||||
type CreateRecipientFormType,
|
||||
recipientSchema,
|
||||
type UpdateRecipientFormType,
|
||||
} from "@/lib/schemas/recipients.schemas"
|
||||
import type { Recipient } from "@/lib/types"
|
||||
} from "@/schemas/recipient.schema"
|
||||
import type { Recipient } from "@/types"
|
||||
|
||||
interface RecipientFormProps {
|
||||
initialData?: Recipient
|
||||
@@ -130,7 +129,7 @@ export default function RecipientForm({
|
||||
className="w-full rounded-lg border px-4 py-2"
|
||||
>
|
||||
<option value="">Select a department</option>
|
||||
{Object.keys(RecipientDepartment).map((department) => (
|
||||
{Object.keys(RECIPIENT_DEPARTMENTS).map((department) => (
|
||||
<option key={department} value={department}>
|
||||
{department}
|
||||
</option>
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
import Link from "next/link"
|
||||
|
||||
export default function ForbiddenPage() {
|
||||
return (
|
||||
<main>
|
||||
<h1>Acceso denegado</h1>
|
||||
<p>No tienes permisos para acceder a esta sección.</p>
|
||||
<Link href="/">Volver al inicio</Link>
|
||||
</main>
|
||||
)
|
||||
}
|
||||
@@ -5,12 +5,12 @@ import {
|
||||
Clipboard,
|
||||
Home,
|
||||
Package,
|
||||
Shield,
|
||||
ShoppingCart,
|
||||
User,
|
||||
} from "lucide-react"
|
||||
import Link from "next/link"
|
||||
import { usePathname } from "next/navigation"
|
||||
|
||||
import {
|
||||
Sidebar,
|
||||
SidebarContent,
|
||||
@@ -21,6 +21,7 @@ import {
|
||||
SidebarMenuButton,
|
||||
SidebarMenuItem,
|
||||
} from "@/components/ui/sidebar"
|
||||
import type { UserRole } from "@/generated/prisma/client"
|
||||
|
||||
import { SidebarSection } from "./sidebar/sidebarSection"
|
||||
|
||||
@@ -72,9 +73,22 @@ const items = [
|
||||
]
|
||||
|
||||
export default function AppSidebar({
|
||||
userRole,
|
||||
...props
|
||||
}: React.ComponentProps<typeof Sidebar>) {
|
||||
}: React.ComponentProps<typeof Sidebar> & { userRole?: UserRole }) {
|
||||
const pathname = usePathname()
|
||||
const visibleItems =
|
||||
userRole === "ADMIN"
|
||||
? [
|
||||
...items,
|
||||
{
|
||||
type: "item",
|
||||
title: "Users",
|
||||
url: "/admin/users",
|
||||
icon: Shield,
|
||||
},
|
||||
]
|
||||
: items
|
||||
|
||||
return (
|
||||
<Sidebar {...props}>
|
||||
@@ -88,7 +102,7 @@ export default function AppSidebar({
|
||||
<SidebarGroup>
|
||||
<SidebarGroupContent>
|
||||
<SidebarMenu>
|
||||
{items.map((item) => {
|
||||
{visibleItems.map((item) => {
|
||||
if (item.type === "item") {
|
||||
const isActive =
|
||||
item.url === "/"
|
||||
@@ -96,7 +110,7 @@ export default function AppSidebar({
|
||||
: pathname.startsWith(item.url)
|
||||
|
||||
return (
|
||||
<SidebarMenuItem key={`item-${item}`}>
|
||||
<SidebarMenuItem key={`item-${item.title}`}>
|
||||
<SidebarMenuButton asChild isActive={isActive}>
|
||||
<Link href={item.url}>
|
||||
<item.icon className="mr-2 h-4 w-4" />
|
||||
@@ -109,7 +123,7 @@ export default function AppSidebar({
|
||||
if (item.type === "section") {
|
||||
return (
|
||||
<SidebarSection
|
||||
key={`section-${item}`}
|
||||
key={`section-${item.title}`}
|
||||
title={item.title}
|
||||
icon={item.icon}
|
||||
items={item.items}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import * as React from "react"
|
||||
import { cva, type VariantProps } from "class-variance-authority"
|
||||
import { Slot } from "radix-ui"
|
||||
import type * as React from "react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
@@ -35,7 +35,7 @@ const buttonVariants = cva(
|
||||
variant: "default",
|
||||
size: "default",
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
function Button({
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type * as React from "react"
|
||||
import * as React from "react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client"
|
||||
|
||||
import type * as React from "react"
|
||||
import * as React from "react"
|
||||
import { CheckIcon } from "lucide-react"
|
||||
import { Checkbox as CheckboxPrimitive } from "radix-ui"
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client"
|
||||
|
||||
import type * as React from "react"
|
||||
import * as React from "react"
|
||||
import { XIcon } from "lucide-react"
|
||||
import { Dialog as DialogPrimitive } from "radix-ui"
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client"
|
||||
|
||||
import type * as React from "react"
|
||||
import * as React from "react"
|
||||
import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react"
|
||||
import { DropdownMenu as DropdownMenuPrimitive } from "radix-ui"
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type * as React from "react"
|
||||
import * as React from "react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type * as React from "react"
|
||||
import * as React from "react"
|
||||
import {
|
||||
ChevronLeftIcon,
|
||||
ChevronRightIcon,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client"
|
||||
|
||||
import type * as React from "react"
|
||||
import * as React from "react"
|
||||
import { Separator as SeparatorPrimitive } from "radix-ui"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client"
|
||||
|
||||
import type * as React from "react"
|
||||
import * as React from "react"
|
||||
import { XIcon } from "lucide-react"
|
||||
import { Dialog as SheetPrimitive } from "radix-ui"
|
||||
|
||||
|
||||
@@ -480,7 +480,7 @@ const sidebarMenuButtonVariants = cva(
|
||||
variant: {
|
||||
default: "hover:bg-sidebar-accent hover:text-sidebar-accent-foreground",
|
||||
outline:
|
||||
"bg-background shadow-[0_0_0_1px_hsl(var(--sidebar-border))] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground hover:shadow-[0_0_0_1px_hsl(var(--sidebar-accent))]",
|
||||
"bg-background shadow-[0_0_0_1px_var(--sidebar-border)] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground hover:shadow-[0_0_0_1px_var(--sidebar-accent)]",
|
||||
},
|
||||
size: {
|
||||
default: "h-8 text-sm",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client"
|
||||
|
||||
import type * as React from "react"
|
||||
import * as React from "react"
|
||||
import { Tooltip as TooltipPrimitive } from "radix-ui"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
-1
@@ -1 +0,0 @@
|
||||
export * from "./index"
|
||||
@@ -1,4 +0,0 @@
|
||||
|
||||
/* !!! This is code generated by Prisma. Do not edit directly. !!!
|
||||
/* eslint-disable */
|
||||
module.exports = { ...require('.') }
|
||||
-1
@@ -1 +0,0 @@
|
||||
export * from "./index"
|
||||
@@ -1,4 +0,0 @@
|
||||
|
||||
/* !!! This is code generated by Prisma. Do not edit directly. !!!
|
||||
/* eslint-disable */
|
||||
module.exports = { ...require('.') }
|
||||
-1
@@ -1 +0,0 @@
|
||||
export * from "./default"
|
||||
File diff suppressed because one or more lines are too long
@@ -1,301 +0,0 @@
|
||||
|
||||
/* !!! This is code generated by Prisma. Do not edit directly. !!!
|
||||
/* eslint-disable */
|
||||
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
|
||||
const {
|
||||
Decimal,
|
||||
objectEnumValues,
|
||||
makeStrictEnum,
|
||||
Public,
|
||||
getRuntime,
|
||||
skip
|
||||
} = require('./runtime/index-browser.js')
|
||||
|
||||
|
||||
const Prisma = {}
|
||||
|
||||
exports.Prisma = Prisma
|
||||
exports.$Enums = {}
|
||||
|
||||
/**
|
||||
* Prisma Client JS version: 6.10.1
|
||||
* Query Engine version: 9b628578b3b7cae625e8c927178f15a170e74a9c
|
||||
*/
|
||||
Prisma.prismaVersion = {
|
||||
client: "6.10.1",
|
||||
engine: "9b628578b3b7cae625e8c927178f15a170e74a9c"
|
||||
}
|
||||
|
||||
Prisma.PrismaClientKnownRequestError = () => {
|
||||
const runtimeName = getRuntime().prettyName;
|
||||
throw new Error(`PrismaClientKnownRequestError is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
|
||||
In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
|
||||
)};
|
||||
Prisma.PrismaClientUnknownRequestError = () => {
|
||||
const runtimeName = getRuntime().prettyName;
|
||||
throw new Error(`PrismaClientUnknownRequestError is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
|
||||
In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
|
||||
)}
|
||||
Prisma.PrismaClientRustPanicError = () => {
|
||||
const runtimeName = getRuntime().prettyName;
|
||||
throw new Error(`PrismaClientRustPanicError is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
|
||||
In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
|
||||
)}
|
||||
Prisma.PrismaClientInitializationError = () => {
|
||||
const runtimeName = getRuntime().prettyName;
|
||||
throw new Error(`PrismaClientInitializationError is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
|
||||
In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
|
||||
)}
|
||||
Prisma.PrismaClientValidationError = () => {
|
||||
const runtimeName = getRuntime().prettyName;
|
||||
throw new Error(`PrismaClientValidationError is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
|
||||
In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
|
||||
)}
|
||||
Prisma.Decimal = Decimal
|
||||
|
||||
/**
|
||||
* Re-export of sql-template-tag
|
||||
*/
|
||||
Prisma.sql = () => {
|
||||
const runtimeName = getRuntime().prettyName;
|
||||
throw new Error(`sqltag is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
|
||||
In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
|
||||
)}
|
||||
Prisma.empty = () => {
|
||||
const runtimeName = getRuntime().prettyName;
|
||||
throw new Error(`empty is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
|
||||
In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
|
||||
)}
|
||||
Prisma.join = () => {
|
||||
const runtimeName = getRuntime().prettyName;
|
||||
throw new Error(`join is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
|
||||
In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
|
||||
)}
|
||||
Prisma.raw = () => {
|
||||
const runtimeName = getRuntime().prettyName;
|
||||
throw new Error(`raw is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
|
||||
In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
|
||||
)}
|
||||
Prisma.validator = Public.validator
|
||||
|
||||
/**
|
||||
* Extensions
|
||||
*/
|
||||
Prisma.getExtensionContext = () => {
|
||||
const runtimeName = getRuntime().prettyName;
|
||||
throw new Error(`Extensions.getExtensionContext is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
|
||||
In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
|
||||
)}
|
||||
Prisma.defineExtension = () => {
|
||||
const runtimeName = getRuntime().prettyName;
|
||||
throw new Error(`Extensions.defineExtension is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
|
||||
In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
|
||||
)}
|
||||
|
||||
/**
|
||||
* Shorthand utilities for JSON filtering
|
||||
*/
|
||||
Prisma.DbNull = objectEnumValues.instances.DbNull
|
||||
Prisma.JsonNull = objectEnumValues.instances.JsonNull
|
||||
Prisma.AnyNull = objectEnumValues.instances.AnyNull
|
||||
|
||||
Prisma.NullTypes = {
|
||||
DbNull: objectEnumValues.classes.DbNull,
|
||||
JsonNull: objectEnumValues.classes.JsonNull,
|
||||
AnyNull: objectEnumValues.classes.AnyNull
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Enums
|
||||
*/
|
||||
|
||||
exports.Prisma.TransactionIsolationLevel = makeStrictEnum({
|
||||
ReadUncommitted: 'ReadUncommitted',
|
||||
ReadCommitted: 'ReadCommitted',
|
||||
RepeatableRead: 'RepeatableRead',
|
||||
Serializable: 'Serializable'
|
||||
});
|
||||
|
||||
exports.Prisma.UserScalarFieldEnum = {
|
||||
id: 'id',
|
||||
username: 'username',
|
||||
name: 'name',
|
||||
email: 'email',
|
||||
password: 'password',
|
||||
role: 'role',
|
||||
isActive: 'isActive',
|
||||
createdAt: 'createdAt',
|
||||
updatedAt: 'updatedAt'
|
||||
};
|
||||
|
||||
exports.Prisma.RecipientScalarFieldEnum = {
|
||||
id: 'id',
|
||||
username: 'username',
|
||||
firstName: 'firstName',
|
||||
lastName: 'lastName',
|
||||
department: 'department',
|
||||
email: 'email',
|
||||
phone: 'phone',
|
||||
isActive: 'isActive',
|
||||
createdAt: 'createdAt',
|
||||
updatedAt: 'updatedAt'
|
||||
};
|
||||
|
||||
exports.Prisma.CategoryScalarFieldEnum = {
|
||||
id: 'id',
|
||||
name: 'name',
|
||||
description: 'description',
|
||||
isActive: 'isActive',
|
||||
createdAt: 'createdAt',
|
||||
updatedAt: 'updatedAt'
|
||||
};
|
||||
|
||||
exports.Prisma.ItemScalarFieldEnum = {
|
||||
id: 'id',
|
||||
name: 'name',
|
||||
description: 'description',
|
||||
categoryId: 'categoryId',
|
||||
stock: 'stock',
|
||||
minStock: 'minStock',
|
||||
maxStock: 'maxStock',
|
||||
createdAt: 'createdAt',
|
||||
updatedAt: 'updatedAt',
|
||||
deletedAt: 'deletedAt'
|
||||
};
|
||||
|
||||
exports.Prisma.AssetScalarFieldEnum = {
|
||||
id: 'id',
|
||||
itemId: 'itemId',
|
||||
serialNumber: 'serialNumber',
|
||||
deliveryNote: 'deliveryNote',
|
||||
status: 'status',
|
||||
notes: 'notes',
|
||||
createdAt: 'createdAt',
|
||||
updatedAt: 'updatedAt'
|
||||
};
|
||||
|
||||
exports.Prisma.AssignmentScalarFieldEnum = {
|
||||
id: 'id',
|
||||
quantity: 'quantity',
|
||||
notes: 'notes',
|
||||
itemId: 'itemId',
|
||||
assetId: 'assetId',
|
||||
recipientId: 'recipientId',
|
||||
assignmentDate: 'assignmentDate',
|
||||
returnDate: 'returnDate',
|
||||
createdBy: 'createdBy',
|
||||
createdAt: 'createdAt',
|
||||
updatedAt: 'updatedAt'
|
||||
};
|
||||
|
||||
exports.Prisma.MovementScalarFieldEnum = {
|
||||
id: 'id',
|
||||
type: 'type',
|
||||
quantity: 'quantity',
|
||||
details: 'details',
|
||||
notes: 'notes',
|
||||
itemId: 'itemId',
|
||||
assetId: 'assetId',
|
||||
previousStock: 'previousStock',
|
||||
newStock: 'newStock',
|
||||
recipientId: 'recipientId',
|
||||
assignmentId: 'assignmentId',
|
||||
userId: 'userId',
|
||||
createdAt: 'createdAt'
|
||||
};
|
||||
|
||||
exports.Prisma.SortOrder = {
|
||||
asc: 'asc',
|
||||
desc: 'desc'
|
||||
};
|
||||
|
||||
exports.Prisma.QueryMode = {
|
||||
default: 'default',
|
||||
insensitive: 'insensitive'
|
||||
};
|
||||
|
||||
exports.Prisma.NullsOrder = {
|
||||
first: 'first',
|
||||
last: 'last'
|
||||
};
|
||||
exports.UserRole = exports.$Enums.UserRole = {
|
||||
ADMIN: 'ADMIN',
|
||||
MANAGER: 'MANAGER',
|
||||
STAFF: 'STAFF',
|
||||
VIEWER: 'VIEWER'
|
||||
};
|
||||
|
||||
exports.RecipientDepartment = exports.$Enums.RecipientDepartment = {
|
||||
IT: 'IT',
|
||||
ENGINEERING: 'ENGINEERING',
|
||||
LOGISTICS: 'LOGISTICS',
|
||||
TRAFFIC: 'TRAFFIC',
|
||||
DRIVER: 'DRIVER',
|
||||
ADMINISTRATION: 'ADMINISTRATION',
|
||||
SALES: 'SALES',
|
||||
OTHER: 'OTHER'
|
||||
};
|
||||
|
||||
exports.ItemStatus = exports.$Enums.ItemStatus = {
|
||||
AVAILABLE: 'AVAILABLE',
|
||||
ASSIGNED: 'ASSIGNED',
|
||||
RESERVED: 'RESERVED',
|
||||
IN_REPAIR: 'IN_REPAIR',
|
||||
BROKEN: 'BROKEN',
|
||||
STOLEN: 'STOLEN',
|
||||
DISPOSED: 'DISPOSED'
|
||||
};
|
||||
|
||||
exports.MovementType = exports.$Enums.MovementType = {
|
||||
IN: 'IN',
|
||||
OUT: 'OUT',
|
||||
ASSIGNMENT: 'ASSIGNMENT',
|
||||
RETURN: 'RETURN',
|
||||
ADJUSTMENT: 'ADJUSTMENT',
|
||||
DELETED: 'DELETED'
|
||||
};
|
||||
|
||||
exports.Prisma.ModelName = {
|
||||
User: 'User',
|
||||
Recipient: 'Recipient',
|
||||
Category: 'Category',
|
||||
Item: 'Item',
|
||||
Asset: 'Asset',
|
||||
Assignment: 'Assignment',
|
||||
Movement: 'Movement'
|
||||
};
|
||||
|
||||
/**
|
||||
* This is a stub Prisma Client that will error at runtime if called.
|
||||
*/
|
||||
class PrismaClient {
|
||||
constructor() {
|
||||
return new Proxy(this, {
|
||||
get(target, prop) {
|
||||
let message
|
||||
const runtime = getRuntime()
|
||||
if (runtime.isEdge) {
|
||||
message = `PrismaClient is not configured to run in ${runtime.prettyName}. In order to run Prisma Client on edge runtime, either:
|
||||
- Use Prisma Accelerate: https://pris.ly/d/accelerate
|
||||
- Use Driver Adapters: https://pris.ly/d/driver-adapters
|
||||
`;
|
||||
} else {
|
||||
message = 'PrismaClient is unable to run in this browser environment, or has been bundled for the browser (running in `' + runtime.prettyName + '`).'
|
||||
}
|
||||
|
||||
message += `
|
||||
If this is unexpected, please open an issue: https://pris.ly/prisma-prisma-bug-report`
|
||||
|
||||
throw new Error(message)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
exports.PrismaClient = PrismaClient
|
||||
|
||||
Object.assign(exports, Prisma)
|
||||
-15222
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
@@ -1,146 +0,0 @@
|
||||
{
|
||||
"name": "prisma-client-8fa07f1ca1555b6abbe80c6f50fa3e992025f58ff8812e13aca6a56a4a773a8c",
|
||||
"main": "index.js",
|
||||
"types": "index.d.ts",
|
||||
"browser": "index-browser.js",
|
||||
"exports": {
|
||||
"./client": {
|
||||
"require": {
|
||||
"node": "./index.js",
|
||||
"edge-light": "./wasm.js",
|
||||
"workerd": "./wasm.js",
|
||||
"worker": "./wasm.js",
|
||||
"browser": "./index-browser.js",
|
||||
"default": "./index.js"
|
||||
},
|
||||
"import": {
|
||||
"node": "./index.js",
|
||||
"edge-light": "./wasm.js",
|
||||
"workerd": "./wasm.js",
|
||||
"worker": "./wasm.js",
|
||||
"browser": "./index-browser.js",
|
||||
"default": "./index.js"
|
||||
},
|
||||
"default": "./index.js"
|
||||
},
|
||||
"./package.json": "./package.json",
|
||||
".": {
|
||||
"require": {
|
||||
"node": "./index.js",
|
||||
"edge-light": "./wasm.js",
|
||||
"workerd": "./wasm.js",
|
||||
"worker": "./wasm.js",
|
||||
"browser": "./index-browser.js",
|
||||
"default": "./index.js"
|
||||
},
|
||||
"import": {
|
||||
"node": "./index.js",
|
||||
"edge-light": "./wasm.js",
|
||||
"workerd": "./wasm.js",
|
||||
"worker": "./wasm.js",
|
||||
"browser": "./index-browser.js",
|
||||
"default": "./index.js"
|
||||
},
|
||||
"default": "./index.js"
|
||||
},
|
||||
"./edge": {
|
||||
"types": "./edge.d.ts",
|
||||
"require": "./edge.js",
|
||||
"import": "./edge.js",
|
||||
"default": "./edge.js"
|
||||
},
|
||||
"./react-native": {
|
||||
"types": "./react-native.d.ts",
|
||||
"require": "./react-native.js",
|
||||
"import": "./react-native.js",
|
||||
"default": "./react-native.js"
|
||||
},
|
||||
"./extension": {
|
||||
"types": "./extension.d.ts",
|
||||
"require": "./extension.js",
|
||||
"import": "./extension.js",
|
||||
"default": "./extension.js"
|
||||
},
|
||||
"./index-browser": {
|
||||
"types": "./index.d.ts",
|
||||
"require": "./index-browser.js",
|
||||
"import": "./index-browser.js",
|
||||
"default": "./index-browser.js"
|
||||
},
|
||||
"./index": {
|
||||
"types": "./index.d.ts",
|
||||
"require": "./index.js",
|
||||
"import": "./index.js",
|
||||
"default": "./index.js"
|
||||
},
|
||||
"./wasm": {
|
||||
"types": "./wasm.d.ts",
|
||||
"require": "./wasm.js",
|
||||
"import": "./wasm.mjs",
|
||||
"default": "./wasm.mjs"
|
||||
},
|
||||
"./runtime/client": {
|
||||
"types": "./runtime/client.d.ts",
|
||||
"require": "./runtime/client.js",
|
||||
"import": "./runtime/client.mjs",
|
||||
"default": "./runtime/client.mjs"
|
||||
},
|
||||
"./runtime/library": {
|
||||
"types": "./runtime/library.d.ts",
|
||||
"require": "./runtime/library.js",
|
||||
"import": "./runtime/library.mjs",
|
||||
"default": "./runtime/library.mjs"
|
||||
},
|
||||
"./runtime/binary": {
|
||||
"types": "./runtime/binary.d.ts",
|
||||
"require": "./runtime/binary.js",
|
||||
"import": "./runtime/binary.mjs",
|
||||
"default": "./runtime/binary.mjs"
|
||||
},
|
||||
"./runtime/wasm-engine-edge": {
|
||||
"types": "./runtime/wasm-engine-edge.d.ts",
|
||||
"require": "./runtime/wasm-engine-edge.js",
|
||||
"import": "./runtime/wasm-engine-edge.mjs",
|
||||
"default": "./runtime/wasm-engine-edge.mjs"
|
||||
},
|
||||
"./runtime/wasm-compiler-edge": {
|
||||
"types": "./runtime/wasm-compiler-edge.d.ts",
|
||||
"require": "./runtime/wasm-compiler-edge.js",
|
||||
"import": "./runtime/wasm-compiler-edge.mjs",
|
||||
"default": "./runtime/wasm-compiler-edge.mjs"
|
||||
},
|
||||
"./runtime/edge": {
|
||||
"types": "./runtime/edge.d.ts",
|
||||
"require": "./runtime/edge.js",
|
||||
"import": "./runtime/edge-esm.js",
|
||||
"default": "./runtime/edge-esm.js"
|
||||
},
|
||||
"./runtime/react-native": {
|
||||
"types": "./runtime/react-native.d.ts",
|
||||
"require": "./runtime/react-native.js",
|
||||
"import": "./runtime/react-native.js",
|
||||
"default": "./runtime/react-native.js"
|
||||
},
|
||||
"./generator-build": {
|
||||
"require": "./generator-build/index.js",
|
||||
"import": "./generator-build/index.js",
|
||||
"default": "./generator-build/index.js"
|
||||
},
|
||||
"./sql": {
|
||||
"require": {
|
||||
"types": "./sql.d.ts",
|
||||
"node": "./sql.js",
|
||||
"default": "./sql.js"
|
||||
},
|
||||
"import": {
|
||||
"types": "./sql.d.ts",
|
||||
"node": "./sql.mjs",
|
||||
"default": "./sql.mjs"
|
||||
},
|
||||
"default": "./sql.js"
|
||||
},
|
||||
"./*": "./*"
|
||||
},
|
||||
"version": "6.10.1",
|
||||
"sideEffects": false
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,370 +0,0 @@
|
||||
declare class AnyNull extends NullTypesEnumValue {
|
||||
#private;
|
||||
}
|
||||
|
||||
declare type Args<T, F extends Operation> = T extends {
|
||||
[K: symbol]: {
|
||||
types: {
|
||||
operations: {
|
||||
[K in F]: {
|
||||
args: any;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
} ? T[symbol]['types']['operations'][F]['args'] : any;
|
||||
|
||||
declare class DbNull extends NullTypesEnumValue {
|
||||
#private;
|
||||
}
|
||||
|
||||
export declare function Decimal(n: Decimal.Value): Decimal;
|
||||
|
||||
export declare namespace Decimal {
|
||||
export type Constructor = typeof Decimal;
|
||||
export type Instance = Decimal;
|
||||
export type Rounding = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8;
|
||||
export type Modulo = Rounding | 9;
|
||||
export type Value = string | number | Decimal;
|
||||
|
||||
// http://mikemcl.github.io/decimal.js/#constructor-properties
|
||||
export interface Config {
|
||||
precision?: number;
|
||||
rounding?: Rounding;
|
||||
toExpNeg?: number;
|
||||
toExpPos?: number;
|
||||
minE?: number;
|
||||
maxE?: number;
|
||||
crypto?: boolean;
|
||||
modulo?: Modulo;
|
||||
defaults?: boolean;
|
||||
}
|
||||
}
|
||||
|
||||
export declare class Decimal {
|
||||
readonly d: number[];
|
||||
readonly e: number;
|
||||
readonly s: number;
|
||||
|
||||
constructor(n: Decimal.Value);
|
||||
|
||||
absoluteValue(): Decimal;
|
||||
abs(): Decimal;
|
||||
|
||||
ceil(): Decimal;
|
||||
|
||||
clampedTo(min: Decimal.Value, max: Decimal.Value): Decimal;
|
||||
clamp(min: Decimal.Value, max: Decimal.Value): Decimal;
|
||||
|
||||
comparedTo(n: Decimal.Value): number;
|
||||
cmp(n: Decimal.Value): number;
|
||||
|
||||
cosine(): Decimal;
|
||||
cos(): Decimal;
|
||||
|
||||
cubeRoot(): Decimal;
|
||||
cbrt(): Decimal;
|
||||
|
||||
decimalPlaces(): number;
|
||||
dp(): number;
|
||||
|
||||
dividedBy(n: Decimal.Value): Decimal;
|
||||
div(n: Decimal.Value): Decimal;
|
||||
|
||||
dividedToIntegerBy(n: Decimal.Value): Decimal;
|
||||
divToInt(n: Decimal.Value): Decimal;
|
||||
|
||||
equals(n: Decimal.Value): boolean;
|
||||
eq(n: Decimal.Value): boolean;
|
||||
|
||||
floor(): Decimal;
|
||||
|
||||
greaterThan(n: Decimal.Value): boolean;
|
||||
gt(n: Decimal.Value): boolean;
|
||||
|
||||
greaterThanOrEqualTo(n: Decimal.Value): boolean;
|
||||
gte(n: Decimal.Value): boolean;
|
||||
|
||||
hyperbolicCosine(): Decimal;
|
||||
cosh(): Decimal;
|
||||
|
||||
hyperbolicSine(): Decimal;
|
||||
sinh(): Decimal;
|
||||
|
||||
hyperbolicTangent(): Decimal;
|
||||
tanh(): Decimal;
|
||||
|
||||
inverseCosine(): Decimal;
|
||||
acos(): Decimal;
|
||||
|
||||
inverseHyperbolicCosine(): Decimal;
|
||||
acosh(): Decimal;
|
||||
|
||||
inverseHyperbolicSine(): Decimal;
|
||||
asinh(): Decimal;
|
||||
|
||||
inverseHyperbolicTangent(): Decimal;
|
||||
atanh(): Decimal;
|
||||
|
||||
inverseSine(): Decimal;
|
||||
asin(): Decimal;
|
||||
|
||||
inverseTangent(): Decimal;
|
||||
atan(): Decimal;
|
||||
|
||||
isFinite(): boolean;
|
||||
|
||||
isInteger(): boolean;
|
||||
isInt(): boolean;
|
||||
|
||||
isNaN(): boolean;
|
||||
|
||||
isNegative(): boolean;
|
||||
isNeg(): boolean;
|
||||
|
||||
isPositive(): boolean;
|
||||
isPos(): boolean;
|
||||
|
||||
isZero(): boolean;
|
||||
|
||||
lessThan(n: Decimal.Value): boolean;
|
||||
lt(n: Decimal.Value): boolean;
|
||||
|
||||
lessThanOrEqualTo(n: Decimal.Value): boolean;
|
||||
lte(n: Decimal.Value): boolean;
|
||||
|
||||
logarithm(n?: Decimal.Value): Decimal;
|
||||
log(n?: Decimal.Value): Decimal;
|
||||
|
||||
minus(n: Decimal.Value): Decimal;
|
||||
sub(n: Decimal.Value): Decimal;
|
||||
|
||||
modulo(n: Decimal.Value): Decimal;
|
||||
mod(n: Decimal.Value): Decimal;
|
||||
|
||||
naturalExponential(): Decimal;
|
||||
exp(): Decimal;
|
||||
|
||||
naturalLogarithm(): Decimal;
|
||||
ln(): Decimal;
|
||||
|
||||
negated(): Decimal;
|
||||
neg(): Decimal;
|
||||
|
||||
plus(n: Decimal.Value): Decimal;
|
||||
add(n: Decimal.Value): Decimal;
|
||||
|
||||
precision(includeZeros?: boolean): number;
|
||||
sd(includeZeros?: boolean): number;
|
||||
|
||||
round(): Decimal;
|
||||
|
||||
sine() : Decimal;
|
||||
sin() : Decimal;
|
||||
|
||||
squareRoot(): Decimal;
|
||||
sqrt(): Decimal;
|
||||
|
||||
tangent() : Decimal;
|
||||
tan() : Decimal;
|
||||
|
||||
times(n: Decimal.Value): Decimal;
|
||||
mul(n: Decimal.Value) : Decimal;
|
||||
|
||||
toBinary(significantDigits?: number): string;
|
||||
toBinary(significantDigits: number, rounding: Decimal.Rounding): string;
|
||||
|
||||
toDecimalPlaces(decimalPlaces?: number): Decimal;
|
||||
toDecimalPlaces(decimalPlaces: number, rounding: Decimal.Rounding): Decimal;
|
||||
toDP(decimalPlaces?: number): Decimal;
|
||||
toDP(decimalPlaces: number, rounding: Decimal.Rounding): Decimal;
|
||||
|
||||
toExponential(decimalPlaces?: number): string;
|
||||
toExponential(decimalPlaces: number, rounding: Decimal.Rounding): string;
|
||||
|
||||
toFixed(decimalPlaces?: number): string;
|
||||
toFixed(decimalPlaces: number, rounding: Decimal.Rounding): string;
|
||||
|
||||
toFraction(max_denominator?: Decimal.Value): Decimal[];
|
||||
|
||||
toHexadecimal(significantDigits?: number): string;
|
||||
toHexadecimal(significantDigits: number, rounding: Decimal.Rounding): string;
|
||||
toHex(significantDigits?: number): string;
|
||||
toHex(significantDigits: number, rounding?: Decimal.Rounding): string;
|
||||
|
||||
toJSON(): string;
|
||||
|
||||
toNearest(n: Decimal.Value, rounding?: Decimal.Rounding): Decimal;
|
||||
|
||||
toNumber(): number;
|
||||
|
||||
toOctal(significantDigits?: number): string;
|
||||
toOctal(significantDigits: number, rounding: Decimal.Rounding): string;
|
||||
|
||||
toPower(n: Decimal.Value): Decimal;
|
||||
pow(n: Decimal.Value): Decimal;
|
||||
|
||||
toPrecision(significantDigits?: number): string;
|
||||
toPrecision(significantDigits: number, rounding: Decimal.Rounding): string;
|
||||
|
||||
toSignificantDigits(significantDigits?: number): Decimal;
|
||||
toSignificantDigits(significantDigits: number, rounding: Decimal.Rounding): Decimal;
|
||||
toSD(significantDigits?: number): Decimal;
|
||||
toSD(significantDigits: number, rounding: Decimal.Rounding): Decimal;
|
||||
|
||||
toString(): string;
|
||||
|
||||
truncated(): Decimal;
|
||||
trunc(): Decimal;
|
||||
|
||||
valueOf(): string;
|
||||
|
||||
static abs(n: Decimal.Value): Decimal;
|
||||
static acos(n: Decimal.Value): Decimal;
|
||||
static acosh(n: Decimal.Value): Decimal;
|
||||
static add(x: Decimal.Value, y: Decimal.Value): Decimal;
|
||||
static asin(n: Decimal.Value): Decimal;
|
||||
static asinh(n: Decimal.Value): Decimal;
|
||||
static atan(n: Decimal.Value): Decimal;
|
||||
static atanh(n: Decimal.Value): Decimal;
|
||||
static atan2(y: Decimal.Value, x: Decimal.Value): Decimal;
|
||||
static cbrt(n: Decimal.Value): Decimal;
|
||||
static ceil(n: Decimal.Value): Decimal;
|
||||
static clamp(n: Decimal.Value, min: Decimal.Value, max: Decimal.Value): Decimal;
|
||||
static clone(object?: Decimal.Config): Decimal.Constructor;
|
||||
static config(object: Decimal.Config): Decimal.Constructor;
|
||||
static cos(n: Decimal.Value): Decimal;
|
||||
static cosh(n: Decimal.Value): Decimal;
|
||||
static div(x: Decimal.Value, y: Decimal.Value): Decimal;
|
||||
static exp(n: Decimal.Value): Decimal;
|
||||
static floor(n: Decimal.Value): Decimal;
|
||||
static hypot(...n: Decimal.Value[]): Decimal;
|
||||
static isDecimal(object: any): object is Decimal;
|
||||
static ln(n: Decimal.Value): Decimal;
|
||||
static log(n: Decimal.Value, base?: Decimal.Value): Decimal;
|
||||
static log2(n: Decimal.Value): Decimal;
|
||||
static log10(n: Decimal.Value): Decimal;
|
||||
static max(...n: Decimal.Value[]): Decimal;
|
||||
static min(...n: Decimal.Value[]): Decimal;
|
||||
static mod(x: Decimal.Value, y: Decimal.Value): Decimal;
|
||||
static mul(x: Decimal.Value, y: Decimal.Value): Decimal;
|
||||
static noConflict(): Decimal.Constructor; // Browser only
|
||||
static pow(base: Decimal.Value, exponent: Decimal.Value): Decimal;
|
||||
static random(significantDigits?: number): Decimal;
|
||||
static round(n: Decimal.Value): Decimal;
|
||||
static set(object: Decimal.Config): Decimal.Constructor;
|
||||
static sign(n: Decimal.Value): number;
|
||||
static sin(n: Decimal.Value): Decimal;
|
||||
static sinh(n: Decimal.Value): Decimal;
|
||||
static sqrt(n: Decimal.Value): Decimal;
|
||||
static sub(x: Decimal.Value, y: Decimal.Value): Decimal;
|
||||
static sum(...n: Decimal.Value[]): Decimal;
|
||||
static tan(n: Decimal.Value): Decimal;
|
||||
static tanh(n: Decimal.Value): Decimal;
|
||||
static trunc(n: Decimal.Value): Decimal;
|
||||
|
||||
static readonly default?: Decimal.Constructor;
|
||||
static readonly Decimal?: Decimal.Constructor;
|
||||
|
||||
static readonly precision: number;
|
||||
static readonly rounding: Decimal.Rounding;
|
||||
static readonly toExpNeg: number;
|
||||
static readonly toExpPos: number;
|
||||
static readonly minE: number;
|
||||
static readonly maxE: number;
|
||||
static readonly crypto: boolean;
|
||||
static readonly modulo: Decimal.Modulo;
|
||||
|
||||
static readonly ROUND_UP: 0;
|
||||
static readonly ROUND_DOWN: 1;
|
||||
static readonly ROUND_CEIL: 2;
|
||||
static readonly ROUND_FLOOR: 3;
|
||||
static readonly ROUND_HALF_UP: 4;
|
||||
static readonly ROUND_HALF_DOWN: 5;
|
||||
static readonly ROUND_HALF_EVEN: 6;
|
||||
static readonly ROUND_HALF_CEIL: 7;
|
||||
static readonly ROUND_HALF_FLOOR: 8;
|
||||
static readonly EUCLID: 9;
|
||||
}
|
||||
|
||||
declare type Exact<A, W> = (A extends unknown ? (W extends A ? {
|
||||
[K in keyof A]: Exact<A[K], W[K]>;
|
||||
} : W) : never) | (A extends Narrowable ? A : never);
|
||||
|
||||
export declare function getRuntime(): GetRuntimeOutput;
|
||||
|
||||
declare type GetRuntimeOutput = {
|
||||
id: RuntimeName;
|
||||
prettyName: string;
|
||||
isEdge: boolean;
|
||||
};
|
||||
|
||||
declare class JsonNull extends NullTypesEnumValue {
|
||||
#private;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates more strict variant of an enum which, unlike regular enum,
|
||||
* throws on non-existing property access. This can be useful in following situations:
|
||||
* - we have an API, that accepts both `undefined` and `SomeEnumType` as an input
|
||||
* - enum values are generated dynamically from DMMF.
|
||||
*
|
||||
* In that case, if using normal enums and no compile-time typechecking, using non-existing property
|
||||
* will result in `undefined` value being used, which will be accepted. Using strict enum
|
||||
* in this case will help to have a runtime exception, telling you that you are probably doing something wrong.
|
||||
*
|
||||
* Note: if you need to check for existence of a value in the enum you can still use either
|
||||
* `in` operator or `hasOwnProperty` function.
|
||||
*
|
||||
* @param definition
|
||||
* @returns
|
||||
*/
|
||||
export declare function makeStrictEnum<T extends Record<PropertyKey, string | number>>(definition: T): T;
|
||||
|
||||
declare type Narrowable = string | number | bigint | boolean | [];
|
||||
|
||||
declare class NullTypesEnumValue extends ObjectEnumValue {
|
||||
_getNamespace(): string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Base class for unique values of object-valued enums.
|
||||
*/
|
||||
declare abstract class ObjectEnumValue {
|
||||
constructor(arg?: symbol);
|
||||
abstract _getNamespace(): string;
|
||||
_getName(): string;
|
||||
toString(): string;
|
||||
}
|
||||
|
||||
export declare const objectEnumValues: {
|
||||
classes: {
|
||||
DbNull: typeof DbNull;
|
||||
JsonNull: typeof JsonNull;
|
||||
AnyNull: typeof AnyNull;
|
||||
};
|
||||
instances: {
|
||||
DbNull: DbNull;
|
||||
JsonNull: JsonNull;
|
||||
AnyNull: AnyNull;
|
||||
};
|
||||
};
|
||||
|
||||
declare type Operation = 'findFirst' | 'findFirstOrThrow' | 'findUnique' | 'findUniqueOrThrow' | 'findMany' | 'create' | 'createMany' | 'createManyAndReturn' | 'update' | 'updateMany' | 'updateManyAndReturn' | 'upsert' | 'delete' | 'deleteMany' | 'aggregate' | 'count' | 'groupBy' | '$queryRaw' | '$executeRaw' | '$queryRawUnsafe' | '$executeRawUnsafe' | 'findRaw' | 'aggregateRaw' | '$runCommandRaw';
|
||||
|
||||
declare namespace Public {
|
||||
export {
|
||||
validator
|
||||
}
|
||||
}
|
||||
export { Public }
|
||||
|
||||
declare type RuntimeName = 'workerd' | 'deno' | 'netlify' | 'node' | 'bun' | 'edge-light' | '';
|
||||
|
||||
declare function validator<V>(): <S>(select: Exact<S, V>) => S;
|
||||
|
||||
declare function validator<C, M extends Exclude<keyof C, `$${string}`>, O extends keyof C[M] & Operation>(client: C, model: M, operation: O): <S>(select: Exact<S, Args<C[M], O>>) => S;
|
||||
|
||||
declare function validator<C, M extends Exclude<keyof C, `$${string}`>, O extends keyof C[M] & Operation, P extends keyof Args<C[M], O>>(client: C, model: M, operation: O, prop: P): <S>(select: Exact<S, Args<C[M], O>[P]>) => S;
|
||||
|
||||
export { }
|
||||
File diff suppressed because one or more lines are too long
-3681
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,199 +0,0 @@
|
||||
// This is your Prisma schema file,
|
||||
// learn more about the docs: https://pris.ly/d/prisma-schema
|
||||
|
||||
// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions?
|
||||
// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init
|
||||
|
||||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
output = "../generated/prisma/client"
|
||||
binaryTargets = ["native", "debian-openssl-1.1.x"]
|
||||
}
|
||||
|
||||
datasource db {
|
||||
provider = "postgresql"
|
||||
url = env("DATABASE_URL")
|
||||
}
|
||||
|
||||
// Enum para los roles de usuario en la aplicación
|
||||
enum UserRole {
|
||||
ADMIN // Administrador con control total
|
||||
MANAGER // Gerente con permisos de gestión
|
||||
STAFF // Personal con permisos operativos
|
||||
VIEWER // Solo lectura
|
||||
}
|
||||
|
||||
// Modelo para los usuarios de la aplicación
|
||||
model User {
|
||||
id String @id @default(uuid())
|
||||
username String @unique // Nombre de usuario único para login
|
||||
name String // Nombre completo del usuario
|
||||
email String @unique // Email único para el usuario
|
||||
password String // Contraseña (debe ser hasheada)
|
||||
role UserRole @default(STAFF) // Rol del usuario, por defecto STAFF
|
||||
isActive Boolean @default(true) // Indica si la cuenta está activa
|
||||
createdAt DateTime @default(now()) // Fecha de creación del registro
|
||||
updatedAt DateTime @updatedAt // Fecha de última actualización del registro
|
||||
movements Movement[] // Relación con los movimientos realizados por este usuario
|
||||
assignments Assignment[] // Relación con las asignaciones creadas por este usuario
|
||||
}
|
||||
|
||||
// Enum para los departamentos de los destinatarios
|
||||
enum RecipientDepartment {
|
||||
IT
|
||||
ENGINEERING // Cambiado de ING a ENGINEERING para mayor claridad
|
||||
LOGISTICS // Cambiado de LNG a LOGISTICS
|
||||
TRAFFIC
|
||||
DRIVER
|
||||
ADMINISTRATION
|
||||
SALES
|
||||
OTHER
|
||||
}
|
||||
|
||||
// Modelo para los destinatarios de los ítems (personas o áreas a las que se asignan cosas)
|
||||
model Recipient {
|
||||
id String @id @default(uuid())
|
||||
username String @unique // Nombre de usuario o identificador único del destinatario
|
||||
firstName String // Nombre del destinatario
|
||||
lastName String // Apellido del destinatario
|
||||
department RecipientDepartment? // Departamento del destinatario, usando el enum
|
||||
email String? @unique // Email opcional del destinatario
|
||||
phone String? // Teléfono opcional del destinatario
|
||||
isActive Boolean @default(true) // Indica si el destinatario está activo
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt // Fecha de última actualización del registro
|
||||
assignments Assignment[] // Relación con las asignaciones de ítems a este destinatario
|
||||
movements Movement[] // Relación con los movimientos de ítems relacionados con este destinatario
|
||||
|
||||
@@index([lastName, firstName]) // Índice para búsquedas por nombre y apellido
|
||||
@@index([department]) // Nuevo índice para búsquedas por departamento
|
||||
}
|
||||
|
||||
// Modelo para las categorías de ítems
|
||||
model Category {
|
||||
id String @id @default(uuid())
|
||||
name String @unique // Nombre único de la categoría
|
||||
description String? // Descripción opcional de la categoría
|
||||
isActive Boolean @default(true) // Indica si la categoría está activa
|
||||
items Item[] // Relación con los productos (ítems genéricos) de esta categoría
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt // Fecha de última actualización del registro
|
||||
|
||||
@@index([name]) // Índice para búsquedas por nombre de categoría
|
||||
}
|
||||
|
||||
// Enum para el estado de un ítem (ya sea Item o Asset)
|
||||
enum ItemStatus {
|
||||
AVAILABLE // Disponible en stock
|
||||
ASSIGNED // Asignado a un destinatario
|
||||
RESERVED // Reservado para una asignación futura
|
||||
IN_REPAIR // En reparación
|
||||
BROKEN // Averiado e inutilizable
|
||||
STOLEN // Robado
|
||||
DISPOSED // Dado de baja/eliminado del inventario
|
||||
}
|
||||
|
||||
// Modelo para ítems genéricos (sin número de serie individual, se gestionan por cantidad)
|
||||
model Item {
|
||||
id String @id @default(uuid())
|
||||
name String // Nombre del producto
|
||||
description String? // Descripción opcional del producto
|
||||
categoryId String // ID de la categoría a la que pertenece el producto
|
||||
category Category @relation(fields: [categoryId], references: [id]) // Relación con la categoría
|
||||
stock Int @default(0) // Cantidad actual en stock
|
||||
minStock Int? // Nivel mínimo de stock para alertas
|
||||
maxStock Int? // Nivel máximo de stock deseado
|
||||
createdAt DateTime @default(now()) // Fecha de creación del registro
|
||||
updatedAt DateTime @updatedAt // Fecha de última actualización del registro
|
||||
deletedAt DateTime? // Fecha de eliminación del registro
|
||||
movements Movement[] // Relación con los movimientos de este producto
|
||||
assignments Assignment[] // Relación con las asignaciones de este producto (por cantidad)
|
||||
assets Asset[] // Relación con los activos serializados que son de este tipo de producto
|
||||
|
||||
@@index([categoryId]) // Índice para búsquedas por categoría
|
||||
@@index([name]) // Índice para búsquedas por nombre de producto
|
||||
}
|
||||
|
||||
// Modelo para ítems serializados (activos individuales con número de serie único)
|
||||
model Asset {
|
||||
id String @id @default(uuid())
|
||||
itemId String? // ID del producto genérico al que pertenece este activo (opcional)
|
||||
item Item? @relation(fields: [itemId], references: [id]) // Relación con el producto genérico
|
||||
serialNumber String @unique // Número de serie único y obligatorio para el activo
|
||||
deliveryNote String? // Número de albarán de entrega (opcional, puede ser para la entrada inicial)
|
||||
status ItemStatus @default(AVAILABLE) // Estado actual del activo individual
|
||||
notes String? // Notas adicionales sobre el activo
|
||||
createdAt DateTime @default(now()) // Fecha de creación del registro
|
||||
updatedAt DateTime @updatedAt // Fecha de última actualización del registro
|
||||
movements Movement[] // Relación con los movimientos de este activo
|
||||
assignment Assignment? // Relación 1:1 con la asignación activa de este activo (un activo solo puede estar en una asignación activa)
|
||||
|
||||
@@index([serialNumber]) // Índice para búsquedas por número de serie
|
||||
@@index([itemId]) // Índice para búsquedas por producto asociado
|
||||
@@index([status]) // Índice para búsquedas por estado del activo
|
||||
}
|
||||
|
||||
// Modelo para registrar las asignaciones de ítems a destinatarios
|
||||
model Assignment {
|
||||
id String @id @default(uuid())
|
||||
quantity Int? // Cantidad asignada (solo si es un Item, para Asset sería 1 implícitamente)
|
||||
notes String? // Notas sobre la asignación
|
||||
itemId String? // ID del producto genérico asignado (si no es un activo serializado)
|
||||
item Item? @relation(fields: [itemId], references: [id]) // Relación con el producto
|
||||
assetId String? @unique // ID del activo serializado asignado (si es un activo, debe ser único para asignaciones activas)
|
||||
asset Asset? @relation(fields: [assetId], references: [id]) // Relación con el activo
|
||||
recipientId String? // ID del destinatario de la asignación
|
||||
recipient Recipient? @relation(fields: [recipientId], references: [id], onDelete: Cascade, onUpdate: Cascade) // Relación con el destinatario
|
||||
assignmentDate DateTime @default(now()) // Fecha en que se realizó la asignación
|
||||
returnDate DateTime? // Fecha en que se devolvió la asignación (si aplica)
|
||||
createdBy String // ID del usuario que realizó la asignación
|
||||
createdUser User @relation(fields: [createdBy], references: [id]) // Relación con el usuario que creó la asignación
|
||||
createdAt DateTime @default(now()) // Fecha de creación del registro de asignación
|
||||
updatedAt DateTime @updatedAt // Fecha de última actualización del registro
|
||||
movement Movement[] // Relación con los movimientos generados por esta asignación (ej. OUT, RETURN)
|
||||
|
||||
// Índices para mejorar el rendimiento de las consultas
|
||||
@@index([itemId])
|
||||
@@index([assetId])
|
||||
@@index([recipientId])
|
||||
@@index([createdBy])
|
||||
}
|
||||
|
||||
// Enum para los tipos de movimiento de stock
|
||||
enum MovementType {
|
||||
IN // Entrada de stock (compra, fabricación)
|
||||
OUT // Salida de stock (venta, consumo)
|
||||
ASSIGNMENT // Movimiento asociado a una asignación
|
||||
RETURN // Movimiento asociado a la devolución de una asignación
|
||||
ADJUSTMENT // Ajuste de inventario (corrección, pérdida)
|
||||
DELETED // Eliminación de un ítem
|
||||
}
|
||||
|
||||
// Modelo para el histórico de todos los movimientos de stock/activos
|
||||
model Movement {
|
||||
id String @id @default(uuid())
|
||||
type MovementType @default(IN) // Tipo de movimiento
|
||||
quantity Int // Cantidad del movimiento (para Item, para Asset sería 1)
|
||||
details String? // Detalles adicionales del movimiento
|
||||
notes String? // Notas sobre el movimiento
|
||||
itemId String? // ID del producto afectado (si es un Item)
|
||||
item Item? @relation(fields: [itemId], references: [id]) // Relación con el producto
|
||||
assetId String? // ID del activo afectado (si es un Asset)
|
||||
asset Asset? @relation(fields: [assetId], references: [id]) // Relación con el activo
|
||||
previousStock Int? // Stock antes de este movimiento (solo para Item)
|
||||
newStock Int? // Stock después de este movimiento (solo para Item)
|
||||
recipientId String? // ID del destinatario relacionado con el movimiento (si aplica)
|
||||
recipient Recipient? @relation(fields: [recipientId], references: [id]) // Relación con el destinatario
|
||||
assignmentId String? // ID de la asignación relacionada (si el movimiento es ASSIGNMENT o RETURN)
|
||||
assignment Assignment? @relation(fields: [assignmentId], references: [id]) // Relación con la asignación
|
||||
userId String // ID del usuario que realizó el movimiento
|
||||
user User @relation(fields: [userId], references: [id]) // Relación con el usuario
|
||||
createdAt DateTime @default(now()) // Fecha en que se registró el movimiento
|
||||
|
||||
// Índices para mejorar el rendimiento de las consultas
|
||||
@@index([itemId])
|
||||
@@index([assetId])
|
||||
@@index([recipientId])
|
||||
@@index([type])
|
||||
@@index([userId])
|
||||
}
|
||||
-1
@@ -1 +0,0 @@
|
||||
export * from "./index"
|
||||
@@ -1,301 +0,0 @@
|
||||
|
||||
/* !!! This is code generated by Prisma. Do not edit directly. !!!
|
||||
/* eslint-disable */
|
||||
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
|
||||
const {
|
||||
Decimal,
|
||||
objectEnumValues,
|
||||
makeStrictEnum,
|
||||
Public,
|
||||
getRuntime,
|
||||
skip
|
||||
} = require('./runtime/index-browser.js')
|
||||
|
||||
|
||||
const Prisma = {}
|
||||
|
||||
exports.Prisma = Prisma
|
||||
exports.$Enums = {}
|
||||
|
||||
/**
|
||||
* Prisma Client JS version: 6.10.1
|
||||
* Query Engine version: 9b628578b3b7cae625e8c927178f15a170e74a9c
|
||||
*/
|
||||
Prisma.prismaVersion = {
|
||||
client: "6.10.1",
|
||||
engine: "9b628578b3b7cae625e8c927178f15a170e74a9c"
|
||||
}
|
||||
|
||||
Prisma.PrismaClientKnownRequestError = () => {
|
||||
const runtimeName = getRuntime().prettyName;
|
||||
throw new Error(`PrismaClientKnownRequestError is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
|
||||
In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
|
||||
)};
|
||||
Prisma.PrismaClientUnknownRequestError = () => {
|
||||
const runtimeName = getRuntime().prettyName;
|
||||
throw new Error(`PrismaClientUnknownRequestError is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
|
||||
In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
|
||||
)}
|
||||
Prisma.PrismaClientRustPanicError = () => {
|
||||
const runtimeName = getRuntime().prettyName;
|
||||
throw new Error(`PrismaClientRustPanicError is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
|
||||
In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
|
||||
)}
|
||||
Prisma.PrismaClientInitializationError = () => {
|
||||
const runtimeName = getRuntime().prettyName;
|
||||
throw new Error(`PrismaClientInitializationError is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
|
||||
In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
|
||||
)}
|
||||
Prisma.PrismaClientValidationError = () => {
|
||||
const runtimeName = getRuntime().prettyName;
|
||||
throw new Error(`PrismaClientValidationError is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
|
||||
In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
|
||||
)}
|
||||
Prisma.Decimal = Decimal
|
||||
|
||||
/**
|
||||
* Re-export of sql-template-tag
|
||||
*/
|
||||
Prisma.sql = () => {
|
||||
const runtimeName = getRuntime().prettyName;
|
||||
throw new Error(`sqltag is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
|
||||
In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
|
||||
)}
|
||||
Prisma.empty = () => {
|
||||
const runtimeName = getRuntime().prettyName;
|
||||
throw new Error(`empty is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
|
||||
In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
|
||||
)}
|
||||
Prisma.join = () => {
|
||||
const runtimeName = getRuntime().prettyName;
|
||||
throw new Error(`join is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
|
||||
In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
|
||||
)}
|
||||
Prisma.raw = () => {
|
||||
const runtimeName = getRuntime().prettyName;
|
||||
throw new Error(`raw is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
|
||||
In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
|
||||
)}
|
||||
Prisma.validator = Public.validator
|
||||
|
||||
/**
|
||||
* Extensions
|
||||
*/
|
||||
Prisma.getExtensionContext = () => {
|
||||
const runtimeName = getRuntime().prettyName;
|
||||
throw new Error(`Extensions.getExtensionContext is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
|
||||
In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
|
||||
)}
|
||||
Prisma.defineExtension = () => {
|
||||
const runtimeName = getRuntime().prettyName;
|
||||
throw new Error(`Extensions.defineExtension is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
|
||||
In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
|
||||
)}
|
||||
|
||||
/**
|
||||
* Shorthand utilities for JSON filtering
|
||||
*/
|
||||
Prisma.DbNull = objectEnumValues.instances.DbNull
|
||||
Prisma.JsonNull = objectEnumValues.instances.JsonNull
|
||||
Prisma.AnyNull = objectEnumValues.instances.AnyNull
|
||||
|
||||
Prisma.NullTypes = {
|
||||
DbNull: objectEnumValues.classes.DbNull,
|
||||
JsonNull: objectEnumValues.classes.JsonNull,
|
||||
AnyNull: objectEnumValues.classes.AnyNull
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Enums
|
||||
*/
|
||||
|
||||
exports.Prisma.TransactionIsolationLevel = makeStrictEnum({
|
||||
ReadUncommitted: 'ReadUncommitted',
|
||||
ReadCommitted: 'ReadCommitted',
|
||||
RepeatableRead: 'RepeatableRead',
|
||||
Serializable: 'Serializable'
|
||||
});
|
||||
|
||||
exports.Prisma.UserScalarFieldEnum = {
|
||||
id: 'id',
|
||||
username: 'username',
|
||||
name: 'name',
|
||||
email: 'email',
|
||||
password: 'password',
|
||||
role: 'role',
|
||||
isActive: 'isActive',
|
||||
createdAt: 'createdAt',
|
||||
updatedAt: 'updatedAt'
|
||||
};
|
||||
|
||||
exports.Prisma.RecipientScalarFieldEnum = {
|
||||
id: 'id',
|
||||
username: 'username',
|
||||
firstName: 'firstName',
|
||||
lastName: 'lastName',
|
||||
department: 'department',
|
||||
email: 'email',
|
||||
phone: 'phone',
|
||||
isActive: 'isActive',
|
||||
createdAt: 'createdAt',
|
||||
updatedAt: 'updatedAt'
|
||||
};
|
||||
|
||||
exports.Prisma.CategoryScalarFieldEnum = {
|
||||
id: 'id',
|
||||
name: 'name',
|
||||
description: 'description',
|
||||
isActive: 'isActive',
|
||||
createdAt: 'createdAt',
|
||||
updatedAt: 'updatedAt'
|
||||
};
|
||||
|
||||
exports.Prisma.ItemScalarFieldEnum = {
|
||||
id: 'id',
|
||||
name: 'name',
|
||||
description: 'description',
|
||||
categoryId: 'categoryId',
|
||||
stock: 'stock',
|
||||
minStock: 'minStock',
|
||||
maxStock: 'maxStock',
|
||||
createdAt: 'createdAt',
|
||||
updatedAt: 'updatedAt',
|
||||
deletedAt: 'deletedAt'
|
||||
};
|
||||
|
||||
exports.Prisma.AssetScalarFieldEnum = {
|
||||
id: 'id',
|
||||
itemId: 'itemId',
|
||||
serialNumber: 'serialNumber',
|
||||
deliveryNote: 'deliveryNote',
|
||||
status: 'status',
|
||||
notes: 'notes',
|
||||
createdAt: 'createdAt',
|
||||
updatedAt: 'updatedAt'
|
||||
};
|
||||
|
||||
exports.Prisma.AssignmentScalarFieldEnum = {
|
||||
id: 'id',
|
||||
quantity: 'quantity',
|
||||
notes: 'notes',
|
||||
itemId: 'itemId',
|
||||
assetId: 'assetId',
|
||||
recipientId: 'recipientId',
|
||||
assignmentDate: 'assignmentDate',
|
||||
returnDate: 'returnDate',
|
||||
createdBy: 'createdBy',
|
||||
createdAt: 'createdAt',
|
||||
updatedAt: 'updatedAt'
|
||||
};
|
||||
|
||||
exports.Prisma.MovementScalarFieldEnum = {
|
||||
id: 'id',
|
||||
type: 'type',
|
||||
quantity: 'quantity',
|
||||
details: 'details',
|
||||
notes: 'notes',
|
||||
itemId: 'itemId',
|
||||
assetId: 'assetId',
|
||||
previousStock: 'previousStock',
|
||||
newStock: 'newStock',
|
||||
recipientId: 'recipientId',
|
||||
assignmentId: 'assignmentId',
|
||||
userId: 'userId',
|
||||
createdAt: 'createdAt'
|
||||
};
|
||||
|
||||
exports.Prisma.SortOrder = {
|
||||
asc: 'asc',
|
||||
desc: 'desc'
|
||||
};
|
||||
|
||||
exports.Prisma.QueryMode = {
|
||||
default: 'default',
|
||||
insensitive: 'insensitive'
|
||||
};
|
||||
|
||||
exports.Prisma.NullsOrder = {
|
||||
first: 'first',
|
||||
last: 'last'
|
||||
};
|
||||
exports.UserRole = exports.$Enums.UserRole = {
|
||||
ADMIN: 'ADMIN',
|
||||
MANAGER: 'MANAGER',
|
||||
STAFF: 'STAFF',
|
||||
VIEWER: 'VIEWER'
|
||||
};
|
||||
|
||||
exports.RecipientDepartment = exports.$Enums.RecipientDepartment = {
|
||||
IT: 'IT',
|
||||
ENGINEERING: 'ENGINEERING',
|
||||
LOGISTICS: 'LOGISTICS',
|
||||
TRAFFIC: 'TRAFFIC',
|
||||
DRIVER: 'DRIVER',
|
||||
ADMINISTRATION: 'ADMINISTRATION',
|
||||
SALES: 'SALES',
|
||||
OTHER: 'OTHER'
|
||||
};
|
||||
|
||||
exports.ItemStatus = exports.$Enums.ItemStatus = {
|
||||
AVAILABLE: 'AVAILABLE',
|
||||
ASSIGNED: 'ASSIGNED',
|
||||
RESERVED: 'RESERVED',
|
||||
IN_REPAIR: 'IN_REPAIR',
|
||||
BROKEN: 'BROKEN',
|
||||
STOLEN: 'STOLEN',
|
||||
DISPOSED: 'DISPOSED'
|
||||
};
|
||||
|
||||
exports.MovementType = exports.$Enums.MovementType = {
|
||||
IN: 'IN',
|
||||
OUT: 'OUT',
|
||||
ASSIGNMENT: 'ASSIGNMENT',
|
||||
RETURN: 'RETURN',
|
||||
ADJUSTMENT: 'ADJUSTMENT',
|
||||
DELETED: 'DELETED'
|
||||
};
|
||||
|
||||
exports.Prisma.ModelName = {
|
||||
User: 'User',
|
||||
Recipient: 'Recipient',
|
||||
Category: 'Category',
|
||||
Item: 'Item',
|
||||
Asset: 'Asset',
|
||||
Assignment: 'Assignment',
|
||||
Movement: 'Movement'
|
||||
};
|
||||
|
||||
/**
|
||||
* This is a stub Prisma Client that will error at runtime if called.
|
||||
*/
|
||||
class PrismaClient {
|
||||
constructor() {
|
||||
return new Proxy(this, {
|
||||
get(target, prop) {
|
||||
let message
|
||||
const runtime = getRuntime()
|
||||
if (runtime.isEdge) {
|
||||
message = `PrismaClient is not configured to run in ${runtime.prettyName}. In order to run Prisma Client on edge runtime, either:
|
||||
- Use Prisma Accelerate: https://pris.ly/d/accelerate
|
||||
- Use Driver Adapters: https://pris.ly/d/driver-adapters
|
||||
`;
|
||||
} else {
|
||||
message = 'PrismaClient is unable to run in this browser environment, or has been bundled for the browser (running in `' + runtime.prettyName + '`).'
|
||||
}
|
||||
|
||||
message += `
|
||||
If this is unexpected, please open an issue: https://pris.ly/prisma-prisma-bug-report`
|
||||
|
||||
throw new Error(message)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
exports.PrismaClient = PrismaClient
|
||||
|
||||
Object.assign(exports, Prisma)
|
||||
@@ -1,198 +0,0 @@
|
||||
"use server"
|
||||
|
||||
import { revalidatePath } from "next/cache"
|
||||
|
||||
import {
|
||||
createAssignment,
|
||||
updateAssignment,
|
||||
} from "@/lib/actions/assignament.actions"
|
||||
import {
|
||||
type CreateAssetFormType,
|
||||
createAssetSchema,
|
||||
type UpdateAssetFormType,
|
||||
updateAssetSchema,
|
||||
} from "@/lib/schemas/asset.schemas"
|
||||
import { AssetService } from "@/services/asset.service"
|
||||
import { AssignmentService } from "@/services/assignment.service"
|
||||
import { ItemService } from "@/services/item.service"
|
||||
import { MovementService } from "@/services/movement.service"
|
||||
|
||||
export async function createAssetAction(formData: CreateAssetFormType) {
|
||||
try {
|
||||
const validatedFields = createAssetSchema.safeParse(formData)
|
||||
|
||||
if (!validatedFields.success) {
|
||||
return {
|
||||
errors: validatedFields.error.flatten().fieldErrors,
|
||||
}
|
||||
}
|
||||
|
||||
const { itemId, serialNumber, deliveryNote, status, notes, recipientId } =
|
||||
validatedFields.data
|
||||
|
||||
const item = await ItemService.findByIdWithCategory(itemId)
|
||||
|
||||
if (!item) {
|
||||
return {
|
||||
success: false,
|
||||
errors: { itemId: ["Item not found"] },
|
||||
}
|
||||
}
|
||||
|
||||
const existentAsset = await AssetService.findBySerialNumber(serialNumber)
|
||||
|
||||
if (existentAsset) {
|
||||
return {
|
||||
success: false,
|
||||
errors: {
|
||||
serialNumber: ["This serial number already exists"],
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const newAsset = await AssetService.create({
|
||||
item: { connect: { id: itemId } },
|
||||
serialNumber,
|
||||
deliveryNote,
|
||||
status,
|
||||
notes,
|
||||
})
|
||||
|
||||
await MovementService.create({
|
||||
itemId,
|
||||
assetId: newAsset?.id,
|
||||
quantity: 1,
|
||||
type: status === "ASSIGNED" ? "ASSIGNMENT" : "IN",
|
||||
})
|
||||
|
||||
if (status === "AVAILABLE") {
|
||||
await ItemService.update(itemId, {
|
||||
stock: item.stock + 1,
|
||||
name: item.name,
|
||||
category: { connect: { id: item.category?.id } },
|
||||
})
|
||||
}
|
||||
|
||||
if (status === "ASSIGNED" && recipientId) {
|
||||
await AssignmentService.create({
|
||||
notes: "",
|
||||
itemId,
|
||||
assetId: newAsset?.id,
|
||||
quantity: 1,
|
||||
recipientId,
|
||||
assignmentDate: new Date(),
|
||||
})
|
||||
}
|
||||
|
||||
revalidatePath("/inventory/assets")
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: "Asset created successfully",
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Database error:", error)
|
||||
return {
|
||||
success: false,
|
||||
message: "Error creating asset",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function updateAssetAction(formData: UpdateAssetFormType) {
|
||||
const validatedFields = updateAssetSchema.safeParse(formData)
|
||||
|
||||
if (!validatedFields.success) {
|
||||
return {
|
||||
errors: validatedFields.error.flatten().fieldErrors,
|
||||
}
|
||||
}
|
||||
|
||||
const { id, itemId, serialNumber, deliveryNote, status, notes, recipientId } =
|
||||
validatedFields.data
|
||||
|
||||
try {
|
||||
const item = await ItemService.findByIdWithCategory(itemId)
|
||||
|
||||
if (!item) {
|
||||
return {
|
||||
success: false,
|
||||
errors: { itemId: ["Item not found"] },
|
||||
}
|
||||
}
|
||||
|
||||
const existentAsset = await AssetService.findBySerialNumber(serialNumber)
|
||||
|
||||
if (
|
||||
existentAsset &&
|
||||
id !== existentAsset.id &&
|
||||
existentAsset.serialNumber === serialNumber
|
||||
) {
|
||||
return {
|
||||
success: false,
|
||||
errors: {
|
||||
serialNumber: ["This serial number already exists"],
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
await AssetService.update(id, {
|
||||
item: { connect: { id: itemId } },
|
||||
serialNumber,
|
||||
deliveryNote,
|
||||
status,
|
||||
notes,
|
||||
})
|
||||
|
||||
await MovementService.create({
|
||||
itemId,
|
||||
assetId: id,
|
||||
quantity: 1,
|
||||
type: status === "ASSIGNED" ? "ASSIGNMENT" : "IN",
|
||||
})
|
||||
|
||||
if (status === "AVAILABLE") {
|
||||
await ItemService.update(itemId, {
|
||||
stock: item.stock + 1,
|
||||
name: item.name,
|
||||
category: { connect: { id: item.category?.id } },
|
||||
})
|
||||
}
|
||||
|
||||
if (status === "ASSIGNED" && recipientId) {
|
||||
if (!recipientId) {
|
||||
return {
|
||||
success: false,
|
||||
errors: { recipientId: ["Recipient is required for assignment"] },
|
||||
}
|
||||
}
|
||||
|
||||
if (existentAsset?.assignment) {
|
||||
await updateAssignment({
|
||||
id: existentAsset.assignment.id,
|
||||
recipientId,
|
||||
quantity: 1,
|
||||
})
|
||||
} else {
|
||||
await createAssignment({
|
||||
itemId,
|
||||
assetId: id,
|
||||
quantity: 1,
|
||||
recipientId,
|
||||
assignmentDate: new Date(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: "Asset updated successfully",
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Database error:", error)
|
||||
return {
|
||||
success: false,
|
||||
message: "Error updating asset",
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,298 +0,0 @@
|
||||
"use server"
|
||||
|
||||
import { revalidatePath } from "next/cache"
|
||||
|
||||
import prisma from "@/lib/prisma"
|
||||
import { AssetService } from "@/services/asset.service"
|
||||
import { AssignmentService } from "@/services/assignment.service"
|
||||
import { getAuthenticatedUserId } from "@/services/auth.service"
|
||||
import { ItemService } from "@/services/item.service"
|
||||
import { MovementService } from "@/services/movement.service"
|
||||
|
||||
import {
|
||||
assignmentSchema,
|
||||
type CreateAssignmentFormType,
|
||||
type ReturnAssignmentFormType,
|
||||
type UpdateAssignmentFormType,
|
||||
updateAssignmentSchema,
|
||||
} from "../schemas/assignment.schemas"
|
||||
|
||||
export async function getAssignments() {
|
||||
return await AssignmentService.findAllWithRecipient()
|
||||
}
|
||||
|
||||
export async function getAssignmentById(id: string) {
|
||||
return await AssignmentService.findById(id)
|
||||
}
|
||||
|
||||
export async function createAssignment(formData: CreateAssignmentFormType) {
|
||||
const createdBy = await getAuthenticatedUserId()
|
||||
|
||||
const validatedFields = assignmentSchema.safeParse({
|
||||
...formData,
|
||||
createdBy,
|
||||
})
|
||||
|
||||
if (!validatedFields.success) {
|
||||
return {
|
||||
success: false,
|
||||
errors: validatedFields.error.flatten().fieldErrors,
|
||||
}
|
||||
}
|
||||
|
||||
const { itemId, assetId, quantity, recipientId } = validatedFields.data
|
||||
|
||||
if (!itemId || !recipientId || quantity <= 0) return
|
||||
|
||||
try {
|
||||
const item = await ItemService.findById(itemId)
|
||||
|
||||
if (!item) {
|
||||
return {
|
||||
success: false,
|
||||
errors: { itemId: ["Item not found"] },
|
||||
}
|
||||
}
|
||||
|
||||
if (item.stock < quantity) {
|
||||
return {
|
||||
success: false,
|
||||
errors: { quantity: ["Item does not have enough stock"] },
|
||||
}
|
||||
}
|
||||
|
||||
if (assetId) {
|
||||
const asset = await AssetService.findById(assetId)
|
||||
|
||||
if (!asset) {
|
||||
return {
|
||||
success: false,
|
||||
errors: { assetId: ["Asset not found"] },
|
||||
}
|
||||
}
|
||||
|
||||
if (asset.itemId !== item.id) {
|
||||
return {
|
||||
success: false,
|
||||
errors: { assetId: ["Asset does not belong to item"] },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await ItemService.updateStock(itemId, -quantity)
|
||||
|
||||
if (assetId && recipientId) {
|
||||
await AssetService.update(assetId, {
|
||||
status: "ASSIGNED",
|
||||
})
|
||||
}
|
||||
|
||||
const createdAssignment = await AssignmentService.create({
|
||||
itemId,
|
||||
assetId: assetId || undefined,
|
||||
quantity,
|
||||
recipientId,
|
||||
})
|
||||
|
||||
await MovementService.create({
|
||||
itemId,
|
||||
assetId: assetId || undefined,
|
||||
quantity,
|
||||
type: "ASSIGNMENT",
|
||||
recipientId,
|
||||
assignmentId: createdAssignment.id,
|
||||
})
|
||||
|
||||
revalidatePath("/assignments")
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: "Assignment created successfully",
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Database error:", error)
|
||||
return {
|
||||
success: false,
|
||||
errors: { error: ["Error creating assignment"] },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function updateAssignment(formData: UpdateAssignmentFormType) {
|
||||
const validatedFields = updateAssignmentSchema.safeParse(formData)
|
||||
|
||||
if (!validatedFields.success) {
|
||||
return {
|
||||
success: false,
|
||||
errors: validatedFields.error.flatten().fieldErrors,
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const { id, recipientId, itemId, assetId, quantity } = validatedFields.data
|
||||
|
||||
const assignment = await prisma.assignment.findUnique({
|
||||
where: { id },
|
||||
})
|
||||
|
||||
if (!assignment) {
|
||||
return {
|
||||
success: false,
|
||||
errors: { id: ["Assignment not found"] },
|
||||
}
|
||||
}
|
||||
|
||||
if (itemId) {
|
||||
const item = await prisma.item.findUnique({
|
||||
where: { id: itemId },
|
||||
})
|
||||
|
||||
if (!item) {
|
||||
return {
|
||||
success: false,
|
||||
errors: { itemId: ["Item not found"] },
|
||||
}
|
||||
}
|
||||
|
||||
// if (item.stock < quantity) {
|
||||
// return {
|
||||
// success: false,
|
||||
// errors: { quantity: ["Item does not have enough stock"] },
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
if (assetId) {
|
||||
const asset = await prisma.asset.findUnique({
|
||||
where: { id: assetId },
|
||||
})
|
||||
|
||||
if (!asset) {
|
||||
return {
|
||||
success: false,
|
||||
errors: { assetId: ["Asset not found"] },
|
||||
}
|
||||
}
|
||||
|
||||
if (asset.itemId !== itemId) {
|
||||
await prisma.asset.update({
|
||||
where: { id: assetId },
|
||||
data: { itemId },
|
||||
})
|
||||
|
||||
return {
|
||||
success: false,
|
||||
errors: { assetId: ["Asset does not belong to item"] },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const createdBy = await getAuthenticatedUserId()
|
||||
|
||||
if (assignment.recipientId !== recipientId) {
|
||||
await MovementService.create({
|
||||
type: "RETURN",
|
||||
quantity: assignment.quantity || 1,
|
||||
itemId: assignment.itemId || undefined,
|
||||
assetId: assignment.assetId || undefined,
|
||||
recipientId: assignment.recipientId || undefined,
|
||||
assignmentId: id,
|
||||
})
|
||||
|
||||
await MovementService.create({
|
||||
type: "ASSIGNMENT",
|
||||
quantity,
|
||||
itemId,
|
||||
assetId: assetId || undefined,
|
||||
recipientId,
|
||||
assignmentId: id,
|
||||
})
|
||||
|
||||
await prisma.assignment.update({
|
||||
data: {
|
||||
...validatedFields.data,
|
||||
createdBy,
|
||||
recipientId,
|
||||
itemId,
|
||||
assetId,
|
||||
quantity,
|
||||
returnDate: null,
|
||||
},
|
||||
where: { id },
|
||||
})
|
||||
} else {
|
||||
await prisma.assignment.update({
|
||||
where: { id },
|
||||
data: {
|
||||
...validatedFields.data,
|
||||
itemId,
|
||||
assetId,
|
||||
quantity,
|
||||
returnDate: new Date(),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
revalidatePath("/assignments")
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: "Assignment updated successfully",
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Database error:", error)
|
||||
return {
|
||||
success: false,
|
||||
errors: { error: ["Error creating assignment"] },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function returnAssignment(formData: ReturnAssignmentFormType) {
|
||||
const { id } = formData
|
||||
|
||||
const assignment = await AssignmentService.findById(id)
|
||||
|
||||
if (!assignment) {
|
||||
return {
|
||||
success: false,
|
||||
errors: { id: ["Assignment not found"] },
|
||||
}
|
||||
}
|
||||
|
||||
if (assignment.returnDate) {
|
||||
return {
|
||||
success: false,
|
||||
errors: { id: ["Assignment already returned"] },
|
||||
}
|
||||
}
|
||||
|
||||
if (assignment.itemId && assignment.quantity) {
|
||||
await ItemService.update(assignment.itemId, {
|
||||
stock: { increment: assignment.quantity || 1 },
|
||||
})
|
||||
}
|
||||
|
||||
if (assignment.assetId) {
|
||||
await AssetService.update(assignment.assetId, {
|
||||
status: "AVAILABLE",
|
||||
})
|
||||
}
|
||||
|
||||
await AssignmentService.delete(id)
|
||||
|
||||
await MovementService.create({
|
||||
type: "RETURN",
|
||||
quantity: assignment.quantity || 1,
|
||||
itemId: assignment.itemId || undefined,
|
||||
assetId: assignment.assetId || undefined,
|
||||
assignmentId: id,
|
||||
})
|
||||
|
||||
revalidatePath("/assignments")
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: "Assignment returned successfully",
|
||||
}
|
||||
}
|
||||
@@ -1,182 +0,0 @@
|
||||
"use server"
|
||||
|
||||
import { revalidatePath } from "next/cache"
|
||||
|
||||
import prisma from "@/lib/prisma"
|
||||
import {
|
||||
type CreateItemFormType,
|
||||
createItemSchema,
|
||||
type UpdateItemFormType,
|
||||
updateItemSchema,
|
||||
} from "@/lib/schemas/item.schemas"
|
||||
import { getAuthenticatedUserId } from "@/services/auth.service"
|
||||
import { ItemService } from "@/services/item.service"
|
||||
|
||||
export async function createItemAction(formData: CreateItemFormType) {
|
||||
const validatedFields = createItemSchema.safeParse(formData)
|
||||
|
||||
if (!validatedFields.success) {
|
||||
return {
|
||||
errors: validatedFields.error.flatten().fieldErrors,
|
||||
}
|
||||
}
|
||||
|
||||
const { name, categoryId, stock } = validatedFields.data
|
||||
|
||||
if (stock < 0) {
|
||||
return {
|
||||
success: false,
|
||||
errors: {
|
||||
stock: ["Stock cannot be negative"],
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const existingItem = await ItemService.findByName(name)
|
||||
|
||||
if (existingItem) {
|
||||
return {
|
||||
success: false,
|
||||
errors: {
|
||||
name: ["An item with this name already exists"],
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const item = await ItemService.create({
|
||||
name,
|
||||
category: { connect: { id: categoryId } },
|
||||
stock: stock || 0,
|
||||
})
|
||||
|
||||
if (stock > 0) {
|
||||
await prisma.movement.create({
|
||||
data: {
|
||||
type: "IN",
|
||||
itemId: item.id,
|
||||
userId: await getAuthenticatedUserId(),
|
||||
quantity: stock,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
revalidatePath("/inventory/items")
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: "Item created successfully!",
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Database error:", error)
|
||||
return {
|
||||
error: "Error creating item",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function updateItemAction(formData: UpdateItemFormType) {
|
||||
const validatedFields = updateItemSchema.safeParse(formData)
|
||||
|
||||
if (!validatedFields.success) {
|
||||
return {
|
||||
errors: validatedFields.error.flatten().fieldErrors,
|
||||
}
|
||||
}
|
||||
|
||||
const { id, stock, name, categoryId } = validatedFields.data
|
||||
|
||||
try {
|
||||
const existingItem = await ItemService.findByIdWithAssetCount(id)
|
||||
|
||||
if (!existingItem) {
|
||||
return {
|
||||
success: false,
|
||||
errors: {
|
||||
id: ["Item not found"],
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const existingItemByName = await ItemService.findByName(name)
|
||||
|
||||
if (existingItemByName && existingItemByName.id !== id) {
|
||||
return {
|
||||
success: false,
|
||||
errors: { name: ["An item with this name already exists"] },
|
||||
}
|
||||
}
|
||||
|
||||
await ItemService.update(id, {
|
||||
stock: stock || existingItem.stock,
|
||||
name: name || existingItem.name,
|
||||
category: { connect: { id: categoryId } },
|
||||
})
|
||||
|
||||
const quantity = stock - existingItem.stock
|
||||
|
||||
if (stock && stock > existingItem.stock) {
|
||||
await prisma.movement.create({
|
||||
data: {
|
||||
type: "IN",
|
||||
itemId: id,
|
||||
quantity,
|
||||
userId: await getAuthenticatedUserId(),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: "Item updated successfully!",
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Database error:", error)
|
||||
return {
|
||||
error: "Failed to update item",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function deleteItemAction(formData: FormData) {
|
||||
const { id } = Object.fromEntries(formData) as { id: string }
|
||||
|
||||
try {
|
||||
const existingItem = await ItemService.findByIdWithAssetCount(id)
|
||||
|
||||
if (!existingItem) {
|
||||
return {
|
||||
success: false,
|
||||
errors: { id: ["Item not found"] },
|
||||
}
|
||||
}
|
||||
|
||||
if (existingItem._count.assets > 0) {
|
||||
return {
|
||||
success: false,
|
||||
errors: { id: ["Item has assets, you cannot delete it"] },
|
||||
}
|
||||
}
|
||||
|
||||
if (existingItem.stock > 0) {
|
||||
return {
|
||||
success: false,
|
||||
errors: { id: ["Item has stock, you cannot delete it"] },
|
||||
}
|
||||
}
|
||||
|
||||
await ItemService.delete(id)
|
||||
|
||||
revalidatePath("/inventory/items")
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: "Item deleted successfully!",
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Database error:", error)
|
||||
return {
|
||||
error: "Failed to delete item",
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
import {
|
||||
type CreateMovementFormType,
|
||||
createMovementSchema,
|
||||
} from "../schemas/movement.schemas"
|
||||
|
||||
export async function createMovementAction(data: CreateMovementFormType) {
|
||||
const validatedFields = createMovementSchema.safeParse(data)
|
||||
|
||||
if (!validatedFields.success) {
|
||||
return {
|
||||
success: false,
|
||||
errors: validatedFields.error.flatten().fieldErrors,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,138 +0,0 @@
|
||||
"use server"
|
||||
|
||||
import { revalidatePath } from "next/cache"
|
||||
|
||||
import prisma from "@/lib/prisma"
|
||||
import {
|
||||
type CreateRecipientFormType,
|
||||
createRecipientSchema,
|
||||
type UpdateRecipientFormType,
|
||||
updateRecipientSchema,
|
||||
} from "@/lib/schemas/recipients.schemas"
|
||||
import { RecipientService } from "@/services/recipient.service"
|
||||
|
||||
export async function createNewRecipient(formData: CreateRecipientFormType) {
|
||||
const validatedFields = createRecipientSchema.safeParse(formData)
|
||||
|
||||
if (!validatedFields.success) {
|
||||
return {
|
||||
success: false,
|
||||
errors: validatedFields.error.flatten().fieldErrors,
|
||||
}
|
||||
}
|
||||
|
||||
const { username, firstName, lastName, department, email, phone } =
|
||||
validatedFields.data
|
||||
|
||||
try {
|
||||
const existingRecipientUsername =
|
||||
await RecipientService.findByUsername(username)
|
||||
|
||||
if (existingRecipientUsername) {
|
||||
return {
|
||||
success: false,
|
||||
errors: {
|
||||
username: ["Username already exists"],
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const existingRecipientEmail = await RecipientService.findByEmail(
|
||||
email || "",
|
||||
)
|
||||
|
||||
if (existingRecipientEmail) {
|
||||
return {
|
||||
success: false,
|
||||
errors: {
|
||||
email: ["Email already exists"],
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
await RecipientService.create({
|
||||
username: username || (firstName[0] + lastName).toLowerCase(),
|
||||
firstName,
|
||||
lastName,
|
||||
department: department,
|
||||
email: email || null,
|
||||
phone: phone || null,
|
||||
})
|
||||
|
||||
revalidatePath("/recipients")
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: "Recipient created successfully",
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Database error:", error)
|
||||
return {
|
||||
message: "Failed to create recipient",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function updateRecipient(formData: UpdateRecipientFormType) {
|
||||
const validatedFields = updateRecipientSchema.safeParse(formData)
|
||||
|
||||
if (!validatedFields.success) {
|
||||
return {
|
||||
success: false,
|
||||
errors: validatedFields.error.flatten().fieldErrors,
|
||||
}
|
||||
}
|
||||
|
||||
const { id, username, firstName, lastName, department, email, phone } =
|
||||
validatedFields.data
|
||||
|
||||
try {
|
||||
const existingRecipient = await RecipientService.findByUsername(username)
|
||||
|
||||
if (existingRecipient && existingRecipient.id !== id) {
|
||||
return {
|
||||
success: false,
|
||||
errors: {
|
||||
username: ["Username already exists"],
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const existingRecipientEmail = await RecipientService.findByEmail(
|
||||
email || "",
|
||||
)
|
||||
|
||||
if (existingRecipientEmail && existingRecipientEmail.id !== id) {
|
||||
return {
|
||||
success: false,
|
||||
errors: {
|
||||
email: ["Email already exists"],
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
await prisma.recipient.update({
|
||||
where: { id },
|
||||
data: {
|
||||
username,
|
||||
firstName,
|
||||
lastName,
|
||||
department: department,
|
||||
email: email || null,
|
||||
phone: phone || null,
|
||||
},
|
||||
})
|
||||
|
||||
revalidatePath("/recipients")
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: "Recipient updated successfully",
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Database error:", error)
|
||||
return {
|
||||
message: "Failed to update recipient",
|
||||
}
|
||||
}
|
||||
}
|
||||
+5
-3
@@ -4,12 +4,11 @@ import { ZodError } from "zod"
|
||||
|
||||
import type { UserRole } from "@/generated/prisma/client"
|
||||
import { SIGN_IN_URL, TOKEN_EXPIRATION_SECONDS } from "@/lib/constants"
|
||||
import { signInSchema } from "@/lib/schemas/auth.schemas"
|
||||
import { verifyPassword } from "@/lib/security"
|
||||
import { signInSchema } from "@/schemas/auth.schema"
|
||||
import { getUserByUsername } from "@/services/user.service"
|
||||
|
||||
declare module "next-auth" {
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
interface Session {
|
||||
user: {
|
||||
id: string
|
||||
@@ -17,7 +16,6 @@ declare module "next-auth" {
|
||||
} & DefaultSession["user"]
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
interface User {
|
||||
role: UserRole
|
||||
}
|
||||
@@ -46,6 +44,10 @@ export const { handlers, signIn, signOut, auth } = NextAuth({
|
||||
throw new Error("Invalid username or password")
|
||||
}
|
||||
|
||||
if (!user.isActive) {
|
||||
throw new Error("Invalid username or password")
|
||||
}
|
||||
|
||||
if (!(await verifyPassword(data.password, user.password)))
|
||||
throw new Error("Invalid username or password")
|
||||
|
||||
|
||||
+22
-1
@@ -3,7 +3,28 @@ const isDemo = process.env.DEMO_MODE === "true"
|
||||
export const ENVIRONMENT = isDemo
|
||||
? "demo"
|
||||
: process.env.NODE_ENV || "development"
|
||||
|
||||
|
||||
export const SIGN_IN_URL = "/login"
|
||||
|
||||
export const TOKEN_EXPIRATION_SECONDS = 60 * 60 * 2 // 2 hour
|
||||
|
||||
export const RECIPIENT_DEPARTMENTS = {
|
||||
IT: "IT",
|
||||
ENGINEERING: "ENGINEERING",
|
||||
LOGISTICS: "LOGISTICS",
|
||||
TRAFFIC: "TRAFFIC",
|
||||
DRIVER: "DRIVER",
|
||||
ADMINISTRATION: "ADMINISTRATION",
|
||||
SALES: "SALES",
|
||||
OTHER: "OTHER",
|
||||
} as const
|
||||
|
||||
export const ITEM_STATUS = {
|
||||
AVAILABLE: "AVAILABLE",
|
||||
ASSIGNED: "ASSIGNED",
|
||||
RESERVED: "RESERVED",
|
||||
IN_REPAIR: "IN_REPAIR",
|
||||
BROKEN: "BROKEN",
|
||||
STOLEN: "STOLEN",
|
||||
DISPOSED: "DISPOSED",
|
||||
} as const
|
||||
|
||||
+4
-5
@@ -1,10 +1,9 @@
|
||||
import type { Prisma } from "@/generated/prisma/client"
|
||||
import type { PaginatedResult } from "@/lib/types"
|
||||
import type { PaginatedResult } from "@/types"
|
||||
|
||||
//eslint-disable-next-line
|
||||
type PaginationArgs<T> = {
|
||||
model: any // prisma.<model>
|
||||
where?: Prisma.Enumerable<any> // filtros
|
||||
type PaginationArgs<_T> = {
|
||||
model: any
|
||||
where?: Prisma.Enumerable<any>
|
||||
page?: number
|
||||
pageSize?: number
|
||||
orderBy?: any
|
||||
|
||||
+11
-5
@@ -1,11 +1,17 @@
|
||||
import { PrismaClient } from "@/generated/prisma/client"
|
||||
import { PrismaPg } from "@prisma/adapter-pg"
|
||||
import { PrismaClient } from "../generated/prisma/client"
|
||||
|
||||
const globalForPrisma = global as unknown as {
|
||||
prisma: PrismaClient
|
||||
const rawDatabaseUrl = process.env.DATABASE_URL
|
||||
const databaseUrl = (rawDatabaseUrl ?? "").trim()
|
||||
if (!databaseUrl) {
|
||||
throw new Error("DATABASE_URL is required")
|
||||
}
|
||||
|
||||
const prisma = globalForPrisma.prisma || new PrismaClient()
|
||||
const adapter = new PrismaPg({
|
||||
connectionString: databaseUrl,
|
||||
})
|
||||
|
||||
if (process.env.NODE_ENV !== "production") globalForPrisma.prisma = prisma
|
||||
const prisma = new PrismaClient({ adapter })
|
||||
|
||||
export { prisma }
|
||||
export default prisma
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
import { z } from "zod"
|
||||
|
||||
export const createItemSchema = z.object({
|
||||
name: z.string().min(1, {
|
||||
error: "Name is required"
|
||||
}),
|
||||
categoryId: z.string().min(1, {
|
||||
error: "Category is required"
|
||||
}),
|
||||
stock: z.coerce
|
||||
.number()
|
||||
.int()
|
||||
.nonnegative()
|
||||
.min(0, {
|
||||
error: "Stock is required"
|
||||
}),
|
||||
})
|
||||
|
||||
export type CreateItemFormType = z.infer<typeof createItemSchema>
|
||||
|
||||
export const updateItemSchema = createItemSchema.extend({
|
||||
id: z.string().min(1, {
|
||||
error: "Item is required"
|
||||
}),
|
||||
})
|
||||
|
||||
export type UpdateItemFormType = z.infer<typeof updateItemSchema>
|
||||
|
||||
export const getItemByIdSchema = z.object({
|
||||
id: z.string().min(1, {
|
||||
error: "Item is required"
|
||||
}),
|
||||
})
|
||||
|
||||
export type GetItemByIdFormType = z.infer<typeof getItemByIdSchema>
|
||||
@@ -1,24 +0,0 @@
|
||||
import type { Movement as PrismaMovement } from "@/generated/prisma/client"
|
||||
|
||||
import type { Asset } from "./asset"
|
||||
import type { Item } from "./item"
|
||||
import type { Recipient } from "./recipient"
|
||||
|
||||
export type Movement = PrismaMovement
|
||||
|
||||
export type MovementSummary = Pick<Movement, "id" | "type" | "quantity">
|
||||
|
||||
export type MovementWithItem = Movement & {
|
||||
item: Item | null
|
||||
}
|
||||
|
||||
export type MovementWithItemAndAsset = Movement & {
|
||||
item: Item | null
|
||||
asset: Asset | null
|
||||
}
|
||||
|
||||
export type MovementWithRecipientItemAsset = Movement & {
|
||||
recipient: Recipient | null
|
||||
item: Item | null
|
||||
asset: Asset | null
|
||||
}
|
||||
@@ -1,199 +0,0 @@
|
||||
// This is your Prisma schema file,
|
||||
// learn more about the docs: https://pris.ly/d/prisma-schema
|
||||
|
||||
// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions?
|
||||
// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init
|
||||
|
||||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
output = "../generated/prisma/client"
|
||||
binaryTargets = ["native", "debian-openssl-1.1.x"]
|
||||
}
|
||||
|
||||
datasource db {
|
||||
provider = "postgresql"
|
||||
url = env("DATABASE_URL")
|
||||
}
|
||||
|
||||
// Enum para los roles de usuario en la aplicación
|
||||
enum UserRole {
|
||||
ADMIN // Administrador con control total
|
||||
MANAGER // Gerente con permisos de gestión
|
||||
STAFF // Personal con permisos operativos
|
||||
VIEWER // Solo lectura
|
||||
}
|
||||
|
||||
// Modelo para los usuarios de la aplicación
|
||||
model User {
|
||||
id String @id @default(uuid())
|
||||
username String @unique // Nombre de usuario único para login
|
||||
name String // Nombre completo del usuario
|
||||
email String @unique // Email único para el usuario
|
||||
password String // Contraseña (debe ser hasheada)
|
||||
role UserRole @default(STAFF) // Rol del usuario, por defecto STAFF
|
||||
isActive Boolean @default(true) // Indica si la cuenta está activa
|
||||
createdAt DateTime @default(now()) // Fecha de creación del registro
|
||||
updatedAt DateTime @updatedAt // Fecha de última actualización del registro
|
||||
movements Movement[] // Relación con los movimientos realizados por este usuario
|
||||
assignments Assignment[] // Relación con las asignaciones creadas por este usuario
|
||||
}
|
||||
|
||||
// Enum para los departamentos de los destinatarios
|
||||
enum RecipientDepartment {
|
||||
IT
|
||||
ENGINEERING // Cambiado de ING a ENGINEERING para mayor claridad
|
||||
LOGISTICS // Cambiado de LNG a LOGISTICS
|
||||
TRAFFIC
|
||||
DRIVER
|
||||
ADMINISTRATION
|
||||
SALES
|
||||
OTHER
|
||||
}
|
||||
|
||||
// Modelo para los destinatarios de los ítems (personas o áreas a las que se asignan cosas)
|
||||
model Recipient {
|
||||
id String @id @default(uuid())
|
||||
username String @unique // Nombre de usuario o identificador único del destinatario
|
||||
firstName String // Nombre del destinatario
|
||||
lastName String // Apellido del destinatario
|
||||
department RecipientDepartment? // Departamento del destinatario, usando el enum
|
||||
email String? @unique // Email opcional del destinatario
|
||||
phone String? // Teléfono opcional del destinatario
|
||||
isActive Boolean @default(true) // Indica si el destinatario está activo
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt // Fecha de última actualización del registro
|
||||
assignments Assignment[] // Relación con las asignaciones de ítems a este destinatario
|
||||
movements Movement[] // Relación con los movimientos de ítems relacionados con este destinatario
|
||||
|
||||
@@index([lastName, firstName]) // Índice para búsquedas por nombre y apellido
|
||||
@@index([department]) // Nuevo índice para búsquedas por departamento
|
||||
}
|
||||
|
||||
// Modelo para las categorías de ítems
|
||||
model Category {
|
||||
id String @id @default(uuid())
|
||||
name String @unique // Nombre único de la categoría
|
||||
description String? // Descripción opcional de la categoría
|
||||
isActive Boolean @default(true) // Indica si la categoría está activa
|
||||
items Item[] // Relación con los productos (ítems genéricos) de esta categoría
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt // Fecha de última actualización del registro
|
||||
|
||||
@@index([name]) // Índice para búsquedas por nombre de categoría
|
||||
}
|
||||
|
||||
// Enum para el estado de un ítem (ya sea Item o Asset)
|
||||
enum ItemStatus {
|
||||
AVAILABLE // Disponible en stock
|
||||
ASSIGNED // Asignado a un destinatario
|
||||
RESERVED // Reservado para una asignación futura
|
||||
IN_REPAIR // En reparación
|
||||
BROKEN // Averiado e inutilizable
|
||||
STOLEN // Robado
|
||||
DISPOSED // Dado de baja/eliminado del inventario
|
||||
}
|
||||
|
||||
// Modelo para ítems genéricos (sin número de serie individual, se gestionan por cantidad)
|
||||
model Item {
|
||||
id String @id @default(uuid())
|
||||
name String // Nombre del producto
|
||||
description String? // Descripción opcional del producto
|
||||
categoryId String // ID de la categoría a la que pertenece el producto
|
||||
category Category @relation(fields: [categoryId], references: [id]) // Relación con la categoría
|
||||
stock Int @default(0) // Cantidad actual en stock
|
||||
minStock Int? // Nivel mínimo de stock para alertas
|
||||
maxStock Int? // Nivel máximo de stock deseado
|
||||
createdAt DateTime @default(now()) // Fecha de creación del registro
|
||||
updatedAt DateTime @updatedAt // Fecha de última actualización del registro
|
||||
deletedAt DateTime? // Fecha de eliminación del registro
|
||||
movements Movement[] // Relación con los movimientos de este producto
|
||||
assignments Assignment[] // Relación con las asignaciones de este producto (por cantidad)
|
||||
assets Asset[] // Relación con los activos serializados que son de este tipo de producto
|
||||
|
||||
@@index([categoryId]) // Índice para búsquedas por categoría
|
||||
@@index([name]) // Índice para búsquedas por nombre de producto
|
||||
}
|
||||
|
||||
// Modelo para ítems serializados (activos individuales con número de serie único)
|
||||
model Asset {
|
||||
id String @id @default(uuid())
|
||||
itemId String? // ID del producto genérico al que pertenece este activo (opcional)
|
||||
item Item? @relation(fields: [itemId], references: [id]) // Relación con el producto genérico
|
||||
serialNumber String @unique // Número de serie único y obligatorio para el activo
|
||||
deliveryNote String? // Número de albarán de entrega (opcional, puede ser para la entrada inicial)
|
||||
status ItemStatus @default(AVAILABLE) // Estado actual del activo individual
|
||||
notes String? // Notas adicionales sobre el activo
|
||||
createdAt DateTime @default(now()) // Fecha de creación del registro
|
||||
updatedAt DateTime @updatedAt // Fecha de última actualización del registro
|
||||
movements Movement[] // Relación con los movimientos de este activo
|
||||
assignment Assignment? // Relación 1:1 con la asignación activa de este activo (un activo solo puede estar en una asignación activa)
|
||||
|
||||
@@index([serialNumber]) // Índice para búsquedas por número de serie
|
||||
@@index([itemId]) // Índice para búsquedas por producto asociado
|
||||
@@index([status]) // Índice para búsquedas por estado del activo
|
||||
}
|
||||
|
||||
// Modelo para registrar las asignaciones de ítems a destinatarios
|
||||
model Assignment {
|
||||
id String @id @default(uuid())
|
||||
quantity Int? // Cantidad asignada (solo si es un Item, para Asset sería 1 implícitamente)
|
||||
notes String? // Notas sobre la asignación
|
||||
itemId String? // ID del producto genérico asignado (si no es un activo serializado)
|
||||
item Item? @relation(fields: [itemId], references: [id]) // Relación con el producto
|
||||
assetId String? @unique // ID del activo serializado asignado (si es un activo, debe ser único para asignaciones activas)
|
||||
asset Asset? @relation(fields: [assetId], references: [id]) // Relación con el activo
|
||||
recipientId String? // ID del destinatario de la asignación
|
||||
recipient Recipient? @relation(fields: [recipientId], references: [id], onDelete: Cascade, onUpdate: Cascade) // Relación con el destinatario
|
||||
assignmentDate DateTime @default(now()) // Fecha en que se realizó la asignación
|
||||
returnDate DateTime? // Fecha en que se devolvió la asignación (si aplica)
|
||||
createdBy String // ID del usuario que realizó la asignación
|
||||
createdUser User @relation(fields: [createdBy], references: [id]) // Relación con el usuario que creó la asignación
|
||||
createdAt DateTime @default(now()) // Fecha de creación del registro de asignación
|
||||
updatedAt DateTime @updatedAt // Fecha de última actualización del registro
|
||||
movement Movement[] // Relación con los movimientos generados por esta asignación (ej. OUT, RETURN)
|
||||
|
||||
// Índices para mejorar el rendimiento de las consultas
|
||||
@@index([itemId])
|
||||
@@index([assetId])
|
||||
@@index([recipientId])
|
||||
@@index([createdBy])
|
||||
}
|
||||
|
||||
// Enum para los tipos de movimiento de stock
|
||||
enum MovementType {
|
||||
IN // Entrada de stock (compra, fabricación)
|
||||
OUT // Salida de stock (venta, consumo)
|
||||
ASSIGNMENT // Movimiento asociado a una asignación
|
||||
RETURN // Movimiento asociado a la devolución de una asignación
|
||||
ADJUSTMENT // Ajuste de inventario (corrección, pérdida)
|
||||
DELETED // Eliminación de un ítem
|
||||
}
|
||||
|
||||
// Modelo para el histórico de todos los movimientos de stock/activos
|
||||
model Movement {
|
||||
id String @id @default(uuid())
|
||||
type MovementType @default(IN) // Tipo de movimiento
|
||||
quantity Int // Cantidad del movimiento (para Item, para Asset sería 1)
|
||||
details String? // Detalles adicionales del movimiento
|
||||
notes String? // Notas sobre el movimiento
|
||||
itemId String? // ID del producto afectado (si es un Item)
|
||||
item Item? @relation(fields: [itemId], references: [id]) // Relación con el producto
|
||||
assetId String? // ID del activo afectado (si es un Asset)
|
||||
asset Asset? @relation(fields: [assetId], references: [id]) // Relación con el activo
|
||||
previousStock Int? // Stock antes de este movimiento (solo para Item)
|
||||
newStock Int? // Stock después de este movimiento (solo para Item)
|
||||
recipientId String? // ID del destinatario relacionado con el movimiento (si aplica)
|
||||
recipient Recipient? @relation(fields: [recipientId], references: [id]) // Relación con el destinatario
|
||||
assignmentId String? // ID de la asignación relacionada (si el movimiento es ASSIGNMENT o RETURN)
|
||||
assignment Assignment? @relation(fields: [assignmentId], references: [id]) // Relación con la asignación
|
||||
userId String // ID del usuario que realizó el movimiento
|
||||
user User @relation(fields: [userId], references: [id]) // Relación con el usuario
|
||||
createdAt DateTime @default(now()) // Fecha en que se registró el movimiento
|
||||
|
||||
// Índices para mejorar el rendimiento de las consultas
|
||||
@@index([itemId])
|
||||
@@index([assetId])
|
||||
@@index([recipientId])
|
||||
@@index([type])
|
||||
@@index([userId])
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user