Files
hotel-demo-front/src/components/widget/chatWidget.jsx
Romain Mallard 7ae740203d
All checks were successful
Deploy React / build-and-deploy (push) Successful in 15s
FIX: chat and room size
2026-03-11 14:05:01 +01:00

274 lines
7.4 KiB
JavaScript

import { useHotel } from "../context/HotelContext";
import { useState, useEffect } from "react";
import { useRef } from "react";
//import {fetchMessage} from .
import "./chatWidget.css"
//FIXME: split element to avoid re render (convcard are being re rendered every time something is typed in the creation )
//TODO: split into multiple component
export default function ChatWidget({convlist}) {
const {
createConversation,
fetchMessages, sendMessage,
usersById, clientId,
fetchConvUsers, addUserToConv
} = useHotel();
const [activeConvId, setActiveConvId] = useState(null);
const [showAddUsers, setShowAddUsers] = useState(false);
const [showCreateConv, setShowCreateConv] = useState(false);
//FIXME: does this make multiple re render ?
const handleOpenConv = async (conv_id) => {
setActiveConvId(conv_id);
};
console.log("client id in chat widget");
function hideCreateConv(){
setShowCreateConv(false);
};
function hideAddUser(){
showAddUsers(false)
};
return (
<div className="chatWidget">
<div className="convHeader">
<div className="convList">
{convlist.map(conv => (
<ConvCard
key={conv.id}
id={conv.id}
title={conv.title}
onOpenConv={setActiveConvId}
/>
))}
</div>
<div className="convUtils">
<button
disabled={!activeConvId}
onClick={() => setShowAddUsers(v => !v)}
>
Update users
</button>
<button
hidden={showCreateConv}
onClick={() => setShowCreateConv(v => !v)}
>
Create Conv
</button>
</div>
</div>
{showAddUsers && activeConvId && (
<AddUsersMenu
convId={activeConvId}
usersById={usersById}
fetchConvUsers={fetchConvUsers}
onValidate={addUserToConv}
onClose={() => setShowAddUsers(false)}
/>
)}
{showCreateConv && (
<CreateConvMenu
onSend={createConversation}
exit={hideCreateConv}
/>
)}
{activeConvId && (
<MessagesBox
conv_id={activeConvId}
fetchMessages={fetchMessages}
usersById={usersById}
clientId={clientId}
/>
)}
<SenderBox
conv_id={activeConvId}
onSend={sendMessage}
disabled={!activeConvId}
/>
</div>
);
}
function SenderBox({ conv_id, onSend, disabled }) {
const [text, setText] = useState("");
const handleSend = () => {
console.log("conv_Id: ",conv_id)
if (!text.trim() || !conv_id) return;
onSend({
conv_id,
message: text,
});
setText("");
};
return (
<div hidden={disabled} className="senderBox">
<input
className="textbox"
value={text}
onChange={e => setText(e.target.value)}
onKeyDown={e => e.key === "Enter" && handleSend() }
placeholder="Type a message…"
/>
<button className="sendbutton" onClick={handleSend}>Send</button>
</div>
);
}
function ConvCard({id, title, onOpenConv}) {
return(
<div className="convcard" onClick={() => onOpenConv(id)} >
<h3>{title}</h3>
</div>
)
}
function MessagesBox({ conv_id }) {
const { messagesByConvId, usersById, clientId } = useHotel();
const messages = messagesByConvId[conv_id] ?? [];
console.log(messagesByConvId);
console.log(usersById);
if (messages.length === 0) {
return <div className="messagesbox empty">No messages</div>;
}
return (
<div className="messageCard">
{messages
.slice()
.sort((a, b) => new Date(a.sent_at) - new Date(b.sent_at))
.map(msg => {
const isMine = msg.sender_id === clientId;
return (
<div key={msg.sent_at}
className={`msg ${isMine ? "msg--mine" : "msg--theirs"}`}>
<p>
<strong>Sender:</strong>{" "}
{usersById[msg.sender_id] ?? "Unknown user"}
</p>
<p>{msg.content}</p>
</div>
);
})}
</div>
);
}
function AddUsersMenu({ convId, usersById, fetchConvUsers, onValidate, onClose }) {
const [selected, setSelected] = useState(new Set());
//new function to fetch already present users in the conv
//let current = fetchConvUsers(convId);
const toggleUser = (id) => {
setSelected(prev => {
const next = new Set(prev);
next.has(id) ? next.delete(id) : next.add(id);
return next;
});
};
const handleValidate = () => {
if (selected.size === 0) return;
onValidate({
conv_id: convId,
users: [...selected],
});
onClose();
};
useEffect(() => {
async function load() {
console.log("fetching conv users ar :", convId);
const ids = await fetchConvUsers({ conv_id: convId });
setSelected(new Set(ids));
}
load();
}, [convId, fetchConvUsers]);
return (
<div className="addUsersMenu">
<h3>update users</h3>
<ul>
{Object.entries(usersById).map(([id, name]) => (
<li key={id}>
<label>
<input
type="checkbox"
checked={selected.has(Number(id))}
onChange={() => toggleUser(Number(id))}
/>
{name}
</label>
</li>
))}
</ul>
<button onClick={handleValidate}>Validate</button>
<button onClick={onClose}>Cancel</button>
</div>
);
}
function CreateConvMenu({onSend, exit}) {
const [nameText, setNameText] = useState("");
const handleSend = () =>{
if (!nameText.trim()) return;
onSend(nameText);
setNameText("");
setTimeout(() => {
window.location.reload();
}, 1000);
};
return (
<div className="createConvBox">
<input
value= {nameText}
autoFocus
onChange= {element => setNameText(element.target.value)}
onKeyDown={e => e.key === "Enter" && handleSend() }
placeholder="Ma Conversation"
onBlur={exit}
/>
<button onClick= {handleSend}>Send</button>
</div>
)
}