Extract admin dashboard from ghabilee-frontend2 into a dedicated Next.js app for backoffice.ghabilee.ir (no SEO indexing / Clarity).
135 lines
4.3 KiB
TypeScript
135 lines
4.3 KiB
TypeScript
'use client'
|
||
|
||
import type { PaginationListColumnType } from '@/types'
|
||
import PaginatedList from '@/components/PaginatedList'
|
||
import PageNavbar from '@/components/layouts/PageNavbar'
|
||
import AdminTableViewButton from '@/components/ui/AdminTableViewButton'
|
||
import StatusChip from '@/components/ui/StatusChip'
|
||
import { APP_ROUTES } from '@/constants/routes'
|
||
import { formatPersonName, coerceToString } from '@/helpers'
|
||
import { formatIranianMobile, formatPersianDate, truncateValue } from '@/lib/formatters'
|
||
import { API_ROUTES } from '@/services/config'
|
||
import type { AdminConversation } from '@/services/adminChat'
|
||
|
||
const CONVERSATION_TYPE_FILTER_ITEMS = [
|
||
{ code: 'event_group', name: 'گروه رویداد' },
|
||
{ code: 'direct', name: 'گفتگوی خصوصی' },
|
||
]
|
||
|
||
const columns: PaginationListColumnType[] = [
|
||
{
|
||
field: 'type',
|
||
label: 'نوع گفتگو',
|
||
filterable: true,
|
||
sortable: false,
|
||
type: 'select',
|
||
filterItems: CONVERSATION_TYPE_FILTER_ITEMS,
|
||
},
|
||
{
|
||
field: 'search',
|
||
label: 'رویداد یا کاربران',
|
||
filterable: true,
|
||
sortable: false,
|
||
type: 'text',
|
||
},
|
||
{
|
||
field: 'eventId',
|
||
label: 'شناسه رویداد',
|
||
filterable: true,
|
||
hideInTable: true,
|
||
sortable: false,
|
||
type: 'text',
|
||
},
|
||
{
|
||
field: 'userId',
|
||
label: 'شناسه کاربر',
|
||
filterable: true,
|
||
hideInTable: true,
|
||
sortable: false,
|
||
type: 'text',
|
||
},
|
||
{
|
||
field: 'preview',
|
||
label: 'آخرین پیام',
|
||
filterable: false,
|
||
sortable: false,
|
||
},
|
||
{
|
||
field: 'memberCount',
|
||
label: 'اعضا',
|
||
filterable: false,
|
||
sortable: false,
|
||
},
|
||
{
|
||
field: 'lastMessageAt',
|
||
label: 'آخرین فعالیت',
|
||
filterable: false,
|
||
sortable: true,
|
||
},
|
||
{
|
||
field: 'createdAt',
|
||
label: 'تاریخ ایجاد',
|
||
filterable: true,
|
||
sortable: true,
|
||
type: 'dateFromTo',
|
||
},
|
||
{ field: 'actions', label: 'عملیات' },
|
||
]
|
||
|
||
const participantLabel = (conversation: AdminConversation) => {
|
||
if (conversation.type === 'event_group') return conversation.eventTitle || 'گروه رویداد'
|
||
|
||
return conversation.participantPreview
|
||
.map((participant) => formatPersonName(participant.firstName, participant.lastName, formatIranianMobile(participant.mobile)))
|
||
.join(' و ')
|
||
}
|
||
|
||
const ChatOversightPage = () => (
|
||
<section className="h-full w-full text-right">
|
||
<PageNavbar
|
||
description="مشاهده فقطخواندنی گفتگوهای گروهی و خصوصی؛ تمام دسترسیها ثبت میشوند"
|
||
pageTitle="نظارت بر گفتگوها"
|
||
/>
|
||
<div className="admin-page-container">
|
||
<div className="mb-4 rounded-2xl border border-fourth-100 bg-fourth-100 px-4 py-3 text-sm text-fourth-900">
|
||
این بخش فقط برای نظارت است. حضور ادمین در اعضای گفتگو نمایش داده نمیشود و امکان ارسال یا تغییر پیام وجود ندارد.
|
||
</div>
|
||
<PaginatedList
|
||
columns={columns}
|
||
url={API_ROUTES.CHAT_OVERSIGHT.ADMIN_LIST}
|
||
>
|
||
{{
|
||
type: (row) => {
|
||
const conversation = row as unknown as AdminConversation
|
||
|
||
return (
|
||
<StatusChip
|
||
chipColor={conversation.type === 'event_group' ? 'warning' : 'default'}
|
||
label={conversation.type === 'event_group' ? 'گروه رویداد' : 'گفتگوی خصوصی'}
|
||
/>
|
||
)
|
||
},
|
||
search: (row) => participantLabel(row as unknown as AdminConversation),
|
||
preview: (_row, value) => truncateValue(coerceToString(value, '—')),
|
||
memberCount: (_row, value) => Number(value ?? 0).toLocaleString('fa-IR'),
|
||
lastMessageAt: (_row, value) => (value ? formatPersianDate(value) : 'بدون پیام'),
|
||
createdAt: (_row, value) => formatPersianDate(value),
|
||
actions: (row) => {
|
||
const conversation = row as unknown as AdminConversation
|
||
|
||
return (
|
||
<AdminTableViewButton
|
||
label="مشاهده گفتگو"
|
||
mode="navigate"
|
||
to={APP_ROUTES.CHAT_OVERSIGHT_DETAIL(conversation.id)}
|
||
/>
|
||
)
|
||
},
|
||
}}
|
||
</PaginatedList>
|
||
</div>
|
||
</section>
|
||
)
|
||
|
||
export default ChatOversightPage
|