Fix student profile dates not saving
Native date pickers blur/refocus the window, which triggered a React Query refetch mid-edit and wiped the in-progress date. Disable refetchOnWindowFocus, and make profile/academics edits work on a snapshot with functional state updates so a background refetch can't clobber input. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -159,9 +159,13 @@ function ProfileTab({ studentId, canEdit, isAdmin }: { studentId: string; canEdi
|
||||
queryKey: ["classes"],
|
||||
queryFn: async () => (await supabase.from("classes").select("id, name").order("name")).data ?? [],
|
||||
});
|
||||
const [form, setForm] = useState<Record<string, unknown> | null>(null);
|
||||
const c = (form ?? s) as Record<string, unknown> | null;
|
||||
const upd = (k: string, v: unknown) => setForm({ ...(c as Record<string, unknown>), [k]: v });
|
||||
// In edit mode we work on a snapshot (`form`) taken when Edit is pressed, so a
|
||||
// background refetch can never clobber in-progress input. Functional updates
|
||||
// avoid stale-closure races.
|
||||
const [form, setForm] = useState<Record<string, unknown>>({});
|
||||
const startEdit = () => { setForm({ ...(s as Record<string, unknown>) }); setEditing(true); };
|
||||
const c = (editing ? form : s) as Record<string, unknown> | null;
|
||||
const upd = (k: string, v: unknown) => setForm((f) => ({ ...f, [k]: v }));
|
||||
const dismissal = (c?.dismissal_methods as string[]) ?? [];
|
||||
const toggleDismissal = (v: string) => upd("dismissal_methods", dismissal.includes(v) ? dismissal.filter((x) => x !== v) : [...dismissal, v]);
|
||||
|
||||
@@ -180,7 +184,7 @@ function ProfileTab({ studentId, canEdit, isAdmin }: { studentId: string; canEdi
|
||||
const { error } = await supabase.from("students").update(payload as never).eq("id", studentId);
|
||||
if (error) throw error;
|
||||
},
|
||||
onSuccess: () => { toast.success("Profile saved"); qc.invalidateQueries({ queryKey: ["student", studentId] }); setForm(null); setEditing(false); },
|
||||
onSuccess: () => { toast.success("Profile saved"); qc.invalidateQueries({ queryKey: ["student", studentId] }); setEditing(false); },
|
||||
onError: (e: Error) => toast.error(e.message),
|
||||
});
|
||||
|
||||
@@ -192,7 +196,7 @@ function ProfileTab({ studentId, canEdit, isAdmin }: { studentId: string; canEdi
|
||||
if (!editing) {
|
||||
return (
|
||||
<div className="bg-card border rounded-lg p-6 space-y-6 mt-4">
|
||||
<div className="flex justify-end"><EditToggle editing={editing} setEditing={setEditing} canEdit={canEdit} /></div>
|
||||
<div className="flex justify-end">{canEdit && <Button size="sm" variant="outline" onClick={startEdit}><Pencil className="h-4 w-4 mr-1" /> Edit</Button>}</div>
|
||||
<Section title="Student">
|
||||
<ViewRow label="First name" value={val("first_name")} />
|
||||
<ViewRow label="Last name" value={val("last_name")} />
|
||||
@@ -281,7 +285,7 @@ function ProfileTab({ studentId, canEdit, isAdmin }: { studentId: string; canEdi
|
||||
</Section>
|
||||
<div className="flex gap-2">
|
||||
<Button onClick={() => save.mutate()} disabled={save.isPending}>{save.isPending ? "Saving…" : "Save profile"}</Button>
|
||||
<Button variant="ghost" onClick={() => { setForm(null); setEditing(false); }}>Cancel</Button>
|
||||
<Button variant="ghost" onClick={() => setEditing(false)}>Cancel</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@@ -513,9 +517,10 @@ function AcademicsTab({ studentId, canEdit }: { studentId: string; canEdit: bool
|
||||
queryKey: ["student", studentId],
|
||||
queryFn: async () => (await supabase.from("students").select("*").eq("id", studentId).single()).data,
|
||||
});
|
||||
const [form, setForm] = useState<Record<string, unknown> | null>(null);
|
||||
const c = (form ?? s) as Record<string, unknown> | null;
|
||||
const upd = (k: string, v: unknown) => setForm({ ...(c as Record<string, unknown>), [k]: v });
|
||||
const [form, setForm] = useState<Record<string, unknown>>({});
|
||||
const startEdit = () => { setForm({ ...(s as Record<string, unknown>) }); setEditing(true); };
|
||||
const c = (editing ? form : s) as Record<string, unknown> | null;
|
||||
const upd = (k: string, v: unknown) => setForm((f) => ({ ...f, [k]: v }));
|
||||
const val = (k: string) => (c?.[k] as string) ?? "";
|
||||
const { data: logins } = useQuery({
|
||||
queryKey: ["curriculum", studentId],
|
||||
@@ -530,7 +535,7 @@ function AcademicsTab({ studentId, canEdit }: { studentId: string; canEdit: bool
|
||||
}).eq("id", studentId);
|
||||
if (error) throw error;
|
||||
},
|
||||
onSuccess: () => { toast.success("Saved"); qc.invalidateQueries({ queryKey: ["student", studentId] }); setForm(null); },
|
||||
onSuccess: () => { toast.success("Saved"); qc.invalidateQueries({ queryKey: ["student", studentId] }); },
|
||||
onError: (e: Error) => toast.error(e.message),
|
||||
});
|
||||
const addLogin = useMutation({
|
||||
@@ -543,7 +548,7 @@ function AcademicsTab({ studentId, canEdit }: { studentId: string; canEdit: bool
|
||||
|
||||
return (
|
||||
<div className="space-y-6 mt-4">
|
||||
<div className="flex justify-end"><EditToggle editing={editing} setEditing={setEditing} canEdit={canEdit} /></div>
|
||||
<div className="flex justify-end"><EditToggle editing={editing} setEditing={(v) => (v ? startEdit() : setEditing(false))} canEdit={canEdit} /></div>
|
||||
|
||||
<div className="bg-card border rounded-lg p-6 space-y-4">
|
||||
{!editing ? (
|
||||
|
||||
Reference in New Issue
Block a user