From f470bd1eea669b97eef2eeca9e9393cb51a5f1e5 Mon Sep 17 00:00:00 2001 From: admin Date: Fri, 7 Aug 2026 04:15:10 +0000 Subject: [PATCH] Modified by www.SourceFiles.app --- src/routes/intake.$token.tsx | 185 +++++++++++++++++++++++++++++++++++ 1 file changed, 185 insertions(+) create mode 100644 src/routes/intake.$token.tsx diff --git a/src/routes/intake.$token.tsx b/src/routes/intake.$token.tsx new file mode 100644 index 0000000..0b850cd --- /dev/null +++ b/src/routes/intake.$token.tsx @@ -0,0 +1,185 @@ +import { createFileRoute } from "@tanstack/react-router"; +import { useQuery, useMutation } from "@tanstack/react-query"; +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { Textarea } from "@/components/ui/textarea"; +import { Checkbox } from "@/components/ui/checkbox"; +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; +import { GraduationCap, Loader2, CheckCircle2, Plus } from "lucide-react"; +import { useState } from "react"; +import { toast } from "sonner"; +import { getIntakeToken, submitIntake, type IntakePayload } from "@/lib/intake.functions"; + +export const Route = createFileRoute("/intake/$token")({ + head: () => ({ meta: [{ title: "Student intake — Bayside Academy" }] }), + component: IntakePage, +}); + +const emptyGuardian = { is_primary: false, full_name: "", relationship: "", phone: "", address: "", city: "", state: "", zip: "", email: "", employer: "" }; +const emptyLogin = { website: "", student_login: "", student_password: "", parent_account: "", parent_password: "" }; +const DISMISSAL = [ + { value: "not_allowed", label: "NOT ALLOWED" }, { value: "bicycle", label: "Bicycle" }, { value: "scooter", label: "Scooter" }, + { value: "walking", label: "Walking" }, { value: "rideshare", label: "Rideshare (Uber/Lyft)" }, { value: "other", label: "Other" }, +]; + +function Field({ label, children, className = "" }: { label: string; children: React.ReactNode; className?: string }) { + return
{children}
; +} +function Section({ title, description, children }: { title: string; description?: string; children: React.ReactNode }) { + return

{title}

{description &&

{description}

}
{children}
; +} + +// Top-level so the inputs don't remount / lose focus on each keystroke. +function GuardianFields({ g, setG }: { g: typeof emptyGuardian; setG: (v: typeof emptyGuardian) => void }) { + const f = (k: keyof typeof emptyGuardian) => (e: React.ChangeEvent) => setG({ ...g, [k]: e.target.value }); + return ( +
+ + + + + + + + + +
+ ); +} + +function IntakePage() { + const { token } = Route.useParams(); + const [done, setDone] = useState(false); + + const { data: info, isLoading } = useQuery({ + queryKey: ["intake-token", token], + queryFn: async () => getIntakeToken({ data: { token } }), + retry: false, + }); + + const [s, setS] = useState({ + dob: "", gender: "", grade_level: "", preferred_start_date: "", allergies: "", chronic_conditions: "", primary_physician: "", physician_phone: "", + home_ed_eval_due: "", previous_schools: "", special_needs: "", portfolio_keeper: "", disciplinary_history: "", custody_agreement: "", + dismissal_other: "", backup_transport_plan: "", interests: "", other_info: "", agreement_signed_by: "", agreement_signed_date: "", + }); + const set = (k: keyof typeof s) => (e: React.ChangeEvent) => setS((f) => ({ ...f, [k]: e.target.value })); + const [primary, setPrimary] = useState({ ...emptyGuardian, is_primary: true }); + const [secondary, setSecondary] = useState({ ...emptyGuardian }); + const [contacts, setContacts] = useState([{ name: "", relationship: "", phone: "", alt_phone: "" }, { name: "", relationship: "", phone: "", alt_phone: "" }]); + const [pickups, setPickups] = useState([{ name: "", relationship: "", phone: "", notes: "" }, { name: "", relationship: "", phone: "", notes: "" }, { name: "", relationship: "", phone: "", notes: "" }]); + const [logins, setLogins] = useState([{ ...emptyLogin }]); + const [dismissal, setDismissal] = useState([]); + const [agree, setAgree] = useState(false); + + const submit = useMutation({ + mutationFn: async () => { + const payload: IntakePayload = { + student: { ...s, dismissal_methods: dismissal }, + guardians: [primary, secondary], + contacts, pickups, logins, + }; + return submitIntake({ data: { token, payload } }); + }, + onSuccess: () => setDone(true), + onError: (e: Error) => toast.error(e.message), + }); + + if (isLoading) return ; + if (!info || info.status !== "ok") { + const msg = info?.status === "used" ? "This intake link has already been used." : info?.status === "expired" ? "This intake link has expired. Please ask the school for a new one." : "This intake link is not valid."; + return

Link unavailable

{msg}

; + } + if (done) return

Thank you!

{info.firstName}'s information has been submitted to Bayside Academy.

; + + return ( +
+
+ Bayside Academy +

Student intake

+

For {info.firstName} {info.lastName} — Bayside Academy. Please complete and submit.

+ +
{ e.preventDefault(); submit.mutate(); }} className="space-y-5"> +
+
+ + + + +
+
+
+
+
+