import { createFileRoute, Link, useNavigate } from "@tanstack/react-router"; import { useQuery, useQueryClient } from "@tanstack/react-query"; import { useEffect, useState } from "react"; import { ArrowLeft, Copy, Download, Loader2, Save, Send, Sparkles, Trash2, X } from "lucide-react"; import { toast } from "sonner"; import { transcriptService } from "@/services/transcripts"; import { userService } from "@/services/users"; import { useAuth } from "@/context/auth"; import type { UserSummary } from "@/services/types"; export const Route = createFileRoute("/_authenticated/transcripts/$id")({ head: () => ({ meta: [{ title: "Transcript — Orphion" }] }), component: TranscriptDetailPage, }); function TranscriptDetailPage() { const { id } = Route.useParams(); const navigate = useNavigate(); const queryClient = useQueryClient(); const { user } = useAuth(); const [text, setText] = useState(""); const [title, setTitle] = useState(""); const [saving, setSaving] = useState(false); const [showSend, setShowSend] = useState(false); const [users, setUsers] = useState([]); const [searchQ, setSearchQ] = useState(""); const [sending, setSending] = useState(false); const { data, isLoading } = useQuery({ queryKey: ["transcript", id], queryFn: () => transcriptService.get(id), }); const transcript = data?.transcript ?? null; useEffect(() => { if (!transcript) return; setText(transcript.transcriptText); setTitle(transcript.title ?? ""); }, [transcript]); useEffect(() => { if (!showSend) return; const handle = window.setTimeout(async () => { const data = await userService.search(searchQ).catch(() => ({ users: [] })); setUsers(data.users); }, 160); return () => window.clearTimeout(handle); }, [showSend, searchQ]); async function save() { if (!transcript) return; setSaving(true); try { await transcriptService.update(transcript.id, { title, transcriptText: text }); await queryClient.invalidateQueries({ queryKey: ["transcript", id] }); await queryClient.invalidateQueries({ queryKey: ["transcripts"] }); toast.success("Saved"); } catch (err) { toast.error(err instanceof Error ? err.message : "Unable to save"); } finally { setSaving(false); } } async function remove() { if (!transcript || !confirm("Delete this transcript?")) return; try { await transcriptService.remove(transcript.id); await queryClient.invalidateQueries({ queryKey: ["transcripts"] }); toast.success("Deleted"); navigate({ to: "/transcripts" }); } catch (err) { toast.error(err instanceof Error ? err.message : "Unable to delete"); } } async function copy() { await navigator.clipboard.writeText(text); toast.success("Transcript copied"); } async function send(receiverId: number) { if (!transcript) return; setSending(true); try { await transcriptService.send({ transcriptId: transcript.id, receiverId }); await queryClient.invalidateQueries({ queryKey: ["transcript", id] }); await queryClient.invalidateQueries({ queryKey: ["transcripts"] }); toast.success("Transcript delivered"); setShowSend(false); navigate({ to: "/sent" }); } catch (err) { toast.error(err instanceof Error ? err.message : "Failed to send"); } finally { setSending(false); } } if (isLoading || !transcript) return
Loading transcript...
; const isReceived = transcript.receiverId === user?.id && transcript.senderId !== user?.id; return (
Back
.txt Audio {!isReceived && ( )} {!isReceived && ( )}
setTitle(event.target.value)} placeholder="Untitled transcript" disabled={isReceived} className="w-full bg-transparent font-display text-2xl font-semibold outline-none disabled:opacity-80" />
{new Date(transcript.createdAt).toLocaleString()} {transcript.metadata?.duration ? ( <> • {Math.round(transcript.metadata.duration)}s ) : null} {transcript.language ? ( <> • {transcript.language} ) : null} • {transcript.receiverId ? "sent" : "saved"}

Transcript

{!isReceived && ( )}