From 3754ea4c28c4faa01f75107df4f417e97dc8119c Mon Sep 17 00:00:00 2001 From: Kevin Carter Date: Sun, 1 Mar 2026 18:32:49 +0000 Subject: [PATCH] mian commit --- .eslintrc.json | 3 + .gitignore | 37 + Dockerfile | 26 + docker-compose.yml | 27 + jwt_dump.json | 10 + next.config.mjs | 8 + package-lock.json | 7404 +++++++++++++++++ package.json | 46 + postcss.config.mjs | 8 + public/announcement.png | Bin 0 -> 2985 bytes public/assignment.png | Bin 0 -> 2138 bytes public/attendance.png | Bin 0 -> 3085 bytes public/avatar.png | Bin 0 -> 14245 bytes public/blood.png | Bin 0 -> 1213 bytes public/calendar.png | Bin 0 -> 1952 bytes public/class.png | Bin 0 -> 2182 bytes public/close.png | Bin 0 -> 1049 bytes public/create.png | Bin 0 -> 1595 bytes public/date.png | Bin 0 -> 1129 bytes public/delete.png | Bin 0 -> 2011 bytes public/exam.png | Bin 0 -> 2627 bytes public/filter.png | Bin 0 -> 2042 bytes public/finance.png | Bin 0 -> 3029 bytes public/home.png | Bin 0 -> 2334 bytes public/lesson.png | Bin 0 -> 2336 bytes public/logo.png | Bin 0 -> 11011 bytes public/logout.png | Bin 0 -> 2588 bytes public/mail.png | Bin 0 -> 830 bytes public/maleFemale.png | Bin 0 -> 7606 bytes public/message.png | Bin 0 -> 2751 bytes public/more.png | Bin 0 -> 2001 bytes public/moreDark.png | Bin 0 -> 2016 bytes public/noAvatar.png | Bin 0 -> 3155 bytes public/parent.png | Bin 0 -> 2759 bytes public/phone.png | Bin 0 -> 370 bytes public/profile.png | Bin 0 -> 3201 bytes public/result.png | Bin 0 -> 2320 bytes public/search.png | Bin 0 -> 2652 bytes public/setting.png | Bin 0 -> 3419 bytes public/singleAttendance.png | Bin 0 -> 3415 bytes public/singleBranch.png | Bin 0 -> 2992 bytes public/singleClass.png | Bin 0 -> 3035 bytes public/singleLesson.png | Bin 0 -> 2646 bytes public/sort.png | Bin 0 -> 1785 bytes public/student.png | Bin 0 -> 2669 bytes public/subject.png | Bin 0 -> 2308 bytes public/teacher.png | Bin 0 -> 2587 bytes public/update.png | Bin 0 -> 1122 bytes public/upload.png | Bin 0 -> 650 bytes public/view.png | Bin 0 -> 2635 bytes scripts/seed-data.json | 142 + scripts/seed.ts | 261 + scripts/seed_schedule.ts | 226 + scripts/test.ts | 17 + src/app/(dashboard)/admin/page.tsx | 49 + src/app/(dashboard)/layout.tsx | 31 + .../(dashboard)/list/announcements/page.tsx | 138 + src/app/(dashboard)/list/assignments/page.tsx | 162 + src/app/(dashboard)/list/classes/page.tsx | 141 + src/app/(dashboard)/list/events/page.tsx | 160 + src/app/(dashboard)/list/exams/page.tsx | 160 + src/app/(dashboard)/list/lessons/page.tsx | 142 + src/app/(dashboard)/list/loading.tsx | 29 + src/app/(dashboard)/list/parents/page.tsx | 144 + src/app/(dashboard)/list/results/page.tsx | 212 + .../(dashboard)/list/students/[id]/page.tsx | 221 + src/app/(dashboard)/list/students/page.tsx | 186 + src/app/(dashboard)/list/subjects/page.tsx | 129 + .../(dashboard)/list/teachers/[id]/page.tsx | 221 + src/app/(dashboard)/list/teachers/page.tsx | 190 + src/app/(dashboard)/parent/page.tsx | 48 + src/app/(dashboard)/student/page.tsx | 57 + src/app/(dashboard)/teacher/page.tsx | 24 + src/app/[[...sign-in]]/page.tsx | 70 + src/app/favicon.ico | Bin 0 -> 3366 bytes src/app/globals.css | 110 + src/app/layout.tsx | 31 + src/components/Announcements.tsx | 66 + src/components/AttendanceChart.tsx | 57 + src/components/AttendanceChartContainer.tsx | 71 + src/components/BigCalendarContainer.tsx | 40 + src/components/BigCalender.tsx | 41 + src/components/ConsoleSuppressor.tsx | 18 + src/components/CountChart.tsx | 54 + src/components/CountChartContainer.tsx | 50 + src/components/EventCalendar.tsx | 38 + src/components/EventCalendarContainer.tsx | 25 + src/components/EventList.tsx | 45 + src/components/FinanceChart.tsx | 126 + src/components/FormContainer.tsx | 117 + src/components/FormModal.tsx | 246 + src/components/InputField.tsx | 41 + src/components/Menu.tsx | 150 + src/components/Navbar.tsx | 42 + src/components/Pagination.tsx | 62 + src/components/Performance.tsx | 40 + src/components/StudentAttendanceCard.tsx | 28 + src/components/Table.tsx | 24 + src/components/TableSearch.tsx | 34 + src/components/UserCard.tsx | 38 + src/components/forms/AnnouncementForm.tsx | 133 + src/components/forms/AssignmentForm.tsx | 132 + src/components/forms/ClassForm.tsx | 157 + src/components/forms/EventForm.tsx | 142 + src/components/forms/ExamForm.tsx | 139 + src/components/forms/LessonForm.tsx | 191 + src/components/forms/ResultForm.tsx | 165 + src/components/forms/StudentForm.tsx | 261 + src/components/forms/SubjectForm.tsx | 116 + src/components/forms/TeacherForm.tsx | 216 + src/lib/actions.ts | 818 ++ src/lib/data.ts | 1063 +++ src/lib/formValidationSchemas.ts | 146 + src/lib/settings.ts | 23 + src/lib/supabase.ts | 30 + src/lib/utils.ts | 45 + src/middleware.ts | 33 + src/types/supabase.ts | 738 ++ supabase/.archive/seed.sql | 242 + supabase/.gitignore | 8 + supabase/config.toml | 384 + supabase/migrations/20260226232057_init.sql | 283 + .../migrations/20260227004419_clerk_roles.sql | 32 + .../20260227004420_supabase_rls.sql | 201 + ...20260228000000_explicit_mapping_tables.sql | 41 + tailwind.config.ts | 28 + test-date.js | 29 + test-lessons.ts | 19 + test-rls-jwt.ts | 12 + test-rls-sql.ts | 13 + test-student-jwt.ts | 14 + test_jwt.js | 2 + test_lesson.js | 2 + tsconfig.json | 26 + usercard_counts.txt | 4 + 135 files changed, 18211 insertions(+) create mode 100644 .eslintrc.json create mode 100644 .gitignore create mode 100644 Dockerfile create mode 100644 docker-compose.yml create mode 100644 jwt_dump.json create mode 100644 next.config.mjs create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 postcss.config.mjs create mode 100644 public/announcement.png create mode 100644 public/assignment.png create mode 100644 public/attendance.png create mode 100644 public/avatar.png create mode 100644 public/blood.png create mode 100644 public/calendar.png create mode 100644 public/class.png create mode 100644 public/close.png create mode 100644 public/create.png create mode 100644 public/date.png create mode 100644 public/delete.png create mode 100644 public/exam.png create mode 100644 public/filter.png create mode 100644 public/finance.png create mode 100644 public/home.png create mode 100644 public/lesson.png create mode 100644 public/logo.png create mode 100644 public/logout.png create mode 100644 public/mail.png create mode 100644 public/maleFemale.png create mode 100644 public/message.png create mode 100644 public/more.png create mode 100644 public/moreDark.png create mode 100644 public/noAvatar.png create mode 100644 public/parent.png create mode 100644 public/phone.png create mode 100644 public/profile.png create mode 100644 public/result.png create mode 100644 public/search.png create mode 100644 public/setting.png create mode 100644 public/singleAttendance.png create mode 100644 public/singleBranch.png create mode 100644 public/singleClass.png create mode 100644 public/singleLesson.png create mode 100644 public/sort.png create mode 100644 public/student.png create mode 100644 public/subject.png create mode 100644 public/teacher.png create mode 100644 public/update.png create mode 100644 public/upload.png create mode 100644 public/view.png create mode 100644 scripts/seed-data.json create mode 100644 scripts/seed.ts create mode 100644 scripts/seed_schedule.ts create mode 100644 scripts/test.ts create mode 100644 src/app/(dashboard)/admin/page.tsx create mode 100644 src/app/(dashboard)/layout.tsx create mode 100644 src/app/(dashboard)/list/announcements/page.tsx create mode 100644 src/app/(dashboard)/list/assignments/page.tsx create mode 100644 src/app/(dashboard)/list/classes/page.tsx create mode 100644 src/app/(dashboard)/list/events/page.tsx create mode 100644 src/app/(dashboard)/list/exams/page.tsx create mode 100644 src/app/(dashboard)/list/lessons/page.tsx create mode 100644 src/app/(dashboard)/list/loading.tsx create mode 100644 src/app/(dashboard)/list/parents/page.tsx create mode 100644 src/app/(dashboard)/list/results/page.tsx create mode 100644 src/app/(dashboard)/list/students/[id]/page.tsx create mode 100644 src/app/(dashboard)/list/students/page.tsx create mode 100644 src/app/(dashboard)/list/subjects/page.tsx create mode 100644 src/app/(dashboard)/list/teachers/[id]/page.tsx create mode 100644 src/app/(dashboard)/list/teachers/page.tsx create mode 100644 src/app/(dashboard)/parent/page.tsx create mode 100644 src/app/(dashboard)/student/page.tsx create mode 100644 src/app/(dashboard)/teacher/page.tsx create mode 100644 src/app/[[...sign-in]]/page.tsx create mode 100644 src/app/favicon.ico create mode 100644 src/app/globals.css create mode 100644 src/app/layout.tsx create mode 100644 src/components/Announcements.tsx create mode 100644 src/components/AttendanceChart.tsx create mode 100644 src/components/AttendanceChartContainer.tsx create mode 100644 src/components/BigCalendarContainer.tsx create mode 100644 src/components/BigCalender.tsx create mode 100644 src/components/ConsoleSuppressor.tsx create mode 100644 src/components/CountChart.tsx create mode 100644 src/components/CountChartContainer.tsx create mode 100644 src/components/EventCalendar.tsx create mode 100644 src/components/EventCalendarContainer.tsx create mode 100644 src/components/EventList.tsx create mode 100644 src/components/FinanceChart.tsx create mode 100644 src/components/FormContainer.tsx create mode 100644 src/components/FormModal.tsx create mode 100644 src/components/InputField.tsx create mode 100644 src/components/Menu.tsx create mode 100644 src/components/Navbar.tsx create mode 100644 src/components/Pagination.tsx create mode 100644 src/components/Performance.tsx create mode 100644 src/components/StudentAttendanceCard.tsx create mode 100644 src/components/Table.tsx create mode 100644 src/components/TableSearch.tsx create mode 100644 src/components/UserCard.tsx create mode 100644 src/components/forms/AnnouncementForm.tsx create mode 100644 src/components/forms/AssignmentForm.tsx create mode 100644 src/components/forms/ClassForm.tsx create mode 100644 src/components/forms/EventForm.tsx create mode 100644 src/components/forms/ExamForm.tsx create mode 100644 src/components/forms/LessonForm.tsx create mode 100644 src/components/forms/ResultForm.tsx create mode 100644 src/components/forms/StudentForm.tsx create mode 100644 src/components/forms/SubjectForm.tsx create mode 100644 src/components/forms/TeacherForm.tsx create mode 100644 src/lib/actions.ts create mode 100644 src/lib/data.ts create mode 100644 src/lib/formValidationSchemas.ts create mode 100644 src/lib/settings.ts create mode 100644 src/lib/supabase.ts create mode 100644 src/lib/utils.ts create mode 100644 src/middleware.ts create mode 100644 src/types/supabase.ts create mode 100644 supabase/.archive/seed.sql create mode 100644 supabase/.gitignore create mode 100644 supabase/config.toml create mode 100644 supabase/migrations/20260226232057_init.sql create mode 100644 supabase/migrations/20260227004419_clerk_roles.sql create mode 100644 supabase/migrations/20260227004420_supabase_rls.sql create mode 100644 supabase/migrations/20260228000000_explicit_mapping_tables.sql create mode 100644 tailwind.config.ts create mode 100644 test-date.js create mode 100644 test-lessons.ts create mode 100644 test-rls-jwt.ts create mode 100644 test-rls-sql.ts create mode 100644 test-student-jwt.ts create mode 100644 test_jwt.js create mode 100644 test_lesson.js create mode 100644 tsconfig.json create mode 100644 usercard_counts.txt diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..bffb357 --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,3 @@ +{ + "extends": "next/core-web-vitals" +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a84107a --- /dev/null +++ b/.gitignore @@ -0,0 +1,37 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js +.yarn/install-state.gz + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# local env files +.env +.env*.local + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..7a33e32 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,26 @@ +# Use Node.js as the base image +FROM node:18 + +# Set the working directory inside the container +WORKDIR /app + +# Copy package.json and package-lock.json files +COPY package*.json ./ + +# Install dependencies +RUN npm install + +# Copy the rest of the application code +COPY . . + +# Generate Database +RUN npx prisma migrate dev --name init + +# Build the Next.js application +RUN npm run build + +# Expose the port the app runs on +EXPOSE 3000 + +# Start the Next.js application +CMD ["npm", "start"] diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..f9f7ad5 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,27 @@ +version: '3.8' + +services: + postgress: + image: postgres:15 + container_name: postgres_db + environment: + POSTGRES_USER: myuser + POSTGRES_PASSWORD: mypassword + POSTGRES_DB: mydb + ports: + - '5432:5432' + volumes: + - postgres_data:/var/lib/postgresql/data + + app: + build: . + container_name: nextjs_app + ports: + - '3000:3000' + environment: + - DATABASE_URL=postgresql://myuser:mypassword@192.168.0.48:5432/mydb + depends_on: + - postgress + +volumes: + postgres_data: diff --git a/jwt_dump.json b/jwt_dump.json new file mode 100644 index 0000000..9622544 --- /dev/null +++ b/jwt_dump.json @@ -0,0 +1,10 @@ +{ + "aud": "authenticated", + "exp": 1772176558, + "iat": 1772176498, + "iss": "https://kind-burro-23.clerk.accounts.dev", + "jti": "0689311f9e0ff06da236", + "nbf": 1772176493, + "role": "admin", + "sub": "user_3AE7OSCzF8rz7XnvTkOUmFV4AKp" +} \ No newline at end of file diff --git a/next.config.mjs b/next.config.mjs new file mode 100644 index 0000000..f6c5729 --- /dev/null +++ b/next.config.mjs @@ -0,0 +1,8 @@ +/** @type {import('next').NextConfig} */ +const nextConfig = { + images: { + remotePatterns: [{ hostname: "images.pexels.com" }], + }, +}; + +export default nextConfig; diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..0018642 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,7404 @@ +{ + "name": "lama-dev-next-dashboard", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "lama-dev-next-dashboard", + "version": "0.1.0", + "dependencies": { + "@clerk/elements": "^0.14.6", + "@clerk/nextjs": "^5.4.1", + "@hookform/resolvers": "^3.9.0", + "@prisma/client": "^5.19.1", + "@supabase/supabase-js": "^2.98.0", + "@types/react-big-calendar": "^1.8.9", + "moment": "^2.30.1", + "next": "14.2.5", + "next-cloudinary": "^6.13.0", + "prisma": "^5.19.1", + "react": "^18", + "react-big-calendar": "^1.13.2", + "react-calendar": "^5.0.0", + "react-dom": "^18", + "react-hook-form": "^7.52.2", + "react-toastify": "^10.0.5", + "recharts": "^2.12.7", + "zod": "^3.23.8" + }, + "devDependencies": { + "@types/node": "^20", + "@types/react": "^18", + "@types/react-dom": "^18", + "dotenv": "^17.3.1", + "eslint": "^8", + "eslint-config-next": "14.2.5", + "postcss": "^8", + "tailwindcss": "^3.4.1", + "ts-node": "^10.9.2", + "tsx": "^4.21.0", + "typescript": "^5" + } + }, + "node_modules/@alloc/quick-lru": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@babel/runtime": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.0.tgz", + "integrity": "sha512-7dRy4DwXwtzBrPbZflqxnvfxLF8kdZXPkhymtDeFoFqE6ldzjQFgYTtYIFARcLEYDrqfBfYcZt1WqFxRoyC9Rw==", + "license": "MIT", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@clerk/backend": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@clerk/backend/-/backend-1.9.2.tgz", + "integrity": "sha512-8vCYux8Xbu5TQ2iq9tYuDnNhv3K/XhZ+34QJG+n4ZX4w4FfTTuzwb5OylcmP69vPvYybhoQfjpK57kBOW22deg==", + "license": "MIT", + "dependencies": { + "@clerk/shared": "2.6.2", + "@clerk/types": "4.19.0", + "cookie": "0.5.0", + "snakecase-keys": "5.4.4", + "tslib": "2.4.1" + }, + "engines": { + "node": ">=18.17.0" + } + }, + "node_modules/@clerk/backend/node_modules/tslib": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", + "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==", + "license": "0BSD" + }, + "node_modules/@clerk/clerk-react": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@clerk/clerk-react/-/clerk-react-5.7.0.tgz", + "integrity": "sha512-VCYj/Qhm4P5u0A3X1M+yycod8cz8flFwtpnI8+ajGUDmMdel9iuR5ix01cgsHfyPuamfiuP1a4xNg7F0d+2P7Q==", + "license": "MIT", + "dependencies": { + "@clerk/shared": "2.6.2", + "@clerk/types": "4.19.0", + "tslib": "2.4.1" + }, + "engines": { + "node": ">=18.17.0" + }, + "peerDependencies": { + "react": ">=18 || >=19.0.0-beta", + "react-dom": ">=18 || >=19.0.0-beta" + } + }, + "node_modules/@clerk/clerk-react/node_modules/tslib": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", + "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==", + "license": "0BSD" + }, + "node_modules/@clerk/elements": { + "version": "0.14.6", + "resolved": "https://registry.npmjs.org/@clerk/elements/-/elements-0.14.6.tgz", + "integrity": "sha512-qlxDr1w7yovVLuOlLGWlJq0yLDjDhJkrcciCQL0FKFXsWwumJkyyAvQjZhqceoHms1Fqx7qwDU8fWg70amEdAA==", + "license": "MIT", + "dependencies": { + "@clerk/types": "^4.19.0", + "@radix-ui/react-form": "^0.1.0", + "@radix-ui/react-slot": "^1.1.0", + "@xstate/react": "^4.1.1", + "client-only": "^0.0.1", + "xstate": "^5.15.0" + }, + "engines": { + "node": ">=18.17.0" + }, + "peerDependencies": { + "@clerk/clerk-react": "^5.0.0", + "@clerk/shared": "^2.0.0", + "next": "^13.5.4 || ^14.0.3 || ^15.0.0-rc", + "react": "^18.0.0 || ^19.0.0-beta", + "react-dom": "^18.0.0 || ^19.0.0-beta" + }, + "peerDependenciesMeta": { + "next": { + "optional": true + } + } + }, + "node_modules/@clerk/nextjs": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/@clerk/nextjs/-/nextjs-5.4.1.tgz", + "integrity": "sha512-rW/UIdsR0hDd90OTy0HS1dk69y8cO24GjnMXX7A2WhN2LmLtvC6K8pIX2w/mOajWNm6MTSBuzTDwLB8rYii9Ww==", + "license": "MIT", + "dependencies": { + "@clerk/backend": "1.9.2", + "@clerk/clerk-react": "5.7.0", + "@clerk/shared": "2.6.2", + "@clerk/types": "4.19.0", + "crypto-js": "4.2.0", + "path-to-regexp": "6.2.2", + "server-only": "0.0.1", + "tslib": "2.4.1" + }, + "engines": { + "node": ">=18.17.0" + }, + "peerDependencies": { + "next": "^13.5.4 || ^14.0.3 || >=15.0.0-rc", + "react": ">=18 || >=19.0.0-beta", + "react-dom": ">=18 || >=19.0.0-beta" + } + }, + "node_modules/@clerk/nextjs/node_modules/tslib": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", + "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==", + "license": "0BSD" + }, + "node_modules/@clerk/shared": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/@clerk/shared/-/shared-2.6.2.tgz", + "integrity": "sha512-RkrNknIr98GPu3srXLhjJViC1Mom1gUsRMNnf1deibX2yvRnndloZGnFb0qxf+pFL/NCkKd3nSHtK3eCJQrVYQ==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "@clerk/types": "4.19.0", + "glob-to-regexp": "0.4.1", + "js-cookie": "3.0.5", + "std-env": "^3.7.0", + "swr": "^2.2.0" + }, + "engines": { + "node": ">=18.17.0" + }, + "peerDependencies": { + "react": ">=18 || >=19.0.0-beta", + "react-dom": ">=18 || >=19.0.0-beta" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/@clerk/types": { + "version": "4.19.0", + "resolved": "https://registry.npmjs.org/@clerk/types/-/types-4.19.0.tgz", + "integrity": "sha512-bDN/nRUD5PFCehQ+Kjdcft0I3b9CIyCcY3OBNDSc1L6RQhlXH+J48EtaP/cbRdslb83LJiBPQ2i/gV4VgblzwA==", + "license": "MIT", + "dependencies": { + "csstype": "3.1.1" + }, + "engines": { + "node": ">=18.17.0" + } + }, + "node_modules/@clerk/types/node_modules/csstype": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz", + "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==", + "license": "MIT" + }, + "node_modules/@cloudinary-util/types": { + "version": "1.5.8", + "resolved": "https://registry.npmjs.org/@cloudinary-util/types/-/types-1.5.8.tgz", + "integrity": "sha512-gD6n1mPLvqQ/0GXx0DwXk6dud1X2ij/XGzX7uz+X3AObvCAEngdBXgStuz9O8PmnlAiQvhulvwwWZVXHvgpjJg==", + "license": "MIT" + }, + "node_modules/@cloudinary-util/url-loader": { + "version": "5.10.3", + "resolved": "https://registry.npmjs.org/@cloudinary-util/url-loader/-/url-loader-5.10.3.tgz", + "integrity": "sha512-bKALWnD2HHL/OZlIQECdjFrGvZYu9VG+RG9pne1y9OVhdClSNS3CZKKSf4F+htcYSp8JXpjdKUzTp2t21b6kiA==", + "license": "MIT", + "dependencies": { + "@cloudinary-util/types": "1.5.8", + "@cloudinary-util/util": "3.3.2", + "@cloudinary/url-gen": "1.15.0", + "zod": "^3.22.4" + } + }, + "node_modules/@cloudinary-util/util": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/@cloudinary-util/util/-/util-3.3.2.tgz", + "integrity": "sha512-Cc0iFxzfl7fcOXuznpeZFGYC885Of/vDgccRDnhTe/8Rf8YKv2PjLtezyo0VgmdA/CpeZy29NCXAsf6liokbwg==", + "license": "MIT" + }, + "node_modules/@cloudinary/transformation-builder-sdk": { + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/@cloudinary/transformation-builder-sdk/-/transformation-builder-sdk-1.15.1.tgz", + "integrity": "sha512-Dvm5DzGPq6NtXRLhpubu7SVfD+TLEWbU9q/FOxpGelWpn3NaTSOH/b+jRbpTL+EgYSHeaTeK6kHMraousPkNQg==", + "license": "MIT", + "dependencies": { + "@cloudinary/url-gen": "^1.7.0" + } + }, + "node_modules/@cloudinary/url-gen": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/@cloudinary/url-gen/-/url-gen-1.15.0.tgz", + "integrity": "sha512-bjU67eZxLUgoRy/Plli4TQio7q6P31OYqnEgXxeN9TKXrzr6h0DeEdIUhKI9gy3HkEBWXWWJIPh7j7gkOJPnyA==", + "license": "MIT", + "dependencies": { + "@cloudinary/transformation-builder-sdk": "^1.10.0" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", + "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", + "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", + "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", + "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", + "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", + "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", + "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", + "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", + "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", + "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", + "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", + "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", + "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", + "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", + "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", + "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", + "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", + "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", + "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", + "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", + "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", + "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", + "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", + "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", + "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", + "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.0.tgz", + "integrity": "sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/js": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", + "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@hookform/resolvers": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/@hookform/resolvers/-/resolvers-3.9.0.tgz", + "integrity": "sha512-bU0Gr4EepJ/EQsH/IwEzYLsT/PEj5C0ynLQ4m+GSHS+xKH4TfSelhluTgOaoc4kA5s7eCsQbM4wvZLzELmWzUg==", + "license": "MIT", + "peerDependencies": { + "react-hook-form": "^7.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.14", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", + "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", + "deprecated": "Use @eslint/config-array instead", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", + "deprecated": "Use @eslint/object-schema instead", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@next/env": { + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.5.tgz", + "integrity": "sha512-/zZGkrTOsraVfYjGP8uM0p6r0BDT6xWpkjdVbcz66PJVSpwXX3yNiRycxAuDfBKGWBrZBXRuK/YVlkNgxHGwmA==", + "license": "MIT" + }, + "node_modules/@next/eslint-plugin-next": { + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-14.2.5.tgz", + "integrity": "sha512-LY3btOpPh+OTIpviNojDpUdIbHW9j0JBYBjsIp8IxtDFfYFyORvw3yNq6N231FVqQA7n7lwaf7xHbVJlA1ED7g==", + "dev": true, + "license": "MIT", + "dependencies": { + "glob": "10.3.10" + } + }, + "node_modules/@next/swc-darwin-arm64": { + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.5.tgz", + "integrity": "sha512-/9zVxJ+K9lrzSGli1///ujyRfon/ZneeZ+v4ptpiPoOU+GKZnm8Wj8ELWU1Pm7GHltYRBklmXMTUqM/DqQ99FQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-darwin-x64": { + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.5.tgz", + "integrity": "sha512-vXHOPCwfDe9qLDuq7U1OYM2wUY+KQ4Ex6ozwsKxp26BlJ6XXbHleOUldenM67JRyBfVjv371oneEvYd3H2gNSA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-gnu": { + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.5.tgz", + "integrity": "sha512-vlhB8wI+lj8q1ExFW8lbWutA4M2ZazQNvMWuEDqZcuJJc78iUnLdPPunBPX8rC4IgT6lIx/adB+Cwrl99MzNaA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-musl": { + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.5.tgz", + "integrity": "sha512-NpDB9NUR2t0hXzJJwQSGu1IAOYybsfeB+LxpGsXrRIb7QOrYmidJz3shzY8cM6+rO4Aojuef0N/PEaX18pi9OA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-gnu": { + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.5.tgz", + "integrity": "sha512-8XFikMSxWleYNryWIjiCX+gU201YS+erTUidKdyOVYi5qUQo/gRxv/3N1oZFCgqpesN6FPeqGM72Zve+nReVXQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-musl": { + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.5.tgz", + "integrity": "sha512-6QLwi7RaYiQDcRDSU/os40r5o06b5ue7Jsk5JgdRBGGp8l37RZEh9JsLSM8QF0YDsgcosSeHjglgqi25+m04IQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-arm64-msvc": { + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.5.tgz", + "integrity": "sha512-1GpG2VhbspO+aYoMOQPQiqc/tG3LzmsdBH0LhnDS3JrtDx2QmzXe0B6mSZZiN3Bq7IOMXxv1nlsjzoS1+9mzZw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-ia32-msvc": { + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.5.tgz", + "integrity": "sha512-Igh9ZlxwvCDsu6438FXlQTHlRno4gFpJzqPjSIBZooD22tKeI4fE/YMRoHVJHmrQ2P5YL1DoZ0qaOKkbeFWeMg==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-x64-msvc": { + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.5.tgz", + "integrity": "sha512-tEQ7oinq1/CjSG9uSTerca3v4AZ+dFa+4Yu6ihaG8Ud8ddqLQgFGcnwYls13H5X5CPDPZJdYxyeMui6muOLd4g==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, + "node_modules/@prisma/client": { + "version": "5.19.1", + "resolved": "https://registry.npmjs.org/@prisma/client/-/client-5.19.1.tgz", + "integrity": "sha512-x30GFguInsgt+4z5I4WbkZP2CGpotJMUXy+Gl/aaUjHn2o1DnLYNTA+q9XdYmAQZM8fIIkvUiA2NpgosM3fneg==", + "hasInstallScript": true, + "license": "Apache-2.0", + "engines": { + "node": ">=16.13" + }, + "peerDependencies": { + "prisma": "*" + }, + "peerDependenciesMeta": { + "prisma": { + "optional": true + } + } + }, + "node_modules/@prisma/debug": { + "version": "5.19.1", + "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-5.19.1.tgz", + "integrity": "sha512-lAG6A6QnG2AskAukIEucYJZxxcSqKsMK74ZFVfCTOM/7UiyJQi48v6TQ47d6qKG3LbMslqOvnTX25dj/qvclGg==", + "license": "Apache-2.0" + }, + "node_modules/@prisma/engines": { + "version": "5.19.1", + "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-5.19.1.tgz", + "integrity": "sha512-kR/PoxZDrfUmbbXqqb8SlBBgCjvGaJYMCOe189PEYzq9rKqitQ2fvT/VJ8PDSe8tTNxhc2KzsCfCAL+Iwm/7Cg==", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@prisma/debug": "5.19.1", + "@prisma/engines-version": "5.19.1-2.69d742ee20b815d88e17e54db4a2a7a3b30324e3", + "@prisma/fetch-engine": "5.19.1", + "@prisma/get-platform": "5.19.1" + } + }, + "node_modules/@prisma/engines-version": { + "version": "5.19.1-2.69d742ee20b815d88e17e54db4a2a7a3b30324e3", + "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-5.19.1-2.69d742ee20b815d88e17e54db4a2a7a3b30324e3.tgz", + "integrity": "sha512-xR6rt+z5LnNqTP5BBc+8+ySgf4WNMimOKXRn6xfNRDSpHvbOEmd7+qAOmzCrddEc4Cp8nFC0txU14dstjH7FXA==", + "license": "Apache-2.0" + }, + "node_modules/@prisma/fetch-engine": { + "version": "5.19.1", + "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-5.19.1.tgz", + "integrity": "sha512-pCq74rtlOVJfn4pLmdJj+eI4P7w2dugOnnTXpRilP/6n5b2aZiA4ulJlE0ddCbTPkfHmOL9BfaRgA8o+1rfdHw==", + "license": "Apache-2.0", + "dependencies": { + "@prisma/debug": "5.19.1", + "@prisma/engines-version": "5.19.1-2.69d742ee20b815d88e17e54db4a2a7a3b30324e3", + "@prisma/get-platform": "5.19.1" + } + }, + "node_modules/@prisma/get-platform": { + "version": "5.19.1", + "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-5.19.1.tgz", + "integrity": "sha512-sCeoJ+7yt0UjnR+AXZL7vXlg5eNxaFOwC23h0KvW1YIXUoa7+W2ZcAUhoEQBmJTW4GrFqCuZ8YSP0mkDa4k3Zg==", + "license": "Apache-2.0", + "dependencies": { + "@prisma/debug": "5.19.1" + } + }, + "node_modules/@radix-ui/primitive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.0.tgz", + "integrity": "sha512-4Z8dn6Upk0qk4P74xBhZ6Hd/w0mPEzOOLxy4xiPXOXqjF7jZS0VAKk7/x/H6FyY2zCkYJqePf1G5KmkmNJ4RBA==", + "license": "MIT" + }, + "node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.0.tgz", + "integrity": "sha512-b4inOtiaOnYf9KWyO3jAeeCG6FeyfY6ldiEPanbUjWd+xIk5wZeHa8yVwmrJ2vderhu/BQvzCrJI0lHd+wIiqw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-context": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.0.tgz", + "integrity": "sha512-OKrckBy+sMEgYM/sMmqmErVn0kZqrHPJze+Ql3DzYsDDp0hl0L62nx/2122/Bvps1qz645jlcu2tD9lrRSdf8A==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-form": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-form/-/react-form-0.1.0.tgz", + "integrity": "sha512-1/oVYPDjbFILOLIarcGcMKo+y6SbTVT/iUKVEw59CF4offwZgBgC3ZOeSBewjqU0vdA6FWTPWTN63obj55S/tQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.0", + "@radix-ui/react-id": "1.1.0", + "@radix-ui/react-label": "2.1.0", + "@radix-ui/react-primitive": "2.0.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-id": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.0.tgz", + "integrity": "sha512-EJUrI8yYh7WOjNOqpoJaf1jlFIH2LvtgAl+YcFqNCa+4hj64ZXmPkAKOFs/ukjz3byN6bdb/AVUqHkI8/uWWMA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-label": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.1.0.tgz", + "integrity": "sha512-peLblDlFw/ngk3UWq0VnYaOLy6agTZZ+MUO/WhVfm14vJGML+xH4FAl2XQGLqdefjNb7ApRg6Yn7U42ZhmYXdw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.0.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-primitive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.0.tgz", + "integrity": "sha512-ZSpFm0/uHa8zTvKBDjLFWLo8dkr4MBsiDLz0g3gMUwqgLHz9rTaRRGYDgvZPtBJgYCBKXkS9fzmoySgr8CO6Cw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.0.tgz", + "integrity": "sha512-FUCf5XMfmW4dtYl69pdS4DbxKy8nj4M7SafBgPllysxmdachynNflAdp/gCsnYWNDnge6tI9onzMp5ARYc1KNw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.0.tgz", + "integrity": "sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@restart/hooks": { + "version": "0.4.16", + "resolved": "https://registry.npmjs.org/@restart/hooks/-/hooks-0.4.16.tgz", + "integrity": "sha512-f7aCv7c+nU/3mF7NWLtVVr0Ra80RqsO89hO72r+Y/nvQr5+q0UFGkocElTH6MJApvReVh6JHUFYn2cw1WdHF3w==", + "license": "MIT", + "dependencies": { + "dequal": "^2.0.3" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@rushstack/eslint-patch": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.10.4.tgz", + "integrity": "sha512-WJgX9nzTqknM393q1QJDJmoW28kUfEnybeTfVNcNAPnIx210RXm2DiXiHzfNPJNIUUb1tJnz/l4QGtJ30PgWmA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@supabase/auth-js": { + "version": "2.98.0", + "resolved": "https://registry.npmjs.org/@supabase/auth-js/-/auth-js-2.98.0.tgz", + "integrity": "sha512-GBH361T0peHU91AQNzOlIrjUZw9TZbB9YDRiyFgk/3Kvr3/Z1NWUZ2athWTfHhwNNi8IrW00foyFxQD9IO/Trg==", + "license": "MIT", + "dependencies": { + "tslib": "2.8.1" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@supabase/functions-js": { + "version": "2.98.0", + "resolved": "https://registry.npmjs.org/@supabase/functions-js/-/functions-js-2.98.0.tgz", + "integrity": "sha512-N/xEyiNU5Org+d+PNCpv+TWniAXRzxIURxDYsS/m2I/sfAB/HcM9aM2Dmf5edj5oWb9GxID1OBaZ8NMmPXL+Lg==", + "license": "MIT", + "dependencies": { + "tslib": "2.8.1" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@supabase/postgrest-js": { + "version": "2.98.0", + "resolved": "https://registry.npmjs.org/@supabase/postgrest-js/-/postgrest-js-2.98.0.tgz", + "integrity": "sha512-v6e9WeZuJijzUut8HyXu6gMqWFepIbaeaMIm1uKzei4yLg9bC9OtEW9O14LE/9ezqNbSAnSLO5GtOLFdm7Bpkg==", + "license": "MIT", + "dependencies": { + "tslib": "2.8.1" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@supabase/realtime-js": { + "version": "2.98.0", + "resolved": "https://registry.npmjs.org/@supabase/realtime-js/-/realtime-js-2.98.0.tgz", + "integrity": "sha512-rOWt28uGyFipWOSd+n0WVMr9kUXiWaa7J4hvyLCIHjRFqWm1z9CaaKAoYyfYMC1Exn3WT8WePCgiVhlAtWC2yw==", + "license": "MIT", + "dependencies": { + "@types/phoenix": "^1.6.6", + "@types/ws": "^8.18.1", + "tslib": "2.8.1", + "ws": "^8.18.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@supabase/storage-js": { + "version": "2.98.0", + "resolved": "https://registry.npmjs.org/@supabase/storage-js/-/storage-js-2.98.0.tgz", + "integrity": "sha512-tzr2mG+v7ILSAZSfZMSL9OPyIH4z1ikgQ8EcQTKfMRz4EwmlFt3UnJaGzSOxyvF5b+fc9So7qdSUWTqGgeLokQ==", + "license": "MIT", + "dependencies": { + "iceberg-js": "^0.8.1", + "tslib": "2.8.1" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@supabase/supabase-js": { + "version": "2.98.0", + "resolved": "https://registry.npmjs.org/@supabase/supabase-js/-/supabase-js-2.98.0.tgz", + "integrity": "sha512-Ohc97CtInLwZyiSASz7tT9/Abm/vqnIbO9REp+PivVUII8UZsuI3bngRQnYgJdFoOIwvaEII1fX1qy8x0CyNiw==", + "license": "MIT", + "dependencies": { + "@supabase/auth-js": "2.98.0", + "@supabase/functions-js": "2.98.0", + "@supabase/postgrest-js": "2.98.0", + "@supabase/realtime-js": "2.98.0", + "@supabase/storage-js": "2.98.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@swc/counter": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", + "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==", + "license": "Apache-2.0" + }, + "node_modules/@swc/helpers": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.5.tgz", + "integrity": "sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A==", + "license": "Apache-2.0", + "dependencies": { + "@swc/counter": "^0.1.3", + "tslib": "^2.4.0" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", + "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/recommended": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@tsconfig/recommended/-/recommended-1.0.7.tgz", + "integrity": "sha512-xiNMgCuoy4mCL4JTywk9XFs5xpRUcKxtWEcMR6FNMtsgewYTIgIR+nvlP4A4iRCAzRsHMnPhvTRrzp4AGcRTEA==", + "license": "MIT" + }, + "node_modules/@types/d3-array": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.1.tgz", + "integrity": "sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg==", + "license": "MIT" + }, + "node_modules/@types/d3-color": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", + "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==", + "license": "MIT" + }, + "node_modules/@types/d3-ease": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz", + "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==", + "license": "MIT" + }, + "node_modules/@types/d3-interpolate": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", + "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", + "license": "MIT", + "dependencies": { + "@types/d3-color": "*" + } + }, + "node_modules/@types/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-P2dlU/q51fkOc/Gfl3Ul9kicV7l+ra934qBFXCFhrZMOL6du1TM0pm1ThYvENukyOn5h9v+yMJ9Fn5JK4QozrQ==", + "license": "MIT" + }, + "node_modules/@types/d3-scale": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.8.tgz", + "integrity": "sha512-gkK1VVTr5iNiYJ7vWDI+yUFFlszhNMtVeneJ6lUTKPjprsvLLI9/tgEGiXJOnlINJA8FyA88gfnQsHbybVZrYQ==", + "license": "MIT", + "dependencies": { + "@types/d3-time": "*" + } + }, + "node_modules/@types/d3-shape": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.6.tgz", + "integrity": "sha512-5KKk5aKGu2I+O6SONMYSNflgiP0WfZIQvVUMan50wHsLG1G94JlxEVnCpQARfTtzytuY0p/9PXXZb3I7giofIA==", + "license": "MIT", + "dependencies": { + "@types/d3-path": "*" + } + }, + "node_modules/@types/d3-time": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.3.tgz", + "integrity": "sha512-2p6olUZ4w3s+07q3Tm2dbiMZy5pCDfYwtLXXHUnVzXgQlZ/OyPtUz6OL382BkOuGlLXqfT+wqv8Fw2v8/0geBw==", + "license": "MIT" + }, + "node_modules/@types/d3-timer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz", + "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==", + "license": "MIT" + }, + "node_modules/@types/date-arithmetic": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@types/date-arithmetic/-/date-arithmetic-4.1.4.tgz", + "integrity": "sha512-p9eZ2X9B80iKiTW4ukVj8B4K6q9/+xFtQ5MGYA5HWToY9nL4EkhV9+6ftT2VHpVMEZb5Tv00Iel516bVdO+yRw==", + "license": "MIT" + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "20.14.14", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.14.tgz", + "integrity": "sha512-d64f00982fS9YoOgJkAMolK7MN8Iq3TDdVjchbYHdEmjth/DHowx82GnoA+tVUAN+7vxfYUgAzi+JXbKNd2SDQ==", + "license": "MIT", + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/phoenix": { + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/@types/phoenix/-/phoenix-1.6.7.tgz", + "integrity": "sha512-oN9ive//QSBkf19rfDv45M7eZPi0eEXylht2OLEXicu5b4KoQ1OzXIw+xDSGWxSxe1JmepRR/ZH283vsu518/Q==", + "license": "MIT" + }, + "node_modules/@types/prop-types": { + "version": "15.7.12", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz", + "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==", + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "18.3.3", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.3.tgz", + "integrity": "sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==", + "license": "MIT", + "dependencies": { + "@types/prop-types": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-big-calendar": { + "version": "1.8.9", + "resolved": "https://registry.npmjs.org/@types/react-big-calendar/-/react-big-calendar-1.8.9.tgz", + "integrity": "sha512-HIHLUxR3PzWHrFdZ00VnCMvDjAh5uzlL0vMC2b7tL3bKaAJsqq9T8h+x0GVeDbZfMfHAd1cs5tZBhVvourNJXQ==", + "license": "MIT", + "dependencies": { + "@types/date-arithmetic": "*", + "@types/prop-types": "*", + "@types/react": "*" + } + }, + "node_modules/@types/react-dom": { + "version": "18.3.0", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.0.tgz", + "integrity": "sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/warning": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/warning/-/warning-3.0.3.tgz", + "integrity": "sha512-D1XC7WK8K+zZEveUPY+cf4+kgauk8N4eHr/XIHXGlGYkHLud6hK9lYfZk1ry1TNh798cZUCgb6MqGEG8DkJt6Q==", + "license": "MIT" + }, + "node_modules/@types/ws": { + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.2.0.tgz", + "integrity": "sha512-5FKsVcHTk6TafQKQbuIVkXq58Fnbkd2wDL4LB7AURN7RUOu1utVP+G8+6u3ZhEroW3DF6hyo3ZEXxgKgp4KeCg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/scope-manager": "7.2.0", + "@typescript-eslint/types": "7.2.0", + "@typescript-eslint/typescript-estree": "7.2.0", + "@typescript-eslint/visitor-keys": "7.2.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.2.0.tgz", + "integrity": "sha512-Qh976RbQM/fYtjx9hs4XkayYujB/aPwglw2choHmf3zBjB4qOywWSdt9+KLRdHubGcoSwBnXUH2sR3hkyaERRg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "7.2.0", + "@typescript-eslint/visitor-keys": "7.2.0" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.2.0.tgz", + "integrity": "sha512-XFtUHPI/abFhm4cbCDc5Ykc8npOKBSJePY3a3s+lwumt7XWJuzP5cZcfZ610MIPHjQjNsOLlYK8ASPaNG8UiyA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.2.0.tgz", + "integrity": "sha512-cyxS5WQQCoBwSakpMrvMXuMDEbhOo9bNHHrNcEWis6XHx6KF518tkF1wBvKIn/tpq5ZpUYK7Bdklu8qY0MsFIA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/types": "7.2.0", + "@typescript-eslint/visitor-keys": "7.2.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "9.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.2.0.tgz", + "integrity": "sha512-c6EIQRHhcpl6+tO8EMR+kjkkV+ugUNXOmeASA1rlzkd8EPIriavpWoiEz1HR/VLhbVIdhqnV6E7JZm00cBDx2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "7.2.0", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/@wojtekmaj/date-utils": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@wojtekmaj/date-utils/-/date-utils-1.5.1.tgz", + "integrity": "sha512-+i7+JmNiE/3c9FKxzWFi2IjRJ+KzZl1QPu6QNrsgaa2MuBgXvUy4gA1TVzf/JMdIIloB76xSKikTWuyYAIVLww==", + "license": "MIT", + "funding": { + "url": "https://github.com/wojtekmaj/date-utils?sponsor=1" + } + }, + "node_modules/@xstate/react": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/@xstate/react/-/react-4.1.2.tgz", + "integrity": "sha512-orAidFrKCrU0ZwN5l/ABPlBfW2ziRDT2RrYoktRlZ0WRoLvA2E/uAC1JpZt43mCLtc8jrdwYCgJiqx1V8NvGTw==", + "license": "MIT", + "dependencies": { + "use-isomorphic-layout-effect": "^1.1.2", + "use-sync-external-store": "^1.2.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "xstate": "^5.18.1" + }, + "peerDependenciesMeta": { + "xstate": { + "optional": true + } + } + }, + "node_modules/acorn": { + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.3", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.3.tgz", + "integrity": "sha512-MxXdReSRhGO7VlFe1bRG/oI7/mdLV9B9JJT0N8vZOhF7gFRR5l3M8W9G8JxmKV+JC5mGqJ0QvqfSOLsCPa4nUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "dev": true, + "license": "MIT" + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", + "dev": true, + "license": "MIT" + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/aria-query": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", + "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "deep-equal": "^2.0.5" + } + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", + "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.5", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-includes": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz", + "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.4", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/array.prototype.findlast": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", + "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.findlastindex": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz", + "integrity": "sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", + "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", + "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.tosorted": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz", + "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3", + "es-errors": "^1.3.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz", + "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "es-abstract": "^1.22.3", + "es-errors": "^1.2.1", + "get-intrinsic": "^1.2.3", + "is-array-buffer": "^3.0.4", + "is-shared-array-buffer": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ast-types-flow": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz", + "integrity": "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/axe-core": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.10.0.tgz", + "integrity": "sha512-Mr2ZakwQ7XUAjp7pAwQWRhhK8mQQ6JAaNWSjmjxil0R8BPioMtQsTLOolGYkji1rcL++3dCqZA3zWqpT+9Ew6g==", + "dev": true, + "license": "MPL-2.0", + "engines": { + "node": ">=4" + } + }, + "node_modules/axobject-query": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.1.1.tgz", + "integrity": "sha512-goKlv8DZrK9hUh975fnHzhNIO4jUnFCfv/dszV5VwUGDFjI6vQ2VwoyjYjYNEbBE8AH87TduWP5uyDR1D+Iteg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "deep-equal": "^2.0.5" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } + }, + "node_modules/call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001651", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001651.tgz", + "integrity": "sha512-9Cf+Xv1jJNe1xPZLGuUXLNkE1BoDkqRqYyFJ9TDYSqhduqA4hu4oR9HluGoWYQC/aj8WHjsGVV+bwkh0+tegRg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/client-only": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", + "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==", + "license": "MIT" + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crypto-js": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz", + "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==", + "license": "MIT" + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "license": "MIT" + }, + "node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "license": "ISC", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-format": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", + "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "license": "ISC", + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "license": "ISC", + "dependencies": { + "d3-path": "^3.1.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "license": "ISC", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "license": "ISC", + "dependencies": { + "d3-time": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/damerau-levenshtein": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", + "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/data-view-buffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz", + "integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz", + "integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz", + "integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/date-arithmetic": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/date-arithmetic/-/date-arithmetic-4.1.0.tgz", + "integrity": "sha512-QWxYLR5P/6GStZcdem+V1xoto6DMadYWpMXU82ES3/RfR3Wdwr3D0+be7mgOJ+Ov0G9D5Dmb9T17sNLQYj9XOg==", + "license": "MIT" + }, + "node_modules/dayjs": { + "version": "1.11.12", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.12.tgz", + "integrity": "sha512-Rt2g+nTbLlDWZTwwrIXjy9MeiZmSDI375FvZs72ngxx8PDC6YXOeR3q5LAuPzjZQxhiWdRKac7RKV+YyQYfYIg==", + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", + "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decimal.js-light": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/decimal.js-light/-/decimal.js-light-2.5.1.tgz", + "integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==", + "license": "MIT" + }, + "node_modules/deep-equal": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.3.tgz", + "integrity": "sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "call-bind": "^1.0.5", + "es-get-iterator": "^1.1.3", + "get-intrinsic": "^1.2.2", + "is-arguments": "^1.1.1", + "is-array-buffer": "^3.0.2", + "is-date-object": "^1.0.5", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "isarray": "^2.0.5", + "object-is": "^1.1.5", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.5.1", + "side-channel": "^1.0.4", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", + "dev": true, + "license": "MIT" + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, + "node_modules/dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "license": "MIT", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/dotenv": { + "version": "17.3.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.3.1.tgz", + "integrity": "sha512-IO8C/dzEb6O3F9/twg6ZLXz164a2fhTnEWb95H23Dm4OuN+92NmEAlTrupP9VW6Jm3sO26tQlqyvyi4CsnY9GA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, + "license": "MIT" + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/enhanced-resolve": { + "version": "5.17.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", + "integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/es-abstract": { + "version": "1.23.3", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz", + "integrity": "sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "arraybuffer.prototype.slice": "^1.0.3", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "data-view-buffer": "^1.0.1", + "data-view-byte-length": "^1.0.1", + "data-view-byte-offset": "^1.0.0", + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-set-tostringtag": "^2.0.3", + "es-to-primitive": "^1.2.1", + "function.prototype.name": "^1.1.6", + "get-intrinsic": "^1.2.4", + "get-symbol-description": "^1.0.2", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.0.3", + "has-symbols": "^1.0.3", + "hasown": "^2.0.2", + "internal-slot": "^1.0.7", + "is-array-buffer": "^3.0.4", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.1", + "is-negative-zero": "^2.0.3", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.3", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.13", + "is-weakref": "^1.0.2", + "object-inspect": "^1.13.1", + "object-keys": "^1.1.1", + "object.assign": "^4.1.5", + "regexp.prototype.flags": "^1.5.2", + "safe-array-concat": "^1.1.2", + "safe-regex-test": "^1.0.3", + "string.prototype.trim": "^1.2.9", + "string.prototype.trimend": "^1.0.8", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.2", + "typed-array-byte-length": "^1.0.1", + "typed-array-byte-offset": "^1.0.2", + "typed-array-length": "^1.0.6", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.15" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-get-iterator": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz", + "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "has-symbols": "^1.0.3", + "is-arguments": "^1.1.1", + "is-map": "^2.0.2", + "is-set": "^2.0.2", + "is-string": "^1.0.7", + "isarray": "^2.0.5", + "stop-iteration-iterator": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-iterator-helpers": { + "version": "1.0.19", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.19.tgz", + "integrity": "sha512-zoMwbCcH5hwUkKJkT8kDIBZSz9I6mVG//+lDCinLCGov4+r7NIy0ld8o03M0cJxl2spVf6ESYVS6/gpIfq1FFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3", + "es-errors": "^1.3.0", + "es-set-tostringtag": "^2.0.3", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "globalthis": "^1.0.3", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.0.3", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.7", + "iterator.prototype": "^1.1.2", + "safe-array-concat": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", + "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz", + "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.4", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", + "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.0" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/esbuild": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", + "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.3", + "@esbuild/android-arm": "0.27.3", + "@esbuild/android-arm64": "0.27.3", + "@esbuild/android-x64": "0.27.3", + "@esbuild/darwin-arm64": "0.27.3", + "@esbuild/darwin-x64": "0.27.3", + "@esbuild/freebsd-arm64": "0.27.3", + "@esbuild/freebsd-x64": "0.27.3", + "@esbuild/linux-arm": "0.27.3", + "@esbuild/linux-arm64": "0.27.3", + "@esbuild/linux-ia32": "0.27.3", + "@esbuild/linux-loong64": "0.27.3", + "@esbuild/linux-mips64el": "0.27.3", + "@esbuild/linux-ppc64": "0.27.3", + "@esbuild/linux-riscv64": "0.27.3", + "@esbuild/linux-s390x": "0.27.3", + "@esbuild/linux-x64": "0.27.3", + "@esbuild/netbsd-arm64": "0.27.3", + "@esbuild/netbsd-x64": "0.27.3", + "@esbuild/openbsd-arm64": "0.27.3", + "@esbuild/openbsd-x64": "0.27.3", + "@esbuild/openharmony-arm64": "0.27.3", + "@esbuild/sunos-x64": "0.27.3", + "@esbuild/win32-arm64": "0.27.3", + "@esbuild/win32-ia32": "0.27.3", + "@esbuild/win32-x64": "0.27.3" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", + "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.0", + "@humanwhocodes/config-array": "^0.11.14", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-next": { + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-14.2.5.tgz", + "integrity": "sha512-zogs9zlOiZ7ka+wgUnmcM0KBEDjo4Jis7kxN1jvC0N4wynQ2MIx/KBkg4mVF63J5EK4W0QMCn7xO3vNisjaAoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@next/eslint-plugin-next": "14.2.5", + "@rushstack/eslint-patch": "^1.3.3", + "@typescript-eslint/parser": "^5.4.2 || ^6.0.0 || 7.0.0 - 7.2.0", + "eslint-import-resolver-node": "^0.3.6", + "eslint-import-resolver-typescript": "^3.5.2", + "eslint-plugin-import": "^2.28.1", + "eslint-plugin-jsx-a11y": "^6.7.1", + "eslint-plugin-react": "^7.33.2", + "eslint-plugin-react-hooks": "^4.5.0 || 5.0.0-canary-7118f5dd7-20230705" + }, + "peerDependencies": { + "eslint": "^7.23.0 || ^8.0.0", + "typescript": ">=3.3.1" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", + "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^3.2.7", + "is-core-module": "^2.13.0", + "resolve": "^1.22.4" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-import-resolver-typescript": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.6.1.tgz", + "integrity": "sha512-xgdptdoi5W3niYeuQxKmzVDTATvLYqhpwmykwsh7f6HIOStGWEIL9iqZgQDF9u9OEzrRwR8no5q2VT+bjAujTg==", + "dev": true, + "license": "ISC", + "dependencies": { + "debug": "^4.3.4", + "enhanced-resolve": "^5.12.0", + "eslint-module-utils": "^2.7.4", + "fast-glob": "^3.3.1", + "get-tsconfig": "^4.5.0", + "is-core-module": "^2.11.0", + "is-glob": "^4.0.3" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts/projects/eslint-import-resolver-ts" + }, + "peerDependencies": { + "eslint": "*", + "eslint-plugin-import": "*" + } + }, + "node_modules/eslint-module-utils": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.1.tgz", + "integrity": "sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^3.2.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import": { + "version": "2.29.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz", + "integrity": "sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-includes": "^3.1.7", + "array.prototype.findlastindex": "^1.2.3", + "array.prototype.flat": "^1.3.2", + "array.prototype.flatmap": "^1.3.2", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.9", + "eslint-module-utils": "^2.8.0", + "hasown": "^2.0.0", + "is-core-module": "^2.13.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.7", + "object.groupby": "^1.0.1", + "object.values": "^1.1.7", + "semver": "^6.3.1", + "tsconfig-paths": "^3.15.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-plugin-jsx-a11y": { + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.9.0.tgz", + "integrity": "sha512-nOFOCaJG2pYqORjK19lqPqxMO/JpvdCZdPtNdxY3kvom3jTvkAbOvQvD8wuD0G8BYR0IGAGYDlzqWJOh/ybn2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "aria-query": "~5.1.3", + "array-includes": "^3.1.8", + "array.prototype.flatmap": "^1.3.2", + "ast-types-flow": "^0.0.8", + "axe-core": "^4.9.1", + "axobject-query": "~3.1.1", + "damerau-levenshtein": "^1.0.8", + "emoji-regex": "^9.2.2", + "es-iterator-helpers": "^1.0.19", + "hasown": "^2.0.2", + "jsx-ast-utils": "^3.3.5", + "language-tags": "^1.0.9", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.8", + "safe-regex-test": "^1.0.3", + "string.prototype.includes": "^2.0.0" + }, + "engines": { + "node": ">=4.0" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + } + }, + "node_modules/eslint-plugin-react": { + "version": "7.35.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.35.0.tgz", + "integrity": "sha512-v501SSMOWv8gerHkk+IIQBkcGRGrO2nfybfj5pLxuJNFTPxxA3PSryhXTK+9pNbtkggheDdsC0E9Q8CuPk6JKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-includes": "^3.1.8", + "array.prototype.findlast": "^1.2.5", + "array.prototype.flatmap": "^1.3.2", + "array.prototype.tosorted": "^1.1.4", + "doctrine": "^2.1.0", + "es-iterator-helpers": "^1.0.19", + "estraverse": "^5.3.0", + "hasown": "^2.0.2", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.8", + "object.fromentries": "^2.0.8", + "object.values": "^1.2.0", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.5", + "semver": "^6.3.1", + "string.prototype.matchall": "^4.0.11", + "string.prototype.repeat": "^1.0.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.2.tgz", + "integrity": "sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" + } + }, + "node_modules/eslint-plugin-react/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-react/node_modules/resolve": { + "version": "2.0.0-next.5", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", + "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/eslint-plugin-react/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "license": "MIT" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-equals": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-5.0.1.tgz", + "integrity": "sha512-WF1Wi8PwwSY7/6Kx0vKXtw8RwuSGoM1bvDaJbu7MxDlR1vovZjIAKrnzyrThgAjm6JDTu0fVgWXDlMGspodfoQ==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", + "dev": true, + "license": "ISC" + }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/foreground-child": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", + "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function.prototype.name": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", + "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "functions-have-names": "^1.2.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-symbol-description": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz", + "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-tsconfig": { + "version": "4.7.6", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.6.tgz", + "integrity": "sha512-ZAqrLlu18NbDdRaHq+AKXzAmqIUPswPWKUchfytdAjiRFnCe5ojG2bstg6mRiZabkKfCoL/e98pbBELIV/YCeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/get-user-locale": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/get-user-locale/-/get-user-locale-2.3.2.tgz", + "integrity": "sha512-O2GWvQkhnbDoWFUJfaBlDIKUEdND8ATpBXD6KXcbhxlfktyD/d8w6mkzM/IlQEqGZAMz/PW6j6Hv53BiigKLUQ==", + "license": "MIT", + "dependencies": { + "mem": "^8.0.0" + }, + "funding": { + "url": "https://github.com/wojtekmaj/get-user-locale?sponsor=1" + } + }, + "node_modules/glob": { + "version": "10.3.10", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", + "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "license": "BSD-2-Clause" + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/globalize": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/globalize/-/globalize-0.1.1.tgz", + "integrity": "sha512-5e01v8eLGfuQSOvx2MsDMOWS0GFtCx1wPzQSmcHw4hkxFzrQDBO3Xwg/m8Hr/7qXMrHeOIE29qWVzyv06u1TZA==" + }, + "node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true, + "license": "MIT" + }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/iceberg-js": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/iceberg-js/-/iceberg-js-0.8.1.tgz", + "integrity": "sha512-1dhVQZXhcHje7798IVM+xoo/1ZdVfzOMIc8/rgVSijRK38EDqOJoGula9N/8ZI5RD8QTxNQtK/Gozpr+qUqRRA==", + "license": "MIT", + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/ignore": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/internal-slot": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", + "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.0", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, + "node_modules/is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", + "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-async-function": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz", + "integrity": "sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.0.tgz", + "integrity": "sha512-Dd+Lb2/zvk9SKy1TGCt1wFJFo/MWBPMX5x7KcvLajWTGuomczdQX61PvY5yK6SVACwpoexWo81IfFyoKY2QnTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-view": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz", + "integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-finalizationregistry": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz", + "integrity": "sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-set": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", + "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", + "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "which-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakmap": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.3.tgz", + "integrity": "sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/iterator.prototype": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.2.tgz", + "integrity": "sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.2.1", + "get-intrinsic": "^1.2.1", + "has-symbols": "^1.0.3", + "reflect.getprototypeof": "^1.0.4", + "set-function-name": "^2.0.1" + } + }, + "node_modules/jackspeak": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", + "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/jiti": { + "version": "1.21.6", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.6.tgz", + "integrity": "sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/js-cookie": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.5.tgz", + "integrity": "sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==", + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/jsx-ast-utils": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", + "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "object.assign": "^4.1.4", + "object.values": "^1.1.6" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/language-subtag-registry": { + "version": "0.3.23", + "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz", + "integrity": "sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/language-tags": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.9.tgz", + "integrity": "sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==", + "dev": true, + "license": "MIT", + "dependencies": { + "language-subtag-registry": "^0.3.20" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lilconfig": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "license": "MIT" + }, + "node_modules/lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", + "license": "MIT" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.3" + } + }, + "node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/luxon": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.5.0.tgz", + "integrity": "sha512-rh+Zjr6DNfUYR3bPwJEnuwDdqMbxZW7LOQfUN4B54+Cl+0o5zaU9RJ6bcidfDtC1cWCZXQ+nvX8bf6bAji37QQ==", + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true, + "license": "ISC" + }, + "node_modules/map-age-cleaner": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", + "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", + "license": "MIT", + "dependencies": { + "p-defer": "^1.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/map-obj": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz", + "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mem": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/mem/-/mem-8.1.1.tgz", + "integrity": "sha512-qFCFUDs7U3b8mBDPyz5EToEKoAkgCzqquIgi9nkkR9bixxOVOre+09lbuH7+9Kn2NFpm56M3GUWVbU2hQgdACA==", + "license": "MIT", + "dependencies": { + "map-age-cleaner": "^0.1.3", + "mimic-fn": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/mem?sponsor=1" + } + }, + "node_modules/memoize-one": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz", + "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==", + "license": "MIT" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", + "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mimic-fn": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-3.1.0.tgz", + "integrity": "sha512-Ysbi9uYW9hFyfrThdDEQuykN4Ey6BuwPD2kpI5ES/nFTDn/98yxYNLZJcgUAKPT/mcrLLKaGzJR9YVxJrIdASQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/moment": { + "version": "2.30.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", + "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/moment-timezone": { + "version": "0.5.45", + "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.45.tgz", + "integrity": "sha512-HIWmqA86KcmCAhnMAN0wuDOARV/525R2+lOLotuGFzn4HO+FH+/645z2wx0Dt3iDv6/p61SIvKnDstISainhLQ==", + "license": "MIT", + "dependencies": { + "moment": "^2.29.4" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/next": { + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/next/-/next-14.2.5.tgz", + "integrity": "sha512-0f8aRfBVL+mpzfBjYfQuLWh2WyAwtJXCRfkPF4UJ5qd2YwrHczsrSzXU4tRMV0OAxR8ZJZWPFn6uhSC56UTsLA==", + "license": "MIT", + "dependencies": { + "@next/env": "14.2.5", + "@swc/helpers": "0.5.5", + "busboy": "1.6.0", + "caniuse-lite": "^1.0.30001579", + "graceful-fs": "^4.2.11", + "postcss": "8.4.31", + "styled-jsx": "5.1.1" + }, + "bin": { + "next": "dist/bin/next" + }, + "engines": { + "node": ">=18.17.0" + }, + "optionalDependencies": { + "@next/swc-darwin-arm64": "14.2.5", + "@next/swc-darwin-x64": "14.2.5", + "@next/swc-linux-arm64-gnu": "14.2.5", + "@next/swc-linux-arm64-musl": "14.2.5", + "@next/swc-linux-x64-gnu": "14.2.5", + "@next/swc-linux-x64-musl": "14.2.5", + "@next/swc-win32-arm64-msvc": "14.2.5", + "@next/swc-win32-ia32-msvc": "14.2.5", + "@next/swc-win32-x64-msvc": "14.2.5" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.1.0", + "@playwright/test": "^1.41.2", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "sass": "^1.3.0" + }, + "peerDependenciesMeta": { + "@opentelemetry/api": { + "optional": true + }, + "@playwright/test": { + "optional": true + }, + "sass": { + "optional": true + } + } + }, + "node_modules/next-cloudinary": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/next-cloudinary/-/next-cloudinary-6.13.0.tgz", + "integrity": "sha512-jaClAJb9P3PMkN9x6Y08NVFNTYUl1KmhvIYReG+sCVaHPuMFgIkQzLTBpinmuQznAdHnpHzSmNpt2o6bcFugQQ==", + "license": "MIT", + "dependencies": { + "@cloudinary-util/types": "1.5.8", + "@cloudinary-util/url-loader": "5.10.3", + "@cloudinary-util/util": "^3.3.2", + "@tsconfig/recommended": "^1.0.7" + }, + "peerDependencies": { + "next": "^12 || ^13 || ^14 || >=15.0.0-rc", + "react": "^17 || ^18 || >=19.0.0-beta" + } + }, + "node_modules/next/node_modules/postcss": { + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "license": "MIT", + "dependencies": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/object-inspect": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", + "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-is": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz", + "integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", + "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.entries": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.8.tgz", + "integrity": "sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", + "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.groupby": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", + "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.values": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.0.tgz", + "integrity": "sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-defer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", + "integrity": "sha512-wB3wfAxZpk2AzOfUMJNL+d36xothRSyj8EXOa4f6GMqYDN9BJaaSISbsk+wS9abmnebVw95C2Kb5t85UmpCxuw==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-to-regexp": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.2.tgz", + "integrity": "sha512-GQX3SSMokngb36+whdpRXE+3f9V8UzyAorlYvOGx87ufGHehNTn5lCxrKtLyZ4Yl/wEKnNnr98ZzOwwDZV5ogw==", + "license": "MIT" + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", + "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pirates": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", + "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/possible-typed-array-names": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", + "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/postcss": { + "version": "8.4.41", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.41.tgz", + "integrity": "sha512-TesUflQ0WKZqAvg52PWL6kHgLKP6xB6heTOdoYM0Wt2UHyxNa4K25EZZMgKns3BH1RLVbZCREPpLY0rhnNoHVQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.0.1", + "source-map-js": "^1.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-import": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", + "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-js": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", + "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", + "dev": true, + "license": "MIT", + "dependencies": { + "camelcase-css": "^2.0.1" + }, + "engines": { + "node": "^12 || ^14 || >= 16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.4.21" + } + }, + "node_modules/postcss-load-config": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz", + "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "lilconfig": "^3.0.0", + "yaml": "^2.3.4" + }, + "engines": { + "node": ">= 14" + }, + "peerDependencies": { + "postcss": ">=8.0.9", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "postcss": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/postcss-load-config/node_modules/lilconfig": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.2.tgz", + "integrity": "sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/postcss-nested": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", + "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^6.1.1" + }, + "engines": { + "node": ">=12.0" + }, + "peerDependencies": { + "postcss": "^8.2.14" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.1.tgz", + "integrity": "sha512-b4dlw/9V8A71rLIDsSwVmak9z2DuBUB7CA1/wSdelNEzqsjoSPeADTWNO09lpH49Diy3/JIZ2bSPB1dI3LJCHg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prisma": { + "version": "5.19.1", + "resolved": "https://registry.npmjs.org/prisma/-/prisma-5.19.1.tgz", + "integrity": "sha512-c5K9MiDaa+VAAyh1OiYk76PXOme9s3E992D7kvvIOhCrNsBQfy2mP2QAQtX0WNj140IgG++12kwZpYB9iIydNQ==", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@prisma/engines": "5.19.1" + }, + "bin": { + "prisma": "build/index.js" + }, + "engines": { + "node": ">=16.13" + }, + "optionalDependencies": { + "fsevents": "2.3.3" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-big-calendar": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/react-big-calendar/-/react-big-calendar-1.13.2.tgz", + "integrity": "sha512-yzeVRM1I+JloeJXytrZx2lJWKUfLAi5bsgGuBjh3aFSHZrdFcGnfA7LE6pBacdyOG+NGP+332m2MziszkmQWcw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.20.7", + "clsx": "^1.2.1", + "date-arithmetic": "^4.1.0", + "dayjs": "^1.11.7", + "dom-helpers": "^5.2.1", + "globalize": "^0.1.1", + "invariant": "^2.2.4", + "lodash": "^4.17.21", + "lodash-es": "^4.17.21", + "luxon": "^3.2.1", + "memoize-one": "^6.0.0", + "moment": "^2.29.4", + "moment-timezone": "^0.5.40", + "prop-types": "^15.8.1", + "react-overlays": "^5.2.1", + "uncontrollable": "^7.2.1" + }, + "peerDependencies": { + "react": "^16.14.0 || ^17 || ^18", + "react-dom": "^16.14.0 || ^17 || ^18" + } + }, + "node_modules/react-big-calendar/node_modules/clsx": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", + "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/react-calendar": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/react-calendar/-/react-calendar-5.0.0.tgz", + "integrity": "sha512-bHcE5e5f+VUKLd4R19BGkcSQLpuwjKBVG0fKz74cwPW5xDfNsReHdDbfd4z3mdjuUuZzVtw4Q920mkwK5/ZOEg==", + "license": "MIT", + "dependencies": { + "@wojtekmaj/date-utils": "^1.1.3", + "clsx": "^2.0.0", + "get-user-locale": "^2.2.1", + "warning": "^4.0.0" + }, + "funding": { + "url": "https://github.com/wojtekmaj/react-calendar?sponsor=1" + }, + "peerDependencies": { + "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, + "node_modules/react-hook-form": { + "version": "7.52.2", + "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.52.2.tgz", + "integrity": "sha512-pqfPEbERnxxiNMPd0bzmt1tuaPcVccywFDpyk2uV5xCIBphHV5T8SVnX9/o3kplPE1zzKt77+YIoq+EMwJp56A==", + "license": "MIT", + "engines": { + "node": ">=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/react-hook-form" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17 || ^18 || ^19" + } + }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, + "node_modules/react-lifecycles-compat": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", + "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==", + "license": "MIT" + }, + "node_modules/react-overlays": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/react-overlays/-/react-overlays-5.2.1.tgz", + "integrity": "sha512-GLLSOLWr21CqtJn8geSwQfoJufdt3mfdsnIiQswouuQ2MMPns+ihZklxvsTDKD3cR2tF8ELbi5xUsvqVhR6WvA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.8", + "@popperjs/core": "^2.11.6", + "@restart/hooks": "^0.4.7", + "@types/warning": "^3.0.0", + "dom-helpers": "^5.2.0", + "prop-types": "^15.7.2", + "uncontrollable": "^7.2.1", + "warning": "^4.0.3" + }, + "peerDependencies": { + "react": ">=16.3.0", + "react-dom": ">=16.3.0" + } + }, + "node_modules/react-smooth": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/react-smooth/-/react-smooth-4.0.1.tgz", + "integrity": "sha512-OE4hm7XqR0jNOq3Qmk9mFLyd6p2+j6bvbPJ7qlB7+oo0eNcL2l7WQzG6MBnT3EXY6xzkLMUBec3AfewJdA0J8w==", + "license": "MIT", + "dependencies": { + "fast-equals": "^5.0.1", + "prop-types": "^15.8.1", + "react-transition-group": "^4.4.5" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/react-toastify": { + "version": "10.0.5", + "resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-10.0.5.tgz", + "integrity": "sha512-mNKt2jBXJg4O7pSdbNUfDdTsK9FIdikfsIE/yUCxbAEXl4HMyJaivrVFcn3Elvt5xvCQYhUZm+hqTIu1UXM3Pw==", + "license": "MIT", + "dependencies": { + "clsx": "^2.1.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "license": "BSD-3-Clause", + "dependencies": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": ">=16.6.0", + "react-dom": ">=16.6.0" + } + }, + "node_modules/read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pify": "^2.3.0" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/recharts": { + "version": "2.12.7", + "resolved": "https://registry.npmjs.org/recharts/-/recharts-2.12.7.tgz", + "integrity": "sha512-hlLJMhPQfv4/3NBSAyq3gzGg4h2v69RJh6KU7b3pXYNNAELs9kEoXOjbkxdXpALqKBoVmVptGfLpxdaVYqjmXQ==", + "license": "MIT", + "dependencies": { + "clsx": "^2.0.0", + "eventemitter3": "^4.0.1", + "lodash": "^4.17.21", + "react-is": "^16.10.2", + "react-smooth": "^4.0.0", + "recharts-scale": "^0.4.4", + "tiny-invariant": "^1.3.1", + "victory-vendor": "^36.6.8" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "react": "^16.0.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/recharts-scale": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/recharts-scale/-/recharts-scale-0.4.5.tgz", + "integrity": "sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w==", + "license": "MIT", + "dependencies": { + "decimal.js-light": "^2.4.1" + } + }, + "node_modules/reflect.getprototypeof": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz", + "integrity": "sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.1", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "globalthis": "^1.0.3", + "which-builtin-type": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", + "license": "MIT" + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", + "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.6", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "set-function-name": "^2.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-array-concat": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz", + "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-regex-test": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", + "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-regex": "^1.1.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/server-only": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/server-only/-/server-only-0.0.1.tgz", + "integrity": "sha512-qepMx2JxAa5jjfzxG79yPPq+8BuFToHd1hm7kI+Z4zAq1ftQiP7HcxMhDDItrbtwVeLg/cY2JnKnrcFkmiswNA==", + "license": "MIT" + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/snake-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz", + "integrity": "sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==", + "license": "MIT", + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/snakecase-keys": { + "version": "5.4.4", + "resolved": "https://registry.npmjs.org/snakecase-keys/-/snakecase-keys-5.4.4.tgz", + "integrity": "sha512-YTywJG93yxwHLgrYLZjlC75moVEX04LZM4FHfihjHe1FCXm+QaLOFfSf535aXOAd0ArVQMWUAe8ZPm4VtWyXaA==", + "license": "MIT", + "dependencies": { + "map-obj": "^4.1.0", + "snake-case": "^3.0.4", + "type-fest": "^2.5.2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/snakecase-keys/node_modules/type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/source-map-js": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", + "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/std-env": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.7.0.tgz", + "integrity": "sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==", + "license": "MIT" + }, + "node_modules/stop-iteration-iterator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", + "integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "internal-slot": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/string-width/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/string-width/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/string.prototype.includes": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/string.prototype.includes/-/string.prototype.includes-2.0.0.tgz", + "integrity": "sha512-E34CkBgyeqNDcrbU76cDjL5JLcVrtSdYq0MEh/B10r17pRP4ciHLwTgnuLV8Ay6cgEMLkcBkFCKyFZ43YldYzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "node_modules/string.prototype.matchall": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.11.tgz", + "integrity": "sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.7", + "regexp.prototype.flags": "^1.5.2", + "set-function-name": "^2.0.2", + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.repeat": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz", + "integrity": "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz", + "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz", + "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/styled-jsx": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.1.tgz", + "integrity": "sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==", + "license": "MIT", + "dependencies": { + "client-only": "0.0.1" + }, + "engines": { + "node": ">= 12.0.0" + }, + "peerDependencies": { + "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/sucrase": { + "version": "3.35.0", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", + "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "glob": "^10.3.10", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "ts-interface-checker": "^0.1.9" + }, + "bin": { + "sucrase": "bin/sucrase", + "sucrase-node": "bin/sucrase-node" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/swr": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/swr/-/swr-2.2.5.tgz", + "integrity": "sha512-QtxqyclFeAsxEUeZIYmsaQ0UjimSq1RZ9Un7I68/0ClKK/U3LoyQunwkQfJZr2fc22DfIXLNDc2wFyTEikCUpg==", + "license": "MIT", + "dependencies": { + "client-only": "^0.0.1", + "use-sync-external-store": "^1.2.0" + }, + "peerDependencies": { + "react": "^16.11.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/tailwindcss": { + "version": "3.4.9", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.9.tgz", + "integrity": "sha512-1SEOvRr6sSdV5IDf9iC+NU4dhwdqzF4zKKq3sAbasUWHEM6lsMhX+eNN5gkPx1BvLFEnZQEUFbXnGj8Qlp83Pg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.5.3", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.3.0", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.21.0", + "lilconfig": "^2.1.0", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.0.0", + "postcss": "^8.4.23", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.1", + "postcss-nested": "^6.0.1", + "postcss-selector-parser": "^6.0.11", + "resolve": "^1.22.2", + "sucrase": "^3.32.0" + }, + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true, + "license": "MIT" + }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/tiny-invariant": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", + "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", + "license": "MIT" + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ts-api-utils": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", + "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/ts-interface-checker": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/ts-node/node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true, + "license": "MIT" + }, + "node_modules/tsconfig-paths": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", + "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/tsx": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", + "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.27.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz", + "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz", + "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz", + "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz", + "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typescript": { + "version": "5.5.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz", + "integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/uncontrollable": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-7.2.1.tgz", + "integrity": "sha512-svtcfoTADIB0nT9nltgjujTi7BzVmwjZClOmskKu/E8FW9BXzg9os8OLr4f8Dlnk0rYWJIWr4wv9eKUXiQvQwQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.6.3", + "@types/react": ">=16.9.11", + "invariant": "^2.2.4", + "react-lifecycles-compat": "^3.0.4" + }, + "peerDependencies": { + "react": ">=15.0.0" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "license": "MIT" + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/use-isomorphic-layout-effect": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz", + "integrity": "sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-sync-external-store": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.2.tgz", + "integrity": "sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true, + "license": "MIT" + }, + "node_modules/victory-vendor": { + "version": "36.9.2", + "resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-36.9.2.tgz", + "integrity": "sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ==", + "license": "MIT AND ISC", + "dependencies": { + "@types/d3-array": "^3.0.3", + "@types/d3-ease": "^3.0.0", + "@types/d3-interpolate": "^3.0.1", + "@types/d3-scale": "^4.0.2", + "@types/d3-shape": "^3.1.0", + "@types/d3-time": "^3.0.0", + "@types/d3-timer": "^3.0.0", + "d3-array": "^3.1.6", + "d3-ease": "^3.0.1", + "d3-interpolate": "^3.0.1", + "d3-scale": "^4.0.2", + "d3-shape": "^3.1.0", + "d3-time": "^3.0.0", + "d3-timer": "^3.0.1" + } + }, + "node_modules/warning": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", + "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.1.4.tgz", + "integrity": "sha512-bppkmBSsHFmIMSl8BO9TbsyzsvGjVoppt8xUiGzwiu/bhDCGxnpOKCxgqj6GuyHE0mINMDecBFPlOm2hzY084w==", + "dev": true, + "license": "MIT", + "dependencies": { + "function.prototype.name": "^1.1.6", + "has-tostringtag": "^1.0.2", + "is-async-function": "^2.0.0", + "is-date-object": "^1.0.5", + "is-finalizationregistry": "^1.0.2", + "is-generator-function": "^1.0.10", + "is-regex": "^1.1.4", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.2", + "which-typed-array": "^1.1.15" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-collection": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", + "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/ws": { + "version": "8.19.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz", + "integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==", + "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/xstate": { + "version": "5.18.1", + "resolved": "https://registry.npmjs.org/xstate/-/xstate-5.18.1.tgz", + "integrity": "sha512-m02IqcCQbaE/kBQLunwub/5i8epvkD2mFutnL17Oeg1eXTShe1sRF4D5mhv1dlaFO4vbW5gRGRhraeAD5c938g==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/xstate" + } + }, + "node_modules/yaml": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.5.0.tgz", + "integrity": "sha512-2wWLbGbYDiSqqIKoPjar3MPgB94ErzCtrNE1FdqGuaO0pi2JGjmE8aW8TDZwzU7vuxcGRdL/4gPQwQ7hD5AMSw==", + "dev": true, + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zod": { + "version": "3.23.8", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz", + "integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..f9a0176 --- /dev/null +++ b/package.json @@ -0,0 +1,46 @@ +{ + "name": "lama-dev-next-dashboard", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "next dev", + "build": "next build", + "start": "next start", + "lint": "next lint", + "seed:users": "tsx scripts/seed.ts", + "seed:schedule": "tsx scripts/seed_schedule.ts" + }, + "dependencies": { + "@clerk/elements": "^0.14.6", + "@clerk/nextjs": "^5.4.1", + "@hookform/resolvers": "^3.9.0", + "@prisma/client": "^5.19.1", + "@supabase/supabase-js": "^2.98.0", + "@types/react-big-calendar": "^1.8.9", + "moment": "^2.30.1", + "next": "14.2.5", + "next-cloudinary": "^6.13.0", + "prisma": "^5.19.1", + "react": "^18", + "react-big-calendar": "^1.13.2", + "react-calendar": "^5.0.0", + "react-dom": "^18", + "react-hook-form": "^7.52.2", + "react-toastify": "^10.0.5", + "recharts": "^2.12.7", + "zod": "^3.23.8" + }, + "devDependencies": { + "@types/node": "^20", + "@types/react": "^18", + "@types/react-dom": "^18", + "dotenv": "^17.3.1", + "eslint": "^8", + "eslint-config-next": "14.2.5", + "postcss": "^8", + "tailwindcss": "^3.4.1", + "ts-node": "^10.9.2", + "tsx": "^4.21.0", + "typescript": "^5" + } +} \ No newline at end of file diff --git a/postcss.config.mjs b/postcss.config.mjs new file mode 100644 index 0000000..1a69fd2 --- /dev/null +++ b/postcss.config.mjs @@ -0,0 +1,8 @@ +/** @type {import('postcss-load-config').Config} */ +const config = { + plugins: { + tailwindcss: {}, + }, +}; + +export default config; diff --git a/public/announcement.png b/public/announcement.png new file mode 100644 index 0000000000000000000000000000000000000000..6928d0e3b5ee92049a6d617336ddeee88400268f GIT binary patch literal 2985 zcmb_edpuP87T-fn9v7WXubU$rj}gtoV3>(1;}KUOF`hBQ-orS1-Xnu*R8+SRIYou& zq>?CgFr`yd#~E~0r^q8JCvsC>G3rF>>`^(gDjeSk6;l1=+>%k)Ilp@3_!bv!M1PuU=5(@Ilfy7KB2?yqiC=w^k6oP`htHgK=Rmso2Z?xb!YJtT4*2NMMF=s)5J)8wh_+aQ1D1dgG)pyIM8}T` zH;LF2q=L3~Ha7OwBrJ<$ZI87j5+N)TBu8PbnM`|I0wIzG5lPd&KA3#r$vqNrWJk0k zlI+OVw$}D!I|stF&6M&B6MtS@RE#PuDsdY5r|eJozbW%fx;~{klh*%Jq4}SkDpi%I zj;pG^hytmv&5ZgYGKzDYIEE*ru5)!%K|X!XO6h-ZKx9nJ=)UQ=BuxGneTRT4Q$4~H z`tx`&)rHC3%rvs_gSa3hgoG;`@v{;CDc(=>XBGyTM4$CAetMEopXmfL000eox;pzy z@&g>(&Wmjir`qnjD zAJ<83iT2px5@u(%N6{tURaMxzqI1!L*af>YoSC%+>XvpVjLi?9U!^~3e6Jha>yg@L zSQF@dQ!{^?Y|Jo$|GqJ4qSuD^`0DH4!5ap+_{nQ1QZ^olw~V-K;BAm2T)ThKHmZZ8 z@OV4CMb-(w6$$cnyGTazYM>n~eQ*6X@uN;(FE5fz>XjV9k-3={D>eZ0W5-OBcVT+kH;2|0cQ)7*uO@h(;(%8-md=s(_lQ~ngB)E6 zEgVgl2at$p;6U5iT_O3Ac?JBiWijnG-X;LL^y!*r%k2;9hswA7lHoN^q1ZZ?aofH3 z+iqox(x06^lpXyyX=PUM>3|)W>L*EcUo~ncNVUsDbeC6E1owkWV(o4@yvgu#dT%4A z-90v(;!h%8ye}N)FE|zkZJsj|LrAHs-~VOC$!NlK1R~xv8gn$=Al(}0K(BRMqU9r z*|(I}Qh9{eimAAyS$N&yCxT+KA(p&!edH(=XluKoaQNw|todmB*1@i{CiO-$O-2!2 zGkienR{`6w+kZG^i<;b7|FCuu{f_v7X|_IzXp`3TTZKSc6{34JtCn@&owZ!eDy=EY zl#~;yNHAXOXe`z1nxDMrgkeVjW2XiM_jKv0iCnJ(f@O30bL4x|8_o2OcE^=HS$|uc zFE}1cmWbg_>7B2I$B|tdgi0+@UyQ-;_`>u?KMgzeuJ6+uX{_CMP`#;duVQ*!0C$v9 zE$DpK1`_E`TYaNhMR5C^zo<%Ej_KK--DV4eIBRceav`ZS|OAb) z$trMC9w4i+S_3SM9pg?!Zn9Eme6?y%WD9wZAn}2F?+wb>0nCYxt6efNFTB2Pgtj~; z;*N3IstHPeQLdL>^Y-=uz`P=uHf~P;?jYk<-Qrlt(YWvdaw*l5ZY{v^7HK1A>quHtj3;b^{OCyKd#yxH>lcTF3Mi+oGZRo=?{;gWA@pY@>6 z;=S)&%ND#X88}P^@Kx2tS28Cu=}Gnzs6PIDlY!+!)$vR84+m>F4r#s#DqC>&oXEgy z-KJ7Ez$UJY1sLVjvhKR~ZcwbSSU7pzxAd`T1-rR2WH<$u&i_w$U`i~e@JWE*Umz-G41=6 z`#SWx#(Ya7?pG2sywsz*->og8>$OxS>I2B}xv=8RHlO;t{cG&Ade8GrL?v`hZX|=q5sT>u0z(-r@4Cnx(ab=6O-QF)rYcjbnBs8CSmwNntsDce9o>7*0XIyMJ z(WOb={$tz?_uiMjrS=NNq#ms-BmS}}M@x2{H5pv{_A*_18yJepD^Cq+NDOJS|Ncs5 zZP@rPzg2;F9RMUh2p+xaQ~-Ksl1`aV(LxEnl$g;mxJe zPykif4!`9f6CfB6A#?Kfq1CLsaDb3s+Z$1%BP$NwM7N0;Nm*Ih0)ruAXRAjyuFA$f zetyBCAR4#zX=%~~Z)?(z!z+^yhL}kPNyD7U@I1Gd5_Kh-)u8&B_H^@hEvGSd`~eLmszm?* literal 0 HcmV?d00001 diff --git a/public/assignment.png b/public/assignment.png new file mode 100644 index 0000000000000000000000000000000000000000..c37102ded523ba6d9a37bf240a7536f12e778d6c GIT binary patch literal 2138 zcmeAS@N?(olHy`uVBq!ia0vp^8X(NU1|)m_?Z^dEoCO|{#S9F5M?jcysy3fA0|U#O z%#etZ2wxwoOb0f1P<1`~na}&5(5G@!cxg`M&GBq+aGBdR_G%+-{G_?Rm z5Y!s5B!-rd{Lu}U|cjWQJw&Sd380To+;(@1_%NPd2fopWMd zS)zhQP-I>_0SWyJeB_O>RvJP^uroNlYaHBZRVs>RE(vO|xPm6P8` zDE!u21rGt9*519(4@TdWsxann?&5P|le5~9?SFCm`Pl2GAF8XYjo)vdKlgk2Hok== zC28k`yZab3+;TUi)Lfl^-b(mr+phxsjV~HLUfpwXRrdQ_2G0OLonK4`t~oHc_l8CK zb8TF{DM^BTL3%bg0Cw}o^AekwYlb+YC4D(X{Oi@4Tw6OMCs|4ScD#@+&q56|l9*a2a z);=1`u-WYKUe9CFRlnQnm@~FX%D;arT@_@k;CUgBVYS&~{*B*$?8&TQ4ettDV|&f5 zDEQpt6;c!1cT5s_#~}H5b>`x$;t6jHZui_jl|DC+;qS5V`Alm|ZXQs1Y@TyW{;2ED zpgSLzoM2|ym|@+ZyiO#xG3+#h16Kya;&~#%f=eGU_O5>x)A4YJ!{gOIFMMm_E?nB7 z{ii{2(aYUCzIrh+uPs?Hb@Sw=g|*X})=o3qs>>eLIrqxV@BO=&6P9Y0iq79Gxj)ty z7~;2Uu2pW0{r}&#d7ely5LLI{)cRe=#@{e?*%j^og-I8?L(O!mf^_n(N4}c+f6dt+ z30G#so~XF#;NRux-*xh?`O)+H?Abxeqqx5pgxP5BYt54LUTXY(wrkEU zaNuo}ojWu8$RbMy`R#`pO_^@>Y-ik&Uh`FLe(5^*-n%@1JcYgpN&Jtpm6KwaW3sO* zmW!RC^dUb`6Zert=NYzyc(XGc3%^-&&GWeAZ*d`3`z`Kj8LFV#-_zC4Wt~$(699l{ Bh6sSFy&sE~n>ND@ORWs-`_3W^Gsd;RNIOb zDsey%cnVk)p+OLe;DBP0Ac_T}j50Y;301*&LoF5h-uv<1%UU=0oV~xj&mO+B*G=&E z^}5LyoFwwO^Ov1CL2w;KEUmLV)1e8%5*xTpSmc^P@#L0*=Ze83GjW-}5jone3GG zFOD9Ey_e~KSp-)Ek?|uZ3L%mcp>c`AP(32rSQ5lFl!82|6n|JTUAgl20ykt51WTt# z&|(-A5=bV8gJUGHGd>WOixn~s{5}KTIdqf35CU`A6f%WMAkztCCl+anYNCm(cM1~5l4s;HULZ%TQ8a;|Yr7#!-$ib0Hh;pK#a&Dxf6BnBB^@qvdJb6Zq8wW8to7NT|)`rT;hDCA0gKcxds99D1ALQr9 zW}0Q!Vp{H)u2M&?<2n`1$iEj!3kpj^3bR94C3dG@KDue2Q>$sk7VRq@xmwP^$CZ`D zbIB_Z`12vUy6A;+I7piYPslC^=BEBn|$!J_=gmEm<1V5b22`FuD=un?83IY zyBS4A=X(V`x%nuV*|=S%4ywjnuip~BA=~jPDr{O`Adj4(c@oSVvT6VA{ynlJxzQCA z2UdL%X@@Q$a3*`tXfdHj1ZVgff2>Q0<9Mf}W_h-|Rkr%;Yj)iGUdyx3`<7z*D^?M% zU7{IDg|-)4{CXQ)F!B4mV(W$Qgw7Y=AF2!c(r3qS4bUTiJ5u7?@#6dA>S8v{-UjsS z``xycJlcO&(TAgh`LI>W@;QnXhwE>e9#a-H3EsqiU<1f0V~72XNZ@ZW?2GHjhC(RaZK&?mYGCK?}FMVrm8i-x-$M~l?T%7;CtDW zjL}K+9su)e)F9O426e|W^q`Zu>5wj~;086;?qseUuo*Kmw4>?#--@*Hm`azps(ceq zT*&Oi7UJCg2bd~_>lpE5?vA{OhwN#@=@z=pwNH90XNM1(nO|E~kvi~phU5mh5VE@E z=)3mZMPB%s()u4Yq_Lv(L#wKPB`V4Q?%9=3bxEA{1w+G8nk>(dC;J$;=^Kpa&tOSC zd)qDna$Z9yQS59{+54z_t1jX74UgC9+g*#!-__605rYG}XbNM$Hz&4UxZLDbQc1V1 zYVjRhQx<$q-xS}l&`eb}$Ottho9l`b`##Tm%rxI}t2O{EIhotMV$Ms;(*gOLwvENl zD%}q*1xeMTyGfR&74$hHj}^7vek*&opANXRX&bvKJ1inY08-GT3O63nhivUG%a3Yb zUdzX;ob!;V?(h2Mc%7ap-{N$Wq6*p<>f=Atl}`iHY2@|ZrqJI5Ogsv2}XN7c8w;7|%$idkT8^G_w# zmY}yH*X)?mMsQCp@s5CsnF@p>slH?&%MaK0oB2m)v?Mp~6{T%jt!7{% zSkJDg*XO8TItA!GzTzX>7dCaJdEP>a&&??K1v`}Vs<=xE7Fn{M-+Fk-f6OCyC(YXS zbi<;L5@SPFtA9-M>@Hc=TbA5NZ|All@?pBl51gy>c-=q_xT>grlfa5ngyElE8R*Q6 zFKR}((fQ_`M_VFx;}@=;H?aS8&(Eh?_R(yVKU<#vbi}VnEv3M}+u!}{A^$9)hu(hS z8!gYR_DEye;e*{-_20r|-}~%Fms&buUFpT-&TIF+v43C`u`I7aNfehGMR@5FY7+Zc zHeGJ%g5wy8T$ix4Gqapz#d|xNblF%EgzhPe)@1oMVTV4feXm@e6Va zfwCg_+*8Y;+>Gny3vxU_^rvR8+fO+S)-PPQvUlr9tAJ+xbpO{V*MF*@pU+T1@G-I*-an0=h{n7Ln*V~o;~hhBvJFQm+~%~&}GED>7U3mUPG)_KP) zAH>H0#C@v}12x9wiMv;W$bk~%L=T4lBI*zJCbuBHX9Oe(HZ&D#lmp^>5W@e|)E>>gbV zX8!V$)=FN~fR&%`>##G*NZ}Bmk7D1>4o5rY-r?YL!9+14&h*k*9G4oa(ibDqp5Ix; zfAhS}Dcc#m-K4L%Y=p~eFrS}ew@+Ihrmu;~vxYO+)U3hs^<$zgmw^&aSAg5y3x*GN NZx3Jhf=?p${1ePE;a30v literal 0 HcmV?d00001 diff --git a/public/avatar.png b/public/avatar.png new file mode 100644 index 0000000000000000000000000000000000000000..f88478ec9d0384765f97a194e72d51e09df5e759 GIT binary patch literal 14245 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 bC$|3pjW literal 0 HcmV?d00001 diff --git a/public/calendar.png b/public/calendar.png new file mode 100644 index 0000000000000000000000000000000000000000..c8088040ea181c4bc28837cb6c1da8f359bbd71e GIT binary patch literal 1952 zcmeAS@N?(olHy`uVBq!ia0vp^8X(NU1|)m_?Z^dEoCO|{#S9F5M?jcysy3fA0|U#O z%#etZ2wxwoOKk;IU`}m2j;n@l3HZGe}M}G*2&MIQzJ7|OG6Vwb4ybT zU<5&}0ZU?N3CS-_&H#DK&Iqm&A%;+nBbrfz3uYB+uu>_a3y`uED3-zb6%@Zf31Ivh zqr@*z%*wH}BqP7b&d0?Dqy)xA^AhC=5Liy2q&~R2DiRAY(j8E-6*!IL7lq{K=h!(X z=9MKXXauF^rKA?67HQh(qpQH@URVKyrUqCPA*Eq`cu{6o_`6Dzfq^N?)5S5QV$R#? z_8G!~GRN&T%|i-S1gtROyrXuMZ|bbe+ifT2IjIX4Uie$G^X9{tuBIcJ#jh_MbX-!h z^~W5!Z;B}w4xVgQ+3I|dN7jht)q~Jm)5|>{=r+OvAE)aL7Lr)QsBA$Z_W$4%}7uQVJKBsNbkkc@0-4SdMxohb62 zY5Lk9ToV}XDsC-q;5TtUbK>&r8_e(CW|uzCF%kIWyL{@Nw_7HkdHA$zf6%&L{ol7% z8TRP;uXi}%FV}FU%tz^9hHCA z%n6b>s@_`_Bb9uiHEZLeYWBBJ?o1bQ`{ZmVsHACYB^V|kMZBL#z z2ln6YeE);t_R9S+>walZyZ`&bt*ZRPBF}WnRtBUOPFvPc`7}x>%jw>sD4_=zGQKK* z4VU~QU!1b#*SufX8!J!Sn?=?7{>?rRdiuTO+I>ANYd9_CIeuO``1fqaS0070Z*Ms- zzIymd{X2#i(rd2;{ny;^W=7%tjM5S_gS(IR%wl>L`j9a;+D4q?XZOMDXO6qs#xZj& z{$bucy)kXE-2EK|4vRytXOw0}1TL0~|9M{_QtOYu4eOcJnh9~Dau=9?C5rr?W8%^F atDb@J%hN@>*yry8)uEoQelF{r5}E)Z6|)uq literal 0 HcmV?d00001 diff --git a/public/class.png b/public/class.png new file mode 100644 index 0000000000000000000000000000000000000000..e4dc30a662aca5577ce93786505101b150ddb84a GIT binary patch literal 2182 zcmeAS@N?(olHy`uVBq!ia0vp^8X(NU1|)m_?Z^dEoCO|{#S9F5M?jcysy3fA0|U#O z%#etZ2wxwoOKk;IU`}m2j;n@l3HZG)p$Kv@o*J zO-?d5)ip6pP1Ut9F*4IlNlG+NOg1z!F-T2>n+4H=VUk-C&>&MIQzJ7|OG6Vwb4ybT z1GpZrB!-rd{LD}d0{0E;4|G^`IV%ItVF%6v3nyqmkTBVpqM4(`R3P3%!I8;>6NeONBS#bcsUtLvo4Giy)Uy)R5@t%<$&e((L7 z$uobRJtOse&el}!IY+%V=x86@w1(yMCbkEjU!^_>1w^hp$Lw|>G2_enZ0YEO)qUD| zy0Ww)IHMj0sVKVEWe4qBZ7zRD2zp37-p2^lsehpdg=B&PY z)D@^y(@ecI)Ol(vD@G_5@`= zrE2Tmw;LuTWPHhAc(GsHW6y-SZ?An$EsoKc{UEUT9cyv>jmcg=f@*E``7Rj$x_jY; zeYeRY&#ztjq1gwu51)&x*6w|~U_ye>O+}&I9tNF$>d^=8H^i!(sQ7N-y3RrB_GF-O z)~?a(uex5H{!00{=z8X6l}+rni}U?oNiMut?!5TE-Yk9ZmzEK$yR#NcN*ot`Z~SjM z8_@Hnvksc479Va>{IaCz(<9H6_vx>v>R&B&P?u1p4DcO2A&+_em%*86>`;=kV@3-&1@<*v3IDLTmpqsG; zOWc{W-2QED|3iVUeiO+5_tl&mAI~hdGv4jGR&P~L`NDeLCG#%kGku-2<*?1polTiJ z?wL8IaXHiGUA+G@C^s*MHC}b&U#5ufOMlfU{c!#U44LGFZOz=8r4DPa9u3|XGM}mT zxaf76@R->xY!3IQze*FjdHV9zKL%5Ta!i`fH)N%+|J(GqOYm{9rDsZi1JLh(-g%d9 z-F^RFWS7E*nJ#7Ky=#4wxeF$A&SkK-T6crRi&Ktyy4v?i#_dX-Z}ysOyF4ktw`kjP zp4tbOzO<`fHGZN$De{`6{+?#9^Dq2sR_^=0)XL_y_Jfd_KlOppclwW!@#($i;(oiS zn*5rsvdQ0ioyH~ONhi`yALKZp%P-7!vjXU#V{@EpyDnsKtG+)vFXX)1#I2R;i49S) zYnWeW=E(m#_xb;h9rM$}no=VbP0l+XkKs4p1+ literal 0 HcmV?d00001 diff --git a/public/close.png b/public/close.png new file mode 100644 index 0000000000000000000000000000000000000000..47e597f9303c3a1bcf62831c56a409e378ae43e7 GIT binary patch literal 1049 zcmV+!1m^pRP)Px&(@8`@R9J<*m_bM!R~W~C@4cNGtgeS{yW*h~+EY*}i5j7%Ob=;jinrz@lqy6- z*jtnk3O+((K?8*>En-M51u66@xfBYM!+KEAKrbG0$SG8k=CI0cw(HL8p|gvwv+K;x zY<|bx_jZ1K^WS;jH{$yB-_^T)dlyK!69Ur0WussfHhx}OI^Yd5H9z0oS?(M+l5qq3 z9Le<;&;Qy{_LYGlq1@jDd;#<$`O-ZAnmiS8<;j0_q5is zU2ZiIO4vSIltRl60nv^GPAU#YySy#e1+pU=F*V;*eGJnWYEmXGPjP) zof5>W3=Fv!{3fR_8oz=A=~RslP4_LG4G!gVE^aZU+FogwOpn#mJ_am)~YM9E}LFs>P*5v^uY z5%Ubuj8-zKrsn6nt%|h(OvaJ9vj~yNu7S%VIrYiNm9LQ80p9le!KnS5AAvF{`1q}g zwI_{ayzb3rm6Cu5sU$Pmtj@+l_I>sr0IQ0biqtUVzq8^NDcD*DCqy`BF6DC38j Tq#AWJ00000NkvXXu0mjfFS`JC literal 0 HcmV?d00001 diff --git a/public/create.png b/public/create.png new file mode 100644 index 0000000000000000000000000000000000000000..0fb69e831373863ee645d7dc9a0fd1720045c138 GIT binary patch literal 1595 zcmb_cTWHfz7|!mq=oFcXPG&_U8I7}toUV~HiOH$Wbb^X_ zK_B$ND=PTn)21Tg>Vr71;EN(&9(?ja^hFsCL{Sk>vMsiq`k)3*lJo!H|DFGK{zJVz zU2|+pY#4^k35S9a^ldU$Z8dry`JT_9&nzXhQNyshd&Vj|zN)SP!z$ki(HM-a>t>R2 z#=-G&0yy-Hg3uV|(;4)e0g$un8Bx+0-H)3H2K^gi5)atyQ;$#OQ%oe-IR!;KKc0qA zVMsEU%Q?0NLCq!PEcD~J zg_?AUPg=()SyeO-;gci~K?X=rBPj<}_O=)`M*&5|j-?p>V1OqJs+X;}M|ASv3g?TVRTCjS4sj z_yFys-GsA^peP?%qOz*!n^LURVVDn4Uf`nI=mgOMQmurWbEb#{pL7#0PYZCR+`!%D zby-}KCNr2i6Ntz|d*~LAmvU3BUQe6TvN4r2Orml&nKr@-&=&Hi>?iy;WiC$Fbg0E? z{ZEBf3a*t=W%Iro^+gI)Usq9mk&I!pFfFTr?x4?rOm9m<`u7GzbE2sGEWdP4nbCI$ z%$PkQt5I1N18X>GJ7;f-0Eq`GP@8>ZDdJE5P7k0G3>rlRJxp4oEO5tJ_Ye)YkKrI2 z)z7{^N!jkS*H__Nx#skR+`MZO^ENLZId>fYP~P~UA{NszmTg!b3)$GiVy#UWTAjbY ztTuf8)NJnXE#h5h&-#31m5_M7xOZRn?#{X+ySo>RM%j4xf-e1h|G|;+hPxGgzTW%R zYvq@*p8Tig&Wl@4KO4ST`L-;-vi|A#{>OukYBhcgTNMBN_7wBz$@uLSrRq)eE45IK zZ)`lXBRz1i`O5eHO=UZ8->A7daT$zlIQo27`}WRTHU0v2bk3RCL;a!Q^11aDsc_>9 o{^i2?ugaG0S*+BY7<<(5t@=QhU9XfzYmD(8UfUDA)DhqN15-`l>;M1& literal 0 HcmV?d00001 diff --git a/public/date.png b/public/date.png new file mode 100644 index 0000000000000000000000000000000000000000..4a8c6a12f2e2460ff427cd97123f2960e19f7f64 GIT binary patch literal 1129 zcmV-v1eW`WP)Px(BS}O-R9J=0m`jXQMHGg=?w+9sgkeGkaEOiwMrFcVT@b?3xX^`B6G$`|0x<@H ztXS|0D_9T`0&I-&k;sAtAs`Pmf{!4O00vM)0;m{30t``JGtfQV)0fR(lS9#c>vngr z=T9otxBjZrr>ah!bE+VWk-%=?7%)0P|B$S2fTKW1ow5cn0k{j~fv!4bJqg?fBH-mD z1JVilq*MSh_31Yt&(^VM3h){ANtynkF-iZgS)~N@ClxRZm6&RR3T_3SHWQo!>?zal2Jn$nEG;{m11!)MTO0uHnePJdT~d4T zuwUaH?gQVJ>DLad(T)XvHM?3}&19fYKJW-|9eAli-*#ZB`xpy! zSJ;-jzy}gE1DGo%YuVy|fqB3*$y*q(=aa~NbO4uQd|VIkyG~t~?6p?h1kPyZrT`;i z`d$V)0mjwoIv!WKLc&PWPz-tnZRqKfE4a}>eUP2cavxT~yqxu^#^^PGMK;s13cAqN zW7?X$*jUs=0EQ^oJLJXtT%_G8%4-ZU{~KwXO&0pBwxP`ARp1Tt{kKA026)eNv|lO8 zWP!JV*+z+7z>h!+uml)yCbd(JyCR&Mxm_lS+~OVmb863)iK83DwE^2aZiOb*4xIIp zk>%chE>?RYH{&OjaY<$<0jLT#HVzt9j z)j8m26FMW{H`O`W+_U2HNxVj!4Z2h3ie2$^43{zO%>mBe;)iT7w1Sa;>{9?+dYHtG8nf4RFd~rj8RfanbysQ6e1->xcA>hq81wt!0-Sc&=sxwNL zEH_1UR+k^kbsCeH1-zj49PoUc0)swT81xE;ws?n$y#VJ`7l7@GEbbKUR^6-6c3s~k z;IIxxFR&SyC@u#a3@I7sW*UL2+)RruRStJ_uRt-^-UPcP*ykePKQBwF3UMpAS~GFw z2emf?pL?7O`XiKAT5d@d4^LIC;8;z-p;vWUA<%MTRAaPvPQ zWx{5^Q?R5<^-x{TEsEZ^3sL2=m7?L|vY9vxm*Z}7ccYY+|1;nnC6lihgYMKzfWuXV zsFWhdGlu&WxTHyUnT(~R%lgFxO3svv>QpFQjRd}~(-{Fj0ncegGvXg-$pBAiQm3WE zHTQyU2lC7Zn!lk%$GD3#00000NkvXXu0mjfYsvy} literal 0 HcmV?d00001 diff --git a/public/delete.png b/public/delete.png new file mode 100644 index 0000000000000000000000000000000000000000..ec67e8c70b2bbabf693457528aa6126a1cefdb18 GIT binary patch literal 2011 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 literal 0 HcmV?d00001 diff --git a/public/home.png b/public/home.png new file mode 100644 index 0000000000000000000000000000000000000000..e5a6e99c0d1100ff02fe7377ee994517e5158a5e GIT binary patch literal 2334 zcmeAS@N?(olHy`uVBq!ia0vp^8X(NU1|)m_?Z^dEoCO|{#S9F5M?jcysy3fA0|U$J z%#etZ2wxwo^Wa<(N{8R68M1X+-k|;7X7uor^*npJ4xM*IYJOKiW36#_acUMJX0YUyHa=khKi4RO{}cd z9~CNQY;9jE>Afg4=IezO+L7g3S#&N7hE@D{#%meEc~WkP&ZC9;*&Va<{*~T!uAAOs zzTaN{-jnm*d_H+{AByhv!VNa$=etE-0=e7gFd?aaBI?}eK8sTMx(-uK;0 zB4nSc)mqI}W{X$cy13=759c|%+$-7j?==mqpYQYM`PFu0Z|s-7=CiK@H7j4t3=P~W z$>2U|S*b@s*bDZX#s&*7e-uAICpIMHt!k%r^q0Nmw>|?^8ee=_>Uwn^Yk@^()McT{ z&wY%-R7>)J@&bu4lfWAnEP+hiYT@NA(yuFai04VHzAf;*lO;K zvpc6Vrl`Ctx%gf0O_(^_)Cn)XRJ&d+V&GHreeHSh=2N%5+bm5M9I53zz_>xvqI%(r z>iH$X+7tJCKe;S4Q*ch~E4Io7+;^7T+3BwGF6H9)uw6&Dew{Vz?9OloAEp}`PxkuA zY>dwjFTO21WrsFHAHxdHbADgDnH${pmN^%EbG@`>6GO(OE%U_Z)ZSZh{of1885dq2 z-fUSec|fEgOYyz!zI{=(_-e(;U3tDw`B+>E20;q}bXCe9DhHaz#Jg z%Vb#1aE#IB`W~}ulgj&Rc)kl=@3BaVZrUu$;Bouh-m_mfo>Q%se{{e1X4zZq2Ywsh zH$H9_S)TLU;$mi-#Fu}3nzOT?URw3wO_I#UwRLG8+cWQe^fy0P!zFFX5Ou4}Y*+4%FumOW75DcYef?BOe9m0P3%QGV58gaf)xKGQ y;fUaG?}Be44f8jges^+*qD8fT!L}PQKiI!)S!sG%CUgO)1>@=J=d#Wzp$Pz#{c0Kj literal 0 HcmV?d00001 diff --git a/public/lesson.png b/public/lesson.png new file mode 100644 index 0000000000000000000000000000000000000000..6009636670821a5cfce40c1abee227572521d171 GIT binary patch literal 2336 zcmeAS@N?(olHy`uVBq!ia0vp^8X(NU1|)m_?Z^dEoCO|{#S9F5M?jcysy3fA0|U#O z%#etZ2wxwoOKk;IU`}m2j;n@l3I^uuL+tFt;?* zHApcv(ltpnFwjj*GBDCjG*2@&G%`psGB>h>n+4H=VUk-C&>&MIQzJ7|OG6Vwb4ybT z1GpZrB!-rd{LD}d0{0E;4|G^`IV%IrR_u(-{@zGGW>zKE<7Hdr~xX8_Q07c<`=;onOi%<--I=^{R>IdsF7-@c%vB zDDb`ZkHy{Z)$cQv(z`Sd3vnOdJT~7?v*fXVn4w{?s>)ts9)5#yNX8xLI?q|Uey-MziiGjg`jh+i%oROZU z!Tdc-bo(8y(l2)coxe_+o^@@*5&s4TyIInMQM`Lw$m;_sA}{)*7hbErcW{p8IjLzC+RAPAv-gGHXU{8I_hb#Dao~dW z=C%3Rg)8^4&FN#R-5pnIuHb6irn*Eo)Kd9?^>2oEw}NUp_wfCRTfghRSl2n54~!o+ zJgg3{Hh;(1!xWqQ;O|7i2W6+q*CloVb**E*y|wFiV%)0f$wy11_Lc7weRcdd(>5nr zAWCDoG2fl{{_k7UPA&gEFP7!jwvh6dTF)jgdvEI_Ci7~-6|Hxn(W{~loYc5r{wnl) z-29}l-`SVio>U$d(oZ>Z#WRm9XQduvKJ#p#8H?f#GkGtyr5v1=1#+eD{n_jtf6JP0 zEG(IH_kyCR@^Fo!ZfV%rKbJpi7-6BN?tqR&35^Yzid9z(|)u@ z7_JRiUioR|o1dMZgZ3tSo7M-cnEJG6<@cM@Ua4{J*VUW)ep0|0g}*?Tt17Jid@}oh z-`-d2fFWlp)Frva@mA1tvk!IBQ+3k2BzL*re0y~1CuRr6w{7oZS(g1MKW{FRpnc`- z-#I2eJl9wzeQJa2FeQy81AbbqmjA9L=5vcum$X`g<&C$ZD~5vQC*ruSW7 za(%QQ#P|MZ#zhYK*O|uXR?0sJ=fT-`D)%zcGE`|C1Ib2b?bMbP6}V9cb{wsX(Klby2bEy{kFb zwchPa3|n>h2LHFie~o?qMlia!Hox=U&F%Bt{RZ>0qXtKF9u?Fn?2vn4Rd8_Hsk1@` z=R67+ge`-8fQge~&kRM01CKQ>?BC|J);;qROO5mdKI;Vst0K~Cc A>;M1& literal 0 HcmV?d00001 diff --git a/public/logo.png b/public/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..e90915b2a70b96826a415f7fe4279569df187e51 GIT binary patch literal 11011 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 literal 0 HcmV?d00001 diff --git a/public/logout.png b/public/logout.png new file mode 100644 index 0000000000000000000000000000000000000000..c52aef64ced80613741d43cf678059bc6f7fc749 GIT binary patch literal 2588 zcmb_ec~n#B6@QUMmH}L-MHVN37|_Y~WJ@NAEMb*h)=|`uyg+Iek~~Oo%^(a8n*~(l zfFLMnQDhlG5d?;{2th0dI-Z<5!l=Lqog4wFh|(8C1Z?|9+jri2@9+M;yM6b(?*sfi z^mL4M007YQ@}vhLPixhsrHS0r-{0jS5A9gb2r&TYx2rDH`Ca-Z0H8j>2@Z$DeSOGG z0T0Ju38EmJloyMj0e~VUBdd{~Sp;)tufWHHGw2j)U+9Czlz zYb0EbDiSi6!H=e5q*xZjX2fw}3@wDeXwO2kATcMJkH(^jAO)}Tkjq&?u_#&1ivJgD zFTz%Y`d?IBubrYYeGwViIS!5yh-f}^iVE`ab4^J9djleKVpaDo`z2+>e%5ygn7r5{0#UF)z@@n| z`0)(1br8g7K_W!b-dJ5yl@jNyF1)XuYIyt4 zH9D5T;n~T(&R1KvY2E?tA};Jak`XXGK3|;T=92Gf;6~})yIWr7l@nibNUQg){5N0P z)abjD&9h%8FVy?ZfHtMoQ}nWQYuLDDGhi(<7v9s9sr@u<+VrA+UQxq)XH2@heITj4 z`py}bIMiUq&ce3e%M*oHdJ-<7tn&2BjT>AH=WsImSg>A8`KWSzVb20kwQJ%uy)62S zOBad&oSxCPQjjC-DpLLibSf_Sa3%`Mt05pdnPbp0naw-#3+Z@=xO-(!?rmCY1uw0-@NGpWY(~Ax?t9_FHfWGm1)xk&}uj7UD^eiO@^yF%gL7MkFrCfKO`_dOUGD8d;^N^?Qa5p4d zWri8_R0MV-nIsBW{p?5W{aV-suR3L9Q%Ft47y1#lLVyXNy~_&E{pF|avOi^JPR^Lg za@&Pq&VT@S;^+xnrh7)%%jf0UJ{}<%6~%#pMdxs(Kg^vDk8XZ#p<~w3-8NWBHSvnFEl^*Qg zo>$oYZ2Fk_KqyhrIM&d(MNR2sboOo5>~^m*W?n&4VrO*COA=*&<<%%F#Wxjd+b$Sb zCYkg;n_frXp$0r0uFTiC(wAf;`>jJ*U_Jf(G~29q?gd2`2)R3N~v zPDZo2G`I&Kdwvn_5$KV;Dcaa3-;{iE8(6Vr$~`{1Va~HW z1Lf3R_l5eT&UNFr^z3nAtK0rk+xXClW514cG-l02HYpzL(FB@$B-E5a}(tEe(rnI(iGl) z6->N-aLSa%+>-vKrHoRe*?RiY_)gImKT~uP zRX1ti4f?V~bJ31Q0rjJ?ZQ}Zfx{4x&+@CXHV=-_$<|sdv?-nK)_B0zh*NH>IHgc*N z5B{B#+x)Mome%>5!m8o=uwIjECvwC5O$q7`f-~-GJ`G7CUo#7K?VoN8tgEQaeA0!w zxfk}khAIfNb2oo&XP#iC5CQYgNXI9uzS_9;@SYj`gNqLx!4_(^>i^Bl&5wS|<#6IZ E0pCX2)Bpeg literal 0 HcmV?d00001 diff --git a/public/mail.png b/public/mail.png new file mode 100644 index 0000000000000000000000000000000000000000..3b8f8579a0f0609299cd1ed14edbe0dbd13b5a71 GIT binary patch literal 830 zcmV-E1Ht@>P)Px%_(?=TR9J=W*IS5`br{F-&p1m;(gD{ZR<LI<7arH{Nzsm*xme2DsjN41!EtSpSLp+1uVGZiI1S6QpqNVUjypMh? zLmzyG%~*kzA^&j+;C{gixB$y>Cq98wIEw9oT!DvhWD((xVhHEr96XZqPeUV%{>F<5 zZ5=n^+eLu;0UOa14Gv?x^!y*d!r#GV0qw^J(MG$$rZ9>tbJiN{YO-z);3@3G&57j2 zcok!9ggcJcO9{FGdvLM}U;%juTN3tFcsv`QE!>}Y5*KCfyYR(4aPtBdK7l841wGhw zmXPDA7(J=C+oJteziA0rK)#YXS;O`C6w?a;o5q1$Wi8Qrz5-k&z?p3HHm=D5Yw=cu zUL_eu@?y0l#Tz(L@#QK37P|Z#w?;dCc&>$ZX0rFosRp$~aCCvuuMAlDuec|WbvzK^ zH;ejEslE;3r~jeb1pzkF8aI@hdp*KGl;;h6jr&V*a>XC#COQH*fj2Rb>sptV)E~%O z@E-OiT0Kdut++9j;BxF(fc`229>=pO+RM_KMsv0Ma6_WhpDt7+(jNSQ{b~Mn^x|n8 zYZu@NJX*T0+oHqrny=D%idk|!4$fLLhI>o0*gB7PD+4xgxYSL0@mPz#{5>ATefVac zHPd*i)J5*Vm;a&5rhro!9M>l*SKze@g>|aJU@;jTUR~1iyDfe<2XG2I169LS5q>)- z?a53@Yjeh>2|zQ*e*vDxOC`On!_RF5o9$znJ0PYGi_gQuO_HHgklQlq zOW{9K3Y?Rf{qIiXE=)=3WaMW1Z<*#-hhY#OC3%eC+B{gDiTbZage!bJg}yIkXaKv* z|3?SXt`-|?wjaiIMNKV|VPy*Nf%sC}Aihf>?^@To*0oOB8GoS->J9!Zwg3PC07*qo IM6N<$g1?V|{r~^~ literal 0 HcmV?d00001 diff --git a/public/maleFemale.png b/public/maleFemale.png new file mode 100644 index 0000000000000000000000000000000000000000..fbf1b5b17a5673749ab321feba405b6f6b1af108 GIT binary patch literal 7606 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 CBeC58 literal 0 HcmV?d00001 diff --git a/public/moreDark.png b/public/moreDark.png new file mode 100644 index 0000000000000000000000000000000000000000..0ae4c35e5141cef180ba1c3fb9da91403584f612 GIT binary patch literal 2016 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 literal 0 HcmV?d00001 diff --git a/public/parent.png b/public/parent.png new file mode 100644 index 0000000000000000000000000000000000000000..56ddf9c9dd2cb79124caa24b402a087f1f33d4d3 GIT binary patch literal 2759 zcmb_ed0bOh7JdO_3ur5&#Ktypflx3jYhnnyf`Ta!1jQf;d4WJSUjhUKgpOEIJFY~K z)v7EihzlrC7(}gQ5hRRfW1wiFEj8p8sXpWM&G zofae!5jZ>v7bGY|QWy;YbOjB56@hXNRv{9KWi*8?ZWcj<-&JNJj-iYFc+nvqpXTMf z=_3^Wvc-kS6e5L!hY@&LlvvJD;Kj0aaHNHyoIzO- zB#_Dl5;0a4n!}ZZ%WZMEIn;-gctLZ^NW&rF>>|7%A}9n!pja*=k_qGmS@MEta)De3 zE=t@%C|_g|3RIQQgdB0OElz>wfqYK5P>y5xh-dwISRN=71dFkFESX9tsxlM`=7pHG zER0J07i-VL=9T(icELd|hXmZYPKad$&a5R|)jk5uERn-g^@6mZ7azQ64m{bs#8s7e zgL@WP;BKfUq#Q^FvZAD*EzS#+Ny4EZaJ~dS26TczjvVAMC?tvno@4{xbmF3^ITq<3 zCtMVAHy(p)P2!PBd=j2&&b7u{P%J?_$HJ0?=aQ{0I220@D~lk@xmX`uK8v)83kR~K zSW>JksbmYXHPzCFH0Lur`I!q#5*`$yDvLpxL;hj=1O9JlUf8Zrr7mpi|A}bnyltgo zd3L|5_=P86e$5x~3)^T8;qnj(#Bg_}t012~7nStC3lKgh7N~D7F9k>XneJdPZB`=^ zh$WE-8BQE=1P5#41&Vnf1VZ1^iHi~cDc?^A&>{?c6wT8xaqcK%GuW=Rvd!>i)jR=Q^D{9z(7*!_VWt$LFG2{L5Y^T`FjKo>cmreHeS*#AFv{%a^QS zr}N5^gT)73T=0lX%8f797PQ6t8WspWO#2-ibxr?Vj%I$LQ_4t(@|Lv^j1y{%27O`% zFxBGzss4`L5tWmCH_%(nKG{3?Y-sHnzPRWiV6Bl! zvq^qHk1U2T~y{#6DExf3w6Q-;4B8T3Mb;}M7aHGQa48JTf_THc4&Fj;}L zOWe8xQ^Z*Q=rPi1X<}5kVKH~+70c@SwByxLZ}-!-L+^U;C%^{t&JgY3i^)6A);(S4 zDbjvhz}gVgJt33`*7*@){^!LYiJ@73yc*xi5XZ_Xz5-R7(-MccIT-qb;}7hgO?TU8Fq4VFI)^_#2kR1fbsN^tiUsQOy@hikNK2)BZgtqRU-9WF&YA zoZjSyY^YH7&s1T5MQSKmlDeX%=OMEdNSxuj`|_y6rMDTH zms4u_5e+Oeec#Lj@#@Ohhh;Nw$)QHQe?#7L%wN^!n0zP^lSugM5$9shKydxVF3!%0 z=+LmgKMb4dZB0{7=at@$!wewl#n$^8YOD^o7S$hl?G}r?tIiZXa6iwyiL~CGbi6Nx z)E9=|)nC0_p68S9a$Qk%?Iy6Nhjmj5z;ZKq%Xt4JPyecVdakB0P02=eoQ$^3smnQ8eEe*Q+jvWGSGCcm6X?V>%pU>=;bzsA zH`qn3ZU(Oi+I2X;s#kg6IagB*YitVrsD4x8POY4w+>&i8nlBLaq7FTI^``B&JNX%7 z&j6S*RkH4X$(5)#cD&6qC7nMvmUPC)J}d4}_a3P}@IrG}1bfNPyFQKS5rpCEy!#X9XP!6N z)oeVzGA{1I7`H&(cJs1a0w?qaX2W+Ko^=FZ=vD7ip9=rz>aV7o M%Qoji$H4D@2XL)7hyVZp literal 0 HcmV?d00001 diff --git a/public/phone.png b/public/phone.png new file mode 100644 index 0000000000000000000000000000000000000000..f2d4135bce7ac31c9613ddacda5e1393cf3be73a GIT binary patch literal 370 zcmV-&0ge8NP)Px$EJ;K`R9J=Wm|+gWAPj}y@L=1~=E;zg=^ttkm9=HGnD~;$WRdaFc2EkuYXh(Y zhyd={Vt(eXy@0AMdc(yA9NA_K74q-yF*#Qo!*gz74l{d>#L2zV%q4*{|4;(sKefyO zZ^AL_AeN8%2@h&y1{nY(tI0Idcu<QIVX#IK2CWB)j&$ZO&yEV7RD_ixRCXNsh!dV+-ikL zAUW?LVDU%Dg=~RJ-l58K=>#>X22Q;1YP_&3$CV~h?_|RPA#67FTGU>e764bx>V!&{ zj==<)2A(RXIblR@4k=3N=DW%E(gUmAnx0xLNOO*sdAb(Qk@K0Zw=Y-R2VNM60>lZ} QIRF3v07*qoM6N<$f_#Udj{pDw literal 0 HcmV?d00001 diff --git a/public/profile.png b/public/profile.png new file mode 100644 index 0000000000000000000000000000000000000000..2de2d7a5e780fa51b3a206072efaf201ea5846c3 GIT binary patch literal 3201 zcmb_fc~n#95)V5Go2`n9Qqm%YRzec?Tp>u=LBIx3ARr0k27=j0ZeECpfE9~Xqaa4G zxV4BPpezl+va3Z=Fg%fhf`BCoMp48AR1xV7S}OFt_s4rL=X|;MoB7RrGxM8o&bfOx z1^F1DOi%~}!obhhlLSAlR7+PI{@?$$h6O*6T;B*j0%3SnwbYKRGhB^8Xg+0xhC|_j z8-X|u%Z5th#DX@-EG~>jAY76G_>~1hRCF?n$>syeu9kBM0Df1Av6e&>`u)#^N23EI zPw)3oc;{-F06|;;ixmomHbOfa4lf>yClCl&oGsSY76T(Nd=VR>CS%xqbJ){DSDqk0 zj>q6a3=SKua!rlp2q0HW%X!qhkZ5u9$8ZHa=G-B)I4sBnSs)wYWAQfl1yR!C0EhuG z!9{_)GoeKiCPS48z@)O{T`iL_G>}deFd<7~7<{~yGS+9 zqRV@QS2E;BBii8{oSbMhDuzx6@fdp$PshaC(?N`*JxFk(+c^@P9clBv-kJQ(lXooa z$iddZ*3p50x5qmX9Gr3UHgn3qnS^o#aS5ulh_>^{zhr;G{|(Ix%k^if3(NX{BAWZb zwNkM>cVAWf!U~vQy9NBhGQeE`C2)Aejh-$l$e-IqDgEya2+xTH-8UasGL`$czJtNQ zT#s;gp&SmA=s{)wgNn8yfovMc19@M#U>76)Q@no;phXyX6n)Uc*!fXL%&*h^Cjz0f z-p|uLG`T>Umz1@v+w_`S#8KX|6j_?$;KP3X)J^VJko6?akZ0%qGbAs@^QPLO&|YNV zULJBy^`>5{g5pmfo3VDE@C*q!+x69@$RV1jWqac5>QSz|e;NbS5%aU(JxH5Y|;pgkX*--84zg^FpGCFn6 zTq+|?&gKwrN==aDpls``)QG_rqo5ObqSxRL;yZZL;Llr4^g+WCKxINg+-ML0(^qH zD?mECy5jsr`WC%!o&Y3bhdJ|7Nk|{u3s7N@y6B4Mt<_BFEz3mfwdDJl7+1%1_4$9QcTrcXwl^V165q9nU9jErHc1^M3!H-vsby zxBrTe;_|fU8O=FE4OPdEi>g1$b09_>v8fYm^A}HRkNx6*cUH7Qtt0#ONPb3hMSsI( zrvUL2b^O>#?1XVcIh8W@DjWY?4j0aKZ5U&Cl&qIudkW4kK)fE=ck?jR672-{;{A^7 z@!c4?2D>#Wx?p))R(DpFywUi+=68%@vfz`l!cVW6u5@!I#0^GD6W&TJn4+C9&25K< z3?XD*@T`NVyyN2e2VXxwds)Ic+W?Rn#9iM4BtF9}{@#o`wKbZat$%clP*$!u4M!W; zavHUvu1HanVlY^I#H7WsMwp37L-uuMZy&myc_V@4SksZ!6))pp`us-O1CceI@DAob z0Oo3Yik@)$G-_aEbluY>66-s|!=L>8!?$Z>R?Js+gPm)*SNhDJBBmsa&hG(IFWkT* ziLC7<@C_`@o%s=#WE7P@ygGJnYO{_k_n~)?kJ1F@q{=9x7tTmGymU|VE&sblK!&u0 zH2F>9%BPyfnHVDj!ZX>HD%KaDbn_Ul%d7k9b1M9*Ls}k4BUiQw^p2i4*5(7Gi)!%9 zNR+O{GB0W5C{Eaw<)}NthI^LpZ}ho+Bc?bvb@uBAr2LgtO~BG=BCPSIEIpM-#U0h? z$OiP#*020)JzA5dG~iZlzm^#gX7J6ApHJQ#mG8DlW9IF^%}^ZlgAUnCrl&ECGc7Zc zC_SdOv7m65rB*^LMxETg@^P{xA}gQ^=PcDvnA8l}Aitg`iy~)YoN^Sk=$qfQf4TGt z>X1_$g3|H~e}KE)wjQCO`>SX97;wA+-?k0ntt zyuN)+k?=f#XIV_DT)H04NtY|8#iWeP8s_c)TJu)ejknp8!$t_lSb>m!Z?++0sZtZ`S{%a}pa+dM&aRp4)ol22|nRiJ!%Hbb!rOk6sTvW=M($VzeDm0c=MBv0bex1)g&^O@h(iNuvr7KCNt e6IlxCYqKu{ecd`Eeb}mx1V67J&kJ8scKreOfh)xT literal 0 HcmV?d00001 diff --git a/public/result.png b/public/result.png new file mode 100644 index 0000000000000000000000000000000000000000..40bf74cd8ae36a6c6c497f644b085abfca237e60 GIT binary patch literal 2320 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 literal 0 HcmV?d00001 diff --git a/public/singleBranch.png b/public/singleBranch.png new file mode 100644 index 0000000000000000000000000000000000000000..b9d843192f85bb3831f27dec55ab50f68d61c47d GIT binary patch literal 2992 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 literal 0 HcmV?d00001 diff --git a/public/singleLesson.png b/public/singleLesson.png new file mode 100644 index 0000000000000000000000000000000000000000..0d3de8a24c4e25f4bb6ff2732809f39a8e7d37f7 GIT binary patch literal 2646 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 Ef;OKk;IU`}m2j;n@l3HZG&D|1u{284 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 literal 0 HcmV?d00001 diff --git a/public/subject.png b/public/subject.png new file mode 100644 index 0000000000000000000000000000000000000000..d33a7472adcb984fc49e866135d41e07f1adeb1f GIT binary patch literal 2308 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 literal 0 HcmV?d00001 diff --git a/public/update.png b/public/update.png new file mode 100644 index 0000000000000000000000000000000000000000..bb6685bbefba9b85307b6cdbb249893754fec514 GIT binary patch literal 1122 zcmV-o1fBbdP)Px(97#k$R9J<@m`i9~RTPH5lg6eoG{z)K1VcJ#YzaD2sR~-Ph*X4H9cZb8;sZg& zVG%*pDk2qUqE<&18y)DRR1ob86zf1mgjN(R_MtV2O@p!4=Jh#QM|W@TGxsK0u*tdS ztiAK?wf=q1+B;*BOuYzL4qOZ@1*U;>z@J%`{j*qHsF~WUKB0c9o>phnv+6hMHuY+? zX|VwN)DP8hi`%4nP`yFTvJ!(d1O33YKo?NdFR^35-Ym<;E5LODdw}bKCBO`@8~6@b z4Qv2fOJaL>Qspt7PATUu~KP?w60JOh5w9tQe9u*w?;jljQe0Zz<~O0 zjbOQrtB*$Hi@^=3dy=t_s`r-gU!SCZU+&NkyaKF`(4Pgq1P%eifE7}F1~`yq*;J8d zeZY3$ju;zY95@~;x6r-@eh3*{huW%ck2I-{sGHR;wMA{JqLtEeSERKtE0gMe^@ze4-qYfq$cpmlJ`0=~i-vGcB0e3#eJ*jR~TjF`MdUrtP>Hb8$E8wQ%{tfcGYyX%B2)ZCc5ws5s3ksL}ON8_*RaIAwRB;ou_?VKZ6srTI43jJ^)b|w@2NVFbrP+*C4>Mnk&<+@RC8OR z1e@htGvHh`7k#_c9ZBR)&q`}OfDO>xjwIreVwg?5N&Ryrh_PmcW5 z!SuwT2{;kgz3B^bfvqzd5wJh<2Tj1|aoq>pw9sVn9Ue$N0wciD)L~sxZTvLXt!Ev8 z9qLEPNyBr64wtIC6NiIpzq)ju!J5^})VGoXUjh($ literal 0 HcmV?d00001 diff --git a/public/upload.png b/public/upload.png new file mode 100644 index 0000000000000000000000000000000000000000..61a8a9147c4d168eb43a350950e29165ccfc5cb5 GIT binary patch literal 650 zcmV;50(Jd~P)Px%L`g(JR9J=WS39zsKoIO%`Aq&qZ*>D7!HyvjrCg(2g%e)v@=3Icp36Rg4`arG z*wuoOm|dvnz;q;0?9j}odjM9fSn&{)d$8QImESmYQS9hV0!M^PQ!~FR!D7efKuX{M zfHpV+0NNW_LH7dJ2OV>WCJ`+6Y^BB76Qd1|&57N^GZnKZnnO}eFeXO^+bLpqi3;5F z7v5^mZPdX9U%RY*P9+BbKVF=B_rVefpWeQ=_UCu^O><6_!J=XTfajXChsq;0lSUH| zUH{A_2LMgY41oi|mU|wb{uF`&9C9b{9{j`ynaU;Tv$r&w6FY4dCo>3NmW2^?a{>B`wYx5gwvB zu_J>mq8TuAog&VDe0>hdSR;eX%GlvYO1R&t3op?`D>%ACQtO@-RS&rtR z+K2i3wYpgB_#FQ?h?YnJ4rRrhGkJ4S?%DdU#d!bht?;qkK&g#!Hj9d7*qc*T2`bWk z#txU`-m=it%w@&lppdFB?-J;&>v0Uflqf%AXQ8NAhCMVFSvvTd`2PsTKDq?{TKQ)| k=p&5$S~TX075^B20HW4qXvZ9jH~;_u07*qoM6N<$g5-K9bN~PV literal 0 HcmV?d00001 diff --git a/public/view.png b/public/view.png new file mode 100644 index 0000000000000000000000000000000000000000..6acc995740f14231e25907b453a81d0412210677 GIT binary patch literal 2635 zcmb_edpwl+8lP%LICMdENE*>+BxB6D&KOfdZn?xLq%oKGolC~dH1iHa9l5lu9dR%u zJ34GhBw@=E)e+g$x@;;FYMYMw9E;WAps3@_s4UuZ{y1mf&*!~8&-eNMp6B~K@9*=b z2l{*JY8z?8U@%>8FZUqT-9mk8YN)Om|EiBx-LwQ=VIml8O{@A`k+*ZrW*7`U!Xbx3 zp?>=a41TmV4dBy3Ye}>~g@(b15`yY68iZ&_Ni>%yB1l|N^9X|KS#8FkNZQDc2T=$x z2|@0AKSEV+E+{qx2?!WWY;3G`tgSU)$iiUpcs#}ihr!{{Dg;^-$Af4RG*4uvVp>Y& z4vH8;jsW8Dc}O)ijm{TCE-2Ij>O)EZV__MASje4U1Ylr5E*K5+AQ1*@ja`x@z#u>z zhzl-D+?5M0vv4`;N(fvUkL7}rpaGCc6LTRHDTFs44)tB*zIr7gP`^;){h0aPbIyBy~RkEc&r`P5pVBgvk)`y{49jb7cQY&Mr$!4FeOBr& z&wsD#{;C|R{@O0-ugXSn6+>*kkhIU8sD^xcT~^ZnKY*%zV#)L^X76prLKAto_ zYo45x7-P|}Ub}F+tA)oe4T{jtw*2Xumrf3U4?tRxE_6JUJx{ARzeW4}T~r91fkxH5 z6#vvct9juMaW=B*u;AkdI|H61)wOD*4z*_JM-th^mHP)s~>hM!1!ZxOcYAHAtypy(9 z45Q+l?MBw>{0&h#y+5aVe|Dt@F4ts?(UL1V%m%ERze+yVk@(d;%GKUSgNDYM?6^C6 zn|)baZ=uO4^LG(lMx^fi?^#-_Zorxg^#=ImLyW#~%9IXYR1jh?P;QxjxERHo`D~Na}$^5j95Mbw_^ItC3c3jA<-v`4L<- zob;R$3_d%iXpa~ARGTZO5A4S4MnyVH$1S7na|SM78k!?So2EScvk#J;wkijKQmvUIu{XM%1bR@VLe?c=K< z!Sbw*(sgYbCNX*mQ4Mm;&SrnNe_T9QbH0aj&XSWi;E{e*>kzs0yBpOeYYrn`ZE&M2 z+Z$flOct*DrJtCgOC>^G^@6J{XH1XXNKP@CijSWW zILl<(!kFTx{rX(8K{mXBQWQ7H9yH>w4}UhAcJ777sN12~n0U|7h>)_Hmu$OLBlYfDy>ie! z%*(Xiu%q`%f|6YI`sCV3JM)7Xcdy;!8cbdDFwtQ~a>?dO$xN8q=Q z7Ci6hMh4J*QDQ$N!ueFpY$d#0pvo-FRf1N~a#5P8q@L&I|yuCcJ`?3F_Oenv(r;3?# z|I!e$tEI6-=|-57ty49h``CPPH!>*T;i_h)-+1wcecwM#Qw(Mj5}iZZulGu)uQU6k zwshqIkJ=&eY)c94yWzc=S-b!G{=jZV=JatnD*qOty)@lSaCV}7blU#Jv9q1^LsY6n z>6bQU*8V>K8>snAx_DxON-gMhtrW+SelRVAzk5J76s}IO!dtAX+~k6H$bVYZS%k}m zQm^_X*UC4zvAB5S!ic0svfjYuu2!vxsey>(=N0_M5?s!ZokNpF;3FwA$KR$>_H9(_ zL{!)t5O)z`YP(KBqTNQ4cm(e-uAXWeFd3*S~ JSM8xD{~HA+_vios literal 0 HcmV?d00001 diff --git a/scripts/seed-data.json b/scripts/seed-data.json new file mode 100644 index 0000000..a7be1a1 --- /dev/null +++ b/scripts/seed-data.json @@ -0,0 +1,142 @@ +{ + "teacherMap": { + "1": "user_3AJAkSqshofbdPsW7lZh6q2eCe5", + "2": "user_3AJAkVye7wKBBK8seog6gljyc7L", + "3": "user_3AJAkXA9lrOHxsGcJNoJGOXKNOr", + "4": "user_3AJAkc3f42kZzVPLvaRBFHor14J", + "5": "user_3AJAkbsXvHmZcGu3wFpRZm732LX", + "6": "user_3AJAke4rOtbf26yRM9JoHhtEjyD", + "7": "user_3AJAklVf8Pnm2pH6Ql1PnfQBIID", + "8": "user_3AJAki8tuWw9rWvZZD9xIP6CxVp", + "9": "user_3AJAkn3ET3kFyUrx636ayvHrLds", + "10": "user_3AJAkuiTMWimGNBtw7ymHVUqwVW", + "11": "user_3AJAkvjGTDDsscx7g9dD998d6Gq", + "12": "user_3AJAkr08HMjIKMG1Guzw3HJqB9L", + "13": "user_3AJAl1xiX1ZtMg0ohV7QB2TpHm5", + "14": "user_3AJAl1tyuI5t3DfmleToHAw6HgJ", + "15": "user_3AJAl3Rr5gq7K1W0fhl6AVNFXrY" + }, + "parentMap": { + "1": "user_3AJAl6KD5fVP5MbjDZLpyoZ7sDG", + "2": "user_3AJAl9gkapHVzn5Tik7RteIEJVZ", + "3": "user_3AJAl5BLWwfpho7phY16SrCleE8", + "4": "user_3AJAl7BN77L27mpmHzjCp96OlFx", + "5": "user_3AJAlFko0fvXyleuRuyqmGkpgTV", + "6": "user_3AJAlEyIdgY7vVA7yZQUbTwimOC", + "7": "user_3AJAlIlHOwSpcR92ENGiHrz0nCg", + "8": "user_3AJAlKekpw2nrtGnnMBvN0xdh3c", + "9": "user_3AJAlLmCzuvKoqh9yh2ulnmz26h", + "10": "user_3AJAlPbUuestp7PvH2BuX2GQK6R", + "11": "user_3AJAlWR17pNYP0S24hiNnUKI2R1", + "12": "user_3AJAlWTNINh2uIOEueR8dPKXjlc", + "13": "user_3AJAlUx3a2u65hTIoxWLjmDnDuj", + "14": "user_3AJAlac7l5vhi9lbnvuOIEZ2zoz", + "15": "user_3AJAldy0F23q4Jm8kz8olXdoao0", + "16": "user_3AJAlekANUdcMJeZ34EFcCjluAq", + "17": "user_3AJAllI3cBBjs5JbcUimhrLEYvf", + "18": "user_3AJAlp8YJPzQwvcutFoCsHAz3Sn", + "19": "user_3AJAllVI1vR6vwSPlLPCyIb9oZB", + "20": "user_3AJAlwjmMMnvV9la8fFlH7TYuOS", + "21": "user_3AJAlxGYIRJnKZmvkt2HB9ukrlC", + "22": "user_3AJAltSwlQoPrRGcsAZcJpH2sH9", + "23": "user_3AJAlvcnUE4GGbYKK0odLUjwxqu", + "24": "user_3AJAm16YficrMn5CeAOCAxV8iu1", + "25": "user_3AJAlxj9Z9gE4EIwQ5pljEywIV0" + }, + "studentMap": { + "1": "user_3AJAm7o0RjL16Gt1jE9YLG0tib7", + "2": "user_3AJAm9SoYdWl5sQfbf8slNI2Qn4", + "3": "user_3AJAm8NIt39YG9DPjnAwq2G2V3G", + "4": "user_3AJAm5KPpNLvz8DjwNU6MRCBO5e", + "5": "user_3AJAmGDojjfnVtn7LrmLVemoCiM", + "6": "user_3AJAmDK9jVHWfe3FjdR7emQ329K", + "7": "user_3AJAmMNLtdeplBIS9kwXYW0FC9Z", + "8": "user_3AJAmNXiIZz0FYILKDOZxq1ET56", + "9": "user_3AJAmMeKtN7oMMrLgcxIEWsm0EV", + "10": "user_3AJAmQsp9Xg8LDpxCkkmccjDCuU", + "11": "user_3AJAmZtzvmAwwu7QJRvIpxZCNYF", + "12": "user_3AJAmXM1fL4b0fONRdM5uIRIxBS", + "13": "user_3AJAmi4pxmDtV24YaIaNmmack33", + "14": "user_3AJAmf864NjSUdQ6ExiMR3zaDCn", + "15": "user_3AJAmbZArRtgzFrBdW77qbd7P1z", + "16": "user_3AJAmpWu9wzc4ve2kwTKPLveFST", + "17": "user_3AJAmoVVKEmMeE8GMd7A2fgn5nY", + "18": "user_3AJAmlYITikQW1km45TqvQ2biBm", + "19": "user_3AJAmuEU2s2CLT9391jnj6Uxb3e", + "20": "user_3AJAmwfQjhHcnd6Y2HGvXWTxTj8", + "21": "user_3AJAmxavPXIvafOo84MWRqKPyRN", + "22": "user_3AJAmxtksJ1U2UjHoP1wzXgk3JB", + "23": "user_3AJAn3gfMCCyfaFrX0yY69XfQfQ", + "24": "user_3AJAn1UL8HJe9pfcZboyDCqg4Zd", + "25": "user_3AJAn4fAYAtcYCLKv1fBkBJSyxw", + "26": "user_3AJAnBlPYjZBRY7HrMaY95WRQ59", + "27": "user_3AJAnD31sahtYeq9Zfzu867VgB8", + "28": "user_3AJAnK8qcNr259cZnIKpH4ZuoRH", + "29": "user_3AJAnECM3SCOTVaHQvwaIkV1YnJ", + "30": "user_3AJAnH4sNG5lbNwuvYHmmbU9J3U", + "31": "user_3AJAnRjFXzyoALI4egtIvZEUFuA", + "32": "user_3AJAnYhwtMvevCuQScoLSJePp79", + "33": "user_3AJAnXQkG2mOAFxFm1lHaOV2aJQ", + "34": "user_3AJAnYU4Frx0bX863nwBE9EJaGH", + "35": "user_3AJAncF3uP2xfkU6WixizrfSSrl", + "36": "user_3AJAngPagGao0QCe5AcGeeGGpDS", + "37": "user_3AJAnazAi3ERTCfqVQr7jDtTOK4", + "38": "user_3AJAnoJnVGxwohyI3ot6cwnZ6iO", + "39": "user_3AJAnoCbmMiBBlXE3PvUN1vg3CT", + "40": "user_3AJAniemPzyyEwPSZZ2h7iXK9lV", + "41": "user_3AJAnvqsElaS1dwqPtmhw4N7dCS", + "42": "user_3AJAnqp0r30RwkxKEJK3nrPJcwR", + "43": "user_3AJAnsBcWHQQGYCpKxLbfWpSWdE", + "44": "user_3AJAnrDUy5R1iFD1Vsb8FNlDO1I", + "45": "user_3AJAo1kdbtoIYYx3gvEcr3D9WT8", + "46": "user_3AJAo0CALCnqJle4D4JGt5VNqHJ", + "47": "user_3AJAo1fZPiFTp8U0NYaprnET0Ls", + "48": "user_3AJAoB35YG2oZHKLvT4UFBQVBqj", + "49": "user_3AJAoDZ1nOyp3f3KO2Lefzgi6Ah", + "50": "user_3AJAo6si4CGdeQ3teM04nPmrJe2" + }, + "classes": [ + { + "id": 1, + "name": "1A", + "gradeId": 1, + "capacity": 20, + "supervisorId": "user_3AJAkSqshofbdPsW7lZh6q2eCe5" + }, + { + "id": 2, + "name": "2A", + "gradeId": 2, + "capacity": 20, + "supervisorId": "user_3AJAkVye7wKBBK8seog6gljyc7L" + }, + { + "id": 3, + "name": "3A", + "gradeId": 3, + "capacity": 20, + "supervisorId": "user_3AJAkXA9lrOHxsGcJNoJGOXKNOr" + }, + { + "id": 4, + "name": "4A", + "gradeId": 4, + "capacity": 20, + "supervisorId": "user_3AJAkc3f42kZzVPLvaRBFHor14J" + }, + { + "id": 5, + "name": "5A", + "gradeId": 5, + "capacity": 20, + "supervisorId": "user_3AJAkbsXvHmZcGu3wFpRZm732LX" + }, + { + "id": 6, + "name": "6A", + "gradeId": 6, + "capacity": 20, + "supervisorId": "user_3AJAkSqshofbdPsW7lZh6q2eCe5" + } + ] +} \ No newline at end of file diff --git a/scripts/seed.ts b/scripts/seed.ts new file mode 100644 index 0000000..7ce4464 --- /dev/null +++ b/scripts/seed.ts @@ -0,0 +1,261 @@ +import "dotenv/config"; +import { createClient } from "@supabase/supabase-js"; +import { clerkClient } from "@clerk/nextjs/server"; +import * as fs from "fs"; +import * as path from "path"; + +const supabase = createClient( + process.env.NEXT_PUBLIC_SUPABASE_URL!, + "sb_secret_N7UND0UgjKTVK-Uodkm0Hg_xSvEMPvz", + { auth: { persistSession: false } } +); + +const PASSWORD = "&%5C400l&%"; + +async function cleanClerk() { + console.log("Cleaning up old Clerk users..."); + const clerk = clerkClient(); + const users = await clerk.users.getUserList({ limit: 500 }); + for (const user of users.data) { + if ( + user.publicMetadata.role === "teacher" || + user.publicMetadata.role === "student" || + user.publicMetadata.role === "parent" + ) { + await clerk.users.deleteUser(user.id); + } + } +} + +async function cleanSupabase() { + console.log("Cleaning up Supabase tables..."); + const tables = [ + "Result", "Assignment", "Exam", "Attendance", "Event", "Announcement", + "Lesson", "TeacherSubject", "Student", "Teacher", "Parent", "Class", "Subject", "Grade" + ]; + for (const table of tables) { + await supabase.from(table).delete().neq("id", "0" as any); + } +} + +async function seedAdmin() { + console.log("Syncing Admin..."); + const clerk = clerkClient(); + const users = await clerk.users.getUserList({ limit: 100 }); + const adminUser = users.data.find(u => u.username === "admin" || u.emailAddresses[0]?.emailAddress?.includes("admin")); + + if (adminUser) { + await supabase.from("Admin").upsert({ id: adminUser.id, username: adminUser.username || "admin" }); + console.log(`Synced Admin ID: ${adminUser.id}`); + } +} + +async function main() { + try { + const clerk = clerkClient(); + await cleanClerk(); + await cleanSupabase(); + await seedAdmin(); + + console.log("Seeding Grades and Subjects..."); + const grades = [1, 2, 3, 4, 5, 6].map((level) => ({ id: level, level })); + await supabase.from("Grade").insert(grades); + + const subjectsArray = [ + { id: 1, name: "Mathematics" }, + { id: 2, name: "Science" }, + { id: 3, name: "English" }, + { id: 4, name: "History" }, + { id: 5, name: "Geography" }, + { id: 6, name: "Physics" }, + { id: 7, name: "Chemistry" }, + { id: 8, name: "Biology" }, + { id: 9, name: "Computer Science" }, + { id: 10, name: "Art" }, + ]; + await supabase.from("Subject").insert(subjectsArray); + + console.log("Creating 15 Teachers..."); + const teacherMap: Record = {}; + for (let i = 1; i <= 15; i++) { + const user = await clerk.users.createUser({ + username: `teacher${i}`, + password: PASSWORD, + firstName: `TName${i}`, + lastName: `TSurname${i}`, + publicMetadata: { role: "teacher" } + }); + teacherMap[i] = user.id; + + await supabase.from("Teacher").insert({ + id: user.id, + username: `teacher${i}`, + name: `TName${i}`, + surname: `TSurname${i}`, + email: `teacher${i}@example.com`, + phone: `123-456-789${i}`, + address: `Address${i}`, + bloodType: "A+", + sex: i % 2 === 0 ? "MALE" : "FEMALE", + birthday: "1996-02-27T00:26:35.280Z" + }); + + await supabase.from("TeacherSubject").insert([ + { subjectId: (i % 10) + 1, teacherId: user.id, isPrimary: true }, + { subjectId: ((i + 1) % 10) + 1, teacherId: user.id } + ]); + } + + console.log("Creating 6 Classes..."); + const classesArray = [ + { id: 1, name: "1A", gradeId: 1, capacity: 20, supervisorId: teacherMap[1] }, + { id: 2, name: "2A", gradeId: 2, capacity: 20, supervisorId: teacherMap[2] }, + { id: 3, name: "3A", gradeId: 3, capacity: 20, supervisorId: teacherMap[3] }, + { id: 4, name: "4A", gradeId: 4, capacity: 20, supervisorId: teacherMap[4] }, + { id: 5, name: "5A", gradeId: 5, capacity: 20, supervisorId: teacherMap[5] }, + { id: 6, name: "6A", gradeId: 6, capacity: 20, supervisorId: teacherMap[1] }, + ]; + await supabase.from("Class").insert(classesArray); + + console.log("Creating 25 Parents..."); + const parentMap: Record = {}; + for (let i = 1; i <= 25; i++) { + const user = await clerk.users.createUser({ + username: `parent${i}`, + password: PASSWORD, + firstName: `PName${i}`, + lastName: `PSurname${i}`, + publicMetadata: { role: "parent" } + }); + parentMap[i] = user.id; + + await supabase.from("Parent").insert({ + id: user.id, + username: `parent${i}`, + name: `PName${i}`, + surname: `PSurname${i}`, + email: `parent${i}@example.com`, + phone: `123-456-789${i}`, + address: `Address${i}` + }); + } + + console.log("Creating 50 Students..."); + const studentMap: Record = {}; + for (let i = 1; i <= 50; i++) { + const user = await clerk.users.createUser({ + username: `student${i}`, + password: PASSWORD, + firstName: `SName${i}`, + lastName: `SSurname${i}`, + publicMetadata: { role: "student" } + }); + studentMap[i] = user.id; + + const classInfo = classesArray[(i % 6)]; + await supabase.from("Student").insert({ + id: user.id, + username: `student${i}`, + name: `SName${i}`, + surname: `SSurname${i}`, + email: `student${i}@example.com`, + phone: `987-654-321${i}`, + address: `Address${i}`, + bloodType: "O-", + sex: i % 2 === 0 ? "MALE" : "FEMALE", + parentId: parentMap[(i % 25) + 1], + gradeId: classInfo.gradeId, + classId: classInfo.id, + birthday: "2016-02-27T00:26:35.281Z" + }); + } + + console.log("Exporting User IDs to seed-data.json..."); + const seedDataPath = path.join(process.cwd(), "scripts", "seed-data.json"); + const seedData = { + teacherMap, + parentMap, + studentMap, + classes: classesArray + }; + fs.writeFileSync(seedDataPath, JSON.stringify(seedData, null, 2)); + + console.log("User generation complete! Saved to seed-data.json."); + + /* + const daysOfWeek: ("MONDAY" | "TUESDAY" | "WEDNESDAY" | "THURSDAY" | "FRIDAY")[] = ["MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY"]; + for (let i = 1; i <= 30; i++) { + const classIndex = i % 6; + const classInfo = classesArray[classIndex]; + + const teacherIndex = (i % 15) + 1; + const teacherId = teacherMap[teacherIndex]; + const subjectId = (teacherIndex % 10) + 1; + + // Distribute across 5 days (Monday to Friday) + const dayIndex = i % 5; + const dayName = daysOfWeek[dayIndex]; + + // Distribute across 6 periods (e.g., 8:00 AM to 2:00 PM) + const periodIndex = (i % 6); + + // Base date (a Monday): 2026-02-23T00:00:00.000Z + const lessonDate = new Date("2026-02-23T00:00:00.000Z"); + lessonDate.setDate(lessonDate.getDate() + dayIndex); + + // Create start time and end time (1 hour lesson) + const startHour = 8 + periodIndex; + const startTime = new Date(lessonDate); + startTime.setUTCHours(startHour, 0, 0, 0); + + const endTime = new Date(lessonDate); + endTime.setUTCHours(startHour + 1, 0, 0, 0); + + await supabase.from("Lesson").insert({ + id: i, + name: `Lesson${i}`, + day: dayName, + startTime: startTime.toISOString(), + endTime: endTime.toISOString(), + subjectId: subjectId, + classId: classInfo.id, + teacherId: teacherId + }); + + await supabase.from("Exam").insert({ + id: i, + title: `Exam ${i}`, + startTime: startTime.toISOString(), + endTime: endTime.toISOString(), + lessonId: i + }); + + await supabase.from("Assignment").insert({ + id: i, + title: `Assignment ${i}`, + startDate: startTime.toISOString(), + dueDate: new Date(startTime.getTime() + 7 * 24 * 60 * 60 * 1000).toISOString(), // Due in 7 days + lessonId: i + }); + + // Result requires a student from the class 'classIndex'. + // Student 'j' is in class 'j % 6'. + const studentBase = classIndex === 0 ? 6 : classIndex; + const studentIndex = studentBase + 6 * (i % 8); // Ensures variation 1-48 + + await supabase.from("Result").insert({ + id: i, + score: 90 + (i % 10), + studentId: studentMap[studentIndex], + examId: i + }); + } + + */ + + } catch (err) { + console.error("Seed error:", err); + } +} + +main(); diff --git a/scripts/seed_schedule.ts b/scripts/seed_schedule.ts new file mode 100644 index 0000000..c3dfa98 --- /dev/null +++ b/scripts/seed_schedule.ts @@ -0,0 +1,226 @@ +import "dotenv/config"; +import { createClient } from "@supabase/supabase-js"; +import * as fs from "fs"; +import * as path from "path"; + +const supabase = createClient( + process.env.NEXT_PUBLIC_SUPABASE_URL!, + "sb_secret_N7UND0UgjKTVK-Uodkm0Hg_xSvEMPvz", + { auth: { persistSession: false } } +); + +const SUBJECTS: Record = { + Math: 1, + Science: 2, + English: 3, + History: 4, + Art: 5, + Music: 6, + PE: 7, + Computer: 8, + Geography: 9, + Biology: 10 +}; + +// ------------------------------------------------------------- +// CONFIGURATION: Adjust the timeline spread and generation odds +// ------------------------------------------------------------- +const CONFIG = { + monthsPast: 3, // How many months backward to generate lessons + monthsFuture: 9, // How many months forward to generate lessons + baseDate: new Date("2026-02-23T00:00:00.000Z"), // "Present" date + examProbability: 0.05, // 5% chance of an Exam per lesson + assignmentProbability: 0.1, // 10% chance of an Assignment per lesson + attendanceProbability: 0.95, // 95% attendance rate for past lessons +}; + +// Helper to chunk large arrays for Supabase batch inserts +function chunkArray(array: T[], size: number): T[][] { + const chunks = []; + for (let i = 0; i < array.length; i += size) { + chunks.push(array.slice(i, i + size)); + } + return chunks; +} + +async function insertInChunks(table: string, data: any[]) { + if (data.length === 0) return; + console.log(`Inserting ${data.length} records into ${table}...`); + const chunks = chunkArray(data, 1000); + for (let i = 0; i < chunks.length; i++) { + const chunk = chunks[i]; + const { error } = await supabase.from(table).insert(chunk); + if (error) { + console.error(`Error inserting into ${table} (chunk ${i}):`, error); + } + } +} + +async function main() { + try { + console.log("Loading user IDs from seed-data.json..."); + const seedDataPath = path.join(process.cwd(), "scripts", "seed-data.json"); + if (!fs.existsSync(seedDataPath)) { + throw new Error("seed-data.json not found! Please run `npm run seed:users` first."); + } + const data = JSON.parse(fs.readFileSync(seedDataPath, "utf-8")); + const { teacherMap, studentMap, classes } = data; + + console.log("Cleaning old Schedule & Attendance data..."); + const tablesToClean = ["Attendance", "Result", "Assignment", "Exam", "Lesson"]; + for (const table of tablesToClean) { + await supabase.from(table).delete().neq("id", "0" as any); + } + + console.log(`Building full year timetable...`); + console.log(`- Past months: ${CONFIG.monthsPast}`); + console.log(`- Future months: ${CONFIG.monthsFuture}`); + + const days = ["MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY"]; + const periods = [8, 9, 10, 11, 13, 14]; // Expanded periods (8 AM - 2 PM, skipping 12 PM lunch) + + let lessonIdCounter = 1; + let examIdCounter = 1; + let assignmentIdCounter = 1; + let resultIdCounter = 1; + let attendanceIdCounter = 1; + + const lessonsData = []; + const examsData = []; + const assignmentsData = []; + const resultsData = []; + const attendancesData = []; + + // Compute start of generation (aligned to a Monday) + const startDate = new Date(CONFIG.baseDate); + startDate.setMonth(startDate.getMonth() - CONFIG.monthsPast); + const startDayOfWeek = startDate.getDay(); + const daysToMonday = startDayOfWeek === 0 ? -6 : 1 - startDayOfWeek; + startDate.setDate(startDate.getDate() + daysToMonday); + + // Compute end of generation + const endDate = new Date(CONFIG.baseDate); + endDate.setMonth(endDate.getMonth() + CONFIG.monthsFuture); + + let currentWeekStart = new Date(startDate); + + while (currentWeekStart < endDate) { + for (let classIndex = 0; classIndex < classes.length; classIndex++) { + const classInfo = classes[classIndex]; + + // Gather students belonging to this class based on seed logic + const studentList: string[] = []; + for (let i = 1; i <= 50; i++) { + const studentBase = classIndex === 0 ? 6 : classIndex; + const studentIdx = studentBase + 6 * (i % 8); + if (studentMap[studentIdx] && !studentList.includes(studentMap[studentIdx])) { + studentList.push(studentMap[studentIdx]); + } + } + + for (let dayOffset = 0; dayOffset < days.length; dayOffset++) { + const dayName = days[dayOffset]; + const currentDate = new Date(currentWeekStart); + currentDate.setDate(currentDate.getDate() + dayOffset); + + for (let period = 0; period < periods.length; period++) { + const startHour = periods[period]; + + const subjectIdx = (classIndex + dayOffset + period) % 10; + const subjectKey = Object.keys(SUBJECTS)[subjectIdx]; + const subjectId = SUBJECTS[subjectKey]; + const teacherId = teacherMap[subjectId]; // Authorized teacher + + const startTime = new Date(currentDate); + startTime.setUTCHours(startHour, 0, 0, 0); + + const endTime = new Date(currentDate); + endTime.setUTCHours(startHour + 1, 0, 0, 0); + + // 1. Insert Lesson + lessonsData.push({ + id: lessonIdCounter, + name: `${classInfo.name} ${subjectKey} (${dayName})`, + day: dayName, + startTime: startTime.toISOString(), + endTime: endTime.toISOString(), + subjectId: subjectId, + classId: classInfo.id, + teacherId: teacherId + }); + + // 2. Insert Exam / Results (Random Probability) + if (Math.random() < CONFIG.examProbability) { + examsData.push({ + id: examIdCounter, + title: `${subjectKey} Assessment`, + startTime: startTime.toISOString(), + endTime: endTime.toISOString(), + lessonId: lessonIdCounter + }); + + // Only give results to a subset to prevent table explosions + for (const sId of studentList.slice(0, 4)) { + resultsData.push({ + id: resultIdCounter++, + score: 60 + Math.floor(Math.random() * 41), // 60-100 + studentId: sId, + examId: examIdCounter + }); + } + examIdCounter++; + } + + // 3. Insert Assignment + if (Math.random() < CONFIG.assignmentProbability) { + assignmentsData.push({ + id: assignmentIdCounter++, + title: `${subjectKey} Practice`, + startDate: startTime.toISOString(), + dueDate: new Date(startTime.getTime() + 7 * 24 * 60 * 60 * 1000).toISOString(), + lessonId: lessonIdCounter + }); + } + + // 4. Insert Attendance (ONLY for dates occurring in the past) + if (startTime < CONFIG.baseDate) { + for (const sId of studentList) { + attendancesData.push({ + id: attendanceIdCounter++, + date: startTime.toISOString(), + present: Math.random() < CONFIG.attendanceProbability, + studentId: sId, + lessonId: lessonIdCounter + }); + } + } + + lessonIdCounter++; + } + } + } + + // Advance to the next week safely + currentWeekStart.setDate(currentWeekStart.getDate() + 7); + } + + // Send payload in bulk batches to Supabase to prevent network/memory bottlenecks + await insertInChunks("Lesson", lessonsData); + await insertInChunks("Exam", examsData); + await insertInChunks("Assignment", assignmentsData); + await insertInChunks("Result", resultsData); + await insertInChunks("Attendance", attendancesData); + + console.log(`\n✅ Timeline successfully generated!`); + console.log(`- Lessons: ${lessonsData.length}`); + console.log(`- Exams: ${examsData.length}`); + console.log(`- Assignments: ${assignmentsData.length}`); + console.log(`- Results: ${resultsData.length}`); + console.log(`- Attendance Records: ${attendancesData.length}`); + + } catch (err) { + console.error("Schedule Seeding Failed:", err); + } +} + +main(); diff --git a/scripts/test.ts b/scripts/test.ts new file mode 100644 index 0000000..47d4a6c --- /dev/null +++ b/scripts/test.ts @@ -0,0 +1,17 @@ +import { createClient } from "@supabase/supabase-js"; +import dotenv from "dotenv"; +dotenv.config({ path: ".env" }); + +const supabase = createClient( + process.env.NEXT_PUBLIC_SUPABASE_URL!, + "sb_secret_N7UND0UgjKTVK-Uodkm0Hg_xSvEMPvz", + { auth: { persistSession: false } } +); + +async function test() { + const { data, error } = await supabase.from("Admin").select("*"); + console.log("Admins:", data); + console.log("Error:", error); +} + +test(); diff --git a/src/app/(dashboard)/admin/page.tsx b/src/app/(dashboard)/admin/page.tsx new file mode 100644 index 0000000..5f8bd7d --- /dev/null +++ b/src/app/(dashboard)/admin/page.tsx @@ -0,0 +1,49 @@ +import Announcements from "@/components/Announcements"; +import AttendanceChartContainer from "@/components/AttendanceChartContainer"; +import CountChartContainer from "@/components/CountChartContainer"; +import EventCalendarContainer from "@/components/EventCalendarContainer"; +import FinanceChart from "@/components/FinanceChart"; +import UserCard from "@/components/UserCard"; + +const AdminPage = ({ + searchParams, +}: { + searchParams: { [keys: string]: string | undefined }; +}) => { + return ( +
+ {/* LEFT */} +
+ {/* USER CARDS */} +
+ + + + +
+ {/* MIDDLE CHARTS */} +
+ {/* COUNT CHART */} +
+ +
+ {/* ATTENDANCE CHART */} +
+ +
+
+ {/* BOTTOM CHART */} +
+ +
+
+ {/* RIGHT */} +
+ + +
+
+ ); +}; + +export default AdminPage; diff --git a/src/app/(dashboard)/layout.tsx b/src/app/(dashboard)/layout.tsx new file mode 100644 index 0000000..e2ee6e2 --- /dev/null +++ b/src/app/(dashboard)/layout.tsx @@ -0,0 +1,31 @@ +import Menu from "@/components/Menu"; +import Navbar from "@/components/Navbar"; +import Image from "next/image"; +import Link from "next/link"; + +export default function DashboardLayout({ + children, +}: Readonly<{ + children: React.ReactNode; +}>) { + return ( +
+ {/* LEFT */} +
+ + logo + SchooLama + + +
+ {/* RIGHT */} +
+ + {children} +
+
+ ); +} diff --git a/src/app/(dashboard)/list/announcements/page.tsx b/src/app/(dashboard)/list/announcements/page.tsx new file mode 100644 index 0000000..b8556ee --- /dev/null +++ b/src/app/(dashboard)/list/announcements/page.tsx @@ -0,0 +1,138 @@ +import FormContainer from "@/components/FormContainer"; +import Pagination from "@/components/Pagination"; +import Table from "@/components/Table"; +import TableSearch from "@/components/TableSearch"; +import { getSupabaseClient } from "@/lib/supabase"; +import { ITEM_PER_PAGE } from "@/lib/settings"; +import { Tables } from "@/types/supabase"; +import Image from "next/image"; +import { auth } from "@clerk/nextjs/server"; + + +type AnnouncementList = Tables<"Announcement"> & { class: Tables<"Class"> | null }; +const AnnouncementListPage = async ({ + searchParams, +}: { + searchParams: { [key: string]: string | undefined }; +}) => { + + const { userId, sessionClaims } = auth(); + const role = (sessionClaims?.metadata as { role?: string })?.role; + const currentUserId = userId; + + const columns = [ + { + header: "Title", + accessor: "title", + }, + { + header: "Class", + accessor: "class", + }, + { + header: "Date", + accessor: "date", + className: "hidden md:table-cell", + }, + ...(role === "admin" + ? [ + { + header: "Actions", + accessor: "action", + }, + ] + : []), + ]; + + const renderRow = (item: AnnouncementList) => ( + + {item.title} + {item.class?.name || "-"} + + {new Intl.DateTimeFormat("en-US").format(new Date(item.date))} + + +
+ {role === "admin" && ( + <> + + + + )} +
+ + + ); + const { page, ...queryParams } = searchParams; + + const p = page ? parseInt(page) : 1; + const supabase = await getSupabaseClient(); + + // URL PARAMS CONDITION + let query = supabase + .from("Announcement") + .select("*, class:Class(*)", { count: "exact" }); + + if (queryParams) { + for (const [key, value] of Object.entries(queryParams)) { + if (value !== undefined) { + switch (key) { + case "search": + query = query.ilike("title", `%${value}%`); + break; + default: + break; + } + } + } + } + + // ROLE CONDITIONS + // Authorization is now handled by Supabase Postgres RLS policies. + // The initialized `supabase` client automatically passes the Clerk user JWT. + + // PAGINATION + query = query.range(ITEM_PER_PAGE * (p - 1), ITEM_PER_PAGE * p - 1); + + const { data: rawData, count, error } = await query; + + if (error) { + console.error("Error fetching announcements from Supabase:", error); + } + + const data = (rawData || []) as unknown as AnnouncementList[]; + + return ( +
+ {/* TOP */} +
+

+ All Announcements +

+
+ +
+ + + {role === "admin" && ( + + )} +
+
+
+ {/* LIST */} + + {/* PAGINATION */} + + + ); +}; + +export default AnnouncementListPage; diff --git a/src/app/(dashboard)/list/assignments/page.tsx b/src/app/(dashboard)/list/assignments/page.tsx new file mode 100644 index 0000000..294cd5a --- /dev/null +++ b/src/app/(dashboard)/list/assignments/page.tsx @@ -0,0 +1,162 @@ +import FormContainer from "@/components/FormContainer"; +import Pagination from "@/components/Pagination"; +import Table from "@/components/Table"; +import TableSearch from "@/components/TableSearch"; +import { getSupabaseClient } from "@/lib/supabase"; +import { ITEM_PER_PAGE } from "@/lib/settings"; +import { Tables } from "@/types/supabase"; +import Image from "next/image"; +import { auth } from "@clerk/nextjs/server"; + +type AssignmentList = Tables<"Assignment"> & { + lesson: Tables<"Lesson"> & { + subject: Tables<"Subject">; + class: Tables<"Class">; + teacher: Tables<"Teacher">; + }; +}; + +const AssignmentListPage = async ({ + searchParams, +}: { + searchParams: { [key: string]: string | undefined }; +}) => { + + const { userId, sessionClaims } = auth(); + const role = (sessionClaims?.metadata as { role?: string })?.role; + const currentUserId = userId; + + + const columns = [ + { + header: "Subject Name", + accessor: "name", + }, + { + header: "Class", + accessor: "class", + }, + { + header: "Teacher", + accessor: "teacher", + className: "hidden md:table-cell", + }, + { + header: "Due Date", + accessor: "dueDate", + className: "hidden md:table-cell", + }, + ...(role === "admin" || role === "teacher" + ? [ + { + header: "Actions", + accessor: "action", + }, + ] + : []), + ]; + + const renderRow = (item: AssignmentList) => ( + + + + + + + + ); + + const { page, ...queryParams } = searchParams; + + const p = page ? parseInt(page) : 1; + const supabase = await getSupabaseClient(); + + // URL PARAMS CONDITION + let query = supabase + .from("Assignment") + .select( + "*, lesson:Lesson!inner(*, subject:Subject(*), class:Class(*), teacher:Teacher(*))", + { count: "exact" } + ); + + if (queryParams) { + for (const [key, value] of Object.entries(queryParams)) { + if (value !== undefined) { + switch (key) { + case "classId": + query = query.eq("lesson.classId", parseInt(value)); + break; + case "teacherId": + query = query.eq("lesson.teacherId", value); + break; + case "search": + query = query.ilike("lesson.subject.name", `%${value}%`); + break; + default: + break; + } + } + } + } + + // ROLE CONDITIONS + // Authorization is now handled by Supabase Postgres RLS policies. + + // PAGINATION + query = query.range(ITEM_PER_PAGE * (p - 1), ITEM_PER_PAGE * p - 1); + + const { data: rawData, count, error } = await query; + + if (error) { + console.error("Error fetching assignments from Supabase:", error); + } + + const data = (rawData || []) as unknown as AssignmentList[]; + return ( +
+ {/* TOP */} +
+

+ All Assignments +

+
+ +
+ + + {role === "admin" || + (role === "teacher" && ( + + ))} +
+
+
+ {/* LIST */} +
{item.lesson?.subject?.name || "-"}{item.lesson?.class?.name || "-"} + {item.lesson?.teacher ? item.lesson.teacher.name + " " + item.lesson.teacher.surname : "-"} + + {new Intl.DateTimeFormat("en-US").format(new Date(item.dueDate))} + +
+ {(role === "admin" || role === "teacher") && ( + <> + + + + )} +
+
+ {/* PAGINATION */} + + + ); +}; + +export default AssignmentListPage; diff --git a/src/app/(dashboard)/list/classes/page.tsx b/src/app/(dashboard)/list/classes/page.tsx new file mode 100644 index 0000000..2ec1c53 --- /dev/null +++ b/src/app/(dashboard)/list/classes/page.tsx @@ -0,0 +1,141 @@ +import FormContainer from "@/components/FormContainer"; +import Pagination from "@/components/Pagination"; +import Table from "@/components/Table"; +import TableSearch from "@/components/TableSearch"; +import { getSupabaseClient } from "@/lib/supabase"; +import { ITEM_PER_PAGE } from "@/lib/settings"; +import { Tables } from "@/types/supabase"; +import Image from "next/image"; +import { auth } from "@clerk/nextjs/server"; + +type ClassList = Tables<"Class"> & { supervisor: Tables<"Teacher"> | null }; + +const ClassListPage = async ({ + searchParams, +}: { + searchParams: { [key: string]: string | undefined }; +}) => { + + const { sessionClaims } = auth(); + const role = (sessionClaims?.metadata as { role?: string })?.role; + + + const columns = [ + { + header: "Class Name", + accessor: "name", + }, + { + header: "Capacity", + accessor: "capacity", + className: "hidden md:table-cell", + }, + { + header: "Grade", + accessor: "grade", + className: "hidden md:table-cell", + }, + { + header: "Supervisor", + accessor: "supervisor", + className: "hidden md:table-cell", + }, + ...(role === "admin" + ? [ + { + header: "Actions", + accessor: "action", + }, + ] + : []), + ]; + + const renderRow = (item: ClassList) => ( + + + + + + + + ); + + const { page, ...queryParams } = searchParams; + + const p = page ? parseInt(page) : 1; + const supabase = await getSupabaseClient(); + + // URL PARAMS CONDITION + let query = supabase + .from("Class") + .select("*, supervisor:Teacher(*)", { count: "exact" }); + + if (queryParams) { + for (const [key, value] of Object.entries(queryParams)) { + if (value !== undefined) { + switch (key) { + case "supervisorId": + query = query.eq("supervisorId", value); + break; + case "search": + query = query.ilike("name", `%${value}%`); + break; + default: + break; + } + } + } + } + + // PAGINATION + query = query.range(ITEM_PER_PAGE * (p - 1), ITEM_PER_PAGE * p - 1); + + const { data: rawData, count, error } = await query; + + if (error) { + console.error("Error fetching classes from Supabase:", error); + } + + const data = (rawData || []) as unknown as ClassList[]; + + return ( +
+ {/* TOP */} +
+

All Classes

+
+ +
+ + + {role === "admin" && } +
+
+
+ {/* LIST */} +
{item.name}{item.capacity}{item.name[0]} + {item.supervisor ? item.supervisor.name + " " + item.supervisor.surname : "-"} + +
+ {role === "admin" && ( + <> + + + + )} +
+
+ {/* PAGINATION */} + + + ); +}; + +export default ClassListPage; diff --git a/src/app/(dashboard)/list/events/page.tsx b/src/app/(dashboard)/list/events/page.tsx new file mode 100644 index 0000000..cb1fd3b --- /dev/null +++ b/src/app/(dashboard)/list/events/page.tsx @@ -0,0 +1,160 @@ +import FormContainer from "@/components/FormContainer"; +import Pagination from "@/components/Pagination"; +import Table from "@/components/Table"; +import TableSearch from "@/components/TableSearch"; +import { getSupabaseClient } from "@/lib/supabase"; +import { ITEM_PER_PAGE } from "@/lib/settings"; +import { Tables } from "@/types/supabase"; +import Image from "next/image"; +import { auth } from "@clerk/nextjs/server"; + +type EventList = Tables<"Event"> & { class: Tables<"Class"> | null }; + +const EventListPage = async ({ + searchParams, +}: { + searchParams: { [key: string]: string | undefined }; +}) => { + + const { userId, sessionClaims } = auth(); + const role = (sessionClaims?.metadata as { role?: string })?.role; + const currentUserId = userId; + + const columns = [ + { + header: "Title", + accessor: "title", + }, + { + header: "Class", + accessor: "class", + }, + { + header: "Date", + accessor: "date", + className: "hidden md:table-cell", + }, + { + header: "Start Time", + accessor: "startTime", + className: "hidden md:table-cell", + }, + { + header: "End Time", + accessor: "endTime", + className: "hidden md:table-cell", + }, + ...(role === "admin" + ? [ + { + header: "Actions", + accessor: "action", + }, + ] + : []), + ]; + + const renderRow = (item: EventList) => ( + + + + + + + + + ); + + const { page, ...queryParams } = searchParams; + + const p = page ? parseInt(page) : 1; + const supabase = await getSupabaseClient(); + + // URL PARAMS CONDITION + let query = supabase + .from("Event") + .select("*, class:Class(*)", { count: "exact" }); + + if (queryParams) { + for (const [key, value] of Object.entries(queryParams)) { + if (value !== undefined) { + switch (key) { + case "search": + query = query.ilike("title", `%${value}%`); + break; + default: + break; + } + } + } + } + + // ROLE CONDITIONS + // Authorization is now handled by Supabase Postgres RLS policies. + // The initialized `supabase` client automatically passes the Clerk user JWT, + // so the database will only return the events this user is allowed to see. + + // PAGINATION + query = query.range(ITEM_PER_PAGE * (p - 1), ITEM_PER_PAGE * p - 1); + + const { data: rawData, count, error } = await query; + + if (error) { + console.error("Error fetching events from Supabase:", error); + } + + const data = (rawData || []) as unknown as EventList[]; + + return ( +
+ {/* TOP */} +
+

All Events

+
+ +
+ + + {role === "admin" && } +
+
+
+ {/* LIST */} +
{item.title}{item.class?.name || "-"} + {new Intl.DateTimeFormat("en-US").format(new Date(item.startTime))} + + {new Date(item.startTime).toLocaleTimeString("en-US", { + hour: "2-digit", + minute: "2-digit", + hour12: false, + })} + + {new Date(item.endTime).toLocaleTimeString("en-US", { + hour: "2-digit", + minute: "2-digit", + hour12: false, + })} + +
+ {role === "admin" && ( + <> + + + + )} +
+
+ {/* PAGINATION */} + + + ); +}; + +export default EventListPage; diff --git a/src/app/(dashboard)/list/exams/page.tsx b/src/app/(dashboard)/list/exams/page.tsx new file mode 100644 index 0000000..97d2b99 --- /dev/null +++ b/src/app/(dashboard)/list/exams/page.tsx @@ -0,0 +1,160 @@ +import FormContainer from "@/components/FormContainer"; +import Pagination from "@/components/Pagination"; +import Table from "@/components/Table"; +import TableSearch from "@/components/TableSearch"; +import { getSupabaseClient } from "@/lib/supabase"; +import { ITEM_PER_PAGE } from "@/lib/settings"; +import { Tables } from "@/types/supabase"; +import Image from "next/image"; +import { auth } from "@clerk/nextjs/server"; + +type ExamList = Tables<"Exam"> & { + lesson: Tables<"Lesson"> & { + subject: Tables<"Subject">; + class: Tables<"Class">; + teacher: Tables<"Teacher">; + }; +}; + +const ExamListPage = async ({ + searchParams, +}: { + searchParams: { [key: string]: string | undefined }; +}) => { + + const { userId, sessionClaims } = auth(); + const role = (sessionClaims?.metadata as { role?: string })?.role; + const currentUserId = userId; + + + const columns = [ + { + header: "Subject Name", + accessor: "name", + }, + { + header: "Class", + accessor: "class", + }, + { + header: "Teacher", + accessor: "teacher", + className: "hidden md:table-cell", + }, + { + header: "Date", + accessor: "date", + className: "hidden md:table-cell", + }, + ...(role === "admin" || role === "teacher" + ? [ + { + header: "Actions", + accessor: "action", + }, + ] + : []), + ]; + + const renderRow = (item: ExamList) => ( + + + + + + + + ); + + const { page, ...queryParams } = searchParams; + + const p = page ? parseInt(page) : 1; + const supabase = await getSupabaseClient(); + + // URL PARAMS CONDITION + let query = supabase + .from("Exam") + .select( + "*, lesson:Lesson!inner(*, subject:Subject(*), class:Class(*), teacher:Teacher(*))", + { count: "exact" } + ); + + if (queryParams) { + for (const [key, value] of Object.entries(queryParams)) { + if (value !== undefined) { + switch (key) { + case "classId": + query = query.eq("lesson.classId", parseInt(value)); + break; + case "teacherId": + query = query.eq("lesson.teacherId", value); + break; + case "search": + query = query.ilike("lesson.subject.name", `%${value}%`); + break; + default: + break; + } + } + } + } + + // ROLE CONDITIONS + // Authorization is now handled by Supabase Postgres RLS policies. + + // PAGINATION + query = query.range(ITEM_PER_PAGE * (p - 1), ITEM_PER_PAGE * p - 1); + + const { data: rawData, count, error } = await query; + + if (error) { + console.error("Error fetching exams from Supabase:", error); + } + + const data = (rawData || []) as unknown as ExamList[]; + + return ( +
+ {/* TOP */} +
+

All Exams

+
+ +
+ + + {(role === "admin" || role === "teacher") && ( + + )} +
+
+
+ {/* LIST */} +
{item.lesson?.subject?.name || "-"}{item.lesson?.class?.name || "-"} + {item.lesson?.teacher ? item.lesson.teacher.name + " " + item.lesson.teacher.surname : "-"} + + {new Intl.DateTimeFormat("en-US").format(new Date(item.startTime))} + +
+ {(role === "admin" || role === "teacher") && ( + <> + + + + )} +
+
+ {/* PAGINATION */} + + + ); +}; + +export default ExamListPage; diff --git a/src/app/(dashboard)/list/lessons/page.tsx b/src/app/(dashboard)/list/lessons/page.tsx new file mode 100644 index 0000000..b318a1b --- /dev/null +++ b/src/app/(dashboard)/list/lessons/page.tsx @@ -0,0 +1,142 @@ +import FormContainer from "@/components/FormContainer"; +import Pagination from "@/components/Pagination"; +import Table from "@/components/Table"; +import TableSearch from "@/components/TableSearch"; +import { getSupabaseClient } from "@/lib/supabase"; +import { ITEM_PER_PAGE } from "@/lib/settings"; +import { Tables } from "@/types/supabase"; +import Image from "next/image"; +import { auth } from "@clerk/nextjs/server"; + +type LessonList = Tables<"Lesson"> & { + subject: Tables<"Subject">; + class: Tables<"Class">; + teacher: Tables<"Teacher">; +}; + + +const LessonListPage = async ({ + searchParams, +}: { + searchParams: { [key: string]: string | undefined }; +}) => { + + const { sessionClaims } = auth(); + const role = (sessionClaims?.metadata as { role?: string })?.role; + + + const columns = [ + { + header: "Subject Name", + accessor: "name", + }, + { + header: "Class", + accessor: "class", + }, + { + header: "Teacher", + accessor: "teacher", + className: "hidden md:table-cell", + }, + ...(role === "admin" + ? [ + { + header: "Actions", + accessor: "action", + }, + ] + : []), + ]; + + const renderRow = (item: LessonList) => ( + + + + + + + ); + + const { page, ...queryParams } = searchParams; + + const p = page ? parseInt(page) : 1; + const supabase = await getSupabaseClient(); + + // URL PARAMS CONDITION + let query = supabase + .from("Lesson") + .select("*, subject:Subject(*), class:Class(*), teacher:Teacher(*)", { count: "exact" }); + + if (queryParams) { + for (const [key, value] of Object.entries(queryParams)) { + if (value !== undefined) { + switch (key) { + case "classId": + query = query.eq("classId", parseInt(value)); + break; + case "teacherId": + query = query.eq("teacherId", value); + break; + case "search": + query = query.or(`subject.name.ilike.%${value}%,teacher.name.ilike.%${value}%,class.name.ilike.%${value}%`); + break; + default: + break; + } + } + } + } + + // PAGINATION + query = query.range(ITEM_PER_PAGE * (p - 1), ITEM_PER_PAGE * p - 1); + + const { data: rawData, count, error } = await query; + + if (error) { + console.error("Error fetching lessons from Supabase:", error); + } + + const data = (rawData || []) as unknown as LessonList[]; + + return ( +
+ {/* TOP */} +
+

All Lessons

+
+ +
+ + + {role === "admin" && } +
+
+
+ {/* LIST */} +
{item.subject?.name || "-"}{item.class?.name || "-"} + {item.teacher ? item.teacher.name + " " + item.teacher.surname : "-"} + +
+ {role === "admin" && ( + <> + + + + )} +
+
+ {/* PAGINATION */} + + + ); +}; + +export default LessonListPage; diff --git a/src/app/(dashboard)/list/loading.tsx b/src/app/(dashboard)/list/loading.tsx new file mode 100644 index 0000000..8e86d98 --- /dev/null +++ b/src/app/(dashboard)/list/loading.tsx @@ -0,0 +1,29 @@ +const Loading = () => { + return ( +
+
+
+
+
+
+
+
+
+ {[...Array(10)].map((_, index) => ( +
+
+
+
+
+
+ ))} +
+
+
+ ); +}; + +export default Loading; diff --git a/src/app/(dashboard)/list/parents/page.tsx b/src/app/(dashboard)/list/parents/page.tsx new file mode 100644 index 0000000..8ca1d08 --- /dev/null +++ b/src/app/(dashboard)/list/parents/page.tsx @@ -0,0 +1,144 @@ +import FormContainer from "@/components/FormContainer"; +import Pagination from "@/components/Pagination"; +import Table from "@/components/Table"; +import TableSearch from "@/components/TableSearch"; +import { getSupabaseClient } from "@/lib/supabase"; +import { ITEM_PER_PAGE } from "@/lib/settings"; +import { Tables } from "@/types/supabase"; +import Image from "next/image"; + +import { auth } from "@clerk/nextjs/server"; + +type ParentList = Tables<"Parent"> & { students: Tables<"Student">[] }; + +const ParentListPage = async ({ + searchParams, +}: { + searchParams: { [key: string]: string | undefined }; +}) => { + + const { sessionClaims } = auth(); + const role = (sessionClaims?.metadata as { role?: string })?.role; + + + const columns = [ + { + header: "Info", + accessor: "info", + }, + { + header: "Student Names", + accessor: "students", + className: "hidden md:table-cell", + }, + { + header: "Phone", + accessor: "phone", + className: "hidden lg:table-cell", + }, + { + header: "Address", + accessor: "address", + className: "hidden lg:table-cell", + }, + ...(role === "admin" + ? [ + { + header: "Actions", + accessor: "action", + }, + ] + : []), + ]; + + const renderRow = (item: ParentList) => ( +
+ + + + + + + ); + + const { page, ...queryParams } = searchParams; + + const p = page ? parseInt(page) : 1; + const supabase = await getSupabaseClient(); + + // URL PARAMS CONDITION + let query = supabase + .from("Parent") + .select("*, students:Student(*)", { count: "exact" }); + + if (queryParams) { + for (const [key, value] of Object.entries(queryParams)) { + if (value !== undefined) { + switch (key) { + case "search": + query = query.ilike("name", `%${value}%`); + break; + default: + break; + } + } + } + } + + // PAGINATION + query = query.range(ITEM_PER_PAGE * (p - 1), ITEM_PER_PAGE * p - 1); + + const { data: rawData, count, error } = await query; + + if (error) { + console.error("Error fetching parents from Supabase:", error); + } + + const data = (rawData || []) as unknown as ParentList[]; + + return ( +
+ {/* TOP */} +
+

All Parents

+
+ +
+ + + {role === "admin" && } +
+
+
+ {/* LIST */} +
+
+

{item.name}

+

{item?.email}

+
+
+ {item.students.map((student) => student.name).join(",")} + {item.phone}{item.address} +
+ {role === "admin" && ( + <> + + + + )} +
+
+ {/* PAGINATION */} + + + ); +}; + +export default ParentListPage; diff --git a/src/app/(dashboard)/list/results/page.tsx b/src/app/(dashboard)/list/results/page.tsx new file mode 100644 index 0000000..09af8d3 --- /dev/null +++ b/src/app/(dashboard)/list/results/page.tsx @@ -0,0 +1,212 @@ +import FormContainer from "@/components/FormContainer"; +import Pagination from "@/components/Pagination"; +import Table from "@/components/Table"; +import TableSearch from "@/components/TableSearch"; +import { getSupabaseClient } from "@/lib/supabase"; +import { ITEM_PER_PAGE } from "@/lib/settings"; +import { Tables } from "@/types/supabase"; +import Image from "next/image"; + +import { auth } from "@clerk/nextjs/server"; + +type ResultList = { + id: number; + title: string; + studentName: string; + studentSurname: string; + teacherName: string; + teacherSurname: string; + score: number; + className: string; + startTime: Date; +}; + + +const ResultListPage = async ({ + searchParams, +}: { + searchParams: { [key: string]: string | undefined }; +}) => { + + const { userId, sessionClaims } = auth(); + const role = (sessionClaims?.metadata as { role?: string })?.role; + const currentUserId = userId; + + + const columns = [ + { + header: "Title", + accessor: "title", + }, + { + header: "Student", + accessor: "student", + }, + { + header: "Score", + accessor: "score", + className: "hidden md:table-cell", + }, + { + header: "Teacher", + accessor: "teacher", + className: "hidden md:table-cell", + }, + { + header: "Class", + accessor: "class", + className: "hidden md:table-cell", + }, + { + header: "Date", + accessor: "date", + className: "hidden md:table-cell", + }, + ...(role === "admin" || role === "teacher" + ? [ + { + header: "Actions", + accessor: "action", + }, + ] + : []), + ]; + + const renderRow = (item: ResultList) => ( + + + + + + + + + + ); + + const { page, ...queryParams } = searchParams; + + const p = page ? parseInt(page) : 1; + const supabase = await getSupabaseClient(); + + // URL PARAMS CONDITION + let query = supabase + .from("Result") + .select(` + *, + student:Student(*), + exam:Exam( + *, + lesson:Lesson!inner( + class:Class(*), + teacher:Teacher(*) + ) + ), + assignment:Assignment( + *, + lesson:Lesson!inner( + class:Class(*), + teacher:Teacher(*) + ) + ) + `, { count: "exact" }); + + if (queryParams) { + for (const [key, value] of Object.entries(queryParams)) { + if (value !== undefined) { + switch (key) { + case "studentId": + query = query.eq("studentId", value); + break; + case "search": + // Supabase JS doesn't easily support OR across joined tables via .or() string syntax + // like `exam.title.ilike.%val%,student.name.ilike.%val%`. + // Workaround: We will fetch broadly and filter below, or just rely on RLS. + // For true broad search in Supabase over joins, + // an RPC function is usually required. For now, dropping search. + console.warn("Cross-table search text not supported in standard Supabase JS select without RPC."); + break; + default: + break; + } + } + } + } + + // ROLE CONDITIONS: Handled by Supabase Postgres RLS. + + // PAGINATION + query = query.range(ITEM_PER_PAGE * (p - 1), ITEM_PER_PAGE * p - 1); + + const { data: dataRes, count, error } = await query; + + if (error) { + console.error("Error fetching results from Supabase:", error); + } + + const dlist = (dataRes || []) as unknown as any[]; + const data = dlist.map((item) => { + const assessment = item.exam || item.assignment; + + if (!assessment) return null; + + const isExam = "startTime" in assessment; + + return { + id: item.id, + title: assessment.title, + studentName: item.student?.name || "Unknown", + studentSurname: item.student?.surname || "", + teacherName: assessment.lesson?.teacher?.name || "-", + teacherSurname: assessment.lesson?.teacher?.surname || "", + score: item.score, + className: assessment.lesson?.class?.name || "-", + startTime: isExam ? assessment.startTime : assessment.startDate, + }; + }).filter(item => item !== null) as ResultList[]; + + return ( +
+ {/* TOP */} +
+

All Results

+
+ +
+ + + {(role === "admin" || role === "teacher") && ( + + )} +
+
+
+ {/* LIST */} +
{item.title}{item.studentName + " " + item.studentName}{item.score} + {item.teacherName + " " + item.teacherSurname} + {item.className} + {new Intl.DateTimeFormat("en-US").format(new Date(item.startTime))} + +
+ {(role === "admin" || role === "teacher") && ( + <> + + + + )} +
+
+ {/* PAGINATION */} + + + ); +}; + +export default ResultListPage; diff --git a/src/app/(dashboard)/list/students/[id]/page.tsx b/src/app/(dashboard)/list/students/[id]/page.tsx new file mode 100644 index 0000000..b24feef --- /dev/null +++ b/src/app/(dashboard)/list/students/[id]/page.tsx @@ -0,0 +1,221 @@ +import Announcements from "@/components/Announcements"; +import BigCalendarContainer from "@/components/BigCalendarContainer"; +import FormContainer from "@/components/FormContainer"; +import Performance from "@/components/Performance"; +import StudentAttendanceCard from "@/components/StudentAttendanceCard"; +import { getSupabaseClient } from "@/lib/supabase"; +import { auth } from "@clerk/nextjs/server"; +import { Tables } from "@/types/supabase"; +import Image from "next/image"; +import Link from "next/link"; +import { notFound } from "next/navigation"; +import { Suspense } from "react"; + +const SingleStudentPage = async ({ + params: { id }, +}: { + params: { id: string }; +}) => { + const { sessionClaims } = auth(); + const role = (sessionClaims?.metadata as { role?: string })?.role; + + const supabase = await getSupabaseClient(); + + const { data, error } = await supabase + .from("Student") + .select(` + *, + class:Class( + *, + lessons:Lesson(count) + ) + `) + .eq("id", id) + .single(); + + if (error || !data) { + return notFound(); + } + + // Extract count from the array returned by PostgREST inner select count + const lessonsCount = Array.isArray(data.class?.lessons) + ? (data.class?.lessons as any)[0]?.count || 0 + : 0; + + const student = { + ...data, + class: { + ...data.class, + _count: { lessons: lessonsCount } + } + } as any; + + if (!student) { + return notFound(); + } + + return ( +
+ {/* LEFT */} +
+ {/* TOP */} +
+ {/* USER INFO CARD */} +
+
+ +
+
+
+

+ {student.name + " " + student.surname} +

+ {role === "admin" && ( + + )} +
+

+ Lorem ipsum, dolor sit amet consectetur adipisicing elit. +

+
+
+ + {student.bloodType} +
+
+ + + {new Intl.DateTimeFormat("en-GB").format(new Date(student.birthday))} + +
+
+ + {student.email || "-"} +
+
+ + {student.phone || "-"} +
+
+
+
+ {/* SMALL CARDS */} +
+ {/* CARD */} +
+ + + + +
+ {/* CARD */} +
+ +
+

+ {student.class.name.charAt(0)}th +

+ Grade +
+
+ {/* CARD */} +
+ +
+

+ {student.class._count.lessons} +

+ Lessons +
+
+ {/* CARD */} +
+ +
+

{student.class.name}

+ Class +
+
+
+
+ {/* BOTTOM */} +
+

Student's Schedule

+ +
+
+ {/* RIGHT */} +
+
+

Shortcuts

+
+ + Student's Lessons + + + Student's Teachers + + + Student's Exams + + + Student's Assignments + + + Student's Results + +
+
+ + +
+
+ ); +}; + +export default SingleStudentPage; diff --git a/src/app/(dashboard)/list/students/page.tsx b/src/app/(dashboard)/list/students/page.tsx new file mode 100644 index 0000000..cb871e3 --- /dev/null +++ b/src/app/(dashboard)/list/students/page.tsx @@ -0,0 +1,186 @@ +import FormContainer from "@/components/FormContainer"; +import Pagination from "@/components/Pagination"; +import Table from "@/components/Table"; +import TableSearch from "@/components/TableSearch"; + +import { getSupabaseClient } from "@/lib/supabase"; +import { ITEM_PER_PAGE } from "@/lib/settings"; +import { Tables } from "@/types/supabase"; +import Image from "next/image"; +import Link from "next/link"; + +import { auth } from "@clerk/nextjs/server"; + +type StudentList = Tables<"Student"> & { class: Tables<"Class"> }; + +const StudentListPage = async ({ + searchParams, +}: { + searchParams: { [key: string]: string | undefined }; +}) => { + const { sessionClaims } = auth(); + const role = (sessionClaims?.metadata as { role?: string })?.role; + + const columns = [ + { + header: "Info", + accessor: "info", + }, + { + header: "Student ID", + accessor: "studentId", + className: "hidden md:table-cell", + }, + { + header: "Grade", + accessor: "grade", + className: "hidden md:table-cell", + }, + { + header: "Phone", + accessor: "phone", + className: "hidden lg:table-cell", + }, + { + header: "Address", + accessor: "address", + className: "hidden lg:table-cell", + }, + ...(role === "admin" + ? [ + { + header: "Actions", + accessor: "action", + }, + ] + : []), + ]; + + const renderRow = (item: StudentList) => ( +
+ + + + + + + + ); + + const { page, ...queryParams } = searchParams; + + const p = page ? parseInt(page) : 1; + const supabase = await getSupabaseClient(); + + // URL PARAMS CONDITION + // Note: we need lessons if teacherId is provided + let query = supabase + .from("Student") + .select("*, class:Class(*, lessons:Lesson(*))", { count: "exact" }); + + if (queryParams) { + for (const [key, value] of Object.entries(queryParams)) { + if (value !== undefined) { + switch (key) { + case "teacherId": + // Filter by teacherId within the joined lessons. + // Supabase postgREST filters on JSON: class.lessons.teacherId=eq... + // It's tricky to filter the main rows based on a nested condition. + // Instead we can use an inner join via class!inner(lessons!inner(*)). + query = query.eq("class.lessons.teacherId", value); + // It might require adjustments, but RLS generally restricts this. + break; + case "search": + query = query.ilike("name", `%${value}%`); + break; + default: + break; + } + } + } + } + + // PAGINATION + query = query.range(ITEM_PER_PAGE * (p - 1), ITEM_PER_PAGE * p - 1); + + let { data: rawData, count, error } = await query; + + if (error) { + console.error("Error fetching students from Supabase:", error); + } + + // Workaround for `teacherId` query: Since Supabase inner joins + // on deep JSON relationships can sometimes fail or return empty arrays + // when `select` is used like "class(*)", let's filter after fetch if `teacherId` was passed + // (In a real scenario, an RPC is better for complex joins that filter parents by nested children) + if (queryParams.teacherId && rawData) { + rawData = rawData.filter(student => + // @ts-ignore + student.class?.lessons?.some((lesson: any) => lesson.teacherId === queryParams.teacherId) + ); + count = rawData.length; + } + + const data = (rawData || []) as unknown as StudentList[]; + + return ( +
+ {/* TOP */} +
+

All Students

+
+ +
+ + + {role === "admin" && ( + // + + )} +
+
+
+ {/* LIST */} +
+ +
+

{item.name}

+

{item.class.name}

+
+
{item.username}{item.class.name[0]}{item.phone}{item.address} +
+ + + + {role === "admin" && ( + // + + )} +
+
+ {/* PAGINATION */} + + + ); +}; + +export default StudentListPage; diff --git a/src/app/(dashboard)/list/subjects/page.tsx b/src/app/(dashboard)/list/subjects/page.tsx new file mode 100644 index 0000000..28fae81 --- /dev/null +++ b/src/app/(dashboard)/list/subjects/page.tsx @@ -0,0 +1,129 @@ +import FormContainer from "@/components/FormContainer"; +import Pagination from "@/components/Pagination"; +import Table from "@/components/Table"; +import TableSearch from "@/components/TableSearch"; +import { getSupabaseClient } from "@/lib/supabase"; +import { ITEM_PER_PAGE } from "@/lib/settings"; +import { Tables } from "@/types/supabase"; +import Image from "next/image"; +import { auth } from "@clerk/nextjs/server"; + +type SubjectList = Tables<"Subject"> & { teachers: Tables<"Teacher">[] }; + +const SubjectListPage = async ({ + searchParams, +}: { + searchParams: { [key: string]: string | undefined }; +}) => { + const { sessionClaims } = auth(); + const role = (sessionClaims?.metadata as { role?: string })?.role; + + const columns = [ + { + header: "Subject Name", + accessor: "name", + }, + { + header: "Teachers", + accessor: "teachers", + className: "hidden md:table-cell", + }, + { + header: "Actions", + accessor: "action", + }, + ]; + + const renderRow = (item: SubjectList) => ( + + + + + + ); + + const { page, ...queryParams } = searchParams; + + const p = page ? parseInt(page) : 1; + const supabase = await getSupabaseClient(); + + // URL PARAMS CONDITION + let query = supabase + .from("Subject") + .select("*, TeacherSubject(Teacher(*))", { count: "exact" }); + + if (queryParams) { + for (const [key, value] of Object.entries(queryParams)) { + if (value !== undefined) { + switch (key) { + case "search": + query = query.ilike("name", `%${value}%`); + break; + default: + break; + } + } + } + } + + // PAGINATION + query = query.range(ITEM_PER_PAGE * (p - 1), ITEM_PER_PAGE * p - 1); + + const { data: rawData, count, error } = await query; + + if (error) { + console.error("Error fetching subjects from Supabase:", error); + } + + const data = (rawData || []).map(subject => { + // @ts-ignore + const teachers = subject.TeacherSubject?.map((rel: any) => rel.Teacher) || []; + return { + ...subject, + teachers + } + }) as unknown as SubjectList[]; + + return ( +
+ {/* TOP */} +
+

All Subjects

+
+ +
+ + + {role === "admin" && ( + + )} +
+
+
+ {/* LIST */} +
{item.name} + {item.teachers.map((teacher) => teacher.name).join(",")} + +
+ {role === "admin" && ( + <> + + + + )} +
+
+ {/* PAGINATION */} + + + ); +}; + +export default SubjectListPage; diff --git a/src/app/(dashboard)/list/teachers/[id]/page.tsx b/src/app/(dashboard)/list/teachers/[id]/page.tsx new file mode 100644 index 0000000..6cd1353 --- /dev/null +++ b/src/app/(dashboard)/list/teachers/[id]/page.tsx @@ -0,0 +1,221 @@ +import Announcements from "@/components/Announcements"; +import BigCalendarContainer from "@/components/BigCalendarContainer"; +import BigCalendar from "@/components/BigCalender"; +import FormContainer from "@/components/FormContainer"; +import Performance from "@/components/Performance"; +import { getSupabaseClient } from "@/lib/supabase"; +import { auth } from "@clerk/nextjs/server"; +import { Tables } from "@/types/supabase"; +import Image from "next/image"; +import Link from "next/link"; +import { notFound } from "next/navigation"; + +const SingleTeacherPage = async ({ + params: { id }, +}: { + params: { id: string }; +}) => { + const { sessionClaims } = auth(); + const role = (sessionClaims?.metadata as { role?: string })?.role; + + const supabase = await getSupabaseClient(); + + const { data, error } = await supabase + .from("Teacher") + .select(` + *, + TeacherSubject(count), + lessons:Lesson(count), + classes:Class(count) + `) + .eq("id", id) + .single(); + + if (error || !data) { + return notFound(); + } + + const subjectsCount = Array.isArray(data.TeacherSubject) ? (data.TeacherSubject as any)[0]?.count || 0 : 0; + const lessonsCount = Array.isArray(data.lessons) ? (data.lessons as any)[0]?.count || 0 : 0; + const classesCount = Array.isArray(data.classes) ? (data.classes as any)[0]?.count || 0 : 0; + + const teacher = { + ...data, + _count: { + subjects: subjectsCount, + lessons: lessonsCount, + classes: classesCount, + } + } as any; + + if (!teacher) { + return notFound(); + } + return ( +
+ {/* LEFT */} +
+ {/* TOP */} +
+ {/* USER INFO CARD */} +
+
+ +
+
+
+

+ {teacher.name + " " + teacher.surname} +

+ {role === "admin" && ( + + )} +
+

+ Lorem ipsum, dolor sit amet consectetur adipisicing elit. +

+
+
+ + {teacher.bloodType} +
+
+ + + {new Intl.DateTimeFormat("en-GB").format(new Date(teacher.birthday))} + +
+
+ + {teacher.email || "-"} +
+
+ + {teacher.phone || "-"} +
+
+
+
+ {/* SMALL CARDS */} +
+ {/* CARD */} +
+ +
+

90%

+ Attendance +
+
+ {/* CARD */} +
+ +
+

+ {teacher._count.subjects} +

+ Branches +
+
+ {/* CARD */} +
+ +
+

+ {teacher._count.lessons} +

+ Lessons +
+
+ {/* CARD */} +
+ +
+

+ {teacher._count.classes} +

+ Classes +
+
+
+
+ {/* BOTTOM */} +
+

Teacher's Schedule

+ +
+
+ {/* RIGHT */} +
+
+

Shortcuts

+
+ + Teacher's Classes + + + Teacher's Students + + + Teacher's Lessons + + + Teacher's Exams + + + Teacher's Assignments + +
+
+ + +
+
+ ); +}; + +export default SingleTeacherPage; diff --git a/src/app/(dashboard)/list/teachers/page.tsx b/src/app/(dashboard)/list/teachers/page.tsx new file mode 100644 index 0000000..8a089aa --- /dev/null +++ b/src/app/(dashboard)/list/teachers/page.tsx @@ -0,0 +1,190 @@ +import FormContainer from "@/components/FormContainer"; +import Pagination from "@/components/Pagination"; +import Table from "@/components/Table"; +import TableSearch from "@/components/TableSearch"; +import { getSupabaseClient } from "@/lib/supabase"; +import { Tables } from "@/types/supabase"; +import Image from "next/image"; +import Link from "next/link"; +import { ITEM_PER_PAGE } from "@/lib/settings"; +import { auth } from "@clerk/nextjs/server"; + +type TeacherList = Tables<"Teacher"> & { subjects: Tables<"Subject">[] } & { classes: Tables<"Class">[] }; + +const TeacherListPage = async ({ + searchParams, +}: { + searchParams: { [key: string]: string | undefined }; +}) => { + const { sessionClaims } = auth(); + const role = (sessionClaims?.metadata as { role?: string })?.role; + const columns = [ + { + header: "Info", + accessor: "info", + }, + { + header: "Teacher ID", + accessor: "teacherId", + className: "hidden md:table-cell", + }, + { + header: "Subjects", + accessor: "subjects", + className: "hidden md:table-cell", + }, + { + header: "Classes", + accessor: "classes", + className: "hidden md:table-cell", + }, + { + header: "Phone", + accessor: "phone", + className: "hidden lg:table-cell", + }, + { + header: "Address", + accessor: "address", + className: "hidden lg:table-cell", + }, + ...(role === "admin" + ? [ + { + header: "Actions", + accessor: "action", + }, + ] + : []), + ]; + + const renderRow = (item: TeacherList) => ( +
+ + + + + + + + + ); + const { page, ...queryParams } = searchParams; + + const p = page ? parseInt(page) : 1; + const supabase = await getSupabaseClient(); + + // URL PARAMS CONDITION + // Note: we need lessons if classId is provided + let query = supabase + .from("Teacher") + .select("*, TeacherSubject(Subject(*)), classes:Class(*), lessons:Lesson(*)", { count: "exact" }); + + if (queryParams) { + for (const [key, value] of Object.entries(queryParams)) { + if (value !== undefined) { + switch (key) { + case "classId": + // Filter by classId within the joined lessons. + query = query.eq("lessons.classId", parseInt(value)); + break; + case "search": + query = query.ilike("name", `%${value}%`); + break; + default: + break; + } + } + } + } + + // PAGINATION + query = query.range(ITEM_PER_PAGE * (p - 1), ITEM_PER_PAGE * p - 1); + + let { data: rawData, count, error } = await query; + + if (error) { + console.error("Error fetching teachers from Supabase:", error); + } + + // Workaround for `classId` query: + if (queryParams.classId && rawData) { + rawData = rawData.filter(teacher => + // @ts-ignore + teacher.lessons?.some((lesson: any) => lesson.classId === parseInt(queryParams.classId!)) + ); + count = rawData.length; + } + + // Map the nested TeacherSubject data back to a flat subjects array for the datatable + const data = (rawData || []).map(teacher => { + // @ts-ignore + const subjects = teacher.TeacherSubject?.map((rel: any) => rel.Subject) || []; + return { + ...teacher, + subjects + } + }) as unknown as TeacherList[]; + + return ( +
+ {/* TOP */} +
+

All Teachers

+
+ +
+ + + {role === "admin" && ( + + )} +
+
+
+ {/* LIST */} +
+ +
+

{item.name}

+

{item?.email}

+
+
{item.username} + {item.subjects.map((subject) => subject.name).join(",")} + + {item.classes.map((classItem) => classItem.name).join(",")} + {item.phone}{item.address} +
+ + + + {role === "admin" && ( + // + + )} +
+
+ {/* PAGINATION */} + + + ); +}; + +export default TeacherListPage; diff --git a/src/app/(dashboard)/parent/page.tsx b/src/app/(dashboard)/parent/page.tsx new file mode 100644 index 0000000..899e2af --- /dev/null +++ b/src/app/(dashboard)/parent/page.tsx @@ -0,0 +1,48 @@ +import Announcements from "@/components/Announcements"; +import BigCalendarContainer from "@/components/BigCalendarContainer"; +import { getSupabaseClient } from "@/lib/supabase"; +import { auth } from "@clerk/nextjs/server"; +import { Tables } from "@/types/supabase"; + + +const ParentPage = async () => { + const { userId } = auth(); + const currentUserId = userId; + + const supabase = await getSupabaseClient(); + const { data: students, error } = await supabase + .from("Student") + .select("*") + // RLS policies should handle identifying parent id + // .eq("parentId", currentUserId!) + + if (error) { + console.error("Error fetching parent students:", error); + } + + const studentsList = (students || []) as Tables<"Student">[]; + + return ( +
+ {/* LEFT */} +
+ {studentsList.map((student) => ( +
+
+

+ Schedule ({student.name + " " + student.surname}) +

+ +
+
+ ))} +
+ {/* RIGHT */} +
+ +
+
+ ); +}; + +export default ParentPage; diff --git a/src/app/(dashboard)/student/page.tsx b/src/app/(dashboard)/student/page.tsx new file mode 100644 index 0000000..399f510 --- /dev/null +++ b/src/app/(dashboard)/student/page.tsx @@ -0,0 +1,57 @@ +import Announcements from "@/components/Announcements"; +import BigCalendarContainer from "@/components/BigCalendarContainer"; +import BigCalendar from "@/components/BigCalender"; +import EventCalendar from "@/components/EventCalendar"; +import { getSupabaseClient } from "@/lib/supabase"; +import { Tables } from "@/types/supabase"; +import { auth } from "@clerk/nextjs/server"; + +const StudentPage = async () => { + const { userId } = auth(); + + const supabase = await getSupabaseClient(); + const { data: studentItem, error: studentError } = await supabase + .from("Student") + .select("classId") + .eq("id", userId!) + .single(); + + if (studentError) { + console.error("Error fetching student details:", studentError); + } + + const { data: classItems, error } = await supabase + .from("Class") + .select("*") + .eq("id", studentItem?.classId || 0); + + if (error) { + console.error("Error fetching student class:", error); + } + + const classItem = (classItems || []) as Tables<"Class">[]; + const studentClassId = classItem.length > 0 ? classItem[0].id : null; + + return ( +
+ {/* LEFT */} +
+
+

Schedule (4A)

+ {studentClassId ? ( + + ) : ( +
No schedule found for your assigned class.
+ )} +
+
+ {/* RIGHT */} +
+ + +
+
+ ); +}; + +export default StudentPage; diff --git a/src/app/(dashboard)/teacher/page.tsx b/src/app/(dashboard)/teacher/page.tsx new file mode 100644 index 0000000..239440c --- /dev/null +++ b/src/app/(dashboard)/teacher/page.tsx @@ -0,0 +1,24 @@ +import Announcements from "@/components/Announcements"; +import BigCalendarContainer from "@/components/BigCalendarContainer"; +import { auth } from "@clerk/nextjs/server"; + +const TeacherPage = () => { + const { userId } = auth(); + return ( +
+ {/* LEFT */} +
+
+

Schedule

+ +
+
+ {/* RIGHT */} +
+ +
+
+ ); +}; + +export default TeacherPage; diff --git a/src/app/[[...sign-in]]/page.tsx b/src/app/[[...sign-in]]/page.tsx new file mode 100644 index 0000000..283416c --- /dev/null +++ b/src/app/[[...sign-in]]/page.tsx @@ -0,0 +1,70 @@ +"use client"; + +import * as Clerk from "@clerk/elements/common"; +import * as SignIn from "@clerk/elements/sign-in"; +import { useUser } from "@clerk/nextjs"; +import Image from "next/image"; +import { useRouter } from "next/navigation"; +import { useEffect } from "react"; + +const LoginPage = () => { + const { isLoaded, isSignedIn, user } = useUser(); + + const router = useRouter(); + + useEffect(() => { + const role = user?.publicMetadata.role; + + if (role) { + router.push(`/${role}`); + } + }, [user, router]); + + return ( +
+ + +

+ + SchooLama +

+

Sign in to your account

+ + + + Username + + + + + + + Password + + + + + + Sign In + +
+
+
+ ); +}; + +export default LoginPage; diff --git a/src/app/favicon.ico b/src/app/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..1b59cd8d6de8df1a8000438a45afc11a418814d3 GIT binary patch literal 3366 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 literal 0 HcmV?d00001 diff --git a/src/app/globals.css b/src/app/globals.css new file mode 100644 index 0000000..d7203b9 --- /dev/null +++ b/src/app/globals.css @@ -0,0 +1,110 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +.react-calendar { + width: 100% !important; + border: none !important; + font-family: "Inter", sans-serif !important; +} + +.react-calendar__navigation__label__labelText { + font-weight: 600; +} + +.react-calendar__tile--active { + background-color: #c3ebfa !important; + color: black !important; +} + +.rbc-btn-group:first-child button { + border: none !important; + background-color: #f1f0ff !important; + margin-right: 2px !important; + font-size: 13px !important; +} + +.rbc-toolbar-label { + text-align: right !important; + padding: 0px 20px !important; +} + +.rbc-btn-group:last-child { + font-size: 13px !important; +} + +.rbc-btn-group:last-child button { + border: none !important; + background-color: #f1f0ff !important; + margin-left: 2px !important; +} + +.rbc-toolbar button.rbc-active { + background-color: #dbdafe !important; + box-shadow: none !important; +} + +.rbc-time-view { + border-color: #eee !important; +} + +.rbc-time-gutter.rbc-time-column { + font-size: 12px !important; +} + +.rbc-time-gutter.rbc-time-column .rbc-timeslot-group { + padding: 0px 20px !important; +} + +.rbc-timeslot-group { + background-color: #f7fdff !important; +} + +.rbc-day-slot { + font-size: 14px !important; +} + +.rbc-event { + border: none !important; + color: black !important; + padding: 5px !important; + border-radius: 6px !important; +} + +.rbc-event-content { + display: block !important; + font-size: 13px; + font-weight: 600; +} + +.rbc-event:nth-child(1) { + background-color: #e2f8ff !important; +} + +.rbc-event:nth-child(2) { + background-color: #fefce8 !important; +} + +.rbc-event:nth-child(3) { + background-color: #f2f1ff !important; +} + +.rbc-event:nth-child(4) { + background-color: #fdf2fb !important; +} + +.rbc-event:nth-child(5) { + background-color: #e2f8ff !important; +} + +.rbc-event:nth-child(6) { + background-color: #fefce8 !important; +} + +.rbc-event:nth-child(7) { + background-color: #f2f1ff !important; +} + +.rbc-event:nth-child(8) { + background-color: #fdf2fb !important; +} \ No newline at end of file diff --git a/src/app/layout.tsx b/src/app/layout.tsx new file mode 100644 index 0000000..ea64654 --- /dev/null +++ b/src/app/layout.tsx @@ -0,0 +1,31 @@ +import type { Metadata } from "next"; +import { Inter } from "next/font/google"; +import "./globals.css"; +import { ClerkProvider } from "@clerk/nextjs"; +import { ToastContainer } from "react-toastify"; +import "react-toastify/dist/ReactToastify.css"; +import ConsoleSuppressor from "@/components/ConsoleSuppressor"; + +const inter = Inter({ subsets: ["latin"] }); + +export const metadata: Metadata = { + title: "Lama Dev School Management Dashboard", + description: "Next.js School Management System", +}; + +export default function RootLayout({ + children, +}: Readonly<{ + children: React.ReactNode; +}>) { + return ( + + + + + {children} + + + + ); +} diff --git a/src/components/Announcements.tsx b/src/components/Announcements.tsx new file mode 100644 index 0000000..ea28a05 --- /dev/null +++ b/src/components/Announcements.tsx @@ -0,0 +1,66 @@ +import { getSupabaseClient } from "@/lib/supabase"; +import { auth } from "@clerk/nextjs/server"; + +const Announcements = async () => { + const { userId, sessionClaims } = auth(); + const role = (sessionClaims?.metadata as { role?: string })?.role; + + const supabase = await getSupabaseClient(); + const { data: rawData, error } = await supabase + .from("Announcement") + .select("*") + .order("date", { ascending: false }) + .limit(3); + + if (error) { + console.error("Error fetching announcements:", error); + } + + const data = rawData || []; + + return ( +
+
+

Announcements

+ View All +
+
+ {data[0] && ( +
+
+

{data[0].title}

+ + {new Intl.DateTimeFormat("en-GB").format(new Date(data[0].date))} + +
+

{data[0].description}

+
+ )} + {data[1] && ( +
+
+

{data[1].title}

+ + {new Intl.DateTimeFormat("en-GB").format(new Date(data[1].date))} + +
+

{data[1].description}

+
+ )} + {data[2] && ( +
+
+

{data[2].title}

+ + {new Intl.DateTimeFormat("en-GB").format(new Date(data[2].date))} + +
+

{data[2].description}

+
+ )} +
+
+ ); +}; + +export default Announcements; diff --git a/src/components/AttendanceChart.tsx b/src/components/AttendanceChart.tsx new file mode 100644 index 0000000..75c689c --- /dev/null +++ b/src/components/AttendanceChart.tsx @@ -0,0 +1,57 @@ +"use client"; +import Image from "next/image"; +import { + BarChart, + Bar, + Rectangle, + XAxis, + YAxis, + CartesianGrid, + Tooltip, + Legend, + ResponsiveContainer, +} from "recharts"; + +const AttendanceChart = ({ + data, +}: { + data: { name: string; present: number; absent: number }[]; +}) => { + return ( + + + + + + + + + + + + ); +}; + +export default AttendanceChart; diff --git a/src/components/AttendanceChartContainer.tsx b/src/components/AttendanceChartContainer.tsx new file mode 100644 index 0000000..28a3f0f --- /dev/null +++ b/src/components/AttendanceChartContainer.tsx @@ -0,0 +1,71 @@ +import Image from "next/image"; +import AttendanceChart from "./AttendanceChart"; +import { getSupabaseClient } from "@/lib/supabase"; + +const AttendanceChartContainer = async () => { + const today = new Date(); + const dayOfWeek = today.getDay(); + const daysSinceMonday = dayOfWeek === 0 ? 6 : dayOfWeek - 1; + + const lastMonday = new Date(today); + + lastMonday.setDate(today.getDate() - daysSinceMonday); + + const supabase = await getSupabaseClient(); + const { data: rawData, error } = await supabase + .from("Attendance") + .select("date, present") + .gte("date", lastMonday.toISOString()); + + if (error) { + console.error("Error fetching attendance data:", error); + } + + const resData = rawData || []; + + // console.log(data) + + const daysOfWeek = ["Mon", "Tue", "Wed", "Thu", "Fri"]; + + const attendanceMap: { [key: string]: { present: number; absent: number } } = + { + Mon: { present: 0, absent: 0 }, + Tue: { present: 0, absent: 0 }, + Wed: { present: 0, absent: 0 }, + Thu: { present: 0, absent: 0 }, + Fri: { present: 0, absent: 0 }, + }; + + resData.forEach((item) => { + const itemDate = new Date(item.date); + const dayOfWeek = itemDate.getDay(); + + if (dayOfWeek >= 1 && dayOfWeek <= 5) { + const dayName = daysOfWeek[dayOfWeek - 1]; + + if (item.present) { + attendanceMap[dayName].present += 1; + } else { + attendanceMap[dayName].absent += 1; + } + } + }); + + const data = daysOfWeek.map((day) => ({ + name: day, + present: attendanceMap[day].present, + absent: attendanceMap[day].absent, + })); + + return ( +
+
+

Attendance

+ +
+ +
+ ); +}; + +export default AttendanceChartContainer; diff --git a/src/components/BigCalendarContainer.tsx b/src/components/BigCalendarContainer.tsx new file mode 100644 index 0000000..90d8e36 --- /dev/null +++ b/src/components/BigCalendarContainer.tsx @@ -0,0 +1,40 @@ +import { getSupabaseClient } from "@/lib/supabase"; +import BigCalendar from "./BigCalender"; + +const BigCalendarContainer = async ({ + type, + id, +}: { + type: "teacherId" | "classId"; + id: string | number; +}) => { + const supabase = await getSupabaseClient(); + + let query = supabase.from("Lesson").select("*"); + if (type === "teacherId") { + query = query.eq("teacherId", id as string); + } else { + query = query.eq("classId", id as number); + } + + const { data: rawData, error } = await query; + if (error) { + console.error("Error fetching calendar lessons:", error); + } + + const dataRes = rawData || []; + + const data = dataRes.map((lesson) => ({ + title: lesson.name, + start: new Date(lesson.startTime), + end: new Date(lesson.endTime), + })); + + return ( +
+ +
+ ); +}; + +export default BigCalendarContainer; diff --git a/src/components/BigCalender.tsx b/src/components/BigCalender.tsx new file mode 100644 index 0000000..f2ec2e4 --- /dev/null +++ b/src/components/BigCalender.tsx @@ -0,0 +1,41 @@ +"use client"; + +import { Calendar, momentLocalizer, View, Views } from "react-big-calendar"; +import moment from "moment"; +import "react-big-calendar/lib/css/react-big-calendar.css"; +import { useState } from "react"; + +const localizer = momentLocalizer(moment); + +const BigCalendar = ({ + data, +}: { + data: { title: string; start: Date; end: Date }[]; +}) => { + const [view, setView] = useState(Views.WORK_WEEK); + const [date, setDate] = useState(new Date()); + + const handleOnChangeView = (selectedView: View) => { + setView(selectedView); + }; + + return ( + + ); +}; + +export default BigCalendar; diff --git a/src/components/ConsoleSuppressor.tsx b/src/components/ConsoleSuppressor.tsx new file mode 100644 index 0000000..204841f --- /dev/null +++ b/src/components/ConsoleSuppressor.tsx @@ -0,0 +1,18 @@ +"use client"; + +if (typeof window !== "undefined") { + const originalError = console.error; + console.error = (...args) => { + if ( + typeof args[0] === "string" && + args[0].includes("Support for defaultProps will be removed from function components") + ) { + return; + } + originalError(...args); + }; +} + +export default function ConsoleSuppressor() { + return null; +} diff --git a/src/components/CountChart.tsx b/src/components/CountChart.tsx new file mode 100644 index 0000000..db4123d --- /dev/null +++ b/src/components/CountChart.tsx @@ -0,0 +1,54 @@ +"use client"; +import Image from "next/image"; +import { + RadialBarChart, + RadialBar, + Legend, + ResponsiveContainer, +} from "recharts"; + + +const CountChart = ({ boys, girls }: { boys: number; girls: number }) => { + const data = [ + { + name: "Total", + count: boys+girls, + fill: "white", + }, + { + name: "Girls", + count: girls, + fill: "#FAE27C", + }, + { + name: "Boys", + count: boys, + fill: "#C3EBFA", + }, + ]; + return ( +
+ + + + + + +
+ ); +}; + +export default CountChart; diff --git a/src/components/CountChartContainer.tsx b/src/components/CountChartContainer.tsx new file mode 100644 index 0000000..b764c39 --- /dev/null +++ b/src/components/CountChartContainer.tsx @@ -0,0 +1,50 @@ +import Image from "next/image"; +import CountChart from "./CountChart"; +import { getSupabaseClient } from "@/lib/supabase"; + +const CountChartContainer = async () => { + const supabase = await getSupabaseClient(); + const { count: boysCount } = await supabase + .from("Student") + .select("*", { count: "exact", head: true }) + .eq("sex", "MALE"); + + const { count: girlsCount } = await supabase + .from("Student") + .select("*", { count: "exact", head: true }) + .eq("sex", "FEMALE"); + + const boys = boysCount || 0; + const girls = girlsCount || 0; + + return ( +
+ {/* TITLE */} +
+

Students

+ +
+ {/* CHART */} + + {/* BOTTOM */} +
+
+
+

{boys}

+

+ Boys ({Math.round((boys / (boys + girls)) * 100)}%) +

+
+
+
+

{girls}

+

+ Girls ({Math.round((girls / (boys + girls)) * 100)}%) +

+
+
+
+ ); +}; + +export default CountChartContainer; diff --git a/src/components/EventCalendar.tsx b/src/components/EventCalendar.tsx new file mode 100644 index 0000000..b923165 --- /dev/null +++ b/src/components/EventCalendar.tsx @@ -0,0 +1,38 @@ +"use client"; + +import { useRouter } from "next/navigation"; +import { useEffect, useState } from "react"; +import Calendar from "react-calendar"; +import "react-calendar/dist/Calendar.css"; + +type ValuePiece = Date | null; + +type Value = ValuePiece | [ValuePiece, ValuePiece]; + +const EventCalendar = () => { + const [value, onChange] = useState(new Date()); + + const router = useRouter(); + + // TEMPORARY FIX: Suppress hydration warning for react-calendar + // react-calendar uses browser locale for formatting which mismatches server rendering + useEffect(() => { + if (value instanceof Date) { + router.push(`?date=${value}`); + } + }, [value, router]); + + // Prevent rendering on the server to avoid hydration mismatch + const [isClient, setIsClient] = useState(false); + useEffect(() => { + setIsClient(true); + }, []); + + if (!isClient) { + return null; // or a loading skeleton + } + + return ; +}; + +export default EventCalendar; diff --git a/src/components/EventCalendarContainer.tsx b/src/components/EventCalendarContainer.tsx new file mode 100644 index 0000000..9320597 --- /dev/null +++ b/src/components/EventCalendarContainer.tsx @@ -0,0 +1,25 @@ +import Image from "next/image"; +import EventCalendar from "./EventCalendar"; +import EventList from "./EventList"; + +const EventCalendarContainer = async ({ + searchParams, +}: { + searchParams: { [keys: string]: string | undefined }; +}) => { + const { date } = searchParams; + return ( +
+ +
+

Events

+ +
+
+ +
+
+ ); +}; + +export default EventCalendarContainer; diff --git a/src/components/EventList.tsx b/src/components/EventList.tsx new file mode 100644 index 0000000..baf940e --- /dev/null +++ b/src/components/EventList.tsx @@ -0,0 +1,45 @@ +import { getSupabaseClient } from "@/lib/supabase"; + +const EventList = async ({ dateParam }: { dateParam: string | undefined }) => { + const date = dateParam ? new Date(dateParam) : new Date(); + + const startOfDay = new Date(date); + startOfDay.setHours(0, 0, 0, 0); + + const endOfDay = new Date(date); + endOfDay.setHours(23, 59, 59, 999); + + const supabase = await getSupabaseClient(); + const { data: rawData, error } = await supabase + .from("Event") + .select("*") + .gte("startTime", startOfDay.toISOString()) + .lte("startTime", endOfDay.toISOString()); + + if (error) { + console.error("Error fetching events:", error); + } + + const data = rawData || []; + + return data.map((event) => ( +
+
+

{event.title}

+ + {new Date(event.startTime).toLocaleTimeString("en-UK", { + hour: "2-digit", + minute: "2-digit", + hour12: false, + })} + +
+

{event.description}

+
+ )); +}; + +export default EventList; diff --git a/src/components/FinanceChart.tsx b/src/components/FinanceChart.tsx new file mode 100644 index 0000000..efe14c8 --- /dev/null +++ b/src/components/FinanceChart.tsx @@ -0,0 +1,126 @@ +"use client"; + +import Image from "next/image"; +import { + LineChart, + Line, + XAxis, + YAxis, + CartesianGrid, + Tooltip, + Legend, + ResponsiveContainer, +} from "recharts"; + +const data = [ + { + name: "Jan", + income: 4000, + expense: 2400, + }, + { + name: "Feb", + income: 3000, + expense: 1398, + }, + { + name: "Mar", + income: 2000, + expense: 9800, + }, + { + name: "Apr", + income: 2780, + expense: 3908, + }, + { + name: "May", + income: 1890, + expense: 4800, + }, + { + name: "Jun", + income: 2390, + expense: 3800, + }, + { + name: "Jul", + income: 3490, + expense: 4300, + }, + { + name: "Aug", + income: 3490, + expense: 4300, + }, + { + name: "Sep", + income: 3490, + expense: 4300, + }, + { + name: "Oct", + income: 3490, + expense: 4300, + }, + { + name: "Nov", + income: 3490, + expense: 4300, + }, + { + name: "Dec", + income: 3490, + expense: 4300, + }, +]; + +const FinanceChart = () => { + return ( +
+
+

Finance

+ +
+ + + + + + + + + + + +
+ ); +}; + +export default FinanceChart; diff --git a/src/components/FormContainer.tsx b/src/components/FormContainer.tsx new file mode 100644 index 0000000..1598156 --- /dev/null +++ b/src/components/FormContainer.tsx @@ -0,0 +1,117 @@ +import { getSupabaseClient } from "@/lib/supabase"; +import FormModal from "./FormModal"; +import { auth } from "@clerk/nextjs/server"; + +export type FormContainerProps = { + table: + | "teacher" + | "student" + | "parent" + | "subject" + | "class" + | "lesson" + | "exam" + | "assignment" + | "result" + | "attendance" + | "event" + | "announcement"; + type: "create" | "update" | "delete"; + data?: any; + id?: number | string; +}; + +const FormContainer = async ({ table, type, data, id }: FormContainerProps) => { + let relatedData = {}; + + const { userId, sessionClaims } = auth(); + const role = (sessionClaims?.metadata as { role?: string })?.role; + const currentUserId = userId; + + if (type !== "delete") { + const supabase = await getSupabaseClient(); + switch (table) { + case "subject": { + const { data: subjectTeachers } = await supabase.from("Teacher").select("id, name, surname"); + relatedData = { teachers: subjectTeachers }; + break; + } + case "class": { + const { data: classGrades } = await supabase.from("Grade").select("id, level"); + const { data: classTeachers } = await supabase.from("Teacher").select("id, name, surname"); + relatedData = { teachers: classTeachers, grades: classGrades }; + break; + } + case "teacher": { + const { data: teacherSubjects } = await supabase.from("Subject").select("id, name"); + relatedData = { subjects: teacherSubjects }; + break; + } + case "student": { + const { data: studentGrades } = await supabase.from("Grade").select("id, level"); + const { data: studentClasses } = await supabase.from("Class").select("*, students:Student(count)"); + const classesWithCount = studentClasses?.map(c => ({ + ...c, + _count: { students: Array.isArray(c.students) ? (c.students as any)[0]?.count || 0 : 0 } + })); + relatedData = { classes: classesWithCount, grades: studentGrades }; + break; + } + case "lesson": { + const { data: lessonSubjects } = await supabase.from("Subject").select("id, name"); + const { data: lessonClasses } = await supabase.from("Class").select("id, name"); + const { data: lessonTeachers } = await supabase.from("Teacher").select("id, name, surname"); + relatedData = { subjects: lessonSubjects, classes: lessonClasses, teachers: lessonTeachers }; + break; + } + case "assignment": { + const { data: assignmentLessons } = await supabase.from("Lesson").select("id, name"); + relatedData = { lessons: assignmentLessons }; + break; + } + case "result": { + const { data: resultStudents } = await supabase.from("Student").select("id, name, surname"); + const { data: resultExams } = await supabase.from("Exam").select("id, title"); + const { data: resultAssignments } = await supabase.from("Assignment").select("id, title"); + relatedData = { students: resultStudents, exams: resultExams, assignments: resultAssignments }; + break; + } + case "exam": { + let query = supabase.from("Lesson").select("id, name"); + if (role === "teacher") { + query = query.eq("teacherId", currentUserId!); + } + const { data: examLessons } = await query; + relatedData = { lessons: examLessons }; + break; + } + + case "event": { + const { data: eventClasses } = await supabase.from("Class").select("id, name"); + relatedData = { classes: eventClasses }; + break; + } + case "announcement": { + const { data: announcementClasses } = await supabase.from("Class").select("id, name"); + relatedData = { classes: announcementClasses }; + break; + } + default: + break; + } + } + + return ( +
+ +
+ ); +}; + +export default FormContainer; diff --git a/src/components/FormModal.tsx b/src/components/FormModal.tsx new file mode 100644 index 0000000..f7806a9 --- /dev/null +++ b/src/components/FormModal.tsx @@ -0,0 +1,246 @@ +"use client"; + +import { + deleteClass, + deleteExam, + deleteStudent, + deleteSubject, + deleteTeacher, + deleteLesson, + deleteAssignment, + deleteResult, + deleteEvent, + deleteAnnouncement, +} from "@/lib/actions"; +import dynamic from "next/dynamic"; +import Image from "next/image"; +import { useRouter } from "next/navigation"; +import { Dispatch, SetStateAction, useEffect, useState } from "react"; +import { useFormState } from "react-dom"; +import { toast } from "react-toastify"; +import { FormContainerProps } from "./FormContainer"; + +const deleteActionMap = { + subject: deleteSubject, + class: deleteClass, + teacher: deleteTeacher, + student: deleteStudent, + exam: deleteExam, + // TODO: OTHER DELETE ACTIONS + parent: deleteSubject, + lesson: deleteLesson, + assignment: deleteAssignment, + result: deleteResult, + attendance: deleteSubject, + event: deleteEvent, + announcement: deleteAnnouncement, +}; + +// USE LAZY LOADING + +// import TeacherForm from "./forms/TeacherForm"; +// import StudentForm from "./forms/StudentForm"; + +const TeacherForm = dynamic(() => import("./forms/TeacherForm"), { + loading: () =>

Loading...

, +}); +const StudentForm = dynamic(() => import("./forms/StudentForm"), { + loading: () =>

Loading...

, +}); +const SubjectForm = dynamic(() => import("./forms/SubjectForm"), { + loading: () =>

Loading...

, +}); +const ClassForm = dynamic(() => import("./forms/ClassForm"), { + loading: () =>

Loading...

, +}); +const ExamForm = dynamic(() => import("./forms/ExamForm"), { + loading: () =>

Loading...

, +}); +const LessonForm = dynamic(() => import("./forms/LessonForm"), { + loading: () =>

Loading...

, +}); +const AssignmentForm = dynamic(() => import("./forms/AssignmentForm"), { + loading: () =>

Loading...

, +}); +const ResultForm = dynamic(() => import("./forms/ResultForm"), { + loading: () =>

Loading...

, +}); +const EventForm = dynamic(() => import("./forms/EventForm"), { + loading: () =>

Loading...

, +}); +const AnnouncementForm = dynamic(() => import("./forms/AnnouncementForm"), { + loading: () =>

Loading...

, +}); +// TODO: OTHER FORMS + +const forms: { + [key: string]: ( + setOpen: Dispatch>, + type: "create" | "update", + data?: any, + relatedData?: any + ) => JSX.Element; +} = { + subject: (setOpen, type, data, relatedData) => ( + + ), + class: (setOpen, type, data, relatedData) => ( + + ), + teacher: (setOpen, type, data, relatedData) => ( + + ), + student: (setOpen, type, data, relatedData) => ( + + ), + exam: (setOpen, type, data, relatedData) => ( + + ), + lesson: (setOpen, type, data, relatedData) => ( + + ), + assignment: (setOpen, type, data, relatedData) => ( + + ), + result: (setOpen, type, data, relatedData) => ( + + ), + event: (setOpen, type, data, relatedData) => ( + + ), + announcement: (setOpen, type, data, relatedData) => ( + + // TODO OTHER LIST ITEMS + ), +}; + +const FormModal = ({ + table, + type, + data, + id, + relatedData, +}: FormContainerProps & { relatedData?: any }) => { + const size = type === "create" ? "w-8 h-8" : "w-7 h-7"; + const bgColor = + type === "create" + ? "bg-lamaYellow" + : type === "update" + ? "bg-lamaSky" + : "bg-lamaPurple"; + + const [open, setOpen] = useState(false); + + const Form = () => { + const [state, formAction] = useFormState(deleteActionMap[table], { + success: false, + error: false, + }); + + const router = useRouter(); + + useEffect(() => { + if (state.success) { + toast(`${table} has been deleted!`); + setOpen(false); + router.refresh(); + } + }, [state, router]); + + return type === "delete" && id ? ( +
+ + + All data will be lost. Are you sure you want to delete this {table}? + + + + ) : type === "create" || type === "update" ? ( + forms[table] ? ( + forms[table](setOpen, type, data, relatedData) + ) : ( + "Form not found!" + ) + ) : ( + "Form not found!" + ); + }; + + return ( + <> + + {open && ( +
+
+
+
setOpen(false)} + > + +
+
+
+ )} + + ); +}; + +export default FormModal; diff --git a/src/components/InputField.tsx b/src/components/InputField.tsx new file mode 100644 index 0000000..baa41cf --- /dev/null +++ b/src/components/InputField.tsx @@ -0,0 +1,41 @@ +import { FieldError } from "react-hook-form"; + +type InputFieldProps = { + label: string; + type?: string; + register: any; + name: string; + defaultValue?: string; + error?: FieldError; + hidden?: boolean; + inputProps?: React.InputHTMLAttributes; +}; + +const InputField = ({ + label, + type = "text", + register, + name, + defaultValue, + error, + hidden, + inputProps, +}: InputFieldProps) => { + return ( +
+ + + {error?.message && ( +

{error.message.toString()}

+ )} +
+ ); +}; + +export default InputField; diff --git a/src/components/Menu.tsx b/src/components/Menu.tsx new file mode 100644 index 0000000..b7c2fba --- /dev/null +++ b/src/components/Menu.tsx @@ -0,0 +1,150 @@ +import { currentUser } from "@clerk/nextjs/server"; +import Image from "next/image"; +import Link from "next/link"; + +const menuItems = [ + { + title: "MENU", + items: [ + { + icon: "/home.png", + label: "Home", + href: "/", + visible: ["admin", "teacher", "student", "parent"], + }, + { + icon: "/teacher.png", + label: "Teachers", + href: "/list/teachers", + visible: ["admin", "teacher"], + }, + { + icon: "/student.png", + label: "Students", + href: "/list/students", + visible: ["admin", "teacher"], + }, + { + icon: "/parent.png", + label: "Parents", + href: "/list/parents", + visible: ["admin", "teacher"], + }, + { + icon: "/subject.png", + label: "Subjects", + href: "/list/subjects", + visible: ["admin"], + }, + { + icon: "/class.png", + label: "Classes", + href: "/list/classes", + visible: ["admin", "teacher"], + }, + { + icon: "/lesson.png", + label: "Lessons", + href: "/list/lessons", + visible: ["admin", "teacher"], + }, + { + icon: "/exam.png", + label: "Exams", + href: "/list/exams", + visible: ["admin", "teacher", "student", "parent"], + }, + { + icon: "/assignment.png", + label: "Assignments", + href: "/list/assignments", + visible: ["admin", "teacher", "student", "parent"], + }, + { + icon: "/result.png", + label: "Results", + href: "/list/results", + visible: ["admin", "teacher", "student", "parent"], + }, + { + icon: "/attendance.png", + label: "Attendance", + href: "/list/attendance", + visible: ["admin", "teacher", "student", "parent"], + }, + { + icon: "/calendar.png", + label: "Events", + href: "/list/events", + visible: ["admin", "teacher", "student", "parent"], + }, + { + icon: "/message.png", + label: "Messages", + href: "/list/messages", + visible: ["admin", "teacher", "student", "parent"], + }, + { + icon: "/announcement.png", + label: "Announcements", + href: "/list/announcements", + visible: ["admin", "teacher", "student", "parent"], + }, + ], + }, + { + title: "OTHER", + items: [ + { + icon: "/profile.png", + label: "Profile", + href: "/profile", + visible: ["admin", "teacher", "student", "parent"], + }, + { + icon: "/setting.png", + label: "Settings", + href: "/settings", + visible: ["admin", "teacher", "student", "parent"], + }, + { + icon: "/logout.png", + label: "Logout", + href: "/logout", + visible: ["admin", "teacher", "student", "parent"], + }, + ], + }, +]; + +const Menu = async () => { + const user = await currentUser(); + const role = user?.publicMetadata.role as string; + return ( +
+ {menuItems.map((i) => ( +
+ + {i.title} + + {i.items.map((item) => { + if (item.visible.includes(role)) { + return ( + + + {item.label} + + ); + } + })} +
+ ))} +
+ ); +}; + +export default Menu; diff --git a/src/components/Navbar.tsx b/src/components/Navbar.tsx new file mode 100644 index 0000000..0a7b058 --- /dev/null +++ b/src/components/Navbar.tsx @@ -0,0 +1,42 @@ +import { UserButton } from "@clerk/nextjs"; +import { currentUser } from "@clerk/nextjs/server"; +import Image from "next/image"; + +const Navbar = async () => { + const user = await currentUser(); + return ( +
+ {/* SEARCH BAR */} +
+ + +
+ {/* ICONS AND USER */} +
+
+ +
+
+ +
+ 1 +
+
+
+ John Doe + + {user?.publicMetadata?.role as string} + +
+ {/* */} + +
+
+ ); +}; + +export default Navbar; diff --git a/src/components/Pagination.tsx b/src/components/Pagination.tsx new file mode 100644 index 0000000..e107a7d --- /dev/null +++ b/src/components/Pagination.tsx @@ -0,0 +1,62 @@ +"use client"; + +import { ITEM_PER_PAGE } from "@/lib/settings"; +import { useRouter } from "next/navigation"; + +const Pagination = ({ page, count }: { page: number; count: number }) => { + const router = useRouter(); + + const hasPrev = ITEM_PER_PAGE * (page - 1) > 0; + const hasNext = ITEM_PER_PAGE * (page - 1) + ITEM_PER_PAGE < count; + + const changePage = (newPage: number) => { + const params = new URLSearchParams(window.location.search); + params.set("page", newPage.toString()); + router.push(`${window.location.pathname}?${params}`); + }; + return ( +
+ +
+ {Array.from( + { length: Math.ceil(count / ITEM_PER_PAGE) }, + (_, index) => { + const pageIndex = index + 1; + return ( + + ); + } + )} +
+ +
+ ); +}; + +export default Pagination; diff --git a/src/components/Performance.tsx b/src/components/Performance.tsx new file mode 100644 index 0000000..17d6f0f --- /dev/null +++ b/src/components/Performance.tsx @@ -0,0 +1,40 @@ +"use client"; +import Image from "next/image"; +import { PieChart, Pie, Sector, Cell, ResponsiveContainer } from "recharts"; + +const data = [ + { name: "Group A", value: 92, fill: "#C3EBFA" }, + { name: "Group B", value: 8, fill: "#FAE27C" }, +]; + +const Performance = () => { + return ( +
+
+

Performance

+ +
+ + + + + +
+

9.2

+

of 10 max LTS

+
+

1st Semester - 2nd Semester

+
+ ); +}; + +export default Performance; diff --git a/src/components/StudentAttendanceCard.tsx b/src/components/StudentAttendanceCard.tsx new file mode 100644 index 0000000..11f407e --- /dev/null +++ b/src/components/StudentAttendanceCard.tsx @@ -0,0 +1,28 @@ +import { getSupabaseClient } from "@/lib/supabase"; + +const StudentAttendanceCard = async ({ id }: { id: string }) => { + const supabase = await getSupabaseClient(); + const { data: attendanceData, error } = await supabase + .from("Attendance") + .select("present") + .eq("studentId", id) + .gte("date", new Date(new Date().getFullYear(), 0, 1).toISOString()); + + if (error) { + console.error("Error fetching student attendance:", error); + } + + const attendance = attendanceData || []; + + const totalDays = attendance.length; + const presentDays = attendance.filter((day) => day.present).length; + const percentage = (presentDays / totalDays) * 100; + return ( +
+

{percentage || "-"}%

+ Attendance +
+ ); +}; + +export default StudentAttendanceCard; diff --git a/src/components/Table.tsx b/src/components/Table.tsx new file mode 100644 index 0000000..bf01eb5 --- /dev/null +++ b/src/components/Table.tsx @@ -0,0 +1,24 @@ +const Table = ({ + columns, + renderRow, + data, +}: { + columns: { header: string; accessor: string; className?: string }[]; + renderRow: (item: any) => React.ReactNode; + data: any[]; +}) => { + return ( +
+ + + {columns.map((col) => ( + + ))} + + + {data.map((item) => renderRow(item))} +
{col.header}
+ ); +}; + +export default Table; diff --git a/src/components/TableSearch.tsx b/src/components/TableSearch.tsx new file mode 100644 index 0000000..ef3badc --- /dev/null +++ b/src/components/TableSearch.tsx @@ -0,0 +1,34 @@ +"use client"; + +import Image from "next/image"; +import { useRouter } from "next/navigation"; + +const TableSearch = () => { + const router = useRouter(); + + const handleSubmit = (e: React.FormEvent) => { + e.preventDefault(); + + const value = (e.currentTarget[0] as HTMLInputElement).value; + + const params = new URLSearchParams(window.location.search); + params.set("search", value); + router.push(`${window.location.pathname}?${params}`); + }; + + return ( + + + + + ); +}; + +export default TableSearch; diff --git a/src/components/UserCard.tsx b/src/components/UserCard.tsx new file mode 100644 index 0000000..15481f1 --- /dev/null +++ b/src/components/UserCard.tsx @@ -0,0 +1,38 @@ +import { getSupabaseClient } from "@/lib/supabase"; +import Image from "next/image"; + +const UserCard = async ({ + type, +}: { + type: "admin" | "teacher" | "student" | "parent"; +}) => { + const supabase = await getSupabaseClient(); + const tableMap: Record = { + admin: "Admin", + teacher: "Teacher", + student: "Student", + parent: "Parent", + }; + const tableName = tableMap[type] as "Admin" | "Teacher" | "Student" | "Parent"; + + const { count } = await supabase + .from(tableName) + .select("*", { count: "exact", head: true }); + + const data = count || 0; + + return ( +
+
+ + 2024/25 + + +
+

{data}

+

{type}s

+
+ ); +}; + +export default UserCard; diff --git a/src/components/forms/AnnouncementForm.tsx b/src/components/forms/AnnouncementForm.tsx new file mode 100644 index 0000000..4fb04f8 --- /dev/null +++ b/src/components/forms/AnnouncementForm.tsx @@ -0,0 +1,133 @@ +"use client"; + +import { zodResolver } from "@hookform/resolvers/zod"; +import { useForm } from "react-hook-form"; +import InputField from "../InputField"; +import { + announcementSchema, + AnnouncementSchema, +} from "@/lib/formValidationSchemas"; +import { + createAnnouncement, + updateAnnouncement, +} from "@/lib/actions"; +import { useFormState } from "react-dom"; +import { Dispatch, SetStateAction, useEffect } from "react"; +import { toast } from "react-toastify"; +import { useRouter } from "next/navigation"; + +const AnnouncementForm = ({ + type, + data, + setOpen, + relatedData, +}: { + type: "create" | "update"; + data?: any; + setOpen: Dispatch>; + relatedData?: any; +}) => { + const { + register, + handleSubmit, + formState: { errors }, + } = useForm({ + resolver: zodResolver(announcementSchema), + }); + + const [state, formAction] = useFormState( + type === "create" ? createAnnouncement : updateAnnouncement, + { + success: false, + error: false, + } + ); + + const onSubmit = handleSubmit((data) => { + formAction(data); + }); + + const router = useRouter(); + + useEffect(() => { + if (state.success) { + toast(`Announcement has been ${type === "create" ? "created" : "updated"}!`); + setOpen(false); + router.refresh(); + } + }, [state, router, type, setOpen]); + + const { classes } = relatedData || {}; + + return ( +
+

+ {type === "create" ? "Create a new announcement" : "Update the announcement"} +

+ +
+ + + {data && ( +
+ {state.error && ( + Something went wrong! + )} + +
+ ); +}; + +export default AnnouncementForm; diff --git a/src/components/forms/AssignmentForm.tsx b/src/components/forms/AssignmentForm.tsx new file mode 100644 index 0000000..606abf5 --- /dev/null +++ b/src/components/forms/AssignmentForm.tsx @@ -0,0 +1,132 @@ +"use client"; + +import { zodResolver } from "@hookform/resolvers/zod"; +import { useForm } from "react-hook-form"; +import InputField from "../InputField"; +import { + assignmentSchema, + AssignmentSchema, +} from "@/lib/formValidationSchemas"; +import { + createAssignment, + updateAssignment, +} from "@/lib/actions"; +import { useFormState } from "react-dom"; +import { Dispatch, SetStateAction, useEffect } from "react"; +import { toast } from "react-toastify"; +import { useRouter } from "next/navigation"; + +const AssignmentForm = ({ + type, + data, + setOpen, + relatedData, +}: { + type: "create" | "update"; + data?: any; + setOpen: Dispatch>; + relatedData?: any; +}) => { + const { + register, + handleSubmit, + formState: { errors }, + } = useForm({ + resolver: zodResolver(assignmentSchema), + }); + + const [state, formAction] = useFormState( + type === "create" ? createAssignment : updateAssignment, + { + success: false, + error: false, + } + ); + + const onSubmit = handleSubmit((data) => { + formAction(data); + }); + + const router = useRouter(); + + useEffect(() => { + if (state.success) { + toast(`Assignment has been ${type === "create" ? "created" : "updated"}!`); + setOpen(false); + router.refresh(); + } + }, [state, router, type, setOpen]); + + const { lessons } = relatedData; + + return ( +
+

+ {type === "create" ? "Create a new assignment" : "Update the assignment"} +

+ +
+ + {data && ( +
+ {state.error && ( + Something went wrong! + )} + +
+ ); +}; + +export default AssignmentForm; diff --git a/src/components/forms/ClassForm.tsx b/src/components/forms/ClassForm.tsx new file mode 100644 index 0000000..a6659a2 --- /dev/null +++ b/src/components/forms/ClassForm.tsx @@ -0,0 +1,157 @@ +"use client"; + +import { zodResolver } from "@hookform/resolvers/zod"; +import { useForm } from "react-hook-form"; +import InputField from "../InputField"; +import { + classSchema, + ClassSchema, + subjectSchema, + SubjectSchema, +} from "@/lib/formValidationSchemas"; +import { + createClass, + createSubject, + updateClass, + updateSubject, +} from "@/lib/actions"; +import { useFormState } from "react-dom"; +import { Dispatch, SetStateAction, useEffect } from "react"; +import { toast } from "react-toastify"; +import { useRouter } from "next/navigation"; + +const ClassForm = ({ + type, + data, + setOpen, + relatedData, +}: { + type: "create" | "update"; + data?: any; + setOpen: Dispatch>; + relatedData?: any; +}) => { + const { + register, + handleSubmit, + formState: { errors }, + } = useForm({ + resolver: zodResolver(classSchema), + }); + + // AFTER REACT 19 IT'LL BE USEACTIONSTATE + + const [state, formAction] = useFormState( + type === "create" ? createClass : updateClass, + { + success: false, + error: false, + } + ); + + const onSubmit = handleSubmit((data) => { + console.log(data); + formAction(data); + }); + + const router = useRouter(); + + useEffect(() => { + if (state.success) { + toast(`Subject has been ${type === "create" ? "created" : "updated"}!`); + setOpen(false); + router.refresh(); + } + }, [state, router, type, setOpen]); + + const { teachers, grades } = relatedData; + + return ( +
+

+ {type === "create" ? "Create a new class" : "Update the class"} +

+ +
+ + + {data && ( +
+ {state.error && ( + Something went wrong! + )} + +
+ ); +}; + +export default ClassForm; diff --git a/src/components/forms/EventForm.tsx b/src/components/forms/EventForm.tsx new file mode 100644 index 0000000..a1daf27 --- /dev/null +++ b/src/components/forms/EventForm.tsx @@ -0,0 +1,142 @@ +"use client"; + +import { zodResolver } from "@hookform/resolvers/zod"; +import { useForm } from "react-hook-form"; +import InputField from "../InputField"; +import { + eventSchema, + EventSchema, +} from "@/lib/formValidationSchemas"; +import { + createEvent, + updateEvent, +} from "@/lib/actions"; +import { useFormState } from "react-dom"; +import { Dispatch, SetStateAction, useEffect } from "react"; +import { toast } from "react-toastify"; +import { useRouter } from "next/navigation"; + +const EventForm = ({ + type, + data, + setOpen, + relatedData, +}: { + type: "create" | "update"; + data?: any; + setOpen: Dispatch>; + relatedData?: any; +}) => { + const { + register, + handleSubmit, + formState: { errors }, + } = useForm({ + resolver: zodResolver(eventSchema), + }); + + const [state, formAction] = useFormState( + type === "create" ? createEvent : updateEvent, + { + success: false, + error: false, + } + ); + + const onSubmit = handleSubmit((data) => { + formAction(data); + }); + + const router = useRouter(); + + useEffect(() => { + if (state.success) { + toast(`Event has been ${type === "create" ? "created" : "updated"}!`); + setOpen(false); + router.refresh(); + } + }, [state, router, type, setOpen]); + + // relatedData parsing + const { classes } = relatedData; + + return ( +
+

+ {type === "create" ? "Create a new event" : "Update the event"} +

+ +
+ + + {data && ( +
+ {state.error && ( + Something went wrong! + )} + +
+ ); +}; + +export default EventForm; diff --git a/src/components/forms/ExamForm.tsx b/src/components/forms/ExamForm.tsx new file mode 100644 index 0000000..a883796 --- /dev/null +++ b/src/components/forms/ExamForm.tsx @@ -0,0 +1,139 @@ +"use client"; + +import { zodResolver } from "@hookform/resolvers/zod"; +import { useForm } from "react-hook-form"; +import InputField from "../InputField"; +import { + examSchema, + ExamSchema, + subjectSchema, + SubjectSchema, +} from "@/lib/formValidationSchemas"; +import { + createExam, + createSubject, + updateExam, + updateSubject, +} from "@/lib/actions"; +import { useFormState } from "react-dom"; +import { Dispatch, SetStateAction, useEffect } from "react"; +import { toast } from "react-toastify"; +import { useRouter } from "next/navigation"; + +const ExamForm = ({ + type, + data, + setOpen, + relatedData, +}: { + type: "create" | "update"; + data?: any; + setOpen: Dispatch>; + relatedData?: any; +}) => { + const { + register, + handleSubmit, + formState: { errors }, + } = useForm({ + resolver: zodResolver(examSchema), + }); + + // AFTER REACT 19 IT'LL BE USEACTIONSTATE + + const [state, formAction] = useFormState( + type === "create" ? createExam : updateExam, + { + success: false, + error: false, + } + ); + + const onSubmit = handleSubmit((data) => { + console.log(data); + formAction(data); + }); + + const router = useRouter(); + + useEffect(() => { + if (state.success) { + toast(`Exam has been ${type === "create" ? "created" : "updated"}!`); + setOpen(false); + router.refresh(); + } + }, [state, router, type, setOpen]); + + const { lessons } = relatedData; + + return ( +
+

+ {type === "create" ? "Create a new exam" : "Update the exam"} +

+ +
+ + + + {data && ( +
+ {state.error && ( + Something went wrong! + )} + +
+ ); +}; + +export default ExamForm; diff --git a/src/components/forms/LessonForm.tsx b/src/components/forms/LessonForm.tsx new file mode 100644 index 0000000..b5740a4 --- /dev/null +++ b/src/components/forms/LessonForm.tsx @@ -0,0 +1,191 @@ +"use client"; + +import { zodResolver } from "@hookform/resolvers/zod"; +import { useForm } from "react-hook-form"; +import InputField from "../InputField"; +import { + lessonSchema, + LessonSchema, +} from "@/lib/formValidationSchemas"; +import { + createLesson, + updateLesson, +} from "@/lib/actions"; +import { useFormState } from "react-dom"; +import { Dispatch, SetStateAction, useEffect } from "react"; +import { toast } from "react-toastify"; +import { useRouter } from "next/navigation"; + +const LessonForm = ({ + type, + data, + setOpen, + relatedData, +}: { + type: "create" | "update"; + data?: any; + setOpen: Dispatch>; + relatedData?: any; +}) => { + const { + register, + handleSubmit, + formState: { errors }, + } = useForm({ + resolver: zodResolver(lessonSchema), + }); + + const [state, formAction] = useFormState( + type === "create" ? createLesson : updateLesson, + { + success: false, + error: false, + } + ); + + const onSubmit = handleSubmit((data) => { + formAction(data); + }); + + const router = useRouter(); + + useEffect(() => { + if (state.success) { + toast(`Lesson has been ${type === "create" ? "created" : "updated"}!`); + setOpen(false); + router.refresh(); + } + }, [state, router, type, setOpen]); + + const { subjects, classes, teachers } = relatedData; + + return ( +
+

+ {type === "create" ? "Create a new lesson" : "Update the lesson"} +

+ +
+ + {data && ( +
+ {state.error && ( + Something went wrong! + )} + +
+ ); +}; + +export default LessonForm; diff --git a/src/components/forms/ResultForm.tsx b/src/components/forms/ResultForm.tsx new file mode 100644 index 0000000..148e417 --- /dev/null +++ b/src/components/forms/ResultForm.tsx @@ -0,0 +1,165 @@ +"use client"; + +import { zodResolver } from "@hookform/resolvers/zod"; +import { useForm } from "react-hook-form"; +import InputField from "../InputField"; +import { + resultSchema, + ResultSchema, +} from "@/lib/formValidationSchemas"; +import { + createResult, + updateResult, +} from "@/lib/actions"; +import { useFormState } from "react-dom"; +import { Dispatch, SetStateAction, useEffect } from "react"; +import { toast } from "react-toastify"; +import { useRouter } from "next/navigation"; + +const ResultForm = ({ + type, + data, + setOpen, + relatedData, +}: { + type: "create" | "update"; + data?: any; + setOpen: Dispatch>; + relatedData?: any; +}) => { + const { + register, + handleSubmit, + formState: { errors }, + } = useForm({ + resolver: zodResolver(resultSchema), + }); + + const [state, formAction] = useFormState( + type === "create" ? createResult : updateResult, + { + success: false, + error: false, + } + ); + + const onSubmit = handleSubmit((data) => { + formAction(data); + }); + + const router = useRouter(); + + useEffect(() => { + if (state.success) { + toast(`Result has been ${type === "create" ? "created" : "updated"}!`); + setOpen(false); + router.refresh(); + } + }, [state, router, type, setOpen]); + + const { students, exams, assignments } = relatedData; + + return ( +
+

+ {type === "create" ? "Create a new result" : "Update the result"} +

+ +
+ + {data && ( +
+ {errors.root && ( + {errors.root.message} + )} + {state.error && ( + Something went wrong! + )} + +
+ ); +}; + +export default ResultForm; diff --git a/src/components/forms/StudentForm.tsx b/src/components/forms/StudentForm.tsx new file mode 100644 index 0000000..62fd4ba --- /dev/null +++ b/src/components/forms/StudentForm.tsx @@ -0,0 +1,261 @@ +"use client"; + +import { zodResolver } from "@hookform/resolvers/zod"; +import { useForm } from "react-hook-form"; +import InputField from "../InputField"; +import Image from "next/image"; +import { Dispatch, SetStateAction, useEffect, useState } from "react"; +import { + studentSchema, + StudentSchema, + teacherSchema, + TeacherSchema, +} from "@/lib/formValidationSchemas"; +import { useFormState } from "react-dom"; +import { + createStudent, + createTeacher, + updateStudent, + updateTeacher, +} from "@/lib/actions"; +import { useRouter } from "next/navigation"; +import { toast } from "react-toastify"; +import { CldUploadWidget } from "next-cloudinary"; + +const StudentForm = ({ + type, + data, + setOpen, + relatedData, +}: { + type: "create" | "update"; + data?: any; + setOpen: Dispatch>; + relatedData?: any; +}) => { + const { + register, + handleSubmit, + formState: { errors }, + } = useForm({ + resolver: zodResolver(studentSchema), + }); + + const [img, setImg] = useState(); + + const [state, formAction] = useFormState( + type === "create" ? createStudent : updateStudent, + { + success: false, + error: false, + } + ); + + const onSubmit = handleSubmit((data) => { + console.log("hello"); + console.log(data); + formAction({ ...data, img: img?.secure_url }); + }); + + const router = useRouter(); + + useEffect(() => { + if (state.success) { + toast(`Student has been ${type === "create" ? "created" : "updated"}!`); + setOpen(false); + router.refresh(); + } + }, [state, router, type, setOpen]); + + const { grades, classes } = relatedData; + + return ( +
+

+ {type === "create" ? "Create a new student" : "Update the student"} +

+ + Authentication Information + +
+ + + +
+ + Personal Information + + { + setImg(result.info); + widget.close(); + }} + > + {({ open }) => { + return ( +
open()} + > + + Upload a photo +
+ ); + }} +
+
+ + + + + + + + {data && ( +
+ {state.error && ( + Something went wrong! + )} + +
+ ); +}; + +export default StudentForm; diff --git a/src/components/forms/SubjectForm.tsx b/src/components/forms/SubjectForm.tsx new file mode 100644 index 0000000..2b7432c --- /dev/null +++ b/src/components/forms/SubjectForm.tsx @@ -0,0 +1,116 @@ +"use client"; + +import { zodResolver } from "@hookform/resolvers/zod"; +import { useForm } from "react-hook-form"; +import InputField from "../InputField"; +import { subjectSchema, SubjectSchema } from "@/lib/formValidationSchemas"; +import { createSubject, updateSubject } from "@/lib/actions"; +import { useFormState } from "react-dom"; +import { Dispatch, SetStateAction, useEffect } from "react"; +import { toast } from "react-toastify"; +import { useRouter } from "next/navigation"; + +const SubjectForm = ({ + type, + data, + setOpen, + relatedData, +}: { + type: "create" | "update"; + data?: any; + setOpen: Dispatch>; + relatedData?: any; +}) => { + const { + register, + handleSubmit, + formState: { errors }, + } = useForm({ + resolver: zodResolver(subjectSchema), + }); + + // AFTER REACT 19 IT'LL BE USEACTIONSTATE + + const [state, formAction] = useFormState( + type === "create" ? createSubject : updateSubject, + { + success: false, + error: false, + } + ); + + const onSubmit = handleSubmit((data) => { + console.log(data); + formAction(data); + }); + + const router = useRouter(); + + useEffect(() => { + if (state.success) { + toast(`Subject has been ${type === "create" ? "created" : "updated"}!`); + setOpen(false); + router.refresh(); + } + }, [state, router, type, setOpen]); + + const { teachers } = relatedData; + + return ( +
+

+ {type === "create" ? "Create a new subject" : "Update the subject"} +

+ +
+ + {data && ( +
+ {state.error && ( + Something went wrong! + )} + +
+ ); +}; + +export default SubjectForm; diff --git a/src/components/forms/TeacherForm.tsx b/src/components/forms/TeacherForm.tsx new file mode 100644 index 0000000..99dcbbd --- /dev/null +++ b/src/components/forms/TeacherForm.tsx @@ -0,0 +1,216 @@ +"use client"; + +import { zodResolver } from "@hookform/resolvers/zod"; +import { useForm } from "react-hook-form"; +import InputField from "../InputField"; +import Image from "next/image"; +import { Dispatch, SetStateAction, useEffect, useState } from "react"; +import { teacherSchema, TeacherSchema } from "@/lib/formValidationSchemas"; +import { useFormState } from "react-dom"; +import { createTeacher, updateTeacher } from "@/lib/actions"; +import { useRouter } from "next/navigation"; +import { toast } from "react-toastify"; +import { CldUploadWidget } from "next-cloudinary"; + +const TeacherForm = ({ + type, + data, + setOpen, + relatedData, +}: { + type: "create" | "update"; + data?: any; + setOpen: Dispatch>; + relatedData?: any; +}) => { + const { + register, + handleSubmit, + formState: { errors }, + } = useForm({ + resolver: zodResolver(teacherSchema), + }); + + const [img, setImg] = useState(); + + const [state, formAction] = useFormState( + type === "create" ? createTeacher : updateTeacher, + { + success: false, + error: false, + } + ); + + const onSubmit = handleSubmit((data) => { + console.log(data); + formAction({ ...data, img: img?.secure_url }); + }); + + const router = useRouter(); + + useEffect(() => { + if (state.success) { + toast(`Teacher has been ${type === "create" ? "created" : "updated"}!`); + setOpen(false); + router.refresh(); + } + }, [state, router, type, setOpen]); + + const { subjects } = relatedData; + + return ( +
+

+ {type === "create" ? "Create a new teacher" : "Update the teacher"} +

+ + Authentication Information + +
+ + + +
+ + Personal Information + +
+ + + + + + + {data && ( +
+ {state.error && ( + Something went wrong! + )} + +
+ ); +}; + +export default TeacherForm; diff --git a/src/lib/actions.ts b/src/lib/actions.ts new file mode 100644 index 0000000..77ed6db --- /dev/null +++ b/src/lib/actions.ts @@ -0,0 +1,818 @@ +"use server"; + +import { revalidatePath } from "next/cache"; +import { + ClassSchema, + ExamSchema, + StudentSchema, + SubjectSchema, + TeacherSchema, + LessonSchema, + AssignmentSchema, + ResultSchema, + EventSchema, + AnnouncementSchema, +} from "./formValidationSchemas"; +import { getSupabaseClient } from "./supabase"; +import { clerkClient } from "@clerk/nextjs/server"; + +type CurrentState = { success: boolean; error: boolean }; + +export const createSubject = async ( + currentState: CurrentState, + data: SubjectSchema +) => { + try { + const supabase = await getSupabaseClient(); + const { data: newSubject, error: subjectError } = await supabase + .from("Subject") + .insert([{ name: data.name }]) + .select() + .single(); + + if (subjectError) throw subjectError; + + if (data.teachers && data.teachers.length > 0) { + const teacherConnections = data.teachers.map((tId) => ({ + subjectId: newSubject.id as number, + teacherId: tId, + })); + const { error: relError } = await supabase + .from("TeacherSubject") + .insert(teacherConnections); + if (relError) throw relError; + } + + return { success: true, error: false }; + } catch (err) { + console.log(err); + return { success: false, error: true }; + } +}; + +export const updateSubject = async ( + currentState: CurrentState, + data: SubjectSchema +) => { + try { + if (!data.id) return { success: false, error: true }; + + const supabase = await getSupabaseClient(); + const { error: subjectError } = await supabase + .from("Subject") + .update({ name: data.name }) + .eq("id", data.id); + + if (subjectError) throw subjectError; + + // To mimic prisma `set` behaviour for m2m, first delete existing relations then insert new + await supabase.from("TeacherSubject").delete().eq("subjectId", data.id); + + if (data.teachers && data.teachers.length > 0) { + const subjectId = data.id as number; + const teacherConnections = data.teachers.map((tId) => ({ + subjectId: subjectId, + teacherId: tId, + })); + const { error: relError } = await supabase + .from("TeacherSubject") + .insert(teacherConnections); + if (relError) throw relError; + } + + return { success: true, error: false }; + } catch (err) { + console.log(err); + return { success: false, error: true }; + } +}; + +export const deleteSubject = async ( + currentState: CurrentState, + data: FormData +) => { + const id = data.get("id") as string; + try { + const supabase = await getSupabaseClient(); + // Assuming cascading delete is setup in Postgres for m2m, else we need to delete from join table first. + const { error } = await supabase.from("Subject").delete().eq("id", parseInt(id)); + if (error) throw error; + + return { success: true, error: false }; + } catch (err) { + console.log(err); + return { success: false, error: true }; + } +}; + +export const createClass = async ( + currentState: CurrentState, + data: ClassSchema +) => { + try { + const supabase = await getSupabaseClient(); + const { error } = await supabase.from("Class").insert([{ + name: data.name, + capacity: data.capacity, + supervisorId: data.supervisorId || null, + gradeId: data.gradeId, + }]); + + if (error) throw error; + return { success: true, error: false }; + } catch (err) { + console.log(err); + return { success: false, error: true }; + } +}; + +export const updateClass = async ( + currentState: CurrentState, + data: ClassSchema +) => { + try { + if (!data.id) return { success: false, error: true }; + const supabase = await getSupabaseClient(); + const { error } = await supabase + .from("Class") + .update({ + name: data.name, + capacity: data.capacity, + supervisorId: data.supervisorId || null, + gradeId: data.gradeId, + }) + .eq("id", data.id); + + if (error) throw error; + return { success: true, error: false }; + } catch (err) { + console.log(err); + return { success: false, error: true }; + } +}; + +export const deleteClass = async ( + currentState: CurrentState, + data: FormData +) => { + const id = data.get("id") as string; + try { + const supabase = await getSupabaseClient(); + const { error } = await supabase.from("Class").delete().eq("id", parseInt(id)); + if (error) throw error; + + return { success: true, error: false }; + } catch (err) { + console.log(err); + return { success: false, error: true }; + } +}; + +export const createTeacher = async ( + currentState: CurrentState, + data: TeacherSchema +) => { + try { + const user = await clerkClient.users.createUser({ + username: data.username, + password: data.password, + firstName: data.name, + lastName: data.surname, + publicMetadata: { role: "teacher" } + }); + + const supabase = await getSupabaseClient(); + const { error: teacherError } = await supabase.from("Teacher").insert([{ + id: user.id, + username: data.username, + name: data.name, + surname: data.surname, + email: data.email || null, + phone: data.phone || null, + address: data.address, + img: data.img || null, + bloodType: data.bloodType, + sex: data.sex, + birthday: data.birthday.toISOString(), + }]); + + if (teacherError) throw teacherError; + + if (data.subjects && data.subjects.length > 0) { + const subjectConnections = data.subjects.map((sId: string) => ({ + subjectId: parseInt(sId), + teacherId: user.id, + })); + const { error: relError } = await supabase + .from("TeacherSubject") + .insert(subjectConnections); + if (relError) throw relError; + } + + return { success: true, error: false }; + } catch (err) { + console.log(err); + return { success: false, error: true }; + } +}; + +export const updateTeacher = async ( + currentState: CurrentState, + data: TeacherSchema +) => { + if (!data.id) { + return { success: false, error: true }; + } + try { + await clerkClient.users.updateUser(data.id, { + username: data.username, + ...(data.password !== "" && { password: data.password }), + firstName: data.name, + lastName: data.surname, + }); + + const supabase = await getSupabaseClient(); + const { error: teacherError } = await supabase.from("Teacher").update({ + ...(data.password !== "" && { password: data.password }), + username: data.username, + name: data.name, + surname: data.surname, + email: data.email || null, + phone: data.phone || null, + address: data.address, + img: data.img || null, + bloodType: data.bloodType, + sex: data.sex, + birthday: data.birthday.toISOString(), + }).eq("id", data.id); + + if (teacherError) throw teacherError; + + await supabase.from("TeacherSubject").delete().eq("teacherId", data.id); + + if (data.subjects && data.subjects.length > 0) { + const subjectConnections = data.subjects.map((sId: string) => ({ + subjectId: parseInt(sId), + teacherId: data.id as string, + })); + const { error: relError } = await supabase + .from("TeacherSubject") + .insert(subjectConnections); + if (relError) throw relError; + } + + return { success: true, error: false }; + } catch (err) { + console.log(err); + return { success: false, error: true }; + } +}; + +export const deleteTeacher = async ( + currentState: CurrentState, + data: FormData +) => { + const id = data.get("id") as string; + try { + await clerkClient.users.deleteUser(id); + + const supabase = await getSupabaseClient(); + const { error: teacherError } = await supabase.from("Teacher").delete().eq("id", id); + if (teacherError) throw teacherError; + + return { success: true, error: false }; + } catch (err) { + console.log(err); + return { success: false, error: true }; + } +}; + +export const createStudent = async ( + currentState: CurrentState, + data: StudentSchema +) => { + console.log(data); + try { + const supabase = await getSupabaseClient(); + const { data: classItems } = await supabase.from("Class").select("capacity, students:Student(count)").eq("id", data.classId); + + const classItem = classItems?.[0]; + const currentStudentsCount = Array.isArray(classItem?.students) ? (classItem?.students as any)[0]?.count || 0 : 0; + + if (classItem && classItem.capacity === currentStudentsCount) { + return { success: false, error: true }; + } + + const user = await clerkClient.users.createUser({ + username: data.username, + password: data.password, + firstName: data.name, + lastName: data.surname, + publicMetadata: { role: "student" } + }); + + const { error: studentError } = await supabase.from("Student").insert([{ + id: user.id, + username: data.username, + name: data.name, + surname: data.surname, + email: data.email || null, + phone: data.phone || null, + address: data.address, + img: data.img || null, + bloodType: data.bloodType, + sex: data.sex, + birthday: data.birthday.toISOString(), + gradeId: data.gradeId, + classId: data.classId, + parentId: data.parentId, + }]); + + if (studentError) throw studentError; + + return { success: true, error: false }; + } catch (err) { + console.log(err); + return { success: false, error: true }; + } +}; + +export const updateStudent = async ( + currentState: CurrentState, + data: StudentSchema +) => { + if (!data.id) { + return { success: false, error: true }; + } + try { + await clerkClient.users.updateUser(data.id, { + username: data.username, + ...(data.password !== "" && { password: data.password }), + firstName: data.name, + lastName: data.surname, + }); + + const supabase = await getSupabaseClient(); + const { error: studentError } = await supabase.from("Student").update({ + ...(data.password !== "" && { password: data.password }), + username: data.username, + name: data.name, + surname: data.surname, + email: data.email || null, + phone: data.phone || null, + address: data.address, + img: data.img || null, + bloodType: data.bloodType, + sex: data.sex, + birthday: data.birthday.toISOString(), + gradeId: data.gradeId, + classId: data.classId, + parentId: data.parentId, + }).eq("id", data.id); + + if (studentError) throw studentError; + + return { success: true, error: false }; + } catch (err) { + console.log(err); + return { success: false, error: true }; + } +}; + +export const deleteStudent = async ( + currentState: CurrentState, + data: FormData +) => { + const id = data.get("id") as string; + try { + await clerkClient.users.deleteUser(id); + + const supabase = await getSupabaseClient(); + const { error: studentError } = await supabase.from("Student").delete().eq("id", id); + if (studentError) throw studentError; + + return { success: true, error: false }; + } catch (err) { + console.log(err); + return { success: false, error: true }; + } +}; + +export const createExam = async ( + currentState: CurrentState, + data: ExamSchema +) => { + try { + const supabase = await getSupabaseClient(); + const { error } = await supabase.from("Exam").insert([{ + title: data.title, + startTime: data.startTime.toISOString(), + endTime: data.endTime.toISOString(), + lessonId: data.lessonId, + }]); + + if (error) throw error; + return { success: true, error: false }; + } catch (err) { + console.log(err); + return { success: false, error: true }; + } +}; + +export const updateExam = async ( + currentState: CurrentState, + data: ExamSchema +) => { + try { + if (!data.id) return { success: false, error: true }; + const supabase = await getSupabaseClient(); + const { error } = await supabase.from("Exam").update({ + title: data.title, + startTime: data.startTime.toISOString(), + endTime: data.endTime.toISOString(), + lessonId: data.lessonId, + }).eq("id", data.id); + + if (error) throw error; + return { success: true, error: false }; + } catch (err) { + console.log(err); + return { success: false, error: true }; + } +}; + +export const deleteExam = async ( + currentState: CurrentState, + data: FormData +) => { + const id = data.get("id") as string; + + try { + const supabase = await getSupabaseClient(); + const { error } = await supabase.from("Exam").delete().eq("id", parseInt(id)); + if (error) throw error; + + return { success: true, error: false }; + } catch (err) { + console.log(err); + return { success: false, error: true }; + } +}; + +export const createLesson = async ( + currentState: CurrentState, + data: LessonSchema +) => { + try { + const supabase = await getSupabaseClient(); + const { error: lessonError } = await supabase + .from("Lesson") + .insert([ + { + name: data.name, + day: data.day, + startTime: data.startTime.toISOString(), + endTime: data.endTime.toISOString(), + subjectId: data.subjectId, + classId: data.classId, + teacherId: data.teacherId, + }, + ]); + + if (lessonError) throw lessonError; + + return { success: true, error: false }; + } catch (err) { + console.log(err); + return { success: false, error: true }; + } +}; + +export const updateLesson = async ( + currentState: CurrentState, + data: LessonSchema +) => { + try { + if (!data.id) return { success: false, error: true }; + + const supabase = await getSupabaseClient(); + const { error: lessonError } = await supabase + .from("Lesson") + .update({ + name: data.name, + day: data.day, + startTime: data.startTime.toISOString(), + endTime: data.endTime.toISOString(), + subjectId: data.subjectId, + classId: data.classId, + teacherId: data.teacherId, + }) + .eq("id", data.id); + + if (lessonError) throw lessonError; + + return { success: true, error: false }; + } catch (err) { + console.log(err); + return { success: false, error: true }; + } +}; + +export const deleteLesson = async ( + currentState: CurrentState, + data: FormData +) => { + const id = data.get("id") as string; + try { + const supabase = await getSupabaseClient(); + const { error } = await supabase.from("Lesson").delete().eq("id", parseInt(id)); + if (error) throw error; + + return { success: true, error: false }; + } catch (err) { + console.log(err); + return { success: false, error: true }; + } +}; + +export const createAssignment = async ( + currentState: CurrentState, + data: AssignmentSchema +) => { + try { + const supabase = await getSupabaseClient(); + const { error: assignmentError } = await supabase + .from("Assignment") + .insert([ + { + title: data.title, + startDate: data.startDate.toISOString(), + dueDate: data.dueDate.toISOString(), + lessonId: data.lessonId, + }, + ]); + + if (assignmentError) throw assignmentError; + + return { success: true, error: false }; + } catch (err) { + console.log(err); + return { success: false, error: true }; + } +}; + +export const updateAssignment = async ( + currentState: CurrentState, + data: AssignmentSchema +) => { + try { + if (!data.id) return { success: false, error: true }; + + const supabase = await getSupabaseClient(); + const { error: assignmentError } = await supabase + .from("Assignment") + .update({ + title: data.title, + startDate: data.startDate.toISOString(), + dueDate: data.dueDate.toISOString(), + lessonId: data.lessonId, + }) + .eq("id", data.id); + + if (assignmentError) throw assignmentError; + + return { success: true, error: false }; + } catch (err) { + console.log(err); + return { success: false, error: true }; + } +}; + +export const deleteAssignment = async ( + currentState: CurrentState, + data: FormData +) => { + const id = data.get("id") as string; + try { + const supabase = await getSupabaseClient(); + const { error } = await supabase.from("Assignment").delete().eq("id", parseInt(id)); + if (error) throw error; + + return { success: true, error: false }; + } catch (err) { + console.log(err); + return { success: false, error: true }; + } +}; + +export const createResult = async ( + currentState: CurrentState, + data: ResultSchema +) => { + try { + const supabase = await getSupabaseClient(); + const { error: resultError } = await supabase + .from("Result") + .insert([ + { + score: data.score, + studentId: data.studentId, + ...(data.examId ? { examId: data.examId } : {}), + ...(data.assignmentId ? { assignmentId: data.assignmentId } : {}), + }, + ]); + + if (resultError) throw resultError; + + return { success: true, error: false }; + } catch (err) { + console.log(err); + return { success: false, error: true }; + } +}; + +export const updateResult = async ( + currentState: CurrentState, + data: ResultSchema +) => { + try { + if (!data.id) return { success: false, error: true }; + + const supabase = await getSupabaseClient(); + const { error: resultError } = await supabase + .from("Result") + .update({ + score: data.score, + studentId: data.studentId, + ...(data.examId ? { examId: data.examId } : {}), + ...(data.assignmentId ? { assignmentId: data.assignmentId } : {}), + }) + .eq("id", data.id); + + if (resultError) throw resultError; + + return { success: true, error: false }; + } catch (err) { + console.log(err); + return { success: false, error: true }; + } +}; + +export const deleteResult = async ( + currentState: CurrentState, + data: FormData +) => { + const id = data.get("id") as string; + try { + const supabase = await getSupabaseClient(); + const { error } = await supabase.from("Result").delete().eq("id", parseInt(id)); + if (error) throw error; + + return { success: true, error: false }; + } catch (err) { + console.log(err); + return { success: false, error: true }; + } +}; + +export const createEvent = async ( + currentState: CurrentState, + data: EventSchema +) => { + try { + const supabase = await getSupabaseClient(); + const { error: eventError } = await supabase + .from("Event") + .insert([ + { + title: data.title, + description: data.description, + startTime: data.startTime.toISOString(), + endTime: data.endTime.toISOString(), + ...(data.classId ? { classId: data.classId } : {}), + }, + ]); + + if (eventError) throw eventError; + + return { success: true, error: false }; + } catch (err) { + console.log(err); + return { success: false, error: true }; + } +}; + +export const updateEvent = async ( + currentState: CurrentState, + data: EventSchema +) => { + try { + if (!data.id) return { success: false, error: true }; + + const supabase = await getSupabaseClient(); + const { error: eventError } = await supabase + .from("Event") + .update({ + title: data.title, + description: data.description, + startTime: data.startTime.toISOString(), + endTime: data.endTime.toISOString(), + ...(data.classId ? { classId: data.classId } : {}), + }) + .eq("id", data.id); + + if (eventError) throw eventError; + + return { success: true, error: false }; + } catch (err) { + console.log(err); + return { success: false, error: true }; + } +}; + +export const deleteEvent = async ( + currentState: CurrentState, + data: FormData +) => { + const id = data.get("id") as string; + try { + const supabase = await getSupabaseClient(); + const { error } = await supabase.from("Event").delete().eq("id", parseInt(id)); + if (error) throw error; + + return { success: true, error: false }; + } catch (err) { + console.log(err); + return { success: false, error: true }; + } +}; + +export const createAnnouncement = async ( + currentState: CurrentState, + data: AnnouncementSchema +) => { + try { + const supabase = await getSupabaseClient(); + const { error: announcementError } = await supabase + .from("Announcement") + .insert([ + { + title: data.title, + description: data.description, + date: data.date.toISOString(), + ...(data.classId ? { classId: data.classId } : {}), + }, + ]); + + if (announcementError) throw announcementError; + + return { success: true, error: false }; + } catch (err) { + console.log(err); + return { success: false, error: true }; + } +}; + +export const updateAnnouncement = async ( + currentState: CurrentState, + data: AnnouncementSchema +) => { + try { + if (!data.id) return { success: false, error: true }; + + const supabase = await getSupabaseClient(); + const { error: announcementError } = await supabase + .from("Announcement") + .update({ + title: data.title, + description: data.description, + date: data.date.toISOString(), + ...(data.classId ? { classId: data.classId } : {}), + }) + .eq("id", data.id); + + if (announcementError) throw announcementError; + + return { success: true, error: false }; + } catch (err) { + console.log(err); + return { success: false, error: true }; + } +}; + +export const deleteAnnouncement = async ( + currentState: CurrentState, + data: FormData +) => { + const id = data.get("id") as string; + try { + const supabase = await getSupabaseClient(); + const { error } = await supabase.from("Announcement").delete().eq("id", parseInt(id)); + if (error) throw error; + + return { success: true, error: false }; + } catch (err) { + console.log(err); + return { success: false, error: true }; + } +}; diff --git a/src/lib/data.ts b/src/lib/data.ts new file mode 100644 index 0000000..01c6e50 --- /dev/null +++ b/src/lib/data.ts @@ -0,0 +1,1063 @@ +// TEMPORARY DATA + +export let role = "student"; + +export const teachersData = [ + { + id: 1, + teacherId: "1234567890", + name: "John Doe", + email: "john@doe.com", + photo: + "https://images.pexels.com/photos/2888150/pexels-photo-2888150.jpeg?auto=compress&cs=tinysrgb&w=1200", + phone: "1234567890", + subjects: ["Math", "Geometry"], + classes: ["1B", "2A", "3C"], + address: "123 Main St, Anytown, USA", + }, + { + id: 2, + teacherId: "1234567890", + name: "Jane Doe", + email: "jane@doe.com", + photo: + "https://images.pexels.com/photos/936126/pexels-photo-936126.jpeg?auto=compress&cs=tinysrgb&w=1200", + phone: "1234567890", + subjects: ["Physics", "Chemistry"], + classes: ["5A", "4B", "3C"], + address: "123 Main St, Anytown, USA", + }, + { + id: 3, + teacherId: "1234567890", + name: "Mike Geller", + email: "mike@geller.com", + photo: + "https://images.pexels.com/photos/428328/pexels-photo-428328.jpeg?auto=compress&cs=tinysrgb&w=1200", + phone: "1234567890", + subjects: ["Biology"], + classes: ["5A", "4B", "3C"], + address: "123 Main St, Anytown, USA", + }, + { + id: 4, + teacherId: "1234567890", + name: "Jay French", + email: "jay@gmail.com", + photo: + "https://images.pexels.com/photos/1187765/pexels-photo-1187765.jpeg?auto=compress&cs=tinysrgb&w=1200", + phone: "1234567890", + subjects: ["History"], + classes: ["5A", "4B", "3C"], + address: "123 Main St, Anytown, USA", + }, + { + id: 5, + teacherId: "1234567890", + name: "Jane Smith", + email: "jane@gmail.com", + photo: + "https://images.pexels.com/photos/1102341/pexels-photo-1102341.jpeg?auto=compress&cs=tinysrgb&w=1200", + phone: "1234567890", + subjects: ["Music", "History"], + classes: ["5A", "4B", "3C"], + address: "123 Main St, Anytown, USA", + }, + { + id: 6, + teacherId: "1234567890", + name: "Anna Santiago", + email: "anna@gmail.com", + photo: + "https://images.pexels.com/photos/712513/pexels-photo-712513.jpeg?auto=compress&cs=tinysrgb&w=1200", + phone: "1234567890", + subjects: ["Physics"], + classes: ["5A", "4B", "3C"], + address: "123 Main St, Anytown, USA", + }, + { + id: 7, + teacherId: "1234567890", + name: "Allen Black", + email: "allen@black.com", + photo: + "https://images.pexels.com/photos/1438081/pexels-photo-1438081.jpeg?auto=compress&cs=tinysrgb&w=1200", + phone: "1234567890", + subjects: ["English", "Spanish"], + classes: ["5A", "4B", "3C"], + address: "123 Main St, Anytown, USA", + }, + { + id: 8, + teacherId: "1234567890", + name: "Ophelia Castro", + email: "ophelia@castro.com", + photo: + "https://images.pexels.com/photos/1036623/pexels-photo-1036623.jpeg?auto=compress&cs=tinysrgb&w=1200", + phone: "1234567890", + subjects: ["Math", "Geometry"], + classes: ["5A", "4B", "3C"], + address: "123 Main St, Anytown, USA", + }, + { + id: 9, + teacherId: "1234567890", + name: "Derek Briggs", + email: "derek@briggs.com", + photo: + "https://images.pexels.com/photos/842980/pexels-photo-842980.jpeg?auto=compress&cs=tinysrgb&w=1200", + phone: "1234567890", + subjects: ["Literature", "English"], + classes: ["5A", "4B", "3C"], + address: "123 Main St, Anytown, USA", + }, + { + id: 10, + teacherId: "1234567890", + name: "John Glover", + email: "john@glover.com", + photo: + "https://images.pexels.com/photos/1043474/pexels-photo-1043474.jpeg?auto=compress&cs=tinysrgb&w=1200", + phone: "1234567890", + subjects: ["Biology"], + classes: ["5A", "4B", "3C"], + address: "123 Main St, Anytown, USA", + }, +]; + +export const studentsData = [ + { + id: 1, + studentId: "1234567890", + name: "John Doe", + email: "john@doe.com", + photo: + "https://images.pexels.com/photos/2888150/pexels-photo-2888150.jpeg?auto=compress&cs=tinysrgb&w=1200", + phone: "1234567890", + grade: 5, + class: "1B", + address: "123 Main St, Anytown, USA", + }, + { + id: 2, + studentId: "1234567890", + name: "Jane Doe", + email: "jane@doe.com", + photo: + "https://images.pexels.com/photos/936126/pexels-photo-936126.jpeg?auto=compress&cs=tinysrgb&w=1200", + phone: "1234567890", + grade: 5, + class: "5A", + address: "123 Main St, Anytown, USA", + }, + { + id: 3, + studentId: "1234567890", + name: "Mike Geller", + email: "mike@geller.com", + photo: + "https://images.pexels.com/photos/428328/pexels-photo-428328.jpeg?auto=compress&cs=tinysrgb&w=1200", + phone: "1234567890", + grade: 5, + class: "5A", + address: "123 Main St, Anytown, USA", + }, + { + id: 4, + studentId: "1234567890", + name: "Jay French", + email: "jay@gmail.com", + photo: + "https://images.pexels.com/photos/1187765/pexels-photo-1187765.jpeg?auto=compress&cs=tinysrgb&w=1200", + phone: "1234567890", + grade: 5, + class: "5A", + address: "123 Main St, Anytown, USA", + }, + { + id: 5, + studentId: "1234567890", + name: "Jane Smith", + email: "jane@gmail.com", + photo: + "https://images.pexels.com/photos/1102341/pexels-photo-1102341.jpeg?auto=compress&cs=tinysrgb&w=1200", + phone: "1234567890", + grade: 5, + class: "5A", + address: "123 Main St, Anytown, USA", + }, + { + id: 6, + studentId: "1234567890", + name: "Anna Santiago", + email: "anna@gmail.com", + photo: + "https://images.pexels.com/photos/712513/pexels-photo-712513.jpeg?auto=compress&cs=tinysrgb&w=1200", + phone: "1234567890", + grade: 5, + class: "5A", + address: "123 Main St, Anytown, USA", + }, + { + id: 7, + studentId: "1234567890", + name: "Allen Black", + email: "allen@black.com", + photo: + "https://images.pexels.com/photos/1438081/pexels-photo-1438081.jpeg?auto=compress&cs=tinysrgb&w=1200", + phone: "1234567890", + grade: 5, + class: "5A", + address: "123 Main St, Anytown, USA", + }, + { + id: 8, + studentId: "1234567890", + name: "Ophelia Castro", + email: "ophelia@castro.com", + photo: + "https://images.pexels.com/photos/1036623/pexels-photo-1036623.jpeg?auto=compress&cs=tinysrgb&w=1200", + phone: "1234567890", + grade: 5, + class: "5A", + address: "123 Main St, Anytown, USA", + }, + { + id: 9, + studentId: "1234567890", + name: "Derek Briggs", + email: "derek@briggs.com", + photo: + "https://images.pexels.com/photos/842980/pexels-photo-842980.jpeg?auto=compress&cs=tinysrgb&w=1200", + phone: "1234567890", + grade: 5, + class: "5A", + address: "123 Main St, Anytown, USA", + }, + { + id: 10, + studentId: "1234567890", + name: "John Glover", + email: "john@glover.com", + photo: + "https://images.pexels.com/photos/1043474/pexels-photo-1043474.jpeg?auto=compress&cs=tinysrgb&w=1200", + phone: "1234567890", + grade: 5, + class: "5A", + address: "123 Main St, Anytown, USA", + }, +]; + +export const parentsData = [ + { + id: 1, + name: "John Doe", + students: ["Sarah Brewer"], + email: "john@doe.com", + phone: "1234567890", + address: "123 Main St, Anytown, USA", + }, + { + id: 2, + name: "Jane Doe", + students: ["Cecilia Bradley"], + email: "jane@doe.com", + phone: "1234567890", + address: "123 Main St, Anytown, USA", + }, + { + id: 3, + name: "Mike Geller", + students: ["Fanny Caldwell"], + email: "mike@geller.com", + phone: "1234567890", + address: "123 Main St, Anytown, USA", + }, + { + id: 4, + name: "Jay French", + students: ["Mollie Fitzgerald", "Ian Bryant"], + email: "mike@geller.com", + phone: "1234567890", + address: "123 Main St, Anytown, USA", + }, + { + id: 5, + name: "Jane Smith", + students: ["Mable Harvey"], + email: "mike@geller.com", + phone: "1234567890", + address: "123 Main St, Anytown, USA", + }, + { + id: 6, + name: "Anna Santiago", + students: ["Joel Lambert"], + email: "mike@geller.com", + phone: "1234567890", + address: "123 Main St, Anytown, USA", + }, + { + id: 7, + name: "Allen Black", + students: ["Carrie Tucker", "Lilly Underwood"], + email: "mike@geller.com", + phone: "1234567890", + address: "123 Main St, Anytown, USA", + }, + { + id: 8, + name: "Ophelia Castro", + students: ["Alexander Blair"], + email: "mike@geller.com", + phone: "1234567890", + address: "123 Main St, Anytown, USA", + }, + { + id: 9, + name: "Derek Briggs", + students: ["Susan Webster", "Maude Stone"], + email: "mike@geller.com", + phone: "1234567890", + address: "123 Main St, Anytown, USA", + }, + { + id: 10, + name: "John Glover", + students: ["Stella Scott"], + email: "mike@geller.com", + phone: "1234567890", + address: "123 Main St, Anytown, USA", + }, +]; + +export const subjectsData = [ + { + id: 1, + name: "Math", + teachers: ["Alice Phelps", "Russell Davidson"], + }, + { + id: 2, + name: "English", + teachers: ["Manuel Becker", "Eddie Chavez"], + }, + { + id: 3, + name: "Physics", + teachers: ["Lola Newman", "Darrell Delgado"], + }, + { + id: 4, + name: "Chemistry", + teachers: ["Nathan Kelly", "Benjamin Snyder"], + }, + { + id: 5, + name: "Biology", + teachers: ["Alma Benson", "Lina Collier"], + }, + { + id: 6, + name: "History", + teachers: ["Hannah Bowman", "Betty Obrien"], + }, + { + id: 7, + name: "Geography", + teachers: ["Lora French", "Sue Brady"], + }, + { + id: 8, + name: "Art", + teachers: ["Harriet Alvarado", "Mayme Keller"], + }, + { + id: 9, + name: "Music", + teachers: ["Gertrude Roy", "Rosa Singleton"], + }, + { + id: 10, + name: "Literature", + teachers: ["Effie Lynch", "Brett Flowers"], + }, +]; + +export const classesData = [ + { + id: 1, + name: "1A", + capacity: 20, + grade: 1, + supervisor: "Joseph Padilla", + }, + { + id: 2, + name: "2B", + capacity: 22, + grade: 2, + supervisor: "Blake Joseph", + }, + { + id: 3, + name: "3C", + capacity: 20, + grade: 3, + supervisor: "Tom Bennett", + }, + { + id: 4, + name: "4B", + capacity: 18, + grade: 4, + supervisor: "Aaron Collins", + }, + { + id: 5, + name: "5A", + capacity: 16, + grade: 5, + supervisor: "Iva Frank", + }, + { + id: 5, + name: "5B", + capacity: 20, + grade: 5, + supervisor: "Leila Santos", + }, + { + id: 7, + name: "7A", + capacity: 18, + grade: 7, + supervisor: "Carrie Walton", + }, + { + id: 8, + name: "6B", + capacity: 22, + grade: 6, + supervisor: "Christopher Butler", + }, + { + id: 9, + name: "6C", + capacity: 18, + grade: 6, + supervisor: "Marc Miller", + }, + { + id: 10, + name: "6D", + capacity: 20, + grade: 6, + supervisor: "Ophelia Marsh", + }, +]; + +export const lessonsData = [ + { + id: 1, + subject: "Math", + class: "1A", + teacher: "Tommy Wise", + }, + { + id: 2, + subject: "English", + class: "2A", + teacher: "Rhoda Frank", + }, + { + id: 3, + subject: "Science", + class: "3A", + teacher: "Della Dunn", + }, + { + id: 4, + subject: "Social Studies", + class: "1B", + teacher: "Bruce Rodriguez", + }, + { + id: 5, + subject: "Art", + class: "4A", + teacher: "Birdie Butler", + }, + { + id: 6, + subject: "Music", + class: "5A", + teacher: "Bettie Oliver", + }, + { + id: 7, + subject: "History", + class: "6A", + teacher: "Herman Howard", + }, + { + id: 8, + subject: "Geography", + class: "6B", + teacher: "Lucinda Thomas", + }, + { + id: 9, + subject: "Physics", + class: "6C", + teacher: "Ronald Roberts", + }, + { + id: 10, + subject: "Chemistry", + class: "4B", + teacher: "Julia Pittman", + }, +]; + +export const examsData = [ + { + id: 1, + subject: "Math", + class: "1A", + teacher: "Martha Morris", + date: "2025-01-01", + }, + { + id: 2, + subject: "English", + class: "2A", + teacher: "Randall Garcia", + date: "2025-01-01", + }, + { + id: 3, + subject: "Science", + class: "3A", + teacher: "Myrtie Scott", + date: "2025-01-01", + }, + { + id: 4, + subject: "Social Studies", + class: "1B", + teacher: "Alvin Swanson", + date: "2025-01-01", + }, + { + id: 5, + subject: "Art", + class: "4A", + teacher: "Mabelle Wallace", + date: "2025-01-01", + }, + { + id: 6, + subject: "Music", + class: "5A", + teacher: "Dale Thompson", + date: "2025-01-01", + }, + { + id: 7, + subject: "History", + class: "6A", + teacher: "Allie Conner", + date: "2025-01-01", + }, + { + id: 8, + subject: "Geography", + class: "6B", + teacher: "Hunter Fuller", + date: "2025-01-01", + }, + { + id: 9, + subject: "Physics", + class: "7A", + teacher: "Lois Lindsey", + date: "2025-01-01", + }, + { + id: 10, + subject: "Chemistry", + class: "8A", + teacher: "Vera Soto", + date: "2025-01-01", + }, +]; + +export const assignmentsData = [ + { + id: 1, + subject: "Math", + class: "1A", + teacher: "Anthony Boone", + dueDate: "2025-01-01", + }, + { + id: 2, + subject: "English", + class: "2A", + teacher: "Clifford Bowen", + dueDate: "2025-01-01", + }, + { + id: 3, + subject: "Science", + class: "3A", + teacher: "Catherine Malone", + dueDate: "2025-01-01", + }, + { + id: 4, + subject: "Social Studies", + class: "1B", + teacher: "Willie Medina", + dueDate: "2025-01-01", + }, + { + id: 5, + subject: "Art", + class: "4A", + teacher: "Jose Ruiz", + dueDate: "2025-01-01", + }, + { + id: 6, + subject: "Music", + class: "5A", + teacher: "Katharine Owens", + dueDate: "2025-01-01", + }, + { + id: 7, + subject: "History", + class: "6A", + teacher: "Shawn Norman", + dueDate: "2025-01-01", + }, + { + id: 8, + subject: "Geography", + class: "6B", + teacher: "Don Holloway", + dueDate: "2025-01-01", + }, + { + id: 9, + subject: "Physics", + class: "7A", + teacher: "Franklin Gregory", + dueDate: "2025-01-01", + }, + { + id: 10, + subject: "Chemistry", + class: "8A", + teacher: "Danny Nguyen", + dueDate: "2025-01-01", + }, +]; + +export const resultsData = [ + { + id: 1, + subject: "Math", + class: "1A", + teacher: "John Doe", + student: "John Doe", + date: "2025-01-01", + type: "exam", + score: 90, + }, + { + id: 2, + subject: "English", + class: "2A", + teacher: "John Doe", + student: "John Doe", + date: "2025-01-01", + type: "exam", + score: 90, + }, + { + id: 3, + subject: "Science", + class: "3A", + teacher: "John Doe", + student: "John Doe", + date: "2025-01-01", + type: "exam", + score: 90, + }, + { + id: 4, + subject: "Social Studies", + class: "1B", + teacher: "John Doe", + student: "John Doe", + date: "2025-01-01", + type: "exam", + score: 90, + }, + { + id: 5, + subject: "Art", + class: "4A", + teacher: "John Doe", + student: "John Doe", + date: "2025-01-01", + type: "exam", + score: 90, + }, + { + id: 6, + subject: "Music", + class: "5A", + teacher: "John Doe", + student: "John Doe", + date: "2025-01-01", + type: "exam", + score: 90, + }, + { + id: 7, + subject: "History", + class: "6A", + teacher: "John Doe", + student: "John Doe", + date: "2025-01-01", + type: "exam", + score: 90, + }, + { + id: 8, + subject: "Geography", + class: "6B", + teacher: "John Doe", + student: "John Doe", + date: "2025-01-01", + type: "exam", + score: 90, + }, + { + id: 9, + subject: "Physics", + class: "7A", + teacher: "John Doe", + student: "John Doe", + date: "2025-01-01", + type: "exam", + score: 90, + }, + { + id: 10, + subject: "Chemistry", + class: "8A", + teacher: "John Doe", + student: "John Doe", + date: "2025-01-01", + type: "exam", + score: 90, + }, +]; + +export const eventsData = [ + { + id: 1, + title: "Lake Trip", + class: "1A", + date: "2025-01-01", + startTime: "10:00", + endTime: "11:00", + }, + { + id: 2, + title: "Picnic", + class: "2A", + date: "2025-01-01", + startTime: "10:00", + endTime: "11:00", + }, + { + id: 3, + title: "Beach Trip", + class: "3A", + date: "2025-01-01", + startTime: "10:00", + endTime: "11:00", + }, + { + id: 4, + title: "Museum Trip", + class: "4A", + date: "2025-01-01", + startTime: "10:00", + endTime: "11:00", + }, + { + id: 5, + title: "Music Concert", + class: "5A", + date: "2025-01-01", + startTime: "10:00", + endTime: "11:00", + }, + { + id: 6, + title: "Magician Show", + class: "1B", + date: "2025-01-01", + startTime: "10:00", + endTime: "11:00", + }, + { + id: 7, + title: "Lake Trip", + class: "2B", + date: "2025-01-01", + startTime: "10:00", + endTime: "11:00", + }, + { + id: 8, + title: "Cycling Race", + class: "3B", + date: "2025-01-01", + startTime: "10:00", + endTime: "11:00", + }, + { + id: 9, + title: "Art Exhibition", + class: "4B", + date: "2025-01-01", + startTime: "10:00", + endTime: "11:00", + }, + { + id: 10, + title: "Sports Tournament", + class: "5B", + date: "2025-01-01", + startTime: "10:00", + endTime: "11:00", + }, +]; + +export const announcementsData = [ + { + id: 1, + title: "About 4A Math Test", + class: "4A", + date: "2025-01-01", + }, + { + id: 2, + title: "About 3A Math Test", + class: "3A", + date: "2025-01-01", + }, + { + id: 3, + title: "About 3B Math Test", + class: "3B", + date: "2025-01-01", + }, + { + id: 4, + title: "About 6A Math Test", + class: "6A", + date: "2025-01-01", + }, + { + id: 5, + title: "About 8C Math Test", + class: "8C", + date: "2025-01-01", + }, + { + id: 6, + title: "About 2A Math Test", + class: "2A", + date: "2025-01-01", + }, + { + id: 7, + title: "About 4C Math Test", + class: "4C", + date: "2025-01-01", + }, + { + id: 8, + title: "About 4B Math Test", + class: "4B", + date: "2025-01-01", + }, + { + id: 9, + title: "About 3C Math Test", + class: "3C", + date: "2025-01-01", + }, + { + id: 10, + title: "About 1C Math Test", + class: "1C", + date: "2025-01-01", + }, +]; + + +// YOU SHOULD CHANGE THE DATES OF THE EVENTS TO THE CURRENT DATE TO SEE THE EVENTS ON THE CALENDAR +export const calendarEvents = [ + { + title: "Math", + allDay: false, + start: new Date(2024, 7, 12, 8, 0), + end: new Date(2024, 7, 12, 8, 45), + }, + { + title: "English", + allDay: false, + start: new Date(2024, 7, 12, 9, 0), + end: new Date(2024, 7, 12, 9, 45), + }, + { + title: "Biology", + allDay: false, + start: new Date(2024, 7, 12, 10, 0), + end: new Date(2024, 7, 12, 10, 45), + }, + { + title: "Physics", + allDay: false, + start: new Date(2024, 7, 12, 11, 0), + end: new Date(2024, 7, 12, 11, 45), + }, + { + title: "Chemistry", + allDay: false, + start: new Date(2024, 7, 12, 13, 0), + end: new Date(2024, 7, 12, 13, 45), + }, + { + title: "History", + allDay: false, + start: new Date(2024, 7, 12, 14, 0), + end: new Date(2024, 7, 12, 14, 45), + }, + { + title: "English", + allDay: false, + start: new Date(2024, 7, 13, 9, 0), + end: new Date(2024, 7, 13, 9, 45), + }, + { + title: "Biology", + allDay: false, + start: new Date(2024, 7, 13, 10, 0), + end: new Date(2024, 7, 13, 10, 45), + }, + { + title: "Physics", + allDay: false, + start: new Date(2024, 7, 13, 11, 0), + end: new Date(2024, 7, 13, 11, 45), + }, + + { + title: "History", + allDay: false, + start: new Date(2024, 7, 13, 14, 0), + end: new Date(2024, 7, 13, 14, 45), + }, + { + title: "Math", + allDay: false, + start: new Date(2024, 7, 14, 8, 0), + end: new Date(2024, 7, 14, 8, 45), + }, + { + title: "Biology", + allDay: false, + start: new Date(2024, 7, 14, 10, 0), + end: new Date(2024, 7, 14, 10, 45), + }, + + { + title: "Chemistry", + allDay: false, + start: new Date(2024, 7, 14, 13, 0), + end: new Date(2024, 7, 14, 13, 45), + }, + { + title: "History", + allDay: false, + start: new Date(2024, 7, 14, 14, 0), + end: new Date(2024, 7, 13, 14, 45), + }, + { + title: "English", + allDay: false, + start: new Date(2024, 7, 15, 9, 0), + end: new Date(2024, 7, 15, 9, 45), + }, + { + title: "Biology", + allDay: false, + start: new Date(2024, 7, 15, 10, 0), + end: new Date(2024, 7, 15, 10, 45), + }, + { + title: "Physics", + allDay: false, + start: new Date(2024, 7, 15, 11, 0), + end: new Date(2024, 7, 15, 11, 45), + }, + + { + title: "History", + allDay: false, + start: new Date(2024, 7, 15, 14, 0), + end: new Date(2024, 7, 15, 14, 45), + }, + { + title: "Math", + allDay: false, + start: new Date(2024, 7, 16, 8, 0), + end: new Date(2024, 7, 16, 8, 45), + }, + { + title: "English", + allDay: false, + start: new Date(2024, 7, 16, 9, 0), + end: new Date(2024, 7, 16, 9, 45), + }, + + { + title: "Physics", + allDay: false, + start: new Date(2024, 7, 16, 11, 0), + end: new Date(2024, 7, 16, 11, 45), + }, + { + title: "Chemistry", + allDay: false, + start: new Date(2024, 7, 16, 13, 0), + end: new Date(2024, 7, 16, 13, 45), + }, + { + title: "History", + allDay: false, + start: new Date(2024, 7, 16, 14, 0), + end: new Date(2024, 7, 16, 14, 45), + }, +]; \ No newline at end of file diff --git a/src/lib/formValidationSchemas.ts b/src/lib/formValidationSchemas.ts new file mode 100644 index 0000000..3c99832 --- /dev/null +++ b/src/lib/formValidationSchemas.ts @@ -0,0 +1,146 @@ +import { z } from "zod"; + +export const subjectSchema = z.object({ + id: z.coerce.number().optional(), + name: z.string().min(1, { message: "Subject name is required!" }), + teachers: z.array(z.string()), //teacher ids +}); + +export type SubjectSchema = z.infer; + +export const classSchema = z.object({ + id: z.coerce.number().optional(), + name: z.string().min(1, { message: "Subject name is required!" }), + capacity: z.coerce.number().min(1, { message: "Capacity name is required!" }), + gradeId: z.coerce.number().min(1, { message: "Grade name is required!" }), + supervisorId: z.coerce.string().optional(), +}); + +export type ClassSchema = z.infer; + +export const teacherSchema = z.object({ + id: z.string().optional(), + username: z + .string() + .min(3, { message: "Username must be at least 3 characters long!" }) + .max(20, { message: "Username must be at most 20 characters long!" }), + password: z + .string() + .min(8, { message: "Password must be at least 8 characters long!" }) + .optional() + .or(z.literal("")), + name: z.string().min(1, { message: "First name is required!" }), + surname: z.string().min(1, { message: "Last name is required!" }), + email: z + .string() + .email({ message: "Invalid email address!" }) + .optional() + .or(z.literal("")), + phone: z.string().optional(), + address: z.string(), + img: z.string().optional(), + bloodType: z.string().min(1, { message: "Blood Type is required!" }), + birthday: z.coerce.date({ message: "Birthday is required!" }), + sex: z.enum(["MALE", "FEMALE"], { message: "Sex is required!" }), + subjects: z.array(z.string()).optional(), // subject ids +}); + +export type TeacherSchema = z.infer; + +export const studentSchema = z.object({ + id: z.string().optional(), + username: z + .string() + .min(3, { message: "Username must be at least 3 characters long!" }) + .max(20, { message: "Username must be at most 20 characters long!" }), + password: z + .string() + .min(8, { message: "Password must be at least 8 characters long!" }) + .optional() + .or(z.literal("")), + name: z.string().min(1, { message: "First name is required!" }), + surname: z.string().min(1, { message: "Last name is required!" }), + email: z + .string() + .email({ message: "Invalid email address!" }) + .optional() + .or(z.literal("")), + phone: z.string().optional(), + address: z.string(), + img: z.string().optional(), + bloodType: z.string().min(1, { message: "Blood Type is required!" }), + birthday: z.coerce.date({ message: "Birthday is required!" }), + sex: z.enum(["MALE", "FEMALE"], { message: "Sex is required!" }), + gradeId: z.coerce.number().min(1, { message: "Grade is required!" }), + classId: z.coerce.number().min(1, { message: "Class is required!" }), + parentId: z.string().min(1, { message: "Parent Id is required!" }), +}); + +export type StudentSchema = z.infer; + +export const examSchema = z.object({ + id: z.coerce.number().optional(), + title: z.string().min(1, { message: "Title name is required!" }), + startTime: z.coerce.date({ message: "Start time is required!" }), + endTime: z.coerce.date({ message: "End time is required!" }), + lessonId: z.coerce.number({ message: "Lesson is required!" }), +}); + +export type ExamSchema = z.infer; + +export const lessonSchema = z.object({ + id: z.coerce.number().optional(), + name: z.string().min(1, { message: "Lesson name is required!" }), + day: z.enum(["MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY"], { message: "Day is required!" }), + startTime: z.coerce.date({ message: "Start time is required!" }), + endTime: z.coerce.date({ message: "End time is required!" }), + subjectId: z.coerce.number({ message: "Subject is required!" }), + classId: z.coerce.number({ message: "Class is required!" }), + teacherId: z.string({ message: "Teacher is required!" }), +}); + +export type LessonSchema = z.infer; + +export const assignmentSchema = z.object({ + id: z.coerce.number().optional(), + title: z.string().min(1, { message: "Assignment title is required!" }), + startDate: z.coerce.date({ message: "Start date is required!" }), + dueDate: z.coerce.date({ message: "Due date is required!" }), + lessonId: z.coerce.number({ message: "Lesson is required!" }), +}); + +export type AssignmentSchema = z.infer; + +export const resultSchema = z.object({ + id: z.coerce.number().optional(), + score: z.coerce.number().min(0).max(100, { message: "Score must be between 0 and 100!" }), + studentId: z.string({ message: "Student is required!" }), + examId: z.coerce.number().optional(), + assignmentId: z.coerce.number().optional(), +}).refine(data => data.examId || data.assignmentId, { + message: "Either Exam or Assignment is required", + path: ["examId"], +}); + +export type ResultSchema = z.infer; + +export const eventSchema = z.object({ + id: z.coerce.number().optional(), + title: z.string().min(1, { message: "Title is required!" }), + description: z.string().min(1, { message: "Description is required!" }), + startTime: z.coerce.date({ message: "Start time is required!" }), + endTime: z.coerce.date({ message: "End time is required!" }), + classId: z.coerce.number().optional(), +}); + +export type EventSchema = z.infer; + +export const announcementSchema = z.object({ + id: z.coerce.number().optional(), + title: z.string().min(1, { message: "Title is required!" }), + description: z.string().min(1, { message: "Description is required!" }), + date: z.coerce.date({ message: "Date is required!" }), + classId: z.coerce.number().optional(), +}); + +export type AnnouncementSchema = z.infer; diff --git a/src/lib/settings.ts b/src/lib/settings.ts new file mode 100644 index 0000000..90dd4fa --- /dev/null +++ b/src/lib/settings.ts @@ -0,0 +1,23 @@ +export const ITEM_PER_PAGE = 10 + +type RouteAccessMap = { + [key: string]: string[]; +}; + +export const routeAccessMap: RouteAccessMap = { + "/admin(.*)": ["admin"], + "/student(.*)": ["student"], + "/teacher(.*)": ["teacher"], + "/parent(.*)": ["parent"], + "/list/teachers": ["admin", "teacher"], + "/list/students": ["admin", "teacher"], + "/list/parents": ["admin", "teacher"], + "/list/subjects": ["admin"], + "/list/classes": ["admin", "teacher"], + "/list/exams": ["admin", "teacher", "student", "parent"], + "/list/assignments": ["admin", "teacher", "student", "parent"], + "/list/results": ["admin", "teacher", "student", "parent"], + "/list/attendance": ["admin", "teacher", "student", "parent"], + "/list/events": ["admin", "teacher", "student", "parent"], + "/list/announcements": ["admin", "teacher", "student", "parent"], +}; \ No newline at end of file diff --git a/src/lib/supabase.ts b/src/lib/supabase.ts new file mode 100644 index 0000000..d8936e6 --- /dev/null +++ b/src/lib/supabase.ts @@ -0,0 +1,30 @@ +import { createClient } from '@supabase/supabase-js' +import { auth } from '@clerk/nextjs/server' +import { Database } from '@/types/supabase' + +// Initialize the Supabase client +const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL! +const supabaseAnonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY! + +export const getSupabaseClient = async () => { + const { getToken } = auth() + + const supabaseAccessToken = await getToken({ template: 'supabase' }) + if (supabaseAccessToken) { + console.log("Token decodes to:", JSON.parse(Buffer.from(supabaseAccessToken.split('.')[1], 'base64').toString())); + } + + const supabase = createClient( + supabaseUrl, + supabaseAnonKey, + { + global: { + headers: { + Authorization: `Bearer ${supabaseAccessToken}`, + }, + }, + } + ) + + return supabase +} diff --git a/src/lib/utils.ts b/src/lib/utils.ts new file mode 100644 index 0000000..33082d2 --- /dev/null +++ b/src/lib/utils.ts @@ -0,0 +1,45 @@ +// IT APPEARS THAT BIG CALENDAR SHOWS THE LAST WEEK WHEN THE CURRENT DAY IS A WEEKEND. +// FOR THIS REASON WE'LL GET THE LAST WEEK AS THE REFERENCE WEEK. +// IN THE TUTORIAL WE'RE TAKING THE NEXT WEEK AS THE REFERENCE WEEK. + +const getLatestMonday = (): Date => { + const today = new Date(); + const dayOfWeek = today.getDay(); + const daysSinceMonday = dayOfWeek === 0 ? 6 : dayOfWeek - 1; + const latestMonday = today; + latestMonday.setDate(today.getDate() - daysSinceMonday); + return latestMonday; +}; + +export const adjustScheduleToCurrentWeek = ( + lessons: { title: string; start: Date; end: Date }[] +): { title: string; start: Date; end: Date }[] => { + const latestMonday = getLatestMonday(); + + return lessons.map((lesson) => { + const lessonDayOfWeek = lesson.start.getDay(); + + const daysFromMonday = lessonDayOfWeek === 0 ? 6 : lessonDayOfWeek - 1; + + const adjustedStartDate = new Date(latestMonday); + + adjustedStartDate.setDate(latestMonday.getDate() + daysFromMonday); + adjustedStartDate.setHours( + lesson.start.getHours(), + lesson.start.getMinutes(), + lesson.start.getSeconds() + ); + const adjustedEndDate = new Date(adjustedStartDate); + adjustedEndDate.setHours( + lesson.end.getHours(), + lesson.end.getMinutes(), + lesson.end.getSeconds() + ); + + return { + title: lesson.title, + start: adjustedStartDate, + end: adjustedEndDate, + }; + }); +}; diff --git a/src/middleware.ts b/src/middleware.ts new file mode 100644 index 0000000..f4b9a89 --- /dev/null +++ b/src/middleware.ts @@ -0,0 +1,33 @@ +import { clerkMiddleware, createRouteMatcher } from "@clerk/nextjs/server"; +import { routeAccessMap } from "./lib/settings"; +import { NextResponse } from "next/server"; + +const matchers = Object.keys(routeAccessMap).map((route) => ({ + matcher: createRouteMatcher([route]), + allowedRoles: routeAccessMap[route], +})); + +console.log(matchers); + +export default clerkMiddleware((auth, req) => { + // if (isProtectedRoute(req)) auth().protect() + + const { sessionClaims } = auth(); + + const role = (sessionClaims?.metadata as { role?: string })?.role; + + for (const { matcher, allowedRoles } of matchers) { + if (matcher(req) && !allowedRoles.includes(role!)) { + return NextResponse.redirect(new URL(`/${role}`, req.url)); + } + } +}); + +export const config = { + matcher: [ + // Skip Next.js internals and all static files, unless found in search params + "/((?!_next|[^?]*\\.(?:html?|css|js(?!on)|jpe?g|webp|png|gif|svg|ttf|woff2?|ico|csv|docx?|xlsx?|zip|webmanifest)).*)", + // Always run for API routes + "/(api|trpc)(.*)", + ], +}; diff --git a/src/types/supabase.ts b/src/types/supabase.ts new file mode 100644 index 0000000..9884d23 --- /dev/null +++ b/src/types/supabase.ts @@ -0,0 +1,738 @@ +export type Json = + | string + | number + | boolean + | null + | { [key: string]: Json | undefined } + | Json[] + +export type Database = { + graphql_public: { + Tables: { + [_ in never]: never + } + Views: { + [_ in never]: never + } + Functions: { + graphql: { + Args: { + extensions?: Json + operationName?: string + query?: string + variables?: Json + } + Returns: Json + } + } + Enums: { + [_ in never]: never + } + CompositeTypes: { + [_ in never]: never + } + } + public: { + Tables: { + Admin: { + Row: { + id: string + username: string + } + Insert: { + id: string + username: string + } + Update: { + id?: string + username?: string + } + Relationships: [] + } + Announcement: { + Row: { + classId: number | null + date: string + description: string + id: number + title: string + } + Insert: { + classId?: number | null + date: string + description: string + id?: number + title: string + } + Update: { + classId?: number | null + date?: string + description?: string + id?: number + title?: string + } + Relationships: [ + { + foreignKeyName: "Announcement_classId_fkey" + columns: ["classId"] + isOneToOne: false + referencedRelation: "Class" + referencedColumns: ["id"] + }, + ] + } + Assignment: { + Row: { + dueDate: string + id: number + lessonId: number + startDate: string + title: string + } + Insert: { + dueDate: string + id?: number + lessonId: number + startDate: string + title: string + } + Update: { + dueDate?: string + id?: number + lessonId?: number + startDate?: string + title?: string + } + Relationships: [ + { + foreignKeyName: "Assignment_lessonId_fkey" + columns: ["lessonId"] + isOneToOne: false + referencedRelation: "Lesson" + referencedColumns: ["id"] + }, + ] + } + Attendance: { + Row: { + date: string + id: number + lessonId: number + present: boolean + studentId: string + } + Insert: { + date: string + id?: number + lessonId: number + present: boolean + studentId: string + } + Update: { + date?: string + id?: number + lessonId?: number + present?: boolean + studentId?: string + } + Relationships: [ + { + foreignKeyName: "Attendance_lessonId_fkey" + columns: ["lessonId"] + isOneToOne: false + referencedRelation: "Lesson" + referencedColumns: ["id"] + }, + { + foreignKeyName: "Attendance_studentId_fkey" + columns: ["studentId"] + isOneToOne: false + referencedRelation: "Student" + referencedColumns: ["id"] + }, + ] + } + Class: { + Row: { + capacity: number + gradeId: number + id: number + name: string + supervisorId: string | null + } + Insert: { + capacity: number + gradeId: number + id?: number + name: string + supervisorId?: string | null + } + Update: { + capacity?: number + gradeId?: number + id?: number + name?: string + supervisorId?: string | null + } + Relationships: [ + { + foreignKeyName: "Class_gradeId_fkey" + columns: ["gradeId"] + isOneToOne: false + referencedRelation: "Grade" + referencedColumns: ["id"] + }, + { + foreignKeyName: "Class_supervisorId_fkey" + columns: ["supervisorId"] + isOneToOne: false + referencedRelation: "Teacher" + referencedColumns: ["id"] + }, + ] + } + Event: { + Row: { + classId: number | null + description: string + endTime: string + id: number + startTime: string + title: string + } + Insert: { + classId?: number | null + description: string + endTime: string + id?: number + startTime: string + title: string + } + Update: { + classId?: number | null + description?: string + endTime?: string + id?: number + startTime?: string + title?: string + } + Relationships: [ + { + foreignKeyName: "Event_classId_fkey" + columns: ["classId"] + isOneToOne: false + referencedRelation: "Class" + referencedColumns: ["id"] + }, + ] + } + Exam: { + Row: { + endTime: string + id: number + lessonId: number + startTime: string + title: string + } + Insert: { + endTime: string + id?: number + lessonId: number + startTime: string + title: string + } + Update: { + endTime?: string + id?: number + lessonId?: number + startTime?: string + title?: string + } + Relationships: [ + { + foreignKeyName: "Exam_lessonId_fkey" + columns: ["lessonId"] + isOneToOne: false + referencedRelation: "Lesson" + referencedColumns: ["id"] + }, + ] + } + Grade: { + Row: { + id: number + level: number + } + Insert: { + id?: number + level: number + } + Update: { + id?: number + level?: number + } + Relationships: [] + } + Lesson: { + Row: { + classId: number + day: Database["public"]["Enums"]["Day"] + endTime: string + id: number + name: string + startTime: string + subjectId: number + teacherId: string + } + Insert: { + classId: number + day: Database["public"]["Enums"]["Day"] + endTime: string + id?: number + name: string + startTime: string + subjectId: number + teacherId: string + } + Update: { + classId?: number + day?: Database["public"]["Enums"]["Day"] + endTime?: string + id?: number + name?: string + startTime?: string + subjectId?: number + teacherId?: string + } + Relationships: [ + { + foreignKeyName: "Lesson_classId_fkey" + columns: ["classId"] + isOneToOne: false + referencedRelation: "Class" + referencedColumns: ["id"] + }, + { + foreignKeyName: "Lesson_subjectId_fkey" + columns: ["subjectId"] + isOneToOne: false + referencedRelation: "Subject" + referencedColumns: ["id"] + }, + { + foreignKeyName: "Lesson_teacherId_fkey" + columns: ["teacherId"] + isOneToOne: false + referencedRelation: "Teacher" + referencedColumns: ["id"] + }, + ] + } + Parent: { + Row: { + address: string + createdAt: string + email: string | null + id: string + name: string + phone: string + surname: string + username: string + } + Insert: { + address: string + createdAt?: string + email?: string | null + id: string + name: string + phone: string + surname: string + username: string + } + Update: { + address?: string + createdAt?: string + email?: string | null + id?: string + name?: string + phone?: string + surname?: string + username?: string + } + Relationships: [] + } + Result: { + Row: { + assignmentId: number | null + examId: number | null + id: number + score: number + studentId: string + } + Insert: { + assignmentId?: number | null + examId?: number | null + id?: number + score: number + studentId: string + } + Update: { + assignmentId?: number | null + examId?: number | null + id?: number + score?: number + studentId?: string + } + Relationships: [ + { + foreignKeyName: "Result_assignmentId_fkey" + columns: ["assignmentId"] + isOneToOne: false + referencedRelation: "Assignment" + referencedColumns: ["id"] + }, + { + foreignKeyName: "Result_examId_fkey" + columns: ["examId"] + isOneToOne: false + referencedRelation: "Exam" + referencedColumns: ["id"] + }, + { + foreignKeyName: "Result_studentId_fkey" + columns: ["studentId"] + isOneToOne: false + referencedRelation: "Student" + referencedColumns: ["id"] + }, + ] + } + Student: { + Row: { + address: string + birthday: string + bloodType: string + classId: number + createdAt: string + email: string | null + gradeId: number + id: string + img: string | null + name: string + parentId: string + phone: string | null + sex: Database["public"]["Enums"]["UserSex"] + surname: string + username: string + } + Insert: { + address: string + birthday: string + bloodType: string + classId: number + createdAt?: string + email?: string | null + gradeId: number + id: string + img?: string | null + name: string + parentId: string + phone?: string | null + sex: Database["public"]["Enums"]["UserSex"] + surname: string + username: string + } + Update: { + address?: string + birthday?: string + bloodType?: string + classId?: number + createdAt?: string + email?: string | null + gradeId?: number + id?: string + img?: string | null + name?: string + parentId?: string + phone?: string | null + sex?: Database["public"]["Enums"]["UserSex"] + surname?: string + username?: string + } + Relationships: [ + { + foreignKeyName: "Student_classId_fkey" + columns: ["classId"] + isOneToOne: false + referencedRelation: "Class" + referencedColumns: ["id"] + }, + { + foreignKeyName: "Student_gradeId_fkey" + columns: ["gradeId"] + isOneToOne: false + referencedRelation: "Grade" + referencedColumns: ["id"] + }, + { + foreignKeyName: "Student_parentId_fkey" + columns: ["parentId"] + isOneToOne: false + referencedRelation: "Parent" + referencedColumns: ["id"] + }, + ] + } + Subject: { + Row: { + id: number + name: string + } + Insert: { + id?: number + name: string + } + Update: { + id?: number + name?: string + } + Relationships: [] + } + Teacher: { + Row: { + address: string + birthday: string + bloodType: string + createdAt: string + email: string | null + id: string + img: string | null + name: string + phone: string | null + sex: Database["public"]["Enums"]["UserSex"] + surname: string + username: string + } + Insert: { + address: string + birthday: string + bloodType: string + createdAt?: string + email?: string | null + id: string + img?: string | null + name: string + phone?: string | null + sex: Database["public"]["Enums"]["UserSex"] + surname: string + username: string + } + Update: { + address?: string + birthday?: string + bloodType?: string + createdAt?: string + email?: string | null + id?: string + img?: string | null + name?: string + phone?: string | null + sex?: Database["public"]["Enums"]["UserSex"] + surname?: string + username?: string + } + Relationships: [] + } + TeacherSubject: { + Row: { + assignedAt: string | null + id: number + isPrimary: boolean | null + subjectId: number + teacherId: string + } + Insert: { + assignedAt?: string | null + id?: number + isPrimary?: boolean | null + subjectId: number + teacherId: string + } + Update: { + assignedAt?: string | null + id?: number + isPrimary?: boolean | null + subjectId?: number + teacherId?: string + } + Relationships: [ + { + foreignKeyName: "TeacherSubject_subjectId_fkey" + columns: ["subjectId"] + isOneToOne: false + referencedRelation: "Subject" + referencedColumns: ["id"] + }, + { + foreignKeyName: "TeacherSubject_teacherId_fkey" + columns: ["teacherId"] + isOneToOne: false + referencedRelation: "Teacher" + referencedColumns: ["id"] + }, + ] + } + } + Views: { + [_ in never]: never + } + Functions: { + auth_user_classes: { Args: never; Returns: number[] } + auth_user_lessons: { Args: never; Returns: number[] } + auth_user_parents: { Args: never; Returns: string[] } + auth_user_students: { Args: never; Returns: string[] } + auth_user_subjects: { Args: never; Returns: number[] } + auth_user_teachers: { Args: never; Returns: string[] } + is_admin: { Args: never; Returns: boolean } + requesting_user_id: { Args: never; Returns: string } + requesting_user_role: { Args: never; Returns: string } + } + Enums: { + Day: "MONDAY" | "TUESDAY" | "WEDNESDAY" | "THURSDAY" | "FRIDAY" + UserSex: "MALE" | "FEMALE" + } + CompositeTypes: { + [_ in never]: never + } + } +} + +type DatabaseWithoutInternals = Omit + +type DefaultSchema = DatabaseWithoutInternals[Extract] + +export type Tables< + DefaultSchemaTableNameOrOptions extends + | keyof (DefaultSchema["Tables"] & DefaultSchema["Views"]) + | { schema: keyof DatabaseWithoutInternals }, + TableName extends DefaultSchemaTableNameOrOptions extends { + schema: keyof DatabaseWithoutInternals + } + ? keyof (DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions["schema"]]["Tables"] & + DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions["schema"]]["Views"]) + : never = never, +> = DefaultSchemaTableNameOrOptions extends { + schema: keyof DatabaseWithoutInternals +} + ? (DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions["schema"]]["Tables"] & + DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions["schema"]]["Views"])[TableName] extends { + Row: infer R + } + ? R + : never + : DefaultSchemaTableNameOrOptions extends keyof (DefaultSchema["Tables"] & + DefaultSchema["Views"]) + ? (DefaultSchema["Tables"] & + DefaultSchema["Views"])[DefaultSchemaTableNameOrOptions] extends { + Row: infer R + } + ? R + : never + : never + +export type TablesInsert< + DefaultSchemaTableNameOrOptions extends + | keyof DefaultSchema["Tables"] + | { schema: keyof DatabaseWithoutInternals }, + TableName extends DefaultSchemaTableNameOrOptions extends { + schema: keyof DatabaseWithoutInternals + } + ? keyof DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions["schema"]]["Tables"] + : never = never, +> = DefaultSchemaTableNameOrOptions extends { + schema: keyof DatabaseWithoutInternals +} + ? DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions["schema"]]["Tables"][TableName] extends { + Insert: infer I + } + ? I + : never + : DefaultSchemaTableNameOrOptions extends keyof DefaultSchema["Tables"] + ? DefaultSchema["Tables"][DefaultSchemaTableNameOrOptions] extends { + Insert: infer I + } + ? I + : never + : never + +export type TablesUpdate< + DefaultSchemaTableNameOrOptions extends + | keyof DefaultSchema["Tables"] + | { schema: keyof DatabaseWithoutInternals }, + TableName extends DefaultSchemaTableNameOrOptions extends { + schema: keyof DatabaseWithoutInternals + } + ? keyof DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions["schema"]]["Tables"] + : never = never, +> = DefaultSchemaTableNameOrOptions extends { + schema: keyof DatabaseWithoutInternals +} + ? DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions["schema"]]["Tables"][TableName] extends { + Update: infer U + } + ? U + : never + : DefaultSchemaTableNameOrOptions extends keyof DefaultSchema["Tables"] + ? DefaultSchema["Tables"][DefaultSchemaTableNameOrOptions] extends { + Update: infer U + } + ? U + : never + : never + +export type Enums< + DefaultSchemaEnumNameOrOptions extends + | keyof DefaultSchema["Enums"] + | { schema: keyof DatabaseWithoutInternals }, + EnumName extends DefaultSchemaEnumNameOrOptions extends { + schema: keyof DatabaseWithoutInternals + } + ? keyof DatabaseWithoutInternals[DefaultSchemaEnumNameOrOptions["schema"]]["Enums"] + : never = never, +> = DefaultSchemaEnumNameOrOptions extends { + schema: keyof DatabaseWithoutInternals +} + ? DatabaseWithoutInternals[DefaultSchemaEnumNameOrOptions["schema"]]["Enums"][EnumName] + : DefaultSchemaEnumNameOrOptions extends keyof DefaultSchema["Enums"] + ? DefaultSchema["Enums"][DefaultSchemaEnumNameOrOptions] + : never + +export type CompositeTypes< + PublicCompositeTypeNameOrOptions extends + | keyof DefaultSchema["CompositeTypes"] + | { schema: keyof DatabaseWithoutInternals }, + CompositeTypeName extends PublicCompositeTypeNameOrOptions extends { + schema: keyof DatabaseWithoutInternals + } + ? keyof DatabaseWithoutInternals[PublicCompositeTypeNameOrOptions["schema"]]["CompositeTypes"] + : never = never, +> = PublicCompositeTypeNameOrOptions extends { + schema: keyof DatabaseWithoutInternals +} + ? DatabaseWithoutInternals[PublicCompositeTypeNameOrOptions["schema"]]["CompositeTypes"][CompositeTypeName] + : PublicCompositeTypeNameOrOptions extends keyof DefaultSchema["CompositeTypes"] + ? DefaultSchema["CompositeTypes"][PublicCompositeTypeNameOrOptions] + : never + +export const Constants = { + graphql_public: { + Enums: {}, + }, + public: { + Enums: { + Day: ["MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY"], + UserSex: ["MALE", "FEMALE"], + }, + }, +} as const + diff --git a/supabase/.archive/seed.sql b/supabase/.archive/seed.sql new file mode 100644 index 0000000..2ccc048 --- /dev/null +++ b/supabase/.archive/seed.sql @@ -0,0 +1,242 @@ +-- Clean database +TRUNCATE TABLE "Admin", "Grade", "Class", "Subject", "Teacher", "TeacherSubject", "Lesson", "Parent", "Student", "Exam", "Assignment", "Result", "Attendance", "Event", "Announcement" CASCADE; + +INSERT INTO "Admin" ("id", "username") VALUES +('admin1', 'admin1'), +('admin2', 'admin2'); + +INSERT INTO "Grade" ("id", "level") VALUES +(1, 1), +(2, 2), +(3, 3), +(4, 4), +(5, 5), +(6, 6); + +INSERT INTO "Teacher" ("id", "username", "name", "surname", "email", "phone", "address", "bloodType", "sex", "birthday") VALUES +('teacher1', 'teacher1', 'TName1', 'TSurname1', 'teacher1@example.com', '123-456-7891', 'Address1', 'A+', 'FEMALE', '1996-02-27T00:26:35.280Z'), +('teacher2', 'teacher2', 'TName2', 'TSurname2', 'teacher2@example.com', '123-456-7892', 'Address2', 'A+', 'MALE', '1996-02-27T00:26:35.281Z'), +('teacher3', 'teacher3', 'TName3', 'TSurname3', 'teacher3@example.com', '123-456-7893', 'Address3', 'A+', 'FEMALE', '1996-02-27T00:26:35.281Z'), +('teacher4', 'teacher4', 'TName4', 'TSurname4', 'teacher4@example.com', '123-456-7894', 'Address4', 'A+', 'MALE', '1996-02-27T00:26:35.281Z'), +('teacher5', 'teacher5', 'TName5', 'TSurname5', 'teacher5@example.com', '123-456-7895', 'Address5', 'A+', 'FEMALE', '1996-02-27T00:26:35.281Z'), +('teacher6', 'teacher6', 'TName6', 'TSurname6', 'teacher6@example.com', '123-456-7896', 'Address6', 'A+', 'MALE', '1996-02-27T00:26:35.281Z'), +('teacher7', 'teacher7', 'TName7', 'TSurname7', 'teacher7@example.com', '123-456-7897', 'Address7', 'A+', 'FEMALE', '1996-02-27T00:26:35.281Z'), +('teacher8', 'teacher8', 'TName8', 'TSurname8', 'teacher8@example.com', '123-456-7898', 'Address8', 'A+', 'MALE', '1996-02-27T00:26:35.281Z'), +('teacher9', 'teacher9', 'TName9', 'TSurname9', 'teacher9@example.com', '123-456-7899', 'Address9', 'A+', 'FEMALE', '1996-02-27T00:26:35.281Z'), +('teacher10', 'teacher10', 'TName10', 'TSurname10', 'teacher10@example.com', '123-456-78910', 'Address10', 'A+', 'MALE', '1996-02-27T00:26:35.281Z'), +('teacher11', 'teacher11', 'TName11', 'TSurname11', 'teacher11@example.com', '123-456-78911', 'Address11', 'A+', 'FEMALE', '1996-02-27T00:26:35.281Z'), +('teacher12', 'teacher12', 'TName12', 'TSurname12', 'teacher12@example.com', '123-456-78912', 'Address12', 'A+', 'MALE', '1996-02-27T00:26:35.281Z'), +('teacher13', 'teacher13', 'TName13', 'TSurname13', 'teacher13@example.com', '123-456-78913', 'Address13', 'A+', 'FEMALE', '1996-02-27T00:26:35.281Z'), +('teacher14', 'teacher14', 'TName14', 'TSurname14', 'teacher14@example.com', '123-456-78914', 'Address14', 'A+', 'MALE', '1996-02-27T00:26:35.281Z'), +('teacher15', 'teacher15', 'TName15', 'TSurname15', 'teacher15@example.com', '123-456-78915', 'Address15', 'A+', 'FEMALE', '1996-02-27T00:26:35.281Z'); + +INSERT INTO "Class" ("id", "name", "gradeId", "capacity", "supervisorId") VALUES +(1, '1A', 1, 17, 'teacher12'), +(2, '2A', 2, 15, 'teacher13'), +(3, '3A', 3, 18, 'teacher14'), +(4, '4A', 4, 20, 'teacher15'), +(5, '5A', 5, 20, 'teacher10'), +(6, '6A', 6, 20, 'teacher11'); + +INSERT INTO "Subject" ("id", "name") VALUES +(1, 'Mathematics'), +(2, 'Science'), +(3, 'English'), +(4, 'History'), +(5, 'Geography'), +(6, 'Physics'), +(7, 'Chemistry'), +(8, 'Biology'), +(9, 'Computer Science'), +(10, 'Art'); + +INSERT INTO "TeacherSubject" ("subjectId", "teacherId", "isPrimary") VALUES +(2, 'teacher1', true), +(3, 'teacher2', true), +(4, 'teacher3', true), +(5, 'teacher4', true), +(6, 'teacher5', true), +(7, 'teacher6', true), +(8, 'teacher7', true), +(9, 'teacher8', true), +(10, 'teacher9', true), +(1, 'teacher10', true), +(2, 'teacher11', true), +(3, 'teacher12', true), +(4, 'teacher13', true), +(5, 'teacher14', true), +(6, 'teacher15', true); + +INSERT INTO "Lesson" ("id", "name", "day", "startTime", "endTime", "subjectId", "classId", "teacherId") VALUES +(1, 'Lesson1', 'TUESDAY', '2026-02-27T01:26:35.281Z', '2026-02-27T03:26:35.281Z', 2, 2, 'teacher2'), +(2, 'Lesson2', 'MONDAY', '2026-02-27T01:26:35.281Z', '2026-02-27T03:26:35.281Z', 3, 3, 'teacher3'), +(3, 'Lesson3', 'TUESDAY', '2026-02-27T01:26:35.281Z', '2026-02-27T03:26:35.281Z', 4, 4, 'teacher4'), +(4, 'Lesson4', 'THURSDAY', '2026-02-27T01:26:35.281Z', '2026-02-27T03:26:35.281Z', 5, 5, 'teacher5'), +(5, 'Lesson5', 'MONDAY', '2026-02-27T01:26:35.281Z', '2026-02-27T03:26:35.281Z', 6, 6, 'teacher6'), +(6, 'Lesson6', 'THURSDAY', '2026-02-27T01:26:35.281Z', '2026-02-27T03:26:35.281Z', 7, 1, 'teacher7'), +(7, 'Lesson7', 'WEDNESDAY', '2026-02-27T01:26:35.281Z', '2026-02-27T03:26:35.281Z', 8, 2, 'teacher8'), +(8, 'Lesson8', 'MONDAY', '2026-02-27T01:26:35.281Z', '2026-02-27T03:26:35.281Z', 9, 3, 'teacher9'), +(9, 'Lesson9', 'FRIDAY', '2026-02-27T01:26:35.281Z', '2026-02-27T03:26:35.281Z', 10, 4, 'teacher10'), +(10, 'Lesson10', 'FRIDAY', '2026-02-27T01:26:35.281Z', '2026-02-27T03:26:35.281Z', 1, 5, 'teacher11'), +(11, 'Lesson11', 'TUESDAY', '2026-02-27T01:26:35.281Z', '2026-02-27T03:26:35.281Z', 2, 6, 'teacher12'), +(12, 'Lesson12', 'THURSDAY', '2026-02-27T01:26:35.281Z', '2026-02-27T03:26:35.281Z', 3, 1, 'teacher13'), +(13, 'Lesson13', 'WEDNESDAY', '2026-02-27T01:26:35.281Z', '2026-02-27T03:26:35.281Z', 4, 2, 'teacher14'), +(14, 'Lesson14', 'TUESDAY', '2026-02-27T01:26:35.281Z', '2026-02-27T03:26:35.281Z', 5, 3, 'teacher15'), +(15, 'Lesson15', 'TUESDAY', '2026-02-27T01:26:35.281Z', '2026-02-27T03:26:35.281Z', 6, 4, 'teacher1'), +(16, 'Lesson16', 'MONDAY', '2026-02-27T01:26:35.281Z', '2026-02-27T03:26:35.281Z', 7, 5, 'teacher2'), +(17, 'Lesson17', 'THURSDAY', '2026-02-27T01:26:35.281Z', '2026-02-27T03:26:35.281Z', 8, 6, 'teacher3'), +(18, 'Lesson18', 'THURSDAY', '2026-02-27T01:26:35.281Z', '2026-02-27T03:26:35.281Z', 9, 1, 'teacher4'), +(19, 'Lesson19', 'FRIDAY', '2026-02-27T01:26:35.281Z', '2026-02-27T03:26:35.281Z', 10, 2, 'teacher5'), +(20, 'Lesson20', 'MONDAY', '2026-02-27T01:26:35.281Z', '2026-02-27T03:26:35.281Z', 1, 3, 'teacher6'), +(21, 'Lesson21', 'THURSDAY', '2026-02-27T01:26:35.281Z', '2026-02-27T03:26:35.281Z', 2, 4, 'teacher7'), +(22, 'Lesson22', 'THURSDAY', '2026-02-27T01:26:35.281Z', '2026-02-27T03:26:35.281Z', 3, 5, 'teacher8'), +(23, 'Lesson23', 'WEDNESDAY', '2026-02-27T01:26:35.281Z', '2026-02-27T03:26:35.281Z', 4, 6, 'teacher9'), +(24, 'Lesson24', 'FRIDAY', '2026-02-27T01:26:35.281Z', '2026-02-27T03:26:35.281Z', 5, 1, 'teacher10'), +(25, 'Lesson25', 'MONDAY', '2026-02-27T01:26:35.281Z', '2026-02-27T03:26:35.281Z', 6, 2, 'teacher11'), +(26, 'Lesson26', 'FRIDAY', '2026-02-27T01:26:35.281Z', '2026-02-27T03:26:35.281Z', 7, 3, 'teacher12'), +(27, 'Lesson27', 'WEDNESDAY', '2026-02-27T01:26:35.281Z', '2026-02-27T03:26:35.281Z', 8, 4, 'teacher13'), +(28, 'Lesson28', 'FRIDAY', '2026-02-27T01:26:35.281Z', '2026-02-27T03:26:35.281Z', 9, 5, 'teacher14'), +(29, 'Lesson29', 'MONDAY', '2026-02-27T01:26:35.281Z', '2026-02-27T03:26:35.281Z', 10, 6, 'teacher15'), +(30, 'Lesson30', 'THURSDAY', '2026-02-27T01:26:35.281Z', '2026-02-27T03:26:35.281Z', 1, 1, 'teacher1'); + +INSERT INTO "Parent" ("id", "username", "name", "surname", "email", "phone", "address") VALUES +('parentId1', 'parentId1', 'PName 1', 'PSurname 1', 'parent1@example.com', '123-456-7891', 'Address1'), +('parentId2', 'parentId2', 'PName 2', 'PSurname 2', 'parent2@example.com', '123-456-7892', 'Address2'), +('parentId3', 'parentId3', 'PName 3', 'PSurname 3', 'parent3@example.com', '123-456-7893', 'Address3'), +('parentId4', 'parentId4', 'PName 4', 'PSurname 4', 'parent4@example.com', '123-456-7894', 'Address4'), +('parentId5', 'parentId5', 'PName 5', 'PSurname 5', 'parent5@example.com', '123-456-7895', 'Address5'), +('parentId6', 'parentId6', 'PName 6', 'PSurname 6', 'parent6@example.com', '123-456-7896', 'Address6'), +('parentId7', 'parentId7', 'PName 7', 'PSurname 7', 'parent7@example.com', '123-456-7897', 'Address7'), +('parentId8', 'parentId8', 'PName 8', 'PSurname 8', 'parent8@example.com', '123-456-7898', 'Address8'), +('parentId9', 'parentId9', 'PName 9', 'PSurname 9', 'parent9@example.com', '123-456-7899', 'Address9'), +('parentId10', 'parentId10', 'PName 10', 'PSurname 10', 'parent10@example.com', '123-456-78910', 'Address10'), +('parentId11', 'parentId11', 'PName 11', 'PSurname 11', 'parent11@example.com', '123-456-78911', 'Address11'), +('parentId12', 'parentId12', 'PName 12', 'PSurname 12', 'parent12@example.com', '123-456-78912', 'Address12'), +('parentId13', 'parentId13', 'PName 13', 'PSurname 13', 'parent13@example.com', '123-456-78913', 'Address13'), +('parentId14', 'parentId14', 'PName 14', 'PSurname 14', 'parent14@example.com', '123-456-78914', 'Address14'), +('parentId15', 'parentId15', 'PName 15', 'PSurname 15', 'parent15@example.com', '123-456-78915', 'Address15'), +('parentId16', 'parentId16', 'PName 16', 'PSurname 16', 'parent16@example.com', '123-456-78916', 'Address16'), +('parentId17', 'parentId17', 'PName 17', 'PSurname 17', 'parent17@example.com', '123-456-78917', 'Address17'), +('parentId18', 'parentId18', 'PName 18', 'PSurname 18', 'parent18@example.com', '123-456-78918', 'Address18'), +('parentId19', 'parentId19', 'PName 19', 'PSurname 19', 'parent19@example.com', '123-456-78919', 'Address19'), +('parentId20', 'parentId20', 'PName 20', 'PSurname 20', 'parent20@example.com', '123-456-78920', 'Address20'), +('parentId21', 'parentId21', 'PName 21', 'PSurname 21', 'parent21@example.com', '123-456-78921', 'Address21'), +('parentId22', 'parentId22', 'PName 22', 'PSurname 22', 'parent22@example.com', '123-456-78922', 'Address22'), +('parentId23', 'parentId23', 'PName 23', 'PSurname 23', 'parent23@example.com', '123-456-78923', 'Address23'), +('parentId24', 'parentId24', 'PName 24', 'PSurname 24', 'parent24@example.com', '123-456-78924', 'Address24'), +('parentId25', 'parentId25', 'PName 25', 'PSurname 25', 'parent25@example.com', '123-456-78925', 'Address25'); + +INSERT INTO "Student" ("id", "username", "name", "surname", "email", "phone", "address", "bloodType", "sex", "parentId", "gradeId", "classId", "birthday") VALUES +('student1', 'student1', 'SName1', 'SSurname 1', 'student1@example.com', '987-654-3211', 'Address1', 'O-', 'FEMALE', 'parentId1', 2, 2, '2016-02-27T00:26:35.281Z'), +('student2', 'student2', 'SName2', 'SSurname 2', 'student2@example.com', '987-654-3212', 'Address2', 'O-', 'MALE', 'parentId1', 3, 3, '2016-02-27T00:26:35.281Z'), +('student3', 'student3', 'SName3', 'SSurname 3', 'student3@example.com', '987-654-3213', 'Address3', 'O-', 'FEMALE', 'parentId2', 4, 4, '2016-02-27T00:26:35.281Z'), +('student4', 'student4', 'SName4', 'SSurname 4', 'student4@example.com', '987-654-3214', 'Address4', 'O-', 'MALE', 'parentId2', 5, 5, '2016-02-27T00:26:35.281Z'), +('student5', 'student5', 'SName5', 'SSurname 5', 'student5@example.com', '987-654-3215', 'Address5', 'O-', 'FEMALE', 'parentId3', 6, 6, '2016-02-27T00:26:35.281Z'), +('student6', 'student6', 'SName6', 'SSurname 6', 'student6@example.com', '987-654-3216', 'Address6', 'O-', 'MALE', 'parentId3', 1, 1, '2016-02-27T00:26:35.281Z'), +('student7', 'student7', 'SName7', 'SSurname 7', 'student7@example.com', '987-654-3217', 'Address7', 'O-', 'FEMALE', 'parentId4', 2, 2, '2016-02-27T00:26:35.281Z'), +('student8', 'student8', 'SName8', 'SSurname 8', 'student8@example.com', '987-654-3218', 'Address8', 'O-', 'MALE', 'parentId4', 3, 3, '2016-02-27T00:26:35.281Z'), +('student9', 'student9', 'SName9', 'SSurname 9', 'student9@example.com', '987-654-3219', 'Address9', 'O-', 'FEMALE', 'parentId5', 4, 4, '2016-02-27T00:26:35.281Z'), +('student10', 'student10', 'SName10', 'SSurname 10', 'student10@example.com', '987-654-32110', 'Address10', 'O-', 'MALE', 'parentId5', 5, 5, '2016-02-27T00:26:35.281Z'), +('student11', 'student11', 'SName11', 'SSurname 11', 'student11@example.com', '987-654-32111', 'Address11', 'O-', 'FEMALE', 'parentId6', 6, 6, '2016-02-27T00:26:35.281Z'), +('student12', 'student12', 'SName12', 'SSurname 12', 'student12@example.com', '987-654-32112', 'Address12', 'O-', 'MALE', 'parentId6', 1, 1, '2016-02-27T00:26:35.281Z'), +('student13', 'student13', 'SName13', 'SSurname 13', 'student13@example.com', '987-654-32113', 'Address13', 'O-', 'FEMALE', 'parentId7', 2, 2, '2016-02-27T00:26:35.281Z'), +('student14', 'student14', 'SName14', 'SSurname 14', 'student14@example.com', '987-654-32114', 'Address14', 'O-', 'MALE', 'parentId7', 3, 3, '2016-02-27T00:26:35.281Z'), +('student15', 'student15', 'SName15', 'SSurname 15', 'student15@example.com', '987-654-32115', 'Address15', 'O-', 'FEMALE', 'parentId8', 4, 4, '2016-02-27T00:26:35.281Z'), +('student16', 'student16', 'SName16', 'SSurname 16', 'student16@example.com', '987-654-32116', 'Address16', 'O-', 'MALE', 'parentId8', 5, 5, '2016-02-27T00:26:35.281Z'), +('student17', 'student17', 'SName17', 'SSurname 17', 'student17@example.com', '987-654-32117', 'Address17', 'O-', 'FEMALE', 'parentId9', 6, 6, '2016-02-27T00:26:35.281Z'), +('student18', 'student18', 'SName18', 'SSurname 18', 'student18@example.com', '987-654-32118', 'Address18', 'O-', 'MALE', 'parentId9', 1, 1, '2016-02-27T00:26:35.281Z'), +('student19', 'student19', 'SName19', 'SSurname 19', 'student19@example.com', '987-654-32119', 'Address19', 'O-', 'FEMALE', 'parentId10', 2, 2, '2016-02-27T00:26:35.281Z'), +('student20', 'student20', 'SName20', 'SSurname 20', 'student20@example.com', '987-654-32120', 'Address20', 'O-', 'MALE', 'parentId10', 3, 3, '2016-02-27T00:26:35.281Z'), +('student21', 'student21', 'SName21', 'SSurname 21', 'student21@example.com', '987-654-32121', 'Address21', 'O-', 'FEMALE', 'parentId11', 4, 4, '2016-02-27T00:26:35.281Z'), +('student22', 'student22', 'SName22', 'SSurname 22', 'student22@example.com', '987-654-32122', 'Address22', 'O-', 'MALE', 'parentId11', 5, 5, '2016-02-27T00:26:35.281Z'), +('student23', 'student23', 'SName23', 'SSurname 23', 'student23@example.com', '987-654-32123', 'Address23', 'O-', 'FEMALE', 'parentId12', 6, 6, '2016-02-27T00:26:35.281Z'), +('student24', 'student24', 'SName24', 'SSurname 24', 'student24@example.com', '987-654-32124', 'Address24', 'O-', 'MALE', 'parentId12', 1, 1, '2016-02-27T00:26:35.281Z'), +('student25', 'student25', 'SName25', 'SSurname 25', 'student25@example.com', '987-654-32125', 'Address25', 'O-', 'FEMALE', 'parentId13', 2, 2, '2016-02-27T00:26:35.281Z'), +('student26', 'student26', 'SName26', 'SSurname 26', 'student26@example.com', '987-654-32126', 'Address26', 'O-', 'MALE', 'parentId13', 3, 3, '2016-02-27T00:26:35.281Z'), +('student27', 'student27', 'SName27', 'SSurname 27', 'student27@example.com', '987-654-32127', 'Address27', 'O-', 'FEMALE', 'parentId14', 4, 4, '2016-02-27T00:26:35.281Z'), +('student28', 'student28', 'SName28', 'SSurname 28', 'student28@example.com', '987-654-32128', 'Address28', 'O-', 'MALE', 'parentId14', 5, 5, '2016-02-27T00:26:35.281Z'), +('student29', 'student29', 'SName29', 'SSurname 29', 'student29@example.com', '987-654-32129', 'Address29', 'O-', 'FEMALE', 'parentId15', 6, 6, '2016-02-27T00:26:35.281Z'), +('student30', 'student30', 'SName30', 'SSurname 30', 'student30@example.com', '987-654-32130', 'Address30', 'O-', 'MALE', 'parentId15', 1, 1, '2016-02-27T00:26:35.281Z'), +('student31', 'student31', 'SName31', 'SSurname 31', 'student31@example.com', '987-654-32131', 'Address31', 'O-', 'FEMALE', 'parentId16', 2, 2, '2016-02-27T00:26:35.281Z'), +('student32', 'student32', 'SName32', 'SSurname 32', 'student32@example.com', '987-654-32132', 'Address32', 'O-', 'MALE', 'parentId16', 3, 3, '2016-02-27T00:26:35.281Z'), +('student33', 'student33', 'SName33', 'SSurname 33', 'student33@example.com', '987-654-32133', 'Address33', 'O-', 'FEMALE', 'parentId17', 4, 4, '2016-02-27T00:26:35.281Z'), +('student34', 'student34', 'SName34', 'SSurname 34', 'student34@example.com', '987-654-32134', 'Address34', 'O-', 'MALE', 'parentId17', 5, 5, '2016-02-27T00:26:35.281Z'), +('student35', 'student35', 'SName35', 'SSurname 35', 'student35@example.com', '987-654-32135', 'Address35', 'O-', 'FEMALE', 'parentId18', 6, 6, '2016-02-27T00:26:35.281Z'), +('student36', 'student36', 'SName36', 'SSurname 36', 'student36@example.com', '987-654-32136', 'Address36', 'O-', 'MALE', 'parentId18', 1, 1, '2016-02-27T00:26:35.281Z'), +('student37', 'student37', 'SName37', 'SSurname 37', 'student37@example.com', '987-654-32137', 'Address37', 'O-', 'FEMALE', 'parentId19', 2, 2, '2016-02-27T00:26:35.281Z'), +('student38', 'student38', 'SName38', 'SSurname 38', 'student38@example.com', '987-654-32138', 'Address38', 'O-', 'MALE', 'parentId19', 3, 3, '2016-02-27T00:26:35.281Z'), +('student39', 'student39', 'SName39', 'SSurname 39', 'student39@example.com', '987-654-32139', 'Address39', 'O-', 'FEMALE', 'parentId20', 4, 4, '2016-02-27T00:26:35.281Z'), +('student40', 'student40', 'SName40', 'SSurname 40', 'student40@example.com', '987-654-32140', 'Address40', 'O-', 'MALE', 'parentId20', 5, 5, '2016-02-27T00:26:35.281Z'), +('student41', 'student41', 'SName41', 'SSurname 41', 'student41@example.com', '987-654-32141', 'Address41', 'O-', 'FEMALE', 'parentId21', 6, 6, '2016-02-27T00:26:35.281Z'), +('student42', 'student42', 'SName42', 'SSurname 42', 'student42@example.com', '987-654-32142', 'Address42', 'O-', 'MALE', 'parentId21', 1, 1, '2016-02-27T00:26:35.281Z'), +('student43', 'student43', 'SName43', 'SSurname 43', 'student43@example.com', '987-654-32143', 'Address43', 'O-', 'FEMALE', 'parentId22', 2, 2, '2016-02-27T00:26:35.281Z'), +('student44', 'student44', 'SName44', 'SSurname 44', 'student44@example.com', '987-654-32144', 'Address44', 'O-', 'MALE', 'parentId22', 3, 3, '2016-02-27T00:26:35.281Z'), +('student45', 'student45', 'SName45', 'SSurname 45', 'student45@example.com', '987-654-32145', 'Address45', 'O-', 'FEMALE', 'parentId23', 4, 4, '2016-02-27T00:26:35.281Z'), +('student46', 'student46', 'SName46', 'SSurname 46', 'student46@example.com', '987-654-32146', 'Address46', 'O-', 'MALE', 'parentId23', 5, 5, '2016-02-27T00:26:35.281Z'), +('student47', 'student47', 'SName47', 'SSurname 47', 'student47@example.com', '987-654-32147', 'Address47', 'O-', 'FEMALE', 'parentId24', 6, 6, '2016-02-27T00:26:35.281Z'), +('student48', 'student48', 'SName48', 'SSurname 48', 'student48@example.com', '987-654-32148', 'Address48', 'O-', 'MALE', 'parentId24', 1, 1, '2016-02-27T00:26:35.281Z'), +('student49', 'student49', 'SName49', 'SSurname 49', 'student49@example.com', '987-654-32149', 'Address49', 'O-', 'FEMALE', 'parentId25', 2, 2, '2016-02-27T00:26:35.281Z'), +('student50', 'student50', 'SName50', 'SSurname 50', 'student50@example.com', '987-654-32150', 'Address50', 'O-', 'MALE', 'parentId25', 3, 3, '2016-02-27T00:26:35.281Z'); + +INSERT INTO "Exam" ("id", "title", "startTime", "endTime", "lessonId") VALUES +(1, 'Exam 1', '2026-02-27T01:26:35.281Z', '2026-02-27T02:26:35.281Z', 2), +(2, 'Exam 2', '2026-02-27T01:26:35.281Z', '2026-02-27T02:26:35.281Z', 3), +(3, 'Exam 3', '2026-02-27T01:26:35.281Z', '2026-02-27T02:26:35.281Z', 4), +(4, 'Exam 4', '2026-02-27T01:26:35.281Z', '2026-02-27T02:26:35.281Z', 5), +(5, 'Exam 5', '2026-02-27T01:26:35.281Z', '2026-02-27T02:26:35.281Z', 6), +(6, 'Exam 6', '2026-02-27T01:26:35.281Z', '2026-02-27T02:26:35.281Z', 7), +(7, 'Exam 7', '2026-02-27T01:26:35.281Z', '2026-02-27T02:26:35.281Z', 8), +(8, 'Exam 8', '2026-02-27T01:26:35.281Z', '2026-02-27T02:26:35.281Z', 9), +(9, 'Exam 9', '2026-02-27T01:26:35.281Z', '2026-02-27T02:26:35.281Z', 10), +(10, 'Exam 10', '2026-02-27T01:26:35.281Z', '2026-02-27T02:26:35.281Z', 11); + +INSERT INTO "Assignment" ("id", "title", "startDate", "dueDate", "lessonId") VALUES +(1, 'Assignment 1', '2026-02-27T01:26:35.281Z', '2026-02-28T00:26:35.281Z', 2), +(2, 'Assignment 2', '2026-02-27T01:26:35.281Z', '2026-02-28T00:26:35.281Z', 3), +(3, 'Assignment 3', '2026-02-27T01:26:35.281Z', '2026-02-28T00:26:35.281Z', 4), +(4, 'Assignment 4', '2026-02-27T01:26:35.281Z', '2026-02-28T00:26:35.281Z', 5), +(5, 'Assignment 5', '2026-02-27T01:26:35.281Z', '2026-02-28T00:26:35.281Z', 6), +(6, 'Assignment 6', '2026-02-27T01:26:35.281Z', '2026-02-28T00:26:35.281Z', 7), +(7, 'Assignment 7', '2026-02-27T01:26:35.281Z', '2026-02-28T00:26:35.281Z', 8), +(8, 'Assignment 8', '2026-02-27T01:26:35.281Z', '2026-02-28T00:26:35.281Z', 9), +(9, 'Assignment 9', '2026-02-27T01:26:35.281Z', '2026-02-28T00:26:35.281Z', 10), +(10, 'Assignment 10', '2026-02-27T01:26:35.281Z', '2026-02-28T00:26:35.281Z', 11); + +INSERT INTO "Result" ("id", "score", "studentId", "examId", "assignmentId") VALUES +(1, 90, 'student1', 1, NULL), +(2, 90, 'student2', 2, NULL), +(3, 90, 'student3', 3, NULL), +(4, 90, 'student4', 4, NULL), +(5, 90, 'student5', 5, NULL), +(6, 90, 'student6', NULL, 1), +(7, 90, 'student7', NULL, 2), +(8, 90, 'student8', NULL, 3), +(9, 90, 'student9', NULL, 4), +(10, 90, 'student10', NULL, 5); + +INSERT INTO "Attendance" ("id", "date", "present", "studentId", "lessonId") VALUES +(1, '2026-02-27T00:26:35.281Z', TRUE, 'student1', 2), +(2, '2026-02-27T00:26:35.281Z', TRUE, 'student2', 3), +(3, '2026-02-27T00:26:35.281Z', TRUE, 'student3', 4), +(4, '2026-02-27T00:26:35.281Z', TRUE, 'student4', 5), +(5, '2026-02-27T00:26:35.281Z', TRUE, 'student5', 6), +(6, '2026-02-27T00:26:35.281Z', TRUE, 'student6', 7), +(7, '2026-02-27T00:26:35.281Z', TRUE, 'student7', 8), +(8, '2026-02-27T00:26:35.281Z', TRUE, 'student8', 9), +(9, '2026-02-27T00:26:35.281Z', TRUE, 'student9', 10), +(10, '2026-02-27T00:26:35.281Z', TRUE, 'student10', 11); + +INSERT INTO "Event" ("id", "title", "description", "startTime", "endTime", "classId") VALUES +(1, 'Event 1', 'Description for Event 1', '2026-02-27T01:26:35.281Z', '2026-02-27T02:26:35.281Z', 2), +(2, 'Event 2', 'Description for Event 2', '2026-02-27T01:26:35.281Z', '2026-02-27T02:26:35.281Z', 3), +(3, 'Event 3', 'Description for Event 3', '2026-02-27T01:26:35.281Z', '2026-02-27T02:26:35.281Z', 4), +(4, 'Event 4', 'Description for Event 4', '2026-02-27T01:26:35.281Z', '2026-02-27T02:26:35.281Z', 5), +(5, 'Event 5', 'Description for Event 5', '2026-02-27T01:26:35.281Z', '2026-02-27T02:26:35.281Z', 1); + +INSERT INTO "Announcement" ("id", "title", "description", "date", "classId") VALUES +(1, 'Announcement 1', 'Description for Announcement 1', '2026-02-27T00:26:35.281Z', 2), +(2, 'Announcement 2', 'Description for Announcement 2', '2026-02-27T00:26:35.281Z', 3), +(3, 'Announcement 3', 'Description for Announcement 3', '2026-02-27T00:26:35.281Z', 4), +(4, 'Announcement 4', 'Description for Announcement 4', '2026-02-27T00:26:35.281Z', 5), +(5, 'Announcement 5', 'Description for Announcement 5', '2026-02-27T00:26:35.281Z', 1); + diff --git a/supabase/.gitignore b/supabase/.gitignore new file mode 100644 index 0000000..ad9264f --- /dev/null +++ b/supabase/.gitignore @@ -0,0 +1,8 @@ +# Supabase +.branches +.temp + +# dotenvx +.env.keys +.env.local +.env.*.local diff --git a/supabase/config.toml b/supabase/config.toml new file mode 100644 index 0000000..092737b --- /dev/null +++ b/supabase/config.toml @@ -0,0 +1,384 @@ +# For detailed configuration reference documentation, visit: +# https://supabase.com/docs/guides/local-development/cli/config +# A string used to distinguish different Supabase projects on the same host. Defaults to the +# working directory name when running `supabase init`. +project_id = "full-stack-school" + +[api] +enabled = true +# Port to use for the API URL. +port = 54321 +# Schemas to expose in your API. Tables, views and stored procedures in this schema will get API +# endpoints. `public` and `graphql_public` schemas are included by default. +schemas = ["public", "graphql_public"] +# Extra schemas to add to the search_path of every request. +extra_search_path = ["public", "extensions"] +# The maximum number of rows returns from a view, table, or stored procedure. Limits payload size +# for accidental or malicious requests. +max_rows = 1000 + +[api.tls] +# Enable HTTPS endpoints locally using a self-signed certificate. +enabled = false +# Paths to self-signed certificate pair. +# cert_path = "../certs/my-cert.pem" +# key_path = "../certs/my-key.pem" + +[db] +# Port to use for the local database URL. +port = 54322 +# Port used by db diff command to initialize the shadow database. +shadow_port = 54320 +# Maximum amount of time to wait for health check when starting the local database. +health_timeout = "2m" +# The database major version to use. This has to be the same as your remote database's. Run `SHOW +# server_version;` on the remote database to check. +major_version = 17 + +[db.pooler] +enabled = false +# Port to use for the local connection pooler. +port = 54329 +# Specifies when a server connection can be reused by other clients. +# Configure one of the supported pooler modes: `transaction`, `session`. +pool_mode = "transaction" +# How many server connections to allow per user/database pair. +default_pool_size = 20 +# Maximum number of client connections allowed. +max_client_conn = 100 + +# [db.vault] +# secret_key = "env(SECRET_VALUE)" + +[db.migrations] +# If disabled, migrations will be skipped during a db push or reset. +enabled = true +# Specifies an ordered list of schema files that describe your database. +# Supports glob patterns relative to supabase directory: "./schemas/*.sql" +schema_paths = ["./migrations/*.sql"] + +[db.seed] +# If enabled, seeds the database after migrations during a db reset. +enabled = true +# Specifies an ordered list of seed files to load during db reset. +# Supports glob patterns relative to supabase directory: "./seeds/*.sql" +sql_paths = [""] + +[db.network_restrictions] +# Enable management of network restrictions. +enabled = false +# List of IPv4 CIDR blocks allowed to connect to the database. +# Defaults to allow all IPv4 connections. Set empty array to block all IPs. +allowed_cidrs = ["0.0.0.0/0"] +# List of IPv6 CIDR blocks allowed to connect to the database. +# Defaults to allow all IPv6 connections. Set empty array to block all IPs. +allowed_cidrs_v6 = ["::/0"] + +[realtime] +enabled = true +# Bind realtime via either IPv4 or IPv6. (default: IPv4) +# ip_version = "IPv6" +# The maximum length in bytes of HTTP request headers. (default: 4096) +# max_header_length = 4096 + +[studio] +enabled = true +# Port to use for Supabase Studio. +port = 54323 +# External URL of the API server that frontend connects to. +api_url = "http://127.0.0.1" +# OpenAI API Key to use for Supabase AI in the Supabase Studio. +openai_api_key = "env(OPENAI_API_KEY)" + +# Email testing server. Emails sent with the local dev setup are not actually sent - rather, they +# are monitored, and you can view the emails that would have been sent from the web interface. +[inbucket] +enabled = true +# Port to use for the email testing server web interface. +port = 54324 +# Uncomment to expose additional ports for testing user applications that send emails. +# smtp_port = 54325 +# pop3_port = 54326 +# admin_email = "admin@email.com" +# sender_name = "Admin" + +[storage] +enabled = true +# The maximum file size allowed (e.g. "5MB", "500KB"). +file_size_limit = "50MiB" + +# Uncomment to configure local storage buckets +# [storage.buckets.images] +# public = false +# file_size_limit = "50MiB" +# allowed_mime_types = ["image/png", "image/jpeg"] +# objects_path = "./images" + +# Allow connections via S3 compatible clients +[storage.s3_protocol] +enabled = true + +# Image transformation API is available to Supabase Pro plan. +# [storage.image_transformation] +# enabled = true + +# Store analytical data in S3 for running ETL jobs over Iceberg Catalog +# This feature is only available on the hosted platform. +[storage.analytics] +enabled = false +max_namespaces = 5 +max_tables = 10 +max_catalogs = 2 + +# Analytics Buckets is available to Supabase Pro plan. +# [storage.analytics.buckets.my-warehouse] + +# Store vector embeddings in S3 for large and durable datasets +# This feature is only available on the hosted platform. +[storage.vector] +enabled = false +max_buckets = 10 +max_indexes = 5 + +# Vector Buckets is available to Supabase Pro plan. +# [storage.vector.buckets.documents-openai] + +[auth] +enabled = true +# The base URL of your website. Used as an allow-list for redirects and for constructing URLs used +# in emails. +site_url = "http://127.0.0.1:3000" +# A list of *exact* URLs that auth providers are permitted to redirect to post authentication. +additional_redirect_urls = ["https://127.0.0.1:3000"] +# How long tokens are valid for, in seconds. Defaults to 3600 (1 hour), maximum 604,800 (1 week). +jwt_expiry = 3600 +# JWT issuer URL. If not set, defaults to the local API URL (http://127.0.0.1:/auth/v1). +# jwt_issuer = "" +# Path to JWT signing key. DO NOT commit your signing keys file to git. +# signing_keys_path = "./signing_keys.json" +# If disabled, the refresh token will never expire. +enable_refresh_token_rotation = true +# Allows refresh tokens to be reused after expiry, up to the specified interval in seconds. +# Requires enable_refresh_token_rotation = true. +refresh_token_reuse_interval = 10 +# Allow/disallow new user signups to your project. +enable_signup = true +# Allow/disallow anonymous sign-ins to your project. +enable_anonymous_sign_ins = false +# Allow/disallow testing manual linking of accounts +enable_manual_linking = false +# Passwords shorter than this value will be rejected as weak. Minimum 6, recommended 8 or more. +minimum_password_length = 6 +# Passwords that do not meet the following requirements will be rejected as weak. Supported values +# are: `letters_digits`, `lower_upper_letters_digits`, `lower_upper_letters_digits_symbols` +password_requirements = "" + +[auth.rate_limit] +# Number of emails that can be sent per hour. Requires auth.email.smtp to be enabled. +email_sent = 2 +# Number of SMS messages that can be sent per hour. Requires auth.sms to be enabled. +sms_sent = 30 +# Number of anonymous sign-ins that can be made per hour per IP address. Requires enable_anonymous_sign_ins = true. +anonymous_users = 30 +# Number of sessions that can be refreshed in a 5 minute interval per IP address. +token_refresh = 150 +# Number of sign up and sign-in requests that can be made in a 5 minute interval per IP address (excludes anonymous users). +sign_in_sign_ups = 30 +# Number of OTP / Magic link verifications that can be made in a 5 minute interval per IP address. +token_verifications = 30 +# Number of Web3 logins that can be made in a 5 minute interval per IP address. +web3 = 30 + +# Configure one of the supported captcha providers: `hcaptcha`, `turnstile`. +# [auth.captcha] +# enabled = true +# provider = "hcaptcha" +# secret = "" + +[auth.email] +# Allow/disallow new user signups via email to your project. +enable_signup = true +# If enabled, a user will be required to confirm any email change on both the old, and new email +# addresses. If disabled, only the new email is required to confirm. +double_confirm_changes = true +# If enabled, users need to confirm their email address before signing in. +enable_confirmations = false +# If enabled, users will need to reauthenticate or have logged in recently to change their password. +secure_password_change = false +# Controls the minimum amount of time that must pass before sending another signup confirmation or password reset email. +max_frequency = "1s" +# Number of characters used in the email OTP. +otp_length = 6 +# Number of seconds before the email OTP expires (defaults to 1 hour). +otp_expiry = 3600 + +# Use a production-ready SMTP server +# [auth.email.smtp] +# enabled = true +# host = "smtp.sendgrid.net" +# port = 587 +# user = "apikey" +# pass = "env(SENDGRID_API_KEY)" +# admin_email = "admin@email.com" +# sender_name = "Admin" + +# Uncomment to customize email template +# [auth.email.template.invite] +# subject = "You have been invited" +# content_path = "./supabase/templates/invite.html" + +# Uncomment to customize notification email template +# [auth.email.notification.password_changed] +# enabled = true +# subject = "Your password has been changed" +# content_path = "./templates/password_changed_notification.html" + +[auth.sms] +# Allow/disallow new user signups via SMS to your project. +enable_signup = false +# If enabled, users need to confirm their phone number before signing in. +enable_confirmations = false +# Template for sending OTP to users +template = "Your code is {{ .Code }}" +# Controls the minimum amount of time that must pass before sending another sms otp. +max_frequency = "5s" + +# Use pre-defined map of phone number to OTP for testing. +# [auth.sms.test_otp] +# 4152127777 = "123456" + +# Configure logged in session timeouts. +# [auth.sessions] +# Force log out after the specified duration. +# timebox = "24h" +# Force log out if the user has been inactive longer than the specified duration. +# inactivity_timeout = "8h" + +# This hook runs before a new user is created and allows developers to reject the request based on the incoming user object. +# [auth.hook.before_user_created] +# enabled = true +# uri = "pg-functions://postgres/auth/before-user-created-hook" + +# This hook runs before a token is issued and allows you to add additional claims based on the authentication method used. +# [auth.hook.custom_access_token] +# enabled = true +# uri = "pg-functions:////" + +# Configure one of the supported SMS providers: `twilio`, `twilio_verify`, `messagebird`, `textlocal`, `vonage`. +[auth.sms.twilio] +enabled = false +account_sid = "" +message_service_sid = "" +# DO NOT commit your Twilio auth token to git. Use environment variable substitution instead: +auth_token = "env(SUPABASE_AUTH_SMS_TWILIO_AUTH_TOKEN)" + +# Multi-factor-authentication is available to Supabase Pro plan. +[auth.mfa] +# Control how many MFA factors can be enrolled at once per user. +max_enrolled_factors = 10 + +# Control MFA via App Authenticator (TOTP) +[auth.mfa.totp] +enroll_enabled = false +verify_enabled = false + +# Configure MFA via Phone Messaging +[auth.mfa.phone] +enroll_enabled = false +verify_enabled = false +otp_length = 6 +template = "Your code is {{ .Code }}" +max_frequency = "5s" + +# Configure MFA via WebAuthn +# [auth.mfa.web_authn] +# enroll_enabled = true +# verify_enabled = true + +# Use an external OAuth provider. The full list of providers are: `apple`, `azure`, `bitbucket`, +# `discord`, `facebook`, `github`, `gitlab`, `google`, `keycloak`, `linkedin_oidc`, `notion`, `twitch`, +# `twitter`, `x`, `slack`, `spotify`, `workos`, `zoom`. +[auth.external.apple] +enabled = false +client_id = "" +# DO NOT commit your OAuth provider secret to git. Use environment variable substitution instead: +secret = "env(SUPABASE_AUTH_EXTERNAL_APPLE_SECRET)" +# Overrides the default auth redirectUrl. +redirect_uri = "" +# Overrides the default auth provider URL. Used to support self-hosted gitlab, single-tenant Azure, +# or any other third-party OIDC providers. +url = "" +# If enabled, the nonce check will be skipped. Required for local sign in with Google auth. +skip_nonce_check = false +# If enabled, it will allow the user to successfully authenticate when the provider does not return an email address. +email_optional = false + +# Allow Solana wallet holders to sign in to your project via the Sign in with Solana (SIWS, EIP-4361) standard. +# You can configure "web3" rate limit in the [auth.rate_limit] section and set up [auth.captcha] if self-hosting. +[auth.web3.solana] +enabled = false + +# Use Firebase Auth as a third-party provider alongside Supabase Auth. +[auth.third_party.firebase] +enabled = false +# project_id = "my-firebase-project" + +# Use Auth0 as a third-party provider alongside Supabase Auth. +[auth.third_party.auth0] +enabled = false +# tenant = "my-auth0-tenant" +# tenant_region = "us" + +# Use AWS Cognito (Amplify) as a third-party provider alongside Supabase Auth. +[auth.third_party.aws_cognito] +enabled = false +# user_pool_id = "my-user-pool-id" +# user_pool_region = "us-east-1" + +# Use Clerk as a third-party provider alongside Supabase Auth. +[auth.third_party.clerk] +enabled = false +# Obtain from https://clerk.com/setup/supabase +# domain = "example.clerk.accounts.dev" + +# OAuth server configuration +[auth.oauth_server] +# Enable OAuth server functionality +enabled = false +# Path for OAuth consent flow UI +authorization_url_path = "/oauth/consent" +# Allow dynamic client registration +allow_dynamic_registration = false + +[edge_runtime] +enabled = true +# Supported request policies: `oneshot`, `per_worker`. +# `per_worker` (default) — enables hot reload during local development. +# `oneshot` — fallback mode if hot reload causes issues (e.g. in large repos or with symlinks). +policy = "per_worker" +# Port to attach the Chrome inspector for debugging edge functions. +inspector_port = 8083 +# The Deno major version to use. +deno_version = 2 + +# [edge_runtime.secrets] +# secret_key = "env(SECRET_VALUE)" + +[analytics] +enabled = true +port = 54327 +# Configure one of the supported backends: `postgres`, `bigquery`. +backend = "postgres" + +# Experimental features may be deprecated any time +[experimental] +# Configures Postgres storage engine to use OrioleDB (S3) +orioledb_version = "" +# Configures S3 bucket URL, eg. .s3-.amazonaws.com +s3_host = "env(S3_HOST)" +# Configures S3 bucket region, eg. us-east-1 +s3_region = "env(S3_REGION)" +# Configures AWS_ACCESS_KEY_ID for S3 bucket +s3_access_key = "env(S3_ACCESS_KEY)" +# Configures AWS_SECRET_ACCESS_KEY for S3 bucket +s3_secret_key = "env(S3_SECRET_KEY)" diff --git a/supabase/migrations/20260226232057_init.sql b/supabase/migrations/20260226232057_init.sql new file mode 100644 index 0000000..0848bea --- /dev/null +++ b/supabase/migrations/20260226232057_init.sql @@ -0,0 +1,283 @@ +-- CreateEnum +CREATE TYPE "UserSex" AS ENUM ('MALE', 'FEMALE'); + +-- CreateEnum +CREATE TYPE "Day" AS ENUM ('MONDAY', 'TUESDAY', 'WEDNESDAY', 'THURSDAY', 'FRIDAY'); + +-- CreateTable +CREATE TABLE "Admin" ( + "id" TEXT NOT NULL, + "username" TEXT NOT NULL, + + CONSTRAINT "Admin_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Student" ( + "id" TEXT NOT NULL, + "username" TEXT NOT NULL, + "name" TEXT NOT NULL, + "surname" TEXT NOT NULL, + "email" TEXT, + "phone" TEXT, + "address" TEXT NOT NULL, + "img" TEXT, + "bloodType" TEXT NOT NULL, + "sex" "UserSex" NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "parentId" TEXT NOT NULL, + "classId" INTEGER NOT NULL, + "gradeId" INTEGER NOT NULL, + "birthday" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "Student_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Teacher" ( + "id" TEXT NOT NULL, + "username" TEXT NOT NULL, + "name" TEXT NOT NULL, + "surname" TEXT NOT NULL, + "email" TEXT, + "phone" TEXT, + "address" TEXT NOT NULL, + "img" TEXT, + "bloodType" TEXT NOT NULL, + "sex" "UserSex" NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "birthday" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "Teacher_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Parent" ( + "id" TEXT NOT NULL, + "username" TEXT NOT NULL, + "name" TEXT NOT NULL, + "surname" TEXT NOT NULL, + "email" TEXT, + "phone" TEXT NOT NULL, + "address" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "Parent_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Grade" ( + "id" SERIAL NOT NULL, + "level" INTEGER NOT NULL, + + CONSTRAINT "Grade_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Class" ( + "id" SERIAL NOT NULL, + "name" TEXT NOT NULL, + "capacity" INTEGER NOT NULL, + "supervisorId" TEXT, + "gradeId" INTEGER NOT NULL, + + CONSTRAINT "Class_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Subject" ( + "id" SERIAL NOT NULL, + "name" TEXT NOT NULL, + + CONSTRAINT "Subject_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Lesson" ( + "id" SERIAL NOT NULL, + "name" TEXT NOT NULL, + "day" "Day" NOT NULL, + "startTime" TIMESTAMP(3) NOT NULL, + "endTime" TIMESTAMP(3) NOT NULL, + "subjectId" INTEGER NOT NULL, + "classId" INTEGER NOT NULL, + "teacherId" TEXT NOT NULL, + + CONSTRAINT "Lesson_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Exam" ( + "id" SERIAL NOT NULL, + "title" TEXT NOT NULL, + "startTime" TIMESTAMP(3) NOT NULL, + "endTime" TIMESTAMP(3) NOT NULL, + "lessonId" INTEGER NOT NULL, + + CONSTRAINT "Exam_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Assignment" ( + "id" SERIAL NOT NULL, + "title" TEXT NOT NULL, + "startDate" TIMESTAMP(3) NOT NULL, + "dueDate" TIMESTAMP(3) NOT NULL, + "lessonId" INTEGER NOT NULL, + + CONSTRAINT "Assignment_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Result" ( + "id" SERIAL NOT NULL, + "score" INTEGER NOT NULL, + "examId" INTEGER, + "assignmentId" INTEGER, + "studentId" TEXT NOT NULL, + + CONSTRAINT "Result_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Attendance" ( + "id" SERIAL NOT NULL, + "date" TIMESTAMP(3) NOT NULL, + "present" BOOLEAN NOT NULL, + "studentId" TEXT NOT NULL, + "lessonId" INTEGER NOT NULL, + + CONSTRAINT "Attendance_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Event" ( + "id" SERIAL NOT NULL, + "title" TEXT NOT NULL, + "description" TEXT NOT NULL, + "startTime" TIMESTAMP(3) NOT NULL, + "endTime" TIMESTAMP(3) NOT NULL, + "classId" INTEGER, + + CONSTRAINT "Event_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Announcement" ( + "id" SERIAL NOT NULL, + "title" TEXT NOT NULL, + "description" TEXT NOT NULL, + "date" TIMESTAMP(3) NOT NULL, + "classId" INTEGER, + + CONSTRAINT "Announcement_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "_SubjectToTeacher" ( + "A" INTEGER NOT NULL, + "B" TEXT NOT NULL +); + +-- CreateIndex +CREATE UNIQUE INDEX "Admin_username_key" ON "Admin"("username"); + +-- CreateIndex +CREATE UNIQUE INDEX "Student_username_key" ON "Student"("username"); + +-- CreateIndex +CREATE UNIQUE INDEX "Student_email_key" ON "Student"("email"); + +-- CreateIndex +CREATE UNIQUE INDEX "Student_phone_key" ON "Student"("phone"); + +-- CreateIndex +CREATE UNIQUE INDEX "Teacher_username_key" ON "Teacher"("username"); + +-- CreateIndex +CREATE UNIQUE INDEX "Teacher_email_key" ON "Teacher"("email"); + +-- CreateIndex +CREATE UNIQUE INDEX "Teacher_phone_key" ON "Teacher"("phone"); + +-- CreateIndex +CREATE UNIQUE INDEX "Parent_username_key" ON "Parent"("username"); + +-- CreateIndex +CREATE UNIQUE INDEX "Parent_email_key" ON "Parent"("email"); + +-- CreateIndex +CREATE UNIQUE INDEX "Parent_phone_key" ON "Parent"("phone"); + +-- CreateIndex +CREATE UNIQUE INDEX "Grade_level_key" ON "Grade"("level"); + +-- CreateIndex +CREATE UNIQUE INDEX "Class_name_key" ON "Class"("name"); + +-- CreateIndex +CREATE UNIQUE INDEX "Subject_name_key" ON "Subject"("name"); + +-- CreateIndex +CREATE UNIQUE INDEX "_SubjectToTeacher_AB_unique" ON "_SubjectToTeacher"("A", "B"); + +-- CreateIndex +CREATE INDEX "_SubjectToTeacher_B_index" ON "_SubjectToTeacher"("B"); + +-- AddForeignKey +ALTER TABLE "Student" ADD CONSTRAINT "Student_parentId_fkey" FOREIGN KEY ("parentId") REFERENCES "Parent"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Student" ADD CONSTRAINT "Student_classId_fkey" FOREIGN KEY ("classId") REFERENCES "Class"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Student" ADD CONSTRAINT "Student_gradeId_fkey" FOREIGN KEY ("gradeId") REFERENCES "Grade"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Class" ADD CONSTRAINT "Class_supervisorId_fkey" FOREIGN KEY ("supervisorId") REFERENCES "Teacher"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Class" ADD CONSTRAINT "Class_gradeId_fkey" FOREIGN KEY ("gradeId") REFERENCES "Grade"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Lesson" ADD CONSTRAINT "Lesson_subjectId_fkey" FOREIGN KEY ("subjectId") REFERENCES "Subject"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Lesson" ADD CONSTRAINT "Lesson_classId_fkey" FOREIGN KEY ("classId") REFERENCES "Class"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Lesson" ADD CONSTRAINT "Lesson_teacherId_fkey" FOREIGN KEY ("teacherId") REFERENCES "Teacher"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Exam" ADD CONSTRAINT "Exam_lessonId_fkey" FOREIGN KEY ("lessonId") REFERENCES "Lesson"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Assignment" ADD CONSTRAINT "Assignment_lessonId_fkey" FOREIGN KEY ("lessonId") REFERENCES "Lesson"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Result" ADD CONSTRAINT "Result_examId_fkey" FOREIGN KEY ("examId") REFERENCES "Exam"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Result" ADD CONSTRAINT "Result_assignmentId_fkey" FOREIGN KEY ("assignmentId") REFERENCES "Assignment"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Result" ADD CONSTRAINT "Result_studentId_fkey" FOREIGN KEY ("studentId") REFERENCES "Student"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Attendance" ADD CONSTRAINT "Attendance_studentId_fkey" FOREIGN KEY ("studentId") REFERENCES "Student"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Attendance" ADD CONSTRAINT "Attendance_lessonId_fkey" FOREIGN KEY ("lessonId") REFERENCES "Lesson"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Event" ADD CONSTRAINT "Event_classId_fkey" FOREIGN KEY ("classId") REFERENCES "Class"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Announcement" ADD CONSTRAINT "Announcement_classId_fkey" FOREIGN KEY ("classId") REFERENCES "Class"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "_SubjectToTeacher" ADD CONSTRAINT "_SubjectToTeacher_A_fkey" FOREIGN KEY ("A") REFERENCES "Subject"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "_SubjectToTeacher" ADD CONSTRAINT "_SubjectToTeacher_B_fkey" FOREIGN KEY ("B") REFERENCES "Teacher"("id") ON DELETE CASCADE ON UPDATE CASCADE; + diff --git a/supabase/migrations/20260227004419_clerk_roles.sql b/supabase/migrations/20260227004419_clerk_roles.sql new file mode 100644 index 0000000..08a0471 --- /dev/null +++ b/supabase/migrations/20260227004419_clerk_roles.sql @@ -0,0 +1,32 @@ +-- Create roles that Clerk passes in the JWT `role` claim +-- PostgREST attempts to assume these roles when making requests. +-- We create them and grant them the standard authenticated role permissions. + +DO $$ +BEGIN + IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'admin') THEN + CREATE ROLE admin NOLOGIN; + GRANT authenticated TO admin; + END IF; + + IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'teacher') THEN + CREATE ROLE teacher NOLOGIN; + GRANT authenticated TO teacher; + END IF; + + IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'student') THEN + CREATE ROLE student NOLOGIN; + GRANT authenticated TO student; + END IF; + + IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'parent') THEN + CREATE ROLE parent NOLOGIN; + GRANT authenticated TO parent; + END IF; +END $$; + +-- Grant the roles to the authenticator role so PostgREST can switch to them +GRANT admin TO authenticator; +GRANT teacher TO authenticator; +GRANT student TO authenticator; +GRANT parent TO authenticator; diff --git a/supabase/migrations/20260227004420_supabase_rls.sql b/supabase/migrations/20260227004420_supabase_rls.sql new file mode 100644 index 0000000..1f26968 --- /dev/null +++ b/supabase/migrations/20260227004420_supabase_rls.sql @@ -0,0 +1,201 @@ +-- 1. Enable RLS on all tables +DO $$ BEGIN + ALTER TABLE "Admin" ENABLE ROW LEVEL SECURITY; + ALTER TABLE "Student" ENABLE ROW LEVEL SECURITY; + ALTER TABLE "Teacher" ENABLE ROW LEVEL SECURITY; + ALTER TABLE "Parent" ENABLE ROW LEVEL SECURITY; + ALTER TABLE "Grade" ENABLE ROW LEVEL SECURITY; + ALTER TABLE "Class" ENABLE ROW LEVEL SECURITY; + ALTER TABLE "Subject" ENABLE ROW LEVEL SECURITY; + ALTER TABLE "Lesson" ENABLE ROW LEVEL SECURITY; + ALTER TABLE "Exam" ENABLE ROW LEVEL SECURITY; + ALTER TABLE "Assignment" ENABLE ROW LEVEL SECURITY; + ALTER TABLE "Result" ENABLE ROW LEVEL SECURITY; + ALTER TABLE "Attendance" ENABLE ROW LEVEL SECURITY; + ALTER TABLE "Event" ENABLE ROW LEVEL SECURITY; + ALTER TABLE "Announcement" ENABLE ROW LEVEL SECURITY; + ALTER TABLE "_SubjectToTeacher" ENABLE ROW LEVEL SECURITY; +EXCEPTION + WHEN undefined_table THEN + NULL; +END $$; + +-- 2. Utility helper functions connecting to Clerk JWT +CREATE OR REPLACE FUNCTION requesting_user_id() +RETURNS text +LANGUAGE sql STABLE +AS $$ + SELECT NULLIF(current_setting('request.jwt.claims', true)::json->>'sub', '')::text; +$$; + +CREATE OR REPLACE FUNCTION requesting_user_role() +RETURNS text +LANGUAGE sql STABLE +AS $$ + SELECT current_setting('request.jwt.claims', true)::json->>'role'; +$$; + +CREATE OR REPLACE FUNCTION is_admin() RETURNS boolean LANGUAGE sql STABLE AS $$ + SELECT requesting_user_role() = 'admin'; +$$; + +-- 3. Bypass-RLS Helper Functions for finding accessible IDs +-- We use SECURITY DEFINER SET search_path = public to execute these queries as the database owner, +-- which prevents infinite recursion errors (stack depth limit exceeded) when querying tables that have RLS enabled. +-- Transaction-local variables like `request.jwt.claims` perfectly persist through SECURITY DEFINER calls. + +CREATE OR REPLACE FUNCTION auth_user_classes() RETURNS SETOF integer LANGUAGE plpgsql SECURITY DEFINER SET search_path = public STABLE AS $$ +BEGIN + RETURN QUERY + SELECT "classId" FROM "Student" WHERE id = requesting_user_id() AND requesting_user_role() = 'student' + UNION + SELECT "classId" FROM "Student" WHERE "parentId" = requesting_user_id() AND requesting_user_role() = 'parent' + UNION + SELECT "classId" FROM "Lesson" WHERE "teacherId" = requesting_user_id() AND requesting_user_role() = 'teacher' + UNION + SELECT id FROM "Class" WHERE "supervisorId" = requesting_user_id() AND requesting_user_role() = 'teacher'; +END; +$$; + +CREATE OR REPLACE FUNCTION auth_user_students() RETURNS SETOF text LANGUAGE plpgsql SECURITY DEFINER SET search_path = public STABLE AS $$ +BEGIN + RETURN QUERY + SELECT id FROM "Student" WHERE id = requesting_user_id() AND requesting_user_role() = 'student' + UNION + SELECT id FROM "Student" WHERE "parentId" = requesting_user_id() AND requesting_user_role() = 'parent' + UNION + SELECT id FROM "Student" WHERE "classId" IN ( + SELECT "classId" FROM "Lesson" WHERE "teacherId" = requesting_user_id() + ) AND requesting_user_role() = 'teacher'; +END; +$$; + +CREATE OR REPLACE FUNCTION auth_user_lessons() RETURNS SETOF integer LANGUAGE plpgsql SECURITY DEFINER SET search_path = public STABLE AS $$ +BEGIN + RETURN QUERY + SELECT id FROM "Lesson" WHERE "teacherId" = requesting_user_id() AND requesting_user_role() = 'teacher' + UNION + SELECT id FROM "Lesson" WHERE "classId" IN ( + SELECT "classId" FROM "Student" WHERE id = requesting_user_id() AND requesting_user_role() = 'student' + ) + UNION + SELECT id FROM "Lesson" WHERE "classId" IN ( + SELECT "classId" FROM "Student" WHERE "parentId" = requesting_user_id() AND requesting_user_role() = 'parent' + ); +END; +$$; + +CREATE OR REPLACE FUNCTION auth_user_subjects() RETURNS SETOF integer LANGUAGE plpgsql SECURITY DEFINER SET search_path = public STABLE AS $$ +BEGIN + RETURN QUERY + SELECT "A" FROM "_SubjectToTeacher" WHERE "B" = requesting_user_id() AND requesting_user_role() = 'teacher' + UNION + SELECT "subjectId" FROM "Lesson" WHERE "classId" IN ( + SELECT "classId" FROM "Student" WHERE id = requesting_user_id() AND requesting_user_role() = 'student' + ) + UNION + SELECT "subjectId" FROM "Lesson" WHERE "classId" IN ( + SELECT "classId" FROM "Student" WHERE "parentId" = requesting_user_id() AND requesting_user_role() = 'parent' + ); +END; +$$; + +CREATE OR REPLACE FUNCTION auth_user_teachers() RETURNS SETOF text LANGUAGE plpgsql SECURITY DEFINER SET search_path = public STABLE AS $$ +BEGIN + RETURN QUERY + SELECT id FROM "Teacher" WHERE id = requesting_user_id() AND requesting_user_role() = 'teacher' + UNION + SELECT "teacherId" FROM "Lesson" WHERE "classId" IN ( + SELECT "classId" FROM "Student" WHERE id = requesting_user_id() AND requesting_user_role() = 'student' + ) + UNION + SELECT "teacherId" FROM "Lesson" WHERE "classId" IN ( + SELECT "classId" FROM "Student" WHERE "parentId" = requesting_user_id() AND requesting_user_role() = 'parent' + ); +END; +$$; + +CREATE OR REPLACE FUNCTION auth_user_parents() RETURNS SETOF text LANGUAGE plpgsql SECURITY DEFINER SET search_path = public STABLE AS $$ +BEGIN + RETURN QUERY + SELECT id FROM "Parent" WHERE id = requesting_user_id() AND requesting_user_role() = 'parent' + UNION + SELECT "parentId" FROM "Student" WHERE id = requesting_user_id() AND requesting_user_role() = 'student'; +END; +$$; + + + +-- 4. Define Table Policies using Helpers +CREATE POLICY "Admin has full access" ON "Admin" FOR ALL USING (is_admin()); +CREATE POLICY "Admins have full access" ON "Student" FOR ALL USING (is_admin()); +CREATE POLICY "Admins have full access" ON "Teacher" FOR ALL USING (is_admin()); +CREATE POLICY "Admins have full access" ON "Parent" FOR ALL USING (is_admin()); +CREATE POLICY "Admins have full access" ON "Grade" FOR ALL USING (is_admin()); +CREATE POLICY "Admins have full access" ON "Class" FOR ALL USING (is_admin()); +CREATE POLICY "Admins have full access" ON "Subject" FOR ALL USING (is_admin()); +CREATE POLICY "Admins have full access" ON "Lesson" FOR ALL USING (is_admin()); +CREATE POLICY "Admins have full access" ON "Exam" FOR ALL USING (is_admin()); +CREATE POLICY "Admins have full access" ON "Assignment" FOR ALL USING (is_admin()); +CREATE POLICY "Admins have full access" ON "Result" FOR ALL USING (is_admin()); +CREATE POLICY "Admins have full access" ON "Attendance" FOR ALL USING (is_admin()); +CREATE POLICY "Admins have full access" ON "Event" FOR ALL USING (is_admin()); +CREATE POLICY "Admins have full access" ON "Announcement" FOR ALL USING (is_admin()); +CREATE POLICY "Admins have full access" ON "_SubjectToTeacher" FOR ALL USING (is_admin()); + + +CREATE POLICY "Anyone can view grades" ON "Grade" FOR SELECT TO authenticated USING (true); +CREATE POLICY "Anyone can view subject-teacher" ON "_SubjectToTeacher" FOR SELECT TO authenticated USING (true); + +CREATE POLICY "Users can view permitted students" ON "Student" FOR SELECT USING ( + is_admin() OR id IN (SELECT auth_user_students()) +); + +CREATE POLICY "Users can view permitted teachers" ON "Teacher" FOR SELECT USING ( + is_admin() OR id IN (SELECT auth_user_teachers()) +); + +CREATE POLICY "Users can view permitted parents" ON "Parent" FOR SELECT USING ( + is_admin() OR id IN (SELECT auth_user_parents()) +); + +CREATE POLICY "Users can view permitted subjects" ON "Subject" FOR SELECT USING ( + is_admin() OR id IN (SELECT auth_user_subjects()) +); + +CREATE POLICY "Users can view permitted classes" ON "Class" FOR SELECT USING ( + is_admin() OR id IN (SELECT auth_user_classes()) +); + +CREATE POLICY "Users can view permitted lessons" ON "Lesson" FOR SELECT USING ( + is_admin() OR id IN (SELECT auth_user_lessons()) +); + +CREATE POLICY "Users can view permitted exams" ON "Exam" FOR SELECT USING ( + is_admin() OR "lessonId" IN (SELECT auth_user_lessons()) +); + +CREATE POLICY "Users can view permitted assignments" ON "Assignment" FOR SELECT USING ( + is_admin() OR "lessonId" IN (SELECT auth_user_lessons()) +); + +CREATE POLICY "Users can view permitted results" ON "Result" FOR SELECT USING ( + is_admin() OR "studentId" IN (SELECT auth_user_students()) OR ( + requesting_user_role() = 'teacher' AND ( + "examId" IN (SELECT id FROM "Exam" WHERE "lessonId" IN (SELECT auth_user_lessons())) OR + "assignmentId" IN (SELECT id FROM "Assignment" WHERE "lessonId" IN (SELECT auth_user_lessons())) + ) + ) +); + +CREATE POLICY "Users can view permitted attendance" ON "Attendance" FOR SELECT USING ( + is_admin() OR "studentId" IN (SELECT auth_user_students()) +); + +CREATE POLICY "Users can view permitted events" ON "Event" FOR SELECT USING ( + is_admin() OR "classId" IS NULL OR "classId" IN (SELECT auth_user_classes()) +); + +CREATE POLICY "Users can view permitted announcements" ON "Announcement" FOR SELECT USING ( + is_admin() OR "classId" IS NULL OR "classId" IN (SELECT auth_user_classes()) +); diff --git a/supabase/migrations/20260228000000_explicit_mapping_tables.sql b/supabase/migrations/20260228000000_explicit_mapping_tables.sql new file mode 100644 index 0000000..bc32f19 --- /dev/null +++ b/supabase/migrations/20260228000000_explicit_mapping_tables.sql @@ -0,0 +1,41 @@ +-- Migration: Drop implicit _SubjectToTeacher and replace with explicit TeacherSubject + +-- 1. Create the new explicit mapping table +CREATE TABLE "TeacherSubject" ( + "id" SERIAL PRIMARY KEY, + "teacherId" TEXT NOT NULL REFERENCES "Teacher"("id") ON DELETE CASCADE, + "subjectId" INTEGER NOT NULL REFERENCES "Subject"("id") ON DELETE CASCADE, + "isPrimary" BOOLEAN DEFAULT false, + "assignedAt" TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +-- 2. Migrate existing data (Optional, but good practice if not resetting) +INSERT INTO "TeacherSubject" ("teacherId", "subjectId") +SELECT "B", "A" FROM "_SubjectToTeacher"; + +-- 3. Drop the old implicit mapping table +DROP TABLE "_SubjectToTeacher"; + +-- 4. Enable RLS on the new table +ALTER TABLE "TeacherSubject" ENABLE ROW LEVEL SECURITY; + +-- 5. Define RLS Policies for the new table +CREATE POLICY "Admins have full access" ON "TeacherSubject" FOR ALL USING (is_admin()); +CREATE POLICY "Anyone can view teacher-subjects" ON "TeacherSubject" FOR SELECT TO authenticated USING (true); + + +-- 6. Update the auth_user_subjects RLS Helper Function to use explicitly named mapping table +CREATE OR REPLACE FUNCTION auth_user_subjects() RETURNS SETOF integer LANGUAGE plpgsql SECURITY DEFINER SET search_path = public STABLE AS $$ +BEGIN + RETURN QUERY + SELECT "subjectId" FROM "TeacherSubject" WHERE "teacherId" = requesting_user_id() AND requesting_user_role() = 'teacher' + UNION + SELECT "subjectId" FROM "Lesson" WHERE "classId" IN ( + SELECT "classId" FROM "Student" WHERE id = requesting_user_id() AND requesting_user_role() = 'student' + ) + UNION + SELECT "subjectId" FROM "Lesson" WHERE "classId" IN ( + SELECT "classId" FROM "Student" WHERE "parentId" = requesting_user_id() AND requesting_user_role() = 'parent' + ); +END; +$$; diff --git a/tailwind.config.ts b/tailwind.config.ts new file mode 100644 index 0000000..05ca007 --- /dev/null +++ b/tailwind.config.ts @@ -0,0 +1,28 @@ +import type { Config } from "tailwindcss"; + +const config: Config = { + content: [ + "./src/pages/**/*.{js,ts,jsx,tsx,mdx}", + "./src/components/**/*.{js,ts,jsx,tsx,mdx}", + "./src/app/**/*.{js,ts,jsx,tsx,mdx}", + ], + theme: { + extend: { + backgroundImage: { + "gradient-radial": "radial-gradient(var(--tw-gradient-stops))", + "gradient-conic": + "conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))", + }, + colors: { + lamaSky: "#C3EBFA", + lamaSkyLight: "#EDF9FD", + lamaPurple: "#CFCEFF", + lamaPurpleLight: "#F1F0FF", + lamaYellow: "#FAE27C", + lamaYellowLight: "#FEFCE8", + }, + }, + }, + plugins: [], +}; +export default config; diff --git a/test-date.js b/test-date.js new file mode 100644 index 0000000..2464e34 --- /dev/null +++ b/test-date.js @@ -0,0 +1,29 @@ +const latestMonday = new Date(); +const dayOfWeek = latestMonday.getDay(); +const daysSinceMonday = dayOfWeek === 0 ? 6 : dayOfWeek - 1; +latestMonday.setDate(latestMonday.getDate() - daysSinceMonday); +latestMonday.setHours(0, 0, 0, 0); + +const dayMap = { MONDAY: 0, TUESDAY: 1, WEDNESDAY: 2, THURSDAY: 3, FRIDAY: 4 }; + +function adjust(dayKey) { + const targetDayOffset = dayMap[dayKey] || 0; + + const targetDate = new Date(latestMonday); + targetDate.setDate(latestMonday.getDate() + targetDayOffset); + + const originalStart = new Date("2026-02-27T10:00:00Z"); // specific test time + const adjustedStart = new Date(originalStart); + + adjustedStart.setFullYear( + targetDate.getFullYear(), + targetDate.getMonth(), + targetDate.getDate() + ); + + console.log(dayKey, adjustedStart.toString()); +} + +adjust("MONDAY"); +adjust("WEDNESDAY"); +adjust("FRIDAY"); diff --git a/test-lessons.ts b/test-lessons.ts new file mode 100644 index 0000000..419692d --- /dev/null +++ b/test-lessons.ts @@ -0,0 +1,19 @@ +import "dotenv/config"; +import { createClient } from "@supabase/supabase-js"; +const supabase = createClient(process.env.NEXT_PUBLIC_SUPABASE_URL!, "sb_secret_N7UND0UgjKTVK-Uodkm0Hg_xSvEMPvz"); + +async function main() { + // 1. Get student 1 ID + const { data: students } = await supabase.from("Student").select("id").limit(1); + const studentId = students?.[0]?.id; + console.log("Student ID:", studentId); + + // 2. Execute SQL to simulate RLS + const { data, error } = await supabase.rpc("simulate_rls_query", { + jwt_claims: JSON.stringify({ sub: studentId, role: "student" }), + query_table: "Lesson" + }); + console.log("RPC Error:", error); + // Wait, rpc might not exist. Let's just create a quick migration or do it directly. +} +main(); diff --git a/test-rls-jwt.ts b/test-rls-jwt.ts new file mode 100644 index 0000000..33d3afc --- /dev/null +++ b/test-rls-jwt.ts @@ -0,0 +1,12 @@ +import "dotenv/config"; +import { createClient } from "@supabase/supabase-js"; +const supabase = createClient(process.env.NEXT_PUBLIC_SUPABASE_URL!, process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!); + +async function test() { + const { data: { session }, error: authErr } = await supabase.auth.signInWithPassword({ + email: 'student1@example.com', + password: '&%5C400l&%' + }); + console.log("session:", session ? "success" : "failed", authErr); +} +test(); diff --git a/test-rls-sql.ts b/test-rls-sql.ts new file mode 100644 index 0000000..b6aa086 --- /dev/null +++ b/test-rls-sql.ts @@ -0,0 +1,13 @@ +import "dotenv/config"; +import { createClient } from "@supabase/supabase-js"; +const supabase = createClient(process.env.NEXT_PUBLIC_SUPABASE_URL!, process.env.SUPABASE_SERVICE_ROLE_KEY!); + +async function main() { + const { data: students } = await supabase.from("Student").select("id").limit(1); + const id = students?.[0]?.id; + + // We can execute raw SQL using the rpc or we can just send it. + // Wait, Supabase js doesn't support raw queries directly via the client without RPC. + console.log("Student ID:", id); +} +main(); diff --git a/test-student-jwt.ts b/test-student-jwt.ts new file mode 100644 index 0000000..bc0091e --- /dev/null +++ b/test-student-jwt.ts @@ -0,0 +1,14 @@ +import "dotenv/config"; +import { clerkClient } from "@clerk/nextjs/server"; +import { createClient } from "@supabase/supabase-js"; + +async function main() { + const clerk = clerkClient(); + const users = await clerk.users.getUserList({ query: "student1" }); + const user = users.data[0]; + + // We can't generate a true template JWT from backend clerkClient easily. + // However, we can use clerkClient to check the user's publicMetadata. + console.log("publicMetadata:", user.publicMetadata); +} +main(); diff --git a/test_jwt.js b/test_jwt.js new file mode 100644 index 0000000..d096fa7 --- /dev/null +++ b/test_jwt.js @@ -0,0 +1,2 @@ +const jwt = require('jsonwebtoken'); +console.log("Checking JWT format..."); diff --git a/test_lesson.js b/test_lesson.js new file mode 100644 index 0000000..858c445 --- /dev/null +++ b/test_lesson.js @@ -0,0 +1,2 @@ +const { createClient } = require('@supabase/supabase-js'); +// wait we don't have supabase js locally mapped easily to check schema, let's just use psql diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..7b28589 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "preserve", + "incremental": true, + "plugins": [ + { + "name": "next" + } + ], + "paths": { + "@/*": ["./src/*"] + } + }, + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], + "exclude": ["node_modules"] +} diff --git a/usercard_counts.txt b/usercard_counts.txt new file mode 100644 index 0000000..109030f --- /dev/null +++ b/usercard_counts.txt @@ -0,0 +1,4 @@ +[UserCard] Parent count: 25 +[UserCard] Student count: 50 +[UserCard] Teacher count: 15 +[UserCard] Admin count: 2