Files
Reactive-Resume/src/dialogs/resume/sections/education.tsx
T
Amruth Pillai 0bc53b9c2a - simplify imports
- update translations
- convert image to base64 before sending to printer
- update development docs
2026-01-22 15:46:09 +01:00

282 lines
7.2 KiB
TypeScript

import { zodResolver } from "@hookform/resolvers/zod";
import { Trans } from "@lingui/react/macro";
import { PencilSimpleLineIcon, PlusIcon } from "@phosphor-icons/react";
import { useForm, useFormContext } from "react-hook-form";
import type z from "zod";
import { RichInput } from "@/components/input/rich-input";
import { URLInput } from "@/components/input/url-input";
import { useResumeStore } from "@/components/resume/store/resume";
import { Button } from "@/components/ui/button";
import { DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog";
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form";
import { Input } from "@/components/ui/input";
import type { DialogProps } from "@/dialogs/store";
import { useDialogStore } from "@/dialogs/store";
import { educationItemSchema } from "@/schema/resume/data";
import { generateId } from "@/utils/string";
const formSchema = educationItemSchema;
type FormValues = z.infer<typeof formSchema>;
export function CreateEducationDialog({ data }: DialogProps<"resume.sections.education.create">) {
const closeDialog = useDialogStore((state) => state.closeDialog);
const updateResumeData = useResumeStore((state) => state.updateResumeData);
const form = useForm<FormValues>({
resolver: zodResolver(formSchema),
defaultValues: {
id: generateId(),
hidden: data?.item?.hidden ?? false,
school: data?.item?.school ?? "",
degree: data?.item?.degree ?? "",
area: data?.item?.area ?? "",
grade: data?.item?.grade ?? "",
location: data?.item?.location ?? "",
period: data?.item?.period ?? "",
website: data?.item?.website ?? { url: "", label: "" },
description: data?.item?.description ?? "",
},
});
const onSubmit = (formData: FormValues) => {
updateResumeData((draft) => {
if (data?.customSectionId) {
const section = draft.customSections.find((s) => s.id === data.customSectionId);
if (section) section.items.push(formData);
} else {
draft.sections.education.items.push(formData);
}
});
closeDialog();
};
return (
<DialogContent>
<DialogHeader>
<DialogTitle className="flex items-center gap-x-2">
<PlusIcon />
<Trans>Create a new education</Trans>
</DialogTitle>
<DialogDescription />
</DialogHeader>
<Form {...form}>
<form className="grid gap-4 sm:grid-cols-2" onSubmit={form.handleSubmit(onSubmit)}>
<EducationForm />
<DialogFooter className="sm:col-span-full">
<Button variant="ghost" onClick={closeDialog}>
<Trans>Cancel</Trans>
</Button>
<Button type="submit" disabled={form.formState.isSubmitting}>
<Trans>Create</Trans>
</Button>
</DialogFooter>
</form>
</Form>
</DialogContent>
);
}
export function UpdateEducationDialog({ data }: DialogProps<"resume.sections.education.update">) {
const closeDialog = useDialogStore((state) => state.closeDialog);
const updateResumeData = useResumeStore((state) => state.updateResumeData);
const form = useForm<FormValues>({
resolver: zodResolver(formSchema),
defaultValues: {
id: data.item.id,
hidden: data.item.hidden,
school: data.item.school,
degree: data.item.degree,
area: data.item.area,
grade: data.item.grade,
location: data.item.location,
period: data.item.period,
website: data.item.website,
description: data.item.description,
},
});
const onSubmit = (formData: FormValues) => {
updateResumeData((draft) => {
if (data?.customSectionId) {
const section = draft.customSections.find((s) => s.id === data.customSectionId);
if (!section) return;
const index = section.items.findIndex((item) => item.id === formData.id);
if (index !== -1) section.items[index] = formData;
} else {
const index = draft.sections.education.items.findIndex((item) => item.id === formData.id);
if (index !== -1) draft.sections.education.items[index] = formData;
}
});
closeDialog();
};
return (
<DialogContent>
<DialogHeader>
<DialogTitle className="flex items-center gap-x-2">
<PencilSimpleLineIcon />
<Trans>Update an existing education</Trans>
</DialogTitle>
<DialogDescription />
</DialogHeader>
<Form {...form}>
<form className="grid gap-4 sm:grid-cols-2" onSubmit={form.handleSubmit(onSubmit)}>
<EducationForm />
<DialogFooter className="sm:col-span-full">
<Button variant="ghost" onClick={closeDialog}>
<Trans>Cancel</Trans>
</Button>
<Button type="submit" disabled={form.formState.isSubmitting}>
<Trans>Save Changes</Trans>
</Button>
</DialogFooter>
</form>
</Form>
</DialogContent>
);
}
function EducationForm() {
const form = useFormContext<FormValues>();
return (
<>
<FormField
control={form.control}
name="school"
render={({ field }) => (
<FormItem>
<FormLabel>
<Trans>School</Trans>
</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="degree"
render={({ field }) => (
<FormItem>
<FormLabel>
<Trans>Degree</Trans>
</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="area"
render={({ field }) => (
<FormItem>
<FormLabel>
<Trans>Area of Study</Trans>
</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="grade"
render={({ field }) => (
<FormItem>
<FormLabel>
<Trans>Grade</Trans>
</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="location"
render={({ field }) => (
<FormItem>
<FormLabel>
<Trans>Location</Trans>
</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="period"
render={({ field }) => (
<FormItem>
<FormLabel>
<Trans>Period</Trans>
</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="website"
render={({ field }) => (
<FormItem className="sm:col-span-full">
<FormLabel>
<Trans>Website</Trans>
</FormLabel>
<FormControl>
<URLInput {...field} value={field.value} onChange={field.onChange} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="description"
render={({ field }) => (
<FormItem className="sm:col-span-full">
<FormLabel>
<Trans>Description</Trans>
</FormLabel>
<FormControl>
<RichInput {...field} value={field.value} onChange={field.onChange} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</>
);
}