This commit is contained in:
2026-08-22 23:10:27 +00:00
parent 15eb0b61f0
commit bf91b2f021
-97
View File
@@ -1,97 +0,0 @@
import { createServerFn } from "@tanstack/react-start";
import { requireSupabaseAuth } from "@/integrations/supabase/auth-middleware";
export type IntakePayload = {
student: {
dob: string; gender: string; grade_level: string; preferred_start_date: string;
allergies: string; chronic_conditions: string; primary_physician: string; physician_phone: string;
home_ed_eval_due: string; previous_schools: string; special_needs: string; portfolio_keeper: string;
disciplinary_history: string; custody_agreement: string;
dismissal_methods: string[]; dismissal_other: string; backup_transport_plan: string;
interests: string; other_info: string; agreement_signed_by: string; agreement_signed_date: string;
};
guardians: { is_primary: boolean; full_name: string; relationship: string; phone: string; address: string; city: string; state: string; zip: string; email: string; employer: string }[];
contacts: { name: string; relationship: string; phone: string; alt_phone: string }[];
pickups: { name: string; relationship: string; phone: string; notes: string }[];
logins: { website: string; student_login: string; student_password: string; parent_account: string; parent_password: string }[];
};
const orNull = (v: string) => (v && v.trim() ? v.trim() : null);
// ── Admin: create a one-time intake link for a student ────────────────────────
export const createIntakeToken = createServerFn({ method: "POST" })
.middleware([requireSupabaseAuth])
.validator((d: { studentId: string }) => d)
.handler(async ({ data, context }) => {
const { supabaseAdmin } = await import("@/integrations/supabase/client.server");
const callerId = (context as { userId: string }).userId;
const { data: adminRow } = await supabaseAdmin.from("user_roles").select("role").eq("user_id", callerId).eq("role", "admin").maybeSingle();
if (!adminRow) throw new Error("Only admins can create intake links.");
const token = crypto.randomUUID().replace(/-/g, "") + crypto.randomUUID().replace(/-/g, "");
const expires_at = new Date(Date.now() + 14 * 24 * 60 * 60 * 1000).toISOString();
const { error } = await supabaseAdmin.from("intake_tokens").insert({ token, student_id: data.studentId, created_by: callerId, expires_at });
if (error) throw new Error(error.message);
return { token };
});
// ── Public: validate a token, return the student's name for the form ──────────
export const getIntakeToken = createServerFn({ method: "POST" })
.validator((d: { token: string }) => d)
.handler(async ({ data }) => {
const { supabaseAdmin } = await import("@/integrations/supabase/client.server");
const { data: row } = await supabaseAdmin.from("intake_tokens").select("student_id, expires_at, used_at").eq("token", data.token).maybeSingle();
if (!row) return { status: "invalid" as const };
if (row.used_at) return { status: "used" as const };
if (new Date(row.expires_at) < new Date()) return { status: "expired" as const };
const { data: student } = await supabaseAdmin.from("students").select("first_name, last_name").eq("id", row.student_id).maybeSingle();
return { status: "ok" as const, firstName: student?.first_name ?? "", lastName: student?.last_name ?? "" };
});
// ── Public: submit the intake, write to the student's record, mark used ───────
export const submitIntake = createServerFn({ method: "POST" })
.validator((d: { token: string; payload: IntakePayload }) => d)
.handler(async ({ data }) => {
const { supabaseAdmin } = await import("@/integrations/supabase/client.server");
const { data: row } = await supabaseAdmin.from("intake_tokens").select("id, student_id, expires_at, used_at").eq("token", data.token).maybeSingle();
if (!row) throw new Error("This link is not valid.");
if (row.used_at) throw new Error("This link has already been used.");
if (new Date(row.expires_at) < new Date()) throw new Error("This link has expired.");
const sid = row.student_id;
const s = data.payload.student;
const { error: e1 } = await supabaseAdmin.from("students").update({
dob: orNull(s.dob), gender: orNull(s.gender), grade_level: orNull(s.grade_level), preferred_start_date: orNull(s.preferred_start_date),
allergies: orNull(s.allergies), chronic_conditions: orNull(s.chronic_conditions), primary_physician: orNull(s.primary_physician), physician_phone: orNull(s.physician_phone),
home_ed_eval_due: orNull(s.home_ed_eval_due), previous_schools: orNull(s.previous_schools), special_needs: orNull(s.special_needs), portfolio_keeper: orNull(s.portfolio_keeper),
disciplinary_history: orNull(s.disciplinary_history), custody_agreement: orNull(s.custody_agreement),
dismissal_methods: s.dismissal_methods ?? [], dismissal_other: orNull(s.dismissal_other), backup_transport_plan: orNull(s.backup_transport_plan),
interests: orNull(s.interests), other_info: orNull(s.other_info), agreement_signed_by: orNull(s.agreement_signed_by), agreement_signed_date: orNull(s.agreement_signed_date),
}).eq("id", sid);
if (e1) throw new Error(e1.message);
// Replace collections with what was submitted (initial intake is the source of truth here).
await supabaseAdmin.from("student_guardians").delete().eq("student_id", sid);
await supabaseAdmin.from("authorized_pickups").delete().eq("student_id", sid);
await supabaseAdmin.from("student_curriculum_logins").delete().eq("student_id", sid);
const guardianRows = data.payload.guardians.filter((g) => g.full_name.trim()).map((g) => ({
student_id: sid, is_primary: g.is_primary, full_name: g.full_name.trim(), relationship: orNull(g.relationship), phone: orNull(g.phone),
address: orNull(g.address), city: orNull(g.city), state: orNull(g.state), zip: orNull(g.zip), email: orNull(g.email), employer: orNull(g.employer),
}));
if (guardianRows.length) { const { error } = await supabaseAdmin.from("student_guardians").insert(guardianRows); if (error) throw new Error(error.message); }
const pickupRows = [
...data.payload.pickups.filter((p) => p.name.trim()).map((p, i) => ({ student_id: sid, kind: "pickup", sort_order: i, name: p.name.trim(), relationship: orNull(p.relationship), phone: orNull(p.phone), alt_phone: null as string | null, notes: orNull(p.notes) })),
...data.payload.contacts.filter((c) => c.name.trim()).map((c, i) => ({ student_id: sid, kind: "emergency", sort_order: i, name: c.name.trim(), relationship: orNull(c.relationship), phone: orNull(c.phone), alt_phone: orNull(c.alt_phone), notes: null as string | null })),
];
if (pickupRows.length) { const { error } = await supabaseAdmin.from("authorized_pickups").insert(pickupRows); if (error) throw new Error(error.message); }
const loginRows = data.payload.logins.filter((l) => Object.values(l).some((v) => v.trim())).map((l) => ({
student_id: sid, website: orNull(l.website), student_login: orNull(l.student_login), student_password: orNull(l.student_password), parent_account: orNull(l.parent_account), parent_password: orNull(l.parent_password),
}));
if (loginRows.length) { const { error } = await supabaseAdmin.from("student_curriculum_logins").insert(loginRows); if (error) throw new Error(error.message); }
await supabaseAdmin.from("intake_tokens").update({ used_at: new Date().toISOString() }).eq("id", row.id);
return { ok: true };
});