/
opt
/
mawid
/
apps
/
dashboard
/
app
/
(app)
/
conversations
/
[id]
/
/opt/mawid/apps/dashboard/app/(app)/conversations/[id]
mkdir
upload
Name
Size
Mode
Actions
page.tsx
3911
0644
edit
dl
rm
Edit:
/opt/mawid/apps/dashboard/app/(app)/conversations/[id]/page.tsx
(3911B)
'use client'; import { useCallback, useEffect, useState } from 'react'; import { useParams, useRouter } from 'next/navigation'; import { api } from '@/lib/api'; import { useLang } from '@/lib/i18n'; import { Badge, Button, Card, Spinner } from '@/components/ui'; interface MessageRow { id: string; direction: 'inbound' | 'outbound'; type: string; body: string | null; createdAt: string; } interface ConversationRow { id: string; patient: { name: string | null; waPhone: string }; handedOff: boolean; } export default function ConversationDetailPage() { const { t, lang } = useLang(); const params = useParams<{ id: string }>(); const router = useRouter(); const [messages, setMessages] = useState<MessageRow[] | null>(null); const [conversation, setConversation] = useState<ConversationRow | null>(null); const load = useCallback(async () => { const [list, msgs] = await Promise.all([ api<ConversationRow[]>('/conversations'), api<MessageRow[]>(`/conversations/${params.id}/messages`), ]); const current = list.find((c) => c.id === params.id) ?? null; setConversation(current); setMessages(msgs); }, [params.id]); useEffect(() => { load().catch(() => router.push('/conversations')); }, [load, router]); async function toggleTakeover() { if (!conversation) return; await api(`/conversations/${params.id}/${conversation.handedOff ? 'resume' : 'takeover'}`, { method: 'POST', }); load(); } if (messages === null || conversation === null) return <Spinner />; return ( <div className="space-y-4"> <div className="flex items-center justify-between"> <button onClick={() => router.push('/conversations')} className="text-sm text-slate-500 hover:text-slate-700" > ← {t('back')} </button> <div className="flex items-center gap-2"> <Badge color={conversation.handedOff ? 'amber' : 'emerald'}> {conversation.handedOff ? t('agentPaused') : t('agentActive')} </Badge> <Button variant={conversation.handedOff ? 'primary' : 'secondary'} onClick={toggleTakeover}> {conversation.handedOff ? t('resumeAgent') : t('takeover')} </Button> </div> </div> <Card> <div className="mb-3 text-sm font-medium"> {conversation.patient.name ?? conversation.patient.waPhone}{' '} <span className="text-slate-400" dir="ltr"> {conversation.patient.waPhone} </span> </div> <div className="space-y-2"> {messages.length === 0 && <p className="text-sm text-slate-400">{t('noMessages')}</p>} {messages.map((message) => ( <div key={message.id} className={`flex ${message.direction === 'outbound' ? 'justify-end' : 'justify-start'}`} > <div className={`max-w-[80%] rounded-2xl px-3 py-2 text-sm ${ message.direction === 'outbound' ? 'rounded-br-sm bg-emerald-600 text-white' : 'rounded-bl-sm bg-slate-100 text-slate-800' }`} > <div className="whitespace-pre-wrap break-words">{message.body ?? `[${message.type}]`}</div> <div className={`mt-0.5 text-[10px] ${ message.direction === 'outbound' ? 'text-emerald-100' : 'text-slate-400' }`} > {new Date(message.createdAt).toLocaleString(lang === 'ar' ? 'ar' : lang, { day: 'numeric', month: 'short', hour: '2-digit', minute: '2-digit', })} </div> </div> </div> ))} </div> </Card> </div> ); }
Save
cmd:
run