import { useInfiniteQuery, type QueryFunctionContext } from "@tanstack/react-query"; import type { Channel, Message, MessageId } from "~/lib/api/types"; import ChatMessage from "./chat-message"; import MessageBox from "./message-box"; import { Separator } from "./ui/separator"; import VisibleTrigger from "./visible-trigger"; interface ChannelAreaProps { channel: Channel; } export default function ChannelArea({ channel }: ChannelAreaProps) { const channelId = channel.id; const fetchMessages = async ({ pageParam }: QueryFunctionContext) => { return await import("~/lib/api/client/channel").then((m) => m.default.paginatedMessages(channelId, 50, pageParam as MessageId | undefined), ); }; const { data, fetchNextPage, hasNextPage, isFetchingNextPage, isPending, status } = useInfiniteQuery({ queryKey: ["messages", channelId], initialPageParam: undefined, queryFn: fetchMessages, getNextPageParam: (lastPage) => (lastPage.length < 50 ? undefined : lastPage[lastPage.length - 1]?.id), staleTime: Infinity, }); const fetchNextPageVisible = () => { if (!isFetchingNextPage && hasNextPage) fetchNextPage(); }; let messageArea = null; if (isPending) { messageArea = (
Loading...
); } else { messageArea = ( <>
{status === "success" && renderMessages(data.pages)}
); } return ( <>
{channel?.name}
{messageArea}
); } function renderMessages(pages: Message[][]) { const messageElements: React.ReactNode[] = []; let lastDate: string | null = null; const formatMessageDate = (date: Date) => { const now = new Date(); const today = new Date(now.getFullYear(), now.getMonth(), now.getDate()); const yesterday = new Date(today); yesterday.setDate(yesterday.getDate() - 1); const messageDate = new Date(date.getFullYear(), date.getMonth(), date.getDate()); const capitalize = (str: string) => str.charAt(0).toUpperCase() + str.slice(1); if (messageDate.getTime() === today.getTime()) { const rtf = new Intl.RelativeTimeFormat(undefined, { numeric: "auto", }); return capitalize(rtf.format(0, "day")); } else if (messageDate.getTime() === yesterday.getTime()) { const rtf = new Intl.RelativeTimeFormat(undefined, { numeric: "auto", }); return capitalize(rtf.format(-1, "day")); } else { return date.toLocaleDateString(undefined, { month: "short", day: "numeric", }); } }; pages.forEach((page) => { page.forEach((message) => { const messageDate = message.createdAt.toDateString(); if (messageDate != lastDate) { if (lastDate) messageElements.push(
{formatMessageDate(new Date(lastDate))}
, ); lastDate = messageDate; } messageElements.push(
, ); }); }); return messageElements; }