- Use browserless over gotenberg

- Implement functionality to move items between sections or pages
- Enhance custom sections to have a `type` property
- Update the v4 importer to account for custom sections
- Update healthcheck to be a simple curl command
- Update dependencies to latest
and a lot more changes
This commit is contained in:
Amruth Pillai
2026-01-21 18:49:54 +01:00
parent b3c342b029
commit 70064be7de
54 changed files with 2153 additions and 822 deletions
+30 -19
View File
@@ -33,18 +33,23 @@ export function CreateAwardDialog({ data }: DialogProps<"resume.sections.awards.
resolver: zodResolver(formSchema),
defaultValues: {
id: generateId(),
hidden: data?.hidden ?? false,
title: data?.title ?? "",
awarder: data?.awarder ?? "",
date: data?.date ?? "",
website: data?.website ?? { url: "", label: "" },
description: data?.description ?? "",
hidden: data?.item?.hidden ?? false,
title: data?.item?.title ?? "",
awarder: data?.item?.awarder ?? "",
date: data?.item?.date ?? "",
website: data?.item?.website ?? { url: "", label: "" },
description: data?.item?.description ?? "",
},
});
const onSubmit = (data: FormValues) => {
const onSubmit = (formData: FormValues) => {
updateResumeData((draft) => {
draft.sections.awards.items.push(data);
if (data?.customSectionId) {
const section = draft.customSections.find((s) => s.id === data.customSectionId);
if (section) section.items.push(formData);
} else {
draft.sections.awards.items.push(formData);
}
});
closeDialog();
};
@@ -85,21 +90,27 @@ export function UpdateAwardDialog({ data }: DialogProps<"resume.sections.awards.
const form = useForm<FormValues>({
resolver: zodResolver(formSchema),
defaultValues: {
id: data.id,
hidden: data.hidden,
title: data.title,
awarder: data.awarder,
date: data.date,
website: data.website,
description: data.description,
id: data.item.id,
hidden: data.item.hidden,
title: data.item.title,
awarder: data.item.awarder,
date: data.item.date,
website: data.item.website,
description: data.item.description,
},
});
const onSubmit = (data: FormValues) => {
const onSubmit = (formData: FormValues) => {
updateResumeData((draft) => {
const index = draft.sections.awards.items.findIndex((item) => item.id === data.id);
if (index === -1) return;
draft.sections.awards.items[index] = data;
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.awards.items.findIndex((item) => item.id === formData.id);
if (index !== -1) draft.sections.awards.items[index] = formData;
}
});
closeDialog();
};
+30 -19
View File
@@ -33,18 +33,23 @@ export function CreateCertificationDialog({ data }: DialogProps<"resume.sections
resolver: zodResolver(formSchema),
defaultValues: {
id: generateId(),
hidden: data?.hidden ?? false,
title: data?.title ?? "",
issuer: data?.issuer ?? "",
date: data?.date ?? "",
website: data?.website ?? { url: "", label: "" },
description: data?.description ?? "",
hidden: data?.item?.hidden ?? false,
title: data?.item?.title ?? "",
issuer: data?.item?.issuer ?? "",
date: data?.item?.date ?? "",
website: data?.item?.website ?? { url: "", label: "" },
description: data?.item?.description ?? "",
},
});
const onSubmit = (values: FormValues) => {
const onSubmit = (formData: FormValues) => {
updateResumeData((draft) => {
draft.sections.certifications.items.push(values);
if (data?.customSectionId) {
const section = draft.customSections.find((s) => s.id === data.customSectionId);
if (section) section.items.push(formData);
} else {
draft.sections.certifications.items.push(formData);
}
});
closeDialog();
};
@@ -85,21 +90,27 @@ export function UpdateCertificationDialog({ data }: DialogProps<"resume.sections
const form = useForm<FormValues>({
resolver: zodResolver(formSchema),
defaultValues: {
id: data.id,
hidden: data.hidden,
title: data.title,
issuer: data.issuer,
date: data.date,
website: data.website,
description: data.description,
id: data.item.id,
hidden: data.item.hidden,
title: data.item.title,
issuer: data.item.issuer,
date: data.item.date,
website: data.item.website,
description: data.item.description,
},
});
const onSubmit = (values: FormValues) => {
const onSubmit = (formData: FormValues) => {
updateResumeData((draft) => {
const index = draft.sections.certifications.items.findIndex((item) => item.id === values.id);
if (index === -1) return;
draft.sections.certifications.items[index] = values;
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.certifications.items.findIndex((item) => item.id === formData.id);
if (index !== -1) draft.sections.certifications.items[index] = formData;
}
});
closeDialog();
};
+41 -15
View File
@@ -11,19 +11,33 @@ import {
DialogHeader,
DialogTitle,
} from "@/components/animate-ui/components/radix/dialog";
import { RichInput } from "@/components/input/rich-input";
import { useResumeStore } from "@/components/resume/store/resume";
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 { customSectionSchema } from "@/schema/resume/data";
import { customSectionSchema, type SectionType } from "@/schema/resume/data";
import { generateId } from "@/utils/string";
const formSchema = customSectionSchema;
type FormValues = z.infer<typeof formSchema>;
const SECTION_TYPE_OPTIONS: { value: SectionType; label: string }[] = [
{ value: "experience", label: "Experience" },
{ value: "education", label: "Education" },
{ value: "projects", label: "Projects" },
{ value: "profiles", label: "Profiles" },
{ value: "skills", label: "Skills" },
{ value: "languages", label: "Languages" },
{ value: "interests", label: "Interests" },
{ value: "awards", label: "Awards" },
{ value: "certifications", label: "Certifications" },
{ value: "publications", label: "Publications" },
{ value: "volunteer", label: "Volunteer" },
{ value: "references", label: "References" },
];
export function CreateCustomSectionDialog({ data }: DialogProps<"resume.sections.custom.create">) {
const closeDialog = useDialogStore((state) => state.closeDialog);
const updateResumeData = useResumeStore((state) => state.updateResumeData);
@@ -33,19 +47,20 @@ export function CreateCustomSectionDialog({ data }: DialogProps<"resume.sections
defaultValues: {
id: generateId(),
title: data?.title ?? "",
type: data?.type ?? "experience",
columns: data?.columns ?? 1,
hidden: data?.hidden ?? false,
content: data?.content ?? "",
items: data?.items ?? [],
},
});
const onSubmit = (data: FormValues) => {
const onSubmit = (formData: FormValues) => {
updateResumeData((draft) => {
draft.customSections.push(data);
draft.customSections.push(formData);
const lastPageIndex = draft.metadata.layout.pages.length - 1;
if (lastPageIndex < 0) return;
draft.metadata.layout.pages[lastPageIndex].main.push(data.id);
draft.metadata.layout.pages[lastPageIndex].main.push(formData.id);
});
closeDialog();
};
@@ -88,17 +103,18 @@ export function UpdateCustomSectionDialog({ data }: DialogProps<"resume.sections
defaultValues: {
id: data.id,
title: data.title,
type: data.type,
columns: data.columns,
hidden: data.hidden,
content: data.content,
items: data.items,
},
});
const onSubmit = (data: FormValues) => {
const onSubmit = (formData: FormValues) => {
updateResumeData((draft) => {
const index = draft.customSections.findIndex((item) => item.id === data.id);
const index = draft.customSections.findIndex((item) => item.id === formData.id);
if (index === -1) return;
draft.customSections[index] = data;
draft.customSections[index] = formData;
});
closeDialog();
};
@@ -115,7 +131,7 @@ export function UpdateCustomSectionDialog({ data }: DialogProps<"resume.sections
<Form {...form}>
<form className="grid gap-4 sm:grid-cols-2" onSubmit={form.handleSubmit(onSubmit)}>
<CustomSectionForm />
<CustomSectionForm isUpdate />
<DialogFooter className="sm:col-span-full">
<Button variant="ghost" onClick={closeDialog}>
@@ -132,7 +148,7 @@ export function UpdateCustomSectionDialog({ data }: DialogProps<"resume.sections
);
}
function CustomSectionForm() {
function CustomSectionForm({ isUpdate = false }: { isUpdate?: boolean }) {
const form = useFormContext<FormValues>();
return (
@@ -155,14 +171,24 @@ function CustomSectionForm() {
<FormField
control={form.control}
name="content"
name="type"
render={({ field }) => (
<FormItem className="sm:col-span-full">
<FormLabel>
<Trans>Content</Trans>
<Trans>Section Type</Trans>
</FormLabel>
<FormControl>
<RichInput {...field} value={field.value} onChange={field.onChange} />
<select
{...field}
disabled={isUpdate}
className="flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-xs transition-colors file:border-0 file:bg-transparent file:font-medium file:text-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50"
>
{SECTION_TYPE_OPTIONS.map((option) => (
<option key={option.value} value={option.value}>
{option.label}
</option>
))}
</select>
</FormControl>
<FormMessage />
</FormItem>
+36 -25
View File
@@ -33,21 +33,26 @@ export function CreateEducationDialog({ data }: DialogProps<"resume.sections.edu
resolver: zodResolver(formSchema),
defaultValues: {
id: generateId(),
hidden: data?.hidden ?? false,
school: data?.school ?? "",
degree: data?.degree ?? "",
area: data?.area ?? "",
grade: data?.grade ?? "",
location: data?.location ?? "",
period: data?.period ?? "",
website: data?.website ?? { url: "", label: "" },
description: data?.description ?? "",
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 = (data: FormValues) => {
const onSubmit = (formData: FormValues) => {
updateResumeData((draft) => {
draft.sections.education.items.push(data);
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();
};
@@ -88,24 +93,30 @@ export function UpdateEducationDialog({ data }: DialogProps<"resume.sections.edu
const form = useForm<FormValues>({
resolver: zodResolver(formSchema),
defaultValues: {
id: data.id,
hidden: data.hidden,
school: data.school,
degree: data.degree,
area: data.area,
grade: data.grade,
location: data.location,
period: data.period,
website: data.website,
description: data.description,
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 = (data: FormValues) => {
const onSubmit = (formData: FormValues) => {
updateResumeData((draft) => {
const index = draft.sections.education.items.findIndex((item) => item.id === data.id);
if (index === -1) return;
draft.sections.education.items[index] = data;
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();
};
+32 -21
View File
@@ -33,19 +33,24 @@ export function CreateExperienceDialog({ data }: DialogProps<"resume.sections.ex
resolver: zodResolver(formSchema),
defaultValues: {
id: generateId(),
hidden: data?.hidden ?? false,
company: data?.company ?? "",
position: data?.position ?? "",
location: data?.location ?? "",
period: data?.period ?? "",
website: data?.website ?? { url: "", label: "" },
description: data?.description ?? "",
hidden: data?.item?.hidden ?? false,
company: data?.item?.company ?? "",
position: data?.item?.position ?? "",
location: data?.item?.location ?? "",
period: data?.item?.period ?? "",
website: data?.item?.website ?? { url: "", label: "" },
description: data?.item?.description ?? "",
},
});
const onSubmit = (data: FormValues) => {
const onSubmit = (formData: FormValues) => {
updateResumeData((draft) => {
draft.sections.experience.items.push(data);
if (data?.customSectionId) {
const section = draft.customSections.find((s) => s.id === data.customSectionId);
if (section) section.items.push(formData);
} else {
draft.sections.experience.items.push(formData);
}
});
closeDialog();
};
@@ -86,22 +91,28 @@ export function UpdateExperienceDialog({ data }: DialogProps<"resume.sections.ex
const form = useForm<FormValues>({
resolver: zodResolver(formSchema),
defaultValues: {
id: data.id,
hidden: data.hidden,
company: data.company,
position: data.position,
location: data.location,
period: data.period,
website: data.website,
description: data.description,
id: data.item.id,
hidden: data.item.hidden,
company: data.item.company,
position: data.item.position,
location: data.item.location,
period: data.item.period,
website: data.item.website,
description: data.item.description,
},
});
const onSubmit = (data: FormValues) => {
const onSubmit = (formData: FormValues) => {
updateResumeData((draft) => {
const index = draft.sections.experience.items.findIndex((item) => item.id === data.id);
if (index === -1) return;
draft.sections.experience.items[index] = data;
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.experience.items.findIndex((item) => item.id === formData.id);
if (index !== -1) draft.sections.experience.items[index] = formData;
}
});
closeDialog();
};
+26 -15
View File
@@ -35,16 +35,21 @@ export function CreateInterestDialog({ data }: DialogProps<"resume.sections.inte
resolver: zodResolver(formSchema),
defaultValues: {
id: generateId(),
hidden: data?.hidden ?? false,
icon: data?.icon ?? "acorn",
name: data?.name ?? "",
keywords: data?.keywords ?? [],
hidden: data?.item?.hidden ?? false,
icon: data?.item?.icon ?? "acorn",
name: data?.item?.name ?? "",
keywords: data?.item?.keywords ?? [],
},
});
const onSubmit = (values: FormValues) => {
const onSubmit = (formData: FormValues) => {
updateResumeData((draft) => {
draft.sections.interests.items.push(values);
if (data?.customSectionId) {
const section = draft.customSections.find((s) => s.id === data.customSectionId);
if (section) section.items.push(formData);
} else {
draft.sections.interests.items.push(formData);
}
});
closeDialog();
};
@@ -85,19 +90,25 @@ export function UpdateInterestDialog({ data }: DialogProps<"resume.sections.inte
const form = useForm<FormValues>({
resolver: zodResolver(formSchema),
defaultValues: {
id: data.id,
hidden: data.hidden,
icon: data.icon,
name: data.name,
keywords: data.keywords,
id: data.item.id,
hidden: data.item.hidden,
icon: data.item.icon,
name: data.item.name,
keywords: data.item.keywords,
},
});
const onSubmit = (values: FormValues) => {
const onSubmit = (formData: FormValues) => {
updateResumeData((draft) => {
const index = draft.sections.interests.items.findIndex((item) => item.id === values.id);
if (index === -1) return;
draft.sections.interests.items[index] = values;
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.interests.items.findIndex((item) => item.id === formData.id);
if (index !== -1) draft.sections.interests.items[index] = formData;
}
});
closeDialog();
};
+26 -15
View File
@@ -33,16 +33,21 @@ export function CreateLanguageDialog({ data }: DialogProps<"resume.sections.lang
resolver: zodResolver(formSchema),
defaultValues: {
id: generateId(),
hidden: data?.hidden ?? false,
language: data?.language ?? "",
fluency: data?.fluency ?? "",
level: data?.level ?? 0,
hidden: data?.item?.hidden ?? false,
language: data?.item?.language ?? "",
fluency: data?.item?.fluency ?? "",
level: data?.item?.level ?? 0,
},
});
const onSubmit = (data: FormValues) => {
const onSubmit = (formData: FormValues) => {
updateResumeData((draft) => {
draft.sections.languages.items.push(data);
if (data?.customSectionId) {
const section = draft.customSections.find((s) => s.id === data.customSectionId);
if (section) section.items.push(formData);
} else {
draft.sections.languages.items.push(formData);
}
});
closeDialog();
};
@@ -83,19 +88,25 @@ export function UpdateLanguageDialog({ data }: DialogProps<"resume.sections.lang
const form = useForm<FormValues>({
resolver: zodResolver(formSchema),
defaultValues: {
id: data.id,
hidden: data.hidden,
language: data.language,
fluency: data.fluency,
level: data.level,
id: data.item.id,
hidden: data.item.hidden,
language: data.item.language,
fluency: data.item.fluency,
level: data.item.level,
},
});
const onSubmit = (data: FormValues) => {
const onSubmit = (formData: FormValues) => {
updateResumeData((draft) => {
const index = draft.sections.languages.items.findIndex((item) => item.id === data.id);
if (index === -1) return;
draft.sections.languages.items[index] = data;
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.languages.items.findIndex((item) => item.id === formData.id);
if (index !== -1) draft.sections.languages.items[index] = formData;
}
});
closeDialog();
};
+28 -17
View File
@@ -35,17 +35,22 @@ export function CreateProfileDialog({ data }: DialogProps<"resume.sections.profi
resolver: zodResolver(formSchema),
defaultValues: {
id: generateId(),
hidden: data?.hidden ?? false,
icon: data?.icon ?? "acorn",
network: data?.network ?? "",
username: data?.username ?? "",
website: data?.website ?? { url: "", label: "" },
hidden: data?.item?.hidden ?? false,
icon: data?.item?.icon ?? "acorn",
network: data?.item?.network ?? "",
username: data?.item?.username ?? "",
website: data?.item?.website ?? { url: "", label: "" },
},
});
const onSubmit = (data: FormValues) => {
const onSubmit = (formData: FormValues) => {
updateResumeData((draft) => {
draft.sections.profiles.items.push(data);
if (data?.customSectionId) {
const section = draft.customSections.find((s) => s.id === data.customSectionId);
if (section) section.items.push(formData);
} else {
draft.sections.profiles.items.push(formData);
}
});
closeDialog();
};
@@ -86,20 +91,26 @@ export function UpdateProfileDialog({ data }: DialogProps<"resume.sections.profi
const form = useForm<FormValues>({
resolver: zodResolver(formSchema),
defaultValues: {
id: data.id,
hidden: data.hidden,
icon: data.icon,
network: data.network,
username: data.username,
website: data.website,
id: data.item.id,
hidden: data.item.hidden,
icon: data.item.icon,
network: data.item.network,
username: data.item.username,
website: data.item.website,
},
});
const onSubmit = (data: FormValues) => {
const onSubmit = (formData: FormValues) => {
updateResumeData((draft) => {
const index = draft.sections.profiles.items.findIndex((item) => item.id === data.id);
if (index === -1) return;
draft.sections.profiles.items[index] = data;
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.profiles.items.findIndex((item) => item.id === formData.id);
if (index !== -1) draft.sections.profiles.items[index] = formData;
}
});
closeDialog();
};
+28 -17
View File
@@ -33,17 +33,22 @@ export function CreateProjectDialog({ data }: DialogProps<"resume.sections.proje
resolver: zodResolver(formSchema),
defaultValues: {
id: generateId(),
hidden: data?.hidden ?? false,
name: data?.name ?? "",
period: data?.period ?? "",
website: data?.website ?? { url: "", label: "" },
description: data?.description ?? "",
hidden: data?.item?.hidden ?? false,
name: data?.item?.name ?? "",
period: data?.item?.period ?? "",
website: data?.item?.website ?? { url: "", label: "" },
description: data?.item?.description ?? "",
},
});
const onSubmit = (values: FormValues) => {
const onSubmit = (formData: FormValues) => {
updateResumeData((draft) => {
draft.sections.projects.items.push(values);
if (data?.customSectionId) {
const section = draft.customSections.find((s) => s.id === data.customSectionId);
if (section) section.items.push(formData);
} else {
draft.sections.projects.items.push(formData);
}
});
closeDialog();
};
@@ -84,20 +89,26 @@ export function UpdateProjectDialog({ data }: DialogProps<"resume.sections.proje
const form = useForm<FormValues>({
resolver: zodResolver(formSchema),
defaultValues: {
id: data.id,
hidden: data.hidden,
name: data.name,
period: data.period,
website: data.website,
description: data.description,
id: data.item.id,
hidden: data.item.hidden,
name: data.item.name,
period: data.item.period,
website: data.item.website,
description: data.item.description,
},
});
const onSubmit = (values: FormValues) => {
const onSubmit = (formData: FormValues) => {
updateResumeData((draft) => {
const index = draft.sections.projects.items.findIndex((item) => item.id === values.id);
if (index === -1) return;
draft.sections.projects.items[index] = values;
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.projects.items.findIndex((item) => item.id === formData.id);
if (index !== -1) draft.sections.projects.items[index] = formData;
}
});
closeDialog();
};
+30 -19
View File
@@ -33,18 +33,23 @@ export function CreatePublicationDialog({ data }: DialogProps<"resume.sections.p
resolver: zodResolver(formSchema),
defaultValues: {
id: generateId(),
hidden: data?.hidden ?? false,
title: data?.title ?? "",
publisher: data?.publisher ?? "",
date: data?.date ?? "",
website: data?.website ?? { url: "", label: "" },
description: data?.description ?? "",
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 = (values: FormValues) => {
const onSubmit = (formData: FormValues) => {
updateResumeData((draft) => {
draft.sections.publications.items.push(values);
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();
};
@@ -85,21 +90,27 @@ export function UpdatePublicationDialog({ data }: DialogProps<"resume.sections.p
const form = useForm<FormValues>({
resolver: zodResolver(formSchema),
defaultValues: {
id: data.id,
hidden: data.hidden,
title: data.title,
publisher: data.publisher,
date: data.date,
website: data.website,
description: data.description,
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 = (values: FormValues) => {
const onSubmit = (formData: FormValues) => {
updateResumeData((draft) => {
const index = draft.sections.publications.items.findIndex((item) => item.id === values.id);
if (index === -1) return;
draft.sections.publications.items[index] = values;
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();
};
+24 -13
View File
@@ -32,15 +32,20 @@ export function CreateReferenceDialog({ data }: DialogProps<"resume.sections.ref
resolver: zodResolver(formSchema),
defaultValues: {
id: generateId(),
hidden: data?.hidden ?? false,
name: data?.name ?? "",
description: data?.description ?? "",
hidden: data?.item?.hidden ?? false,
name: data?.item?.name ?? "",
description: data?.item?.description ?? "",
},
});
const onSubmit = (values: FormValues) => {
const onSubmit = (formData: FormValues) => {
updateResumeData((draft) => {
draft.sections.references.items.push(values);
if (data?.customSectionId) {
const section = draft.customSections.find((s) => s.id === data.customSectionId);
if (section) section.items.push(formData);
} else {
draft.sections.references.items.push(formData);
}
});
closeDialog();
};
@@ -81,18 +86,24 @@ export function UpdateReferenceDialog({ data }: DialogProps<"resume.sections.ref
const form = useForm<FormValues>({
resolver: zodResolver(formSchema),
defaultValues: {
id: data.id,
hidden: data.hidden,
name: data.name,
description: data.description,
id: data.item.id,
hidden: data.item.hidden,
name: data.item.name,
description: data.item.description,
},
});
const onSubmit = (values: FormValues) => {
const onSubmit = (formData: FormValues) => {
updateResumeData((draft) => {
const index = draft.sections.references.items.findIndex((item) => item.id === values.id);
if (index === -1) return;
draft.sections.references.items[index] = values;
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.references.items.findIndex((item) => item.id === formData.id);
if (index !== -1) draft.sections.references.items[index] = formData;
}
});
closeDialog();
};
+30 -19
View File
@@ -37,18 +37,23 @@ export function CreateSkillDialog({ data }: DialogProps<"resume.sections.skills.
resolver: zodResolver(formSchema),
defaultValues: {
id: generateId(),
hidden: data?.hidden ?? false,
icon: data?.icon ?? "acorn",
name: data?.name ?? "",
proficiency: data?.proficiency ?? "",
level: data?.level ?? 0,
keywords: data?.keywords ?? [],
hidden: data?.item?.hidden ?? false,
icon: data?.item?.icon ?? "acorn",
name: data?.item?.name ?? "",
proficiency: data?.item?.proficiency ?? "",
level: data?.item?.level ?? 0,
keywords: data?.item?.keywords ?? [],
},
});
const onSubmit = (data: FormValues) => {
const onSubmit = (formData: FormValues) => {
updateResumeData((draft) => {
draft.sections.skills.items.push(data);
if (data?.customSectionId) {
const section = draft.customSections.find((s) => s.id === data.customSectionId);
if (section) section.items.push(formData);
} else {
draft.sections.skills.items.push(formData);
}
});
closeDialog();
};
@@ -89,21 +94,27 @@ export function UpdateSkillDialog({ data }: DialogProps<"resume.sections.skills.
const form = useForm<FormValues>({
resolver: zodResolver(formSchema),
defaultValues: {
id: data.id,
hidden: data.hidden,
icon: data.icon,
name: data.name,
proficiency: data.proficiency,
level: data.level,
keywords: data.keywords,
id: data.item.id,
hidden: data.item.hidden,
icon: data.item.icon,
name: data.item.name,
proficiency: data.item.proficiency,
level: data.item.level,
keywords: data.item.keywords,
},
});
const onSubmit = (data: FormValues) => {
const onSubmit = (formData: FormValues) => {
updateResumeData((draft) => {
const index = draft.sections.skills.items.findIndex((item) => item.id === data.id);
if (index === -1) return;
draft.sections.skills.items[index] = data;
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.skills.items.findIndex((item) => item.id === formData.id);
if (index !== -1) draft.sections.skills.items[index] = formData;
}
});
closeDialog();
};
+30 -19
View File
@@ -33,18 +33,23 @@ export function CreateVolunteerDialog({ data }: DialogProps<"resume.sections.vol
resolver: zodResolver(formSchema),
defaultValues: {
id: generateId(),
hidden: data?.hidden ?? false,
organization: data?.organization ?? "",
location: data?.location ?? "",
period: data?.period ?? "",
website: data?.website ?? { url: "", label: "" },
description: data?.description ?? "",
hidden: data?.item?.hidden ?? false,
organization: data?.item?.organization ?? "",
location: data?.item?.location ?? "",
period: data?.item?.period ?? "",
website: data?.item?.website ?? { url: "", label: "" },
description: data?.item?.description ?? "",
},
});
const onSubmit = (values: FormValues) => {
const onSubmit = (formData: FormValues) => {
updateResumeData((draft) => {
draft.sections.volunteer.items.push(values);
if (data?.customSectionId) {
const section = draft.customSections.find((s) => s.id === data.customSectionId);
if (section) section.items.push(formData);
} else {
draft.sections.volunteer.items.push(formData);
}
});
closeDialog();
};
@@ -85,21 +90,27 @@ export function UpdateVolunteerDialog({ data }: DialogProps<"resume.sections.vol
const form = useForm<FormValues>({
resolver: zodResolver(formSchema),
defaultValues: {
id: data.id,
hidden: data.hidden,
organization: data.organization,
location: data.location,
period: data.period,
website: data.website,
description: data.description,
id: data.item.id,
hidden: data.item.hidden,
organization: data.item.organization,
location: data.item.location,
period: data.item.period,
website: data.item.website,
description: data.item.description,
},
});
const onSubmit = (values: FormValues) => {
const onSubmit = (formData: FormValues) => {
updateResumeData((draft) => {
const index = draft.sections.volunteer.items.findIndex((item) => item.id === values.id);
if (index === -1) return;
draft.sections.volunteer.items[index] = values;
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.volunteer.items.findIndex((item) => item.id === formData.id);
if (index !== -1) draft.sections.volunteer.items[index] = formData;
}
});
closeDialog();
};
+96 -24
View File
@@ -38,30 +38,102 @@ const dialogTypeSchema = z.discriminatedUnion("type", [
}),
}),
z.object({ type: z.literal("resume.template.gallery"), data: z.undefined() }),
z.object({ type: z.literal("resume.sections.profiles.create"), data: profileItemSchema.optional() }),
z.object({ type: z.literal("resume.sections.profiles.update"), data: profileItemSchema }),
z.object({ type: z.literal("resume.sections.experience.create"), data: experienceItemSchema.optional() }),
z.object({ type: z.literal("resume.sections.experience.update"), data: experienceItemSchema }),
z.object({ type: z.literal("resume.sections.education.create"), data: educationItemSchema.optional() }),
z.object({ type: z.literal("resume.sections.education.update"), data: educationItemSchema }),
z.object({ type: z.literal("resume.sections.projects.create"), data: projectItemSchema.optional() }),
z.object({ type: z.literal("resume.sections.projects.update"), data: projectItemSchema }),
z.object({ type: z.literal("resume.sections.skills.create"), data: skillItemSchema.optional() }),
z.object({ type: z.literal("resume.sections.skills.update"), data: skillItemSchema }),
z.object({ type: z.literal("resume.sections.languages.create"), data: languageItemSchema.optional() }),
z.object({ type: z.literal("resume.sections.languages.update"), data: languageItemSchema }),
z.object({ type: z.literal("resume.sections.awards.create"), data: awardItemSchema.optional() }),
z.object({ type: z.literal("resume.sections.awards.update"), data: awardItemSchema }),
z.object({ type: z.literal("resume.sections.certifications.create"), data: certificationItemSchema.optional() }),
z.object({ type: z.literal("resume.sections.certifications.update"), data: certificationItemSchema }),
z.object({ type: z.literal("resume.sections.publications.create"), data: publicationItemSchema.optional() }),
z.object({ type: z.literal("resume.sections.publications.update"), data: publicationItemSchema }),
z.object({ type: z.literal("resume.sections.interests.create"), data: interestItemSchema.optional() }),
z.object({ type: z.literal("resume.sections.interests.update"), data: interestItemSchema }),
z.object({ type: z.literal("resume.sections.volunteer.create"), data: volunteerItemSchema.optional() }),
z.object({ type: z.literal("resume.sections.volunteer.update"), data: volunteerItemSchema }),
z.object({ type: z.literal("resume.sections.references.create"), data: referenceItemSchema.optional() }),
z.object({ type: z.literal("resume.sections.references.update"), data: referenceItemSchema }),
z.object({
type: z.literal("resume.sections.profiles.create"),
data: z.object({ item: profileItemSchema.optional(), customSectionId: z.string().optional() }).optional(),
}),
z.object({
type: z.literal("resume.sections.profiles.update"),
data: z.object({ item: profileItemSchema, customSectionId: z.string().optional() }),
}),
z.object({
type: z.literal("resume.sections.experience.create"),
data: z.object({ item: experienceItemSchema.optional(), customSectionId: z.string().optional() }).optional(),
}),
z.object({
type: z.literal("resume.sections.experience.update"),
data: z.object({ item: experienceItemSchema, customSectionId: z.string().optional() }),
}),
z.object({
type: z.literal("resume.sections.education.create"),
data: z.object({ item: educationItemSchema.optional(), customSectionId: z.string().optional() }).optional(),
}),
z.object({
type: z.literal("resume.sections.education.update"),
data: z.object({ item: educationItemSchema, customSectionId: z.string().optional() }),
}),
z.object({
type: z.literal("resume.sections.projects.create"),
data: z.object({ item: projectItemSchema.optional(), customSectionId: z.string().optional() }).optional(),
}),
z.object({
type: z.literal("resume.sections.projects.update"),
data: z.object({ item: projectItemSchema, customSectionId: z.string().optional() }),
}),
z.object({
type: z.literal("resume.sections.skills.create"),
data: z.object({ item: skillItemSchema.optional(), customSectionId: z.string().optional() }).optional(),
}),
z.object({
type: z.literal("resume.sections.skills.update"),
data: z.object({ item: skillItemSchema, customSectionId: z.string().optional() }),
}),
z.object({
type: z.literal("resume.sections.languages.create"),
data: z.object({ item: languageItemSchema.optional(), customSectionId: z.string().optional() }).optional(),
}),
z.object({
type: z.literal("resume.sections.languages.update"),
data: z.object({ item: languageItemSchema, customSectionId: z.string().optional() }),
}),
z.object({
type: z.literal("resume.sections.awards.create"),
data: z.object({ item: awardItemSchema.optional(), customSectionId: z.string().optional() }).optional(),
}),
z.object({
type: z.literal("resume.sections.awards.update"),
data: z.object({ item: awardItemSchema, customSectionId: z.string().optional() }),
}),
z.object({
type: z.literal("resume.sections.certifications.create"),
data: z.object({ item: certificationItemSchema.optional(), customSectionId: z.string().optional() }).optional(),
}),
z.object({
type: z.literal("resume.sections.certifications.update"),
data: z.object({ item: certificationItemSchema, customSectionId: z.string().optional() }),
}),
z.object({
type: z.literal("resume.sections.publications.create"),
data: z.object({ item: publicationItemSchema.optional(), customSectionId: z.string().optional() }).optional(),
}),
z.object({
type: z.literal("resume.sections.publications.update"),
data: z.object({ item: publicationItemSchema, customSectionId: z.string().optional() }),
}),
z.object({
type: z.literal("resume.sections.interests.create"),
data: z.object({ item: interestItemSchema.optional(), customSectionId: z.string().optional() }).optional(),
}),
z.object({
type: z.literal("resume.sections.interests.update"),
data: z.object({ item: interestItemSchema, customSectionId: z.string().optional() }),
}),
z.object({
type: z.literal("resume.sections.volunteer.create"),
data: z.object({ item: volunteerItemSchema.optional(), customSectionId: z.string().optional() }).optional(),
}),
z.object({
type: z.literal("resume.sections.volunteer.update"),
data: z.object({ item: volunteerItemSchema, customSectionId: z.string().optional() }),
}),
z.object({
type: z.literal("resume.sections.references.create"),
data: z.object({ item: referenceItemSchema.optional(), customSectionId: z.string().optional() }).optional(),
}),
z.object({
type: z.literal("resume.sections.references.update"),
data: z.object({ item: referenceItemSchema, customSectionId: z.string().optional() }),
}),
z.object({ type: z.literal("resume.sections.custom.create"), data: customSectionSchema.optional() }),
z.object({ type: z.literal("resume.sections.custom.update"), data: customSectionSchema }),
]);