From 77b369be6182aba0a69230ced17b9aa483fc0a4d Mon Sep 17 00:00:00 2001 From: ritikhaashok Date: Thu, 23 Apr 2026 13:45:58 -0500 Subject: [PATCH 01/13] changes --- package-lock.json | 111 +++++-- .../20260129194131_init/migration.sql | 66 ++++ .../20260217005051_add_gad/migration.sql | 36 ++ .../migrations/20260226040142/migration.sql | 123 +++++++ .../20260226042411_add_image/migration.sql | 203 ++++++++++++ .../migrations/20260226060301/migration.sql | 14 + .../20260226072412_appointments/migration.sql | 26 ++ .../migration.sql | 3 + .../migrations/20260409203356/migration.sql | 310 ++++++++++++++++++ 9 files changed, 873 insertions(+), 19 deletions(-) create mode 100644 prisma/migrations/20260129194131_init/migration.sql create mode 100644 prisma/migrations/20260217005051_add_gad/migration.sql create mode 100644 prisma/migrations/20260226040142/migration.sql create mode 100644 prisma/migrations/20260226042411_add_image/migration.sql create mode 100644 prisma/migrations/20260226060301/migration.sql create mode 100644 prisma/migrations/20260226072412_appointments/migration.sql create mode 100644 prisma/migrations/20260409184455_add_recurring_fields/migration.sql create mode 100644 prisma/migrations/20260409203356/migration.sql diff --git a/package-lock.json b/package-lock.json index 24be3b6..4acd9dd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,8 +16,10 @@ "@prisma/adapter-better-sqlite3": "^7.2.0", "@prisma/client": "^7.2.0", "@tiptap/extension-text-align": "^3.20.1", + "@types/dompurify": "^3.2.0", "@types/nodemailer": "^7.0.4", "better-auth": "^1.4.7", + "dompurify": "^3.3.3", "dotenv": "^17.2.3", "marked": "^17.0.4", "nodemailer": "^7.0.11", @@ -90,6 +92,7 @@ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", @@ -463,6 +466,7 @@ "version": "1.4.18", "resolved": "https://registry.npmjs.org/@better-auth/core/-/core-1.4.18.tgz", "integrity": "sha512-q+awYgC7nkLEBdx2sW0iJjkzgSHlIxGnOpsN1r/O1+a4m7osJNHtfK2mKJSL1I+GfNyIlxJF8WvD/NLuYMpmcg==", + "peer": true, "dependencies": { "@standard-schema/spec": "^1.0.0", "zod": "^4.3.5" @@ -492,12 +496,14 @@ "version": "0.3.0", "resolved": "https://registry.npmjs.org/@better-auth/utils/-/utils-0.3.0.tgz", "integrity": "sha512-W+Adw6ZA6mgvnSnhOki270rwJ42t4XzSK6YWGF//BbVXL6SwCLWfyzBc1lN2m/4RM28KubdBKQ4X5VMoLRNPQw==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@better-fetch/fetch": { "version": "1.1.21", "resolved": "https://registry.npmjs.org/@better-fetch/fetch/-/fetch-1.1.21.tgz", - "integrity": "sha512-/ImESw0sskqlVR94jB+5+Pxjf+xBwDZF/N5+y2/q4EqD7IARUTSpPfIo8uf39SYpCxyOCtbyYpUrZ3F/k0zT4A==" + "integrity": "sha512-/ImESw0sskqlVR94jB+5+Pxjf+xBwDZF/N5+y2/q4EqD7IARUTSpPfIo8uf39SYpCxyOCtbyYpUrZ3F/k0zT4A==", + "peer": true }, "node_modules/@bomb.sh/tab": { "version": "0.0.14", @@ -642,7 +648,8 @@ "resolved": "https://registry.npmjs.org/@electric-sql/pglite/-/pglite-0.3.15.tgz", "integrity": "sha512-Cj++n1Mekf9ETfdc16TlDi+cDDQF0W7EcbyRHYOAeZdsAe8M/FJg18itDTSwyHfar2WIezawM9o0EKaRGVKygQ==", "devOptional": true, - "license": "Apache-2.0" + "license": "Apache-2.0", + "peer": true }, "node_modules/@electric-sql/pglite-socket": { "version": "0.0.20", @@ -1128,6 +1135,7 @@ "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.6.tgz", "integrity": "sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==", "license": "MIT", + "peer": true, "dependencies": { "@floating-ui/core": "^1.7.5", "@floating-ui/utils": "^0.2.11" @@ -1889,6 +1897,7 @@ "resolved": "https://registry.npmjs.org/@nuxt/kit/-/kit-4.4.2.tgz", "integrity": "sha512-5+IPRNX2CjkBhuWUwz0hBuLqiaJPRoKzQ+SvcdrQDbAyE+VDeFt74VpSFr5/R0ujrK4b+XnSHUJWdS72w6hsog==", "license": "MIT", + "peer": true, "dependencies": { "c12": "^3.3.3", "consola": "^3.4.2", @@ -3703,6 +3712,7 @@ "resolved": "https://registry.npmjs.org/@prisma/client/-/client-7.3.0.tgz", "integrity": "sha512-FXBIxirqQfdC6b6HnNgxGmU7ydCPEPk7maHMOduJJfnTP+MuOGa15X4omjR/zpPUUpm8ef/mEFQjJudOGkXFcQ==", "license": "Apache-2.0", + "peer": true, "dependencies": { "@prisma/client-runtime-utils": "7.3.0" }, @@ -4857,6 +4867,7 @@ "resolved": "https://registry.npmjs.org/@tiptap/core/-/core-3.20.5.tgz", "integrity": "sha512-Pkjd41UJ4F6Z8cPV+gEvqnt1VhY2g66xMjbpxREs0ECA5jRezCNKSZcc2pueQRTMtmn1SaSzGM9U/ifhVlVYOA==", "license": "MIT", + "peer": true, "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" @@ -4953,6 +4964,7 @@ "resolved": "https://registry.npmjs.org/@tiptap/extension-collaboration/-/extension-collaboration-3.20.5.tgz", "integrity": "sha512-IalIm6BznHds2VzR4+6gMAgi4VXwZAXdYkl28EPZ8/xscBaUn1tCxcTBbCpmN3UhkABaCoJtmmER5TDy+x72Ag==", "license": "MIT", + "peer": true, "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" @@ -4982,6 +4994,7 @@ "resolved": "https://registry.npmjs.org/@tiptap/extension-drag-handle/-/extension-drag-handle-3.20.5.tgz", "integrity": "sha512-D2W2fkpmXKRG4i0K0XVfbsTRYQMU9RudQIXBB7HnYZFosyJs3dvsT1cFurDUANKLPCxbI24eiubAKs6b1vzGpA==", "license": "MIT", + "peer": true, "dependencies": { "@floating-ui/dom": "^1.6.13" }, @@ -5142,6 +5155,7 @@ "resolved": "https://registry.npmjs.org/@tiptap/extension-list/-/extension-list-3.20.5.tgz", "integrity": "sha512-s+Y8Q7Orq+WQiwgFB/VPMYZe+6EAR2F69xCpvOynlzTInLO4cF6QpXomuGEYAZxLHe8ZBmeIaR7y8MH/OgjrDw==", "license": "MIT", + "peer": true, "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" @@ -5197,6 +5211,7 @@ "resolved": "https://registry.npmjs.org/@tiptap/extension-node-range/-/extension-node-range-3.20.5.tgz", "integrity": "sha512-6CbgZULF+dQ9KTothAORBZAXPdGneWicMWTV3Gyeh9gNySC18QsGQj3D2GxnllpMekmZXydtDbNFSoCiWjKFWQ==", "license": "MIT", + "peer": true, "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" @@ -5302,6 +5317,7 @@ "resolved": "https://registry.npmjs.org/@tiptap/extensions/-/extensions-3.20.5.tgz", "integrity": "sha512-c4am6SznqfMnbUNSh4MvufiD7cMLdqL1BArok22uBgSWkS1sB9RVBYe8+x0jrOkk0UPEVlzDHbQ+nU+WmIyS2Q==", "license": "MIT", + "peer": true, "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" @@ -5333,6 +5349,7 @@ "resolved": "https://registry.npmjs.org/@tiptap/pm/-/pm-3.20.5.tgz", "integrity": "sha512-yJhDa7Chx2EqJMX/jlewBv0za7slf1dKHWYve1XaApuVHEkxl0Ul3EDbwnx316vIITkuFW/pWSwkSsAplyBeCw==", "license": "MIT", + "peer": true, "dependencies": { "prosemirror-changeset": "^2.3.0", "prosemirror-collab": "^1.3.1", @@ -5399,6 +5416,7 @@ "resolved": "https://registry.npmjs.org/@tiptap/suggestion/-/suggestion-3.20.5.tgz", "integrity": "sha512-5fqRNgnzYdJ1oDpyLqwrbVsZwvI+5VW/U89LPMvBYM7sFS7Xd0xfyxyAOWcJN4V0zLeTcuElWN3R+IUTLKbU+Q==", "license": "MIT", + "peer": true, "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" @@ -5413,6 +5431,7 @@ "resolved": "https://registry.npmjs.org/@tiptap/vue-3/-/vue-3-3.20.5.tgz", "integrity": "sha512-5uUK3RAMNvUetZOv56Kz8nurhxHxMH60GgCCrVFgIBZoTc14u3d3v7EpcA6gNgzogutrR8GxvyFU3iIkj4kkHA==", "license": "MIT", + "peer": true, "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" @@ -5469,6 +5488,16 @@ "@types/node": "*" } }, + "node_modules/@types/dompurify": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@types/dompurify/-/dompurify-3.2.0.tgz", + "integrity": "sha512-Fgg31wv9QbLDA0SpTOXO3MaxySc4DKGLi8sna4/Utjo4r3ZRPdCt4UQee8BWr+Q5z21yifghREPJGYaEOEIACg==", + "deprecated": "This is a stub types definition. dompurify provides its own type definitions, so you do not need this installed.", + "license": "MIT", + "dependencies": { + "dompurify": "*" + } + }, "node_modules/@types/estree": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", @@ -5532,6 +5561,13 @@ "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==", "license": "MIT" }, + "node_modules/@types/trusted-types": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", + "license": "MIT", + "optional": true + }, "node_modules/@types/web-bluetooth": { "version": "0.0.21", "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.21.tgz", @@ -5868,6 +5904,7 @@ "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-14.2.1.tgz", "integrity": "sha512-3vwDzV+GDUNpdegRY6kzpLm4Igptq+GA0QkJ3W61Iv27YWwW/ufSlOfgQIpN6FZRMG0mkaz4gglJRtq5SeJyIQ==", "license": "MIT", + "peer": true, "dependencies": { "@types/web-bluetooth": "^0.0.21", "@vueuse/metadata": "14.2.1", @@ -5993,6 +6030,7 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -6333,6 +6371,7 @@ "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.8.2.tgz", "integrity": "sha512-riJjyv1/mHLIPX4RwiK+oW9/4c3TEUeORHKefKAKnZ5kyslbN+HXowtbaVEqt4IMUB7OXlfixcs6gsFeo/jhiQ==", "license": "Apache-2.0", + "peer": true, "peerDependencies": { "bare-abort-controller": "*" }, @@ -6556,6 +6595,7 @@ "resolved": "https://registry.npmjs.org/better-call/-/better-call-1.1.8.tgz", "integrity": "sha512-XMQ2rs6FNXasGNfMjzbyroSwKwYbZ/T3IxruSS6U2MJRsSYh3wYtG3o6H00ZlKZ/C/UPOAD97tqgQJNsxyeTXw==", "license": "MIT", + "peer": true, "dependencies": { "@better-auth/utils": "^0.3.0", "@better-fetch/fetch": "^1.1.4", @@ -6701,6 +6741,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", @@ -6802,6 +6843,7 @@ "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", "license": "MIT", + "peer": true, "engines": { "node": ">=8" } @@ -6919,6 +6961,7 @@ "resolved": "https://registry.npmjs.org/citty/-/citty-0.1.6.tgz", "integrity": "sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==", "license": "MIT", + "peer": true, "dependencies": { "consola": "^3.2.3" } @@ -6994,15 +7037,6 @@ "integrity": "sha512-Z3UPUKasUVDFCDYAjP2fmlVRf1jFHJv1izAmPjiOa0OCIw1W7iC8PZ2GsoDa8uZv+mKyWopxxStT9q05+27h7w==", "license": "Apache-2.0" }, - "node_modules/commander": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", - "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", - "license": "MIT", - "engines": { - "node": ">=16" - } - }, "node_modules/commondir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", @@ -7595,6 +7629,15 @@ "url": "https://github.com/fb55/domhandler?sponsor=1" } }, + "node_modules/dompurify": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.1.tgz", + "integrity": "sha512-JahakDAIg1gyOm7dlgWSDjV4n7Ip2PKR55NIT6jrMfIgLFgWo81vdr1/QGqWtFNRqXP9UV71oVePtjqS2ebnPw==", + "license": "(MPL-2.0 OR Apache-2.0)", + "optionalDependencies": { + "@types/trusted-types": "^2.0.7" + } + }, "node_modules/domutils": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", @@ -7675,7 +7718,8 @@ "version": "8.6.0", "resolved": "https://registry.npmjs.org/embla-carousel/-/embla-carousel-8.6.0.tgz", "integrity": "sha512-SjWyZBHJPbqxHOzckOfo8lHisEaJWmwd23XppYFYVh10bU66/Pn5tkVkbkCMZVdbUE5eTCI2nD8OyIP4Z+uwkA==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/embla-carousel-auto-height": { "version": "8.6.0", @@ -8252,6 +8296,7 @@ "resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-7.1.0.tgz", "integrity": "sha512-trLf4SzuuUxfusZADLINj+dE8clK1frKdmqiJNb1Es75fmI5oY6X2mxLVUciLLjxqw/xr72Dhy+lER6dGd02FQ==", "license": "Apache-2.0", + "peer": true, "engines": { "node": ">=10" } @@ -8505,6 +8550,7 @@ "integrity": "sha512-U7tt8JsyrxSRKspfhtLET79pU8K+tInj5QZXs1jSugO1Vq5dFj3kmZsRldo29mTBfcjDRVRXrEZ6LS63Cog9ZA==", "devOptional": true, "license": "MIT", + "peer": true, "engines": { "node": ">=16.9.0" } @@ -8898,7 +8944,6 @@ "resolved": "https://registry.npmjs.org/isomorphic.js/-/isomorphic.js-0.2.5.tgz", "integrity": "sha512-PIeMbHqMt4DnUP3MA/Flc0HElYjMXArsw1qwJZcm9sqR8mq3l8NYizFMty0pWwE/tzIGH3EKK5+jes5mAr85yw==", "license": "MIT", - "peer": true, "funding": { "type": "GitHub Sponsors โค", "url": "https://github.com/sponsors/dmonad" @@ -8933,6 +8978,7 @@ "resolved": "https://registry.npmjs.org/jose/-/jose-6.1.3.tgz", "integrity": "sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ==", "license": "MIT", + "peer": true, "funding": { "url": "https://github.com/sponsors/panva" } @@ -8996,6 +9042,7 @@ "resolved": "https://registry.npmjs.org/kysely/-/kysely-0.28.10.tgz", "integrity": "sha512-ksNxfzIW77OcZ+QWSAPC7yDqUSaIVwkTWnTPNiIy//vifNbwsSgQ57OkkncHxxpcBHM3LRfLAZVEh7kjq5twVA==", "license": "MIT", + "peer": true, "engines": { "node": ">=20.0.0" } @@ -9057,7 +9104,6 @@ "resolved": "https://registry.npmjs.org/lib0/-/lib0-0.2.117.tgz", "integrity": "sha512-DeXj9X5xDCjgKLU/7RR+/HQEVzuuEUiwldwOGsHK/sfAfELGWEyTcf0x+uOvCvK3O2zPmZePXWL85vtia6GyZw==", "license": "MIT", - "peer": true, "dependencies": { "isomorphic.js": "^0.2.4" }, @@ -9811,6 +9857,7 @@ "integrity": "sha512-FBrGau0IXmuqg4haEZRBfHNWB5mUARw6hNwPDXXGg0XzVJ50mr/9hb267lvpVMnhZ1FON3qNd4Xfcez1rbFwSg==", "devOptional": true, "license": "MIT", + "peer": true, "dependencies": { "aws-ssl-profiles": "^1.1.1", "denque": "^2.1.0", @@ -9867,6 +9914,7 @@ } ], "license": "MIT", + "peer": true, "engines": { "node": "^20.0.0 || >=22.0.0" } @@ -10203,6 +10251,7 @@ "resolved": "https://registry.npmjs.org/nuxt/-/nuxt-4.4.2.tgz", "integrity": "sha512-iWVFpr/YEqVU/CenqIHMnIkvb2HE/9f+q8oxZ+pj2et+60NljGRClCgnmbvGPdmNFE0F1bEhoBCYfqbDOCim3Q==", "license": "MIT", + "peer": true, "dependencies": { "@dxup/nuxt": "^0.4.0", "@nuxt/cli": "^3.34.0", @@ -10555,6 +10604,7 @@ "resolved": "https://registry.npmjs.org/oxc-parser/-/oxc-parser-0.117.0.tgz", "integrity": "sha512-l3cbgK5wUvWDVNWM/JFU77qDdGZK1wudnLsFcrRyNo/bL1CyU8pC25vDhMHikVY29lbK2InTWsX42RxVSutUdQ==", "license": "MIT", + "peer": true, "dependencies": { "@oxc-project/types": "^0.117.0" }, @@ -10754,6 +10804,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -11242,7 +11293,6 @@ "resolved": "https://registry.npmjs.org/preact/-/preact-10.12.1.tgz", "integrity": "sha512-l8386ixSsBdbreOAkqtrwqHwdvR35ID8c3rKPa8lCWuO86dBi32QWHV4vfsZK1utLLFMvw+Z5Ad4XLkZzchscg==", "license": "MIT", - "peer": true, "funding": { "type": "opencollective", "url": "https://opencollective.com/preact" @@ -11280,6 +11330,7 @@ "integrity": "sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==", "dev": true, "license": "MIT", + "peer": true, "bin": { "prettier": "bin/prettier.cjs" }, @@ -11388,6 +11439,7 @@ "devOptional": true, "hasInstallScript": true, "license": "Apache-2.0", + "peer": true, "dependencies": { "@prisma/config": "7.3.0", "@prisma/dev": "0.20.0", @@ -11561,6 +11613,7 @@ "resolved": "https://registry.npmjs.org/prosemirror-model/-/prosemirror-model-1.25.4.tgz", "integrity": "sha512-PIM7E43PBxKce8OQeezAs9j4TP+5yDpZVbuurd1h5phUxEKIu+G2a+EUZzIC5nS1mJktDJWzbqS23n1tsAf5QA==", "license": "MIT", + "peer": true, "dependencies": { "orderedmap": "^2.0.0" } @@ -11590,6 +11643,7 @@ "resolved": "https://registry.npmjs.org/prosemirror-state/-/prosemirror-state-1.4.4.tgz", "integrity": "sha512-6jiYHH2CIGbCfnxdHbXZ12gySFY/fz/ulZE333G6bPqIZ4F+TXo9ifiR86nAHpWnfoNjOb3o5ESi7J8Uz1jXHw==", "license": "MIT", + "peer": true, "dependencies": { "prosemirror-model": "^1.0.0", "prosemirror-transform": "^1.0.0", @@ -11650,6 +11704,7 @@ "resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.41.7.tgz", "integrity": "sha512-jUwKNCEIGiqdvhlS91/2QAg21e4dfU5bH2iwmSDQeosXJgKF7smG0YSplOWK0cjSNgIqXe7VXqo7EIfUFJdt3w==", "license": "MIT", + "peer": true, "dependencies": { "prosemirror-model": "^1.20.0", "prosemirror-state": "^1.0.0", @@ -12010,6 +12065,7 @@ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.60.0.tgz", "integrity": "sha512-yqjxruMGBQJ2gG4HtjZtAfXArHomazDHoFwFFmZZl0r7Pdo7qCIXKqKHZc8yeoMgzJJ+pO6pEEHa+V7uzWlrAQ==", "license": "MIT", + "peer": true, "dependencies": { "@types/estree": "1.0.8" }, @@ -12296,8 +12352,7 @@ "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", "devOptional": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/scule": { "version": "1.3.0", @@ -12827,6 +12882,15 @@ "url": "https://opencollective.com/svgo" } }, + "node_modules/svgo/node_modules/commander": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", + "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", + "license": "MIT", + "engines": { + "node": ">=16" + } + }, "node_modules/system-architecture": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/system-architecture/-/system-architecture-0.1.0.tgz", @@ -12856,6 +12920,7 @@ "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.5.0.tgz", "integrity": "sha512-I8K9wewnVDkL1NTGoqWmVEIlUcB9gFriAEkXkfCjX5ib8ezGxtR3xD7iZIxrfArjEsH7F1CHD4RFUtxefdqV/A==", "license": "MIT", + "peer": true, "funding": { "type": "github", "url": "https://github.com/sponsors/dcastil" @@ -12884,7 +12949,8 @@ "version": "4.2.2", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.2.2.tgz", "integrity": "sha512-KWBIxs1Xb6NoLdMVqhbhgwZf2PGBpPEiwOqgI4pFIYbNTfBXiKYyWoTsXgBQ9WFg/OlhnvHaY+AEpW7wSmFo2Q==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/tapable": { "version": "2.3.2", @@ -13130,6 +13196,7 @@ "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", "devOptional": true, "license": "MIT", + "peer": true, "dependencies": { "esbuild": "~0.27.0", "get-tsconfig": "^4.7.5" @@ -13610,6 +13677,7 @@ "integrity": "sha512-mm1rxUsmOxzrwnX5arGS+U4T25RdvpPjPN4yR0u9pUBov9+zGVtO84tif1eY4r6zWxVxu3KzIyknJy3rxfRZZg==", "devOptional": true, "license": "MIT", + "peer": true, "peerDependencies": { "typescript": ">=5" }, @@ -13732,6 +13800,7 @@ "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz", "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", "license": "MIT", + "peer": true, "dependencies": { "esbuild": "^0.27.0", "fdir": "^6.5.0", @@ -14087,6 +14156,7 @@ "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.31.tgz", "integrity": "sha512-iV/sU9SzOlmA/0tygSmjkEN6Jbs3nPoIPFhCMLD2STrjgOU8DX7ZtzMhg4ahVwf5Rp9KoFzcXeB1ZrVbLBp5/Q==", "license": "MIT", + "peer": true, "dependencies": { "@vue/compiler-dom": "3.5.31", "@vue/compiler-sfc": "3.5.31", @@ -14129,6 +14199,7 @@ "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.6.4.tgz", "integrity": "sha512-Hz9q5sa33Yhduglwz6g9skT8OBPii+4bFn88w6J+J4MfEo4KRRpmiNG/hHHkdbRFlLBOqxN8y8gf2Fb0MTUgVg==", "license": "MIT", + "peer": true, "dependencies": { "@vue/devtools-api": "^6.6.4" }, @@ -14327,6 +14398,7 @@ "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz", "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==", "license": "ISC", + "peer": true, "bin": { "yaml": "bin.mjs" }, @@ -14443,6 +14515,7 @@ "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz", "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", "license": "MIT", + "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/prisma/migrations/20260129194131_init/migration.sql b/prisma/migrations/20260129194131_init/migration.sql new file mode 100644 index 0000000..b547781 --- /dev/null +++ b/prisma/migrations/20260129194131_init/migration.sql @@ -0,0 +1,66 @@ +-- CreateTable +CREATE TABLE "user" ( + "id" TEXT NOT NULL PRIMARY KEY, + "name" TEXT NOT NULL, + "email" TEXT NOT NULL, + "emailVerified" BOOLEAN NOT NULL DEFAULT false, + "image" TEXT, + "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" DATETIME NOT NULL +); + +-- CreateTable +CREATE TABLE "session" ( + "id" TEXT NOT NULL PRIMARY KEY, + "expiresAt" DATETIME NOT NULL, + "token" TEXT NOT NULL, + "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" DATETIME NOT NULL, + "ipAddress" TEXT, + "userAgent" TEXT, + "userId" TEXT NOT NULL, + CONSTRAINT "session_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE +); + +-- CreateTable +CREATE TABLE "account" ( + "id" TEXT NOT NULL PRIMARY KEY, + "accountId" TEXT NOT NULL, + "providerId" TEXT NOT NULL, + "userId" TEXT NOT NULL, + "accessToken" TEXT, + "refreshToken" TEXT, + "idToken" TEXT, + "accessTokenExpiresAt" DATETIME, + "refreshTokenExpiresAt" DATETIME, + "scope" TEXT, + "password" TEXT, + "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" DATETIME NOT NULL, + CONSTRAINT "account_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE +); + +-- CreateTable +CREATE TABLE "verification" ( + "id" TEXT NOT NULL PRIMARY KEY, + "identifier" TEXT NOT NULL, + "value" TEXT NOT NULL, + "expiresAt" DATETIME NOT NULL, + "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" DATETIME NOT NULL +); + +-- CreateIndex +CREATE UNIQUE INDEX "user_email_key" ON "user"("email"); + +-- CreateIndex +CREATE INDEX "session_userId_idx" ON "session"("userId"); + +-- CreateIndex +CREATE UNIQUE INDEX "session_token_key" ON "session"("token"); + +-- CreateIndex +CREATE INDEX "account_userId_idx" ON "account"("userId"); + +-- CreateIndex +CREATE INDEX "verification_identifier_idx" ON "verification"("identifier"); diff --git a/prisma/migrations/20260217005051_add_gad/migration.sql b/prisma/migrations/20260217005051_add_gad/migration.sql new file mode 100644 index 0000000..278fd8e --- /dev/null +++ b/prisma/migrations/20260217005051_add_gad/migration.sql @@ -0,0 +1,36 @@ +-- CreateTable +CREATE TABLE "GadForm" ( + "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + "userId" TEXT NOT NULL, + "status" TEXT NOT NULL DEFAULT 'IN_PROGRESS', + "totalScore" INTEGER, + "severity" TEXT, + "submittedAt" DATETIME, + CONSTRAINT "GadForm_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE +); + +-- CreateTable +CREATE TABLE "GadQuestion" ( + "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + "formId" INTEGER NOT NULL, + "userId" TEXT NOT NULL, + "g01" INTEGER, + "g02" INTEGER, + "g03" INTEGER, + "g04" INTEGER, + "g05" INTEGER, + "g06" INTEGER, + "g07" INTEGER, + "g08" INTEGER, + CONSTRAINT "GadQuestion_formId_fkey" FOREIGN KEY ("formId") REFERENCES "GadForm" ("id") ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT "GadQuestion_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE +); + +-- CreateIndex +CREATE INDEX "GadForm_userId_idx" ON "GadForm"("userId"); + +-- CreateIndex +CREATE UNIQUE INDEX "GadQuestion_formId_key" ON "GadQuestion"("formId"); + +-- CreateIndex +CREATE INDEX "GadQuestion_userId_idx" ON "GadQuestion"("userId"); diff --git a/prisma/migrations/20260226040142/migration.sql b/prisma/migrations/20260226040142/migration.sql new file mode 100644 index 0000000..38b3e29 --- /dev/null +++ b/prisma/migrations/20260226040142/migration.sql @@ -0,0 +1,123 @@ +/* + Warnings: + + - You are about to drop the `GadForm` table. If the table is not empty, all the data it contains will be lost. + - You are about to drop the `GadQuestion` table. If the table is not empty, all the data it contains will be lost. + - You are about to drop the column `image` on the `user` table. All the data in the column will be lost. + +*/ +-- DropIndex +DROP INDEX "GadForm_userId_idx"; + +-- DropIndex +DROP INDEX "GadQuestion_userId_idx"; + +-- DropIndex +DROP INDEX "GadQuestion_formId_key"; + +-- DropTable +PRAGMA foreign_keys=off; +DROP TABLE "GadForm"; +PRAGMA foreign_keys=on; + +-- DropTable +PRAGMA foreign_keys=off; +DROP TABLE "GadQuestion"; +PRAGMA foreign_keys=on; + +-- CreateTable +CREATE TABLE "AppForm" ( + "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + "userId" TEXT NOT NULL, + "status" TEXT NOT NULL DEFAULT 'IN_PROGRESS', + "submittedAt" DATETIME, + CONSTRAINT "AppForm_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE +); + +-- CreateTable +CREATE TABLE "AppQuestion" ( + "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + "formId" INTEGER NOT NULL, + "userId" TEXT NOT NULL, + "q01" TEXT, + "q02" TEXT, + "q03" TEXT, + "q04" TEXT, + "q05" TEXT, + "q06" TEXT, + "q07" TEXT, + "q08" TEXT, + "q09" TEXT, + "q10" TEXT, + "q11" TEXT, + "q12" TEXT, + "q13" TEXT, + "q14" TEXT, + "q15" TEXT, + "q16" TEXT, + "q17" TEXT, + "q18" TEXT, + "q19" TEXT, + "q20" TEXT, + "q21" TEXT, + "q22" TEXT, + "q23" TEXT, + "q24" TEXT, + "q25" TEXT, + "q26" TEXT, + "q27" TEXT, + "q28" TEXT, + "q29" TEXT, + "q30" TEXT, + "q31" TEXT, + "q32" TEXT, + "q33" TEXT, + "q34" TEXT, + "q35" TEXT, + "q36" TEXT, + "q37" TEXT, + "q38" TEXT, + "q39" TEXT, + "q40" TEXT, + "q41" TEXT, + "q42" TEXT, + "q43" TEXT, + "q44" TEXT, + "q45" TEXT, + "q46" TEXT, + "q47" TEXT, + "q48" TEXT, + "q49" TEXT, + "q50" TEXT, + CONSTRAINT "AppQuestion_formId_fkey" FOREIGN KEY ("formId") REFERENCES "AppForm" ("id") ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT "AppQuestion_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE +); + +-- RedefineTables +PRAGMA defer_foreign_keys=ON; +PRAGMA foreign_keys=OFF; +CREATE TABLE "new_user" ( + "id" TEXT NOT NULL PRIMARY KEY, + "name" TEXT NOT NULL, + "email" TEXT NOT NULL, + "emailVerified" BOOLEAN NOT NULL DEFAULT false, + "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" DATETIME NOT NULL, + "role" TEXT NOT NULL DEFAULT 'CLIENT', + "phoneNumber" INTEGER +); +INSERT INTO "new_user" ("createdAt", "email", "emailVerified", "id", "name", "updatedAt") SELECT "createdAt", "email", "emailVerified", "id", "name", "updatedAt" FROM "user"; +DROP TABLE "user"; +ALTER TABLE "new_user" RENAME TO "user"; +CREATE UNIQUE INDEX "user_email_key" ON "user"("email"); +PRAGMA foreign_keys=ON; +PRAGMA defer_foreign_keys=OFF; + +-- CreateIndex +CREATE UNIQUE INDEX "AppForm_userId_key" ON "AppForm"("userId"); + +-- CreateIndex +CREATE UNIQUE INDEX "AppQuestion_formId_key" ON "AppQuestion"("formId"); + +-- CreateIndex +CREATE INDEX "AppQuestion_userId_idx" ON "AppQuestion"("userId"); diff --git a/prisma/migrations/20260226042411_add_image/migration.sql b/prisma/migrations/20260226042411_add_image/migration.sql new file mode 100644 index 0000000..b34507c --- /dev/null +++ b/prisma/migrations/20260226042411_add_image/migration.sql @@ -0,0 +1,203 @@ +-- AlterTable +ALTER TABLE "user" ADD COLUMN "image" TEXT; + +-- CreateTable +CREATE TABLE "form" ( + "id" TEXT NOT NULL PRIMARY KEY, + "title" TEXT NOT NULL, + "description" TEXT, + "slug" TEXT NOT NULL, + "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" DATETIME NOT NULL +); + +-- CreateTable +CREATE TABLE "question" ( + "id" TEXT NOT NULL PRIMARY KEY, + "text" TEXT NOT NULL, + "type" TEXT NOT NULL, + "alias" TEXT NOT NULL, + "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" DATETIME NOT NULL +); + +-- CreateTable +CREATE TABLE "form_question" ( + "id" TEXT NOT NULL PRIMARY KEY, + "formId" TEXT NOT NULL, + "questionId" TEXT NOT NULL, + "order" INTEGER NOT NULL, + CONSTRAINT "form_question_formId_fkey" FOREIGN KEY ("formId") REFERENCES "form" ("id") ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT "form_question_questionId_fkey" FOREIGN KEY ("questionId") REFERENCES "question" ("id") ON DELETE CASCADE ON UPDATE CASCADE +); + +-- CreateTable +CREATE TABLE "form_assignment" ( + "id" TEXT NOT NULL PRIMARY KEY, + "userId" TEXT NOT NULL, + "formId" TEXT NOT NULL, + "assignedAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + "completedAt" DATETIME, + CONSTRAINT "form_assignment_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT "form_assignment_formId_fkey" FOREIGN KEY ("formId") REFERENCES "form" ("id") ON DELETE CASCADE ON UPDATE CASCADE +); + +-- CreateTable +CREATE TABLE "ace_response" ( + "id" TEXT NOT NULL PRIMARY KEY, + "userId" TEXT NOT NULL, + "responses" TEXT NOT NULL, + "completedAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + CONSTRAINT "ace_response_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE +); + +-- CreateTable +CREATE TABLE "GadForm" ( + "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + "userId" TEXT NOT NULL, + "status" TEXT NOT NULL DEFAULT 'IN_PROGRESS', + "totalScore" INTEGER, + "severity" TEXT, + "submittedAt" DATETIME, + CONSTRAINT "GadForm_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE +); + +-- CreateTable +CREATE TABLE "GadQuestion" ( + "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + "formId" INTEGER NOT NULL, + "userId" TEXT NOT NULL, + "g01" INTEGER, + "g02" INTEGER, + "g03" INTEGER, + "g04" INTEGER, + "g05" INTEGER, + "g06" INTEGER, + "g07" INTEGER, + "g08" INTEGER, + CONSTRAINT "GadQuestion_formId_fkey" FOREIGN KEY ("formId") REFERENCES "GadForm" ("id") ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT "GadQuestion_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE +); + +-- CreateTable +CREATE TABLE "PhqForm" ( + "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + "userId" TEXT NOT NULL, + "status" TEXT NOT NULL DEFAULT 'IN_PROGRESS', + "totalScore" INTEGER, + "submittedAt" DATETIME, + CONSTRAINT "PhqForm_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE +); + +-- CreateTable +CREATE TABLE "PhqQuestion" ( + "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + "formId" INTEGER NOT NULL, + "userId" TEXT NOT NULL, + "q1" INTEGER, + "q2" INTEGER, + "q3" INTEGER, + "q4" INTEGER, + "q5" INTEGER, + "q6" INTEGER, + "q7" INTEGER, + "q8" INTEGER, + "q9" INTEGER, + CONSTRAINT "PhqQuestion_formId_fkey" FOREIGN KEY ("formId") REFERENCES "PhqForm" ("id") ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT "PhqQuestion_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE +); + +-- CreateTable +CREATE TABLE "PclForm" ( + "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + "userId" TEXT NOT NULL, + "status" TEXT NOT NULL DEFAULT 'IN_PROGRESS', + "submittedAt" DATETIME, + CONSTRAINT "PclForm_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE +); + +-- CreateTable +CREATE TABLE "PclQuestion" ( + "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + "formId" INTEGER NOT NULL, + "userId" TEXT NOT NULL, + "q01" INTEGER, + "q02" INTEGER, + "q03" INTEGER, + "q04" INTEGER, + "q05" INTEGER, + "q06" INTEGER, + "q07" INTEGER, + "q08" INTEGER, + "q09" INTEGER, + "q10" INTEGER, + "q11" INTEGER, + "q12" INTEGER, + "q13" INTEGER, + "q14" INTEGER, + "q15" INTEGER, + "q16" INTEGER, + "q17" INTEGER, + "q18" INTEGER, + "q19" INTEGER, + "q20" INTEGER, + CONSTRAINT "PclQuestion_formId_fkey" FOREIGN KEY ("formId") REFERENCES "PclForm" ("id") ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT "PclQuestion_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE +); + +-- CreateIndex +CREATE UNIQUE INDEX "form_slug_key" ON "form"("slug"); + +-- CreateIndex +CREATE UNIQUE INDEX "question_alias_key" ON "question"("alias"); + +-- CreateIndex +CREATE INDEX "form_question_formId_idx" ON "form_question"("formId"); + +-- CreateIndex +CREATE INDEX "form_question_questionId_idx" ON "form_question"("questionId"); + +-- CreateIndex +CREATE UNIQUE INDEX "form_question_formId_questionId_key" ON "form_question"("formId", "questionId"); + +-- CreateIndex +CREATE INDEX "form_assignment_userId_idx" ON "form_assignment"("userId"); + +-- CreateIndex +CREATE INDEX "form_assignment_formId_idx" ON "form_assignment"("formId"); + +-- CreateIndex +CREATE UNIQUE INDEX "form_assignment_userId_formId_key" ON "form_assignment"("userId", "formId"); + +-- CreateIndex +CREATE INDEX "ace_response_userId_idx" ON "ace_response"("userId"); + +-- CreateIndex +CREATE INDEX "GadForm_userId_idx" ON "GadForm"("userId"); + +-- CreateIndex +CREATE UNIQUE INDEX "GadQuestion_formId_key" ON "GadQuestion"("formId"); + +-- CreateIndex +CREATE INDEX "GadQuestion_userId_idx" ON "GadQuestion"("userId"); + +-- CreateIndex +CREATE UNIQUE INDEX "PhqForm_userId_key" ON "PhqForm"("userId"); + +-- CreateIndex +CREATE INDEX "PhqForm_userId_idx" ON "PhqForm"("userId"); + +-- CreateIndex +CREATE UNIQUE INDEX "PhqQuestion_formId_key" ON "PhqQuestion"("formId"); + +-- CreateIndex +CREATE INDEX "PhqQuestion_userId_idx" ON "PhqQuestion"("userId"); + +-- CreateIndex +CREATE INDEX "PclForm_userId_idx" ON "PclForm"("userId"); + +-- CreateIndex +CREATE UNIQUE INDEX "PclQuestion_formId_key" ON "PclQuestion"("formId"); + +-- CreateIndex +CREATE INDEX "PclQuestion_userId_idx" ON "PclQuestion"("userId"); diff --git a/prisma/migrations/20260226060301/migration.sql b/prisma/migrations/20260226060301/migration.sql new file mode 100644 index 0000000..d40952a --- /dev/null +++ b/prisma/migrations/20260226060301/migration.sql @@ -0,0 +1,14 @@ +-- CreateTable +CREATE TABLE "client" ( + "id" TEXT NOT NULL PRIMARY KEY, + "userId" TEXT NOT NULL, + "status" TEXT NOT NULL DEFAULT 'INCOMPLETE', + "therapyWeek" INTEGER, + CONSTRAINT "client_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE +); + +-- CreateIndex +CREATE UNIQUE INDEX "client_userId_key" ON "client"("userId"); + +-- CreateIndex +CREATE INDEX "client_status_idx" ON "client"("status"); diff --git a/prisma/migrations/20260226072412_appointments/migration.sql b/prisma/migrations/20260226072412_appointments/migration.sql new file mode 100644 index 0000000..e8d585f --- /dev/null +++ b/prisma/migrations/20260226072412_appointments/migration.sql @@ -0,0 +1,26 @@ +/* + Warnings: + + - You are about to drop the `client` table. If the table is not empty, all the data it contains will be lost. + +*/ +-- DropTable +PRAGMA foreign_keys=off; +DROP TABLE "client"; +PRAGMA foreign_keys=on; + +-- CreateTable +CREATE TABLE "Appointment" ( + "id" TEXT NOT NULL PRIMARY KEY, + "clientId" TEXT NOT NULL, + "adminId" TEXT NOT NULL, + "title" TEXT NOT NULL, + "description" TEXT, + "startTime" DATETIME NOT NULL, + "endTime" DATETIME NOT NULL, + "status" TEXT NOT NULL DEFAULT 'SCHEDULED', + "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" DATETIME NOT NULL, + CONSTRAINT "Appointment_clientId_fkey" FOREIGN KEY ("clientId") REFERENCES "user" ("id") ON DELETE RESTRICT ON UPDATE CASCADE, + CONSTRAINT "Appointment_adminId_fkey" FOREIGN KEY ("adminId") REFERENCES "user" ("id") ON DELETE RESTRICT ON UPDATE CASCADE +); diff --git a/prisma/migrations/20260409184455_add_recurring_fields/migration.sql b/prisma/migrations/20260409184455_add_recurring_fields/migration.sql new file mode 100644 index 0000000..c2580e5 --- /dev/null +++ b/prisma/migrations/20260409184455_add_recurring_fields/migration.sql @@ -0,0 +1,3 @@ +-- AlterTable +ALTER TABLE "Appointment" ADD COLUMN "recurrence" TEXT; +ALTER TABLE "Appointment" ADD COLUMN "seriesId" TEXT; diff --git a/prisma/migrations/20260409203356/migration.sql b/prisma/migrations/20260409203356/migration.sql new file mode 100644 index 0000000..ffdd9af --- /dev/null +++ b/prisma/migrations/20260409203356/migration.sql @@ -0,0 +1,310 @@ +/* + Warnings: + + - You are about to drop the `ace_response` table. If the table is not empty, all the data it contains will be lost. + - You are about to drop the `form` table. If the table is not empty, all the data it contains will be lost. + - You are about to drop the `form_assignment` table. If the table is not empty, all the data it contains will be lost. + - You are about to drop the `form_question` table. If the table is not empty, all the data it contains will be lost. + - You are about to drop the `question` table. If the table is not empty, all the data it contains will be lost. + - You are about to drop the column `recurrence` on the `Appointment` table. All the data in the column will be lost. + - You are about to drop the column `seriesId` on the `Appointment` table. All the data in the column will be lost. + +*/ +-- DropIndex +DROP INDEX "ace_response_userId_idx"; + +-- DropIndex +DROP INDEX "form_slug_key"; + +-- DropIndex +DROP INDEX "form_assignment_userId_formId_key"; + +-- DropIndex +DROP INDEX "form_assignment_formId_idx"; + +-- DropIndex +DROP INDEX "form_assignment_userId_idx"; + +-- DropIndex +DROP INDEX "form_question_formId_questionId_key"; + +-- DropIndex +DROP INDEX "form_question_questionId_idx"; + +-- DropIndex +DROP INDEX "form_question_formId_idx"; + +-- DropIndex +DROP INDEX "question_alias_key"; + +-- AlterTable +ALTER TABLE "PclForm" ADD COLUMN "severity" TEXT; +ALTER TABLE "PclForm" ADD COLUMN "totalScore" INTEGER; + +-- AlterTable +ALTER TABLE "PclQuestion" ADD COLUMN "worstEvent" TEXT; + +-- AlterTable +ALTER TABLE "PhqForm" ADD COLUMN "severity" TEXT; + +-- AlterTable +ALTER TABLE "PhqQuestion" ADD COLUMN "q10" INTEGER; + +-- DropTable +PRAGMA foreign_keys=off; +DROP TABLE "ace_response"; +PRAGMA foreign_keys=on; + +-- DropTable +PRAGMA foreign_keys=off; +DROP TABLE "form"; +PRAGMA foreign_keys=on; + +-- DropTable +PRAGMA foreign_keys=off; +DROP TABLE "form_assignment"; +PRAGMA foreign_keys=on; + +-- DropTable +PRAGMA foreign_keys=off; +DROP TABLE "form_question"; +PRAGMA foreign_keys=on; + +-- DropTable +PRAGMA foreign_keys=off; +DROP TABLE "question"; +PRAGMA foreign_keys=on; + +-- CreateTable +CREATE TABLE "client" ( + "id" TEXT NOT NULL PRIMARY KEY, + "userId" TEXT NOT NULL, + "status" TEXT NOT NULL DEFAULT 'INCOMPLETE', + "therapyWeek" INTEGER, + "missedSessions" INTEGER NOT NULL DEFAULT 0, + CONSTRAINT "client_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE +); + +-- CreateTable +CREATE TABLE "client_permission" ( + "id" TEXT NOT NULL PRIMARY KEY, + "clientId" TEXT NOT NULL, + "canViewScores" BOOLEAN NOT NULL DEFAULT false, + "canViewNotes" BOOLEAN NOT NULL DEFAULT false, + "canViewPlan" BOOLEAN NOT NULL DEFAULT false, + CONSTRAINT "client_permission_clientId_fkey" FOREIGN KEY ("clientId") REFERENCES "client" ("id") ON DELETE CASCADE ON UPDATE CASCADE +); + +-- CreateTable +CREATE TABLE "client_plan" ( + "id" TEXT NOT NULL PRIMARY KEY, + "clientId" TEXT NOT NULL, + "content" TEXT NOT NULL DEFAULT '', + "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" DATETIME NOT NULL, + CONSTRAINT "client_plan_clientId_fkey" FOREIGN KEY ("clientId") REFERENCES "client" ("id") ON DELETE CASCADE ON UPDATE CASCADE +); + +-- CreateTable +CREATE TABLE "change_audit" ( + "id" TEXT NOT NULL PRIMARY KEY, + "entityType" TEXT NOT NULL, + "entityId" TEXT NOT NULL, + "oldValue" TEXT, + "newValue" TEXT, + "reasoning" TEXT, + "documentationPath" TEXT, + "documentationName" TEXT, + "signatureData" TEXT NOT NULL, + "signedById" TEXT NOT NULL, + "signedAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + CONSTRAINT "change_audit_signedById_fkey" FOREIGN KEY ("signedById") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE +); + +-- CreateTable +CREATE TABLE "ace_form" ( + "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + "userId" TEXT NOT NULL, + "status" TEXT NOT NULL DEFAULT 'IN_PROGRESS', + "totalScore" INTEGER, + "severity" TEXT, + "submittedAt" DATETIME, + CONSTRAINT "ace_form_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE +); + +-- CreateTable +CREATE TABLE "ace_question" ( + "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + "formId" INTEGER NOT NULL, + "userId" TEXT NOT NULL, + "a01" TEXT, + "a02" TEXT, + "a03" TEXT, + "a04" TEXT, + "a05" TEXT, + "a06" TEXT, + "a07" TEXT, + "a08" TEXT, + "a09" TEXT, + "a10" TEXT, + CONSTRAINT "ace_question_formId_fkey" FOREIGN KEY ("formId") REFERENCES "ace_form" ("id") ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT "ace_question_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE +); + +-- CreateTable +CREATE TABLE "PhysicianStatementForm" ( + "id" TEXT NOT NULL PRIMARY KEY, + "userId" TEXT NOT NULL, + "status" TEXT NOT NULL DEFAULT 'NOT_SUBMITTED', + "originalFileName" TEXT, + "storedFileName" TEXT, + "mimeType" TEXT, + "uploadedAt" DATETIME, + "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" DATETIME NOT NULL, + CONSTRAINT "PhysicianStatementForm_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE +); + +-- CreateTable +CREATE TABLE "ReleaseOfInformationAuthorizationForm" ( + "id" TEXT NOT NULL PRIMARY KEY, + "userId" TEXT NOT NULL, + "status" TEXT NOT NULL DEFAULT 'NOT_SUBMITTED', + "originalFileName" TEXT, + "storedFileName" TEXT, + "mimeType" TEXT, + "uploadedAt" DATETIME, + "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" DATETIME NOT NULL, + CONSTRAINT "ReleaseOfInformationAuthorizationForm_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE +); + +-- CreateTable +CREATE TABLE "session_note" ( + "id" TEXT NOT NULL PRIMARY KEY, + "clientId" TEXT NOT NULL, + "content" TEXT NOT NULL, + "attended" BOOLEAN NOT NULL DEFAULT true, + "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + CONSTRAINT "session_note_clientId_fkey" FOREIGN KEY ("clientId") REFERENCES "client" ("id") ON DELETE CASCADE ON UPDATE CASCADE +); + +-- CreateTable +CREATE TABLE "session_note_edit" ( + "id" TEXT NOT NULL PRIMARY KEY, + "sessionNoteId" TEXT NOT NULL, + "originalContent" TEXT, + "reason" TEXT, + "signature" TEXT, + "editedAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + CONSTRAINT "session_note_edit_sessionNoteId_fkey" FOREIGN KEY ("sessionNoteId") REFERENCES "session_note" ("id") ON DELETE CASCADE ON UPDATE CASCADE +); + +-- CreateTable +CREATE TABLE "declaration_template" ( + "id" TEXT NOT NULL PRIMARY KEY, + "requestKind" TEXT NOT NULL, + "version" INTEGER NOT NULL, + "content" TEXT NOT NULL, + "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +-- CreateTable +CREATE TABLE "session_notes_request" ( + "id" TEXT NOT NULL PRIMARY KEY, + "clientId" TEXT NOT NULL, + "requestKind" TEXT NOT NULL, + "status" TEXT NOT NULL DEFAULT 'PENDING', + "signatureData" TEXT NOT NULL, + "declarationTemplateId" TEXT NOT NULL, + "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + "decidedAt" DATETIME, + "decidedByUserId" TEXT, + "rejectionReason" TEXT, + "approvedSummaryText" TEXT, + CONSTRAINT "session_notes_request_clientId_fkey" FOREIGN KEY ("clientId") REFERENCES "client" ("id") ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT "session_notes_request_declarationTemplateId_fkey" FOREIGN KEY ("declarationTemplateId") REFERENCES "declaration_template" ("id") ON DELETE RESTRICT ON UPDATE CASCADE, + CONSTRAINT "session_notes_request_decidedByUserId_fkey" FOREIGN KEY ("decidedByUserId") REFERENCES "user" ("id") ON DELETE SET NULL ON UPDATE CASCADE +); + +-- RedefineTables +PRAGMA defer_foreign_keys=ON; +PRAGMA foreign_keys=OFF; +CREATE TABLE "new_Appointment" ( + "id" TEXT NOT NULL PRIMARY KEY, + "clientId" TEXT NOT NULL, + "adminId" TEXT NOT NULL, + "title" TEXT NOT NULL, + "description" TEXT, + "startTime" DATETIME NOT NULL, + "endTime" DATETIME NOT NULL, + "status" TEXT NOT NULL DEFAULT 'SCHEDULED', + "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" DATETIME NOT NULL, + CONSTRAINT "Appointment_clientId_fkey" FOREIGN KEY ("clientId") REFERENCES "user" ("id") ON DELETE RESTRICT ON UPDATE CASCADE, + CONSTRAINT "Appointment_adminId_fkey" FOREIGN KEY ("adminId") REFERENCES "user" ("id") ON DELETE RESTRICT ON UPDATE CASCADE +); +INSERT INTO "new_Appointment" ("adminId", "clientId", "createdAt", "description", "endTime", "id", "startTime", "status", "title", "updatedAt") SELECT "adminId", "clientId", "createdAt", "description", "endTime", "id", "startTime", "status", "title", "updatedAt" FROM "Appointment"; +DROP TABLE "Appointment"; +ALTER TABLE "new_Appointment" RENAME TO "Appointment"; +CREATE INDEX "Appointment_clientId_idx" ON "Appointment"("clientId"); +CREATE INDEX "Appointment_adminId_idx" ON "Appointment"("adminId"); +PRAGMA foreign_keys=ON; +PRAGMA defer_foreign_keys=OFF; + +-- CreateIndex +CREATE UNIQUE INDEX "client_userId_key" ON "client"("userId"); + +-- CreateIndex +CREATE INDEX "client_status_idx" ON "client"("status"); + +-- CreateIndex +CREATE UNIQUE INDEX "client_permission_clientId_key" ON "client_permission"("clientId"); + +-- CreateIndex +CREATE UNIQUE INDEX "client_plan_clientId_key" ON "client_plan"("clientId"); + +-- CreateIndex +CREATE INDEX "change_audit_entityType_entityId_idx" ON "change_audit"("entityType", "entityId"); + +-- CreateIndex +CREATE UNIQUE INDEX "ace_form_userId_key" ON "ace_form"("userId"); + +-- CreateIndex +CREATE INDEX "ace_form_userId_idx" ON "ace_form"("userId"); + +-- CreateIndex +CREATE UNIQUE INDEX "ace_question_formId_key" ON "ace_question"("formId"); + +-- CreateIndex +CREATE INDEX "ace_question_userId_idx" ON "ace_question"("userId"); + +-- CreateIndex +CREATE UNIQUE INDEX "PhysicianStatementForm_userId_key" ON "PhysicianStatementForm"("userId"); + +-- CreateIndex +CREATE INDEX "PhysicianStatementForm_status_idx" ON "PhysicianStatementForm"("status"); + +-- CreateIndex +CREATE UNIQUE INDEX "ReleaseOfInformationAuthorizationForm_userId_key" ON "ReleaseOfInformationAuthorizationForm"("userId"); + +-- CreateIndex +CREATE INDEX "ReleaseOfInformationAuthorizationForm_status_idx" ON "ReleaseOfInformationAuthorizationForm"("status"); + +-- CreateIndex +CREATE INDEX "session_note_clientId_idx" ON "session_note"("clientId"); + +-- CreateIndex +CREATE INDEX "session_note_edit_sessionNoteId_idx" ON "session_note_edit"("sessionNoteId"); + +-- CreateIndex +CREATE UNIQUE INDEX "declaration_template_requestKind_version_key" ON "declaration_template"("requestKind", "version"); + +-- CreateIndex +CREATE INDEX "session_notes_request_clientId_idx" ON "session_notes_request"("clientId"); + +-- CreateIndex +CREATE INDEX "session_notes_request_status_idx" ON "session_notes_request"("status"); + +-- CreateIndex +CREATE INDEX "session_notes_request_declarationTemplateId_idx" ON "session_notes_request"("declarationTemplateId"); From 04a26edc2b619c42f66fa566f9411c0232bb01ab Mon Sep 17 00:00:00 2001 From: ritikhaashok Date: Thu, 23 Apr 2026 15:28:33 -0500 Subject: [PATCH 02/13] create/delete reccuring events works on the CORRECT branch!! --- app/pages/calendar.vue | 137 ++++++++++++++++------ package-lock.json | 14 +++ package.json | 1 + prisma/schema/appointments.prisma | 4 + server/api/appointments/[id].delete.ts | 126 +++++++++++++-------- server/api/appointments/[id].put.ts | 56 +++++---- server/api/appointments/index.get.ts | 1 + server/api/appointments/index.post.ts | 150 +++++++++++++++++++------ 8 files changed, 344 insertions(+), 145 deletions(-) diff --git a/app/pages/calendar.vue b/app/pages/calendar.vue index b8b0435..bebfe86 100644 --- a/app/pages/calendar.vue +++ b/app/pages/calendar.vue @@ -15,6 +15,9 @@ | ({ id: string; role?: string } & Record) | null) ?? null ) + const deleteType = ref<'ONE' | 'FUTURE' | 'ALL' | null>(null) + const isDeleteTypeModalOpen = ref(false) + const isDeleteConfirmOpen = ref(false) const toast = useToast() const clients = ref([]) const events = ref([]) @@ -273,6 +276,7 @@ description: info.event.extendedProps?.description || info.event._def?.extendedProps?.description, status: info.event.extendedProps?.status || info.event._def?.extendedProps?.status, + seriesId: info.event.extendedProps.seriesId, } console.log('selectedEvent after click:', selectedEvent.value) @@ -296,17 +300,21 @@ async function saveEdit() { try { - await $fetch(`/api/appointments/${selectedEvent.value.id}`, { - method: 'PUT', - body: { - id: selectedEvent.value.id, - title: editForm.title, - description: editForm.description, - date: editForm.date, - startTime: editForm.startTime, - endTime: editForm.endTime, - }, - }) + async function saveEdit(type = 'ONE') { + await $fetch(`/api/appointments/${selectedEvent.value.id}`, { + method: 'PUT', + body: { + type, + seriesId: selectedEvent.value.seriesId, + startTime: selectedEvent.value.start, // IMPORTANT for FUTURE + title: editForm.title, + description: editForm.description, + date: editForm.date, + startTimeNew: editForm.startTime, + endTimeNew: editForm.endTime, + }, + }) + } toast.add({ title: 'Session updated', @@ -327,11 +335,38 @@ } } - async function deleteEvent() { + function onDeleteClick() { + // CLOSE the current modal first + isViewModalOpen.value = false + + setTimeout(() => { + if (selectedEvent.value?.seriesId) { + isDeleteTypeModalOpen.value = true + } else { + deleteType.value = 'ONE' + isDeleteConfirmOpen.value = true + } + }, 100) // small delay so UI updates cleanly + } + + function selectDeleteType(type: 'ONE' | 'FUTURE' | 'ALL') { + deleteType.value = type + isDeleteTypeModalOpen.value = false + + setTimeout(() => { + isDeleteConfirmOpen.value = true + }, 100) + } + + async function confirmDelete() { try { await $fetch(`/api/appointments/${selectedEvent.value.id}`, { method: 'DELETE', - credentials: 'include', + body: { + type: deleteType.value || 'ONE', // fallback safety + startTime: selectedEvent.value.start?.toISOString(), + seriesId: selectedEvent.value.seriesId || null, + }, }) toast.add({ @@ -339,12 +374,14 @@ color: 'success', }) - isDeleteConfirming.value = false + // reset state + deleteType.value = null + isDeleteConfirmOpen.value = false isViewModalOpen.value = false await loadEvents() } catch (error) { - console.error('Delete error:', error) + console.error(error) toast.add({ title: 'Failed to delete session', @@ -362,6 +399,7 @@ date: '', startTime: '', endTime: '', + recurrence: '', }) const clientOptions = computed(() => @@ -405,6 +443,8 @@ date: form.date, startTime: form.startTime, endTime: form.endTime, + isRecurring: !!form.recurrence, + recurrence: form.recurrence || null, }, }) @@ -416,11 +456,20 @@ closeCreateModal() await loadEvents() - } catch (error) { - console.error(error) + // } catch (error) { + // console.error(error) + + // toast.add({ + // title: 'Failed to create session', + // color: 'error', + // }) + // } + } catch (error: any) { + console.error('๐Ÿ”ฅ FULL ERROR:', error) + console.error('๐Ÿ”ฅ STACK:', error?.stack) toast.add({ - title: 'Failed to create session', + title: error?.data?.statusMessage || error?.message || 'Failed to create session', color: 'error', }) } @@ -525,7 +574,12 @@ - +
Cancel @@ -534,6 +588,35 @@
+ + + + + + + + + + + + + - -
-

