feat: schedule automatic form closure

This commit is contained in:
2026-07-31 00:54:15 +07:00 Unverified
parent 8ee011cdfc
commit 6a73b60c48
20 changed files with 1226 additions and 35 deletions
+51 -1
View File
@@ -20,6 +20,8 @@ import {
} from "@/app/actions/questions";
import { Plus, Trash, ArrowUp, ArrowDown, Loader2, Image as ImageIcon, X, Check, GripVertical, AlertCircle } from "lucide-react";
import Image from 'next/image';
import { format, parseISO } from "date-fns";
import { DateTimePicker } from "@/components/date-time-picker";
import { RichTextEditor } from "@/components/rich-text-editor";
import { getErrorMessage } from "@/lib/utils";
import {
@@ -66,6 +68,8 @@ import {
FieldDescription,
FieldGroup,
FieldLabel,
FieldLegend,
FieldSet,
} from "@/components/ui/field";
interface Question {
@@ -87,16 +91,28 @@ interface FormEditorClientProps {
title: string;
description: string | null;
isOpen: boolean;
closesAt: string | null;
allowMultipleSubmissions: boolean;
};
initialQuestions: Question[];
}
function toDateTimeLocalValue(value: string | null) {
if (!value) return "";
const date = new Date(value);
const localDate = new Date(date.getTime() - date.getTimezoneOffset() * 60_000);
return localDate.toISOString().slice(0, 16);
}
export default function FormEditorClient({ form, initialQuestions }: FormEditorClientProps) {
const router = useRouter();
const [formTitle, setFormTitle] = useState(form.title);
const [formDescription, setFormDescription] = useState(form.description || "");
const [formIsOpen, setFormIsOpen] = useState(form.isOpen);
const [closesAt, setClosesAt] = useState(
toDateTimeLocalValue(form.closesAt)
);
const [allowMultipleSubmissions, setAllowMultipleSubmissions] = useState(
form.allowMultipleSubmissions
);
@@ -108,6 +124,7 @@ export default function FormEditorClient({ form, initialQuestions }: FormEditorC
const formTitleRef = useRef(formTitle);
const formDescriptionRef = useRef(formDescription);
const formIsOpenRef = useRef(formIsOpen);
const closesAtRef = useRef(closesAt);
const allowMultipleSubmissionsRef = useRef(allowMultipleSubmissions);
const questionsRef = useRef(questions);
@@ -115,9 +132,10 @@ export default function FormEditorClient({ form, initialQuestions }: FormEditorC
formTitleRef.current = formTitle;
formDescriptionRef.current = formDescription;
formIsOpenRef.current = formIsOpen;
closesAtRef.current = closesAt;
allowMultipleSubmissionsRef.current = allowMultipleSubmissions;
questionsRef.current = questions;
}, [allowMultipleSubmissions, formDescription, formIsOpen, formTitle, questions]);
}, [allowMultipleSubmissions, closesAt, formDescription, formIsOpen, formTitle, questions]);
const saveForm = useCallback(async () => {
const title = formTitleRef.current;
@@ -128,6 +146,9 @@ export default function FormEditorClient({ form, initialQuestions }: FormEditorC
title: title.trim(),
description: formDescriptionRef.current,
isOpen: formIsOpenRef.current,
closesAt: closesAtRef.current
? new Date(closesAtRef.current).toISOString()
: null,
allowMultipleSubmissions: allowMultipleSubmissionsRef.current,
});
router.refresh();
@@ -169,6 +190,14 @@ export default function FormEditorClient({ form, initialQuestions }: FormEditorC
formAutoSave.schedule();
};
const handleClosesAtChange = (val: string) => {
closesAtRef.current = val;
setClosesAt(val);
formAutoSave.schedule();
};
const selectedCloseDateTime = closesAt ? parseISO(closesAt) : undefined;
const handleAllowMultipleSubmissionsChange = (val: boolean) => {
allowMultipleSubmissionsRef.current = val;
setAllowMultipleSubmissions(val);
@@ -389,6 +418,27 @@ export default function FormEditorClient({ form, initialQuestions }: FormEditorC
Accepting Submissions
</FieldLabel>
</Field>
<FieldSet className="gap-3">
<FieldLegend variant="label">
Automatically close submissions
</FieldLegend>
<Field>
<FieldLabel htmlFor="form-close-date">Date and time</FieldLabel>
<DateTimePicker
id="form-close-date"
value={selectedCloseDateTime}
onChange={(date) =>
handleClosesAtChange(
date ? format(date, "yyyy-MM-dd'T'HH:mm") : ""
)
}
/>
</Field>
<FieldDescription>
Changes are saved automatically. Leave blank for no deadline.
The selected date and time use your device&apos;s time zone.
</FieldDescription>
</FieldSet>
<Field orientation="horizontal">
<Switch
id="allow-multiple-submissions"