135 lines
3.1 KiB
TypeScript
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>
|
|
);
|
|
}
|