mirror of
https://git.v0id.ovh/n3wt-innov/n3wt-school.git
synced 2026-04-06 05:01:25 +00:00
197 lines
5.3 KiB
JavaScript
197 lines
5.3 KiB
JavaScript
import React from 'react';
|
|
import { User, Trash2 } from 'lucide-react';
|
|
import { getGravatarUrl } from '@/utils/gravatar';
|
|
|
|
const ConversationItem = ({
|
|
conversation,
|
|
isSelected,
|
|
onClick,
|
|
onDelete, // Nouvelle prop pour la suppression
|
|
unreadCount = 0,
|
|
lastMessage,
|
|
isTyping = false,
|
|
userPresences = {}, // Nouveau prop pour les statuts de présence
|
|
}) => {
|
|
const formatTime = (dateString) => {
|
|
if (!dateString) return '';
|
|
const date = new Date(dateString);
|
|
const now = new Date();
|
|
const diffInHours = (now - date) / (1000 * 60 * 60);
|
|
|
|
if (diffInHours < 24) {
|
|
return date.toLocaleTimeString('fr-FR', {
|
|
hour: '2-digit',
|
|
minute: '2-digit',
|
|
});
|
|
} else {
|
|
return date.toLocaleDateString('fr-FR', {
|
|
day: '2-digit',
|
|
month: '2-digit',
|
|
});
|
|
}
|
|
};
|
|
|
|
const getInterlocutorName = () => {
|
|
if (conversation.interlocuteur) {
|
|
// Si nous avons le nom et prénom, les utiliser
|
|
if (
|
|
conversation.interlocuteur.first_name &&
|
|
conversation.interlocuteur.last_name
|
|
) {
|
|
return `${conversation.interlocuteur.first_name} ${conversation.interlocuteur.last_name}`;
|
|
}
|
|
// Sinon, utiliser l'email comme fallback
|
|
if (conversation.interlocuteur.email) {
|
|
return conversation.interlocuteur.email;
|
|
}
|
|
}
|
|
return conversation.name || 'Utilisateur inconnu';
|
|
};
|
|
|
|
const getLastMessageText = () => {
|
|
if (isTyping) {
|
|
return (
|
|
<span className="text-primary italic">Tape un message...</span>
|
|
);
|
|
}
|
|
|
|
if (lastMessage) {
|
|
return lastMessage.content || lastMessage.corpus || 'Message...';
|
|
}
|
|
|
|
if (conversation.last_message) {
|
|
return (
|
|
conversation.last_message.content ||
|
|
conversation.last_message.corpus ||
|
|
'Message...'
|
|
);
|
|
}
|
|
|
|
return 'Aucun message';
|
|
};
|
|
|
|
const getLastMessageTime = () => {
|
|
if (lastMessage) {
|
|
return formatTime(lastMessage.created_at || lastMessage.date_envoi);
|
|
}
|
|
|
|
if (conversation.last_message) {
|
|
return formatTime(
|
|
conversation.last_message.created_at ||
|
|
conversation.last_message.date_envoi
|
|
);
|
|
}
|
|
|
|
return '';
|
|
};
|
|
|
|
const getUserPresenceStatus = () => {
|
|
if (conversation.interlocuteur?.id) {
|
|
const presence = userPresences[conversation.interlocuteur.id];
|
|
return presence?.status || 'offline';
|
|
}
|
|
return 'offline';
|
|
};
|
|
|
|
const getPresenceColor = (status) => {
|
|
switch (status) {
|
|
case 'online':
|
|
return 'bg-tertiary';
|
|
case 'away':
|
|
return 'bg-yellow-400';
|
|
case 'busy':
|
|
return 'bg-red-400';
|
|
case 'offline':
|
|
default:
|
|
return 'bg-gray-400';
|
|
}
|
|
};
|
|
|
|
const getPresenceLabel = (status) => {
|
|
switch (status) {
|
|
case 'online':
|
|
return 'En ligne';
|
|
case 'away':
|
|
return 'Absent';
|
|
case 'busy':
|
|
return 'Occupé';
|
|
case 'offline':
|
|
default:
|
|
return 'Hors ligne';
|
|
}
|
|
};
|
|
|
|
const presenceStatus = getUserPresenceStatus();
|
|
|
|
return (
|
|
<div
|
|
className={`group flex items-center p-3 cursor-pointer rounded-lg transition-all duration-200 hover:bg-gray-50 ${
|
|
isSelected
|
|
? 'bg-primary/5 border-l-4 border-primary'
|
|
: 'hover:bg-gray-50'
|
|
}`}
|
|
onClick={onClick}
|
|
>
|
|
{/* Avatar */}
|
|
<div className="relative">
|
|
<img
|
|
src={getGravatarUrl(
|
|
conversation.interlocuteur?.email || 'default',
|
|
48
|
|
)}
|
|
alt={`Avatar de ${getInterlocutorName()}`}
|
|
className="w-12 h-12 rounded-full object-cover shadow-md"
|
|
/>
|
|
|
|
{/* Indicateur de statut en ligne */}
|
|
<div
|
|
className={`absolute -bottom-0.5 -right-0.5 w-4 h-4 ${getPresenceColor(presenceStatus)} border-2 border-white rounded-full`}
|
|
title={getPresenceLabel(presenceStatus)}
|
|
></div>
|
|
</div>
|
|
|
|
{/* Contenu de la conversation */}
|
|
<div className="flex-1 ml-3 overflow-hidden">
|
|
<div className="flex items-center justify-between">
|
|
<h3
|
|
className={`font-headline font-semibold truncate ${
|
|
isSelected ? 'text-secondary' : 'text-gray-900'
|
|
}`}
|
|
>
|
|
{getInterlocutorName()}
|
|
</h3>
|
|
<div className="flex items-center space-x-2">
|
|
{unreadCount > 0 && (
|
|
<span className="bg-red-500 text-white text-xs rounded-full w-4 h-4 text-center"></span>
|
|
)}
|
|
<span className="text-xs text-gray-500">
|
|
{getLastMessageTime()}
|
|
</span>
|
|
{/* Bouton de suppression */}
|
|
{onDelete && (
|
|
<button
|
|
onClick={(e) => {
|
|
e.stopPropagation(); // Empêcher la sélection de la conversation
|
|
onDelete();
|
|
}}
|
|
className="opacity-0 group-hover:opacity-100 hover:bg-red-100 p-1 rounded transition-all duration-200"
|
|
title="Supprimer la conversation"
|
|
>
|
|
<Trash2 className="w-4 h-4 text-red-500 hover:text-red-700" />
|
|
</button>
|
|
)}
|
|
</div>
|
|
</div>
|
|
|
|
<p
|
|
className={`text-sm truncate mt-1 ${isTyping ? '' : 'text-gray-600'}`}
|
|
>
|
|
{getLastMessageText()}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default ConversationItem;
|