diff --git a/package-lock.json b/package-lock.json index badf18d..df32786 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,6 +28,7 @@ "dayjs": "^1.11.18", "dotenv": "^17.2.3", "express": "^5.1.0", + "firebase": "^12.5.0", "flatpickr": "^4.6.13", "html2pdf.js": "^0.12.1", "lucide-react": "^0.543.0", @@ -16178,6 +16179,620 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@firebase/ai": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@firebase/ai/-/ai-2.5.0.tgz", + "integrity": "sha512-OXv/jZLRjV9jTejWA4KOvW8gM1hNsLvQSCPwKhi2CEfe0Nap3rM6z+Ial0PGqXga0WgzhpypEvJOFvaAUFX3kg==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/app-check-interop-types": "0.3.3", + "@firebase/component": "0.7.0", + "@firebase/logger": "0.5.0", + "@firebase/util": "1.13.0", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@firebase/app": "0.x", + "@firebase/app-types": "0.x" + } + }, + "node_modules/@firebase/analytics": { + "version": "0.10.19", + "resolved": "https://registry.npmjs.org/@firebase/analytics/-/analytics-0.10.19.tgz", + "integrity": "sha512-3wU676fh60gaiVYQEEXsbGS4HbF2XsiBphyvvqDbtC1U4/dO4coshbYktcCHq+HFaGIK07iHOh4pME0hEq1fcg==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.7.0", + "@firebase/installations": "0.6.19", + "@firebase/logger": "0.5.0", + "@firebase/util": "1.13.0", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/analytics-compat": { + "version": "0.2.25", + "resolved": "https://registry.npmjs.org/@firebase/analytics-compat/-/analytics-compat-0.2.25.tgz", + "integrity": "sha512-fdzoaG0BEKbqksRDhmf4JoyZf16Wosrl0Y7tbZtJyVDOOwziE0vrFjmZuTdviL0yhak+Nco6rMsUUbkbD+qb6Q==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/analytics": "0.10.19", + "@firebase/analytics-types": "0.8.3", + "@firebase/component": "0.7.0", + "@firebase/util": "1.13.0", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/analytics-types": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/@firebase/analytics-types/-/analytics-types-0.8.3.tgz", + "integrity": "sha512-VrIp/d8iq2g501qO46uGz3hjbDb8xzYMrbu8Tp0ovzIzrvJZ2fvmj649gTjge/b7cCCcjT0H37g1gVtlNhnkbg==", + "license": "Apache-2.0" + }, + "node_modules/@firebase/app": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/@firebase/app/-/app-0.14.5.tgz", + "integrity": "sha512-zyNY77xJOGwcuB+xCxF8z8lSiHvD4ox7BCsqLEHEvgqQoRjxFZ0fkROR6NV5QyXmCqRLodMM8J5d2EStOocWIw==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.7.0", + "@firebase/logger": "0.5.0", + "@firebase/util": "1.13.0", + "idb": "7.1.1", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@firebase/app-check": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@firebase/app-check/-/app-check-0.11.0.tgz", + "integrity": "sha512-XAvALQayUMBJo58U/rxW02IhsesaxxfWVmVkauZvGEz3vOAjMEQnzFlyblqkc2iAaO82uJ2ZVyZv9XzPfxjJ6w==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.7.0", + "@firebase/logger": "0.5.0", + "@firebase/util": "1.13.0", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/app-check-compat": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@firebase/app-check-compat/-/app-check-compat-0.4.0.tgz", + "integrity": "sha512-UfK2Q8RJNjYM/8MFORltZRG9lJj11k0nW84rrffiKvcJxLf1jf6IEjCIkCamykHE73C6BwqhVfhIBs69GXQV0g==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/app-check": "0.11.0", + "@firebase/app-check-types": "0.5.3", + "@firebase/component": "0.7.0", + "@firebase/logger": "0.5.0", + "@firebase/util": "1.13.0", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/app-check-interop-types": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@firebase/app-check-interop-types/-/app-check-interop-types-0.3.3.tgz", + "integrity": "sha512-gAlxfPLT2j8bTI/qfe3ahl2I2YcBQ8cFIBdhAQA4I2f3TndcO+22YizyGYuttLHPQEpWkhmpFW60VCFEPg4g5A==", + "license": "Apache-2.0" + }, + "node_modules/@firebase/app-check-types": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/@firebase/app-check-types/-/app-check-types-0.5.3.tgz", + "integrity": "sha512-hyl5rKSj0QmwPdsAxrI5x1otDlByQ7bvNvVt8G/XPO2CSwE++rmSVf3VEhaeOR4J8ZFaF0Z0NDSmLejPweZ3ng==", + "license": "Apache-2.0" + }, + "node_modules/@firebase/app-compat": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/@firebase/app-compat/-/app-compat-0.5.5.tgz", + "integrity": "sha512-lVG/nRnXaot0rQSZazmTNqy83ti9O3+kdwoaE0d5wahRIWNoDirbIMcGVjDDgdmf4IE6FYreWOMh0L3DV1475w==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/app": "0.14.5", + "@firebase/component": "0.7.0", + "@firebase/logger": "0.5.0", + "@firebase/util": "1.13.0", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@firebase/app-types": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/@firebase/app-types/-/app-types-0.9.3.tgz", + "integrity": "sha512-kRVpIl4vVGJ4baogMDINbyrIOtOxqhkZQg4jTq3l8Lw6WSk0xfpEYzezFu+Kl4ve4fbPl79dvwRtaFqAC/ucCw==", + "license": "Apache-2.0" + }, + "node_modules/@firebase/auth-compat": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@firebase/auth-compat/-/auth-compat-0.6.1.tgz", + "integrity": "sha512-I0o2ZiZMnMTOQfqT22ur+zcGDVSAfdNZBHo26/Tfi8EllfR1BO7aTVo2rt/ts8o/FWsK8pOALLeVBGhZt8w/vg==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/auth": "1.11.1", + "@firebase/auth-types": "0.13.0", + "@firebase/component": "0.7.0", + "@firebase/util": "1.13.0", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/auth-compat/node_modules/@firebase/auth": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@firebase/auth/-/auth-1.11.1.tgz", + "integrity": "sha512-Mea0G/BwC1D0voSG+60Ylu3KZchXAFilXQ/hJXWCw3gebAu+RDINZA0dJMNeym7HFxBaBaByX8jSa7ys5+F2VA==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.7.0", + "@firebase/logger": "0.5.0", + "@firebase/util": "1.13.0", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@firebase/app": "0.x", + "@react-native-async-storage/async-storage": "^1.18.1" + }, + "peerDependenciesMeta": { + "@react-native-async-storage/async-storage": { + "optional": true + } + } + }, + "node_modules/@firebase/auth-interop-types": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@firebase/auth-interop-types/-/auth-interop-types-0.2.4.tgz", + "integrity": "sha512-JPgcXKCuO+CWqGDnigBtvo09HeBs5u/Ktc2GaFj2m01hLarbxthLNm7Fk8iOP1aqAtXV+fnnGj7U28xmk7IwVA==", + "license": "Apache-2.0" + }, + "node_modules/@firebase/auth-types": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@firebase/auth-types/-/auth-types-0.13.0.tgz", + "integrity": "sha512-S/PuIjni0AQRLF+l9ck0YpsMOdE8GO2KU6ubmBB7P+7TJUCQDa3R1dlgYm9UzGbbePMZsp0xzB93f2b/CgxMOg==", + "license": "Apache-2.0", + "peerDependencies": { + "@firebase/app-types": "0.x", + "@firebase/util": "1.x" + } + }, + "node_modules/@firebase/component": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@firebase/component/-/component-0.7.0.tgz", + "integrity": "sha512-wR9En2A+WESUHexjmRHkqtaVH94WLNKt6rmeqZhSLBybg4Wyf0Umk04SZsS6sBq4102ZsDBFwoqMqJYj2IoDSg==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/util": "1.13.0", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@firebase/data-connect": { + "version": "0.3.11", + "resolved": "https://registry.npmjs.org/@firebase/data-connect/-/data-connect-0.3.11.tgz", + "integrity": "sha512-G258eLzAD6im9Bsw+Qm1Z+P4x0PGNQ45yeUuuqe5M9B1rn0RJvvsQCRHXgE52Z+n9+WX1OJd/crcuunvOGc7Vw==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/auth-interop-types": "0.2.4", + "@firebase/component": "0.7.0", + "@firebase/logger": "0.5.0", + "@firebase/util": "1.13.0", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/database": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@firebase/database/-/database-1.1.0.tgz", + "integrity": "sha512-gM6MJFae3pTyNLoc9VcJNuaUDej0ctdjn3cVtILo3D5lpp0dmUHHLFN/pUKe7ImyeB1KAvRlEYxvIHNF04Filg==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/app-check-interop-types": "0.3.3", + "@firebase/auth-interop-types": "0.2.4", + "@firebase/component": "0.7.0", + "@firebase/logger": "0.5.0", + "@firebase/util": "1.13.0", + "faye-websocket": "0.11.4", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@firebase/database-compat": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@firebase/database-compat/-/database-compat-2.1.0.tgz", + "integrity": "sha512-8nYc43RqxScsePVd1qe1xxvWNf0OBnbwHxmXJ7MHSuuTVYFO3eLyLW3PiCKJ9fHnmIz4p4LbieXwz+qtr9PZDg==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.7.0", + "@firebase/database": "1.1.0", + "@firebase/database-types": "1.0.16", + "@firebase/logger": "0.5.0", + "@firebase/util": "1.13.0", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@firebase/database-types": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/@firebase/database-types/-/database-types-1.0.16.tgz", + "integrity": "sha512-xkQLQfU5De7+SPhEGAXFBnDryUWhhlFXelEg2YeZOQMCdoe7dL64DDAd77SQsR+6uoXIZY5MB4y/inCs4GTfcw==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/app-types": "0.9.3", + "@firebase/util": "1.13.0" + } + }, + "node_modules/@firebase/firestore": { + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/@firebase/firestore/-/firestore-4.9.2.tgz", + "integrity": "sha512-iuA5+nVr/IV/Thm0Luoqf2mERUvK9g791FZpUJV1ZGXO6RL2/i/WFJUj5ZTVXy5pRjpWYO+ZzPcReNrlilmztA==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.7.0", + "@firebase/logger": "0.5.0", + "@firebase/util": "1.13.0", + "@firebase/webchannel-wrapper": "1.0.5", + "@grpc/grpc-js": "~1.9.0", + "@grpc/proto-loader": "^0.7.8", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/firestore-compat": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@firebase/firestore-compat/-/firestore-compat-0.4.2.tgz", + "integrity": "sha512-cy7ov6SpFBx+PHwFdOOjbI7kH00uNKmIFurAn560WiPCZXy9EMnil1SOG7VF4hHZKdenC+AHtL4r3fNpirpm0w==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.7.0", + "@firebase/firestore": "4.9.2", + "@firebase/firestore-types": "3.0.3", + "@firebase/util": "1.13.0", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/firestore-types": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@firebase/firestore-types/-/firestore-types-3.0.3.tgz", + "integrity": "sha512-hD2jGdiWRxB/eZWF89xcK9gF8wvENDJkzpVFb4aGkzfEaKxVRD1kjz1t1Wj8VZEp2LCB53Yx1zD8mrhQu87R6Q==", + "license": "Apache-2.0", + "peerDependencies": { + "@firebase/app-types": "0.x", + "@firebase/util": "1.x" + } + }, + "node_modules/@firebase/functions": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/@firebase/functions/-/functions-0.13.1.tgz", + "integrity": "sha512-sUeWSb0rw5T+6wuV2o9XNmh9yHxjFI9zVGFnjFi+n7drTEWpl7ZTz1nROgGrSu472r+LAaj+2YaSicD4R8wfbw==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/app-check-interop-types": "0.3.3", + "@firebase/auth-interop-types": "0.2.4", + "@firebase/component": "0.7.0", + "@firebase/messaging-interop-types": "0.2.3", + "@firebase/util": "1.13.0", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/functions-compat": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@firebase/functions-compat/-/functions-compat-0.4.1.tgz", + "integrity": "sha512-AxxUBXKuPrWaVNQ8o1cG1GaCAtXT8a0eaTDfqgS5VsRYLAR0ALcfqDLwo/QyijZj1w8Qf8n3Qrfy/+Im245hOQ==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.7.0", + "@firebase/functions": "0.13.1", + "@firebase/functions-types": "0.6.3", + "@firebase/util": "1.13.0", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/functions-types": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/@firebase/functions-types/-/functions-types-0.6.3.tgz", + "integrity": "sha512-EZoDKQLUHFKNx6VLipQwrSMh01A1SaL3Wg6Hpi//x6/fJ6Ee4hrAeswK99I5Ht8roiniKHw4iO0B1Oxj5I4plg==", + "license": "Apache-2.0" + }, + "node_modules/@firebase/installations": { + "version": "0.6.19", + "resolved": "https://registry.npmjs.org/@firebase/installations/-/installations-0.6.19.tgz", + "integrity": "sha512-nGDmiwKLI1lerhwfwSHvMR9RZuIH5/8E3kgUWnVRqqL7kGVSktjLTWEMva7oh5yxQ3zXfIlIwJwMcaM5bK5j8Q==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.7.0", + "@firebase/util": "1.13.0", + "idb": "7.1.1", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/installations-compat": { + "version": "0.2.19", + "resolved": "https://registry.npmjs.org/@firebase/installations-compat/-/installations-compat-0.2.19.tgz", + "integrity": "sha512-khfzIY3EI5LePePo7vT19/VEIH1E3iYsHknI/6ek9T8QCozAZshWT9CjlwOzZrKvTHMeNcbpo/VSOSIWDSjWdQ==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.7.0", + "@firebase/installations": "0.6.19", + "@firebase/installations-types": "0.5.3", + "@firebase/util": "1.13.0", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/installations-types": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/@firebase/installations-types/-/installations-types-0.5.3.tgz", + "integrity": "sha512-2FJI7gkLqIE0iYsNQ1P751lO3hER+Umykel+TkLwHj6plzWVxqvfclPUZhcKFVQObqloEBTmpi2Ozn7EkCABAA==", + "license": "Apache-2.0", + "peerDependencies": { + "@firebase/app-types": "0.x" + } + }, + "node_modules/@firebase/logger": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@firebase/logger/-/logger-0.5.0.tgz", + "integrity": "sha512-cGskaAvkrnh42b3BA3doDWeBmuHFO/Mx5A83rbRDYakPjO9bJtRL3dX7javzc2Rr/JHZf4HlterTW2lUkfeN4g==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@firebase/messaging": { + "version": "0.12.23", + "resolved": "https://registry.npmjs.org/@firebase/messaging/-/messaging-0.12.23.tgz", + "integrity": "sha512-cfuzv47XxqW4HH/OcR5rM+AlQd1xL/VhuaeW/wzMW1LFrsFcTn0GND/hak1vkQc2th8UisBcrkVcQAnOnKwYxg==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.7.0", + "@firebase/installations": "0.6.19", + "@firebase/messaging-interop-types": "0.2.3", + "@firebase/util": "1.13.0", + "idb": "7.1.1", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/messaging-compat": { + "version": "0.2.23", + "resolved": "https://registry.npmjs.org/@firebase/messaging-compat/-/messaging-compat-0.2.23.tgz", + "integrity": "sha512-SN857v/kBUvlQ9X/UjAqBoQ2FEaL1ZozpnmL1ByTe57iXkmnVVFm9KqAsTfmf+OEwWI4kJJe9NObtN/w22lUgg==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.7.0", + "@firebase/messaging": "0.12.23", + "@firebase/util": "1.13.0", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/messaging-interop-types": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@firebase/messaging-interop-types/-/messaging-interop-types-0.2.3.tgz", + "integrity": "sha512-xfzFaJpzcmtDjycpDeCUj0Ge10ATFi/VHVIvEEjDNc3hodVBQADZ7BWQU7CuFpjSHE+eLuBI13z5F/9xOoGX8Q==", + "license": "Apache-2.0" + }, + "node_modules/@firebase/performance": { + "version": "0.7.9", + "resolved": "https://registry.npmjs.org/@firebase/performance/-/performance-0.7.9.tgz", + "integrity": "sha512-UzybENl1EdM2I1sjYm74xGt/0JzRnU/0VmfMAKo2LSpHJzaj77FCLZXmYQ4oOuE+Pxtt8Wy2BVJEENiZkaZAzQ==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.7.0", + "@firebase/installations": "0.6.19", + "@firebase/logger": "0.5.0", + "@firebase/util": "1.13.0", + "tslib": "^2.1.0", + "web-vitals": "^4.2.4" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/performance-compat": { + "version": "0.2.22", + "resolved": "https://registry.npmjs.org/@firebase/performance-compat/-/performance-compat-0.2.22.tgz", + "integrity": "sha512-xLKxaSAl/FVi10wDX/CHIYEUP13jXUjinL+UaNXT9ByIvxII5Ne5150mx6IgM8G6Q3V+sPiw9C8/kygkyHUVxg==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.7.0", + "@firebase/logger": "0.5.0", + "@firebase/performance": "0.7.9", + "@firebase/performance-types": "0.2.3", + "@firebase/util": "1.13.0", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/performance-types": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@firebase/performance-types/-/performance-types-0.2.3.tgz", + "integrity": "sha512-IgkyTz6QZVPAq8GSkLYJvwSLr3LS9+V6vNPQr0x4YozZJiLF5jYixj0amDtATf1X0EtYHqoPO48a9ija8GocxQ==", + "license": "Apache-2.0" + }, + "node_modules/@firebase/performance/node_modules/web-vitals": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-4.2.4.tgz", + "integrity": "sha512-r4DIlprAGwJ7YM11VZp4R884m0Vmgr6EAKe3P+kO0PPj3Unqyvv59rczf6UiGcb9Z8QxZVcqKNwv/g0WNdWwsw==", + "license": "Apache-2.0" + }, + "node_modules/@firebase/remote-config": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@firebase/remote-config/-/remote-config-0.7.0.tgz", + "integrity": "sha512-dX95X6WlW7QlgNd7aaGdjAIZUiQkgWgNS+aKNu4Wv92H1T8Ue/NDUjZHd9xb8fHxLXIHNZeco9/qbZzr500MjQ==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.7.0", + "@firebase/installations": "0.6.19", + "@firebase/logger": "0.5.0", + "@firebase/util": "1.13.0", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/remote-config-compat": { + "version": "0.2.20", + "resolved": "https://registry.npmjs.org/@firebase/remote-config-compat/-/remote-config-compat-0.2.20.tgz", + "integrity": "sha512-P/ULS9vU35EL9maG7xp66uljkZgcPMQOxLj3Zx2F289baTKSInE6+YIkgHEi1TwHoddC/AFePXPpshPlEFkbgg==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.7.0", + "@firebase/logger": "0.5.0", + "@firebase/remote-config": "0.7.0", + "@firebase/remote-config-types": "0.5.0", + "@firebase/util": "1.13.0", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/remote-config-types": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@firebase/remote-config-types/-/remote-config-types-0.5.0.tgz", + "integrity": "sha512-vI3bqLoF14L/GchtgayMiFpZJF+Ao3uR8WCde0XpYNkSokDpAKca2DxvcfeZv7lZUqkUwQPL2wD83d3vQ4vvrg==", + "license": "Apache-2.0" + }, + "node_modules/@firebase/storage": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@firebase/storage/-/storage-0.14.0.tgz", + "integrity": "sha512-xWWbb15o6/pWEw8H01UQ1dC5U3rf8QTAzOChYyCpafV6Xki7KVp3Yaw2nSklUwHEziSWE9KoZJS7iYeyqWnYFA==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.7.0", + "@firebase/util": "1.13.0", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/storage-compat": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@firebase/storage-compat/-/storage-compat-0.4.0.tgz", + "integrity": "sha512-vDzhgGczr1OfcOy285YAPur5pWDEvD67w4thyeCUh6Ys0izN9fNYtA1MJERmNBfqjqu0lg0FM5GLbw0Il21M+g==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.7.0", + "@firebase/storage": "0.14.0", + "@firebase/storage-types": "0.8.3", + "@firebase/util": "1.13.0", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/storage-types": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/@firebase/storage-types/-/storage-types-0.8.3.tgz", + "integrity": "sha512-+Muk7g9uwngTpd8xn9OdF/D48uiQ7I1Fae7ULsWPuKoCH3HU7bfFPhxtJYzyhjdniowhuDpQcfPmuNRAqZEfvg==", + "license": "Apache-2.0", + "peerDependencies": { + "@firebase/app-types": "0.x", + "@firebase/util": "1.x" + } + }, + "node_modules/@firebase/util": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/@firebase/util/-/util-1.13.0.tgz", + "integrity": "sha512-0AZUyYUfpMNcztR5l09izHwXkZpghLgCUaAGjtMwXnCg3bj4ml5VgiwqOMOxJ+Nw4qN/zJAaOQBcJ7KGkWStqQ==", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@firebase/webchannel-wrapper": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@firebase/webchannel-wrapper/-/webchannel-wrapper-1.0.5.tgz", + "integrity": "sha512-+uGNN7rkfn41HLO0vekTFhTxk61eKa8mTpRGLO0QSqlQdKvIoGAvLp3ppdVIWbTGYJWM6Kp0iN+PjMIOcnVqTw==", + "license": "Apache-2.0" + }, "node_modules/@floating-ui/core": { "version": "1.7.3", "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.3.tgz", @@ -16206,6 +16821,78 @@ "license": "MIT", "optional": true }, + "node_modules/@grpc/grpc-js": { + "version": "1.9.15", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.9.15.tgz", + "integrity": "sha512-nqE7Hc0AzI+euzUwDAy0aY5hCp10r734gMGRdU+qOPX0XSceI2ULrcXB5U2xSc5VkWwalCj4M7GzCAygZl2KoQ==", + "license": "Apache-2.0", + "dependencies": { + "@grpc/proto-loader": "^0.7.8", + "@types/node": ">=12.12.47" + }, + "engines": { + "node": "^8.13.0 || >=10.10.0" + } + }, + "node_modules/@grpc/proto-loader": { + "version": "0.7.15", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.15.tgz", + "integrity": "sha512-tMXdRCfYVixjuFK+Hk0Q1s38gV9zDiDJfWL3h1rv4Qc39oILCu1TRTDt7+fGUI8K4G1Fj125Hx/ru3azECWTyQ==", + "license": "Apache-2.0", + "dependencies": { + "lodash.camelcase": "^4.3.0", + "long": "^5.0.0", + "protobufjs": "^7.2.5", + "yargs": "^17.7.2" + }, + "bin": { + "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@grpc/proto-loader/node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@grpc/proto-loader/node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@grpc/proto-loader/node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, "node_modules/@humanwhocodes/config-array": { "version": "0.13.0", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", @@ -17165,6 +17852,70 @@ "url": "https://opencollective.com/popperjs" } }, + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==", + "license": "BSD-3-Clause" + }, "node_modules/@react-aria/ssr": { "version": "3.9.10", "resolved": "https://registry.npmjs.org/@react-aria/ssr/-/ssr-3.9.10.tgz", @@ -24090,6 +24841,66 @@ "node": ">=8" } }, + "node_modules/firebase": { + "version": "12.5.0", + "resolved": "https://registry.npmjs.org/firebase/-/firebase-12.5.0.tgz", + "integrity": "sha512-Ak8JcpH7FL6kiv0STwkv5+3CYEROO9iFWSx7OCZVvc4kIIABAIyAGs1mPGaHRxGUIApFZdMCXA7baq17uS6Mow==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/ai": "2.5.0", + "@firebase/analytics": "0.10.19", + "@firebase/analytics-compat": "0.2.25", + "@firebase/app": "0.14.5", + "@firebase/app-check": "0.11.0", + "@firebase/app-check-compat": "0.4.0", + "@firebase/app-compat": "0.5.5", + "@firebase/app-types": "0.9.3", + "@firebase/auth": "1.11.1", + "@firebase/auth-compat": "0.6.1", + "@firebase/data-connect": "0.3.11", + "@firebase/database": "1.1.0", + "@firebase/database-compat": "2.1.0", + "@firebase/firestore": "4.9.2", + "@firebase/firestore-compat": "0.4.2", + "@firebase/functions": "0.13.1", + "@firebase/functions-compat": "0.4.1", + "@firebase/installations": "0.6.19", + "@firebase/installations-compat": "0.2.19", + "@firebase/messaging": "0.12.23", + "@firebase/messaging-compat": "0.2.23", + "@firebase/performance": "0.7.9", + "@firebase/performance-compat": "0.2.22", + "@firebase/remote-config": "0.7.0", + "@firebase/remote-config-compat": "0.2.20", + "@firebase/storage": "0.14.0", + "@firebase/storage-compat": "0.4.0", + "@firebase/util": "1.13.0" + } + }, + "node_modules/firebase/node_modules/@firebase/auth": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@firebase/auth/-/auth-1.11.1.tgz", + "integrity": "sha512-Mea0G/BwC1D0voSG+60Ylu3KZchXAFilXQ/hJXWCw3gebAu+RDINZA0dJMNeym7HFxBaBaByX8jSa7ys5+F2VA==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.7.0", + "@firebase/logger": "0.5.0", + "@firebase/util": "1.13.0", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@firebase/app": "0.x", + "@react-native-async-storage/async-storage": "^1.18.1" + }, + "peerDependenciesMeta": { + "@react-native-async-storage/async-storage": { + "optional": true + } + } + }, "node_modules/flat-cache": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", @@ -27269,6 +28080,27 @@ } } }, + "node_modules/jsdom/node_modules/ws": { + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "license": "MIT", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/jsesc": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", @@ -27566,6 +28398,12 @@ "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", "license": "MIT" }, + "node_modules/lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", + "license": "MIT" + }, "node_modules/lodash.clonedeep": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", @@ -27609,6 +28447,12 @@ "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", "license": "MIT" }, + "node_modules/long": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz", + "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==", + "license": "Apache-2.0" + }, "node_modules/longest-streak": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", @@ -30912,23 +31756,6 @@ "node": ">= 0.8.0" } }, - "node_modules/prettier": { - "version": "2.8.8", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", - "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", - "license": "MIT", - "optional": true, - "peer": true, - "bin": { - "prettier": "bin-prettier.js" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, "node_modules/pretty-bytes": { "version": "5.6.0", "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", @@ -31247,6 +32074,30 @@ "prosemirror-transform": "^1.1.0" } }, + "node_modules/protobufjs": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.5.4.tgz", + "integrity": "sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg==", + "hasInstallScript": true, + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/node": ">=13.7.0", + "long": "^5.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -32030,20 +32881,6 @@ "node": ">=14.0.0" } }, - "node_modules/react-scripts/node_modules/yaml": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.1.tgz", - "integrity": "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==", - "license": "ISC", - "optional": true, - "peer": true, - "bin": { - "yaml": "bin.mjs" - }, - "engines": { - "node": ">= 14.6" - } - }, "node_modules/react-transition-group": { "version": "4.4.5", "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", @@ -34869,9 +35706,9 @@ } }, "node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", "license": "Apache-2.0", "peer": true, "bin": { @@ -34879,7 +35716,7 @@ "tsserver": "bin/tsserver" }, "engines": { - "node": ">=14.17" + "node": ">=4.2.0" } }, "node_modules/uc.micro": { @@ -35930,27 +36767,6 @@ "node": ">= 0.6" } }, - "node_modules/webpack-dev-server/node_modules/ws": { - "version": "8.18.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", - "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", - "license": "MIT", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, "node_modules/webpack-manifest-plugin": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/webpack-manifest-plugin/-/webpack-manifest-plugin-4.1.1.tgz", @@ -36628,16 +37444,16 @@ } }, "node_modules/ws": { - "version": "7.5.10", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", - "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "version": "8.18.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", + "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", "license": "MIT", "engines": { - "node": ">=8.3.0" + "node": ">=10.0.0" }, "peerDependencies": { "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" + "utf-8-validate": ">=5.0.2" }, "peerDependenciesMeta": { "bufferutil": { diff --git a/package.json b/package.json index 6b0153b..07df497 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "dayjs": "^1.11.18", "dotenv": "^17.2.3", "express": "^5.1.0", + "firebase": "^12.5.0", "flatpickr": "^4.6.13", "html2pdf.js": "^0.12.1", "lucide-react": "^0.543.0", @@ -83,4 +84,4 @@ "overrides": { "react": "$react" } -} \ No newline at end of file +} diff --git a/src/components/AgendarConsulta/FormNovaConsulta.jsx b/src/components/AgendarConsulta/FormNovaConsulta.jsx index bc261a6..acbfe29 100644 --- a/src/components/AgendarConsulta/FormNovaConsulta.jsx +++ b/src/components/AgendarConsulta/FormNovaConsulta.jsx @@ -69,7 +69,7 @@ const FormNovaConsulta = ({ onCancel, onSave, setAgendamento, agendamento }) => }, [authHeader]); useEffect(() => { -<<<<<<< HEAD +<<<<<<< Updated upstream ChamarMedicos(); }, [ChamarMedicos]); ======= @@ -78,7 +78,7 @@ const FormNovaConsulta = ({ onCancel, onSave, setAgendamento, agendamento }) => setHorarioInicio(formatarHora(agendamento.scheduled_at)); } }, []) ->>>>>>> melhoriasAgendamentos +>>>>>>> Stashed changes useEffect(() => { if (!agendamento.dataAtendimento || !agendamento.doctor_id) return; diff --git a/src/components/doctors/DoctorForm.jsx b/src/components/doctors/DoctorForm.jsx index 22b5c42..4da6185 100644 --- a/src/components/doctors/DoctorForm.jsx +++ b/src/components/doctors/DoctorForm.jsx @@ -1,15 +1,18 @@ import React, { useState, useRef, useCallback } from "react"; import { Link, useNavigate, useLocation } from "react-router-dom"; +import { useAuth } from "../components/utils/AuthProvider"; +import API_KEY from "../components/utils/apiKeys"; import "./DoctorForm.css"; import HorariosDisponibilidade from "../doctors/HorariosDisponibilidade"; +import { useAuth } from '../utils/AuthProvider'; +import API_KEY from '../utils/apiKeys'; -const ENDPOINT_AVAILABILITY = - "https://mock.apidog.com/m1/1053378-0-default/rest/v1/doctor_availability"; +const ENDPOINT_AVAILABILITY = "https://yuanqfswhberkoevtmfr.supabase.co/rest/v1/doctor_availability"; function DoctorForm({ onSave, onCancel, formData, setFormData, isLoading }) { const navigate = useNavigate(); const location = useLocation(); - + const { getAuthorizationHeader } = useAuth(); const FormatTelefones = (valor) => { const digits = String(valor).replace(/\D/g, "").slice(0, 11); @@ -54,7 +57,6 @@ function DoctorForm({ onSave, onCancel, formData, setFormData, isLoading }) { ); }; - const [avatarUrl, setAvatarUrl] = useState(null); const [showRequiredModal, setShowRequiredModal] = useState(false); const [emptyFields, setEmptyFields] = useState([]); @@ -74,6 +76,15 @@ function DoctorForm({ onSave, onCancel, formData, setFormData, isLoading }) { horarios: false, }); + const resolveAuthHeader = () => { + try { + const h = getAuthorizationHeader(); + return h || ''; + } catch { + return ''; + } + } + const handleToggleCollapse = (section) => { setCollapsedSections((prevState) => ({ ...prevState, @@ -126,14 +137,14 @@ function DoctorForm({ onSave, onCancel, formData, setFormData, isLoading }) { } }; -const handleAvailabilityUpdate = useCallback((newAvailability) => { - setFormData((prev) => { - if (JSON.stringify(prev.availability) !== JSON.stringify(newAvailability)) { - return { ...prev, availability: newAvailability }; - } - return prev; - }); -}, []); + const handleAvailabilityUpdate = useCallback((newAvailability) => { + setFormData((prev) => { + if (JSON.stringify(prev.availability) !== JSON.stringify(newAvailability)) { + return { ...prev, availability: newAvailability }; + } + return prev; + }); + }, []); const handleCepBlur = async () => { const cep = formData.cep?.replace(/\D/g, ""); @@ -213,21 +224,68 @@ const handleAvailabilityUpdate = useCallback((newAvailability) => { } }, 300); }; - const handleCreateAvailability = async (newAvailability) => { + + const handleCreateAvailability = async (doctorId, availabilityData) => { try { + const myHeaders = new Headers(); + const authHeader = resolveAuthHeader(); + if (authHeader) myHeaders.append("Authorization", authHeader); + myHeaders.append("Content-Type", "application/json"); + if (API_KEY) myHeaders.append("apikey", API_KEY); + const response = await fetch(ENDPOINT_AVAILABILITY, { method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify(newAvailability), + headers: myHeaders, + body: JSON.stringify({ + doctor_id: doctorId, + availability: availabilityData, + created_at: new Date().toISOString(), + updated_at: new Date().toISOString() + }), }); + + if (!response.ok) { + const errorText = await response.text(); + throw new Error(`Erro ${response.status}: ${errorText}`); + } + const data = await response.json(); - console.log("Disponibilidade criada :", data); - alert("Disponibilidade criada com sucesso!"); + console.log("Disponibilidade criada:", data); + return data; } catch (error) { console.error("Erro ao criar disponibilidade:", error); - alert("Erro ao criar disponibilidade."); + throw error; + } + }; + + const handlePatchAvailability = async (id, updatedAvailability) => { + try { + const myHeaders = new Headers(); + const authHeader = resolveAuthHeader(); + if (authHeader) myHeaders.append("Authorization", authHeader); + myHeaders.append("Content-Type", "application/json"); + if (API_KEY) myHeaders.append("apikey", API_KEY); + + const response = await fetch(`${ENDPOINT_AVAILABILITY}?id=eq.${id}`, { + method: "PATCH", + headers: myHeaders, + body: JSON.stringify({ + availability: updatedAvailability, + updated_at: new Date().toISOString() + }), + }); + + if (!response.ok) { + const errorText = await response.text(); + throw new Error(`Erro ${response.status}: ${errorText}`); + } + + const data = await response.json(); + console.log("Disponibilidade atualizada:", data); + return data; + } catch (error) { + console.error("Erro ao atualizar disponibilidade:", error); + throw error; } }; @@ -270,23 +328,29 @@ const handleAvailabilityUpdate = useCallback((newAvailability) => { } try { - await onSave({ ...formData }); + const savedDoctor = await onSave({ ...formData }); - if (formData.availability && formData.availability.length > 0) { + if (formData.availability && formData.availability.length > 0 && savedDoctor.id) { + if (formData.availabilityId) { + + await handlePatchAvailability(formData.availabilityId, formData.availability); + } else { + + await handleCreateAvailability(savedDoctor.id, formData.availability); + } } alert("Médico salvo com sucesso!"); } catch (error) { - console.error("Erro ao salvar médico:", error); - alert("Erro ao salvar médico."); - }; + console.error("Erro ao salvar médico ou disponibilidade:", error); + alert("Erro ao salvar médico ou disponibilidade."); + } }; const handleModalClose = () => { setShowRequiredModal(false); }; - return ( <> {/* Modal de Alerta */} @@ -727,4 +791,4 @@ const handleAvailabilityUpdate = useCallback((newAvailability) => { ); } -export default DoctorForm; +export default DoctorForm; \ No newline at end of file diff --git a/src/components/doctors/HorariosDisponibilidade.css b/src/components/doctors/HorariosDisponibilidade.css new file mode 100644 index 0000000..c726b67 --- /dev/null +++ b/src/components/doctors/HorariosDisponibilidade.css @@ -0,0 +1,154 @@ +.horarios-container { + max-width: 1100px; + margin: 0 auto; + font-family: "Inter", sans-serif; + display: grid; + grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); + gap: 15px; +} + +/* Cards mais compactos */ +.day-card { + background-color: #f9fafb; + border: 1px solid #e5e7eb; + border-radius: 8px; + padding: 8px; + height: 220px; + display: flex; + flex-direction: column; + justify-content: space-between; + transition: all 0.2s ease; +} + +.day-card:hover { + transform: translateY(-2px); + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.06); +} + +.day-card.checked { + background-color: #1f2937; + color: white; + border-color: #4b5563; +} + +/* Cabeçalho compacto */ +.day-header { + display: flex; + justify-content: space-between; + align-items: center; + padding: 8px; + border-radius: 6px; + border-bottom: 1px solid #e5e7eb; + cursor: pointer; +} + +.day-header.checked { + background-color: #1f2937; + color: white; + border-color: #4b5563; +} + +.day-header label { + display: flex; + align-items: center; + gap: 8px; + font-weight: 600; + font-size: 14px; +} + +/* Seção de blocos mais compacta */ +.blocks-section { + margin-top: 6px; + display: flex; + flex-direction: column; + gap: 6px; + flex-grow: 1; + overflow-y: auto; + padding-right: 2px; +} + +/* Blocos de tempo menores */ +.time-block { + background-color: #ffffff; + border: 1px solid #e5e7eb; + border-radius: 6px; + padding: 6px; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04); + transition: transform 0.15s, box-shadow 0.15s; +} + +.time-block:hover { + transform: translateY(-1px); + box-shadow: 0 2px 5px rgba(0, 0, 0, 0.08); +} + +.time-block.new { + background-color: #eef2ff; + border-color: #6366f1; +} + +/* Inputs compactos */ +.time-inputs { + display: flex; + flex-direction: column; + gap: 6px; +} + +.input-wrapper { + position: relative; +} + +.input-wrapper input { + padding: 4px 24px 4px 4px; + border: 1px solid #d1d5db; + border-radius: 4px; + width: 100%; + font-size: 13px; + outline: none; +} + +.clock-icon { + position: absolute; + right: 6px; + top: 50%; + transform: translateY(-50%); + color: #9ca3af; + font-size: 12px; +} + +/* Botões compactos */ +.btn-remove { + margin-top: 6px; + width: 100%; + background-color: #ef4444; + border: none; + color: white; + font-weight: bold; + padding: 4px 0; + border-radius: 4px; + cursor: pointer; + font-size: 12px; + transition: background-color 0.15s; +} + +.btn-remove:hover { + background-color: #dc2626; +} + +.btn-add { + background-color: #10b981; + color: white; + font-weight: bold; + border: none; + padding: 6px 12px; + border-radius: 6px; + cursor: pointer; + align-self: center; + transition: background-color 0.15s; + width: 100%; + font-size: 13px; +} + +.btn-add:hover { + background-color: #059669; +} \ No newline at end of file diff --git a/src/components/doctors/HorariosDisponibilidade.jsx b/src/components/doctors/HorariosDisponibilidade.jsx index bc8b83b..be13988 100644 --- a/src/components/doctors/HorariosDisponibilidade.jsx +++ b/src/components/doctors/HorariosDisponibilidade.jsx @@ -1,5 +1,6 @@ import React, { useState, useEffect, useCallback, useRef } from "react"; import { Clock } from "lucide-react"; +import "./HorariosDisponibilidade.css"; const initialBlockTemplate = { id: null, @@ -36,7 +37,6 @@ const HorariosDisponibilidade = ({ const handleDayCheck = useCallback((dayIndex, currentIsChecked) => { const isChecked = !currentIsChecked; - setAvailability((prev) => prev.map((day, i) => i === dayIndex @@ -63,7 +63,6 @@ const HorariosDisponibilidade = ({ const handleAddBlock = useCallback((dayIndex) => { const tempId = Date.now() + Math.random(); const newBlock = { ...initialBlockTemplate, id: tempId, isNew: true }; - setAvailability((prev) => prev.map((day, i) => i === dayIndex @@ -109,298 +108,91 @@ const HorariosDisponibilidade = ({ }, []); const handleSave = useCallback(() => { - if (onUpdate) onUpdate(availability); - }, [availability, onUpdate]); - - const renderTimeBlock = (dayIndex, bloco) => ( -
-
-
- -
- - handleTimeChange(dayIndex, bloco.id, "inicio", e.target.value) - } - style={{ - padding: "4px 6px", - border: "1px solid #d1d5db", - borderRadius: "6px", - width: "100%", - boxSizing: "border-box", - outline: "none", - fontSize: "13px", - }} - step="300" - /> - -
-
- -
- -
- - handleTimeChange(dayIndex, bloco.id, "termino", e.target.value) - } - style={{ - padding: "4px 6px", - border: "1px solid #d1d5db", - borderRadius: "6px", - width: "100%", - boxSizing: "border-box", - outline: "none", - fontSize: "13px", - }} - step="300" - /> - -
-
-
- - - {bloco.isNew && ( - - )} -
- ); + if (onUpdate) onUpdate(availability); + }, [availability, onUpdate]); return ( -
-
- {availability.map((day, dayIndex) => { - const isChecked = day.isChecked; +
+ {availability.map((day, dayIndex) => ( +
+
handleDayCheck(dayIndex, day.isChecked)} + > + +
- const dayHeaderStyle = { - display: "flex", - alignItems: "center", - justifyContent: "space-between", - padding: "12px 0", - borderBottom: "1px solid #e5e7eb", - marginBottom: "16px", - backgroundColor: isChecked ? "#1f2937" : "#f9fafb", - borderRadius: "8px", - paddingLeft: "16px", - paddingRight: "16px", - cursor: "pointer", - transition: "background-color 0.2s", - }; + {day.isChecked && ( +
+
+ {day.blocos.map((bloco) => ( +
+
+ - return ( -
-
handleDayCheck(dayIndex, isChecked)} - > - + +
+ + +
+ ))}
- {isChecked && ( -
- {day.blocos.length === 0 && ( -

- Nenhum bloco de horário definido. -

- )} - -
- {day.blocos.map((bloco) => - renderTimeBlock(dayIndex, bloco) - )} -
- - -
- )} +
- ); - })} -
+ )} +
+ ))}
); }; diff --git a/src/pages/DisponibilidadesDoctorPage.jsx b/src/pages/DisponibilidadesDoctorPage.jsx index e107595..3f2e27f 100644 --- a/src/pages/DisponibilidadesDoctorPage.jsx +++ b/src/pages/DisponibilidadesDoctorPage.jsx @@ -1,68 +1,75 @@ -import React, { useState, useEffect, useCallback } from "react"; +import React, { useState, useEffect, useCallback, useMemo } from "react"; import HorariosDisponibilidade from "../components/doctors/HorariosDisponibilidade"; -const ENDPOINT = - "https://mock.apidog.com/m1/1053378-0-default/rest/v1/doctor_availability"; +import { useAuth } from "../components/utils/AuthProvider"; +import API_KEY from "../components/utils/apiKeys"; +import { GetAllDoctors } from "../components/utils/Functions-Endpoints/Doctor"; -const MEDICOS_MOCKADOS = [ - { id: 53, nome: "João Silva" }, - { id: 19, nome: "Ana Costa" }, - { id: 11, nome: "Pedro Santos" }, -]; +const ENDPOINT = + "https://yuanqfswhberkoevtmfr.supabase.co/rest/v1/doctor_availability"; const diasDaSemana = ["Dom", "Seg", "Ter", "Qua", "Qui", "Sex", "Sáb"]; -const formatarDataHora = (isoString) => { - if (!isoString) return "N/A"; - try { - const data = new Date(isoString); - // Usa o toLocaleTimeString para extrair hora e minuto - return data.toLocaleTimeString("pt-BR", { - hour: "2-digit", - minute: "2-digit", - timeZone: "UTC", - }); - } catch { - return "Data Inválida"; - } -}; - const DisponibilidadesDoctorPage = () => { + const { getAuthorizationHeader } = useAuth(); const [disponibilidades, setDisponibilidades] = useState([]); const [loading, setLoading] = useState(false); - const [filtroMedicoNome, setFiltroMedicoNome] = useState(""); - const [gerenciarModo, setGerenciarModo] = useState(false); - const [editando, setEditando] = useState(null); // ID da disponibilidade sendo editada + const [doctors, setDoctors] = useState([]); + const [searchTerm, setSearchTerm] = useState(""); + const [selectedDoctor, setSelectedDoctor] = useState(null); + const [editando, setEditando] = useState(null); + const [doctorsLoading, setDoctorsLoading] = useState(true); - const encontrarMedicoIdPorNome = (nome) => { - if (!nome) return null; - const termo = nome.toLowerCase(); - const medico = MEDICOS_MOCKADOS.find((m) => - m.nome.toLowerCase().includes(termo) - ); - return medico ? medico.id : null; + useEffect(() => { + const fetchDoctors = async () => { + try { + setDoctorsLoading(true); + const data = await GetAllDoctors(); + console.log("Médicos recebidos:", data); + setDoctors(Array.isArray(data) ? data : []); + } catch (error) { + console.error("Erro ao carregar médicos:", error); + setDoctors([]); + } finally { + setDoctorsLoading(false); + } + }; + fetchDoctors(); + }, []); + + const resolveAuthHeader = () => { + try { + const h = getAuthorizationHeader(); + return h || ""; + } catch { + return ""; + } }; - const fetchDisponibilidades = useCallback(async (nome) => { - setLoading(true); + const getHeaders = () => { + const myHeaders = new Headers(); + const authHeader = resolveAuthHeader(); + if (authHeader) myHeaders.append("Authorization", authHeader); + myHeaders.append("Content-Type", "application/json"); + if (API_KEY) myHeaders.append("apikey", API_KEY); + return myHeaders; + }; - const doctorId = encontrarMedicoIdPorNome(nome); - if (!doctorId) { - setLoading(false); - return; + const fetchDisponibilidades = useCallback(async (doctorId = null) => { + setLoading(true); + let url = ENDPOINT; + if (doctorId) { + url += `?doctor_id=eq.${doctorId}&select=*&order=weekday.asc,start_time.asc`; + } else { + url += `?select=*&order=doctor_id.asc,weekday.asc,start_time.asc`; } try { - const res = await fetch(`${ENDPOINT}?doctor_id=eq.${doctorId}`); + const res = await fetch(url, { method: "GET", headers: getHeaders() }); + if (!res.ok) throw new Error(`Erro HTTP: ${res.status}`); const data = await res.json(); - - setDisponibilidades( - Array.isArray(data) - ? data - : data && Array.isArray(data.items) - ? data.items - : [] - ); + setDisponibilidades(Array.isArray(data) ? data : []); } catch (e) { console.error("Erro ao buscar disponibilidades:", e); + alert("Erro ao carregar disponibilidades"); setDisponibilidades([]); } finally { setLoading(false); @@ -70,39 +77,32 @@ const DisponibilidadesDoctorPage = () => { }, []); useEffect(() => { - if (!gerenciarModo && editando) { - setEditando(null); - } - }, [gerenciarModo]); - - useEffect(() => { - if (editando) return; - if (filtroMedicoNome) { - const timer = setTimeout(() => { - fetchDisponibilidades(filtroMedicoNome); - }, 300); - - return () => clearTimeout(timer); + if (selectedDoctor) { + fetchDisponibilidades(selectedDoctor.id); } else { - setDisponibilidades([]); + fetchDisponibilidades(null); } - }, [filtroMedicoNome, fetchDisponibilidades, editando]); + }, [selectedDoctor, fetchDisponibilidades]); - const atualizarDisponibilidade = async (id, novoIntervalo) => { + const atualizarDisponibilidade = async (id, dadosAtualizados) => { try { const res = await fetch(`${ENDPOINT}?id=eq.${id}`, { - method: "PUT", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ slot_minutes: novoIntervalo }), + method: "PATCH", + headers: getHeaders(), + body: JSON.stringify(dadosAtualizados), }); if (res.ok) { alert("Disponibilidade atualizada com sucesso!"); setEditando(null); - fetchDisponibilidades(filtroMedicoNome); + if (selectedDoctor) fetchDisponibilidades(selectedDoctor.id); + else fetchDisponibilidades(); } else { + const errorData = await res.json(); + console.error("Erro na resposta:", errorData); alert("Erro ao atualizar disponibilidade"); } - } catch { + } catch (error) { + console.error("Erro:", error); alert("Falha ao conectar com o servidor"); } }; @@ -111,118 +111,138 @@ const DisponibilidadesDoctorPage = () => { if (!window.confirm("Deseja realmente excluir esta disponibilidade?")) return; try { - const res = await fetch(`${ENDPOINT}?id=eq.${id}`, { method: "DELETE" }); + const res = await fetch(`${ENDPOINT}?id=eq.${id}`, { + method: "DELETE", + headers: getHeaders(), + }); if (res.ok) { - alert("Disponibilidade excluída!"); + alert("Disponibilidade excluída com sucesso!"); setDisponibilidades((prev) => prev.filter((d) => d.id !== id)); } else { + const errorData = await res.json(); + console.error("Erro na resposta:", errorData); alert("Erro ao excluir disponibilidade"); } - } catch { + } catch (error) { + console.error("Erro:", error); alert("Erro ao conectar com o servidor"); } }; - const disponibilidadeParaEdicao = editando - ? disponibilidades.find((d) => d.id === editando) - : null; - -const initialAvailabilityParaEdicao = diasDaSemana.map((dia, weekdayIndex) => { - const blocosDoDia = disponibilidades - .filter(d => d.weekday === weekdayIndex) - .map(d => ({ - id: d.id, - inicio: d.start_time - ? new Date(d.start_time).toISOString().substring(11, 16) - : "07:00", - termino: d.end_time - ? new Date(d.end_time).toISOString().substring(11, 16) - : "17:00", - isNew: false, - slot_minutes: d.slot_minutes, - })); - - return { - dia, - isChecked: blocosDoDia.length > 0, - blocos: blocosDoDia, - }; -}); + const initialAvailabilityParaEdicao = useMemo( + () => + diasDaSemana.map((dia, weekdayIndex) => { + const blocosDoDia = disponibilidades + .filter((d) => d.weekday === weekdayIndex && d.active !== false) + .map((d) => ({ + id: d.id, + inicio: d.start_time ? d.start_time.substring(0, 5) : "07:00", + termino: d.end_time ? d.end_time.substring(0, 5) : "17:00", + isNew: false, + slot_minutes: d.slot_minutes || 30, + appointment_type: d.appointment_type || "presencial", + active: d.active !== false, + })); + return { + dia, + weekday: weekdayIndex, + isChecked: blocosDoDia.length > 0, + blocos: blocosDoDia, + }; + }), + [disponibilidades] + ); const handleUpdateHorarios = (horariosAtualizados) => { - console.log("Horários editados:", horariosAtualizados); - - setEditando(null); - fetchDisponibilidades(filtroMedicoNome); + const bloco = horariosAtualizados + .flatMap((d) => d.blocos) + .find((b) => b.id === editando); + if (!bloco) return alert("Bloco não encontrado."); + const dadosAtualizados = { + start_time: bloco.inicio + ":00", + end_time: bloco.termino + ":00", + slot_minutes: bloco.slot_minutes, + appointment_type: bloco.appointment_type, + active: bloco.active, + }; + atualizarDisponibilidade(editando, dadosAtualizados); }; + const filteredDoctors = useMemo(() => { + if (!searchTerm) return doctors; + return doctors.filter((doc) => + doc.name.toLowerCase().includes(searchTerm.toLowerCase()) + ); + }, [doctors, searchTerm]); + return (
- {/* Cabeçalho */} -
-

- Disponibilidades por Médico -

+

+ Disponibilidades dos Médicos +

- {/* Botão Voltar/Gerenciar */} - + /> + {searchTerm && ( +
    + {filteredDoctors.length > 0 ? ( + filteredDoctors.map((doc) => ( +
  • { + setSelectedDoctor(doc); + setSearchTerm(doc.name); + }} + style={{ + padding: "6px 8px", + cursor: "pointer", + borderBottom: "1px solid #eee", + }} + > + {doc.name} +
  • + )) + ) : ( +
  • + Nenhum médico encontrado +
  • + )} +
+ )}
- {/* Campo de busca - ESCONDIDO NO MODO DE EDIÇÃO */} - {!editando && ( -
-
- setFiltroMedicoNome(e.target.value)} - style={{ - border: "1px solid #ccc", - borderRadius: "4px", - padding: "5px", - marginTop: "10px", - marginBottom: "10px", - }} - /> -
-
- )} -

