import { createFileRoute, useNavigate, Link } from "@tanstack/react-router"; import { z } from "zod"; import { useEffect, useState } from "react"; import { ProtectedLayout } from "@/components/protected-layout"; import { PageContainer, PageHeader } from "@/components/app-shell"; import { Card, CardContent } from "@/components/ui/card"; 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 { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { supabase } from "@/integrations/supabase/client"; import { useAuth } from "@/lib/auth"; import { ArrowLeft, Loader2 } from "lucide-react"; import { toast } from "sonner"; const search = z.object({ clientId: z.string().optional() }); export const Route = createFileRoute("/cases/new")({ validateSearch: search, component: () => ( ), }); function NewCase() { const { clientId } = Route.useSearch(); const navigate = useNavigate(); const { user } = useAuth(); const [clients, setClients] = useState([]); const [users, setUsers] = useState([]); const [submitting, setSubmitting] = useState(false); const [form, setForm] = useState({ client_id: clientId ?? "", case_number: "", title: "", practice_area: "", description: "", status: "intake" as const, assigned_attorney_id: user?.id ?? "", default_hourly_rate: "", }); useEffect(() => { (async () => { const [{ data: cs }, { data: us }] = await Promise.all([ supabase.from("clients").select("id, name").is("archived_at", null).order("name"), supabase.from("profiles").select("id, full_name, email").order("full_name"), ]); setClients(cs ?? []); setUsers(us ?? []); })(); }, []); useEffect(() => { if (user?.id && !form.assigned_attorney_id) { setForm((f) => ({ ...f, assigned_attorney_id: user.id })); } }, [user?.id]); // Auto-generate case number suggestion useEffect(() => { if (!form.case_number) { const yr = new Date().getFullYear(); const rand = Math.floor(1000 + Math.random() * 9000); setForm((f) => ({ ...f, case_number: `${yr}-${rand}` })); } }, []); const onSubmit = async (e: React.FormEvent) => { e.preventDefault(); if (!form.client_id || !form.title.trim() || !form.case_number.trim()) { toast.error("Please fill in client, title, and case number."); return; } setSubmitting(true); const payload = { client_id: form.client_id, case_number: form.case_number.trim(), title: form.title.trim(), practice_area: form.practice_area.trim() || null, description: form.description.trim() || null, status: form.status, assigned_attorney_id: form.assigned_attorney_id || null, default_hourly_rate: form.default_hourly_rate ? parseFloat(form.default_hourly_rate) : null, created_by: user?.id, }; const { data, error } = await supabase.from("cases").insert(payload).select("id").single(); setSubmitting(false); if (error) { toast.error("Could not create case", { description: error.message }); return; } toast.success("Case created"); navigate({ to: "/cases/$caseId", params: { caseId: data.id } }); }; return ( All cases Client setForm({ ...form, client_id: v })}> {clients.map((c) => {c.name})} Case number setForm({ ...form, case_number: e.target.value })} required maxLength={50} /> Title setForm({ ...form, title: e.target.value })} required maxLength={200} /> Practice area setForm({ ...form, practice_area: e.target.value })} placeholder="HOA collections, Litigation, Transactional…" maxLength={120} /> Status setForm({ ...form, status: v })}> Intake Active On hold Assigned attorney setForm({ ...form, assigned_attorney_id: v })}> {users.map((u) => {u.full_name || u.email})} Default hourly rate ($) setForm({ ...form, default_hourly_rate: e.target.value })} /> Description setForm({ ...form, description: e.target.value })} maxLength={5000} /> Cancel {submitting && } Create case ); }