61 lines
1.9 KiB
TypeScript
61 lines
1.9 KiB
TypeScript
import React from "react";
|
|
import { Link } from "react-router-dom";
|
|
import type { ChatThread } from "./types";
|
|
import { useI18n } from "../i18n";
|
|
|
|
function formatTime(value?: number | null) {
|
|
if (!value) return "";
|
|
return new Date(value).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
|
|
}
|
|
|
|
export default function ChatList({
|
|
threads,
|
|
basePath,
|
|
unreadIds,
|
|
}: {
|
|
threads: ChatThread[];
|
|
basePath: string;
|
|
unreadIds?: Set<string>;
|
|
}) {
|
|
const { t } = useI18n();
|
|
return (
|
|
<div className="chat-list">
|
|
{threads.map((thread) => {
|
|
const last = thread.lastMessage;
|
|
const preview = last?.body ?? t("chat.noMessages");
|
|
const path = `${basePath}/${thread.id}`;
|
|
const isUnread = unreadIds?.has(thread.id);
|
|
return (
|
|
<Link
|
|
key={thread.id}
|
|
to={path}
|
|
className={`chat-list-item ${isUnread ? "unread" : ""}`}
|
|
>
|
|
<div className={`chat-avatar chat-avatar--${thread.kind}`}>
|
|
{thread.kind === "global" ? "#" : thread.name.charAt(0).toUpperCase()}
|
|
</div>
|
|
<div className="chat-list-body">
|
|
<div className="chat-list-top">
|
|
<strong>{thread.name}</strong>
|
|
<div className="chat-list-meta">
|
|
<span>{formatTime(last?.createdAt)}</span>
|
|
{isUnread && <span className="chat-unread-dot" aria-hidden="true" />}
|
|
</div>
|
|
</div>
|
|
<div className="chat-list-bottom">
|
|
<p>{preview}</p>
|
|
<span className={`chat-pill chat-pill--${thread.kind}`}>
|
|
{thread.kind === "global"
|
|
? t("chat.global")
|
|
: thread.kind === "direct"
|
|
? t("chat.direct")
|
|
: t("chat.group")}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</Link>
|
|
);
|
|
})}
|
|
</div>
|
|
);
|
|
}
|