diff --git a/src/router.tsx b/src/router.tsx index 3423d59..bffbc8c 100644 --- a/src/router.tsx +++ b/src/router.tsx @@ -3,7 +3,14 @@ import { createRouter } from "@tanstack/react-router"; import { routeTree } from "./routeTree.gen"; export const getRouter = () => { - const queryClient = new QueryClient(); + const queryClient = new QueryClient({ + defaultOptions: { + // Don't refetch when the window regains focus — opening a native date + // picker blurs/refocuses the window, which would refetch mid-edit and + // wipe in-progress form input. + queries: { refetchOnWindowFocus: false }, + }, + }); const router = createRouter({ routeTree, diff --git a/src/routes/_authenticated/students.$id.tsx b/src/routes/_authenticated/students.$id.tsx index 346416d..f9c1be6 100644 --- a/src/routes/_authenticated/students.$id.tsx +++ b/src/routes/_authenticated/students.$id.tsx @@ -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 | null>(null); - const c = (form ?? s) as Record | null; - const upd = (k: string, v: unknown) => setForm({ ...(c as Record), [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>({}); + const startEdit = () => { setForm({ ...(s as Record) }); setEditing(true); }; + const c = (editing ? form : s) as Record | 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 (
-
+
{canEdit && }
@@ -281,7 +285,7 @@ function ProfileTab({ studentId, canEdit, isAdmin }: { studentId: string; canEdi
- +
); @@ -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 | null>(null); - const c = (form ?? s) as Record | null; - const upd = (k: string, v: unknown) => setForm({ ...(c as Record), [k]: v }); + const [form, setForm] = useState>({}); + const startEdit = () => { setForm({ ...(s as Record) }); setEditing(true); }; + const c = (editing ? form : s) as Record | 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 (
-
+
(v ? startEdit() : setEditing(false))} canEdit={canEdit} />
{!editing ? (