mirror of
https://github.com/Sosokker/B2D-Ventures.git
synced 2025-12-20 14:34:05 +01:00
feat: add project edit page
This commit is contained in:
parent
2df7d9c514
commit
9513b6e806
145
src/app/project/[projectId]/edit/EditProjectForm.tsx
Normal file
145
src/app/project/[projectId]/edit/EditProjectForm.tsx
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { SubmitHandler, useForm } from "react-hook-form";
|
||||||
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
|
import { projectEditSchema, ProjectEditSchema } from "@/types/schemas/project.schema";
|
||||||
|
import { Textarea } from "@/components/ui/textarea";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import { Input } from "@/components/ui/input";
|
||||||
|
import { Form, FormField, FormItem, FormLabel, FormControl, FormMessage, FormDescription } from "@/components/ui/form";
|
||||||
|
import { DateTimePicker } from "@/components/ui/datetime-picker";
|
||||||
|
import { MdxEditor } from "@/components/MarkdownEditor";
|
||||||
|
import { editProjectById } from "@/lib/data/projectMutate";
|
||||||
|
import toast from "react-hot-toast";
|
||||||
|
import { useRouter } from "next/navigation";
|
||||||
|
import { createSupabaseClient } from "@/lib/supabase/clientComponentClient";
|
||||||
|
import { useState } from "react";
|
||||||
|
|
||||||
|
export default function EditProjectForm({
|
||||||
|
projectData,
|
||||||
|
projectId,
|
||||||
|
}: {
|
||||||
|
projectData: ProjectEditSchema;
|
||||||
|
projectId: number;
|
||||||
|
}) {
|
||||||
|
const router = useRouter();
|
||||||
|
const client = createSupabaseClient();
|
||||||
|
|
||||||
|
const projectForm = useForm<ProjectEditSchema>({
|
||||||
|
resolver: zodResolver(projectEditSchema),
|
||||||
|
defaultValues: {
|
||||||
|
project_name: projectData.project_name || "",
|
||||||
|
project_short_description: projectData.project_short_description || "",
|
||||||
|
project_description: projectData.project_description || "",
|
||||||
|
deadline: projectData.deadline ? projectData.deadline : undefined,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const [deadline, setDeadline] = useState(projectData.deadline);
|
||||||
|
const [descriptionContent, setDescriptionContent] = useState(projectData.project_description || "");
|
||||||
|
|
||||||
|
const onSubmit: SubmitHandler<ProjectEditSchema> = async (updates) => {
|
||||||
|
try {
|
||||||
|
const updatedData = {
|
||||||
|
...updates,
|
||||||
|
deadline: deadline ? new Date(deadline).toISOString() : undefined,
|
||||||
|
project_description: descriptionContent,
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = await editProjectById(client, projectId, updatedData);
|
||||||
|
|
||||||
|
if (result) {
|
||||||
|
toast.success("Project updated successfully!");
|
||||||
|
router.push(`/deals/${projectId}`);
|
||||||
|
} else {
|
||||||
|
toast.error("No fields to update!");
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
toast.error("Error updating project!");
|
||||||
|
console.error("Error updating project:", error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Form {...projectForm}>
|
||||||
|
<form onSubmit={projectForm.handleSubmit(onSubmit)} className="space-y-8">
|
||||||
|
<FormField
|
||||||
|
control={projectForm.control}
|
||||||
|
name="project_name"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel>Project Name</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<Input placeholder="Project Name" {...field} value={field.value || ""} />
|
||||||
|
</FormControl>
|
||||||
|
<FormDescription>Provide the name of the project.</FormDescription>
|
||||||
|
<FormMessage>
|
||||||
|
{projectForm.formState.errors.project_name && (
|
||||||
|
<span>{projectForm.formState.errors.project_name.message}</span>
|
||||||
|
)}
|
||||||
|
</FormMessage>
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<FormField
|
||||||
|
control={projectForm.control}
|
||||||
|
name="project_short_description"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel>Short Description</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<Textarea placeholder="Brief project overview" {...field} value={field.value || ""} />
|
||||||
|
</FormControl>
|
||||||
|
<FormDescription>A short summary of the project.</FormDescription>
|
||||||
|
<FormMessage>
|
||||||
|
{projectForm.formState.errors.project_short_description && (
|
||||||
|
<span>{projectForm.formState.errors.project_short_description.message}</span>
|
||||||
|
)}
|
||||||
|
</FormMessage>
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<FormField
|
||||||
|
control={projectForm.control}
|
||||||
|
name="project_description"
|
||||||
|
render={() => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel>Full Description</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<MdxEditor content={descriptionContent} setContentInParent={setDescriptionContent} />
|
||||||
|
</FormControl>
|
||||||
|
<FormDescription>Provide a detailed description of the project in Markdown format.</FormDescription>
|
||||||
|
<FormMessage>
|
||||||
|
{projectForm.formState.errors.project_description && (
|
||||||
|
<span>{projectForm.formState.errors.project_description.message}</span>
|
||||||
|
)}
|
||||||
|
</FormMessage>
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<FormField
|
||||||
|
control={projectForm.control}
|
||||||
|
name="deadline"
|
||||||
|
render={() => (
|
||||||
|
<FormItem className="w-1/4">
|
||||||
|
<FormLabel>Deadline</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<DateTimePicker
|
||||||
|
hourCycle={24}
|
||||||
|
value={deadline ? new Date(deadline) : undefined}
|
||||||
|
onChange={(date) => setDeadline(date?.toISOString())}
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
<FormDescription>Specify the project deadline in a 24-hour format.</FormDescription>
|
||||||
|
<FormMessage>
|
||||||
|
{projectForm.formState.errors.deadline && <span>{projectForm.formState.errors.deadline.message}</span>}
|
||||||
|
</FormMessage>
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Button type="submit">Submit</Button>
|
||||||
|
</form>
|
||||||
|
</Form>
|
||||||
|
);
|
||||||
|
}
|
||||||
39
src/app/project/[projectId]/edit/page.tsx
Normal file
39
src/app/project/[projectId]/edit/page.tsx
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import React, { Suspense } from "react";
|
||||||
|
import EditProjectForm from "./EditProjectForm";
|
||||||
|
import { Separator } from "@/components/ui/separator";
|
||||||
|
import { getProjectDataQuery } from "@/lib/data/projectQuery";
|
||||||
|
import { createSupabaseClient } from "@/lib/supabase/serverComponentClient";
|
||||||
|
import { ProjectEditSchema } from "@/types/schemas/project.schema";
|
||||||
|
|
||||||
|
export default async function EditProjectPage({ params }: { params: { projectId: string } }) {
|
||||||
|
const client = createSupabaseClient();
|
||||||
|
const projectId = Number(params.projectId);
|
||||||
|
|
||||||
|
const { data: projectData, error: projectDataError } = await getProjectDataQuery(client, projectId);
|
||||||
|
|
||||||
|
if (projectDataError) {
|
||||||
|
console.error("Error fetching project data:", projectDataError);
|
||||||
|
return <p>Error loading project data.</p>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const mappedProjectData: ProjectEditSchema = {
|
||||||
|
project_name: projectData.project_name,
|
||||||
|
project_status_id: projectData.project_status_id,
|
||||||
|
project_type_id: projectData.project_type_id,
|
||||||
|
project_short_description: projectData.project_short_description,
|
||||||
|
project_description: projectData.project_description,
|
||||||
|
deadline: projectData.deadline ? new Date(projectData.deadline).toISOString() : undefined,
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="container max-w-screen-xl">
|
||||||
|
<div className="my-5">
|
||||||
|
<span className="text-2xl font-bold">Edit Project</span>
|
||||||
|
<Separator className="my-5" />
|
||||||
|
</div>
|
||||||
|
<Suspense fallback={<p>Loading project data...</p>}>
|
||||||
|
{projectData ? <EditProjectForm projectData={mappedProjectData} projectId={projectId} /> : <p>Loading...</p>}
|
||||||
|
</Suspense>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
29
src/lib/data/projectMutate.ts
Normal file
29
src/lib/data/projectMutate.ts
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import { Database, Tables } from "@/types/database.types";
|
||||||
|
import { SupabaseClient } from "@supabase/supabase-js";
|
||||||
|
|
||||||
|
export type ProjectInvestmentDetailSchema = Tables<"project_investment_detail">;
|
||||||
|
|
||||||
|
export interface ProjectEditSchema {
|
||||||
|
project_name?: string;
|
||||||
|
project_status_id?: number;
|
||||||
|
project_type_id?: number;
|
||||||
|
project_short_description?: string;
|
||||||
|
project_description?: string;
|
||||||
|
deadline?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function editProjectById(
|
||||||
|
client: SupabaseClient<Database>,
|
||||||
|
projectId: number,
|
||||||
|
projectData: Partial<ProjectEditSchema>
|
||||||
|
) {
|
||||||
|
return client.from("project").update(projectData).eq("id", projectId).select();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function editProjectInvestmentDetailById(
|
||||||
|
client: SupabaseClient<Database>,
|
||||||
|
projectId: number,
|
||||||
|
investmentDetailData: Partial<ProjectInvestmentDetailSchema>
|
||||||
|
) {
|
||||||
|
return client.from("project_investment_detail").update(investmentDetailData).eq("project_id", projectId).select();
|
||||||
|
}
|
||||||
@ -53,6 +53,9 @@ function getProjectDataQuery(client: SupabaseClient, projectId: number) {
|
|||||||
project_short_description,
|
project_short_description,
|
||||||
project_description,
|
project_description,
|
||||||
published_time,
|
published_time,
|
||||||
|
project_status_id,
|
||||||
|
project_type_id,
|
||||||
|
deadline,
|
||||||
...project_investment_detail!inner (
|
...project_investment_detail!inner (
|
||||||
min_investment,
|
min_investment,
|
||||||
total_investment,
|
total_investment,
|
||||||
|
|||||||
12
src/types/schemas/project.schema.ts
Normal file
12
src/types/schemas/project.schema.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
export const projectEditSchema = z.object({
|
||||||
|
project_name: z.string().optional(),
|
||||||
|
project_status_id: z.number().optional(),
|
||||||
|
project_type_id: z.number().optional(),
|
||||||
|
project_short_description: z.string().optional(),
|
||||||
|
project_description: z.string().optional(),
|
||||||
|
deadline: z.string().optional(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export type ProjectEditSchema = z.infer<typeof projectEditSchema>;
|
||||||
Loading…
Reference in New Issue
Block a user