riplog-view/frontend/src/Chatroom.tsx

135 lines
3.1 KiB
TypeScript

import React, { useEffect, useRef } from "react";
import { useQuery } from "@apollo/react-hooks";
import { gql } from "apollo-boost";
import { GQLMessage } from "./gql-types";
function perDay(messages: GQLMessage[]) {
const days = messages.reduce((acc, msg) => {
const [day] = msg.time.split("T");
if (!(day in acc)) {
acc[day] = [];
}
acc[day].push(msg);
return acc;
}, {});
return Object.entries(days).sort(([a], [b]) => {
if (a > b) {
return 1;
}
return -1;
});
}
function formatTime(time: string): string {
const t = new Date(time);
return [t.getHours(), t.getMinutes(), t.getSeconds()]
.map(x => `0${x}`.slice(-2))
.join(":");
}
function colorname(name: string): string {
const n = name
.split("")
.map(x => x.charCodeAt(0))
.reduce((a, b) => a + b, 0);
return `hsl(${n % 360}, 60%, 50%)`;
}
export default function Chatroom() {
const {
loading: localLoading,
error: localError,
data: localData
} = useQuery(gql`
{
currentChat {
workspace
channel
}
}
`);
const variables = {
workspace: localData.currentChat?.workspace || "",
channel: localData.currentChat?.channel || ""
};
const {
loading: remoteLoading,
error: remoteError,
data: remoteData
} = useQuery(
gql`
query Messages($workspace: String!, $channel: String!) {
messages(
workspace: $workspace
order: DATE_ASC
filter: { channel: $channel }
) {
messages {
content
username
userRealname
time
messageId
}
}
}
`,
{
variables
}
);
const lastMessage = useRef(null);
useEffect(() => {
lastMessage.current?.scrollIntoView();
});
if (localLoading || remoteLoading) {
return <div>Loading</div>;
}
if (localData.currentChat == null) {
return <div>Select a channel from the left menu</div>;
}
if (localError) {
return <div>{localError.message}</div>;
}
if (remoteError) {
return <div>{remoteError.message}</div>;
}
return (
<div>
<ul className="chatlog">
{perDay(remoteData.messages.messages).map(([day, messages]) => (
<li>
<div className="day">{day}</div>
<ul>
{messages.map((msg: GQLMessage) => (
<li key={msg.messageId}>
<article className="message">
<header>
<div className="time" title={msg.time}>
{formatTime(msg.time)}
</div>
<div
className="realname"
style={{ color: colorname(msg.username) }}
>
{msg.userRealname}
</div>
<div className="username">{msg.username}</div>
</header>
<p>{msg.content}</p>
</article>
</li>
))}
</ul>
</li>
))}
</ul>
<div ref={lastMessage}></div>
</div>
);
}