- {editando - ? "Editar Disponibilidade" - : gerenciarModo - ? "Gerenciar Disponibilidades" - : "Disponibilidades Encontradas"}{" "} + {editando ? "Editar Disponibilidade" : "Lista de Disponibilidades"}{" "} ({disponibilidades.length})

@@ -256,51 +276,79 @@ const initialAvailabilityParaEdicao = diasDaSemana.map((dia, weekdayIndex) => { ) : ( - +
+ - - - {gerenciarModo && } + + + + - {disponibilidades.map((disp) => ( - - - - - - - {gerenciarModo && ( + {disponibilidades.map((disp) => { + const medico = doctors.find((d) => d.id === disp.doctor_id); + return ( + + + + + + + + - )} - - ))} + + ); + })}
Médico Dia da Semana Início TérminoIntervaloTipo ConsultaAçõesIntervalo (min)TipoStatusAções
{diasDaSemana[disp.weekday]}{formatarDataHora(disp.start_time)}{formatarDataHora(disp.end_time)}{disp.slot_minutes}{disp.appointment_type}
{medico ? medico.name : disp.doctor_id}{diasDaSemana[disp.weekday]}{disp.start_time}{disp.end_time}{disp.slot_minutes || 30}{disp.appointment_type || "presencial"} + + {disp.active === false ? "Inativa" : "Ativa"} + + +
{" "} + + +
)}