Modified by www.SourceFiles.app
This commit is contained in:
@@ -1,67 +0,0 @@
|
|||||||
import { createFileRoute, useNavigate, Link } from "@tanstack/react-router";
|
|
||||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
|
||||||
import { supabase } from "@/integrations/supabase/client";
|
|
||||||
import { useAuth } from "@/hooks/use-auth";
|
|
||||||
import { Button } from "@/components/ui/button";
|
|
||||||
import { Input } from "@/components/ui/input";
|
|
||||||
import { Label } from "@/components/ui/label";
|
|
||||||
import { ArrowLeft, Lock, Loader2 } from "lucide-react";
|
|
||||||
import { useState } from "react";
|
|
||||||
import { toast } from "sonner";
|
|
||||||
|
|
||||||
export const Route = createFileRoute("/_authenticated/students/new")({
|
|
||||||
head: () => ({ meta: [{ title: "New student — School Portal" }] }),
|
|
||||||
component: NewStudentPage,
|
|
||||||
});
|
|
||||||
|
|
||||||
function NewStudentPage() {
|
|
||||||
const { roles } = useAuth();
|
|
||||||
const navigate = useNavigate();
|
|
||||||
const qc = useQueryClient();
|
|
||||||
const [firstName, setFirstName] = useState("");
|
|
||||||
const [lastName, setLastName] = useState("");
|
|
||||||
const [dob, setDob] = useState("");
|
|
||||||
|
|
||||||
const create = useMutation({
|
|
||||||
mutationFn: async () => {
|
|
||||||
const { data, error } = await supabase
|
|
||||||
.from("students")
|
|
||||||
.insert({ first_name: firstName.trim(), last_name: lastName.trim(), dob: dob || null })
|
|
||||||
.select("id")
|
|
||||||
.single();
|
|
||||||
if (error) throw error;
|
|
||||||
return data.id as string;
|
|
||||||
},
|
|
||||||
onSuccess: (id) => {
|
|
||||||
qc.invalidateQueries({ queryKey: ["students"] });
|
|
||||||
toast.success("Student created — fill out the rest of the profile");
|
|
||||||
navigate({ to: "/students/$id", params: { id } });
|
|
||||||
},
|
|
||||||
onError: (e: Error) => toast.error(e.message),
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!roles.includes("admin")) {
|
|
||||||
return <div className="p-8"><Lock className="h-6 w-6 text-muted-foreground" /><h1 className="mt-2 text-xl font-semibold">Admins only</h1><p className="text-sm text-muted-foreground">Only admins can add students.</p></div>;
|
|
||||||
}
|
|
||||||
|
|
||||||
const canSave = firstName.trim() && lastName.trim() && !create.isPending;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="p-8 max-w-lg">
|
|
||||||
<Link to="/students" className="inline-flex items-center gap-1 text-sm text-muted-foreground hover:text-foreground mb-4"><ArrowLeft className="h-4 w-4" /> Back to students</Link>
|
|
||||||
<h1 className="text-2xl font-semibold mb-1">New student</h1>
|
|
||||||
<p className="text-muted-foreground text-sm mb-6">Start with a name — you'll fill out the full profile (or send it to a parent) next.</p>
|
|
||||||
|
|
||||||
<form onSubmit={(e) => { e.preventDefault(); if (canSave) create.mutate(); }} className="bg-card border rounded-lg p-5 space-y-4">
|
|
||||||
<div className="grid grid-cols-2 gap-3">
|
|
||||||
<div><Label>First name</Label><Input value={firstName} onChange={(e) => setFirstName(e.target.value)} required autoFocus /></div>
|
|
||||||
<div><Label>Last name</Label><Input value={lastName} onChange={(e) => setLastName(e.target.value)} required /></div>
|
|
||||||
</div>
|
|
||||||
<div><Label>Date of birth (optional)</Label><Input type="date" value={dob} onChange={(e) => setDob(e.target.value)} /></div>
|
|
||||||
<Button type="submit" disabled={!canSave} className="w-full">
|
|
||||||
{create.isPending ? <><Loader2 className="h-4 w-4 mr-1 animate-spin" /> Creating…</> : "Create profile"}
|
|
||||||
</Button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user