diff --git a/src/App.tsx b/src/App.tsx index ccd76fa..6b94855 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -72,6 +72,10 @@ function App() { create:"/subjects/create", meta:{label:"Subjects", icon:} }, + { + name: "departments", + meta: { hide: true }, + }, { name: "classes", list:"/classes", diff --git a/src/lib/schema.ts b/src/lib/schema.ts index 0be7ca7..acd6df8 100644 --- a/src/lib/schema.ts +++ b/src/lib/schema.ts @@ -16,10 +16,14 @@ export const subjectSchema = z.object({ code: z.string().min(5, "Subject code must be at least 5 characters"), description: z .string() - .min(5, "Subject description must be at least 5 characters"), - department: z - .string() - .min(2, "Subject department must be at least 2 characters"), + .min(5, "Subject description must be at least 5 characters") + .max(255, "Subject description must be at most 255 characters"), + departmentId: z.coerce + .number({ + required_error: "Department is required", + invalid_type_error: "Department is required", + }) + .min(1, "Department is required"), }); const scheduleSchema = z.object({ diff --git a/src/pages/subjects/create.tsx b/src/pages/subjects/create.tsx index ee75db8..61256b4 100644 --- a/src/pages/subjects/create.tsx +++ b/src/pages/subjects/create.tsx @@ -1,16 +1,268 @@ -import React from 'react' -import { RequireRole } from '@/components/require-role'; +import React from "react"; +import { CreateView } from "@/components/refine-ui/views/create-view"; +import { Breadcrumb } from "@/components/refine-ui/layout/breadcrumb"; +import { Button } from "@/components/ui/button"; +import { useBack, useList, type HttpError } from "@refinedev/core"; +import { useForm } from "@refinedev/react-hook-form"; +import { Separator } from "@/components/ui/separator"; +import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card"; +import { Controller } from "react-hook-form"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { subjectSchema } from "@/lib/schema"; +import * as z from "zod"; +import { toast } from "sonner"; +import { + FieldGroup, + FieldLabel, + FieldError, + FieldDescription, + Field, +} from "@/components/ui/field"; +import { + InputGroup, + InputGroupTextarea, + InputGroupAddon, + InputGroupText, +} from "@/components/ui/input-group"; +import { Input } from "@/components/ui/input"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; +import { RequireRole } from "@/components/require-role"; +import type { Department } from "@/types"; + +type CreateSubjectFormOutput = z.infer; + +const Create = () => { + const back = useBack(); + const { + refineCore: { onFinish, formLoading }, + ...form + } = useForm({ + resolver: zodResolver(subjectSchema), + defaultValues: { + name: "", + code: "", + description: "", + departmentId: undefined, + }, + refineCoreProps: { + resource: "subjects", + action: "create", + onMutationSuccess: () => { + toast.success("Subject created successfully"); + back(); + }, + onMutationError: (error) => { + toast.error(error.message ?? "Failed to create subject"); + }, + }, + }); + + const { query: DepartmentsQuery } = useList({ + resource: "departments", + }); + const departments = (DepartmentsQuery.data?.data ?? []) as Department[]; + const departmentIsLoading = DepartmentsQuery.isLoading; + + function onSubmit(data: CreateSubjectFormOutput) { + onFinish(data); + } -const SubjectsCreate =()=>{ return ( - create - ) -} + + + Create Subject + + Provide the details of the subject to be created. + + + + + + + Fill in the details to create a new subject + + + + + + ( + + + Subject name + + {fieldState.error ? "*" : null} + + + + {fieldState.invalid && ( + + )} + + )} + /> + + + ( + + + Code + + {fieldState.error ? "*" : null} + + + + {fieldState.invalid && ( + + )} + + )} + /> + + ( + + + Department + + {fieldState.error ? "*" : null} + + + + field.onChange(Number(value)) + } + onOpenChange={(open) => { + if (!open) field.onBlur(); + }} + > + + + + + {departments.map((department) => ( + + {department.name} + + ))} + + + {fieldState.invalid && ( + + )} + + )} + /> + + + ( + + + Description + + {fieldState.error ? "*" : null} + + + + + + + {field.value.length}/255 characters + + + + + Include topics, level, and how this subject is used in + the curriculum. + + {fieldState.invalid && ( + + )} + + )} + /> + + + + {formLoading ? "Creating..." : "Submit"} + + Back + + + + + ); +}; const SubjectsCreatePage = () => ( - + ); -export default SubjectsCreatePage \ No newline at end of file +export default SubjectsCreatePage; diff --git a/src/types/index.ts b/src/types/index.ts index 7694584..796e143 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -1,9 +1,17 @@ +export type Department = { + id: number; + code: string; + name: string; + description: string; +}; + export type Subject = { id: number; name: string; code: string; description: string; - department: string; + departmentId: number; + department?: Department; createdAt?: string; }; @@ -107,12 +115,6 @@ export function toClassScheduleSlot(schedule: Schedule): ClassScheduleSlot { }; } -export type Department = { - id: number; - name: string; - description: string; -}; - export type ClassDetails = { id: number; name: string;
Provide the details of the subject to be created.