From bc6439822cf096aaea8cf4886cf3f055e733ace1 Mon Sep 17 00:00:00 2001 From: THIS ONE IS A LITTLE BIT TRICKY KRUB Date: Sat, 19 Oct 2024 17:48:10 +0700 Subject: [PATCH] Refactor BusinessForm component to fetch industry data from Supabase and countries data from a REST API --- src/app/business/apply/page.tsx | 624 +------------------------------- src/components/BusinessForm.tsx | 68 ++-- 2 files changed, 56 insertions(+), 636 deletions(-) diff --git a/src/app/business/apply/page.tsx b/src/app/business/apply/page.tsx index fe94bda..bfdbd60 100644 --- a/src/app/business/apply/page.tsx +++ b/src/app/business/apply/page.tsx @@ -1,27 +1,15 @@ "use client"; import { createSupabaseClient } from "@/lib/supabase/clientComponentClient"; -import { useEffect, useState } from "react"; -import { useForm, SubmitHandler } from "react-hook-form"; +import { useState } from "react"; +import { SubmitHandler } from "react-hook-form"; import { z } from "zod"; -import { zodResolver } from "@hookform/resolvers/zod"; import BusinessForm from "@/components/BusinessForm"; import { businessFormSchema } from "@/types/schemas/application.schema"; import Swal from "sweetalert2"; -import { Button } from "@/components/ui/button"; -import { Input } from "@/components/ui/input"; -import { Label } from "@/components/ui/label"; -import { Textarea } from "@/components/ui/textarea"; type businessSchema = z.infer; export default function ApplyBusiness() { - const [industry, setIndustry] = useState<{ id: number; name: string }[]>([]); - const [projectType, setProjectType] = useState([]); - const [projectPitch, setProjectPitch] = useState("text"); const [applyProject, setApplyProject] = useState(false); - const [selectedImages, setSelectedImages] = useState([]); - const [projectPitchFile, setProjectPitchFile] = useState(""); - const MAX_FILE_SIZE = 5000000; - const ACCEPTED_IMAGE_TYPES = ["image/jpeg", "image/jpg", "image/png"]; const onSubmit: SubmitHandler = async (data) => { const transformedData = await transformChoice(data); @@ -56,220 +44,18 @@ export default function ApplyBusiness() { icon: error == null ? "success" : "error", title: error == null ? "success" : "Error: " + error.code, text: - error == null ? "your application has been submitted" : error.message, + error == null ? "Your application has been submitted" : error.message, confirmButtonColor: error == null ? "green" : "red", + }).then((result) => { + if (result.isConfirmed && applyProject) { + window.location.href = "/project/apply"; + } else { + window.location.href = "/"; + } }); }; - const createPitchDeckSchema = (inputType: string) => { - if (inputType === "text") { - return z - .string() - .url("Pitch deck must be a valid URL.") - .refine((url: string) => url.endsWith(".md"), { - message: "Pitch deck URL must link to a markdown file (.md).", - }); - } else if (inputType === "file") { - return z - .custom( - (val: any) => { - return val instanceof File; - }, - { - message: "Input must be a file.", - } - ) - .refine((file: File) => file.size < MAX_FILE_SIZE, { - message: "File can't be bigger than 5MB.", - }) - .refine((file: File) => file.name.endsWith(".md"), { - message: "File must be a markdown file (.md).", - }); - } else { - return z.any(); // avoid undefined - } - }; - const imageSchema = z - .custom( - (val: any) => - val && typeof val === "object" && "size" in val && "type" in val, - { - message: "Input must be a file.", - } - ) - .refine((file: File) => file.size < MAX_FILE_SIZE, { - message: "File can't be bigger than 5MB.", - }) - .refine((file: File) => ACCEPTED_IMAGE_TYPES.includes(file.type), { - message: "File format must be either jpg, jpeg, or png.", - }); - - const projectFormSchema = z.object({ - projectName: z.string().min(5, { - message: "Project name must be at least 5 characters.", - }), - projectType: z.string({ - required_error: "Please select one of the option", - }), - shortDescription: z - .string({ - required_error: "Please provide a brief description for your project", - }) - .min(10, { - message: "Short description must be at least 10 characters.", - }), - projectPitchDeck: createPitchDeckSchema(projectPitch), - projectLogo: imageSchema, - - projectPhotos: z.custom( - (value: string | Iterable | ArrayLike) => { - console.log("Tozod", value); - if (value instanceof FileList || Array.isArray(value)) { - if (value.length === 1) { - return false; - } - return Array.from(value).every((item) => item instanceof File); - } - return false; - }, - { - message: - "Must be a FileList or an array of File objects with at least one file.", - } - ), - minInvest: z - .number({ - required_error: "Minimum invesment must be a number.", - invalid_type_error: "Minimum invesment must be a valid number.", - }) - .positive() - .max(9999999999, "Minimum invesment must be a realistic amount."), - targetInvest: z - .number({ - required_error: "Target invesment must be a number.", - invalid_type_error: "Target invesment must be a valid number.", - }) - .positive() - .max(9999999999, "Target invesment must be a realistic amount."), - deadline: z - .string() - .min(1, "Deadline is required.") - .refine((value: string) => !isNaN(Date.parse(value)), { - message: "Invalid date-time format.", - }) - .transform((value: string | number | Date) => new Date(value)) - .refine((date: Date) => date > new Date(), { - message: "Deadline must be in the future.", - }), - }); - // const businessFormSchema = z.object({ - // companyName: z.string().min(5, { - // message: "Company name must be at least 5 characters.", - // }), - // industry: z.string({ - // required_error: "Please select one of the option", - // }), - // isInUS: z - // .string({ - // required_error: "Please select either 'Yes' or 'No'.", - // }) - // .transform((val: string) => val.toLowerCase()) - // .refine((val: string) => val === "yes" || val === "no", { - // message: "Please select either 'Yes' or 'No'.", - // }), - // isForSale: z - // .string({ - // required_error: "Please select either 'Yes' or 'No'.", - // }) - // .transform((val: string) => val.toLowerCase()) - // .refine((val: string) => val === "yes" || val === "no", { - // message: "Please select either 'Yes' or 'No'.", - // }), - // isGenerating: z - // .string({ - // required_error: "Please select either 'Yes' or 'No'.", - // }) - // .transform((val: string) => val.toLowerCase()) - // .refine((val: string) => val === "yes" || val === "no", { - // message: "Please select either 'Yes' or 'No'.", - // }), - // totalRaised: z - // .number({ - // required_error: "Total raised must be a number.", - // invalid_type_error: "Total raised must be a valid number.", - // }) - // .positive() - // .max(9999999999, "Total raised must be a realistic amount."), - // communitySize: z.string({ - // required_error: "Please select one of the option", - // }), - // businessPitchDeck: createPitchDeckSchema(businessPitch), - // }); let supabase = createSupabaseClient(); - // const { - // register, - // handleSubmit, - // setValue: setValueBusiness, - // formState: { errors: errorsBusiness }, - // } = useForm({ - // resolver: zodResolver(businessFormSchema), - // }); - const { - register: registerSecondForm, - handleSubmit: handleSecondSubmit, - formState: { errors: errorsProject }, - setValue: setValueProject, - } = useForm({ - resolver: zodResolver(projectFormSchema), - }); - - const communitySize = [ - "N/A", - "0-5K", - "5-10K", - "10-20K", - "20-50K", - "50-100K", - "100K+", - ]; - - // useEffect(() => { - // register("industry"); - // register("isInUS"); - // register("isForSale"); - // register("isGenerating"); - // }, [register]); - - const handleFileChange = (event: React.ChangeEvent) => { - if (event.target.files) { - const filesArray = Array.from(event.target.files); - console.log("first file", filesArray); - setSelectedImages((prevImages) => { - const updatedImages = [...prevImages, ...filesArray]; - console.log("Updated Images Array:", updatedImages); - // ensure we're setting an array of File objects - setValueProject("projectPhotos", updatedImages); - return updatedImages; - }); - } - }; - - const handleRemoveImage = (index: number) => { - setSelectedImages((prevImages) => { - const updatedImages = prevImages.filter((_, i) => i !== index); - console.log("After removal - Updated Images:", updatedImages); - // ensure we're setting an array of File objects - setValueProject("projectPhotos", updatedImages); - return updatedImages; - }); - }; - - const ensureArrayValue = (value: any): File[] => { - if (Array.isArray(value)) return value; - if (value instanceof File) return [value]; - return []; - }; - const transformChoice = (data: any) => { // convert any yes and no to true or false const transformedData = Object.entries(data).reduce( @@ -292,100 +78,7 @@ export default function ApplyBusiness() { ); return transformedData; }; - // const handleBusinessPitchChange = (type: string) => { - // setBusinessPitch(type); - // // clear out old data - // setValueBusiness("pitchDeck", ""); - // }; - // const handleBusinessFieldChange = (fieldName: string, value: any) => { - // switch (fieldName) { - // case "isInUS": - // setIsInUS(value); - // break; - // case "isForSale": - // setIsForSale(value); - // break; - // case "isGenerating": - // setIsGenerating(value); - // break; - // } - // setValueBusiness(fieldName, value); - // }; - const handleProjectFieldChange = (fieldName: string, value: any) => { - switch (fieldName) { - } - setValueProject(fieldName, value); - }; - - const fetchIndustry = async () => { - let { data: BusinessType, error } = await supabase - .from("business_type") - .select("id, value"); - - if (error) { - console.error(error); - } else { - if (BusinessType) { - // console.table(); - setIndustry( - BusinessType.map((item) => ({ - id: item.id, - name: item.value, - })) - ); - } - } - }; - - const onSubmitSingleForm = (data: any) => { - // const pitchDeckSchema = createPitchDeckSchema(businessPitch); - // pitchDeckSchema.parse(data.businessPitchDeck); - console.log("Valid form input:", data); - alert(JSON.stringify(data)); - }; - - const onSubmitBothForms = (firstFormData: any, secondFormData: any) => { - const formattedSecondFormData = { - ...secondFormData, - projectPhotos: ensureArrayValue(secondFormData.projectPhotos), - }; - alert(JSON.stringify(firstFormData)); - alert(JSON.stringify(formattedSecondFormData)); - console.log("Both forms submitted:", { - firstFormData, - formattedSecondFormData, - }); - }; - - const handleSubmitForms = (firstFormData: any) => { - const transformedData = transformChoice(firstFormData); - if (applyProject) { - handleSecondSubmit((secondFormData: any) => { - onSubmitBothForms(transformedData, secondFormData); - })(); - } else { - onSubmitSingleForm(transformedData); - } - }; - const fetchProjectType = async () => { - let { data: ProjectType, error } = await supabase - .from("project_type") - .select("value"); - - if (error) { - console.error(error); - } else { - if (ProjectType) { - console.table(ProjectType); - setProjectType(ProjectType.map((item) => item.value)); - } - } - }; - useEffect(() => { - fetchIndustry(); - fetchProjectType(); - }, []); return (
@@ -406,309 +99,10 @@ export default function ApplyBusiness() { {/* form */} {/*
*/} -
- {" "} -
- {/* header */} -
-

- Begin Your First Fundraising Project -

-

- Starting a fundraising project is mandatory for all businesses. - This step is crucial
- to begin your journey and unlock the necessary tools for raising - funds. -

- {/* project's name */} -
- -
- -
-
- {errorsProject.projectName && ( -

- {errorsProject.projectName.message as string} -

- )} - {/* project type */} - {/* Project type} - fieldName="projectType" - choices={projectType} - // handleFunction={handleProjectFieldChange} - description={<>Please specify the primary purpose of the funds} - placeholder="Select a Project type" - selectLabel="Project type" - /> */} - {errorsProject.projectType && ( -

- {errorsProject.projectType.message as string} -

- )} - {/* short description */} -
- -
-