From ad2dc764c41a887c44efefd0ddd4f77d146248db Mon Sep 17 00:00:00 2001 From: admin Date: Sat, 22 Aug 2026 23:10:33 +0000 Subject: [PATCH] Terminal --- src/routes/_authenticated/messages.tsx | 166 ------------------------- 1 file changed, 166 deletions(-) delete mode 100644 src/routes/_authenticated/messages.tsx diff --git a/src/routes/_authenticated/messages.tsx b/src/routes/_authenticated/messages.tsx deleted file mode 100644 index 904b8f6..0000000 --- a/src/routes/_authenticated/messages.tsx +++ /dev/null @@ -1,166 +0,0 @@ -import { createFileRoute } from "@tanstack/react-router"; -import { useQuery, 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 { Textarea } from "@/components/ui/textarea"; -import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog"; -import { Plus, MessageSquare } from "lucide-react"; -import { useEffect, useRef, useState } from "react"; -import { toast } from "sonner"; - -export const Route = createFileRoute("/_authenticated/messages")({ - head: () => ({ meta: [{ title: "Messages — School Portal" }] }), - component: MessagesPage, -}); - -function MessagesPage() { - const { user, roles } = useAuth(); - const isStaff = roles.includes("admin") || roles.includes("teacher"); - const qc = useQueryClient(); - const [activeThread, setActiveThread] = useState(null); - - const { data: threads } = useQuery({ - queryKey: ["threads", user?.id], - queryFn: async () => { - const { data: parts } = await supabase.from("thread_participants").select("thread_id").eq("user_id", user!.id); - const ids = (parts ?? []).map((p) => p.thread_id); - if (ids.length === 0) return []; - const { data } = await supabase.from("message_threads").select("*").in("id", ids).order("updated_at", { ascending: false }); - return data ?? []; - }, - enabled: !!user, - }); - - useEffect(() => { - if (!user) return; - const ch = supabase.channel("messages-realtime").on("postgres_changes", { event: "*", schema: "public", table: "messages" }, () => { - qc.invalidateQueries({ queryKey: ["thread-messages"] }); - }).subscribe(); - return () => { supabase.removeChannel(ch); }; - }, [user, qc]); - - return ( -
-
-

Messages

- setActiveThread(id)} isStaff={isStaff} /> -
-
-
- {(threads ?? []).map((t) => ( - - ))} - {threads?.length === 0 &&
No threads yet
} -
-
- {activeThread ? :
Select a thread
} -
-
-
- ); -} - -function ThreadView({ threadId }: { threadId: string }) { - const { user } = useAuth(); - const qc = useQueryClient(); - const [text, setText] = useState(""); - const endRef = useRef(null); - - const { data: messages } = useQuery({ - queryKey: ["thread-messages", threadId], - queryFn: async () => (await supabase.from("messages").select("*").eq("thread_id", threadId).order("created_at")).data ?? [], - }); - - useEffect(() => { endRef.current?.scrollIntoView({ behavior: "smooth" }); }, [messages]); - - const send = useMutation({ - mutationFn: async () => { - if (!text.trim()) return; - const { error } = await supabase.from("messages").insert({ thread_id: threadId, sender_id: user!.id, body: text.trim() }); - if (error) throw error; - await supabase.from("message_threads").update({ updated_at: new Date().toISOString() }).eq("id", threadId); - }, - onSuccess: () => { setText(""); qc.invalidateQueries({ queryKey: ["thread-messages", threadId] }); }, - onError: (e: Error) => toast.error(e.message), - }); - - return ( - <> -
- {(messages ?? []).map((m) => ( -
-
- {m.body} -
{new Date(m.created_at).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" })}
-
-
- ))} -
-
-
{ e.preventDefault(); send.mutate(); }}> - setText(e.target.value)} placeholder="Type a message…" /> - -
- - ); -} - -function NewThreadDialog({ onCreated, isStaff }: { onCreated: (id: string) => void; isStaff: boolean }) { - const { user } = useAuth(); - const [open, setOpen] = useState(false); - const [subject, setSubject] = useState(""); - const [body, setBody] = useState(""); - const [recipientId, setRecipientId] = useState(""); - - const { data: recipients } = useQuery({ - queryKey: ["thread-recipients", isStaff], - queryFn: async () => (await supabase.from("profiles").select("id, full_name, email").neq("id", user!.id).order("full_name")).data ?? [], - enabled: open && !!user, - }); - - const create = useMutation({ - mutationFn: async () => { - if (!recipientId) throw new Error("Pick a recipient"); - const { data: thread, error } = await supabase.from("message_threads").insert({ subject, created_by: user!.id }).select().single(); - if (error) throw error; - const { error: pErr } = await supabase.from("thread_participants").insert([ - { thread_id: thread.id, user_id: user!.id }, - { thread_id: thread.id, user_id: recipientId }, - ]); - if (pErr) throw pErr; - if (body.trim()) { - await supabase.from("messages").insert({ thread_id: thread.id, sender_id: user!.id, body: body.trim() }); - } - return thread.id; - }, - onSuccess: (id) => { setOpen(false); setSubject(""); setBody(""); setRecipientId(""); onCreated(id); toast.success("Thread started"); }, - onError: (e: Error) => toast.error(e.message), - }); - - return ( - - - - New conversation -
-
- - -
-
setSubject(e.target.value)} />
-