- Are you sure you want to delete this session? -

-
- Cancel - Delete -
-
-
Delete diff --git a/package-lock.json b/package-lock.json index 4acd9dd..bd5f220 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,6 +24,7 @@ "marked": "^17.0.4", "nodemailer": "^7.0.11", "nuxt": "4.4.2", + "uuid": "^14.0.0", "vue": "^3.5.25", "vue-router": "^4.6.4", "vue-signature-pad": "^3.0.2", @@ -13671,6 +13672,19 @@ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "license": "MIT" }, + "node_modules/uuid": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-14.0.0.tgz", + "integrity": "sha512-Qo+uWgilfSmAhXCMav1uYFynlQO7fMFiMVZsQqZRMIXp0O7rR7qjkj+cPvBHLgBqi960QCoo/PH2/6ZtVqKvrg==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist-node/bin/uuid" + } + }, "node_modules/valibot": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/valibot/-/valibot-1.2.0.tgz", diff --git a/package.json b/package.json index 8174137..f75cfbf 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "marked": "^17.0.4", "nodemailer": "^7.0.11", "nuxt": "4.4.2", + "uuid": "^14.0.0", "vue": "^3.5.25", "vue-router": "^4.6.4", "vue-signature-pad": "^3.0.2", diff --git a/prisma/schema/appointments.prisma b/prisma/schema/appointments.prisma index d67e001..63944ca 100644 --- a/prisma/schema/appointments.prisma +++ b/prisma/schema/appointments.prisma @@ -9,6 +9,10 @@ model Appointment { status String @default("SCHEDULED") createdAt DateTime @default(now()) updatedAt DateTime @updatedAt + + seriesId String? + recurrence String + client User @relation("ClientAppointments", fields: [clientId], references: [id], onDelete: Restrict) admin User @relation("AdminAppointments", fields: [adminId], references: [id], onDelete: Restrict) diff --git a/server/api/appointments/[id].delete.ts b/server/api/appointments/[id].delete.ts index ece1cdc..9261da7 100644 --- a/server/api/appointments/[id].delete.ts +++ b/server/api/appointments/[id].delete.ts @@ -1,54 +1,90 @@ +// import { requireAdmin } from '../../utils/guard' +// import { prisma } from '../../utils/prisma' +// import { createError, defineEventHandler, getHeaders, getRouterParam } from 'h3' + +// export default defineEventHandler(async (event) => { +// try { +// const id = getRouterParam(event, 'id') +// if (!id) { +// throw createError({ +// statusCode: 400, +// statusMessage: 'Missing appointment ID', +// }) +// } + +// const user = requireAdmin(event) +// const adminId = user.id + +// await prisma.appointment.delete({ +// where: { id }, +// }) + +// return { +// success: true, +// } +// } catch (error: any) { +// if (error?.code === 'P2025') { +// throw createError({ +// statusCode: 404, +// statusMessage: 'Appointment not found', +// }) +// } + +// if (error && typeof error === 'object' && 'statusCode' in error) { +// throw error +// } + +// console.error('Delete appointment error:', error) + +// // Check if it's a Prisma error +// if (error && typeof error === 'object') { +// const errorObj = error as Record +// console.error('Error details:', { +// message: errorObj.message, +// code: errorObj.code, +// meta: errorObj.meta, +// }) +// } + +// throw createError({ +// statusCode: 500, +// statusMessage: 'Failed to delete appointment', +// }) +// } +// }) import { requireAdmin } from '../../utils/guard' import { prisma } from '../../utils/prisma' -import { createError, defineEventHandler, getHeaders, getRouterParam } from 'h3' +import { createError, defineEventHandler, getRouterParam, readBody } from 'h3' export default defineEventHandler(async (event) => { - try { - const id = getRouterParam(event, 'id') - if (!id) { - throw createError({ - statusCode: 400, - statusMessage: 'Missing appointment ID', - }) - } - - const user = requireAdmin(event) - const adminId = user.id - - await prisma.appointment.delete({ - where: { id }, + const id = getRouterParam(event, 'id') + const { type, startTime, seriesId } = await readBody(event) + + if (!id) throw createError({ statusCode: 400 }) + + // ONE + if (type === 'ONE' || !seriesId) { + await prisma.appointment.delete({ where: { id } }) + } + + // ALL + else if (type === 'ALL') { + await prisma.appointment.deleteMany({ + where: { seriesId }, }) + } - return { - success: true, - } - } catch (error: any) { - if (error?.code === 'P2025') { - throw createError({ - statusCode: 404, - statusMessage: 'Appointment not found', - }) - } - - if (error && typeof error === 'object' && 'statusCode' in error) { - throw error - } - - console.error('Delete appointment error:', error) - - // Check if it's a Prisma error - if (error && typeof error === 'object') { - const errorObj = error as Record - console.error('Error details:', { - message: errorObj.message, - code: errorObj.code, - meta: errorObj.meta, - }) - } - - throw createError({ - statusCode: 500, - statusMessage: 'Failed to delete appointment', + // FUTURE + else if (type === 'FUTURE') { + await prisma.appointment.deleteMany({ + where: { + seriesId, + startTime: { + gte: new Date(startTime), + }, + }, }) } + + return { success: true } }) diff --git a/server/api/appointments/[id].put.ts b/server/api/appointments/[id].put.ts index eb1cbe0..9a338d3 100644 --- a/server/api/appointments/[id].put.ts +++ b/server/api/appointments/[id].put.ts @@ -3,43 +3,39 @@ import { requireAdmin } from '../../utils/guard' import { defineEventHandler, getRouterParam, readBody, createError } from 'h3' export default defineEventHandler(async (event) => { - requireAdmin(event) + const id = getRouterParam(event, 'id') + const { type, startTime, seriesId, title, description, date, startTimeNew, endTimeNew } = + await readBody(event) - try { - const id = getRouterParam(event, 'id') - if (!id) throw createError({ statusCode: 400, statusMessage: 'Missing ID' }) - const { title, description, date, startTime, endTime } = await readBody(event) - - const startTimeDate = new Date(`${date}T${startTime}`) - const endTimeDate = new Date(`${date}T${endTime}`) + const newStart = new Date(`${date}T${startTimeNew}`) + const newEnd = new Date(`${date}T${endTimeNew}`) + // ONE + if (type === 'ONE' || !seriesId) { await prisma.appointment.update({ where: { id }, - data: { - title, - description, - startTime: startTimeDate, - endTime: endTimeDate, - }, + data: { title, description, startTime: newStart, endTime: newEnd }, }) + } - return { success: true } - } catch (error: any) { - if (error?.code === 'P2025') { - throw createError({ - statusCode: 404, - statusMessage: 'Appointment not found', - }) - } - - if (error && typeof error === 'object' && 'statusCode' in error) { - throw error - } + // ALL + else if (type === 'ALL') { + await prisma.appointment.updateMany({ + where: { seriesId }, + data: { title, description }, + }) + } - console.error('Error updating appointment:', error) - throw createError({ - statusCode: 500, - statusMessage: 'Failed to update appointment', + // FUTURE + else if (type === 'FUTURE') { + await prisma.appointment.updateMany({ + where: { + seriesId, + startTime: { gte: new Date(startTime) }, + }, + data: { title, description }, }) } + + return { success: true } }) diff --git a/server/api/appointments/index.get.ts b/server/api/appointments/index.get.ts index 852e60e..43c0b60 100644 --- a/server/api/appointments/index.get.ts +++ b/server/api/appointments/index.get.ts @@ -60,5 +60,6 @@ export default defineEventHandler(async (event) => { clientName: a.client.name, description: a.description, status: a.status, + seriesId: a.seriesId, })) }) diff --git a/server/api/appointments/index.post.ts b/server/api/appointments/index.post.ts index 4b2aae7..787a9ed 100644 --- a/server/api/appointments/index.post.ts +++ b/server/api/appointments/index.post.ts @@ -1,66 +1,144 @@ +// import { requireAdmin } from '../../utils/guard' +// import { prisma } from '../../utils/prisma' +// import { readBody, createError, defineEventHandler, getHeaders } from 'h3' + +// export default defineEventHandler(async (event) => { +// try { +// const body = await readBody(event) + +// const user = requireAdmin(event) +// const adminId = user.id + +// const { clientId, title, description, date, startTime, endTime } = body + +// if (!clientId || !title || !date || !startTime || !endTime) { +// throw createError({ +// statusCode: 400, +// statusMessage: 'Missing required fields', +// }) +// } + +// const start = new Date(`${date}T${startTime}`) +// const end = new Date(`${date}T${endTime}`) + +// if (Number.isNaN(start.getTime()) || Number.isNaN(end.getTime()) || end <= start) { +// throw createError({ +// statusCode: 400, +// statusMessage: 'Invalid date/time range', +// }) +// } + +// const appointment = await prisma.appointment.create({ +// data: { +// clientId, +// adminId, +// title, +// description, +// startTime: start, +// endTime: end, +// status: 'SCHEDULED', +// }, +// }) + +// return { +// success: true, +// appointment, +// } +// } catch (error: any) { +// if (error && typeof error === 'object' && 'statusCode' in error) { +// throw error +// } + +// if (error?.code === 'P2003') { +// throw createError({ +// statusCode: 400, +// statusMessage: 'Invalid client ID or Foreign Key constraint failed', +// }) +// } + +// console.error('Create appointment error:', error) + +// throw createError({ +// statusCode: 500, +// statusMessage: 'Failed to create appointment', +// }) +// } +// }) import { requireAdmin } from '../../utils/guard' import { prisma } from '../../utils/prisma' -import { readBody, createError, defineEventHandler, getHeaders } from 'h3' +import { readBody, createError, defineEventHandler } from 'h3' +import { v4 as uuidv4 } from 'uuid' export default defineEventHandler(async (event) => { try { const body = await readBody(event) - const user = requireAdmin(event) const adminId = user.id - const { clientId, title, description, date, startTime, endTime } = body + const { clientId, title, description, date, startTime, endTime, isRecurring, recurrence } = body if (!clientId || !title || !date || !startTime || !endTime) { - throw createError({ - statusCode: 400, - statusMessage: 'Missing required fields', - }) + throw createError({ statusCode: 400, statusMessage: 'Missing required fields' }) } - const start = new Date(`${date}T${startTime}`) - const end = new Date(`${date}T${endTime}`) + const baseStart = new Date(`${date}T${startTime}`) + const baseEnd = new Date(`${date}T${endTime}`) - if (Number.isNaN(start.getTime()) || Number.isNaN(end.getTime()) || end <= start) { - throw createError({ - statusCode: 400, - statusMessage: 'Invalid date/time range', - }) + if (baseEnd <= baseStart) { + throw createError({ statusCode: 400, statusMessage: 'Invalid time range' }) } - const appointment = await prisma.appointment.create({ - data: { + const seriesId = isRecurring ? uuidv4() : null + const count = isRecurring ? 20 : 1 + + const appointmentsToCreate = [] + + for (let i = 0; i < count; i++) { + const newStart = new Date(baseStart) + const newEnd = new Date(baseEnd) + + if (isRecurring) { + if (recurrence === 'DAILY') { + newStart.setDate(baseStart.getDate() + i) + newEnd.setDate(baseEnd.getDate() + i) + } + + if (recurrence === 'WEEKLY') { + newStart.setDate(baseStart.getDate() + i * 7) + newEnd.setDate(baseEnd.getDate() + i * 7) + } + + if (recurrence === 'MONTHLY') { + newStart.setMonth(baseStart.getMonth() + i) + newEnd.setMonth(baseEnd.getMonth() + i) + } + } + + appointmentsToCreate.push({ clientId, adminId, title, description, - startTime: start, - endTime: end, + startTime: newStart, + endTime: newEnd, status: 'SCHEDULED', - }, - }) - - return { - success: true, - appointment, - } - } catch (error: any) { - if (error && typeof error === 'object' && 'statusCode' in error) { - throw error - } - - if (error?.code === 'P2003') { - throw createError({ - statusCode: 400, - statusMessage: 'Invalid client ID or Foreign Key constraint failed', + seriesId, + recurrence: isRecurring ? recurrence : null, }) } - console.error('Create appointment error:', error) + await prisma.appointment.createMany({ + data: appointmentsToCreate, + }) + + return { success: true } + } catch (error: any) { + console.error('๐Ÿ”ฅ BACKEND FULL ERROR:', error) + console.error('๐Ÿ”ฅ BACKEND STACK:', error?.stack) throw createError({ statusCode: 500, - statusMessage: 'Failed to create appointment', + statusMessage: error?.message || JSON.stringify(error), }) } }) From 478ecc0f9490d0489d29ae16ab1735409ef00a59 Mon Sep 17 00:00:00 2001 From: ritikhaashok Date: Thu, 23 Apr 2026 15:52:50 -0500 Subject: [PATCH 03/13] deleted commented code --- server/api/appointments/[id].delete.ts | 54 --------------------- server/api/appointments/index.post.ts | 66 -------------------------- 2 files changed, 120 deletions(-) diff --git a/server/api/appointments/[id].delete.ts b/server/api/appointments/[id].delete.ts index 9261da7..546ad01 100644 --- a/server/api/appointments/[id].delete.ts +++ b/server/api/appointments/[id].delete.ts @@ -1,57 +1,3 @@ -// import { requireAdmin } from '../../utils/guard' -// import { prisma } from '../../utils/prisma' -// import { createError, defineEventHandler, getHeaders, getRouterParam } from 'h3' - -// export default defineEventHandler(async (event) => { -// try { -// const id = getRouterParam(event, 'id') -// if (!id) { -// throw createError({ -// statusCode: 400, -// statusMessage: 'Missing appointment ID', -// }) -// } - -// const user = requireAdmin(event) -// const adminId = user.id - -// await prisma.appointment.delete({ -// where: { id }, -// }) - -// return { -// success: true, -// } -// } catch (error: any) { -// if (error?.code === 'P2025') { -// throw createError({ -// statusCode: 404, -// statusMessage: 'Appointment not found', -// }) -// } - -// if (error && typeof error === 'object' && 'statusCode' in error) { -// throw error -// } - -// console.error('Delete appointment error:', error) - -// // Check if it's a Prisma error -// if (error && typeof error === 'object') { -// const errorObj = error as Record -// console.error('Error details:', { -// message: errorObj.message, -// code: errorObj.code, -// meta: errorObj.meta, -// }) -// } - -// throw createError({ -// statusCode: 500, -// statusMessage: 'Failed to delete appointment', -// }) -// } -// }) import { requireAdmin } from '../../utils/guard' import { prisma } from '../../utils/prisma' import { createError, defineEventHandler, getRouterParam, readBody } from 'h3' diff --git a/server/api/appointments/index.post.ts b/server/api/appointments/index.post.ts index 787a9ed..67e204f 100644 --- a/server/api/appointments/index.post.ts +++ b/server/api/appointments/index.post.ts @@ -1,69 +1,3 @@ -// import { requireAdmin } from '../../utils/guard' -// import { prisma } from '../../utils/prisma' -// import { readBody, createError, defineEventHandler, getHeaders } from 'h3' - -// export default defineEventHandler(async (event) => { -// try { -// const body = await readBody(event) - -// const user = requireAdmin(event) -// const adminId = user.id - -// const { clientId, title, description, date, startTime, endTime } = body - -// if (!clientId || !title || !date || !startTime || !endTime) { -// throw createError({ -// statusCode: 400, -// statusMessage: 'Missing required fields', -// }) -// } - -// const start = new Date(`${date}T${startTime}`) -// const end = new Date(`${date}T${endTime}`) - -// if (Number.isNaN(start.getTime()) || Number.isNaN(end.getTime()) || end <= start) { -// throw createError({ -// statusCode: 400, -// statusMessage: 'Invalid date/time range', -// }) -// } - -// const appointment = await prisma.appointment.create({ -// data: { -// clientId, -// adminId, -// title, -// description, -// startTime: start, -// endTime: end, -// status: 'SCHEDULED', -// }, -// }) - -// return { -// success: true, -// appointment, -// } -// } catch (error: any) { -// if (error && typeof error === 'object' && 'statusCode' in error) { -// throw error -// } - -// if (error?.code === 'P2003') { -// throw createError({ -// statusCode: 400, -// statusMessage: 'Invalid client ID or Foreign Key constraint failed', -// }) -// } - -// console.error('Create appointment error:', error) - -// throw createError({ -// statusCode: 500, -// statusMessage: 'Failed to create appointment', -// }) -// } -// }) import { requireAdmin } from '../../utils/guard' import { prisma } from '../../utils/prisma' import { readBody, createError, defineEventHandler } from 'h3' From 44427446b75a4eecbfd856e07733352e75c4912c Mon Sep 17 00:00:00 2001 From: ritikhaashok Date: Fri, 24 Apr 2026 13:01:08 -0500 Subject: [PATCH 04/13] updated interaction for switching between days, weeks, and months --- app/pages/calendar.vue | 46 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 40 insertions(+), 6 deletions(-) diff --git a/app/pages/calendar.vue b/app/pages/calendar.vue index bebfe86..cd7dbcb 100644 --- a/app/pages/calendar.vue +++ b/app/pages/calendar.vue @@ -172,6 +172,32 @@ const isEditMode = ref(false) const isDeleteConfirming = ref(false) const mobileView = ref('week') + const currentRangeLabel = ref('') + + function formatShortDate(date: Date) { + return date.toLocaleDateString('en-US') + } + + function updateRangeLabel(viewType: string, start: Date) { + if (viewType.includes('Week')) { + currentRangeLabel.value = `Week of ${formatShortDate(start)}` + return + } + + if (viewType.includes('Month')) { + currentRangeLabel.value = start.toLocaleDateString('en-US', { + month: 'long', + year: 'numeric', + }) + return + } + + currentRangeLabel.value = start.toLocaleDateString('en-US', { + month: 'long', + day: 'numeric', + year: 'numeric', + }) + } watch(mobileView, (view) => { changeView(view) @@ -202,6 +228,7 @@ datesSet(info) { const view = info.view.type + updateRangeLabel(view, info.view.currentStart) if (view.includes('Day')) mobileView.value = 'day' if (view.includes('Week')) mobileView.value = 'week' @@ -485,15 +512,22 @@ +

+ {{ currentRangeLabel }} +

- - +
+ + +
-
+
\ No newline at end of file diff --git a/app/components/Notes.vue b/app/components/Notes.vue index 85ec834..178b430 100644 --- a/app/components/Notes.vue +++ b/app/components/Notes.vue @@ -138,6 +138,8 @@ const localPreviousNotes = ref([...props.previousNotes]) const localSessionNotes = ref([...props.sessionNotes]) + const formEditPanelRef = ref<{ handleSave: () => void } | null>(null) + watch( () => props.previousNotes, (v) => { @@ -1743,28 +1745,31 @@ description="Try again or open the client profile to view form answers." />
-

- {{ formPreviewData.submitted ? 'Submitted' : 'Not submitted' }} - - ยท - {{ - new Date( - formPreviewData.completedAt ?? formPreviewData.submittedAt ?? '' - ).toLocaleString('en-US') - }} + + {{ formPreviewData.submitted ? 'Submitted' : 'Not submitted' }} + + ยท + {{ + new Date( + formPreviewData.completedAt ?? formPreviewData.submittedAt ?? '' + ).toLocaleString('en-US') + }} + -

-
-
+
+ + +
+ +
+
- -
-
- -

No answers yet.

diff --git a/server/api/clients/[id]/forms/[formKey].patch.ts b/server/api/clients/[id]/forms/[formKey].patch.ts index c688ab7..392944c 100644 --- a/server/api/clients/[id]/forms/[formKey].patch.ts +++ b/server/api/clients/[id]/forms/[formKey].patch.ts @@ -91,7 +91,11 @@ export default defineEventHandler(async (event) => { if (!form) throw createError({ statusCode: 404, statusMessage: 'Form not found' }) const keys = ['g01','g02','g03','g04','g05','g06','g07','g08'] const data: Record = {} - answers.forEach((a, i) => { if (keys[i]) data[keys[i]!] = toInt(a.answer, GAD_OPTIONS) }) + answers.forEach((a, i) => { + if (!keys[i]) return + const map = keys[i] === 'g08' ? PHQ_DIFFICULTY_OPTIONS : GAD_OPTIONS + data[keys[i]!] = toInt(a.answer, map) + }) await prisma.gadQuestion.update({ where: { formId: form.id }, data }) // Recalculate score (g01-g07 only, g08 is difficulty) diff --git a/server/utils/clinical-form-display.ts b/server/utils/clinical-form-display.ts index 0d4f97b..4d68ce4 100644 --- a/server/utils/clinical-form-display.ts +++ b/server/utils/clinical-form-display.ts @@ -64,6 +64,13 @@ export const GAD_OPTIONS: Record = { 3: 'Nearly every day', } +export const DIFFICULTY_OPTIONS: Record = { + 0: 'Not difficult at all', + 1: 'Somewhat difficult', + 2: 'Very difficult', + 3: 'Extremely difficult', +} + export const PCL_OPTIONS: Record = { 0: 'Not at all', 1: 'A little bit', @@ -127,7 +134,9 @@ export async function loadClinicalFormQuestions( const answers = [q.g01, q.g02, q.g03, q.g04, q.g05, q.g06, q.g07, q.g08] return GAD_LABELS.slice(0, answers.length).map((label, i) => ({ label, - answer: answers[i] != null ? (GAD_OPTIONS[answers[i] as number] ?? String(answers[i])) : '', + answer: answers[i] != null + ? ((i === 7 ? DIFFICULTY_OPTIONS : GAD_OPTIONS)[answers[i] as number] ?? String(answers[i])) + : '', })) } @@ -145,7 +154,9 @@ export async function loadClinicalFormQuestions( const answers = [q.q1, q.q2, q.q3, q.q4, q.q5, q.q6, q.q7, q.q8, q.q9, q.q10] return PHQ_LABELS.slice(0, answers.length).map((label, i) => ({ label, - answer: answers[i] != null ? (PHQ_OPTIONS[answers[i] as number] ?? String(answers[i])) : '', + answer: answers[i] != null + ? ((i === 9 ? DIFFICULTY_OPTIONS : PHQ_OPTIONS)[answers[i] as number] ?? String(answers[i])) + : '', })) } @@ -161,14 +172,14 @@ export async function loadClinicalFormQuestions( (await prisma.pclQuestion.findFirst({ where: { userId } })) } if (!q) return [] - const questions: ClinicalFormQuestionRow[] = [] + const questions: ClinicalFormQuestionRow[] = [ + { label: 'Worst event', answer: q.worstEvent ?? '' }, + ] for (let i = 1; i <= 20; i++) { const key = `q${String(i).padStart(2, '0')}` as keyof typeof q const val = q[key] const numVal = typeof val === 'number' ? val : null - if (numVal != null && numVal >= 0) { - questions.push({ label: `Item ${i}`, answer: PCL_OPTIONS[numVal] ?? String(numVal) }) - } + questions.push({ label: PCL_LABELS[i - 1] ?? `Item ${i}`, answer: numVal != null ? (PCL_OPTIONS[numVal] ?? String(numVal)) : '' }) } return questions } From b768190ff57d20464e9512032a2d4c4549c5b28c Mon Sep 17 00:00:00 2001 From: Devika Date: Wed, 29 Apr 2026 01:46:20 -0500 Subject: [PATCH 10/13] forms-fix --- server/api/admin/backfill-absences.post.ts | 2 +- server/api/appointments/index.post.ts | 2 +- server/api/session-notes/pending-approvals.get.ts | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/server/api/admin/backfill-absences.post.ts b/server/api/admin/backfill-absences.post.ts index 4a39ae6..23b4777 100644 --- a/server/api/admin/backfill-absences.post.ts +++ b/server/api/admin/backfill-absences.post.ts @@ -22,7 +22,7 @@ export default defineEventHandler(async (event) => { const calendarAbsences = await prisma.sessionNote.count({ where: { clientId: client.id, - attended: false, + attendanceStatus: 'no-show', }, }) diff --git a/server/api/appointments/index.post.ts b/server/api/appointments/index.post.ts index 4a1b91d..64df377 100644 --- a/server/api/appointments/index.post.ts +++ b/server/api/appointments/index.post.ts @@ -130,7 +130,7 @@ export default defineEventHandler(async (event) => { sessionName, sessionNumber, content: '', - attended: true, + attendanceStatus: 'show', }, }) } diff --git a/server/api/session-notes/pending-approvals.get.ts b/server/api/session-notes/pending-approvals.get.ts index 7409519..20e2198 100644 --- a/server/api/session-notes/pending-approvals.get.ts +++ b/server/api/session-notes/pending-approvals.get.ts @@ -15,7 +15,7 @@ export default defineEventHandler(async (event) => { typeof query.kind === 'string' ? query.kind.toUpperCase() : '' const kindFilter = kindParam === 'PROGRESS' || kindParam === 'PSYCHOTHERAPY' - ? { kind: kindParam } + ? { kind: kindParam as 'PROGRESS' | 'PSYCHOTHERAPY' } : {} const rows = await prisma.sessionNote.findMany({ @@ -55,7 +55,7 @@ export default defineEventHandler(async (event) => { kind: r.kind, status: r.status, content: r.content, - attended: r.attended, + attendanceStatus: r.attendanceStatus, appointmentId: r.appointmentId, appointmentStartTime: r.appointment?.startTime?.toISOString() ?? null, clinicianSignedAt: r.clinicianSignedAt?.toISOString() ?? null, From 7b56e217b10afcadb4b352b06ac41ca770eeea4c Mon Sep 17 00:00:00 2001 From: Devika Date: Wed, 29 Apr 2026 13:26:11 -0500 Subject: [PATCH 11/13] added and fixed a few things in notes page --- app/components/Notes.vue | 178 +++++++++++++++++++++++--------- app/components/NotesToolbar.vue | 5 + 2 files changed, 135 insertions(+), 48 deletions(-) diff --git a/app/components/Notes.vue b/app/components/Notes.vue index f91ab5d..b3c7fb2 100644 --- a/app/components/Notes.vue +++ b/app/components/Notes.vue @@ -140,6 +140,7 @@ const selectedSessionNoteId = ref(null) const localPreviousNotes = ref([...props.previousNotes]) const localSessionNotes = ref([...props.sessionNotes]) + const showEditHistory = ref(false) const formEditPanelRef = ref<{ handleSave: () => void } | null>(null) @@ -253,6 +254,11 @@ async function selectSessionNote(sn: SessionNoteRow) { if (sn.status === 'DRAFT' && sn.appointmentId) { + selectedSessionNoteId.value = null + selectedPreviousNote.value = null + editingNoteId.value = null + editingSessionNoteId.value = null + isEditingPreviousPanel.value = false selectedAppointmentId.value = sn.appointmentId noteContent.value = sn.content currentNoteKind.value = sn.kind ?? 'PROGRESS' @@ -282,6 +288,7 @@ const noteContent = ref(props.currentNote.content || '') /** Kind for the current in-progress note; progress notes are the default. */ + watch(noteContent, (val) => console.log('noteContent changed:', val)) const currentNoteKind = ref('PROGRESS') /** Filter for the sidebar Notes tab: 'all' | 'PROGRESS' | 'PSYCHOTHERAPY'. */ const notesKindFilter = ref<'all' | NoteKind>('all') @@ -346,10 +353,6 @@ 'PCL-5': 'pcl', } - watch(sidebarTab, (t) => { - if (t !== 'forms') selectedForm.value = null - }) - const formPanelSubTab = ref<'answers' | 'history'>('answers') const CLINICAL_FORM_KEYS = new Set(['ace', 'gad', 'phq', 'pcl']) @@ -616,26 +619,64 @@ ) async function saveDraftNote() { - if (!noteContent.value.trim() || !selectedAppointmentId.value) return - saveStatus.value = 'saving' - try { - await $fetch(`/api/clients/${props.client.id}/notes`, { - method: 'POST', - body: { + if (!noteContent.value.trim() || !selectedAppointmentId.value) return + saveStatus.value = 'saving' + try { + const response = await $fetch(`/api/clients/${props.client.id}/notes`, { + method: 'POST', + body: { + content: noteContent.value, + appointmentId: selectedAppointmentId.value, + kind: currentNoteKind.value, + action: 'save-draft', + }, + }) as SessionNoteRow + + // Update or insert the saved note in the local list + const existingIdx = localSessionNotes.value.findIndex((n) => n.id === response.id) + const row: SessionNoteRow = { + id: response.id, + createdAt: response.createdAt, content: noteContent.value, - appointmentId: selectedAppointmentId.value, - kind: currentNoteKind.value, - action: 'draft', - }, - }) - localStorage.setItem(`note_draft_${props.client.id}`, noteContent.value) - lastSaved.value = new Date() - saveStatus.value = 'saved' - } catch (err) { - console.error('Draft save failed:', err) - saveStatus.value = 'error' + attendanceStatus: response.attendanceStatus ?? 'show', + sessionName: response.sessionName, + sessionNumber: response.sessionNumber, + appointmentId: response.appointmentId, + appointmentStartTime: selectedAppointment.value?.startTime ?? null, + kind: response.kind, + status: response.status, + } + if (existingIdx === -1) localSessionNotes.value.unshift(row) + else localSessionNotes.value[existingIdx] = row + + localStorage.setItem(`note_draft_${props.client.id}`, noteContent.value) + lastSaved.value = new Date() + saveStatus.value = 'saved' + } catch (err) { + console.error('Draft save failed:', err) + saveStatus.value = 'error' + } } - } +// if (!noteContent.value.trim() || !selectedAppointmentId.value) return +// saveStatus.value = 'saving' +// try { +// await $fetch(`/api/clients/${props.client.id}/notes`, { +// method: 'POST', +// body: { +// content: noteContent.value, +// appointmentId: selectedAppointmentId.value, +// kind: currentNoteKind.value, +// action: 'save-draft', +// }, +// }) +// localStorage.setItem(`note_draft_${props.client.id}`, noteContent.value) +// lastSaved.value = new Date() +// saveStatus.value = 'saved' +// } catch (err) { +// console.error('Draft save failed:', err) +// saveStatus.value = 'error' +// } +// } function startEditPrevious() { const sd = selectedNoteData.value @@ -698,6 +739,8 @@ showEditJustificationModal.value = false } + const showAttendanceWarningModal = ref(false) + const isSavingPrevious = ref(false) const didApplyInitialFocus = ref(false) @@ -857,6 +900,11 @@ async function saveNote() { if (!noteContent.value.trim()) return + if (!attendanceStatus.value) { + showAttendanceWarningModal.value = true + return + } + showSaveModal.value = true } @@ -1424,12 +1472,12 @@ class="flex min-h-0 flex-1 flex-col divide-y divide-gray-200 overflow-hidden border-l border-gray-200 md:flex-row md:divide-x md:divide-y-0 dark:divide-gray-800 dark:border-gray-800 min-w-0" >
@@ -1503,15 +1551,14 @@
-
-
-
+
+
+
+
+
+
+
+

+ Edited {{ new Date(edit.editedAt).toLocaleString('en-US') }} +

+

Reason: {{ edit.reason }}

+
-
+
@@ -1647,6 +1704,7 @@ @@ -1690,7 +1748,7 @@ !isEditingPreviousPanel && (!selectedAppointmentId || !canEditCurrentNote || !canMarkAttendance) " - @click="showSaveModal = true" + @click="saveNote" class="w-auto" />
@@ -1707,7 +1765,7 @@
-
+
@@ -1932,6 +1990,30 @@
+ + +
+
+

+ Please mark whether the client attended this session before submitting the note. +

+
+ +
+
+
+
+ + emit('update:modelValue', val)) +watch(() => props.modelValue, (val) => { + if (val !== localContent.value) localContent.value = val +}) + const items: EditorToolbarItem[][] = [ [ { From 8c1939aa09c52087838315aaeb9b02afec2fcca4 Mon Sep 17 00:00:00 2001 From: Devika Date: Wed, 29 Apr 2026 13:32:31 -0500 Subject: [PATCH 12/13] changed the location of the attendance dropdown --- app/components/Notes.vue | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/components/Notes.vue b/app/components/Notes.vue index b3c7fb2..c01cf30 100644 --- a/app/components/Notes.vue +++ b/app/components/Notes.vue @@ -1696,8 +1696,10 @@
+
+
From 72a893469e7fe5e8a57a6082a33cde73c9139e81 Mon Sep 17 00:00:00 2001 From: swaminathanR04 Date: Wed, 29 Apr 2026 18:03:58 -0500 Subject: [PATCH 13/13] pnpm-lock.yaml updated (build fix --- pnpm-lock.yaml | 60 ++++++++------------------------------------------ 1 file changed, 9 insertions(+), 51 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d8cbda5..18bb813 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -71,6 +71,9 @@ importers: nuxt: specifier: 4.4.2 version: 4.4.2(@babel/core@7.29.0)(@babel/plugin-syntax-jsx@7.28.6(@babel/core@7.29.0))(@electric-sql/pglite@0.3.15)(@parcel/watcher@2.5.6)(@types/node@25.5.0)(@vue/compiler-sfc@3.5.30)(better-sqlite3@12.8.0)(cac@6.7.14)(db0@0.3.4(@electric-sql/pglite@0.3.15)(better-sqlite3@12.8.0)(mysql2@3.15.3))(ioredis@5.10.1)(lightningcss@1.32.0)(magicast@0.5.2)(mysql2@3.15.3)(rollup-plugin-visualizer@7.0.1(rollup@4.60.0))(rollup@4.60.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(vite@7.3.1(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) + uuid: + specifier: ^14.0.0 + version: 14.0.0 vue: specifier: ^3.5.25 version: 3.5.30(typescript@5.9.3) @@ -854,56 +857,48 @@ packages: engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] - libc: [glibc] '@oxc-minify/binding-linux-arm64-musl@0.117.0': resolution: {integrity: sha512-C3zapJconWpl2Y7LR3GkRkH6jxpuV2iVUfkFcHT5Ffn4Zu7l88mZa2dhcfdULZDybN1Phka/P34YUzuskUUrXw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] - libc: [musl] '@oxc-minify/binding-linux-ppc64-gnu@0.117.0': resolution: {integrity: sha512-2T/Bm+3/qTfuNS4gKSzL8qbiYk+ErHW2122CtDx+ilZAzvWcJ8IbqdZIbEWOlwwe03lESTxPwTBLFqVgQU2OeQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] - libc: [glibc] '@oxc-minify/binding-linux-riscv64-gnu@0.117.0': resolution: {integrity: sha512-MKLjpldYkeoB4T+yAi4aIAb0waifxUjLcKkCUDmYAY3RqBJTvWK34KtfaKZL0IBMIXfD92CbKkcxQirDUS9Xcg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] - libc: [glibc] '@oxc-minify/binding-linux-riscv64-musl@0.117.0': resolution: {integrity: sha512-UFVcbPvKUStry6JffriobBp8BHtjmLLPl4bCY+JMxIn/Q3pykCpZzRwFTcDurG/kY8tm+uSNfKKdRNa5Nh9A7g==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] - libc: [musl] '@oxc-minify/binding-linux-s390x-gnu@0.117.0': resolution: {integrity: sha512-B9GyPQ1NKbvpETVAMyJMfRlD3c6UJ7kiuFUAlx9LTYiQL+YIyT6vpuRlq1zgsXxavZluVrfeJv6x0owV4KDx4Q==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] - libc: [glibc] '@oxc-minify/binding-linux-x64-gnu@0.117.0': resolution: {integrity: sha512-fXfhtr+WWBGNy4M5GjAF5vu/lpulR4Me34FjTyaK9nDrTZs7LM595UDsP1wliksqp4hD/KdoqHGmbCrC+6d4vA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] - libc: [glibc] '@oxc-minify/binding-linux-x64-musl@0.117.0': resolution: {integrity: sha512-jFBgGbx1oLadb83ntJmy1dWlAHSQanXTS21G4PgkxyONmxZdZ/UMKr7KsADzMuoPsd2YhJHxzRpwJd9U+4BFBw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] - libc: [musl] '@oxc-minify/binding-openharmony-arm64@0.117.0': resolution: {integrity: sha512-nxPd9vx1vYz8IlIMdl9HFdOK/ood1H5hzbSFsyO8JU55tkcJoBL8TLCbuFf9pHpOy27l2gcPyV6z3p4eAcTH5Q==} @@ -981,56 +976,48 @@ packages: engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] - libc: [glibc] '@oxc-parser/binding-linux-arm64-musl@0.117.0': resolution: {integrity: sha512-QagKTDF4lrz8bCXbUi39Uq5xs7C7itAseKm51f33U+Dyar9eJY/zGKqfME9mKLOiahX7Fc1J3xMWVS0AdDXLPg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] - libc: [musl] '@oxc-parser/binding-linux-ppc64-gnu@0.117.0': resolution: {integrity: sha512-RPddpcE/0xxWaommWy0c5i/JdrXcXAkxBS2GOrAUh5LKmyCh03hpJedOAWszG4ADsKQwoUQQ1/tZVGRhZIWtKA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] - libc: [glibc] '@oxc-parser/binding-linux-riscv64-gnu@0.117.0': resolution: {integrity: sha512-ur/WVZF9FSOiZGxyP+nfxZzuv6r5OJDYoVxJnUR7fM/hhXLh4V/be6rjbzm9KLCDBRwYCEKJtt+XXNccwd06IA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] - libc: [glibc] '@oxc-parser/binding-linux-riscv64-musl@0.117.0': resolution: {integrity: sha512-ujGcAx8xAMvhy7X5sBFi3GXML1EtyORuJZ5z2T6UV3U416WgDX/4OCi3GnoteeenvxIf6JgP45B+YTHpt71vpA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] - libc: [musl] '@oxc-parser/binding-linux-s390x-gnu@0.117.0': resolution: {integrity: sha512-hbsfKjUwRjcMZZvvmpZSc+qS0bHcHRu8aV/I3Ikn9BzOA0ZAgUE7ctPtce5zCU7bM8dnTLi4sJ1Pi9YHdx6Urw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] - libc: [glibc] '@oxc-parser/binding-linux-x64-gnu@0.117.0': resolution: {integrity: sha512-1QrTrf8rige7UPJrYuDKJLQOuJlgkt+nRSJLBMHWNm9TdivzP48HaK3f4q18EjNlglKtn03lgjMu4fryDm8X4A==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] - libc: [glibc] '@oxc-parser/binding-linux-x64-musl@0.117.0': resolution: {integrity: sha512-gRvK6HPzF5ITRL68fqb2WYYs/hGviPIbkV84HWCgiJX+LkaOpp+HIHQl3zVZdyKHwopXToTbXbtx/oFjDjl8pg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] - libc: [musl] '@oxc-parser/binding-openharmony-arm64@0.117.0': resolution: {integrity: sha512-QPJvFbnnDZZY7xc+xpbIBWLThcGBakwaYA9vKV8b3+oS5MGfAZUoTFJcix5+Zg2Ri46sOfrUim6Y6jsKNcssAQ==} @@ -1111,56 +1098,48 @@ packages: engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] - libc: [glibc] '@oxc-transform/binding-linux-arm64-musl@0.117.0': resolution: {integrity: sha512-ykxpPQp0eAcSmhy0Y3qKvdanHY4d8THPonDfmCoktUXb6r0X6qnjpJB3V+taN1wevW55bOEZd97kxtjTKjqhmg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] - libc: [musl] '@oxc-transform/binding-linux-ppc64-gnu@0.117.0': resolution: {integrity: sha512-Rvspti4Kr7eq6zSrURK5WjscfWQPvmy/KjJZV45neRKW8RLonE3r9+NgrwSLGoHvQ3F24fbqlkplox1RtlhH5A==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] - libc: [glibc] '@oxc-transform/binding-linux-riscv64-gnu@0.117.0': resolution: {integrity: sha512-Dr2ZW9ZZ4l1eQ5JUEUY3smBh4JFPCPuybWaDZTLn3ADZjyd8ZtNXEjeMT8rQbbhbgSL9hEgbwaqraole3FNThQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] - libc: [glibc] '@oxc-transform/binding-linux-riscv64-musl@0.117.0': resolution: {integrity: sha512-oD1Bnes1bIC3LVBSrWEoSUBj6fvatESPwAVWfJVGVQlqWuOs/ZBn1e4Nmbipo3KGPHK7DJY75r/j7CQCxhrOFQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] - libc: [musl] '@oxc-transform/binding-linux-s390x-gnu@0.117.0': resolution: {integrity: sha512-qT//IAPLvse844t99Kff5j055qEbXfwzWgvCMb0FyjisnB8foy25iHZxZIocNBe6qwrCYWUP1M8rNrB/WyfS1Q==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] - libc: [glibc] '@oxc-transform/binding-linux-x64-gnu@0.117.0': resolution: {integrity: sha512-2YEO5X+KgNzFqRVO5dAkhjcI5gwxus4NSWVl/+cs2sI6P0MNPjqE3VWPawl4RTC11LvetiiZdHcujUCPM8aaUw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] - libc: [glibc] '@oxc-transform/binding-linux-x64-musl@0.117.0': resolution: {integrity: sha512-3wqWbTSaIFZvDr1aqmTul4cg8PRWYh6VC52E8bLI7ytgS/BwJLW+sDUU2YaGIds4sAf/1yKeJRmudRCDPW9INg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] - libc: [musl] '@oxc-transform/binding-openharmony-arm64@0.117.0': resolution: {integrity: sha512-Ebxx6NPqhzlrjvx4+PdSqbOq+li0f7X59XtJljDghkbJsbnkHvhLmPR09ifHt5X32UlZN63ekjwcg/nbmHLLlA==} @@ -1220,42 +1199,36 @@ packages: engines: {node: '>= 10.0.0'} cpu: [arm] os: [linux] - libc: [glibc] '@parcel/watcher-linux-arm-musl@2.5.6': resolution: {integrity: sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg==} engines: {node: '>= 10.0.0'} cpu: [arm] os: [linux] - libc: [musl] '@parcel/watcher-linux-arm64-glibc@2.5.6': resolution: {integrity: sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [linux] - libc: [glibc] '@parcel/watcher-linux-arm64-musl@2.5.6': resolution: {integrity: sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [linux] - libc: [musl] '@parcel/watcher-linux-x64-glibc@2.5.6': resolution: {integrity: sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [linux] - libc: [glibc] '@parcel/watcher-linux-x64-musl@2.5.6': resolution: {integrity: sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [linux] - libc: [musl] '@parcel/watcher-wasm@2.5.6': resolution: {integrity: sha512-byAiBZ1t3tXQvc8dMD/eoyE7lTXYorhn+6uVW5AC+JGI1KtJC/LvDche5cfUE+qiefH+Ybq0bUCJU0aB1cSHUA==} @@ -1475,79 +1448,66 @@ packages: resolution: {integrity: sha512-RzeBwv0B3qtVBWtcuABtSuCzToo2IEAIQrcyB/b2zMvBWVbjo8bZDjACUpnaafaxhTw2W+imQbP2BD1usasK4g==} cpu: [arm] os: [linux] - libc: [glibc] '@rollup/rollup-linux-arm-musleabihf@4.60.0': resolution: {integrity: sha512-Sf7zusNI2CIU1HLzuu9Tc5YGAHEZs5Lu7N1ssJG4Tkw6e0MEsN7NdjUDDfGNHy2IU+ENyWT+L2obgWiguWibWQ==} cpu: [arm] os: [linux] - libc: [musl] '@rollup/rollup-linux-arm64-gnu@4.60.0': resolution: {integrity: sha512-DX2x7CMcrJzsE91q7/O02IJQ5/aLkVtYFryqCjduJhUfGKG6yJV8hxaw8pZa93lLEpPTP/ohdN4wFz7yp/ry9A==} cpu: [arm64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-arm64-musl@4.60.0': resolution: {integrity: sha512-09EL+yFVbJZlhcQfShpswwRZ0Rg+z/CsSELFCnPt3iK+iqwGsI4zht3secj5vLEs957QvFFXnzAT0FFPIxSrkQ==} cpu: [arm64] os: [linux] - libc: [musl] '@rollup/rollup-linux-loong64-gnu@4.60.0': resolution: {integrity: sha512-i9IcCMPr3EXm8EQg5jnja0Zyc1iFxJjZWlb4wr7U2Wx/GrddOuEafxRdMPRYVaXjgbhvqalp6np07hN1w9kAKw==} cpu: [loong64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-loong64-musl@4.60.0': resolution: {integrity: sha512-DGzdJK9kyJ+B78MCkWeGnpXJ91tK/iKA6HwHxF4TAlPIY7GXEvMe8hBFRgdrR9Ly4qebR/7gfUs9y2IoaVEyog==} cpu: [loong64] os: [linux] - libc: [musl] '@rollup/rollup-linux-ppc64-gnu@4.60.0': resolution: {integrity: sha512-RwpnLsqC8qbS8z1H1AxBA1H6qknR4YpPR9w2XX0vo2Sz10miu57PkNcnHVaZkbqyw/kUWfKMI73jhmfi9BRMUQ==} cpu: [ppc64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-ppc64-musl@4.60.0': resolution: {integrity: sha512-Z8pPf54Ly3aqtdWC3G4rFigZgNvd+qJlOE52fmko3KST9SoGfAdSRCwyoyG05q1HrrAblLbk1/PSIV+80/pxLg==} cpu: [ppc64] os: [linux] - libc: [musl] '@rollup/rollup-linux-riscv64-gnu@4.60.0': resolution: {integrity: sha512-3a3qQustp3COCGvnP4SvrMHnPQ9d1vzCakQVRTliaz8cIp/wULGjiGpbcqrkv0WrHTEp8bQD/B3HBjzujVWLOA==} cpu: [riscv64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-riscv64-musl@4.60.0': resolution: {integrity: sha512-pjZDsVH/1VsghMJ2/kAaxt6dL0psT6ZexQVrijczOf+PeP2BUqTHYejk3l6TlPRydggINOeNRhvpLa0AYpCWSQ==} cpu: [riscv64] os: [linux] - libc: [musl] '@rollup/rollup-linux-s390x-gnu@4.60.0': resolution: {integrity: sha512-3ObQs0BhvPgiUVZrN7gqCSvmFuMWvWvsjG5ayJ3Lraqv+2KhOsp+pUbigqbeWqueGIsnn+09HBw27rJ+gYK4VQ==} cpu: [s390x] os: [linux] - libc: [glibc] '@rollup/rollup-linux-x64-gnu@4.60.0': resolution: {integrity: sha512-EtylprDtQPdS5rXvAayrNDYoJhIz1/vzN2fEubo3yLE7tfAw+948dO0g4M0vkTVFhKojnF+n6C8bDNe+gDRdTg==} cpu: [x64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-x64-musl@4.60.0': resolution: {integrity: sha512-k09oiRCi/bHU9UVFqD17r3eJR9bn03TyKraCrlz5ULFJGdJGi7VOmm9jl44vOJvRJ6P7WuBi/s2A97LxxHGIdw==} cpu: [x64] os: [linux] - libc: [musl] '@rollup/rollup-openbsd-x64@4.60.0': resolution: {integrity: sha512-1o/0/pIhozoSaDJoDcec+IVLbnRtQmHwPV730+AOD29lHEEo4F5BEUB24H0OBdhbBBDwIOSuf7vgg0Ywxdfiiw==} @@ -1634,28 +1594,24 @@ packages: engines: {node: '>= 20'} cpu: [arm64] os: [linux] - libc: [glibc] '@tailwindcss/oxide-linux-arm64-musl@4.2.2': resolution: {integrity: sha512-oCfG/mS+/+XRlwNjnsNLVwnMWYH7tn/kYPsNPh+JSOMlnt93mYNCKHYzylRhI51X+TbR+ufNhhKKzm6QkqX8ag==} engines: {node: '>= 20'} cpu: [arm64] os: [linux] - libc: [musl] '@tailwindcss/oxide-linux-x64-gnu@4.2.2': resolution: {integrity: sha512-rTAGAkDgqbXHNp/xW0iugLVmX62wOp2PoE39BTCGKjv3Iocf6AFbRP/wZT/kuCxC9QBh9Pu8XPkv/zCZB2mcMg==} engines: {node: '>= 20'} cpu: [x64] os: [linux] - libc: [glibc] '@tailwindcss/oxide-linux-x64-musl@4.2.2': resolution: {integrity: sha512-XW3t3qwbIwiSyRCggeO2zxe3KWaEbM0/kW9e8+0XpBgyKU4ATYzcVSMKteZJ1iukJ3HgHBjbg9P5YPRCVUxlnQ==} engines: {node: '>= 20'} cpu: [x64] os: [linux] - libc: [musl] '@tailwindcss/oxide-wasm32-wasi@4.2.2': resolution: {integrity: sha512-eKSztKsmEsn1O5lJ4ZAfyn41NfG7vzCg496YiGtMDV86jz1q/irhms5O0VrY6ZwTUkFy/EKG3RfWgxSI3VbZ8Q==} @@ -3292,28 +3248,24 @@ packages: engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] - libc: [glibc] lightningcss-linux-arm64-musl@1.32.0: resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] - libc: [musl] lightningcss-linux-x64-gnu@1.32.0: resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] - libc: [glibc] lightningcss-linux-x64-musl@1.32.0: resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] - libc: [musl] lightningcss-win32-arm64-msvc@1.32.0: resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} @@ -4699,6 +4651,10 @@ packages: util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + uuid@14.0.0: + resolution: {integrity: sha512-Qo+uWgilfSmAhXCMav1uYFynlQO7fMFiMVZsQqZRMIXp0O7rR7qjkj+cPvBHLgBqi960QCoo/PH2/6ZtVqKvrg==} + hasBin: true + valibot@1.2.0: resolution: {integrity: sha512-mm1rxUsmOxzrwnX5arGS+U4T25RdvpPjPN4yR0u9pUBov9+zGVtO84tif1eY4r6zWxVxu3KzIyknJy3rxfRZZg==} peerDependencies: @@ -9856,6 +9812,8 @@ snapshots: util-deprecate@1.0.2: {} + uuid@14.0.0: {} + valibot@1.2.0(typescript@5.9.3): optionalDependencies: typescript: 5.9.3