mirror of
https://git.v0id.ovh/n3wt-innov/n3wt-school.git
synced 2026-01-28 23:43:22 +00:00
feat: Messagerie WIP [#17]
This commit is contained in:
205
Front-End/src/components/Chat.js
Normal file
205
Front-End/src/components/Chat.js
Normal file
@ -0,0 +1,205 @@
|
||||
import React, { useState, useRef, useEffect } from 'react';
|
||||
import { SendHorizontal } from 'lucide-react';
|
||||
import Image from 'next/image';
|
||||
|
||||
export default function Chat({
|
||||
discussions,
|
||||
setDiscussions,
|
||||
onSendMessage,
|
||||
simulateResponse,
|
||||
}) {
|
||||
const [selectedDiscussion, setSelectedDiscussion] = useState(null);
|
||||
const [messages, setMessages] = useState({});
|
||||
const [newMessage, setNewMessage] = useState('');
|
||||
const [showCreateForm, setShowCreateForm] = useState(false);
|
||||
const [newDiscussionName, setNewDiscussionName] = useState('');
|
||||
const [newDiscussionProfilePic, setNewDiscussionProfilePic] = useState('');
|
||||
const messagesEndRef = useRef(null);
|
||||
|
||||
const scrollToBottom = () => {
|
||||
messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
scrollToBottom();
|
||||
}, [messages]);
|
||||
|
||||
const handleSendMessage = () => {
|
||||
if (newMessage.trim() && selectedDiscussion) {
|
||||
const discussionMessages = messages[selectedDiscussion.id] || [];
|
||||
const newMessages = {
|
||||
...messages,
|
||||
[selectedDiscussion.id]: [
|
||||
...discussionMessages,
|
||||
{
|
||||
id: discussionMessages.length + 1,
|
||||
text: newMessage,
|
||||
date: new Date(),
|
||||
isResponse: false,
|
||||
},
|
||||
],
|
||||
};
|
||||
setMessages(newMessages);
|
||||
setNewMessage('');
|
||||
onSendMessage && onSendMessage(selectedDiscussion, newMessage);
|
||||
simulateResponse && simulateResponse(selectedDiscussion.id, setMessages);
|
||||
}
|
||||
};
|
||||
|
||||
const handleKeyPress = (event) => {
|
||||
if (event.key === 'Enter') {
|
||||
handleSendMessage();
|
||||
}
|
||||
};
|
||||
|
||||
const handleCreateDiscussion = () => {
|
||||
if (newDiscussionName.trim()) {
|
||||
const newDiscussion = {
|
||||
id: discussions.length + 1,
|
||||
name: newDiscussionName,
|
||||
profilePic: newDiscussionProfilePic || '/default-profile.png', // Image par défaut si aucune n'est fournie
|
||||
lastMessage: '',
|
||||
lastMessageDate: new Date(),
|
||||
};
|
||||
setDiscussions([...discussions, newDiscussion]);
|
||||
setNewDiscussionName('');
|
||||
setNewDiscussionProfilePic('');
|
||||
setShowCreateForm(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex h-full">
|
||||
{/* Liste des discussions */}
|
||||
<div className="w-1/4 bg-gray-100 border-r border-gray-300 p-4 overflow-y-auto">
|
||||
<h2 className="text-lg font-bold mb-4">Discussions</h2>
|
||||
<button
|
||||
onClick={() => setShowCreateForm(!showCreateForm)}
|
||||
className="w-full p-2 mb-4 bg-blue-500 text-white rounded-lg"
|
||||
>
|
||||
{showCreateForm ? 'Annuler' : 'Créer une discussion'}
|
||||
</button>
|
||||
{showCreateForm && (
|
||||
<div className="mb-4 p-2 border rounded-lg bg-white">
|
||||
<input
|
||||
type="text"
|
||||
value={newDiscussionName}
|
||||
onChange={(e) => setNewDiscussionName(e.target.value)}
|
||||
placeholder="Nom de la discussion"
|
||||
className="w-full p-2 mb-2 border rounded"
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
value={newDiscussionProfilePic}
|
||||
onChange={(e) => setNewDiscussionProfilePic(e.target.value)}
|
||||
placeholder="URL de la photo de profil (optionnel)"
|
||||
className="w-full p-2 mb-2 border rounded"
|
||||
/>
|
||||
<button
|
||||
onClick={handleCreateDiscussion}
|
||||
className="w-full p-2 bg-green-500 text-white rounded-lg"
|
||||
>
|
||||
Ajouter
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
{discussions && discussions.length > 0 ? (
|
||||
discussions.map((discussion) => (
|
||||
<div
|
||||
key={discussion.id}
|
||||
className={`flex items-center p-2 mb-2 cursor-pointer rounded ${
|
||||
selectedDiscussion?.id === discussion.id
|
||||
? 'bg-blue-100'
|
||||
: 'hover:bg-gray-200'
|
||||
}`}
|
||||
onClick={() => setSelectedDiscussion(discussion)}
|
||||
>
|
||||
<Image
|
||||
src={discussion.profilePic}
|
||||
alt={`${discussion.name}'s profile`}
|
||||
className="w-10 h-10 rounded-full mr-3"
|
||||
width={40}
|
||||
height={40}
|
||||
/>
|
||||
<div className="flex-1">
|
||||
<p className="font-medium">{discussion.name}</p>
|
||||
<p className="text-sm text-gray-500 truncate">
|
||||
{discussion.lastMessage}
|
||||
</p>
|
||||
</div>
|
||||
<span className="text-xs text-gray-400">
|
||||
{new Date(discussion.lastMessageDate).toLocaleTimeString()}
|
||||
</span>
|
||||
</div>
|
||||
))
|
||||
) : (
|
||||
<p className="text-gray-500">Aucune discussion disponible.</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Zone de chat */}
|
||||
<div className="flex-1 flex flex-col bg-white">
|
||||
{/* En-tête du chat */}
|
||||
{selectedDiscussion && (
|
||||
<div className="flex items-center p-4 border-b border-gray-300">
|
||||
<Image
|
||||
src={selectedDiscussion.profilePic}
|
||||
alt={`${selectedDiscussion.name}'s profile`}
|
||||
className="w-10 h-10 rounded-full mr-3"
|
||||
width={40}
|
||||
height={40}
|
||||
/>
|
||||
<h2 className="text-lg font-bold">{selectedDiscussion.name}</h2>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Messages */}
|
||||
<div className="flex-1 overflow-y-auto p-4">
|
||||
{selectedDiscussion &&
|
||||
(messages[selectedDiscussion.id] || []).map((message) => (
|
||||
<div
|
||||
key={message.id}
|
||||
className={`flex mb-4 ${
|
||||
message.isResponse ? 'justify-start' : 'justify-end'
|
||||
}`}
|
||||
>
|
||||
<div
|
||||
className={`p-3 rounded-lg max-w-xs ${
|
||||
message.isResponse
|
||||
? 'bg-gray-200 text-gray-800'
|
||||
: 'bg-blue-500 text-white'
|
||||
}`}
|
||||
>
|
||||
<p>{message.text}</p>
|
||||
<span className="text-xs text-gray-500 block mt-1">
|
||||
{new Date(message.date).toLocaleTimeString()}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
<div ref={messagesEndRef} />
|
||||
</div>
|
||||
|
||||
{/* Champ de saisie */}
|
||||
{selectedDiscussion && (
|
||||
<div className="p-4 border-t border-gray-300 flex items-center">
|
||||
<input
|
||||
type="text"
|
||||
value={newMessage}
|
||||
onChange={(e) => setNewMessage(e.target.value)}
|
||||
className="flex-1 p-2 border border-gray-300 rounded-lg mr-2"
|
||||
placeholder="Écrire un message..."
|
||||
onKeyDown={handleKeyPress}
|
||||
/>
|
||||
<button
|
||||
onClick={handleSendMessage}
|
||||
className="p-2 bg-blue-500 text-white rounded-lg"
|
||||
>
|
||||
<SendHorizontal />
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user