mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2026-07-25 17:34:52 +10:00
0bc53b9c2a
- update translations - convert image to base64 before sending to printer - update development docs
228 lines
6.1 KiB
TypeScript
228 lines
6.1 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 { publicationItemSchema } from "@/schema/resume/data";
|
|
import { generateId } from "@/utils/string";
|
|
|
|
const formSchema = publicationItemSchema;
|
|
|
|
type FormValues = z.infer<typeof formSchema>;
|
|
|
|
export function CreatePublicationDialog({ data }: DialogProps<"resume.sections.publications.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,
|
|
title: data?.item?.title ?? "",
|
|
publisher: data?.item?.publisher ?? "",
|
|
date: data?.item?.date ?? "",
|
|
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.publications.items.push(formData);
|
|
}
|
|
});
|
|
closeDialog();
|
|
};
|
|
|
|
return (
|
|
<DialogContent>
|
|
<DialogHeader>
|
|
<DialogTitle className="flex items-center gap-x-2">
|
|
<PlusIcon />
|
|
<Trans>Create a new publication</Trans>
|
|
</DialogTitle>
|
|
<DialogDescription />
|
|
</DialogHeader>
|
|
|
|
<Form {...form}>
|
|
<form className="grid gap-4 sm:grid-cols-2" onSubmit={form.handleSubmit(onSubmit)}>
|
|
<PublicationForm />
|
|
|
|
<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 UpdatePublicationDialog({ data }: DialogProps<"resume.sections.publications.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,
|
|
title: data.item.title,
|
|
publisher: data.item.publisher,
|
|
date: data.item.date,
|
|
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.publications.items.findIndex((item) => item.id === formData.id);
|
|
if (index !== -1) draft.sections.publications.items[index] = formData;
|
|
}
|
|
});
|
|
closeDialog();
|
|
};
|
|
|
|
return (
|
|
<DialogContent>
|
|
<DialogHeader>
|
|
<DialogTitle className="flex items-center gap-x-2">
|
|
<PencilSimpleLineIcon />
|
|
<Trans>Update an existing publication</Trans>
|
|
</DialogTitle>
|
|
<DialogDescription />
|
|
</DialogHeader>
|
|
|
|
<Form {...form}>
|
|
<form className="grid gap-4 sm:grid-cols-2" onSubmit={form.handleSubmit(onSubmit)}>
|
|
<PublicationForm />
|
|
|
|
<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 PublicationForm() {
|
|
const form = useFormContext<FormValues>();
|
|
|
|
return (
|
|
<>
|
|
<FormField
|
|
control={form.control}
|
|
name="title"
|
|
render={({ field }) => (
|
|
<FormItem>
|
|
<FormLabel>
|
|
<Trans>Title</Trans>
|
|
</FormLabel>
|
|
<FormControl>
|
|
<Input {...field} />
|
|
</FormControl>
|
|
<FormMessage />
|
|
</FormItem>
|
|
)}
|
|
/>
|
|
|
|
<FormField
|
|
control={form.control}
|
|
name="publisher"
|
|
render={({ field }) => (
|
|
<FormItem>
|
|
<FormLabel>
|
|
<Trans>Publisher</Trans>
|
|
</FormLabel>
|
|
<FormControl>
|
|
<Input {...field} />
|
|
</FormControl>
|
|
<FormMessage />
|
|
</FormItem>
|
|
)}
|
|
/>
|
|
|
|
<FormField
|
|
control={form.control}
|
|
name="date"
|
|
render={({ field }) => (
|
|
<FormItem>
|
|
<FormLabel>
|
|
<Trans>Date</Trans>
|
|
</FormLabel>
|
|
<FormControl>
|
|
<Input {...field} />
|
|
</FormControl>
|
|
<FormMessage />
|
|
</FormItem>
|
|
)}
|
|
/>
|
|
|
|
<FormField
|
|
control={form.control}
|
|
name="website"
|
|
render={({ field }) => (
|
|
<FormItem>
|
|
<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>
|
|
)}
|
|
/>
|
|
</>
|
|
);
|
|
}
|