'use client' import { useCallback, useMemo, useState } from 'react' import { useInfiniteQuery, useQuery } from '@tanstack/react-query' import { useParams } from 'next/navigation' import DateSeparator from '@/app/(dashboard)/chat-oversight/[id]/_components/DateSeparator' import Button from '@/components/formElements/Button' import AdminState from '@/components/feedback/AdminState' import { DetailSkeleton, ListSkeleton } from '@/components/feedback/LoadingState' import PageNavbar from '@/components/layouts/PageNavbar' import StatusChip from '@/components/ui/StatusChip' import { APP_ROUTES } from '@/constants/routes' import { groupMessagesForDisplay } from '@/features/chat/groupMessagesForDisplay' import { formatPersonName } from '@/helpers' import { formatIranianMobile, formatPersianDate } from '@/lib/formatters' import useAdminChatSocket from '@/hooks/useAdminChatSocket' import { GET_ADMIN_CONVERSATION, GET_ADMIN_CONVERSATION_MESSAGES, GET_ADMIN_CONVERSATION_PARTICIPANTS, type AdminChatMessage, } from '@/services/adminChat' import AdminMessageBubble from './_components/AdminMessageBubble' const ChatOversightDetailPage = () => { const params = useParams<{ id: string }>() const conversationId = params.id const [liveMessages, setLiveMessages] = useState([]) const handleLiveMessage = useCallback((message: AdminChatMessage) => { setLiveMessages((current) => (current.some((item) => item.id === message.id) ? current : [...current, message])) }, []) const socket = useAdminChatSocket(conversationId, handleLiveMessage) const conversationQuery = useQuery({ queryKey: ['admin', 'chat-oversight', conversationId], queryFn: () => GET_ADMIN_CONVERSATION(conversationId), enabled: Boolean(conversationId), }) const participantsQuery = useQuery({ queryKey: ['admin', 'chat-oversight', conversationId, 'participants'], queryFn: () => GET_ADMIN_CONVERSATION_PARTICIPANTS(conversationId), enabled: Boolean(conversationId), }) const messagesQuery = useInfiniteQuery({ queryKey: ['admin', 'chat-oversight', conversationId, 'messages'], initialPageParam: undefined as string | undefined, queryFn: ({ pageParam }) => GET_ADMIN_CONVERSATION_MESSAGES(conversationId, pageParam ? { before: pageParam } : undefined), getNextPageParam: (lastPage) => (lastPage.hasMoreBefore ? (lastPage.olderCursor ?? undefined) : undefined), enabled: Boolean(conversationId), }) const messages = useMemo(() => { const seen = new Set() const history = [...(messagesQuery.data?.pages ?? [])].reverse().flatMap((page) => page.items) return [...history, ...liveMessages].filter((message) => { if (seen.has(message.id)) return false seen.add(message.id) return true }) }, [liveMessages, messagesQuery.data]) const displayItems = useMemo(() => groupMessagesForDisplay(messages, { showSenderNames: true }), [messages]) const conversation = conversationQuery.data const participants = useMemo(() => participantsQuery.data ?? [], [participantsQuery.data]) const participantSideById = useMemo( () => new Map(participants.map((participant, index) => [participant.userId, index % 2 === 0 ? 'primary' : 'secondary'] as const)), [participants] ) const title = conversation ? conversation.type === 'event_group' ? conversation.eventTitle || 'گروه رویداد' : participants .map((participant) => formatPersonName(participant.firstName, participant.lastName, formatIranianMobile(participant.mobile))) .join(' و ') || 'گفتگوی خصوصی' : 'جزئیات گفتگو' const loadError = conversationQuery.error ?? participantsQuery.error ?? messagesQuery.error const isInitialLoading = conversationQuery.isLoading || participantsQuery.isLoading || messagesQuery.isLoading return (
بازگشت به گفتگوها } pageTitle={title} />

حالت نظارت — فقط خواندنی

مشاهده شما عضویت، اعلان یا تغییر وضعیت خوانده‌شدن برای کاربران ایجاد نمی‌کند و در گزارش فعالیت ادمین ثبت می‌شود.

{conversation ? (
) : null}
{socket.error ? (

{socket.error} پیام‌های ذخیره‌شده همچنان از طریق API قابل مشاهده‌اند.

) : null} {isInitialLoading ? ( <> ) : null} {!isInitialLoading && loadError ? (
{ void conversationQuery.refetch() void participantsQuery.refetch() void messagesQuery.refetch() }} />
) : null} {!isInitialLoading && !loadError && conversation ? ( <>

اعضای گفتگو

{conversation.memberCount.toLocaleString('fa-IR')} نفر
{participants.map((participant) => (

{formatPersonName(participant.firstName, participant.lastName, 'کاربر')}

{formatIranianMobile(participant.mobile)}

))}

پیام‌های گفتگو

{conversation.lastMessageAt ? ( آخرین فعالیت: {formatPersianDate(conversation.lastMessageAt)} ) : null}
{messagesQuery.hasNextPage ? (
) : null} {messages.length === 0 ? ( ) : (
{displayItems.map((item) => { if (item.kind === 'date') { return ( ) } return ( ) })}
)}
) : null}
) } export default ChatOversightDetailPage