fix: address code review issues from Task 4 (onSubmit, AiDraftBanner, STEP_FIELDS)
This commit is contained in:
@@ -36,6 +36,12 @@ import {
|
||||
} from "@/lib/event-form";
|
||||
import { parseRecurrenceRule, validateRecurrence } from "@/lib/recurrence";
|
||||
|
||||
const STEP_FIELDS: Record<1 | 2 | 3, (keyof EventFormValues)[]> = {
|
||||
1: ["title", "url"],
|
||||
2: ["start", "end"],
|
||||
3: ["recurrenceRule"],
|
||||
};
|
||||
|
||||
interface EventDialogProps {
|
||||
open: boolean;
|
||||
onOpenChange: (open: boolean) => void;
|
||||
@@ -96,12 +102,6 @@ export const EventDialog = ({
|
||||
onOpenChange(nextOpen);
|
||||
};
|
||||
|
||||
const STEP_FIELDS: Record<1 | 2 | 3, (keyof EventFormValues)[]> = {
|
||||
1: ["title", "url"],
|
||||
2: ["start", "end"],
|
||||
3: ["recurrenceRule"],
|
||||
};
|
||||
|
||||
const handleNext = async () => {
|
||||
const valid = await trigger(STEP_FIELDS[step]);
|
||||
if (valid) advanceStep();
|
||||
@@ -148,41 +148,42 @@ export const EventDialog = ({
|
||||
reset(getDefaultEventFormValues());
|
||||
});
|
||||
|
||||
const onSubmit = handleSubmit((values) => {
|
||||
const result = validateEventFormValues(values);
|
||||
if (!result.success) {
|
||||
const fieldErrors = result.error.flatten().fieldErrors;
|
||||
for (const [fieldName, messages] of Object.entries(fieldErrors)) {
|
||||
const firstMessage = messages?.[0];
|
||||
if (firstMessage) {
|
||||
setError(fieldName as keyof EventFormValues, {
|
||||
message: firstMessage,
|
||||
});
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (values.recurrenceRule) {
|
||||
const recurrenceValidation = validateRecurrence(parseRecurrenceRule(values.recurrenceRule));
|
||||
if (!recurrenceValidation.isValid) {
|
||||
setError("recurrenceRule", {
|
||||
message:
|
||||
recurrenceValidation.errors.rule ||
|
||||
recurrenceValidation.errors.count ||
|
||||
recurrenceValidation.errors.until ||
|
||||
"Invalid recurrence.",
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
onSave(result.data);
|
||||
reset(getDefaultEventFormValues());
|
||||
});
|
||||
|
||||
const stepProps = { control, register, errors, watch, setValue, isAiDraft };
|
||||
|
||||
if (!isMobile) {
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={handleOpenChange}>
|
||||
<DialogContent className="max-w-2xl rounded-[10px] bg-card p-0 shadow-xl">
|
||||
<DialogHeader className="px-6 py-5 shadow-[inset_0_-1px_0_0_var(--color-border)]">
|
||||
<DialogTitle className="text-[28px] tracking-[-0.06em]">{titleText}</DialogTitle>
|
||||
<DialogDescription>{descriptionText}</DialogDescription>
|
||||
</DialogHeader>
|
||||
<form className="grid gap-6 px-6 py-5" onSubmit={handleSave}>
|
||||
{isAiDraft && <AiDraftBanner />}
|
||||
<section className="grid gap-3">
|
||||
<p className="font-mono text-[11px] uppercase text-muted-foreground">Event details</p>
|
||||
<DetailsStep {...stepProps} isAiDraft={false} />
|
||||
</section>
|
||||
<section className="grid gap-3">
|
||||
<p className="font-mono text-[11px] uppercase text-muted-foreground">Schedule</p>
|
||||
<ScheduleStep {...stepProps} isAiDraft={false} />
|
||||
</section>
|
||||
<section className="grid gap-3">
|
||||
<p className="font-mono text-[11px] uppercase text-muted-foreground">Recurrence</p>
|
||||
<RecurrenceStep {...stepProps} isAiDraft={false} />
|
||||
</section>
|
||||
<DialogFooter>
|
||||
<Button type="button" variant="ghost" onClick={() => handleOpenChange(false)}>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button type="submit">{saveLabel}</Button>
|
||||
</DialogFooter>
|
||||
</form>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
|
||||
const progressBars = (
|
||||
<div className="grid grid-cols-3 gap-1.5 px-4 pt-2 pb-3">
|
||||
{([1, 2, 3] as const).map((n) => (
|
||||
@@ -203,40 +204,6 @@ export const EventDialog = ({
|
||||
3: "Recurrence",
|
||||
};
|
||||
|
||||
if (!isMobile) {
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={handleOpenChange}>
|
||||
<DialogContent className="max-w-2xl rounded-[10px] bg-card p-0 shadow-xl">
|
||||
<DialogHeader className="px-6 py-5 shadow-[inset_0_-1px_0_0_var(--color-border)]">
|
||||
<DialogTitle className="text-[28px] tracking-[-0.06em]">{titleText}</DialogTitle>
|
||||
<DialogDescription>{descriptionText}</DialogDescription>
|
||||
</DialogHeader>
|
||||
<form className="grid gap-6 px-6 py-5" onSubmit={onSubmit}>
|
||||
{isAiDraft && <AiDraftBanner />}
|
||||
<section className="grid gap-3">
|
||||
<p className="font-mono text-[11px] uppercase text-muted-foreground">Event details</p>
|
||||
<DetailsStep {...stepProps} />
|
||||
</section>
|
||||
<section className="grid gap-3">
|
||||
<p className="font-mono text-[11px] uppercase text-muted-foreground">Schedule</p>
|
||||
<ScheduleStep {...stepProps} />
|
||||
</section>
|
||||
<section className="grid gap-3">
|
||||
<p className="font-mono text-[11px] uppercase text-muted-foreground">Recurrence</p>
|
||||
<RecurrenceStep {...stepProps} />
|
||||
</section>
|
||||
<DialogFooter>
|
||||
<Button type="button" variant="ghost" onClick={() => handleOpenChange(false)}>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button type="submit">{saveLabel}</Button>
|
||||
</DialogFooter>
|
||||
</form>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Drawer open={open} onOpenChange={handleOpenChange}>
|
||||
<DrawerContent>
|
||||
|
||||
Reference in New Issue
Block a user