All checks were successful
Deploy React / build-and-deploy (push) Successful in 15s
274 lines
7.4 KiB
JavaScript
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>
|
|
)
|
|
}
|