diff --git a/package-lock.json b/package-lock.json index 589a4fa..e8785db 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,15 +8,19 @@ "name": "cohortgate", "version": "0.0.0", "dependencies": { + "@hookform/resolvers": "^5.0.1", "@tailwindcss/vite": "^4.0.12", "bootstrap": "^5.3.3", "firebase": "^11.4.0", "react": "^19.0.0", "react-bootstrap": "^2.10.9", "react-dom": "^19.0.0", + "react-hook-form": "^7.55.0", + "react-icons": "^5.5.0", "react-router": "^7.3.0", "react-router-dom": "^7.3.0", - "tailwindcss": "^4.0.12" + "tailwindcss": "^4.0.12", + "zod": "^3.24.2" }, "devDependencies": { "@eslint/js": "^9.21.0", @@ -1425,6 +1429,18 @@ "node": ">=6" } }, + "node_modules/@hookform/resolvers": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@hookform/resolvers/-/resolvers-5.0.1.tgz", + "integrity": "sha512-u/+Jp83luQNx9AdyW2fIPGY6Y7NG68eN2ZW8FOJYL+M0i4s49+refdJdOp/A9n9HFQtQs3HIDHQvX3ZET2o7YA==", + "license": "MIT", + "dependencies": { + "@standard-schema/utils": "^0.3.0" + }, + "peerDependencies": { + "react-hook-form": "^7.55.0" + } + }, "node_modules/@humanfs/core": { "version": "0.19.1", "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", @@ -1889,6 +1905,12 @@ "win32" ] }, + "node_modules/@standard-schema/utils": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@standard-schema/utils/-/utils-0.3.0.tgz", + "integrity": "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==", + "license": "MIT" + }, "node_modules/@swc/helpers": { "version": "0.5.15", "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", @@ -3672,6 +3694,31 @@ "react": "^19.0.0" } }, + "node_modules/react-hook-form": { + "version": "7.55.0", + "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.55.0.tgz", + "integrity": "sha512-XRnjsH3GVMQz1moZTW53MxfoWN7aDpUg/GpVNc4A3eXRVNdGXfbzJ4vM4aLQ8g6XCUh1nIbx70aaNCl7kxnjog==", + "license": "MIT", + "engines": { + "node": ">=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/react-hook-form" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17 || ^18 || ^19" + } + }, + "node_modules/react-icons": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.5.0.tgz", + "integrity": "sha512-MEFcXdkP3dLo8uumGI5xN3lDFNsRtrjbOEKDLD7yv76v4wpnEq2Lt2qeHaQOr34I/wPN3s3+N08WkQ+CW37Xiw==", + "license": "MIT", + "peerDependencies": { + "react": "*" + } + }, "node_modules/react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", @@ -4206,6 +4253,15 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/zod": { + "version": "3.24.2", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.2.tgz", + "integrity": "sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } } } } diff --git a/package.json b/package.json index f6c203a..619bcc0 100644 --- a/package.json +++ b/package.json @@ -10,15 +10,19 @@ "preview": "vite preview" }, "dependencies": { + "@hookform/resolvers": "^5.0.1", "@tailwindcss/vite": "^4.0.12", "bootstrap": "^5.3.3", "firebase": "^11.4.0", "react": "^19.0.0", "react-bootstrap": "^2.10.9", "react-dom": "^19.0.0", + "react-hook-form": "^7.55.0", + "react-icons": "^5.5.0", "react-router": "^7.3.0", "react-router-dom": "^7.3.0", - "tailwindcss": "^4.0.12" + "tailwindcss": "^4.0.12", + "zod": "^3.24.2" }, "devDependencies": { "@eslint/js": "^9.21.0", diff --git a/src/components/Form/Form.jsx b/src/components/Form/Form.jsx index 5fbd65a..df916b7 100644 --- a/src/components/Form/Form.jsx +++ b/src/components/Form/Form.jsx @@ -1,7 +1,215 @@ -import React from "react"; +import React, { useState,useRef,useEffect } from "react"; +import { useForm } from "react-hook-form"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { z } from "zod"; +import { FaSpinner } from "react-icons/fa"; -function Form() { - return
Form
; -} +const TECHNOLOGIES = [ + "AI/ML", "Blockchain", "IoT", "Cybersecurity", "Cloud Computing","Data Science", "Big Data", "DevOps", "Mobile Development", "Web Development" +]; -export default Form; +const SECTORS = [ + "Healthcare", "Finance", "Education", "Retail", "Manufacturing", "Technology", "Energy", "Transportation", "Government", "E-commerce", "Telecommunications", "Media & Entertainment", "Hospitality & Tourism", "Aerospace & Defense", "Supply Chain & Logistics", "Real Estate & Construction", "Environmental & Sustainability", "Food & Beverage", "Other" +]; + +const schema = z.object({ + companyName: z.string().min(1, "Company Name is required"), + website: z.string().url("Invalid URL"), + email: z.string().email("Invalid Email"), + repName: z.string().min(1, "Representative Name is required"), + contact: z.string().min(10, "Contact Number is required"), + sector: z.string().min(1, "Please select a sector"), + otherSector: z.string().optional(), + problemStatement: z.string().min(1, "Please describe your problem statement"), + brochure: z.any() + .refine((file) => file?.length > 0, "Please upload a PDF file") + .refine((file) => file?.[0]?.type === "application/pdf", "Only PDF files are allowed"), + technologies: z.array(z.string()).optional() +}); + +const Form = () => { + const [uploadProgress, setUploadProgress] = useState(0); + const [isSubmitting, setIsSubmitting] = useState(false); + const [selectedSector, setSelectedSector] = useState(""); + const [successMessage, setSuccessMessage] = useState(""); + const [fileName, setFileName] = useState(""); + const successRef = useRef(null); + + const { + register, + handleSubmit, + reset, + formState: { errors }, + setValue, + watch + } = useForm({ resolver: zodResolver(schema) }); + + useEffect(() => { + if (successMessage && successRef.current) { + successRef.current.scrollIntoView({ behavior: "smooth", block: "center" }); + } + }, [successMessage]); + + const handleFileChange = (e) => { + const file = e.target.files[0]; + setFileName(file?.name || ""); + setUploadProgress(0); + setValue("brochure", e.target.files); + }; + + const onSubmit = async (data) => { + setIsSubmitting(true); + setSuccessMessage(""); + setUploadProgress(0); + + const interval = setInterval(() => { + setUploadProgress((prev) => { + const newProgress = prev + 10; + if (newProgress >= 100) { + clearInterval(interval); + return 100; + } + return newProgress; + }); + }, 200); + + await new Promise(resolve => setTimeout(resolve, 2000)); + + console.log("Form Submitted:", data); + setIsSubmitting(false); + setSuccessMessage("Form submitted successfully!"); + reset(); + setFileName(""); + }; + + const inputClass = "w-full p-2 border rounded-lg shadow-md shadow-gray-300 dark:shadow-gray-700 dark:bg-gray-800 dark:text-white focus:ring-2 focus:ring-blue-500 focus:outline-none"; + const labelClass = "block text-gray-700 dark:text-gray-300 mb-1"; + const errorClass = "text-red-500 text-sm"; + + return ( +
+ +

Company Onboarding Form

+ + {successMessage && ( +

{successMessage}

+ )} + +
+ {/* Company Details */} +
+ + + {errors.companyName &&

{errors.companyName.message}

} +
+ +
+ + + {errors.website &&

{errors.website.message}

} +
+ +
+ + + {errors.email &&

{errors.email.message}

} +
+ + {/* Representative Details */} +
+ + + {errors.repName &&

{errors.repName.message}

} +
+ +
+ + + {errors.contact &&

{errors.contact.message}

} +
+ +
+ + + {errors.sector &&

{errors.sector.message}

} +
+ + {selectedSector === "Other" && ( +
+ + +
+ )} + + {/* Technological Preference */} +
+ +
+ {TECHNOLOGIES.map((tech) => ( + + ))} +
+
+ + {/* Problem Statement */} +
+ +