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 0000000..6928d0e Binary files /dev/null and b/public/announcement.png differ diff --git a/public/assignment.png b/public/assignment.png new file mode 100644 index 0000000..c37102d Binary files /dev/null and b/public/assignment.png differ diff --git a/public/attendance.png b/public/attendance.png new file mode 100644 index 0000000..eb72e77 Binary files /dev/null and b/public/attendance.png differ diff --git a/public/avatar.png b/public/avatar.png new file mode 100644 index 0000000..f88478e Binary files /dev/null and b/public/avatar.png differ diff --git a/public/blood.png b/public/blood.png new file mode 100644 index 0000000..e1f3382 Binary files /dev/null and b/public/blood.png differ diff --git a/public/calendar.png b/public/calendar.png new file mode 100644 index 0000000..c808804 Binary files /dev/null and b/public/calendar.png differ diff --git a/public/class.png b/public/class.png new file mode 100644 index 0000000..e4dc30a Binary files /dev/null and b/public/class.png differ diff --git a/public/close.png b/public/close.png new file mode 100644 index 0000000..47e597f Binary files /dev/null and b/public/close.png differ diff --git a/public/create.png b/public/create.png new file mode 100644 index 0000000..0fb69e8 Binary files /dev/null and b/public/create.png differ diff --git a/public/date.png b/public/date.png new file mode 100644 index 0000000..4a8c6a1 Binary files /dev/null and b/public/date.png differ diff --git a/public/delete.png b/public/delete.png new file mode 100644 index 0000000..ec67e8c Binary files /dev/null and b/public/delete.png differ diff --git a/public/exam.png b/public/exam.png new file mode 100644 index 0000000..ab137db Binary files /dev/null and b/public/exam.png differ diff --git a/public/filter.png b/public/filter.png new file mode 100644 index 0000000..ed3b86a Binary files /dev/null and b/public/filter.png differ diff --git a/public/finance.png b/public/finance.png new file mode 100644 index 0000000..042c6ea Binary files /dev/null and b/public/finance.png differ diff --git a/public/home.png b/public/home.png new file mode 100644 index 0000000..e5a6e99 Binary files /dev/null and b/public/home.png differ diff --git a/public/lesson.png b/public/lesson.png new file mode 100644 index 0000000..6009636 Binary files /dev/null and b/public/lesson.png differ diff --git a/public/logo.png b/public/logo.png new file mode 100644 index 0000000..e90915b Binary files /dev/null and b/public/logo.png differ diff --git a/public/logout.png b/public/logout.png new file mode 100644 index 0000000..c52aef6 Binary files /dev/null and b/public/logout.png differ diff --git a/public/mail.png b/public/mail.png new file mode 100644 index 0000000..3b8f857 Binary files /dev/null and b/public/mail.png differ diff --git a/public/maleFemale.png b/public/maleFemale.png new file mode 100644 index 0000000..fbf1b5b Binary files /dev/null and b/public/maleFemale.png differ diff --git a/public/message.png b/public/message.png new file mode 100644 index 0000000..7dad5a2 Binary files /dev/null and b/public/message.png differ diff --git a/public/more.png b/public/more.png new file mode 100644 index 0000000..7eafa7b Binary files /dev/null and b/public/more.png differ diff --git a/public/moreDark.png b/public/moreDark.png new file mode 100644 index 0000000..0ae4c35 Binary files /dev/null and b/public/moreDark.png differ diff --git a/public/noAvatar.png b/public/noAvatar.png new file mode 100644 index 0000000..eb2a81c Binary files /dev/null and b/public/noAvatar.png differ diff --git a/public/parent.png b/public/parent.png new file mode 100644 index 0000000..56ddf9c Binary files /dev/null and b/public/parent.png differ diff --git a/public/phone.png b/public/phone.png new file mode 100644 index 0000000..f2d4135 Binary files /dev/null and b/public/phone.png differ diff --git a/public/profile.png b/public/profile.png new file mode 100644 index 0000000..2de2d7a Binary files /dev/null and b/public/profile.png differ diff --git a/public/result.png b/public/result.png new file mode 100644 index 0000000..40bf74c Binary files /dev/null and b/public/result.png differ diff --git a/public/search.png b/public/search.png new file mode 100644 index 0000000..5fa8b03 Binary files /dev/null and b/public/search.png differ diff --git a/public/setting.png b/public/setting.png new file mode 100644 index 0000000..193d779 Binary files /dev/null and b/public/setting.png differ diff --git a/public/singleAttendance.png b/public/singleAttendance.png new file mode 100644 index 0000000..cf7db9b Binary files /dev/null and b/public/singleAttendance.png differ diff --git a/public/singleBranch.png b/public/singleBranch.png new file mode 100644 index 0000000..b9d8431 Binary files /dev/null and b/public/singleBranch.png differ diff --git a/public/singleClass.png b/public/singleClass.png new file mode 100644 index 0000000..e9aea85 Binary files /dev/null and b/public/singleClass.png differ diff --git a/public/singleLesson.png b/public/singleLesson.png new file mode 100644 index 0000000..0d3de8a Binary files /dev/null and b/public/singleLesson.png differ diff --git a/public/sort.png b/public/sort.png new file mode 100644 index 0000000..c52382d Binary files /dev/null and b/public/sort.png differ diff --git a/public/student.png b/public/student.png new file mode 100644 index 0000000..7088284 Binary files /dev/null and b/public/student.png differ diff --git a/public/subject.png b/public/subject.png new file mode 100644 index 0000000..d33a747 Binary files /dev/null and b/public/subject.png differ diff --git a/public/teacher.png b/public/teacher.png new file mode 100644 index 0000000..50d984b Binary files /dev/null and b/public/teacher.png differ diff --git a/public/update.png b/public/update.png new file mode 100644 index 0000000..bb6685b Binary files /dev/null and b/public/update.png differ diff --git a/public/upload.png b/public/upload.png new file mode 100644 index 0000000..61a8a91 Binary files /dev/null and b/public/upload.png differ diff --git a/public/view.png b/public/view.png new file mode 100644 index 0000000..6acc995 Binary files /dev/null and b/public/view.png differ 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 0000000..1b59cd8 Binary files /dev/null and b/src/app/favicon.ico differ 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