diff --git a/src/components/ProjectForm.tsx b/src/app/project/apply/ProjectForm.tsx similarity index 99% rename from src/components/ProjectForm.tsx rename to src/app/project/apply/ProjectForm.tsx index 427aa40..a81622e 100644 --- a/src/components/ProjectForm.tsx +++ b/src/app/project/apply/ProjectForm.tsx @@ -1,4 +1,6 @@ -import { useEffect, useState } from "react"; +"use client"; + +import React, { useEffect, useState } from "react"; import { SubmitHandler, useForm, ControllerRenderProps } from "react-hook-form"; import { Button } from "@/components/ui/button"; import { MultipleOptionSelector } from "@/components/multipleSelector"; @@ -9,7 +11,7 @@ import { z } from "zod"; import { zodResolver } from "@hookform/resolvers/zod"; import { Label } from "@/components/ui/label"; import { createSupabaseClient } from "@/lib/supabase/clientComponentClient"; -import { Textarea } from "./ui/textarea"; +import { Textarea } from "@/components/ui/textarea"; import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from "@/components/ui/command"; import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"; import { cn } from "@/lib/utils"; @@ -93,7 +95,9 @@ const ProjectForm = ({ onSubmit }: ProjectFormProps & { onSubmit: SubmitHandler< useEffect(() => { fetchProjectType(); fetchTag(); + // eslint-disable-next-line react-hooks/exhaustive-deps }, []); + return (
)} className="space-y-8"> diff --git a/src/app/project/apply/page.tsx b/src/app/project/apply/page.tsx index 0509058..6d84278 100644 --- a/src/app/project/apply/page.tsx +++ b/src/app/project/apply/page.tsx @@ -1,29 +1,57 @@ "use client"; import { createSupabaseClient } from "@/lib/supabase/clientComponentClient"; -import ProjectForm from "@/components/ProjectForm"; +import ProjectForm from "./ProjectForm"; import { projectFormSchema } from "@/types/schemas/application.schema"; import { z } from "zod"; import { SubmitHandler } from "react-hook-form"; import Swal from "sweetalert2"; import { uploadFile } from "@/app/api/generalApi"; -import { Loader } from "@/components/loading/loader"; -import { useState } from "react"; -import { errors } from "@playwright/test"; +import { useRouter } from "next/navigation"; +import toast from "react-hot-toast"; +import { useUserRole } from "@/hooks/useUserRole"; +import { LegacyLoader } from "@/components/loading/LegacyLoader"; type projectSchema = z.infer; -let supabase = createSupabaseClient(); +const supabase = createSupabaseClient(); const BUCKET_PITCH_APPLICATION_NAME = "project-application"; export default function ApplyProject() { - const [isSuccess, setIsSuccess] = useState(true); - const onSubmit: SubmitHandler = async (data) => { - // alert("มาแน้ววว"); - await sendApplication(data); - // console.table(data); - // console.log(typeof data["projectPhotos"], data["projectPhotos"]); + const router = useRouter(); + const { data, session, isLoading, error } = useUserRole(); + const userId = session?.user.id; + const role: string = data?.role; + + if (isLoading || !session) { + return ; + } + + if (error) { + throw error; + } + + if (role != "business") { + router.push("/business/apply"); + toast.error("Please apply to raise on B2DVentures first!"); + return; + } + + const displayAlert = (error: any) => { + Swal.fire({ + icon: error == null ? "success" : "error", + title: error == null ? "Success" : `Error: ${error.code}`, + text: error == null ? "Your application has been submitted" : error.message, + confirmButtonColor: error == null ? "green" : "red", + allowOutsideClick: false, + }).then((result) => { + if (result.isConfirmed) { + toast.error("Error sending Project Application"); + router.push("/"); + } + }); }; - const saveApplicationData = async (recvData: any, userId: string) => { + + const saveApplicationData = async (recvData: any) => { const pitchType = typeof recvData["projectPitchDeck"]; const { data: projectData, error: projectError } = await supabase .from("project_application") @@ -43,183 +71,109 @@ export default function ApplyProject() { return { projectId: projectData?.[0]?.id, error: projectError }; }; + const saveTags = async (tags: string[], projectId: string) => { const tagPromises = tags.map(async (tag) => { const response = await supabase .from("project_application_tag") .insert([{ tag_id: tag, item_id: projectId }]) .select(); - - // console.log("Insert response for tag:", tag, response); - return response; }); const results = await Promise.all(tagPromises); - - // Collect errors const errors = results.filter((result) => result.error).map((result) => result.error); return { errors }; }; - const uploadPitchFile = async (file: File, userId: string, projectId: string) => { - if (!file || !userId) { - console.error("Pitch file or user ID is undefined."); - return false; - } + const uploadPitchFile = async (file: File, projectId: string) => { + if (!file || !userId) return false; return await uploadFile(file, BUCKET_PITCH_APPLICATION_NAME, `${userId}/${projectId}/pitches/${file.name}`); }; - const uploadLogoAndPhotos = async (logoFile: File, photos: File[], userId: string, projectId: string) => { + const uploadLogoAndPhotos = async (logoFile: File, photos: File[], projectId: string) => { const uploadResults: { logo?: any; photos: any[] } = { photos: [] }; - // upload logo if (logoFile) { const logoResult = await uploadFile( logoFile, BUCKET_PITCH_APPLICATION_NAME, `${userId}/${projectId}/logo/${logoFile.name}` ); - - if (!logoResult.success) { - console.error("Error uploading logo:", logoResult.errors); - return { success: false, logo: logoResult, photos: [] }; - } - + if (!logoResult.success) return { success: false, logo: logoResult, photos: [] }; uploadResults.logo = logoResult; } - // upload each photo const uploadPhotoPromises = photos.map((image) => uploadFile(image, BUCKET_PITCH_APPLICATION_NAME, `${userId}/${projectId}/photos/${image.name}`) ); const photoResults = await Promise.all(uploadPhotoPromises); uploadResults.photos = photoResults; - - // check if all uploads were successful const allUploadsSuccessful = photoResults.every((result) => result.success); - return { - success: allUploadsSuccessful, - logo: uploadResults.logo, - photos: uploadResults.photos, - }; + return { success: allUploadsSuccessful, logo: uploadResults.logo, photos: uploadResults.photos }; }; - const displayAlert = (error: any) => { - Swal.fire({ - icon: error == null ? "success" : "error", - title: error == null ? "Success" : `Error: ${error.code}`, - text: error == null ? "Your application has been submitted" : error.message, - confirmButtonColor: error == null ? "green" : "red", - }).then((result) => { - if (result.isConfirmed) { - // window.location.href = "/"; - } - }); - }; - - const sendApplication = async (recvData: any) => { - setIsSuccess(false); - const { - data: { user }, - } = await supabase.auth.getUser(); - - if (!user?.id) { - console.error("User ID is undefined."); - return; - } - - // save application data - const { projectId, error } = await saveApplicationData(recvData, user.id); - - if (error) { - displayAlert(error); - return; - } - const tagError = await saveTags(recvData["tag"], projectId); - // if (tagError) { - // displayAlert(tagError); - // return; - // } - - // upload pitch file if it’s a file - if (typeof recvData["projectPitchDeck"] === "object") { - const uploadPitchSuccess = await uploadPitchFile(recvData["projectPitchDeck"], user.id, projectId); - - if (!uploadPitchSuccess) { - console.error("Error uploading pitch file."); - } else { - console.log("Pitch file uploaded successfully."); - } - } - - // upload logo and photos - const { success, logo, photos } = await uploadLogoAndPhotos( - recvData["projectLogo"], - recvData["projectPhotos"], - user.id, - projectId - ); - if (!success) { - console.error("Error uploading media files."); - } - - // console.log("Bucket Name:", BUCKET_PITCH_APPLICATION_NAME); - // console.log("Logo Path:", logo.data.path); - // console.table(photos); - - const logoURL = await getPrivateURL(logo.data.path, BUCKET_PITCH_APPLICATION_NAME); - let photoURLsArray: string[] = []; - const photoURLPromises = photos.map( - async (item: { success: boolean; errors: typeof errors; data: { path: string } }) => { - const photoURL = await getPrivateURL(item.data.path, BUCKET_PITCH_APPLICATION_NAME); - if (photoURL?.signedUrl) { - photoURLsArray.push(photoURL.signedUrl); - } else { - console.error("Signed URL for photo is undefined."); - } - } - ); - - await Promise.all(photoURLPromises); - // console.log(logoURL.publicUrl, projectId, logo.data.path); - // console.log(logoURL?.signedUrl, projectId); - // console.log(photoURLsArray[0], photoURLsArray[1]); - if (logoURL?.signedUrl) { - await updateImageURL(logoURL.signedUrl, "project_logo", projectId); - } else { - console.error("Signed URL for logo is undefined."); - } - await updateImageURL(photoURLsArray, "project_photos", projectId); - // console.log(logoURL, photosUrl); - setIsSuccess(true); - displayAlert(error); - }; const updateImageURL = async (url: string | string[], columnName: string, projectId: number) => { const { error } = await supabase .from("project_application") .update({ [columnName]: url }) .eq("id", projectId); - // console.log( - // `Updating ${columnName} with URL: ${url} for project ID: ${projectId}` - // ); - if (error) { - console.error(error); - } + if (error) toast.error(error.message); }; + const getPrivateURL = async (path: string, bucketName: string) => { - const { data } = await supabase.storage.from(bucketName).createSignedUrl(path, 9999999999999999999999999999); - // console.table(data); + const { data } = await supabase.storage.from(bucketName).createSignedUrl(path, 31560000); return data; }; + + const sendApplication = async (recvData: any) => { + const { projectId, error } = await saveApplicationData(recvData); + if (error) { + displayAlert(error); + return; + } + + await saveTags(recvData["tag"], projectId); + + if (typeof recvData["projectPitchDeck"] === "object") { + await uploadPitchFile(recvData["projectPitchDeck"], projectId); + } + + const { success, logo, photos } = await uploadLogoAndPhotos( + recvData["projectLogo"], + recvData["projectPhotos"], + projectId + ); + if (!success) toast.error("Error uploading media files."); + + const logoURL = await getPrivateURL(logo.data.path, BUCKET_PITCH_APPLICATION_NAME); + let photoURLsArray: string[] = []; + const photoURLPromises = photos.map(async (item) => { + const photoURL = await getPrivateURL(item.data.path, BUCKET_PITCH_APPLICATION_NAME); + if (photoURL?.signedUrl) photoURLsArray.push(photoURL.signedUrl); + }); + await Promise.all(photoURLPromises); + + if (logoURL?.signedUrl) await updateImageURL(logoURL.signedUrl, "project_logo", projectId); + await updateImageURL(photoURLsArray, "project_photos", projectId); + + if (error) { + displayAlert(error); + router.push("/project/apply"); + } + }; + + const onSubmit: SubmitHandler = async (data) => { + await sendApplication(data); + }; + return (
- -
+

Apply to raise on B2DVentures