84 lines
4.5 KiB
TypeScript
84 lines
4.5 KiB
TypeScript
'use client'
|
|
|
|
import { useConversations } from '@/hooks/queries/messaging';
|
|
import { useUser } from '@/hooks/queries/auth';
|
|
import { Conversation } from '@/types/messaging';
|
|
import { Search } from 'lucide-react';
|
|
import Input from '@/components/common/Input';
|
|
|
|
interface ConversationListProps {
|
|
onSelect: (conversation: Conversation) => void;
|
|
activeId?: string;
|
|
}
|
|
|
|
export default function ConversationList({ onSelect, activeId }: ConversationListProps) {
|
|
const { data: conversations, isLoading } = useConversations();
|
|
const { data: currentUser } = useUser();
|
|
|
|
if (isLoading) return <div className="p-4">Chargement des conversations...</div>;
|
|
|
|
// Fix: If conversations is not an array (though useQuery should handle it now with response.data)
|
|
const conversationList = Array.isArray(conversations) ? conversations : [];
|
|
|
|
return (
|
|
<div className="flex flex-col h-full bg-white dark:bg-black border-r border-gray-100 dark:border-neutral-800">
|
|
<div className="p-4 border-b border-gray-100 dark:border-neutral-800">
|
|
<h2 className="text-xl font-bold mb-4">Messages</h2>
|
|
<div className="relative">
|
|
<Search className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-400" />
|
|
<Input
|
|
placeholder="Rechercher..."
|
|
className="pl-10"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="flex-1 overflow-y-auto">
|
|
{conversationList.map((conv) => {
|
|
const otherParticipant = conv.participants?.find(p => p.id !== currentUser?.id);
|
|
const isActive = activeId === conv.id;
|
|
|
|
return (
|
|
<button
|
|
key={conv.id}
|
|
onClick={() => onSelect(conv)}
|
|
className={`w-full flex items-center p-4 hover:bg-gray-50 dark:hover:bg-neutral-900 transition-colors border-b border-gray-50 dark:border-neutral-900 last:border-0 ${isActive ? 'bg-gray-50 dark:bg-neutral-900' : ''}`}
|
|
>
|
|
<div className="relative">
|
|
<div className="w-12 h-12 rounded-full bg-gray-200 dark:bg-neutral-800 flex items-center justify-center overflow-hidden border border-gray-100 dark:border-neutral-700">
|
|
{otherParticipant?.avatarUrl ? (
|
|
<img src={otherParticipant.avatarUrl} alt="" className="w-full h-full object-cover" />
|
|
) : (
|
|
<span className="text-sm font-bold text-gray-500">
|
|
{(conv.label || otherParticipant?.name || '?').substring(0, 2).toUpperCase()}
|
|
</span>
|
|
)}
|
|
</div>
|
|
{conv.unread_count && conv.unread_count > 0 ? (
|
|
<span className="absolute -top-1 -right-1 w-5 h-5 bg-black dark:bg-white text-white dark:text-black text-[10px] font-bold rounded-full flex items-center justify-center">
|
|
{conv.unread_count}
|
|
</span>
|
|
) : null}
|
|
</div>
|
|
|
|
<div className="ml-4 flex-1 text-left">
|
|
<div className="flex justify-between items-baseline">
|
|
<h3 className="font-semibold text-sm truncate max-w-[140px]">
|
|
{conv.label || otherParticipant?.name || 'Sans nom'}
|
|
</h3>
|
|
<span className="text-[10px] text-gray-400 uppercase">
|
|
{conv.lastMessage?.createdAt ? new Date(conv.lastMessage.createdAt).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }) : ''}
|
|
</span>
|
|
</div>
|
|
<p className="text-xs text-gray-500 dark:text-neutral-400 truncate max-w-[200px]">
|
|
{conv.lastMessage?.body || 'Aucun message'}
|
|
</p>
|
|
</div>
|
|
</button>
|
|
);
|
|
})}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|