diff --git a/.env b/.env index f70fed1..41a3980 100644 --- a/.env +++ b/.env @@ -6,7 +6,6 @@ NEXT_PUBLIC_CLERK_SIGN_UP_URL=/sign-up NEXT_PUBLIC_CLERK_AFTER_SIGN_IN_URL=/dashboard NEXT_PUBLIC_CLERK_AFTER_SIGN_UP_URL=/dashboard -POSTGRES_PRISMA_URL="postgres://default:5YBlPxAmaN4c@ep-morning-smoke-a4r3sc7j-pooler.us-east-1.aws.neon.tech:5432/verceldb?sslmode=require&pgbouncer=true&connect_timeout=15" -POSTGRES_URL_NON_POOLING="postgres://default:5YBlPxAmaN4c@ep-morning-smoke-a4r3sc7j.us-east-1.aws.neon.tech:5432/verceldb?sslmode=require" - -DATABASE_URL="postgresql://johndoe:randompassword@localhost:5432/mydb?schema=public" \ No newline at end of file +POSTGRES_PRISMA_URL="postgresql://postgres:Monteria80@localhost:5432/quickform?schema=public" +POSTGRES_URL_NON_POOLING="postgresql://postgres:Monteria80@localhost:5432/quickform?schema=public" +DATABASE_URL="postgresql://postgres:Monteria80@localhost:5432/quickform?schema=public" \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..5dabb89 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "sarif-viewer.connectToGithubCodeScanning": "off" +} \ No newline at end of file diff --git a/Docs/AddElement.md b/Docs/AddElement.md new file mode 100644 index 0000000..f6200b3 --- /dev/null +++ b/Docs/AddElement.md @@ -0,0 +1,304 @@ +# Adding a New Form Element + +This guide explains how to add a new form element type to the Quick Form Builder system. + +## Overview + +Form elements are the building blocks of forms in our system. Each element type (like text fields, checkboxes, etc.) is implemented as a separate component that follows a consistent pattern and interface. + +## Element Categories + +Elements are divided into two categories in the sidebar: + +1. **Layout Elements**: Static elements used for form structure and presentation (e.g., Title, SubTitle, Paragraph, Separator, Spacer, Image) +2. **Form Elements**: Interactive input elements that collect data (e.g., TextField, NumberField, ImageUpload) + +When adding a new element, make sure to place it in the appropriate section in `FormElementsSidebar.tsx`. + +## TypeScript Best Practices + +### Image Handling +When working with images in TypeScript, avoid using the global `Image` constructor as it can conflict with imported icon components. Instead: + +```typescript +// ❌ Don't use this +const img = new Image(); + +// ✅ Use this instead +const img = document.createElement('img') as HTMLImageElement; +``` + +### Form Element Type Definitions +Always define proper types for your element's attributes: + +```typescript +type CustomInstance = FormElementInstance & { + extraAttributes: { + // Define your element's specific attributes here + label: string; + required: boolean; + // ... other attributes + }; +}; + +// Use zod for runtime validation +const propertiesSchema = z.object({ + label: z.string().min(2).max(50), + required: z.boolean().default(false), + // ... other validations +}); +``` + +### Property Updates +Always use the `useDesigner` hook to update element properties. Direct mutations of `extraAttributes` will not trigger re-renders or persist changes: + +```typescript +function PropertiesComponent({ elementInstance }: { elementInstance: FormElementInstance }) { + const element = elementInstance as CustomInstance; + const { updateElement } = useDesigner(); + const form = useForm({ + resolver: zodResolver(propertiesSchema), + mode: "onBlur", + defaultValues: element.extraAttributes, + }); + + // ❌ Don't update properties directly + const wrongWay = () => { + element.extraAttributes.someProperty = newValue; // This won't work properly + }; + + // ✅ Use updateElement from useDesigner + const rightWay = (values: propertiesFormSchemaType) => { + updateElement(element.id, { + ...element, + extraAttributes: { + ...element.extraAttributes, + ...values, + }, + }); + }; + + return ( +
+ { + e.preventDefault(); + }} + className="space-y-3" + > + {/* Form fields here */} +
+ + ); +} +``` + +## Step-by-Step Guide + +### 1. Add Element Type Definition + +In `src/components/FormElements.tsx`, add your new element type to the `ElementsType` union type: + +```typescript +export type ElementsType = + | "TextField" + | "TitleField" + // ... other existing types ... + | "YourNewFieldType"; // Add your new type here +``` + +### 2. Create Element Component File + +Create a new file for your element under `src/components/field/` (e.g., `YourNewField.tsx`). The file should include: + +#### a) Type Definitions +```typescript +type CustomInstance = FormElementInstance & { + extraAttributes: { + label: string; + helperText: string; + required: boolean; + placeholder: string; + // Add any additional attributes your element needs + }; +}; + +const propertiesSchema = z.object({ + label: z.string().min(2).max(50), + helperText: z.string().max(200), + required: z.boolean().default(false), + placeholder: z.string().max(50), + // Add validation for any additional properties +}); +``` + +#### b) Element Implementation +```typescript +export const YourNewFormElement: FormElement = { + type: "YourNewFieldType", + + // Factory function to create new instances + construct: (id: string) => ({ + id, + type: "YourNewFieldType", + extraAttributes: { + label: "Default Label", + helperText: "Default helper text", + required: false, + placeholder: "Default placeholder", + }, + }), + + // Sidebar button configuration + designerBtnElement: { + icon: YourIcon, // Import from react-icons + label: "Your Element", + }, + + // Component references + designerComponent: DesignerComponent, + formComponent: FormComponent, + propertiesComponent: PropertiesComponent, + + // Validation logic + validate: (formElement: FormElementInstance, currentValue: string): boolean => { + const element = formElement as CustomInstance; + if (element.extraAttributes.required) { + return currentValue.length > 0; + } + return true; + }, +}; +``` + +#### c) Required Components + +1. Designer Component (Preview in builder): +```typescript +function DesignerComponent({ elementInstance }: { elementInstance: FormElementInstance }) { + const element = elementInstance as CustomInstance; + const { label, helperText, required, placeholder } = element.extraAttributes; + return ( +
+ + + {helperText &&

{helperText}

} +
+ ); +} +``` + +2. Form Component (Live form element): +```typescript +function FormComponent({ + elementInstance, + submitValue, + isInvalid, + defaultValue, +}: { + elementInstance: FormElementInstance; + submitValue?: (key: string, value: string) => void; + isInvalid?: boolean; + defaultValue?: string; +}) { + const element = elementInstance as CustomInstance; + // Implementation for the actual form input +} +``` + +3. Properties Component (Settings panel): +```typescript +function PropertiesComponent({ elementInstance }: { elementInstance: FormElementInstance }) { + const element = elementInstance as CustomInstance; + const { updateElement } = useDesigner(); + const form = useForm({ + resolver: zodResolver(propertiesSchema), + mode: "onBlur", + defaultValues: element.extraAttributes, + }); + + // ❌ Don't update properties directly + const wrongWay = () => { + element.extraAttributes.someProperty = newValue; // This won't work properly + }; + + // ✅ Use updateElement from useDesigner + const rightWay = (values: propertiesFormSchemaType) => { + updateElement(element.id, { + ...element, + extraAttributes: { + ...element.extraAttributes, + ...values, + }, + }); + }; + + return ( +
+ { + e.preventDefault(); + }} + className="space-y-3" + > + {/* Form fields here */} +
+ + ); +} +``` + +### 3. Register the Element + +In `src/components/FormElements.tsx`, import and add your element to the FormElements object: + +```typescript +import { YourNewFormElement } from "./field/YourNewField"; + +export const FormElements: FormElementsType = { + TextField: TextFieldFormElement, + // ... other elements ... + YourNewFieldType: YourNewFormElement, +}; +``` + +### 4. Add to Sidebar + +In `src/components/FormElementsSidebar.tsx`, add your element to the sidebar: + +```typescript + +``` + +## Database Integration + +No additional database changes are required. The system stores form content as JSON in the Prisma database, and new elements are automatically handled as long as they follow the FormElementInstance interface. + +## Testing Your New Element + +1. Create a new form +2. Verify your element appears in the sidebar +3. Test dragging and dropping the element +4. Test property editing +5. Test form saving and loading +6. Test form publishing and submission + +## Best Practices + +1. Follow the existing naming conventions +2. Implement proper validation +3. Include helpful default values +4. Add appropriate TypeScript types +5. Ensure proper error handling +6. Test all component states (preview, edit, submit) + +## Common Issues + +- If the element doesn't appear in the sidebar, check the FormElements export +- If properties don't update, verify the PropertiesComponent implementation +- If validation fails, check the validate function implementation diff --git a/audit.js b/audit.js new file mode 100644 index 0000000..d25b57c --- /dev/null +++ b/audit.js @@ -0,0 +1,92 @@ +const fs = require('fs'); +const path = require('path'); +const glob = require('glob'); + +// Read package.json and get dependencies +const packageJson = JSON.parse(fs.readFileSync('package.json', 'utf8')); +const dependencies = { + ...packageJson.dependencies, + ...packageJson.devDependencies +}; + +// Define directories to scan +const dirsToScan = [ + 'src', + 'pages', + 'components', + 'lib', + 'utils', + 'styles', + 'app' +]; + +// Get all JS/TS files +const files = glob.sync(`{${dirsToScan.join(',')}}/**/*.{js,jsx,ts,tsx}`); + +// Initialize results +const results = { + used: new Set(), + unused: new Set(), + nextSpecific: new Set(['next', '@next/font', 'next-auth']), // Common Next.js packages + internal: new Set() // For @/ imports +}; + +// Process each file +files.forEach(file => { + const content = fs.readFileSync(file, 'utf8'); + + // Check for import statements + const importRegex = /import.*?['"]([^'"]+)['"]/g; + let match; + + while ((match = importRegex.exec(content)) !== null) { + const importPath = match[1]; + + // Handle different import types + if (importPath.startsWith('@/')) { + results.internal.add(importPath); + continue; + } + + // Get package name (handle scoped packages) + const packageName = importPath.startsWith('@') + ? importPath.split('/').slice(0, 2).join('/') + : importPath.split('/')[0]; + + if (dependencies[packageName]) { + results.used.add(packageName); + } + } + + // Check for require statements + const requireRegex = /require\(['"]([^'"]+)['"]\)/g; + while ((match = requireRegex.exec(content)) !== null) { + const packageName = match[1].split('/')[0]; + if (dependencies[packageName]) { + results.used.add(packageName); + } + } +}); + +// Find unused dependencies +Object.keys(dependencies).forEach(dep => { + if (!results.used.has(dep) && !results.nextSpecific.has(dep)) { + results.unused.add(dep); + } +}); + +// Print results +console.log('\nDependency Audit Results\n'); +console.log('Used Dependencies:', Array.from(results.used).sort()); +console.log('\nPotentially Unused Dependencies:', Array.from(results.unused).sort()); +console.log('\nNext.js Specific Dependencies:', Array.from(results.nextSpecific)); +console.log('\nInternal Imports:', Array.from(results.internal).sort()); + +// Print summary +console.log('\nSummary:'); +console.log(`Total Dependencies: ${Object.keys(dependencies).length}`); +console.log(`Used: ${results.used.size}`); +console.log(`Potentially Unused: ${results.unused.size}`); +console.log(`Next.js Specific: ${results.nextSpecific.size}`); + +console.log('\nNote: This is a basic analysis and may have false positives. Please verify before removing any packages.'); \ No newline at end of file diff --git a/moon.yml b/moon.yml new file mode 100644 index 0000000..d47cb15 --- /dev/null +++ b/moon.yml @@ -0,0 +1,20 @@ +type: application + +# Project configuration +project: + name: Quick-Form-Builder + description: Form builder application + +# Tasks configuration +tasks: + dev: + command: npm run dev + local: true + build: + command: npm run build + deps: + - ^:build + test: + command: npm run test + lint: + command: npm run lint diff --git a/next.config.mjs b/next.config.mjs index e709436..2f2c6cb 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -1,8 +1,20 @@ /** @type {import('next').NextConfig} */ const nextConfig = { experimental: { - serverActions: true, + serverActions: { + bodySizeLimit: '10mb' + } }, + images: { + remotePatterns: [ + { + protocol: 'https', + hostname: 'placehold.co', + }, + ], + domains: ['placehold.co'], + unoptimized: true + } }; export default nextConfig; diff --git a/package-lock.json b/package-lock.json index 77d3a87..56e362c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,7 @@ "@clerk/nextjs": "^4.29.9", "@dnd-kit/core": "^6.1.0", "@hookform/resolvers": "^3.3.4", - "@prisma/client": "^5.10.2", + "@prisma/client": "^6.3.0", "@radix-ui/react-accordion": "^1.1.2", "@radix-ui/react-alert-dialog": "^1.0.5", "@radix-ui/react-aspect-ratio": "^1.0.3", @@ -40,17 +40,19 @@ "@radix-ui/react-toggle": "^1.0.3", "@radix-ui/react-toggle-group": "^1.0.4", "@radix-ui/react-tooltip": "^1.0.7", + "canvas": "^3.1.0", "class-variance-authority": "^0.7.0", "clsx": "^2.1.0", "cmdk": "^1.0.0", "date-fns": "^3.4.0", + "directory-tree": "^3.5.2", "embla-carousel-react": "^8.0.0", "framer-motion": "^11.0.12", "input-otp": "^1.1.0", "lucide-react": "^0.356.0", - "next": "14.1.3", - "next-themes": "^0.2.1", - "nextjs-toploader": "^1.6.6", + "next": "14.2.23", + "next-themes": "^0.4.4", + "nextjs-toploader": "^3.7.15", "react": "^18", "react-confetti": "^6.1.0", "react-day-picker": "^8.10.0", @@ -72,6 +74,7 @@ "eslint": "^8", "eslint-config-next": "14.1.3", "postcss": "^8", + "prisma": "^6.3.0", "tailwindcss": "^3.3.0", "typescript": "^5" } @@ -108,12 +111,13 @@ } }, "node_modules/@clerk/backend": { - "version": "0.38.3", - "resolved": "https://registry.npmjs.org/@clerk/backend/-/backend-0.38.3.tgz", - "integrity": "sha512-k14WRljVNETpIYrt99MBP/Zd7KEwkudQKSCEMatQbiRkWgrpwDWE8Czv+JzF1J7sdMiicBI+p2ph9biX1EOFzw==", + "version": "0.38.14", + "resolved": "https://registry.npmjs.org/@clerk/backend/-/backend-0.38.14.tgz", + "integrity": "sha512-hejdtVIy5z5TABDASEJnigrbGnN15JYzJbTjnbpCO8n6Bw2B1DVfR1fsQZw1TaE9HSWh15UCZMjuvtYH0IHciQ==", + "license": "MIT", "dependencies": { - "@clerk/shared": "1.3.3", - "@clerk/types": "3.62.1", + "@clerk/shared": "1.4.2", + "@clerk/types": "3.65.4", "@peculiar/webcrypto": "1.4.1", "@types/node": "16.18.6", "cookie": "0.5.0", @@ -129,20 +133,23 @@ "node_modules/@clerk/backend/node_modules/@types/node": { "version": "16.18.6", "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.6.tgz", - "integrity": "sha512-vmYJF0REqDyyU0gviezF/KHq/fYaUbFhkcNbQCuPGFQj6VTbXuHZoxs/Y7mutWe73C8AC6l9fFu8mSYiBAqkGA==" + "integrity": "sha512-vmYJF0REqDyyU0gviezF/KHq/fYaUbFhkcNbQCuPGFQj6VTbXuHZoxs/Y7mutWe73C8AC6l9fFu8mSYiBAqkGA==", + "license": "MIT" }, "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==" + "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==", + "license": "0BSD" }, "node_modules/@clerk/clerk-react": { - "version": "4.30.7", - "resolved": "https://registry.npmjs.org/@clerk/clerk-react/-/clerk-react-4.30.7.tgz", - "integrity": "sha512-+6Q1hVteqn66gFLiCKSqqSdz2MBjsEjs1fkGLAEKZC1GdfOKrH6oWcLuSwUdyqRvJWuyjeIgwq15zoHtXKyztA==", + "version": "4.32.4", + "resolved": "https://registry.npmjs.org/@clerk/clerk-react/-/clerk-react-4.32.4.tgz", + "integrity": "sha512-QJP4oThzyTpMnZR27r5iwH1Bqh+oBJp5S1D0lRDPB+kmObfSWdzVAePXhD0PCZn/3lkb6UXeoH+T0oSM2ySPSQ==", + "license": "MIT", "dependencies": { - "@clerk/shared": "1.3.3", - "@clerk/types": "3.62.1", + "@clerk/shared": "1.4.2", + "@clerk/types": "3.65.4", "tslib": "2.4.1" }, "engines": { @@ -155,16 +162,19 @@ "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==" + "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==", + "license": "0BSD" }, "node_modules/@clerk/clerk-sdk-node": { - "version": "4.13.11", - "resolved": "https://registry.npmjs.org/@clerk/clerk-sdk-node/-/clerk-sdk-node-4.13.11.tgz", - "integrity": "sha512-6CiRx61SW0B7i+4STlID537LvwFJvNGWxxQZY96OPHQnvYGYsp+9PdEyY4zaQiyLQBLYJt1+uc7VsdSYY5Omww==", - "dependencies": { - "@clerk/backend": "0.38.3", - "@clerk/shared": "1.3.3", - "@clerk/types": "3.62.1", + "version": "4.13.22", + "resolved": "https://registry.npmjs.org/@clerk/clerk-sdk-node/-/clerk-sdk-node-4.13.22.tgz", + "integrity": "sha512-2XwlQ01nK/4cqJsiKFWw5GPZ7l7BChyCobZ6Jd4GZDr65pGhljO3BdKEHA4Dqs/d9H3QJkaZqUAcmpahBaRzug==", + "deprecated": "January 10 2025 marks the end of support for @clerk/clerk-sdk-node as previously announced in our October 2024 deprecation notice. Express users can migrate to the @clerk/express package. For more information, you can find our changelog here: https://clerk.com/changelog/2025-01-10-node-sdk-eol", + "license": "MIT", + "dependencies": { + "@clerk/backend": "0.38.14", + "@clerk/shared": "1.4.2", + "@clerk/types": "3.65.4", "@types/cookies": "0.7.7", "@types/express": "4.17.14", "@types/node-fetch": "2.6.2", @@ -180,6 +190,7 @@ "version": "3.2.1", "resolved": "https://registry.npmjs.org/snakecase-keys/-/snakecase-keys-3.2.1.tgz", "integrity": "sha512-CjU5pyRfwOtaOITYv5C8DzpZ8XA/ieRsDpr93HI2r6e3YInC6moZpSQbmUtg8cTk58tq2x3jcG2gv+p1IZGmMA==", + "license": "MIT", "dependencies": { "map-obj": "^4.1.0", "to-snake-case": "^1.0.0" @@ -191,19 +202,20 @@ "node_modules/@clerk/clerk-sdk-node/node_modules/tslib": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", - "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==" + "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==", + "license": "0BSD" }, "node_modules/@clerk/nextjs": { - "version": "4.29.9", - "resolved": "https://registry.npmjs.org/@clerk/nextjs/-/nextjs-4.29.9.tgz", - "integrity": "sha512-RsOz+lxlPYJi9cBvhBRqAUVUOMBT20R3ppt3eof97DkqCT6YaHJx/S13XcYUuo6ojYRDDJ/nI6XiLcfpqIJO6g==", - "dependencies": { - "@clerk/backend": "0.38.3", - "@clerk/clerk-react": "4.30.7", - "@clerk/clerk-sdk-node": "4.13.11", - "@clerk/shared": "1.3.3", - "@clerk/types": "3.62.1", - "path-to-regexp": "6.2.1", + "version": "4.31.6", + "resolved": "https://registry.npmjs.org/@clerk/nextjs/-/nextjs-4.31.6.tgz", + "integrity": "sha512-rGZ687oHrMzWu2zA5HXHVdCp31C7Ltb+pM0Sc6CgJ7KfURbK8GsG2w/Yw2PhntuKoya4y8h03uaXdgfCxGOzMQ==", + "license": "MIT", + "dependencies": { + "@clerk/backend": "0.38.14", + "@clerk/clerk-react": "4.32.4", + "@clerk/clerk-sdk-node": "4.13.22", + "@clerk/shared": "1.4.2", + "@clerk/types": "3.65.4", "tslib": "2.4.1" }, "engines": { @@ -221,9 +233,10 @@ "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==" }, "node_modules/@clerk/shared": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@clerk/shared/-/shared-1.3.3.tgz", - "integrity": "sha512-Eein8cK72dlvY6Q1uFuw9K9MJH1OPjU8FzWloMTKklBo+iPiM6+uENGeGwlY5KId3q/kgPwRc2hBQnUoaijxCQ==", + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@clerk/shared/-/shared-1.4.2.tgz", + "integrity": "sha512-R+OkzCtnNU7sn/F6dBfdY5lKs84TN785VZdBBefmyr7zsXcFEqbCcfQzyvgtIS28Ln5SifFEBoAyYR334IXO8w==", + "license": "MIT", "dependencies": { "glob-to-regexp": "0.4.1", "js-cookie": "3.0.1", @@ -239,9 +252,10 @@ } }, "node_modules/@clerk/types": { - "version": "3.62.1", - "resolved": "https://registry.npmjs.org/@clerk/types/-/types-3.62.1.tgz", - "integrity": "sha512-RmQhWB7EMZw2nE24viQG79VyEUULZYWndYew5oXiZx06DyvysMNCorDyEGRmgBbprv7bnbYhHdOtKmx8Wj0jug==", + "version": "3.65.4", + "resolved": "https://registry.npmjs.org/@clerk/types/-/types-3.65.4.tgz", + "integrity": "sha512-sDNt7kp/rYVUF+wJvLPlH+YMm/iKgtARVmTZBU0rgXKPrEKJA1vdmT2UCe4geO1lgqHCi1lXTzm2O90NCWC9yA==", + "license": "MIT", "dependencies": { "csstype": "3.1.1" }, @@ -252,7 +266,8 @@ "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==" + "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==", + "license": "MIT" }, "node_modules/@dnd-kit/accessibility": { "version": "3.1.0", @@ -506,9 +521,10 @@ } }, "node_modules/@next/env": { - "version": "14.1.3", - "resolved": "https://registry.npmjs.org/@next/env/-/env-14.1.3.tgz", - "integrity": "sha512-VhgXTvrgeBRxNPjyfBsDIMvgsKDxjlpw4IAUsHCX8Gjl1vtHUYRT3+xfQ/wwvLPDd/6kqfLqk9Pt4+7gysuCKQ==" + "version": "14.2.23", + "resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.23.tgz", + "integrity": "sha512-CysUC9IO+2Bh0omJ3qrb47S8DtsTKbFidGm6ow4gXIG6reZybqxbkH2nhdEm1tC8SmgzDdpq3BIML0PWsmyUYA==", + "license": "MIT" }, "node_modules/@next/eslint-plugin-next": { "version": "14.1.3", @@ -520,12 +536,13 @@ } }, "node_modules/@next/swc-darwin-arm64": { - "version": "14.1.3", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.1.3.tgz", - "integrity": "sha512-LALu0yIBPRiG9ANrD5ncB3pjpO0Gli9ZLhxdOu6ZUNf3x1r3ea1rd9Q+4xxUkGrUXLqKVK9/lDkpYIJaCJ6AHQ==", + "version": "14.2.23", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.23.tgz", + "integrity": "sha512-WhtEntt6NcbABA8ypEoFd3uzq5iAnrl9AnZt9dXdO+PZLACE32z3a3qA5OoV20JrbJfSJ6Sd6EqGZTrlRnGxQQ==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "darwin" @@ -535,12 +552,13 @@ } }, "node_modules/@next/swc-darwin-x64": { - "version": "14.1.3", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.1.3.tgz", - "integrity": "sha512-E/9WQeXxkqw2dfcn5UcjApFgUq73jqNKaE5bysDm58hEUdUGedVrnRhblhJM7HbCZNhtVl0j+6TXsK0PuzXTCg==", + "version": "14.2.23", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.23.tgz", + "integrity": "sha512-vwLw0HN2gVclT/ikO6EcE+LcIN+0mddJ53yG4eZd0rXkuEr/RnOaMH8wg/sYl5iz5AYYRo/l6XX7FIo6kwbw1Q==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "darwin" @@ -550,12 +568,13 @@ } }, "node_modules/@next/swc-linux-arm64-gnu": { - "version": "14.1.3", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.1.3.tgz", - "integrity": "sha512-USArX9B+3rZSXYLFvgy0NVWQgqh6LHWDmMt38O4lmiJNQcwazeI6xRvSsliDLKt+78KChVacNiwvOMbl6g6BBw==", + "version": "14.2.23", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.23.tgz", + "integrity": "sha512-uuAYwD3At2fu5CH1wD7FpP87mnjAv4+DNvLaR9kiIi8DLStWSW304kF09p1EQfhcbUI1Py2vZlBO2VaVqMRtpg==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -565,12 +584,13 @@ } }, "node_modules/@next/swc-linux-arm64-musl": { - "version": "14.1.3", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.1.3.tgz", - "integrity": "sha512-esk1RkRBLSIEp1qaQXv1+s6ZdYzuVCnDAZySpa62iFTMGTisCyNQmqyCTL9P+cLJ4N9FKCI3ojtSfsyPHJDQNw==", + "version": "14.2.23", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.23.tgz", + "integrity": "sha512-Mm5KHd7nGgeJ4EETvVgFuqKOyDh+UMXHXxye6wRRFDr4FdVRI6YTxajoV2aHE8jqC14xeAMVZvLqYqS7isHL+g==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -580,12 +600,13 @@ } }, "node_modules/@next/swc-linux-x64-gnu": { - "version": "14.1.3", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.1.3.tgz", - "integrity": "sha512-8uOgRlYEYiKo0L8YGeS+3TudHVDWDjPVDUcST+z+dUzgBbTEwSSIaSgF/vkcC1T/iwl4QX9iuUyUdQEl0Kxalg==", + "version": "14.2.23", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.23.tgz", + "integrity": "sha512-Ybfqlyzm4sMSEQO6lDksggAIxnvWSG2cDWnG2jgd+MLbHYn2pvFA8DQ4pT2Vjk3Cwrv+HIg7vXJ8lCiLz79qoQ==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -595,12 +616,13 @@ } }, "node_modules/@next/swc-linux-x64-musl": { - "version": "14.1.3", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.1.3.tgz", - "integrity": "sha512-DX2zqz05ziElLoxskgHasaJBREC5Y9TJcbR2LYqu4r7naff25B4iXkfXWfcp69uD75/0URmmoSgT8JclJtrBoQ==", + "version": "14.2.23", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.23.tgz", + "integrity": "sha512-OSQX94sxd1gOUz3jhhdocnKsy4/peG8zV1HVaW6DLEbEmRRtUCUQZcKxUD9atLYa3RZA+YJx+WZdOnTkDuNDNA==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -610,12 +632,13 @@ } }, "node_modules/@next/swc-win32-arm64-msvc": { - "version": "14.1.3", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.1.3.tgz", - "integrity": "sha512-HjssFsCdsD4GHstXSQxsi2l70F/5FsRTRQp8xNgmQs15SxUfUJRvSI9qKny/jLkY3gLgiCR3+6A7wzzK0DBlfA==", + "version": "14.2.23", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.23.tgz", + "integrity": "sha512-ezmbgZy++XpIMTcTNd0L4k7+cNI4ET5vMv/oqNfTuSXkZtSA9BURElPFyarjjGtRgZ9/zuKDHoMdZwDZIY3ehQ==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "win32" @@ -625,12 +648,13 @@ } }, "node_modules/@next/swc-win32-ia32-msvc": { - "version": "14.1.3", - "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.1.3.tgz", - "integrity": "sha512-DRuxD5axfDM1/Ue4VahwSxl1O5rn61hX8/sF0HY8y0iCbpqdxw3rB3QasdHn/LJ6Wb2y5DoWzXcz3L1Cr+Thrw==", + "version": "14.2.23", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.23.tgz", + "integrity": "sha512-zfHZOGguFCqAJ7zldTKg4tJHPJyJCOFhpoJcVxKL9BSUHScVDnMdDuOU1zPPGdOzr/GWxbhYTjyiEgLEpAoFPA==", "cpu": [ "ia32" ], + "license": "MIT", "optional": true, "os": [ "win32" @@ -640,12 +664,13 @@ } }, "node_modules/@next/swc-win32-x64-msvc": { - "version": "14.1.3", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.1.3.tgz", - "integrity": "sha512-uC2DaDoWH7h1P/aJ4Fok3Xiw6P0Lo4ez7NbowW2VGNXw/Xv6tOuLUcxhBYZxsSUJtpeknCi8/fvnSpyCFp4Rcg==", + "version": "14.2.23", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.23.tgz", + "integrity": "sha512-xCtq5BD553SzOgSZ7UH5LH+OATQihydObTrCTvVzOro8QiWYKdBVwcB2Mn2MLMo6DGW9yH1LSPw7jS7HhgJgjw==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "win32" @@ -687,19 +712,21 @@ } }, "node_modules/@peculiar/asn1-schema": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.3.8.tgz", - "integrity": "sha512-ULB1XqHKx1WBU/tTFIA+uARuRoBVZ4pNdOA878RDrRbBfBGcSzi5HBkdScC6ZbHn8z7L8gmKCgPC1LHRrP46tA==", + "version": "2.3.15", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.3.15.tgz", + "integrity": "sha512-QPeD8UA8axQREpgR5UTAfu2mqQmm97oUqahDtNdBcfj3qAnoXzFdQW+aNf/tD2WVXF8Fhmftxoj0eMIT++gX2w==", + "license": "MIT", "dependencies": { "asn1js": "^3.0.5", - "pvtsutils": "^1.3.5", - "tslib": "^2.6.2" + "pvtsutils": "^1.3.6", + "tslib": "^2.8.1" } }, "node_modules/@peculiar/json-schema": { "version": "1.1.12", "resolved": "https://registry.npmjs.org/@peculiar/json-schema/-/json-schema-1.1.12.tgz", "integrity": "sha512-coUfuoMeIB7B8/NMekxaDzLhaYmp0HZNPEjYRm9goRou8UZIC3z21s0sL9AWoCw4EG876QyO3kYrc61WNF9B/w==", + "license": "MIT", "dependencies": { "tslib": "^2.0.0" }, @@ -711,6 +738,7 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/@peculiar/webcrypto/-/webcrypto-1.4.1.tgz", "integrity": "sha512-eK4C6WTNYxoI7JOabMoZICiyqRRtJB220bh0Mbj5RwRycleZf9BPyZoxsTvpP0FpmVS2aS13NKOuh5/tN3sIRw==", + "license": "MIT", "dependencies": { "@peculiar/asn1-schema": "^2.3.0", "@peculiar/json-schema": "^1.1.12", @@ -732,70 +760,75 @@ } }, "node_modules/@prisma/client": { - "version": "5.10.2", - "resolved": "https://registry.npmjs.org/@prisma/client/-/client-5.10.2.tgz", - "integrity": "sha512-ef49hzB2yJZCvM5gFHMxSFL9KYrIP9udpT5rYo0CsHD4P9IKj473MbhU1gjKKftiwWBTIyrt9jukprzZXazyag==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/@prisma/client/-/client-6.3.0.tgz", + "integrity": "sha512-BY3Fi28PUSk447Bpv22LhZp4HgNPo7NsEN+EteM1CLDnLjig5863jpW+3c3HHLFmml+nB/eJv1CjSriFZ8z7Cg==", "hasInstallScript": true, + "license": "Apache-2.0", "engines": { - "node": ">=16.13" + "node": ">=18.18" }, "peerDependencies": { - "prisma": "*" + "prisma": "*", + "typescript": ">=5.1.0" }, "peerDependenciesMeta": { "prisma": { "optional": true + }, + "typescript": { + "optional": true } } }, "node_modules/@prisma/debug": { - "version": "5.10.2", - "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-5.10.2.tgz", - "integrity": "sha512-bkBOmH9dpEBbMKFJj8V+Zp8IZHIBjy3fSyhLhxj4FmKGb/UBSt9doyfA6k1UeUREsMJft7xgPYBbHSOYBr8XCA==", - "optional": true, - "peer": true + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-6.3.0.tgz", + "integrity": "sha512-m1lQv//0Rc5RG8TBpNUuLCxC35Ghi5XfpPmL83Gh04/GICHD2J5H2ndMlaljrUNaQDF9dOxIuFAYP1rE9wkXkg==", + "devOptional": true, + "license": "Apache-2.0" }, "node_modules/@prisma/engines": { - "version": "5.10.2", - "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-5.10.2.tgz", - "integrity": "sha512-HkSJvix6PW8YqEEt3zHfCYYJY69CXsNdhU+wna+4Y7EZ+AwzeupMnUThmvaDA7uqswiHkgm5/SZ6/4CStjaGmw==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-6.3.0.tgz", + "integrity": "sha512-RXqYhlZb9sx/xkUfYIZuEPn7sT0WgTxNOuEYQ7AGw3IMpP9QGVEDVsluc/GcNkM8NTJszeqk8AplJzI9lm7Jxw==", + "devOptional": true, "hasInstallScript": true, - "optional": true, - "peer": true, + "license": "Apache-2.0", "dependencies": { - "@prisma/debug": "5.10.2", - "@prisma/engines-version": "5.10.0-34.5a9203d0590c951969e85a7d07215503f4672eb9", - "@prisma/fetch-engine": "5.10.2", - "@prisma/get-platform": "5.10.2" + "@prisma/debug": "6.3.0", + "@prisma/engines-version": "6.3.0-17.acc0b9dd43eb689cbd20c9470515d719db10d0b0", + "@prisma/fetch-engine": "6.3.0", + "@prisma/get-platform": "6.3.0" } }, "node_modules/@prisma/engines-version": { - "version": "5.10.0-34.5a9203d0590c951969e85a7d07215503f4672eb9", - "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-5.10.0-34.5a9203d0590c951969e85a7d07215503f4672eb9.tgz", - "integrity": "sha512-uCy/++3Jx/O3ufM+qv2H1L4tOemTNqcP/gyEVOlZqTpBvYJUe0tWtW0y3o2Ueq04mll4aM5X3f6ugQftOSLdFQ==", - "optional": true, - "peer": true + "version": "6.3.0-17.acc0b9dd43eb689cbd20c9470515d719db10d0b0", + "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-6.3.0-17.acc0b9dd43eb689cbd20c9470515d719db10d0b0.tgz", + "integrity": "sha512-R/ZcMuaWZT2UBmgX3Ko6PAV3f8//ZzsjRIG1eKqp3f2rqEqVtCv+mtzuH2rBPUC9ujJ5kCb9wwpxeyCkLcHVyA==", + "devOptional": true, + "license": "Apache-2.0" }, "node_modules/@prisma/fetch-engine": { - "version": "5.10.2", - "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-5.10.2.tgz", - "integrity": "sha512-dSmXcqSt6DpTmMaLQ9K8ZKzVAMH3qwGCmYEZr/uVnzVhxRJ1EbT/w2MMwIdBNq1zT69Rvh0h75WMIi0mrIw7Hg==", - "optional": true, - "peer": true, + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-6.3.0.tgz", + "integrity": "sha512-GBy0iT4f1mH31ePzfcpVSUa7JLRTeq4914FG2vR3LqDwRweSm4ja1o5flGDz+eVIa/BNYfkBvRRxv4D6ve6Eew==", + "devOptional": true, + "license": "Apache-2.0", "dependencies": { - "@prisma/debug": "5.10.2", - "@prisma/engines-version": "5.10.0-34.5a9203d0590c951969e85a7d07215503f4672eb9", - "@prisma/get-platform": "5.10.2" + "@prisma/debug": "6.3.0", + "@prisma/engines-version": "6.3.0-17.acc0b9dd43eb689cbd20c9470515d719db10d0b0", + "@prisma/get-platform": "6.3.0" } }, "node_modules/@prisma/get-platform": { - "version": "5.10.2", - "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-5.10.2.tgz", - "integrity": "sha512-nqXP6vHiY2PIsebBAuDeWiUYg8h8mfjBckHh6Jezuwej0QJNnjDiOq30uesmg+JXxGk99nqyG3B7wpcOODzXvg==", - "optional": true, - "peer": true, + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-6.3.0.tgz", + "integrity": "sha512-V8zZ1d0xfyi6FjpNP4AcYuwSpGcdmu35OXWnTPm8IW594PYALzKXHwIa9+o0f+Lo9AecFWrwrwaoYe56UNfTtQ==", + "devOptional": true, + "license": "Apache-2.0", "dependencies": { - "@prisma/debug": "5.10.2" + "@prisma/debug": "6.3.0" } }, "node_modules/@radix-ui/number": { @@ -2139,11 +2172,19 @@ "integrity": "sha512-RbhOOTCNoCrbfkRyoXODZp75MlpiHMgbE5MEBZAnnnLyQNgrigEj4p0lzsMDyc1zVsJDLrivB58tgg3emX0eEA==", "dev": true }, + "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.2", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.2.tgz", - "integrity": "sha512-E4KcWTpoLHqwPHLxidpOqQbcrZVgi0rsmmZXUle1jXmJfuIf/UWpczUJ7MZZ5tlxytgJXyp0w4PGkkeLiuIdZw==", + "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" } }, @@ -2151,6 +2192,7 @@ "version": "1.19.5", "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", + "license": "MIT", "dependencies": { "@types/connect": "*", "@types/node": "*" @@ -2160,6 +2202,7 @@ "version": "3.4.38", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "license": "MIT", "dependencies": { "@types/node": "*" } @@ -2168,6 +2211,7 @@ "version": "0.7.7", "resolved": "https://registry.npmjs.org/@types/cookies/-/cookies-0.7.7.tgz", "integrity": "sha512-h7BcvPUogWbKCzBR2lY4oqaZbO3jXZksexYJVFvkrFeLgbZjQkU4x8pRq6eg2MHXQhY0McQdqmmsxRWlVAHooA==", + "license": "MIT", "dependencies": { "@types/connect": "*", "@types/express": "*", @@ -2179,6 +2223,7 @@ "version": "4.17.14", "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.14.tgz", "integrity": "sha512-TEbt+vaPFQ+xpxFLFssxUDXj5cWCxZJjIcB7Yg0k0GMHGtgtQgpvx/MUQUeAkNbA9AAGrwkAsoeItdTgS7FMyg==", + "license": "MIT", "dependencies": { "@types/body-parser": "*", "@types/express-serve-static-core": "^4.17.18", @@ -2187,9 +2232,10 @@ } }, "node_modules/@types/express-serve-static-core": { - "version": "4.17.43", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.43.tgz", - "integrity": "sha512-oaYtiBirUOPQGSWNGPWnzyAFJ0BP3cwvN4oWZQY+zUBwpVIGsKUkpBpSztp74drYcjavs7SKFZ4DX1V2QeN8rg==", + "version": "4.19.6", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.6.tgz", + "integrity": "sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A==", + "license": "MIT", "dependencies": { "@types/node": "*", "@types/qs": "*", @@ -2200,7 +2246,8 @@ "node_modules/@types/http-errors": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", - "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==" + "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", + "license": "MIT" }, "node_modules/@types/json5": { "version": "0.0.29", @@ -2211,12 +2258,14 @@ "node_modules/@types/keygrip": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/@types/keygrip/-/keygrip-1.0.6.tgz", - "integrity": "sha512-lZuNAY9xeJt7Bx4t4dx0rYCDqGPW8RXhQZK1td7d4H6E9zYbLoOtjBvfwdTKpsyxQI/2jv+armjX/RW+ZNpXOQ==" + "integrity": "sha512-lZuNAY9xeJt7Bx4t4dx0rYCDqGPW8RXhQZK1td7d4H6E9zYbLoOtjBvfwdTKpsyxQI/2jv+armjX/RW+ZNpXOQ==", + "license": "MIT" }, "node_modules/@types/mime": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", - "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==" + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "license": "MIT" }, "node_modules/@types/node": { "version": "20.11.26", @@ -2230,16 +2279,12 @@ "version": "2.6.2", "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.2.tgz", "integrity": "sha512-DHqhlq5jeESLy19TYhLakJ07kNumXWjcDdxXsLUMJZ6ue8VZJj4kLPQVE/2mdHh3xZziNF1xppu5lwmS53HR+A==", + "license": "MIT", "dependencies": { "@types/node": "*", "form-data": "^3.0.0" } }, - "node_modules/@types/nprogress": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@types/nprogress/-/nprogress-0.2.3.tgz", - "integrity": "sha512-k7kRA033QNtC+gLc4VPlfnue58CM1iQLgn1IMAU8VPHGOj7oIHPp9UlhedEnD/Gl8evoCjwkZjlBORtZ3JByUA==" - }, "node_modules/@types/prop-types": { "version": "15.7.11", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.11.tgz", @@ -2247,14 +2292,16 @@ "devOptional": true }, "node_modules/@types/qs": { - "version": "6.9.12", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.12.tgz", - "integrity": "sha512-bZcOkJ6uWrL0Qb2NAWKa7TBU+mJHPzhx9jjLL1KHF+XpzEcR7EXHvjbHlGtR/IsP1vyPrehuS6XqkmaePy//mg==" + "version": "6.9.18", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.18.tgz", + "integrity": "sha512-kK7dgTYDyGqS+e2Q4aK9X3D7q234CIZ1Bv0q/7Z5IwRDoADNU81xXJK/YVyLbLTZCoIwUoDoffFeF+p/eIklAA==", + "license": "MIT" }, "node_modules/@types/range-parser": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", - "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==" + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "license": "MIT" }, "node_modules/@types/react": { "version": "18.2.65", @@ -2286,19 +2333,21 @@ "version": "0.17.4", "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", + "license": "MIT", "dependencies": { "@types/mime": "^1", "@types/node": "*" } }, "node_modules/@types/serve-static": { - "version": "1.15.5", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.5.tgz", - "integrity": "sha512-PDRk21MnK70hja/YF8AHfC7yIsiQHn1rcXx7ijCFBX/k+XQJhQT/gw3xekXKJvx+5SXaMMS8oqQy09Mzvz2TuQ==", + "version": "1.15.7", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", + "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", + "license": "MIT", "dependencies": { "@types/http-errors": "*", - "@types/mime": "*", - "@types/node": "*" + "@types/node": "*", + "@types/send": "*" } }, "node_modules/@typescript-eslint/parser": { @@ -2541,6 +2590,15 @@ "dequal": "^2.0.3" } }, + "node_modules/array-back": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz", + "integrity": "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "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", @@ -2729,6 +2787,7 @@ "version": "3.0.5", "resolved": "https://registry.npmjs.org/asn1js/-/asn1js-3.0.5.tgz", "integrity": "sha512-FVnvrKJwpt9LP2lAMl8qZswRNm3T4q9CON+bxldk2iwk3FFpuwhx2FfinyitizWHsVYyaY+y5JzDR0rCMV5yTQ==", + "license": "BSD-3-Clause", "dependencies": { "pvtsutils": "^1.3.2", "pvutils": "^1.1.3", @@ -2756,7 +2815,8 @@ "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" }, "node_modules/autoprefixer": { "version": "10.4.18", @@ -2833,6 +2893,26 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "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/binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", @@ -2841,6 +2921,17 @@ "node": ">=8" } }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "license": "MIT", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -2852,11 +2943,12 @@ } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "license": "MIT", "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -2894,6 +2986,30 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "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": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, "node_modules/busboy": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", @@ -2937,6 +3053,7 @@ "version": "5.3.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "license": "MIT", "engines": { "node": ">=6" } @@ -2953,6 +3070,7 @@ "version": "6.2.2", "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz", "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==", + "license": "MIT", "dependencies": { "camelcase": "^5.3.1", "map-obj": "^4.0.0", @@ -2966,9 +3084,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001597", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001597.tgz", - "integrity": "sha512-7LjJvmQU6Sj7bL0j5b5WY/3n7utXUJvAe1lxhsHDbLmwX9mdL86Yjtr+5SRCyf8qME4M7pU2hswj0FpyBVCv9w==", + "version": "1.0.30001695", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001695.tgz", + "integrity": "sha512-vHyLade6wTgI2u1ec3WQBxv+2BrTERV28UXQu9LO6lZ9pYeMk34vjXFLOxo1A4UBA8XTL4njRQZdno/yYaSmWw==", "funding": [ { "type": "opencollective", @@ -2982,7 +3100,22 @@ "type": "github", "url": "https://github.com/sponsors/ai" } - ] + ], + "license": "CC-BY-4.0" + }, + "node_modules/canvas": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/canvas/-/canvas-3.1.0.tgz", + "integrity": "sha512-tTj3CqqukVJ9NgSahykNwtGda7V33VLObwrHfzT0vqJXu7J4d4C/7kQQW3fOEGDfZZoILPut5H00gOjyttPGyg==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "node-addon-api": "^7.0.0", + "prebuild-install": "^7.1.1" + }, + "engines": { + "node": "^18.12.0 || >= 20.9.0" + } }, "node_modules/chalk": { "version": "4.1.2", @@ -3034,6 +3167,12 @@ "node": ">= 6" } }, + "node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "license": "ISC" + }, "node_modules/class-variance-authority": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.0.tgz", @@ -3099,6 +3238,7 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", "dependencies": { "delayed-stream": "~1.0.0" }, @@ -3106,6 +3246,125 @@ "node": ">= 0.8" } }, + "node_modules/command-line-args": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-5.2.1.tgz", + "integrity": "sha512-H4UfQhZyakIjC74I9d34fGYDwk3XpSr17QhEd0Q3I9Xq1CETHo4Hcuo87WyWHpAF1aSLjLRf5lD9ZGX2qStUvg==", + "license": "MIT", + "dependencies": { + "array-back": "^3.1.0", + "find-replace": "^3.0.0", + "lodash.camelcase": "^4.3.0", + "typical": "^4.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/command-line-usage": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-6.1.3.tgz", + "integrity": "sha512-sH5ZSPr+7UStsloltmDh7Ce5fb8XPlHyoPzTpyyMuYCtervL65+ubVZ6Q61cFtFl62UyJlc8/JwERRbAFPUqgw==", + "license": "MIT", + "dependencies": { + "array-back": "^4.0.2", + "chalk": "^2.4.2", + "table-layout": "^1.0.2", + "typical": "^5.2.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/command-line-usage/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/command-line-usage/node_modules/array-back": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.2.tgz", + "integrity": "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/command-line-usage/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/command-line-usage/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/command-line-usage/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "license": "MIT" + }, + "node_modules/command-line-usage/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/command-line-usage/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/command-line-usage/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/command-line-usage/node_modules/typical": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", + "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/commander": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", @@ -3124,14 +3383,16 @@ "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/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -3190,6 +3451,30 @@ } } }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "license": "MIT", + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -3200,6 +3485,7 @@ "version": "4.2.2", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -3242,6 +3528,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", "engines": { "node": ">=0.4.0" } @@ -3255,6 +3542,15 @@ "node": ">=6" } }, + "node_modules/detect-libc": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", + "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, "node_modules/detect-node-es": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", @@ -3277,6 +3573,22 @@ "node": ">=8" } }, + "node_modules/directory-tree": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/directory-tree/-/directory-tree-3.5.2.tgz", + "integrity": "sha512-DsOqeZEHkZnZrVOJG3mE/J9M6J8PulImiC6I1ZpoprVlfno8GvLOPDMkxiJihklLK7B9aVudG463L1+S/kzjiw==", + "license": "MIT", + "dependencies": { + "command-line-args": "^5.2.0", + "command-line-usage": "^6.1.1" + }, + "bin": { + "directory-tree": "bin/index.js" + }, + "engines": { + "node": ">=10.0" + } + }, "node_modules/dlv": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", @@ -3298,6 +3610,7 @@ "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" @@ -3344,6 +3657,15 @@ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, "node_modules/enhanced-resolve": { "version": "5.16.0", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.16.0.tgz", @@ -3938,6 +4260,15 @@ "node": ">=0.10.0" } }, + "node_modules/expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", + "license": "(MIT OR WTFPL)", + "engines": { + "node": ">=6" + } + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -4003,9 +4334,10 @@ } }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -4013,6 +4345,18 @@ "node": ">=8" } }, + "node_modules/find-replace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-replace/-/find-replace-3.0.0.tgz", + "integrity": "sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==", + "license": "MIT", + "dependencies": { + "array-back": "^3.0.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -4074,9 +4418,10 @@ } }, "node_modules/form-data": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", - "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.2.tgz", + "integrity": "sha512-sJe+TQb2vIaIyO783qN6BlMYWMw3WBOHA1Ay2qxsnjuafEOQFJ2JakedOQirT6D5XPRxDvS7AHYyem9fTpb4LQ==", + "license": "MIT", "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", @@ -4123,6 +4468,12 @@ } } }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "license": "MIT" + }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -4233,6 +4584,12 @@ "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" } }, + "node_modules/github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", + "license": "MIT" + }, "node_modules/glob": { "version": "10.3.10", "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", @@ -4268,7 +4625,8 @@ "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==" + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "license": "BSD-2-Clause" }, "node_modules/glob/node_modules/brace-expansion": { "version": "2.0.1", @@ -4445,6 +4803,26 @@ "node": ">= 0.4" } }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "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": "BSD-3-Clause" + }, "node_modules/ignore": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", @@ -4492,8 +4870,13 @@ "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 + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "license": "ISC" }, "node_modules/input-otp": { "version": "1.1.0", @@ -4716,6 +5099,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "license": "MIT", "engines": { "node": ">=0.12.0" } @@ -4925,6 +5309,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.1.tgz", "integrity": "sha512-+0rgsUXZu4ncpPxRL+lNEptWMOWl9etvPHc/koSRp6MPwpRYAhmk0dUG00J4bxVV3r9uUzfo24wW0knS07SKSw==", + "license": "MIT", "engines": { "node": ">=12" } @@ -5059,6 +5444,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", + "license": "MIT" + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -5080,6 +5471,7 @@ "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" } @@ -5104,6 +5496,7 @@ "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" }, @@ -5120,11 +5513,12 @@ } }, "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "license": "MIT", "dependencies": { - "braces": "^3.0.2", + "braces": "^3.0.3", "picomatch": "^2.3.1" }, "engines": { @@ -5135,6 +5529,7 @@ "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -5143,6 +5538,7 @@ "version": "2.1.35", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", "dependencies": { "mime-db": "1.52.0" }, @@ -5150,6 +5546,18 @@ "node": ">= 0.6" } }, + "node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -5166,7 +5574,6 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -5179,6 +5586,12 @@ "node": ">=16 || 14 >=14.17" } }, + "node_modules/mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", + "license": "MIT" + }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -5196,15 +5609,16 @@ } }, "node_modules/nanoid": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", - "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "version": "3.3.8", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz", + "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", "funding": [ { "type": "github", "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "bin": { "nanoid": "bin/nanoid.cjs" }, @@ -5212,6 +5626,12 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/napi-build-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-2.0.0.tgz", + "integrity": "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==", + "license": "MIT" + }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -5219,12 +5639,13 @@ "dev": true }, "node_modules/next": { - "version": "14.1.3", - "resolved": "https://registry.npmjs.org/next/-/next-14.1.3.tgz", - "integrity": "sha512-oexgMV2MapI0UIWiXKkixF8J8ORxpy64OuJ/J9oVUmIthXOUCcuVEZX+dtpgq7wIfIqtBwQsKEDXejcjTsan9g==", + "version": "14.2.23", + "resolved": "https://registry.npmjs.org/next/-/next-14.2.23.tgz", + "integrity": "sha512-mjN3fE6u/tynneLiEg56XnthzuYw+kD7mCujgVqioxyPqbmiotUCGJpIZGS/VaPg3ZDT1tvWxiVyRzeqJFm/kw==", + "license": "MIT", "dependencies": { - "@next/env": "14.1.3", - "@swc/helpers": "0.5.2", + "@next/env": "14.2.23", + "@swc/helpers": "0.5.5", "busboy": "1.6.0", "caniuse-lite": "^1.0.30001579", "graceful-fs": "^4.2.11", @@ -5238,18 +5659,19 @@ "node": ">=18.17.0" }, "optionalDependencies": { - "@next/swc-darwin-arm64": "14.1.3", - "@next/swc-darwin-x64": "14.1.3", - "@next/swc-linux-arm64-gnu": "14.1.3", - "@next/swc-linux-arm64-musl": "14.1.3", - "@next/swc-linux-x64-gnu": "14.1.3", - "@next/swc-linux-x64-musl": "14.1.3", - "@next/swc-win32-arm64-msvc": "14.1.3", - "@next/swc-win32-ia32-msvc": "14.1.3", - "@next/swc-win32-x64-msvc": "14.1.3" + "@next/swc-darwin-arm64": "14.2.23", + "@next/swc-darwin-x64": "14.2.23", + "@next/swc-linux-arm64-gnu": "14.2.23", + "@next/swc-linux-arm64-musl": "14.2.23", + "@next/swc-linux-x64-gnu": "14.2.23", + "@next/swc-linux-x64-musl": "14.2.23", + "@next/swc-win32-arm64-msvc": "14.2.23", + "@next/swc-win32-ia32-msvc": "14.2.23", + "@next/swc-win32-x64-msvc": "14.2.23" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", + "@playwright/test": "^1.41.2", "react": "^18.2.0", "react-dom": "^18.2.0", "sass": "^1.3.0" @@ -5258,19 +5680,22 @@ "@opentelemetry/api": { "optional": true }, + "@playwright/test": { + "optional": true + }, "sass": { "optional": true } } }, "node_modules/next-themes": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.2.1.tgz", - "integrity": "sha512-B+AKNfYNIzh0vqQQKqQItTS8evEouKD7H5Hj3kmuPERwddR2TxvDSFZuTj6T7Jfn1oyeUyJMydPl1Bkxkh0W7A==", + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.4.4.tgz", + "integrity": "sha512-LDQ2qIOJF0VnuVrrMSMLrWGjRMkq+0mpgl6e0juCLqdJ+oo8Q84JRWT6Wh11VDQKkMMe+dVzDKLWs5n87T+PkQ==", + "license": "MIT", "peerDependencies": { - "next": "*", - "react": "*", - "react-dom": "*" + "react": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc" } }, "node_modules/next/node_modules/postcss": { @@ -5301,14 +5726,17 @@ } }, "node_modules/nextjs-toploader": { - "version": "1.6.6", - "resolved": "https://registry.npmjs.org/nextjs-toploader/-/nextjs-toploader-1.6.6.tgz", - "integrity": "sha512-LKow/aV28/DLhj4yH1E8ydF/I5QDNsb5NqlbsXBaIVFrmZ9/OGHyxPLdumvPE2IOYoQdvJ4XWoaCA1v7aivYBg==", + "version": "3.7.15", + "resolved": "https://registry.npmjs.org/nextjs-toploader/-/nextjs-toploader-3.7.15.tgz", + "integrity": "sha512-DvvXEJVRPfE2j1HVXgFhmPl8pRcLb/4mvyVBDuYdMdkbEY7KJghp0fG5iOZ002cV6awbBw9j/Di7vQL8LRazxQ==", + "license": "MIT", "dependencies": { - "@types/nprogress": "^0.2.2", "nprogress": "^0.2.0", "prop-types": "^15.8.1" }, + "funding": { + "url": "https://buymeacoffee.com/thesgj" + }, "peerDependencies": { "next": ">= 6.0.0", "react": ">= 16.0.0", @@ -5319,15 +5747,35 @@ "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/node-abi": { + "version": "3.73.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.73.0.tgz", + "integrity": "sha512-z8iYzQGBu35ZkTQ9mtR8RqugJZ9RCLn8fv3d7LsgDBzOijGQP3RdKTX4LA7LXw03ZhU5z0l4xfhIMgSES31+cg==", + "license": "MIT", + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-addon-api": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", + "license": "MIT" + }, "node_modules/node-fetch-native": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.0.1.tgz", - "integrity": "sha512-VzW+TAk2wE4X9maiKMlT+GsPU4OMmR1U9CrHSmd3DFLn2IcZ9VJ6M6BBugGfYUnPCLSYxXdZy17M0BEJyhUTwg==" + "integrity": "sha512-VzW+TAk2wE4X9maiKMlT+GsPU4OMmR1U9CrHSmd3DFLn2IcZ9VJ6M6BBugGfYUnPCLSYxXdZy17M0BEJyhUTwg==", + "license": "MIT" }, "node_modules/node-releases": { "version": "2.0.14", @@ -5487,7 +5935,6 @@ "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, "dependencies": { "wrappy": "1" } @@ -5597,11 +6044,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/path-to-regexp": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.1.tgz", - "integrity": "sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==" - }, "node_modules/path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -5793,6 +6235,32 @@ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" }, + "node_modules/prebuild-install": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.3.tgz", + "integrity": "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==", + "license": "MIT", + "dependencies": { + "detect-libc": "^2.0.0", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^2.0.0", + "node-abi": "^3.3.0", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^4.0.0", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0" + }, + "bin": { + "prebuild-install": "bin.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -5803,20 +6271,31 @@ } }, "node_modules/prisma": { - "version": "5.10.2", - "resolved": "https://registry.npmjs.org/prisma/-/prisma-5.10.2.tgz", - "integrity": "sha512-hqb/JMz9/kymRE25pMWCxkdyhbnIWrq+h7S6WysJpdnCvhstbJSNP/S6mScEcqiB8Qv2F+0R3yG+osRaWqZacQ==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/prisma/-/prisma-6.3.0.tgz", + "integrity": "sha512-y+Zh3Qg+xGCWyyrNUUNaFW/OltaV/yXYuTa0WRgYkz5LGyifmAsgpv94I47+qGRocZrMGcbF2A/78/oO2zgifA==", + "devOptional": true, "hasInstallScript": true, - "optional": true, - "peer": true, + "license": "Apache-2.0", "dependencies": { - "@prisma/engines": "5.10.2" + "@prisma/engines": "6.3.0" }, "bin": { "prisma": "build/index.js" }, "engines": { - "node": ">=16.13" + "node": ">=18.18" + }, + "optionalDependencies": { + "fsevents": "2.3.3" + }, + "peerDependencies": { + "typescript": ">=5.1.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, "node_modules/prop-types": { @@ -5829,6 +6308,16 @@ "react-is": "^16.13.1" } }, + "node_modules/pump": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz", + "integrity": "sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==", + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -5839,17 +6328,19 @@ } }, "node_modules/pvtsutils": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/pvtsutils/-/pvtsutils-1.3.5.tgz", - "integrity": "sha512-ARvb14YB9Nm2Xi6nBq1ZX6dAM0FsJnuk+31aUp4TrcZEdKUlSqOqsxJHUPJDNE3qiIp+iUPEIeR6Je/tgV7zsA==", + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/pvtsutils/-/pvtsutils-1.3.6.tgz", + "integrity": "sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg==", + "license": "MIT", "dependencies": { - "tslib": "^2.6.1" + "tslib": "^2.8.1" } }, "node_modules/pvutils": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/pvutils/-/pvutils-1.1.3.tgz", "integrity": "sha512-pMpnA0qRdFp32b1sJl1wOJNxZLQ2cbQx+k6tjNtZ8CpvVhNqEPRgivZ2WOUev2YMajecdH7ctUPDvEe87nariQ==", + "license": "MIT", "engines": { "node": ">=6.0.0" } @@ -5877,10 +6368,35 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", + "license": "MIT", "engines": { "node": ">=8" } }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/rc/node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/react": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", @@ -6043,6 +6559,20 @@ "pify": "^2.3.0" } }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", @@ -6054,6 +6584,15 @@ "node": ">=8.10.0" } }, + "node_modules/reduce-flatten": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/reduce-flatten/-/reduce-flatten-2.0.0.tgz", + "integrity": "sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/reflect.getprototypeof": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.5.tgz", @@ -6216,6 +6755,26 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "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/safe-regex-test": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", @@ -6245,7 +6804,6 @@ "version": "7.6.0", "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", - "dev": true, "dependencies": { "lru-cache": "^6.0.0" }, @@ -6260,7 +6818,6 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, "dependencies": { "yallist": "^4.0.0" }, @@ -6348,6 +6905,51 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "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/simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "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": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, "node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -6361,6 +6963,7 @@ "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" @@ -6370,6 +6973,7 @@ "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", @@ -6383,6 +6987,7 @@ "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" }, @@ -6415,6 +7020,15 @@ "node": ">=10.0.0" } }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, "node_modules/string-width": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", @@ -6654,6 +7268,7 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/swr/-/swr-2.2.0.tgz", "integrity": "sha512-AjqHOv2lAhkuUdIiBu9xbuettzAzWXmCEcLONNKJRba87WAefz8Ca9d6ds/SzrPc235n1IxWYdhJ2zF3MNUaoQ==", + "license": "MIT", "dependencies": { "use-sync-external-store": "^1.2.0" }, @@ -6661,6 +7276,39 @@ "react": "^16.11.0 || ^17.0.0 || ^18.0.0" } }, + "node_modules/table-layout": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/table-layout/-/table-layout-1.0.2.tgz", + "integrity": "sha512-qd/R7n5rQTRFi+Zf2sk5XVVd9UQl6ZkduPFC3S7WEGJAmetDTjY3qPN50eSKzwuzEyQKy5TN2TiZdkIjos2L6A==", + "license": "MIT", + "dependencies": { + "array-back": "^4.0.1", + "deep-extend": "~0.6.0", + "typical": "^5.2.0", + "wordwrapjs": "^4.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/table-layout/node_modules/array-back": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.2.tgz", + "integrity": "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/table-layout/node_modules/typical": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", + "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/tailwind-merge": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.2.1.tgz", @@ -6726,6 +7374,34 @@ "node": ">=6" } }, + "node_modules/tar-fs": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.2.tgz", + "integrity": "sha512-EsaAXwxmx8UB7FRKqeozqEPop69DXcmYwTQwXvyAPF352HJsPdkVhvTaDPYqfNgruveJIJy3TA2l+2zj8LJIJA==", + "license": "MIT", + "dependencies": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "license": "MIT", + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -6754,12 +7430,14 @@ "node_modules/to-no-case": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/to-no-case/-/to-no-case-1.0.2.tgz", - "integrity": "sha512-Z3g735FxuZY8rodxV4gH7LxClE4H0hTIyHNIHdk+vpQxjLm0cwnKXq/OFVZ76SOQmto7txVcwSCwkU5kqp+FKg==" + "integrity": "sha512-Z3g735FxuZY8rodxV4gH7LxClE4H0hTIyHNIHdk+vpQxjLm0cwnKXq/OFVZ76SOQmto7txVcwSCwkU5kqp+FKg==", + "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==", + "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, @@ -6771,6 +7449,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/to-snake-case/-/to-snake-case-1.0.0.tgz", "integrity": "sha512-joRpzBAk1Bhi2eGEYBjukEWHOe/IvclOkiJl3DtA91jV6NwQ3MwXA4FHYeqk8BNp/D8bmi9tcNbRu/SozP0jbQ==", + "license": "MIT", "dependencies": { "to-space-case": "^1.0.0" } @@ -6779,6 +7458,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/to-space-case/-/to-space-case-1.0.0.tgz", "integrity": "sha512-rLdvwXZ39VOn1IxGL3V6ZstoTbwLRckQmn/U8ZDLuWwIXNpuZDhQ3AiRUlhTbOXFVE9C+dR51wM0CBDhk31VcA==", + "license": "MIT", "dependencies": { "to-no-case": "^1.0.0" } @@ -6813,9 +7493,22 @@ } }, "node_modules/tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + "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/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } }, "node_modules/tween-functions": { "version": "1.2.0", @@ -6923,7 +7616,7 @@ "version": "5.4.2", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.2.tgz", "integrity": "sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ==", - "dev": true, + "devOptional": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -6932,6 +7625,15 @@ "node": ">=14.17" } }, + "node_modules/typical": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-4.0.0.tgz", + "integrity": "sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/unbox-primitive": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", @@ -7033,11 +7735,12 @@ } }, "node_modules/use-sync-external-store": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", - "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.4.0.tgz", + "integrity": "sha512-9WXSPC5fMv61vaupRkCKCxsPxBocVnwakBEkMIHHpkTTg6icbJtg6jzgtLDm4bl3cSHAca52rYWih0k4K3PfHw==", + "license": "MIT", "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "node_modules/util-deprecate": { @@ -7058,15 +7761,16 @@ } }, "node_modules/webcrypto-core": { - "version": "1.7.8", - "resolved": "https://registry.npmjs.org/webcrypto-core/-/webcrypto-core-1.7.8.tgz", - "integrity": "sha512-eBR98r9nQXTqXt/yDRtInszPMjTaSAMJAFDg2AHsgrnczawT1asx9YNBX6k5p+MekbPF4+s/UJJrr88zsTqkSg==", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/webcrypto-core/-/webcrypto-core-1.8.1.tgz", + "integrity": "sha512-P+x1MvlNCXlKbLSOY4cYrdreqPG5hbzkmawbcXLKN/mf6DZW0SdNNkZ+sjwsqVkI4A4Ko2sPZmkZtCKY58w83A==", + "license": "MIT", "dependencies": { - "@peculiar/asn1-schema": "^2.3.8", + "@peculiar/asn1-schema": "^2.3.13", "@peculiar/json-schema": "^1.1.12", - "asn1js": "^3.0.1", + "asn1js": "^3.0.5", "pvtsutils": "^1.3.5", - "tslib": "^2.6.2" + "tslib": "^2.7.0" } }, "node_modules/which": { @@ -7162,6 +7866,28 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/wordwrapjs": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-4.0.1.tgz", + "integrity": "sha512-kKlNACbvHrkpIw6oPeYDSmdCTu2hdMHoyXLTcUKala++lx5Y+wjJ/e474Jqv5abnVmwxw08DiTuHmw69lJGksA==", + "license": "MIT", + "dependencies": { + "reduce-flatten": "^2.0.0", + "typical": "^5.2.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/wordwrapjs/node_modules/typical": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", + "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/wrap-ansi": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", @@ -7252,14 +7978,12 @@ "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 + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/yaml": { "version": "2.4.1", diff --git a/package.json b/package.json index 3a90e06..a52dd05 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "@clerk/nextjs": "^4.29.9", "@dnd-kit/core": "^6.1.0", "@hookform/resolvers": "^3.3.4", - "@prisma/client": "^5.10.2", + "@prisma/client": "^6.3.0", "@radix-ui/react-accordion": "^1.1.2", "@radix-ui/react-alert-dialog": "^1.0.5", "@radix-ui/react-aspect-ratio": "^1.0.3", @@ -41,17 +41,19 @@ "@radix-ui/react-toggle": "^1.0.3", "@radix-ui/react-toggle-group": "^1.0.4", "@radix-ui/react-tooltip": "^1.0.7", + "canvas": "^3.1.0", "class-variance-authority": "^0.7.0", "clsx": "^2.1.0", "cmdk": "^1.0.0", "date-fns": "^3.4.0", + "directory-tree": "^3.5.2", "embla-carousel-react": "^8.0.0", "framer-motion": "^11.0.12", "input-otp": "^1.1.0", "lucide-react": "^0.356.0", - "next": "14.1.3", - "next-themes": "^0.2.1", - "nextjs-toploader": "^1.6.6", + "next": "14.2.23", + "next-themes": "^0.4.4", + "nextjs-toploader": "^3.7.15", "react": "^18", "react-confetti": "^6.1.0", "react-day-picker": "^8.10.0", @@ -73,6 +75,7 @@ "eslint": "^8", "eslint-config-next": "14.1.3", "postcss": "^8", + "prisma": "^6.3.0", "tailwindcss": "^3.3.0", "typescript": "^5" } diff --git a/prisma/migrations/20250123154420_add_theme_field/migration.sql b/prisma/migrations/20250123154420_add_theme_field/migration.sql new file mode 100644 index 0000000..363df71 --- /dev/null +++ b/prisma/migrations/20250123154420_add_theme_field/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "Form" ADD COLUMN "theme" TEXT NOT NULL DEFAULT 'default'; diff --git a/prisma/migrations/20250127214005_upgrade_to_v6/migration.sql b/prisma/migrations/20250127214005_upgrade_to_v6/migration.sql new file mode 100644 index 0000000..9041f83 --- /dev/null +++ b/prisma/migrations/20250127214005_upgrade_to_v6/migration.sql @@ -0,0 +1,2 @@ +-- CreateIndex +CREATE INDEX "Form_userId_id_idx" ON "Form"("userId", "id"); diff --git a/prisma/migrations/20250131151448_add_multi_page_support/migration.sql b/prisma/migrations/20250131151448_add_multi_page_support/migration.sql new file mode 100644 index 0000000..93b60f5 --- /dev/null +++ b/prisma/migrations/20250131151448_add_multi_page_support/migration.sql @@ -0,0 +1,17 @@ +-- AlterTable +ALTER TABLE "Form" ADD COLUMN "isMultiPage" BOOLEAN NOT NULL DEFAULT false, +ALTER COLUMN "description" DROP NOT NULL; + +-- CreateTable +CREATE TABLE "Page" ( + "id" SERIAL NOT NULL, + "formId" INTEGER NOT NULL, + "order" INTEGER NOT NULL, + "elements" TEXT NOT NULL DEFAULT '[]', + "config" TEXT NOT NULL DEFAULT '{}', + + CONSTRAINT "Page_pkey" PRIMARY KEY ("id") +); + +-- AddForeignKey +ALTER TABLE "Page" ADD CONSTRAINT "Page_formId_fkey" FOREIGN KEY ("formId") REFERENCES "Form"("id") ON DELETE RESTRICT ON UPDATE CASCADE; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index c3d5aaa..6b69e63 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -1,9 +1,3 @@ -// This is your Prisma schema file, -// learn more about it in the docs: https://pris.ly/d/prisma-schema - -// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions? -// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init - generator client { provider = "prisma-client-js" } @@ -15,28 +9,37 @@ datasource db { } model Form { - id Int @id @default(autoincrement()) - userId String - createdAt DateTime @default(now()) - published Boolean @default(false) - name String - description String @default("") - content String @default("[]") - - visits Int @default(0) - submissions Int @default(0) - - shareURL String @unique @default(uuid()) + id Int @id @default(autoincrement()) + userId String + createdAt DateTime @default(now()) + published Boolean @default(false) + name String + description String? @default("") + content String @default("[]") + visits Int @default(0) + submissions Int @default(0) + shareURL String @unique @default(uuid()) + theme String @default("default") + isMultiPage Boolean @default(false) + pages Page[] @relation("FormToPages") FormSubmissions FormSubmissions[] - @@unique([name, userId]) + @@index([userId, id]) } model FormSubmissions { id Int @id @default(autoincrement()) createdAt DateTime @default(now()) formId Int + content String form Form @relation(fields: [formId], references: [id]) +} - content String +model Page { + id Int @id @default(autoincrement()) + form Form @relation("FormToPages", fields: [formId], references: [id]) + formId Int + order Int + elements String @default("[]") + config String @default("{}") } diff --git a/src/action/form-embed.ts b/src/action/form-embed.ts new file mode 100644 index 0000000..3ffc715 --- /dev/null +++ b/src/action/form-embed.ts @@ -0,0 +1,47 @@ +"use server"; + +import { currentUser } from "@clerk/nextjs"; +import prisma from "@/lib/prisma"; + +class UserNotFoundErr extends Error {} + +export type EmbedCodeResponse = { + scriptUrl: string; + embedCode: string; + formId: number; +}; + +export async function GenerateEmbedCode(formId: number): Promise { + const user = await currentUser(); + if (!user) { + throw new UserNotFoundErr(); + } + + // Verify the form exists and belongs to the user + const form = await prisma.form.findFirst({ + where: { + id: formId, + userId: user.id, + }, + }); + + if (!form) { + throw new Error("Form not found"); + } + + // Generate unique script URL for this form + const scriptUrl = `/api/embed/${formId}/js`; + + // Generate the embed code with a container div and the script + const embedCode = ` + +
+ + `.trim(); + + return { + scriptUrl, + embedCode, + formId, + }; +} diff --git a/src/action/form.ts b/src/action/form.ts index 6cdbe0a..9aa23cf 100644 --- a/src/action/form.ts +++ b/src/action/form.ts @@ -3,6 +3,46 @@ import prisma from "@/lib/prisma"; import { formSchema, formSchemaType } from "@/schemas/form"; import { currentUser } from "@clerk/nextjs"; +import { PageConfig } from "@/context/DesignerContext"; +import { z } from "zod"; +import { Form, Prisma } from "@prisma/client"; + +export type FullForm = { + id: number; + userId: string; + createdAt: Date; + published: boolean; + name: string; + description: string | null; + content: string; + visits: number; + submissions: number; + shareURL: string; + theme: string; + isMultiPage: boolean; + pages: Page[]; +}; + +export type Page = { + elements: string; + config: string; + order: number; +}; + +const pageSchema = z.object({ + elements: z.string(), + config: z.string(), + order: z.number(), +}); + +const updateFormSchema = z.object({ + id: z.number(), + content: z.string(), + isMultiPage: z.boolean(), + pages: z.array(pageSchema), +}); + +export type UpdateFormInput = z.infer; class UserNotFoundErr extends Error {} @@ -52,13 +92,38 @@ export async function CreateForm(data: formSchemaType) { throw new UserNotFoundErr(); } - const { name, description } = data; + const { name, description, theme } = data; + + // Check for existing forms with the same name + const existingForms = await prisma.form.findMany({ + where: { + userId: user.id, + name: { + startsWith: name, + }, + }, + select: { + name: true, + }, + }); + + // If there are existing forms with the same name, append a number + let newName = name; + if (existingForms.length > 0) { + const existingNames = new Set(existingForms.map(f => f.name)); + let counter = 1; + while (existingNames.has(newName)) { + newName = `${name} (${counter})`; + counter++; + } + } const form = await prisma.form.create({ data: { userId: user.id, - name, + name: newName, description, + theme: theme || "default", }, }); @@ -68,42 +133,33 @@ export async function CreateForm(data: formSchemaType) { return form.id; } + export async function DeleteForm(formId: number) { const user = await currentUser(); if (!user) { throw new UserNotFoundErr(); } - // Check if the form exists before attempting to delete it - const existingForm = await prisma.form.findUnique({ + // Check if the form exists and belongs to the user + const existingForm = await prisma.form.findFirst({ where: { id: formId, + userId: user.id, }, }); if (!existingForm) { - throw new Error("Form not found"); + throw new Error("Form not found or you don't have permission to delete it"); } - // Check if there are any related records (e.g., submissions) before deleting the form - const submissions = await prisma.formSubmissions.findMany({ + // Delete related submissions first + await prisma.formSubmissions.deleteMany({ where: { formId: formId, }, }); - // Delete related records first - await Promise.all( - submissions.map(async (submission) => { - await prisma.formSubmissions.delete({ - where: { - id: submission.id, - }, - }); - }) - ); - - // Now delete the form + // Delete the form await prisma.form.delete({ where: { id: formId, @@ -129,68 +185,141 @@ export async function GetForms() { }); } -export async function GetFormById(id: number) { +export async function GetFormById(id: number): Promise { + const form = await prisma.form.findUnique({ + where: { id }, + include: { + pages: { + orderBy: { + order: 'asc' + } + } + } + }); + + if (!form) return null; + + return form; +} + +export async function UpdateFormContent(input: UpdateFormInput) { + console.log('Received form data:', input); // Debug log + + const validation = updateFormSchema.safeParse(input); + if (!validation.success) { + console.error('Validation error:', validation.error); // Debug log + throw new Error('Invalid form data'); + } + const user = await currentUser(); if (!user) { throw new UserNotFoundErr(); } - return await prisma.form.findUnique({ - where: { - userId: user.id, - id, - }, - }); + const { id, content, isMultiPage, pages } = input; + + try { + const form = await prisma.form.update({ + where: { + id, + userId: user.id, + }, + data: { + content, + isMultiPage, + pages: { + deleteMany: {}, + create: pages, + }, + }, + include: { + pages: true + } + }); + + console.log('Updated form:', form); // Debug log + return form; + } catch (error) { + console.error('Database error:', error); // Debug log + throw error; + } } -export async function UpdateFormContent(id: number, jsonContent: string) { +export async function PublishForm(id: number) { const user = await currentUser(); if (!user) { throw new UserNotFoundErr(); } - return await prisma.form.update({ + // First check if the form exists and belongs to the user + const form = await prisma.form.findFirst({ where: { - userId: user.id, id, - }, - data: { - content: jsonContent, + userId: user.id, }, }); -} -export async function PublishForm(id: number) { - const user = await currentUser(); - if (!user) { - throw new UserNotFoundErr(); + if (!form) { + throw new Error("Form not found"); } return await prisma.form.update({ - data: { - published: true, - }, where: { - userId: user.id, id, }, + data: { + published: true, + }, }); } export async function GetFormContentByUrl(formUrl: string) { - return await prisma.form.update({ + const form = await prisma.form.findUnique({ select: { content: true, - }, - data: { - visits: { - increment: 1, + theme: true, + isMultiPage: true, + pages: { + select: { + elements: true, + config: true, + order: true, + }, + orderBy: { + order: 'asc', + }, }, }, where: { shareURL: formUrl, }, }); + + if (!form) return null; + + // For multi-page forms, combine all elements from pages + if (form.isMultiPage && form.pages) { + const allElements = form.pages.reduce((acc, page) => { + const pageElements = JSON.parse(page.elements); + return [...acc, ...pageElements]; + }, [] as any[]); + + return { + theme: form.theme, + content: JSON.stringify(allElements), + }; + } + + // Update visit count + await prisma.form.update({ + where: { shareURL: formUrl }, + data: { visits: { increment: 1 } }, + }); + + return { + theme: form.theme, + content: form.content, + }; } export async function SubmitForm(formUrl: string, content: string) { diff --git a/src/app/(routes)/dashboard/page.tsx b/src/app/(routes)/dashboard/page.tsx index 7f299cc..1982808 100644 --- a/src/app/(routes)/dashboard/page.tsx +++ b/src/app/(routes)/dashboard/page.tsx @@ -1,6 +1,7 @@ -import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +"use client"; +import { StatsCard } from "@/components/ui/stats-card"; import { Skeleton } from "@/components/ui/skeleton"; -import { ReactNode, Suspense } from "react"; +import { ReactNode, Suspense, useEffect, useState } from "react"; import { LuView } from "react-icons/lu"; import { FaWpforms } from "react-icons/fa"; import { HiCursorClick } from "react-icons/hi"; @@ -9,131 +10,139 @@ import { Separator } from "@/components/ui/separator"; import CreateFormBtn from "@/components/CreateFormBtn"; import { GetFormStats, GetForms } from "@/action/form"; import FormCard from "@/components/FormCard"; +import { Form } from "@prisma/client"; +import { toast } from "@/components/ui/use-toast"; export default function Home() { + const [stats, setStats] = useState> | null>(null); + const [forms, setForms] = useState(null); + const [loading, setLoading] = useState(true); + + useEffect(() => { + const loadData = async () => { + try { + setLoading(true); + const [statsData, formsData] = await Promise.all([ + GetFormStats(), + GetForms(), + ]); + setStats(statsData); + setForms(formsData); + } catch (error) { + console.error("Error loading dashboard data:", error); + toast({ + title: "Error", + description: "Failed to load dashboard data. Please try again.", + variant: "destructive", + }); + setForms([]); + } finally { + setLoading(false); + } + }; + + loadData(); + }, []); + + const handleFormDeleted = (formId: number) => { + if (!forms) return; + + setForms((prevForms) => { + if (!prevForms) return []; + return prevForms.filter((form) => form.id !== formId); + }); + + // Update stats + setStats((prevStats) => { + if (!prevStats || !forms) return null; + const deletedForm = forms.find(f => f.id === formId); + if (!deletedForm) return prevStats; + + return { + ...prevStats, + visits: prevStats.visits - (deletedForm.visits || 0), + submissions: prevStats.submissions - (deletedForm.submissions || 0), + }; + }); + }; + return (
- }> - - +
+ } + helperText="All time form visits" + value={stats?.visits.toLocaleString() || "0"} + loading={loading} + className="shadow-md shadow-blue-600" + /> + + } + helperText="All time form submissions" + value={stats?.submissions.toLocaleString() || "0"} + loading={loading} + className="shadow-md shadow-yellow-600" + /> + + } + helperText="Visits that result in form submission" + value={stats?.submissionRate.toLocaleString() + "%" || "0%"} + loading={loading} + className="shadow-md shadow-green-600" + /> + + } + helperText="Visits that leave without interacting" + value={stats?.bounceRate.toLocaleString() + "%" || "0%"} + loading={loading} + className="shadow-md shadow-red-600" + /> +
+

Your forms

+
- ( + {loading ? ( + [1, 2, 3, 4].map((el) => ( - ))} - > - - + )) + ) : forms === null ? ( +
+

Error loading forms. Please try refreshing the page.

+
+ ) : forms.length === 0 ? ( +
+

No forms created yet. Create your first form to get started!

+
+ ) : ( + forms.map((form) => ( + + )) + )}
); } -async function CardStatsWrapper() { - const stats = await GetFormStats(); - return ; -} - interface StatsCardProps { - data?: Awaited>; - loading: boolean; -} - -function StatsCards(props: StatsCardProps) { - const { data, loading } = props; - - return ( -
- } - helperText="All time form visits" - value={data?.visits.toLocaleString() || ""} - loading={loading} - className="shadow-md shadow-blue-600" - /> - - } - helperText="All time form submissions" - value={data?.submissions.toLocaleString() || ""} - loading={loading} - className="shadow-md shadow-yellow-600" - /> - - } - helperText="Visits that result in form submission" - value={data?.submissionRate.toLocaleString() + "%" || ""} - loading={loading} - className="shadow-md shadow-green-600" - /> - - } - helperText="Visits that leaves without interacting" - value={data?.submissionRate.toLocaleString() + "%" || ""} - loading={loading} - className="shadow-md shadow-red-600" - /> -
- ); -} - -export function StatsCard({ - title, - value, - icon, - helperText, - loading, - className, -}: { title: string; value: string; helperText: string; className: string; loading: boolean; icon: ReactNode; -}) { - return ( - - - {title} - {icon} - - -
- {loading && ( - - 0 - - )} - {!loading && value} -
-

{helperText}

-
-
- ); } function FormCardSkeleton() { - return ; -} - -async function FormCards() { - const forms = await GetForms(); - return ( - <> - {forms.map((form) => ( - - ))} - - ); + return ; } diff --git a/src/app/api/embed/[formId]/js/route.ts b/src/app/api/embed/[formId]/js/route.ts new file mode 100644 index 0000000..57dac2a --- /dev/null +++ b/src/app/api/embed/[formId]/js/route.ts @@ -0,0 +1,578 @@ +import prisma from "@/lib/prisma"; +import { NextResponse } from "next/server"; +import { getAllStyles } from '@/lib/styles/embed'; +import type { Form, Page } from '@prisma/client'; + +export const dynamic = 'force-dynamic'; + +export async function GET( + request: Request, + { params }: { params: { formId: string } } +) { + if (!params.formId) { + console.log("Missing formId"); + return new NextResponse("Missing formId", { status: 400 }); + } + + try { + const formId = parseInt(params.formId); + console.log("Looking for form:", formId); + + // First get the form + const form = await prisma.form.findFirst({ + where: { + id: formId, + published: true, + } + }) as Form | null; + + console.log("Form found:", form); + + if (!form) { + console.log("Form not found or not published"); + return new NextResponse("Form not found or not published", { status: 404 }); + } + + // Get pages if it's a multi-page form + let formContent; + try { + if (form.isMultiPage) { + const pages = await prisma.page.findMany({ + where: { formId: form.id }, + orderBy: { order: 'asc' } + }); + + formContent = pages.reduce((acc: any[], page) => { + const pageElements = JSON.parse(page.elements); + return [...acc, ...pageElements]; + }, []); + } else { + formContent = JSON.parse(form.content); + } + console.log("Form content parsed:", formContent); + } catch (error) { + console.error("Error parsing form content:", error); + return new NextResponse("Invalid form content", { status: 500 }); + } + + if (!Array.isArray(formContent)) { + console.error("Form content is not an array:", formContent); + return new NextResponse("Invalid form content", { status: 500 }); + } + + // Get all styles as a single string and escape it for JavaScript + const styles = ` + ${getAllStyles()} + + .quick-form-two-column { + width: 100%; + margin: 1rem 0; + display: grid; + grid-template-columns: repeat(2, 1fr); + } + + .quick-form-column { + width: 100%; + display: flex; + flex-direction: column; + gap: 1rem; + padding: 0 0.5rem; + } + + .quick-form-column > * { + width: 100%; + } + + @media (max-width: 640px) { + .quick-form-two-column { + grid-template-columns: 1fr; + } + + .quick-form-column { + padding: 0; + } + } + + /* Base styles */ + .quick-form-wrapper { + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; + max-width: 800px; + margin: 0 auto; + padding: 1rem; + } + + .quick-form-title { + font-size: 2em; + margin-bottom: 1rem; + font-weight: 600; + } + + .quick-form-subtitle { + font-size: 1.5em; + margin-bottom: 1rem; + font-weight: 500; + color: #666; + } + + .quick-form-label { + display: block; + margin-bottom: 0.5rem; + font-weight: 500; + } + + .quick-form-input { + width: 100%; + padding: 0.5rem; + border: 1px solid #ddd; + border-radius: 4px; + font-size: 1rem; + margin-bottom: 0.5rem; + } + + .quick-form-helper-text { + font-size: 0.875rem; + color: #666; + margin-top: 0.25rem; + } + + .quick-form-error { + color: #dc2626; + font-size: 0.875rem; + margin-top: 0.25rem; + } + + /* Rating scale styles */ + .quick-form-rating-wrapper { + margin: 1rem 0; + } + + .quick-form-rating-question { + font-weight: 500; + margin-bottom: 0.5rem; + } + + .quick-form-rating-scale { + display: flex; + justify-content: space-between; + align-items: center; + gap: 0.5rem; + } + + .quick-form-rating-label { + font-size: 0.875rem; + color: #666; + text-align: center; + } + + .quick-form-rating-radio { + margin: 0 0.25rem; + } + + /* Image styles */ + .quick-form-image { + max-width: 100%; + height: auto; + margin: 1rem auto; + display: block; + } + `.replace(/\\/g, '\\\\') + .replace(/'/g, "\\'") + .replace(/\n/g, ' ') + .trim(); + + // Create utility functions for the bundle + const utilityFunctions = ` + function createElement(tag, className, textContent) { + const element = document.createElement(tag); + if (className) element.className = className; + if (textContent) element.textContent = textContent; + return element; + } + + function createLabel(text) { + return createElement('label', 'quick-form-label', text); + } + + function createHelperText(text) { + return createElement('div', 'quick-form-helper-text', text); + } + + function createInput(type, name, required, placeholder) { + const input = createElement('input', 'quick-form-input'); + input.type = type; + input.name = name; + input.required = required; + if (placeholder) input.placeholder = placeholder; + return input; + } + + function createWrapper() { + return createElement('div', 'quick-form-field'); + } + + function createFormElement(element) { + const wrapper = createWrapper(); + + switch (element.type) { + case 'TextField': { + const { label, helperText, required, placeHolder } = element.extraAttributes; + if (label) wrapper.appendChild(createLabel(label)); + wrapper.appendChild(createInput('text', element.id, required, placeHolder)); + if (helperText) wrapper.appendChild(createHelperText(helperText)); + return wrapper; + } + + case 'NumberField': { + const { label, helperText, required, placeHolder } = element.extraAttributes; + if (label) wrapper.appendChild(createLabel(label)); + wrapper.appendChild(createInput('number', element.id, required, placeHolder)); + if (helperText) wrapper.appendChild(createHelperText(helperText)); + return wrapper; + } + + case 'TitleField': { + const { title, fontSize, alignment } = element.extraAttributes; + const titleEl = createElement('h1', 'quick-form-title', title); + titleEl.style.textAlign = alignment; + if (fontSize === 'h2') titleEl.style.fontSize = '1.5em'; + else if (fontSize === 'h3') titleEl.style.fontSize = '1.17em'; + return titleEl; + } + + case 'SubTitleField': { + const { subTitle, fontSize, alignment } = element.extraAttributes; + const subtitleEl = createElement('h2', 'quick-form-subtitle', subTitle); + subtitleEl.style.textAlign = alignment; + if (fontSize === 'h3') subtitleEl.style.fontSize = '1.17em'; + else if (fontSize === 'h4') subtitleEl.style.fontSize = '1em'; + return subtitleEl; + } + + case 'TwoColumnLayoutField': { + const { gap, columns } = element.extraAttributes; + const layoutWrapper = createElement('div', 'quick-form-two-column'); + layoutWrapper.style.display = 'grid'; + layoutWrapper.style.gridTemplateColumns = 'repeat(2, 1fr)'; + layoutWrapper.style.gap = (parseFloat(gap) * 0.25) + 'rem'; + + // Create left column + const leftColumn = createElement('div', 'quick-form-column'); + if (columns.left && Array.isArray(columns.left)) { + columns.left.forEach(childElement => { + const childNode = createFormElement(childElement); + if (childNode) leftColumn.appendChild(childNode); + }); + } + layoutWrapper.appendChild(leftColumn); + + // Create right column + const rightColumn = createElement('div', 'quick-form-column'); + if (columns.right && Array.isArray(columns.right)) { + columns.right.forEach(childElement => { + const childNode = createFormElement(childElement); + if (childNode) rightColumn.appendChild(childNode); + }); + } + layoutWrapper.appendChild(rightColumn); + + return layoutWrapper; + } + + case 'RatingScaleField': { + const { + label, helperText, required, question, + minLabel, midLabel, maxLabel, + minValue, maxValue + } = element.extraAttributes; + + const fieldWrapper = createWrapper(); + if (label) fieldWrapper.appendChild(createLabel(label)); + if (question) { + const questionEl = createElement('div', 'quick-form-rating-question', question); + fieldWrapper.appendChild(questionEl); + } + + const scale = createElement('div', 'quick-form-rating-scale'); + + // Create buttons + const buttons = createElement('div', 'quick-form-rating-buttons'); + for (let i = minValue; i <= maxValue; i++) { + const button = createElement('button', 'quick-form-rating-button', i.toString()); + button.type = 'button'; + button.onclick = function() { + // Remove selected class from all buttons + const allButtons = buttons.getElementsByClassName('quick-form-rating-button'); + Array.from(allButtons).forEach(btn => btn.classList.remove('selected')); + // Add selected class to clicked button + button.classList.add('selected'); + // Update hidden input + hiddenInput.value = i.toString(); + }; + buttons.appendChild(button); + } + scale.appendChild(buttons); + + // Create labels + const labels = createElement('div', 'quick-form-rating-labels'); + labels.appendChild(createElement('span', '', minLabel)); + if (midLabel) labels.appendChild(createElement('span', '', midLabel)); + labels.appendChild(createElement('span', '', maxLabel)); + scale.appendChild(labels); + + // Hidden input for form submission + const hiddenInput = createInput('hidden', element.id, required); + scale.appendChild(hiddenInput); + + fieldWrapper.appendChild(scale); + if (helperText) fieldWrapper.appendChild(createHelperText(helperText)); + + return fieldWrapper; + } + + case 'ImageElement': { + const { + base64Image, height, width, maintainAspectRatio, + alignment, marginTop, marginBottom, marginLeft, marginRight + } = element.extraAttributes; + + const imageWrapper = createElement('div'); + imageWrapper.style.textAlign = alignment; + imageWrapper.style.marginTop = marginTop + 'px'; + imageWrapper.style.marginBottom = marginBottom + 'px'; + imageWrapper.style.marginLeft = marginLeft + 'px'; + imageWrapper.style.marginRight = marginRight + 'px'; + + if (base64Image) { + const img = createElement('img'); + img.src = base64Image; + img.style.width = width + 'px'; + if (maintainAspectRatio) { + img.style.height = 'auto'; + } else { + img.style.height = height + 'px'; + } + imageWrapper.appendChild(img); + } + + return imageWrapper; + } + + case 'ImageUploadField': { + const { label, helperText, required } = element.extraAttributes; + const wrapper = createWrapper(); + if (label) wrapper.appendChild(createLabel(label)); + + const uploadWrapper = createElement('div', 'quick-form-upload'); + const input = createInput('file', element.id, required); + input.accept = 'image/*'; + + const preview = createElement('div', 'quick-form-image-preview'); + input.onchange = function(e) { + const target = e.target; + const file = target && target.files ? target.files[0] : null; + if (file) { + const reader = new FileReader(); + reader.onload = function(e) { + const target = e.target; + preview.innerHTML = ''; + const img = createElement('img'); + img.src = target ? target.result : ''; + preview.appendChild(img); + }; + reader.readAsDataURL(file); + } + }; + + uploadWrapper.appendChild(input); + uploadWrapper.appendChild(preview); + wrapper.appendChild(uploadWrapper); + if (helperText) wrapper.appendChild(createHelperText(helperText)); + return wrapper; + } + + case 'DualImageUpload': { + const { label, helperText, required } = element.extraAttributes; + const wrapper = createWrapper(); + if (label) wrapper.appendChild(createLabel(label)); + + const uploadsWrapper = createElement('div', 'quick-form-dual-upload'); + + // First upload + const upload1 = createElement('div', 'quick-form-upload'); + const input1 = createInput('file', element.id + '_1', required); + input1.accept = 'image/*'; + const preview1 = createElement('div', 'quick-form-image-preview'); + input1.onchange = function(e) { + const target = e.target; + const file = target && target.files ? target.files[0] : null; + if (file) { + const reader = new FileReader(); + reader.onload = function(e) { + const target = e.target; + preview1.innerHTML = ''; + const img = createElement('img'); + img.src = target ? target.result : ''; + preview1.appendChild(img); + }; + reader.readAsDataURL(file); + } + }; + upload1.appendChild(input1); + upload1.appendChild(preview1); + + // Second upload + const upload2 = createElement('div', 'quick-form-upload'); + const input2 = createInput('file', element.id + '_2', required); + input2.accept = 'image/*'; + const preview2 = createElement('div', 'quick-form-image-preview'); + input2.onchange = function(e) { + const target = e.target; + const file = target && target.files ? target.files[0] : null; + if (file) { + const reader = new FileReader(); + reader.onload = function(e) { + const target = e.target; + preview2.innerHTML = ''; + const img = createElement('img'); + img.src = target ? target.result : ''; + preview2.appendChild(img); + }; + reader.readAsDataURL(file); + } + }; + upload2.appendChild(input2); + upload2.appendChild(preview2); + + uploadsWrapper.appendChild(upload1); + uploadsWrapper.appendChild(upload2); + wrapper.appendChild(uploadsWrapper); + if (helperText) wrapper.appendChild(createHelperText(helperText)); + return wrapper; + } + + case 'PictureSelect': { + const { label, helperText, required, options } = element.extraAttributes; + const wrapper = createWrapper(); + if (label) wrapper.appendChild(createLabel(label)); + + const optionsWrapper = createElement('div', 'quick-form-picture-select'); + const hiddenInput = createInput('hidden', element.id, required); + + options.forEach((option, index) => { + const optionWrapper = createElement('div', 'quick-form-picture-option'); + const img = createElement('img'); + img.src = option.base64Image; + img.alt = option.label || 'Option ' + (index + 1); + + optionWrapper.onclick = function() { + // Remove selected class from all options + const allOptions = optionsWrapper.getElementsByClassName('quick-form-picture-option'); + Array.from(allOptions).forEach(opt => opt.classList.remove('selected')); + // Add selected class to clicked option + optionWrapper.classList.add('selected'); + // Update hidden input + hiddenInput.value = option.value || index.toString(); + }; + + if (option.label) { + const label = createElement('div', 'quick-form-picture-label', option.label); + optionWrapper.appendChild(label); + } + + optionWrapper.appendChild(img); + optionsWrapper.appendChild(optionWrapper); + }); + + optionsWrapper.appendChild(hiddenInput); + wrapper.appendChild(optionsWrapper); + if (helperText) wrapper.appendChild(createHelperText(helperText)); + return wrapper; + } + + case 'CheckboxField': { + const { label, helperText, required } = element.extraAttributes; + const wrapper = createWrapper(); + + const checkboxWrapper = createElement('div', 'quick-form-checkbox'); + const input = createInput('checkbox', element.id, required); + const labelEl = createLabel(label); + + checkboxWrapper.appendChild(input); + checkboxWrapper.appendChild(labelEl); + wrapper.appendChild(checkboxWrapper); + + if (helperText) wrapper.appendChild(createHelperText(helperText)); + return wrapper; + } + + default: + console.warn('Unknown element type:', element.type); + return null; + } + } + `; + + // Generate the form bundle - using an array of strings to avoid template literal formatting issues + const bundleScript = [ + '(() => {', + utilityFunctions, + `const containerId = 'quick-form-${formId}';`, + `const formId = ${formId};`, + 'let container = document.getElementById(containerId);', + 'if (!container) {', + ' console.error("Quick Form container not found:", containerId);', + ' return;', + '}', + 'container.innerHTML = "";', + 'const style = document.createElement("style");', + `style.textContent = '${styles}';`, + 'document.head.appendChild(style);', + 'const form = document.createElement("form");', + 'form.className = "quick-form";', + `const formContent = ${JSON.stringify(formContent)};`, + 'formContent.forEach(element => {', + ' const node = createFormElement(element);', + ' if (node) form.appendChild(node);', + '});', + 'form.onsubmit = async (e) => {', + ' e.preventDefault();', + ' const formData = new FormData(form);', + ' const data = Object.fromEntries(formData.entries());', + ' try {', + ' const response = await fetch("/api/submit/" + formId, {', + ' method: "POST",', + ' headers: {', + ' "Content-Type": "application/json",', + ' },', + ' body: JSON.stringify(data),', + ' });', + ' if (response.ok) {', + ' alert("Form submitted successfully!");', + ' form.reset();', + ' } else {', + ' alert("Error submitting form. Please try again.");', + ' }', + ' } catch (error) {', + ' console.error("Error submitting form:", error);', + ' alert("Error submitting form. Please try again.");', + ' }', + '};', + 'const submitBtn = document.createElement("button");', + 'submitBtn.type = "submit";', + 'submitBtn.className = "quick-form-submit";', + 'submitBtn.textContent = "Submit";', + 'form.appendChild(submitBtn);', + 'container.appendChild(form);', + '})();' + ].join('\n'); + + return new NextResponse(bundleScript, { + headers: { + 'Content-Type': 'application/javascript' + } + }); + } catch (error) { + console.error('Error generating form bundle:', error); + return new NextResponse('Error generating form bundle', { status: 500 }); + } +} \ No newline at end of file diff --git a/src/app/api/placeholder/[width]/[height]/route.tsx b/src/app/api/placeholder/[width]/[height]/route.tsx new file mode 100644 index 0000000..0d6197f --- /dev/null +++ b/src/app/api/placeholder/[width]/[height]/route.tsx @@ -0,0 +1,36 @@ +import { NextResponse } from 'next/server'; +import { createCanvas } from 'canvas'; + +export async function GET(request: Request, { params }: { params: { width: string, height: string } }) { + try { + const width = Number(params.width); + const height = Number(params.height); + + const canvas = createCanvas(width, height); + const ctx = canvas.getContext('2d'); + + // Fill background + ctx.fillStyle = '#e2e8f0'; + ctx.fillRect(0, 0, width, height); + + // Add text + ctx.fillStyle = '#1e293b'; + ctx.font = `${Math.min(width, height) * 0.1}px Arial`; + ctx.textAlign = 'center'; + ctx.textBaseline = 'middle'; + ctx.fillText('Add Image', width / 2, height / 2); + + // Convert to buffer + const buffer = canvas.toBuffer('image/png'); + + return new NextResponse(buffer, { + headers: { + 'Content-Type': 'image/png', + 'Cache-Control': 'public, max-age=31536000, immutable', + }, + }); + } catch (e) { + console.error('Failed to generate image:', e); + return new NextResponse('Failed to generate image', { status: 500 }); + } +} diff --git a/src/app/api/submit-form/[formId]/route.ts b/src/app/api/submit-form/[formId]/route.ts new file mode 100644 index 0000000..0db4199 --- /dev/null +++ b/src/app/api/submit-form/[formId]/route.ts @@ -0,0 +1,65 @@ +import prisma from "@/lib/prisma"; +import { NextResponse } from "next/server"; + +export const dynamic = 'force-dynamic'; + +export async function POST( + request: Request, + { params }: { params: { formId: string } } +) { + try { + const formId = parseInt(params.formId); + const data = await request.json(); + + // Get the form to verify it exists and is published + const form = await prisma.form.findFirst({ + where: { + id: formId, + published: true, + }, + }); + + if (!form) { + return new NextResponse("Form not found", { status: 404 }); + } + + // Save the submission + const submission = await prisma.formSubmissions.create({ + data: { + formId, + content: JSON.stringify(data), + }, + }); + + // Update form submission count + await prisma.form.update({ + where: { id: formId }, + data: { submissions: { increment: 1 } }, + }); + + return new NextResponse(JSON.stringify({ + data: submission, + message: "Form submitted successfully", + }), { + headers: { + 'Content-Type': 'application/json', + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Methods': 'POST', + }, + }); + } catch (error) { + console.error('Error processing form submission:', error); + return new NextResponse("Error processing submission", { status: 500 }); + } +} + +// Handle CORS preflight requests +export async function OPTIONS() { + return new NextResponse(null, { + headers: { + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Methods': 'POST', + 'Access-Control-Allow-Headers': 'Content-Type', + }, + }); +} diff --git a/src/app/builder/[id]/page.tsx b/src/app/builder/[id]/page.tsx index 940c655..4e4c564 100644 --- a/src/app/builder/[id]/page.tsx +++ b/src/app/builder/[id]/page.tsx @@ -10,13 +10,14 @@ async function BuilderPage({ }; }) { const { id } = params; - const form = await GetFormById(Number(id)); + const formId = Number(id); + const form = await GetFormById(formId); if (!form) { throw new Error("form not found"); } return ( <> - + ); } diff --git a/src/app/forms/[id]/page.tsx b/src/app/forms/[id]/page.tsx index 4e8a6d0..70a8087 100644 --- a/src/app/forms/[id]/page.tsx +++ b/src/app/forms/[id]/page.tsx @@ -10,7 +10,7 @@ import { format, formatDistance } from "date-fns"; import { Badge } from "@/components/ui/badge"; import { Checkbox } from "@/components/ui/checkbox"; import { GetFormById, GetFormWithSubmissions } from "@/action/form"; -import { StatsCard } from "@/app/(routes)/dashboard/page"; +import { StatsCard } from "@/components/ui/stats-card"; import ShareForm from "@/components/ShareForm"; async function FormDetailPage({ @@ -115,25 +115,42 @@ async function SubmissionsTable({ id }: { id: number }) { type: ElementsType; }[] = []; - formElements.forEach((element) => { - switch (element.type) { - case "TextField": - case "NumberField": - case "TextAreaField": - case "DateField": - case "SelectField": - case "CheckboxField": - columns.push({ - id: element.id, - label: element.extraAttributes?.label, - required: element.extraAttributes?.required, - type: element.type, - }); - break; - default: - break; - } - }); + function parseFormElements(elements: FormElementInstance[]) { + elements.forEach((element) => { + switch (element.type) { + case "TextField": + case "NumberField": + case "TextAreaField": + case "DateField": + case "SelectField": + case "CheckboxField": + case "ImageUploadField": + case "DualImageUpload": + case "PictureSelectField": + case "RatingScaleField": + columns.push({ + id: element.id, + label: element.extraAttributes?.label, + required: element.extraAttributes?.required, + type: element.type, + }); + break; + case "TwoColumnLayoutField": + // Parse elements in both columns + const { leftColumn, rightColumn } = element.extraAttributes as { + leftColumn: FormElementInstance[]; + rightColumn: FormElementInstance[]; + }; + parseFormElements(leftColumn); + parseFormElements(rightColumn); + break; + default: + break; + } + }); + } + + parseFormElements(formElements); const rows: Row[] = []; form.FormSubmissions.forEach((submission) => { diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 7da9e29..0ad68ce 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -5,36 +5,37 @@ import { ThemeProvider } from "@/providers/ThemeProvider"; const poppins = Poppins({ subsets: ["latin"], weight: ["300", "400", "500", "600", "700", "800",] }); import NextTopLoader from 'nextjs-toploader' import { ClerkProvider } from "@clerk/nextjs"; -import DesignerContextProvider from "@/context/DesignerContext"; +import { DesignerContextProvider } from "@/context/DesignerContext"; import { Toaster } from "@/components/ui/toaster"; export const metadata: Metadata = { - title: "QuickForm - Build Custom Forms with Drag and Drop", - description: "Create your custom forms effortlessly with QuickForm. Simply drag and drop elements to generate tailored forms for your needs.", + title: "Quick Form Builder", + description: "Create forms quickly and easily", }; export default function RootLayout({ children, -}: Readonly<{ +}: { children: React.ReactNode; -}>) { +}) { return ( - - - - - - + + - - + + {children} - - + + diff --git a/src/app/not-found.tsx b/src/app/not-found.tsx index c92d738..e2004e5 100644 --- a/src/app/not-found.tsx +++ b/src/app/not-found.tsx @@ -1,12 +1,25 @@ import Link from 'next/link'; import React from 'react'; +import Image from 'next/image'; const NotFoundPage = () => { return (
- - + 404 Error + Meteor

Oh no!!

You're either misspelling the URL
or requesting a page that's no longer here. @@ -14,8 +27,20 @@ const NotFoundPage = () => {

Back to Home
- - + Astronaut + Spaceship
); }; diff --git a/src/app/sign-in/[[...sign-in]]/page.tsx b/src/app/sign-in/[[...sign-in]]/page.tsx index 89bcdcb..bb3e381 100644 --- a/src/app/sign-in/[[...sign-in]]/page.tsx +++ b/src/app/sign-in/[[...sign-in]]/page.tsx @@ -1,5 +1,6 @@ import { SignIn } from '@clerk/nextjs' import React from 'react' +import Image from 'next/image' const SignInPage = () => { return ( @@ -7,10 +8,12 @@ const SignInPage = () => {
diff --git a/src/app/sign-up/[[...sign-up]]/page.tsx b/src/app/sign-up/[[...sign-up]]/page.tsx index 31ea7a9..81de753 100644 --- a/src/app/sign-up/[[...sign-up]]/page.tsx +++ b/src/app/sign-up/[[...sign-up]]/page.tsx @@ -1,5 +1,6 @@ import { SignUp } from '@clerk/nextjs' import React from 'react' +import Image from 'next/image' const SignUpPage = () => { return ( @@ -7,10 +8,12 @@ const SignUpPage = () => {
diff --git a/src/app/submit/[formUrl]/page.tsx b/src/app/submit/[formUrl]/page.tsx index 1ff3ba0..f45c7cc 100644 --- a/src/app/submit/[formUrl]/page.tsx +++ b/src/app/submit/[formUrl]/page.tsx @@ -1,6 +1,7 @@ import { GetFormContentByUrl } from "@/action/form"; import { FormElementInstance } from "@/components/FormElements"; import FormSubmitComponent from "@/components/FormSubmitComponent"; +import { FormTheme } from "@/schemas/form"; import React from "react"; async function SubmitPage({ @@ -17,8 +18,9 @@ async function SubmitPage({ } const formContent = JSON.parse(form.content) as FormElementInstance[]; + const theme = (form.theme || "default") as FormTheme; - return ; + return ; } -export default SubmitPage; \ No newline at end of file +export default SubmitPage; diff --git a/src/components/Designer.tsx b/src/components/Designer.tsx index 71f30a3..5946914 100644 --- a/src/components/Designer.tsx +++ b/src/components/Designer.tsx @@ -9,9 +9,43 @@ import { idGenerator } from "@/lib/idGenerator"; import { Button } from "./ui/button"; import { BiSolidTrash } from "react-icons/bi"; import useDesigner from "@/hooks/useDesigner"; +import { formThemes } from "@/schemas/form"; +import PageNavigation from "./PageNavigation"; -function Designer() { - const { elements, addElement, selectedElement, setSelectedElement, removeElement } = useDesigner(); +type ColumnType = 'left' | 'right'; + +interface TwoColumnLayoutAttributes { + columns: { + [key in ColumnType]: FormElementInstance[]; + }; +} + +interface TwoColumnLayoutInstance extends FormElementInstance { + type: 'TwoColumnLayoutField'; + extraAttributes: TwoColumnLayoutAttributes; +} + +interface DesignerProps { + elements?: FormElementInstance[]; +} + +function Designer({ elements: propElements }: DesignerProps) { + const { + elements: contextElements, + addElement, + selectedElement, + setSelectedElement, + removeElement, + theme, + updateElement, + isMultiPage, + pages, + currentPage, + setPages, + setElements + } = useDesigner(); + + const elements = propElements || contextElements; const droppable = useDroppable({ id: "designer-drop-area", @@ -27,16 +61,77 @@ function Designer() { const isDesignerBtnElement = active.data?.current?.isDesignerBtnElement; const isDroppingOverDesignerDropArea = over.data?.current?.isDesignerDropArea; + const isDroppingOverColumn = over.data?.current?.isColumnDropArea; const droppingSidebarBtnOverDesignerDropArea = isDesignerBtnElement && isDroppingOverDesignerDropArea; // First - if (droppingSidebarBtnOverDesignerDropArea) { const type = active.data?.current?.type; const newElement = FormElements[type as ElementsType].construct(idGenerator()); - addElement(elements.length, newElement); + if (isMultiPage) { + const updatedPages = [...pages]; + if (!updatedPages[currentPage]) { + updatedPages[currentPage] = { + elements: [], + config: { + navigationType: 'tabs', + showPageNumbers: true + } + }; + } + updatedPages[currentPage].elements.push(newElement); + setPages(updatedPages); + } else { + addElement(elements.length, newElement); + } + return; + } + + // Handle dropping into columns + if (isDroppingOverColumn) { + const type = active.data?.current?.type; + const columnId = over.data?.current?.columnId as ColumnType; + const parentId = over.data?.current?.elementId; + + // Find the parent TwoColumnLayout element + const parentIndex = elements.findIndex((el) => el.id === parentId); + if (parentIndex === -1) return; + + const parent = elements[parentIndex]; + const isTwoColumnLayout = (el: FormElementInstance): el is TwoColumnLayoutInstance => + el.type === 'TwoColumnLayoutField'; + + if (!isTwoColumnLayout(parent)) return; + + // Create new element + const newElement = FormElements[type as ElementsType].construct(idGenerator()); + + // Update the appropriate column + const updatedColumns = { ...parent.extraAttributes.columns }; + updatedColumns[columnId] = [...(updatedColumns[columnId] || []), newElement]; + + // Update the parent element + const updatedParent: TwoColumnLayoutInstance = { + ...parent, + type: 'TwoColumnLayoutField', + extraAttributes: { + columns: updatedColumns + } + }; + + // Update elements list + const updatedElements = [...elements]; + updatedElements[parentIndex] = updatedParent; + + if (isMultiPage) { + const updatedPages = [...pages]; + updatedPages[currentPage].elements = updatedElements; + setPages(updatedPages); + } else { + setElements(updatedElements); + } return; } @@ -66,7 +161,22 @@ function Designer() { indexForNewElement = overElementIndex + 1; } - addElement(indexForNewElement, newElement); + if (isMultiPage) { + const updatedPages = [...pages]; + if (!updatedPages[currentPage]) { + updatedPages[currentPage] = { + elements: [], + config: { + navigationType: 'tabs', + showPageNumbers: true + } + }; + } + updatedPages[currentPage].elements.splice(indexForNewElement, 0, newElement); + setPages(updatedPages); + } else { + addElement(indexForNewElement, newElement); + } return; } @@ -96,39 +206,80 @@ function Designer() { indexForNewElement = overElementIndex + 1; } - addElement(indexForNewElement, activeElement); + if (isMultiPage) { + const updatedPages = [...pages]; + if (!updatedPages[currentPage]) { + updatedPages[currentPage] = { + elements: [], + config: { + navigationType: 'tabs', + showPageNumbers: true + } + }; + } + updatedPages[currentPage].elements.splice(indexForNewElement, 0, activeElement); + setPages(updatedPages); + } else { + addElement(indexForNewElement, activeElement); + } } }, }); + const handleRemoveElement = (id: string) => { + if (isMultiPage) { + const updatedPages = [...pages]; + updatedPages[currentPage].elements = updatedPages[currentPage].elements.filter( + element => element.id !== id + ); + setPages(updatedPages); + } else { + removeElement(id); + } + }; + return (
-
{ - if (selectedElement) setSelectedElement(null); - }} - > +
+
- {!droppable.isOver && elements.length === 0 && ( -

Drop here

+ {!droppable.isOver && (isMultiPage ? pages[currentPage]?.elements.length === 0 : elements.length === 0) && ( +

+ Drop elements here +

)} - {droppable.isOver && elements.length === 0 && ( + {droppable.isOver && (
)} - {elements.length > 0 && ( -
+ + {isMultiPage ? ( +
+ {pages[currentPage]?.elements.map((element) => ( + handleRemoveElement(element.id)} + /> + ))} +
+ ) : ( +
{elements.map((element) => ( - + handleRemoveElement(element.id)} + /> ))}
)} @@ -139,16 +290,22 @@ function Designer() { ); } -function DesignerElementWrapper({ element }: { element: FormElementInstance }) { - const { removeElement, selectedElement, setSelectedElement } = useDesigner(); +export interface DesignerElementWrapperProps { + element: FormElementInstance; + onRemove: () => void; +} + +export function DesignerElementWrapper({ element, onRemove }: DesignerElementWrapperProps) { + const { setSelectedElement, selectedElement } = useDesigner(); const [mouseIsOver, setMouseIsOver] = useState(false); + const topHalf = useDroppable({ id: element.id + "-top", data: { type: element.type, elementId: element.id, - isTopHalfDesignerElement: true, + isTopHalfDroppable: true, }, }); @@ -157,7 +314,7 @@ function DesignerElementWrapper({ element }: { element: FormElementInstance }) { data: { type: element.type, elementId: element.id, - isBottomHalfDesignerElement: true, + isBottomHalfDroppable: true, }, }); @@ -170,28 +327,25 @@ function DesignerElementWrapper({ element }: { element: FormElementInstance }) { }, }); - if (draggable.isDragging) return null; // temporary remove the element from designer + if (draggable.isDragging) return null; const DesignerElement = FormElements[element.type].designerComponent; + return (
{ - setMouseIsOver(true); - }} - onMouseLeave={() => { - setMouseIsOver(false); - }} + className="relative h-[120px] w-full hover:cursor-pointer rounded-md ring-1 ring-accent ring-inset mb-4" + onMouseEnter={() => setMouseIsOver(true)} + onMouseLeave={() => setMouseIsOver(false)} onClick={(e) => { e.stopPropagation(); setSelectedElement(element); }} >
-
+
{mouseIsOver && ( <>
@@ -199,28 +353,30 @@ function DesignerElementWrapper({ element }: { element: FormElementInstance }) { className="flex justify-center h-full border rounded-md rounded-l-none bg-red-500" variant={"outline"} onClick={(e) => { - e.stopPropagation(); // avoid selection of element while deleting - removeElement(element.id); + e.stopPropagation(); + onRemove(); }} >
-

Click for properties or drag to move

+

Click to edit properties or drag to move

)} - {topHalf.isOver &&
} + {topHalf.isOver &&
}
- +
+ +
- {bottomHalf.isOver &&
} + {bottomHalf.isOver &&
}
); } diff --git a/src/components/DesignerElementWrapper.tsx b/src/components/DesignerElementWrapper.tsx new file mode 100644 index 0000000..a39cbe6 --- /dev/null +++ b/src/components/DesignerElementWrapper.tsx @@ -0,0 +1,109 @@ +"use client"; + +import React, { useState } from "react"; +import { FormElementInstance } from "./FormElements"; +import { useDesigner } from "@/context/DesignerContext"; +import { useDraggable } from "@dnd-kit/core"; +import { Button } from "./ui/button"; +import { BiSolidTrash } from "react-icons/bi"; +import { cn } from "@/lib/utils"; + +export interface DesignerElementWrapperProps { + element: FormElementInstance; + onRemove: () => void; +} + +export function DesignerElementWrapper({ element, onRemove }: DesignerElementWrapperProps) { + const { setSelectedElement, selectedElement } = useDesigner(); + + const [mouseIsOver, setMouseIsOver] = useState(false); + + const topHalf = useDraggable({ + id: element.id + "-top", + data: { + type: element.type, + elementId: element.id, + isTopHalfDesignerElement: true, + isDesignerElement: true, + }, + }); + + const bottomHalf = useDraggable({ + id: element.id + "-bottom", + data: { + type: element.type, + elementId: element.id, + isBottomHalfDesignerElement: true, + isDesignerElement: true, + }, + }); + + const handleMouseEnter = () => { + setMouseIsOver(true); + }; + + const handleMouseLeave = () => { + setMouseIsOver(false); + }; + + const handleClick = (e: React.MouseEvent) => { + e.stopPropagation(); + setSelectedElement(element); + }; + + return ( +
+
+
+ {mouseIsOver && ( + <> +
+ +
+
+

Click for properties or drag to move

+
+ + )} +
+
+ {mouseIsOver ? ( +

Click for properties or drag to move

+ ) : ( +
{element.type}
+ )} +
+
+
+ ); +} diff --git a/src/components/DesignerSidebar.tsx b/src/components/DesignerSidebar.tsx index cc2e483..cc0f9fb 100644 --- a/src/components/DesignerSidebar.tsx +++ b/src/components/DesignerSidebar.tsx @@ -7,10 +7,12 @@ function DesignerSidebar() { const { selectedElement } = useDesigner(); return ( ); } -export default DesignerSidebar; \ No newline at end of file +export default DesignerSidebar; diff --git a/src/components/EmbedFormPreview.tsx b/src/components/EmbedFormPreview.tsx new file mode 100644 index 0000000..7c677ca --- /dev/null +++ b/src/components/EmbedFormPreview.tsx @@ -0,0 +1,68 @@ +import { useEffect, useRef, useState } from "react"; + +interface EmbedFormPreviewProps { + formId: number; + previewMode?: boolean; +} + +export default function EmbedFormPreview({ formId, previewMode = false }: EmbedFormPreviewProps) { + const [isLoading, setIsLoading] = useState(true); + const iframeRef = useRef(null); + const messageHandlerRef = useRef<((event: MessageEvent) => void) | null>(null); + + useEffect(() => { + const iframe = iframeRef.current; + if (!iframe) return; + + // Reset iframe content + iframe.srcdoc = ` + + +
+ + + + + `; + + // Create and store message handler + messageHandlerRef.current = (event: MessageEvent) => { + if (event.data === 'loaded') { + setIsLoading(false); + } + }; + + // Add message listener + window.addEventListener('message', messageHandlerRef.current); + + // Cleanup function + return () => { + if (messageHandlerRef.current) { + window.removeEventListener('message', messageHandlerRef.current); + messageHandlerRef.current = null; + } + }; + }, [formId]); + + return ( +
+ {isLoading && ( +
+
+
+
+
+
+ )} +