Files
diplom-frontend/app/components/channel-area.tsx
2025-05-20 04:16:03 +03:00

84 lines
2.6 KiB
TypeScript

import { useInfiniteQuery, type QueryFunctionContext } from "@tanstack/react-query"
import type { Channel, MessageId } from "~/lib/api/types"
import ChatMessage from "./chat-message"
import MessageBox from "./message-box"
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,
error,
fetchNextPage,
hasNextPage,
isFetching,
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 = <div className="flex items-center justify-center size-full">
<span>Loading...</span>
</div>
} else {
messageArea = <>
<div className="flex-1" />
<div className="flex flex-col-reverse overflow-auto gap-2">
{
status === "success" && data.pages.map((page, i) => (
page.map((message) => (
<div key={message.id} className="w-full">
<ChatMessage message={message} />
</div>
))
)
)
}
<VisibleTrigger triggerOnce={false} onVisible={fetchNextPageVisible} />
</div>
</>
}
return (
<>
<div className="flex flex-col size-full">
<div className="w-full min-h-12 border-b-2 flex items-center justify-center">
{channel?.name}
</div>
<div className="flex-1 overflow-y-auto flex flex-col pl-2 pr-0.5">
{messageArea}
</div>
<div className="w-full max-w-full max-h-1/2">
<MessageBox channelId={channelId} />
</div>
</div>
</>
);
}