mirror of
https://github.com/Sosokker/B2D-Ventures.git
synced 2025-12-20 06:24:06 +01:00
fix: correct image loading issue in ImageModal and optimize performance
This commit is contained in:
parent
2b51f4d025
commit
9953aae4a4
@ -2,14 +2,7 @@ import { useEffect, useState } from "react";
|
|||||||
import { SubmitHandler, useForm, ControllerRenderProps } from "react-hook-form";
|
import { SubmitHandler, useForm, ControllerRenderProps } from "react-hook-form";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { MultipleOptionSelector } from "@/components/multipleSelector";
|
import { MultipleOptionSelector } from "@/components/multipleSelector";
|
||||||
import {
|
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form";
|
||||||
Form,
|
|
||||||
FormControl,
|
|
||||||
FormField,
|
|
||||||
FormItem,
|
|
||||||
FormLabel,
|
|
||||||
FormMessage,
|
|
||||||
} from "@/components/ui/form";
|
|
||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
import { projectFormSchema } from "@/types/schemas/application.schema";
|
import { projectFormSchema } from "@/types/schemas/application.schema";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
@ -17,19 +10,8 @@ import { zodResolver } from "@hookform/resolvers/zod";
|
|||||||
import { Label } from "@/components/ui/label";
|
import { Label } from "@/components/ui/label";
|
||||||
import { createSupabaseClient } from "@/lib/supabase/clientComponentClient";
|
import { createSupabaseClient } from "@/lib/supabase/clientComponentClient";
|
||||||
import { Textarea } from "./ui/textarea";
|
import { Textarea } from "./ui/textarea";
|
||||||
import {
|
import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from "@/components/ui/command";
|
||||||
Command,
|
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
|
||||||
CommandEmpty,
|
|
||||||
CommandGroup,
|
|
||||||
CommandInput,
|
|
||||||
CommandItem,
|
|
||||||
CommandList,
|
|
||||||
} from "@/components/ui/command";
|
|
||||||
import {
|
|
||||||
Popover,
|
|
||||||
PopoverContent,
|
|
||||||
PopoverTrigger,
|
|
||||||
} from "@/components/ui/popover";
|
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { ChevronsUpDown, Check, X } from "lucide-react";
|
import { ChevronsUpDown, Check, X } from "lucide-react";
|
||||||
|
|
||||||
@ -39,30 +21,21 @@ type FieldType = ControllerRenderProps<any, "projectPhotos">;
|
|||||||
interface ProjectFormProps {
|
interface ProjectFormProps {
|
||||||
onSubmit: SubmitHandler<projectSchema>;
|
onSubmit: SubmitHandler<projectSchema>;
|
||||||
}
|
}
|
||||||
const ProjectForm = ({
|
const ProjectForm = ({ onSubmit }: ProjectFormProps & { onSubmit: SubmitHandler<projectSchema> }) => {
|
||||||
onSubmit,
|
|
||||||
}: ProjectFormProps & { onSubmit: SubmitHandler<projectSchema> }) => {
|
|
||||||
const form = useForm<projectSchema>({
|
const form = useForm<projectSchema>({
|
||||||
resolver: zodResolver(projectFormSchema),
|
resolver: zodResolver(projectFormSchema),
|
||||||
defaultValues: {},
|
defaultValues: {},
|
||||||
});
|
});
|
||||||
let supabase = createSupabaseClient();
|
let supabase = createSupabaseClient();
|
||||||
const [projectType, setProjectType] = useState<
|
const [projectType, setProjectType] = useState<{ id: number; name: string }[]>([]);
|
||||||
{ id: number; name: string }[]
|
|
||||||
>([]);
|
|
||||||
const [projectPitch, setProjectPitch] = useState("text");
|
const [projectPitch, setProjectPitch] = useState("text");
|
||||||
const [selectedImages, setSelectedImages] = useState<File[]>([]);
|
const [selectedImages, setSelectedImages] = useState<File[]>([]);
|
||||||
const [projectPitchFile, setProjectPitchFile] = useState("");
|
const [projectPitchFile, setProjectPitchFile] = useState("");
|
||||||
const [tag, setTag] = useState<{ id: number; value: string }[]>([]);
|
const [tag, setTag] = useState<{ id: number; value: string }[]>([]);
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
const [selectedTag, setSelectedTag] = useState<
|
const [selectedTag, setSelectedTag] = useState<{ id: number; value: string }[]>([]);
|
||||||
{ id: number; value: string }[]
|
|
||||||
>([]);
|
|
||||||
|
|
||||||
const handleFileChange = (
|
const handleFileChange = (event: React.ChangeEvent<HTMLInputElement>, field: FieldType) => {
|
||||||
event: React.ChangeEvent<HTMLInputElement>,
|
|
||||||
field: FieldType
|
|
||||||
) => {
|
|
||||||
if (event.target.files) {
|
if (event.target.files) {
|
||||||
const filesArray = Array.from(event.target.files);
|
const filesArray = Array.from(event.target.files);
|
||||||
console.log("first file", filesArray);
|
console.log("first file", filesArray);
|
||||||
@ -86,9 +59,7 @@ const ProjectForm = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const fetchProjectType = async () => {
|
const fetchProjectType = async () => {
|
||||||
let { data: ProjectType, error } = await supabase
|
let { data: ProjectType, error } = await supabase.from("project_type").select("id, value");
|
||||||
.from("project_type")
|
|
||||||
.select("id, value");
|
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
@ -125,10 +96,7 @@ const ProjectForm = ({
|
|||||||
}, []);
|
}, []);
|
||||||
return (
|
return (
|
||||||
<Form {...form}>
|
<Form {...form}>
|
||||||
<form
|
<form onSubmit={form.handleSubmit(onSubmit as SubmitHandler<projectSchema>)} className="space-y-8">
|
||||||
onSubmit={form.handleSubmit(onSubmit as SubmitHandler<projectSchema>)}
|
|
||||||
className="space-y-8"
|
|
||||||
>
|
|
||||||
<div className="ml-96 space-y-10">
|
<div className="ml-96 space-y-10">
|
||||||
{/* project name */}
|
{/* project name */}
|
||||||
<FormField
|
<FormField
|
||||||
@ -137,17 +105,10 @@ const ProjectForm = ({
|
|||||||
render={({ field }: { field: any }) => (
|
render={({ field }: { field: any }) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<div className="space-y-5">
|
<div className="space-y-5">
|
||||||
<FormLabel className="font-bold text-lg">
|
<FormLabel className="font-bold text-lg">Project name</FormLabel>
|
||||||
Project name
|
|
||||||
</FormLabel>
|
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<div className="flex space-x-5">
|
<div className="flex space-x-5">
|
||||||
<Input
|
<Input type="text" id="projectName" className="w-96" {...field} />
|
||||||
type="text"
|
|
||||||
id="projectName"
|
|
||||||
className="w-96"
|
|
||||||
{...field}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
</div>
|
</div>
|
||||||
@ -169,9 +130,7 @@ const ProjectForm = ({
|
|||||||
handleFunction={(selectedValues: any) => {
|
handleFunction={(selectedValues: any) => {
|
||||||
field.onChange(selectedValues.id);
|
field.onChange(selectedValues.id);
|
||||||
}}
|
}}
|
||||||
description={
|
description={<>Please specify the primary purpose of the funds</>}
|
||||||
<>Please specify the primary purpose of the funds</>
|
|
||||||
}
|
|
||||||
placeholder="Select a Project type"
|
placeholder="Select a Project type"
|
||||||
selectLabel="Project type"
|
selectLabel="Project type"
|
||||||
/>
|
/>
|
||||||
@ -189,18 +148,11 @@ const ProjectForm = ({
|
|||||||
<FormItem>
|
<FormItem>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<div className="mt-10 space-y-5">
|
<div className="mt-10 space-y-5">
|
||||||
<FormLabel className="font-bold text-lg">
|
<FormLabel className="font-bold text-lg">Short description</FormLabel>
|
||||||
Short description
|
|
||||||
</FormLabel>
|
|
||||||
<div className="flex space-x-5">
|
<div className="flex space-x-5">
|
||||||
<Textarea
|
<Textarea id="shortDescription" className="w-96" {...field} />
|
||||||
id="shortDescription"
|
|
||||||
className="w-96"
|
|
||||||
{...field}
|
|
||||||
/>
|
|
||||||
<span className="text-[12px] text-neutral-500 self-center">
|
<span className="text-[12px] text-neutral-500 self-center">
|
||||||
Could you provide a brief description of your project{" "}
|
Could you provide a brief description of your project <br /> in one or two sentences?
|
||||||
<br /> in one or two sentences?
|
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -225,9 +177,7 @@ const ProjectForm = ({
|
|||||||
<div className="flex space-x-2 w-96">
|
<div className="flex space-x-2 w-96">
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
variant={
|
variant={projectPitch === "text" ? "default" : "outline"}
|
||||||
projectPitch === "text" ? "default" : "outline"
|
|
||||||
}
|
|
||||||
onClick={() => setProjectPitch("text")}
|
onClick={() => setProjectPitch("text")}
|
||||||
className="w-32 h-12 text-base"
|
className="w-32 h-12 text-base"
|
||||||
>
|
>
|
||||||
@ -235,9 +185,7 @@ const ProjectForm = ({
|
|||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
variant={
|
variant={projectPitch === "file" ? "default" : "outline"}
|
||||||
projectPitch === "file" ? "default" : "outline"
|
|
||||||
}
|
|
||||||
onClick={() => setProjectPitch("file")}
|
onClick={() => setProjectPitch("file")}
|
||||||
className="w-32 h-12 text-base"
|
className="w-32 h-12 text-base"
|
||||||
>
|
>
|
||||||
@ -247,11 +195,7 @@ const ProjectForm = ({
|
|||||||
<div className="flex space-x-5">
|
<div className="flex space-x-5">
|
||||||
<Input
|
<Input
|
||||||
type={projectPitch === "file" ? "file" : "text"}
|
type={projectPitch === "file" ? "file" : "text"}
|
||||||
placeholder={
|
placeholder={projectPitch === "file" ? "Upload your Markdown file" : "https:// "}
|
||||||
projectPitch === "file"
|
|
||||||
? "Upload your Markdown file"
|
|
||||||
: "https:// "
|
|
||||||
}
|
|
||||||
accept={projectPitch === "file" ? ".md" : undefined}
|
accept={projectPitch === "file" ? ".md" : undefined}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
const value = e.target;
|
const value = e.target;
|
||||||
@ -266,11 +210,9 @@ const ProjectForm = ({
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<span className="text-[12px] text-neutral-500 self-center">
|
<span className="text-[12px] text-neutral-500 self-center">
|
||||||
Please upload a file or paste a link to your pitch,
|
Please upload a file or paste a link to your pitch, which should <br />
|
||||||
which should <br />
|
cover key aspects of your project: what it will do, what investors <br /> can expect to gain,
|
||||||
cover key aspects of your project: what it will do,
|
and any highlights that make it stand out.
|
||||||
what investors <br /> can expect to gain, and any
|
|
||||||
highlights that make it stand out.
|
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
{projectPitchFile && (
|
{projectPitchFile && (
|
||||||
@ -302,23 +244,22 @@ const ProjectForm = ({
|
|||||||
<FormItem>
|
<FormItem>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<div className="mt-10 space-y-5">
|
<div className="mt-10 space-y-5">
|
||||||
<FormLabel className="font-bold text-lg mt-10">
|
<FormLabel className="font-bold text-lg mt-10">Project logo</FormLabel>
|
||||||
Project logo
|
<div className="flex space-x-5">
|
||||||
</FormLabel>
|
<Input
|
||||||
<Input
|
type="file"
|
||||||
type="file"
|
id="projectLogo"
|
||||||
id="projectLogo"
|
className="w-96"
|
||||||
className="w-96"
|
accept="image/*"
|
||||||
accept="image/*"
|
onChange={(e) => {
|
||||||
onChange={(e) => {
|
const file = e.target.files?.[0];
|
||||||
const file = e.target.files?.[0];
|
field.onChange(file || "");
|
||||||
field.onChange(file || "");
|
}}
|
||||||
}}
|
/>
|
||||||
/>
|
<span className="text-[12px] text-neutral-500 self-center">
|
||||||
<span className="text-[12px] text-neutral-500 self-center">
|
Please upload the logo picture that best represents your project.
|
||||||
Please upload the logo picture that best represents your
|
</span>
|
||||||
project.
|
</div>
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<FormMessage />
|
<FormMessage />
|
||||||
@ -334,9 +275,7 @@ const ProjectForm = ({
|
|||||||
<FormItem>
|
<FormItem>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<div className="mt-10 space-y-5">
|
<div className="mt-10 space-y-5">
|
||||||
<FormLabel className="font-bold text-lg mt-10">
|
<FormLabel className="font-bold text-lg mt-10">Project photos</FormLabel>
|
||||||
Project photos
|
|
||||||
</FormLabel>
|
|
||||||
<div className="flex space-x-5">
|
<div className="flex space-x-5">
|
||||||
<Input
|
<Input
|
||||||
type="file"
|
type="file"
|
||||||
@ -349,16 +288,15 @@ const ProjectForm = ({
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<span className="text-[12px] text-neutral-500 self-center">
|
<span className="text-[12px] text-neutral-500 self-center">
|
||||||
Please upload the logo picture that best represents your
|
Please upload the photo that best represents your project.
|
||||||
project.
|
<p className="text-red-500">
|
||||||
|
*** It is recommended that the photo be horizontal for better presentation.
|
||||||
|
</p>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-5 space-y-2 w-96">
|
<div className="mt-5 space-y-2 w-96">
|
||||||
{selectedImages.map((image, index) => (
|
{selectedImages.map((image, index) => (
|
||||||
<div
|
<div key={index} className="flex justify-between items-center border p-2 rounded">
|
||||||
key={index}
|
|
||||||
className="flex justify-between items-center border p-2 rounded"
|
|
||||||
>
|
|
||||||
<span>{image.name}</span>
|
<span>{image.name}</span>
|
||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="outline"
|
||||||
@ -385,9 +323,7 @@ const ProjectForm = ({
|
|||||||
render={({ field }: { field: any }) => (
|
render={({ field }: { field: any }) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<div className="mt-10 space-y-5">
|
<div className="mt-10 space-y-5">
|
||||||
<FormLabel className="font-bold text-lg">
|
<FormLabel className="font-bold text-lg">Minimum investment</FormLabel>
|
||||||
Minimum investment
|
|
||||||
</FormLabel>
|
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<div className="flex space-x-5">
|
<div className="flex space-x-5">
|
||||||
<Input
|
<Input
|
||||||
@ -419,9 +355,7 @@ const ProjectForm = ({
|
|||||||
render={({ field }: { field: any }) => (
|
render={({ field }: { field: any }) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<div className="mt-10 space-y-5">
|
<div className="mt-10 space-y-5">
|
||||||
<FormLabel className="font-bold text-lg">
|
<FormLabel className="font-bold text-lg">Target investment</FormLabel>
|
||||||
Target investment
|
|
||||||
</FormLabel>
|
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<div className="flex space-x-5">
|
<div className="flex space-x-5">
|
||||||
<Input
|
<Input
|
||||||
@ -437,8 +371,8 @@ const ProjectForm = ({
|
|||||||
value={field.value}
|
value={field.value}
|
||||||
/>
|
/>
|
||||||
<span className="text-[12px] text-neutral-500 self-center">
|
<span className="text-[12px] text-neutral-500 self-center">
|
||||||
We encourage you to set a specific target investment{" "}
|
We encourage you to set a specific target investment <br /> amount that reflects your funding
|
||||||
<br /> amount that reflects your funding goals.
|
goals.
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
@ -457,16 +391,10 @@ const ProjectForm = ({
|
|||||||
<FormLabel className="font-bold text-lg">Deadline</FormLabel>
|
<FormLabel className="font-bold text-lg">Deadline</FormLabel>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<div className="flex space-x-5">
|
<div className="flex space-x-5">
|
||||||
<Input
|
<Input type="datetime-local" id="deadline" className="w-96" {...field} />
|
||||||
type="datetime-local"
|
|
||||||
id="deadline"
|
|
||||||
className="w-96"
|
|
||||||
{...field}
|
|
||||||
/>
|
|
||||||
<span className="text-[12px] text-neutral-500 self-center">
|
<span className="text-[12px] text-neutral-500 self-center">
|
||||||
What is the deadline for your fundraising project?
|
What is the deadline for your fundraising project? Setting <br /> a clear timeline can help
|
||||||
Setting <br /> a clear timeline can help motivate
|
motivate potential investors.
|
||||||
potential investors.
|
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
@ -493,9 +421,7 @@ const ProjectForm = ({
|
|||||||
aria-expanded={open}
|
aria-expanded={open}
|
||||||
className="w-96 justify-between overflow-hidden text-ellipsis whitespace-nowrap"
|
className="w-96 justify-between overflow-hidden text-ellipsis whitespace-nowrap"
|
||||||
>
|
>
|
||||||
{selectedTag.length > 0
|
{selectedTag.length > 0 ? selectedTag.map((t) => t.value).join(", ") : "Select tags..."}
|
||||||
? selectedTag.map((t) => t.value).join(", ")
|
|
||||||
: "Select tags..."}
|
|
||||||
<ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
|
<ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
|
||||||
</Button>
|
</Button>
|
||||||
</PopoverTrigger>
|
</PopoverTrigger>
|
||||||
@ -511,15 +437,11 @@ const ProjectForm = ({
|
|||||||
value={tag.value}
|
value={tag.value}
|
||||||
onSelect={() => {
|
onSelect={() => {
|
||||||
setSelectedTag((prev) => {
|
setSelectedTag((prev) => {
|
||||||
const exists = prev.find(
|
const exists = prev.find((t) => t.id === tag.id);
|
||||||
(t) => t.id === tag.id
|
|
||||||
);
|
|
||||||
const updatedTags = exists
|
const updatedTags = exists
|
||||||
? prev.filter((t) => t.id !== tag.id)
|
? prev.filter((t) => t.id !== tag.id)
|
||||||
: [...prev, tag];
|
: [...prev, tag];
|
||||||
field.onChange(
|
field.onChange(updatedTags.map((t) => t.id));
|
||||||
updatedTags.map((t) => t.id)
|
|
||||||
);
|
|
||||||
return updatedTags;
|
return updatedTags;
|
||||||
});
|
});
|
||||||
setOpen(false);
|
setOpen(false);
|
||||||
@ -528,9 +450,7 @@ const ProjectForm = ({
|
|||||||
<Check
|
<Check
|
||||||
className={cn(
|
className={cn(
|
||||||
"h-4",
|
"h-4",
|
||||||
selectedTag.some((t) => t.id === tag.id)
|
selectedTag.some((t) => t.id === tag.id) ? "opacity-100" : "opacity-0"
|
||||||
? "opacity-100"
|
|
||||||
: "opacity-0"
|
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
{tag.value}
|
{tag.value}
|
||||||
@ -542,8 +462,7 @@ const ProjectForm = ({
|
|||||||
</PopoverContent>
|
</PopoverContent>
|
||||||
</Popover>
|
</Popover>
|
||||||
<span className="text-[12px] text-neutral-500 self-center">
|
<span className="text-[12px] text-neutral-500 self-center">
|
||||||
Add 1 to 5 tags that describe your project. Tags help{" "}
|
Add 1 to 5 tags that describe your project. Tags help <br />
|
||||||
<br />
|
|
||||||
investors understand your focus.
|
investors understand your focus.
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
@ -561,9 +480,7 @@ const ProjectForm = ({
|
|||||||
<button
|
<button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setSelectedTag((prev) => {
|
setSelectedTag((prev) => {
|
||||||
const updatedTags = prev.filter(
|
const updatedTags = prev.filter((t) => t.id !== tag.id);
|
||||||
(t) => t.id !== tag.id
|
|
||||||
);
|
|
||||||
field.onChange(updatedTags.map((t) => t.id));
|
field.onChange(updatedTags.map((t) => t.id));
|
||||||
return updatedTags;
|
return updatedTags;
|
||||||
});
|
});
|
||||||
@ -579,10 +496,7 @@ const ProjectForm = ({
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<center>
|
<center>
|
||||||
<Button
|
<Button className="mt-12 mb-20 h-10 text-base font-bold py-6 px-5 " type="submit">
|
||||||
className="mt-12 mb-20 h-10 text-base font-bold py-6 px-5 "
|
|
||||||
type="submit"
|
|
||||||
>
|
|
||||||
Submit application
|
Submit application
|
||||||
</Button>
|
</Button>
|
||||||
</center>
|
</center>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user