veza/apps/web/src/features/chat/components/ChatSidebar.tsx

118 lines
3.3 KiB
TypeScript
Raw Normal View History

import React, { useEffect } from 'react';
import { useChatStore } from '../store/chatStore';
import { useAuthStore } from '@/features/auth/store/authStore';
import { apiClient } from '@/lib/apiClient';
import { useQuery } from '@tanstack/react-query';
import { cn } from '@/lib/utils';
import { Loader2 } from 'lucide-react';
interface ConversationItemProps {
conversation: { id: string; name: string; type: string };
onSelect: (id: string) => void;
isSelected: boolean;
}
2025-12-13 02:34:34 +00:00
const ConversationItem: React.FC<ConversationItemProps> = ({
conversation,
onSelect,
isSelected,
}) => {
return (
<div
onClick={() => onSelect(conversation.id)}
className={cn(
2025-12-13 02:34:34 +00:00
'flex items-center p-3 rounded-lg cursor-pointer transition-colors',
isSelected ? 'bg-blue-100 text-blue-800' : 'hover:bg-gray-100',
)}
>
2025-12-13 02:34:34 +00:00
<span className="font-medium">
{conversation.name || `Conversation ${conversation.id.substring(0, 8)}`}
</span>
{/* <span className="ml-auto text-sm opacity-70">3</span> */}
</div>
);
};
export const ChatSidebar: React.FC = () => {
2025-12-13 02:34:34 +00:00
const { user } = useAuthStore();
const userId = user?.id;
const {
conversations,
currentConversationId,
setCurrentConversation,
addConversation,
} = useChatStore();
// Fetch conversations from backend
const { data, isLoading, error } = useQuery({
queryKey: ['chatConversations', userId],
queryFn: async () => {
if (!userId) return [];
const response = await apiClient.get('/conversations');
return response.data.conversations;
},
enabled: !!userId,
});
2025-12-13 02:34:34 +00:00
useEffect(() => {
if (data) {
data.forEach((conv: any) =>
addConversation({
id: conv.id,
name: conv.name,
type: conv.type,
participants: conv.participants,
unread_count: 0, // Default for now
}),
);
}
}, [data, addConversation]);
if (isLoading) {
return (
<div className="w-64 border-r bg-gray-50 flex items-center justify-center">
<Loader2 className="animate-spin text-blue-500" size={24} />
</div>
);
}
if (error) {
return (
<div className="w-64 border-r bg-gray-50 flex items-center justify-center text-red-500 p-4">
2025-12-13 02:34:34 +00:00
Erreur:{' '}
{(error as any).message || 'Impossible de charger les conversations'}
</div>
);
}
return (
<div className="w-64 border-r bg-gray-50 flex flex-col">
<div className="p-4 border-b">
<h2 className="text-xl font-bold">Conversations</h2>
</div>
<div className="flex-1 overflow-y-auto p-2">
{conversations.length === 0 ? (
<div className="text-gray-500 text-sm p-2">
Aucune conversation. Créez-en une !
</div>
) : (
conversations.map((conv) => (
<ConversationItem
key={conv.id}
conversation={conv}
onSelect={setCurrentConversation}
isSelected={conv.id === currentConversationId}
/>
))
)}
</div>
<div className="p-4 border-t">
{/* Button to create new conversation (TODO) */}
<button className="w-full p-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700">
Nouvelle Conversation
</button>
</div>
</div>
);
2025-12-13 02:34:34 +00:00
};