mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-10-01 15:48:23 -05:00
Unread indicator for chat
This commit is contained in:
@@ -23,10 +23,11 @@ export function Chat({
|
||||
inputRef,
|
||||
actionFetcher,
|
||||
isOpen,
|
||||
setIsOpen,
|
||||
toggleOpen,
|
||||
unreadCount,
|
||||
} = useChat(id);
|
||||
|
||||
if (!user) return null;
|
||||
if (!user || !messages) return null;
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -76,13 +77,16 @@ export function Chat({
|
||||
</actionFetcher.Form>
|
||||
</div>
|
||||
)}
|
||||
<button className="chat__fab" onClick={() => setIsOpen(() => !isOpen)}>
|
||||
<button className="chat__fab" onClick={toggleOpen}>
|
||||
{isOpen ? (
|
||||
<CrossIcon className="chat__fab__icon" />
|
||||
) : (
|
||||
<SpeechBubbleIcon className="chat__fab__icon" />
|
||||
)}
|
||||
</button>
|
||||
{unreadCount > 0 && (
|
||||
<div className="chat__fab__unread">{unreadCount}</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ export default function useChat(id: string) {
|
||||
const [messagesAfterLoad, setMessagesAfterLoad] = React.useState<
|
||||
ChatLoaderData["messages"]
|
||||
>([]);
|
||||
const [unreadCount, setUnreadCount] = React.useState(0);
|
||||
const loaderFetcher = useFetcher<ChatLoaderData>();
|
||||
const actionFetcher = useFetcher<ChatActionData>();
|
||||
const containerRef = React.useRef<HTMLUListElement>(null);
|
||||
@@ -21,16 +22,33 @@ export default function useChat(id: string) {
|
||||
const user = useUser();
|
||||
invariant(user, "!user");
|
||||
|
||||
useSocketEvent(`chat-${id}`, (data: Unpacked<ChatLoaderData["messages"]>) => {
|
||||
if (data.sender.id === user.id) return;
|
||||
setMessagesAfterLoad((messages) => [...messages, data]);
|
||||
setIsOpen(true);
|
||||
});
|
||||
const eventHandler = React.useCallback(
|
||||
(data: Unpacked<ChatLoaderData["messages"]>) => {
|
||||
if (data.sender.id === user.id) return;
|
||||
setMessagesAfterLoad((messages) => [...messages, data]);
|
||||
if (!isOpen) {
|
||||
setUnreadCount((count) => count + 1);
|
||||
}
|
||||
},
|
||||
[isOpen]
|
||||
);
|
||||
|
||||
useSocketEvent(`chat-${id}`, eventHandler);
|
||||
|
||||
React.useEffect(() => {
|
||||
loaderFetcher.load(chatRoute([id]));
|
||||
}, []);
|
||||
|
||||
// open chat on data load if there are messages
|
||||
React.useEffect(() => {
|
||||
if (!loaderFetcher.data) return;
|
||||
|
||||
if (loaderFetcher.data.messages.length > 0) {
|
||||
setIsOpen(true);
|
||||
}
|
||||
}, [loaderFetcher.data]);
|
||||
|
||||
// after sending message reset and refocus input so user can keep typing
|
||||
React.useEffect(() => {
|
||||
if (actionFetcher.submission) {
|
||||
formRef.current?.reset();
|
||||
@@ -69,6 +87,17 @@ export default function useChat(id: string) {
|
||||
return newMessageContent;
|
||||
}, [actionFetcher]);
|
||||
|
||||
const toggleOpen = React.useCallback(() => {
|
||||
setIsOpen((open) => {
|
||||
if (!open) {
|
||||
setUnreadCount(0);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
}, []);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!containerRef.current) return;
|
||||
containerRef.current.scrollTop = containerRef.current.scrollHeight;
|
||||
@@ -82,6 +111,7 @@ export default function useChat(id: string) {
|
||||
inputRef,
|
||||
actionFetcher,
|
||||
isOpen,
|
||||
setIsOpen,
|
||||
toggleOpen,
|
||||
unreadCount,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -11,5 +11,5 @@ export function useSocketEvent(event: string, handler: (data: any) => void) {
|
||||
return () => {
|
||||
socket.close();
|
||||
};
|
||||
}, []);
|
||||
}, [handler]);
|
||||
}
|
||||
|
||||
@@ -588,6 +588,23 @@ hr {
|
||||
width: 28px;
|
||||
}
|
||||
|
||||
.chat__fab__unread {
|
||||
position: fixed;
|
||||
z-index: 70;
|
||||
bottom: 60px;
|
||||
left: 50.9%;
|
||||
display: flex;
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: var(--theme-warning);
|
||||
border-radius: 50%;
|
||||
color: var(--button-text);
|
||||
font-size: var(--fonts-xs);
|
||||
font-weight: var(--bold);
|
||||
}
|
||||
|
||||
.chat__window {
|
||||
position: fixed;
|
||||
z-index: 50;
|
||||
@@ -620,6 +637,10 @@ hr {
|
||||
.chat__window {
|
||||
left: 85%;
|
||||
}
|
||||
|
||||
.chat__fab__unread {
|
||||
left: 85.9%;
|
||||
}
|
||||
}
|
||||
|
||||
.chat__messages {
|
||||
|
||||
Reference in New Issue
Block a user