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";
|
} from "@/lib/event-form";
|
||||||
import { parseRecurrenceRule, validateRecurrence } from "@/lib/recurrence";
|
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 {
|
interface EventDialogProps {
|
||||||
open: boolean;
|
open: boolean;
|
||||||
onOpenChange: (open: boolean) => void;
|
onOpenChange: (open: boolean) => void;
|
||||||
@@ -96,12 +102,6 @@ export const EventDialog = ({
|
|||||||
onOpenChange(nextOpen);
|
onOpenChange(nextOpen);
|
||||||
};
|
};
|
||||||
|
|
||||||
const STEP_FIELDS: Record<1 | 2 | 3, (keyof EventFormValues)[]> = {
|
|
||||||
1: ["title", "url"],
|
|
||||||
2: ["start", "end"],
|
|
||||||
3: ["recurrenceRule"],
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleNext = async () => {
|
const handleNext = async () => {
|
||||||
const valid = await trigger(STEP_FIELDS[step]);
|
const valid = await trigger(STEP_FIELDS[step]);
|
||||||
if (valid) advanceStep();
|
if (valid) advanceStep();
|
||||||
@@ -148,41 +148,42 @@ export const EventDialog = ({
|
|||||||
reset(getDefaultEventFormValues());
|
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 };
|
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 = (
|
const progressBars = (
|
||||||
<div className="grid grid-cols-3 gap-1.5 px-4 pt-2 pb-3">
|
<div className="grid grid-cols-3 gap-1.5 px-4 pt-2 pb-3">
|
||||||
{([1, 2, 3] as const).map((n) => (
|
{([1, 2, 3] as const).map((n) => (
|
||||||
@@ -203,40 +204,6 @@ export const EventDialog = ({
|
|||||||
3: "Recurrence",
|
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 (
|
return (
|
||||||
<Drawer open={open} onOpenChange={handleOpenChange}>
|
<Drawer open={open} onOpenChange={handleOpenChange}>
|
||||||
<DrawerContent>
|
<DrawerContent>
|
||||||
|
|||||||
Reference in New Issue
Block a user