mirror of
https://github.com/Sosokker/B2D-Ventures.git
synced 2025-12-18 21:44:06 +01:00
refactor: extract function from project apply page
This commit is contained in:
parent
d5c6590cd3
commit
04fc8a33ab
20
src/app/project/apply/displayAlert.ts
Normal file
20
src/app/project/apply/displayAlert.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import Swal from "sweetalert2";
|
||||||
|
import toast from "react-hot-toast";
|
||||||
|
|
||||||
|
export 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) {
|
||||||
|
if (error) {
|
||||||
|
toast.error("Error sending Project Application");
|
||||||
|
} else {
|
||||||
|
toast.success("Your application has been submitted!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
6
src/app/project/apply/fileUploadService.ts
Normal file
6
src/app/project/apply/fileUploadService.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
import { uploadFile } from "@/app/api/generalApi";
|
||||||
|
|
||||||
|
export const uploadFiles = async (files: File[], path: string) => {
|
||||||
|
const results = await Promise.all(files.map((file) => uploadFile(file, "project-application", path + file.name)));
|
||||||
|
return results;
|
||||||
|
};
|
||||||
@ -1,31 +1,25 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { createSupabaseClient } from "@/lib/supabase/clientComponentClient";
|
import { saveApplicationData, saveTags } from "./projectService";
|
||||||
|
import { uploadFiles } from "./fileUploadService";
|
||||||
|
import { displayAlert } from "./displayAlert";
|
||||||
import ProjectForm from "./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 { useRouter } from "next/navigation";
|
|
||||||
import toast from "react-hot-toast";
|
|
||||||
import { useUserRole } from "@/hooks/useUserRole";
|
|
||||||
import { LegacyLoader } from "@/components/loading/LegacyLoader";
|
import { LegacyLoader } from "@/components/loading/LegacyLoader";
|
||||||
|
import toast from "react-hot-toast";
|
||||||
type projectSchema = z.infer<typeof projectFormSchema>;
|
import { useRouter } from "next/navigation";
|
||||||
const supabase = createSupabaseClient();
|
import { useUserRole } from "@/hooks/useUserRole";
|
||||||
const BUCKET_PITCH_APPLICATION_NAME = "project-application";
|
|
||||||
|
|
||||||
export default function ApplyProject() {
|
export default function ApplyProject() {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { data, session, isLoading, error } = useUserRole();
|
const { data, session, isLoading, error } = useUserRole();
|
||||||
const userId = session?.user.id;
|
|
||||||
const role: string = data?.role;
|
const role: string = data?.role;
|
||||||
|
|
||||||
if (isLoading || !session) {
|
if (isLoading || !session) {
|
||||||
return <LegacyLoader />;
|
return <LegacyLoader />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const userId = session!.user.id;
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
@ -36,139 +30,21 @@ export default function ApplyProject() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const displayAlert = (error: any) => {
|
const sendApplication = async (data: any) => {
|
||||||
Swal.fire({
|
try {
|
||||||
icon: error == null ? "success" : "error",
|
const { projectId, error } = await saveApplicationData(data, userId);
|
||||||
title: error == null ? "Success" : `Error: ${error.code}`,
|
if (error) {
|
||||||
text: error == null ? "Your application has been submitted" : error.message,
|
displayAlert(error);
|
||||||
confirmButtonColor: error == null ? "green" : "red",
|
return;
|
||||||
allowOutsideClick: false,
|
|
||||||
}).then((result) => {
|
|
||||||
if (result.isConfirmed) {
|
|
||||||
toast.error("Error sending Project Application");
|
|
||||||
router.push("/");
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const saveApplicationData = async (recvData: any) => {
|
await saveTags(data["tag"], projectId);
|
||||||
const pitchType = typeof recvData["projectPitchDeck"];
|
await uploadFiles(data["projectPhotos"], `${userId}/${projectId}/photos/`);
|
||||||
const { data: projectData, error: projectError } = await supabase
|
displayAlert(null);
|
||||||
.from("project_application")
|
router.push("/");
|
||||||
.insert([
|
} catch (error) {
|
||||||
{
|
|
||||||
user_id: userId,
|
|
||||||
pitch_deck_url: pitchType === "string" ? recvData["projectPitchDeck"] : "",
|
|
||||||
target_investment: recvData["targetInvest"],
|
|
||||||
deadline: recvData["deadline"],
|
|
||||||
project_name: recvData["projectName"],
|
|
||||||
project_type_id: recvData["projectType"],
|
|
||||||
short_description: recvData["shortDescription"],
|
|
||||||
min_investment: recvData["minInvest"],
|
|
||||||
},
|
|
||||||
])
|
|
||||||
.select();
|
|
||||||
|
|
||||||
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();
|
|
||||||
return response;
|
|
||||||
});
|
|
||||||
|
|
||||||
const results = await Promise.all(tagPromises);
|
|
||||||
const errors = results.filter((result) => result.error).map((result) => result.error);
|
|
||||||
|
|
||||||
return { errors };
|
|
||||||
};
|
|
||||||
|
|
||||||
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[], projectId: string) => {
|
|
||||||
const uploadResults: { logo?: any; photos: any[] } = { photos: [] };
|
|
||||||
|
|
||||||
if (logoFile) {
|
|
||||||
const logoResult = await uploadFile(
|
|
||||||
logoFile,
|
|
||||||
BUCKET_PITCH_APPLICATION_NAME,
|
|
||||||
`${userId}/${projectId}/logo/${logoFile.name}`
|
|
||||||
);
|
|
||||||
if (!logoResult.success) return { success: false, logo: logoResult, photos: [] };
|
|
||||||
uploadResults.logo = logoResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
const allUploadsSuccessful = photoResults.every((result) => result.success);
|
|
||||||
|
|
||||||
return { success: allUploadsSuccessful, logo: uploadResults.logo, photos: uploadResults.photos };
|
|
||||||
};
|
|
||||||
|
|
||||||
const updateImageURL = async (url: string | string[], columnName: string, projectId: number) => {
|
|
||||||
const { error } = await supabase
|
|
||||||
.from("project_application")
|
|
||||||
.update({ [columnName]: url })
|
|
||||||
.eq("id", projectId);
|
|
||||||
if (error) toast.error(error.message);
|
|
||||||
};
|
|
||||||
|
|
||||||
const getPrivateURL = async (path: string, bucketName: string) => {
|
|
||||||
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);
|
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<projectSchema> = async (data) => {
|
|
||||||
await sendApplication(data);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -187,7 +63,7 @@ export default function ApplyProject() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="grid auto-rows-max bg-zinc-100 dark:bg-zinc-900 pt-12 -mb-6">
|
<div className="grid auto-rows-max bg-zinc-100 dark:bg-zinc-900 pt-12 -mb-6">
|
||||||
<ProjectForm onSubmit={onSubmit} />
|
<ProjectForm onSubmit={sendApplication} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
38
src/app/project/apply/projectService.ts
Normal file
38
src/app/project/apply/projectService.ts
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import { createSupabaseClient } from "@/lib/supabase/clientComponentClient";
|
||||||
|
|
||||||
|
const supabase = createSupabaseClient();
|
||||||
|
|
||||||
|
export const saveApplicationData = async (data: any, userId: string) => {
|
||||||
|
const pitchType = typeof data["projectPitchDeck"];
|
||||||
|
const { data: projectData, error } = await supabase
|
||||||
|
.from("project_application")
|
||||||
|
.insert([
|
||||||
|
{
|
||||||
|
user_id: userId,
|
||||||
|
pitch_deck_url: pitchType === "string" ? data["projectPitchDeck"] : "",
|
||||||
|
target_investment: data["targetInvest"],
|
||||||
|
deadline: data["deadline"],
|
||||||
|
project_name: data["projectName"],
|
||||||
|
project_type_id: data["projectType"],
|
||||||
|
short_description: data["shortDescription"],
|
||||||
|
min_investment: data["minInvest"],
|
||||||
|
},
|
||||||
|
])
|
||||||
|
.select();
|
||||||
|
|
||||||
|
return { projectId: projectData?.[0]?.id, error };
|
||||||
|
};
|
||||||
|
|
||||||
|
export 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();
|
||||||
|
return response;
|
||||||
|
});
|
||||||
|
|
||||||
|
const results = await Promise.all(tagPromises);
|
||||||
|
const errors = results.filter((result) => result.error).map((result) => result.error);
|
||||||
|
return { errors };
|
||||||
|
};
|
||||||
Loading…
Reference in New Issue
Block a user