admin/app/(dashboard)/guest-lists/page.tsx
alisaza e1eaf5eff5 feat: initial ghabilee-admin backoffice app
Extract admin dashboard from ghabilee-frontend2 into a dedicated Next.js
app for backoffice.ghabilee.ir (no SEO indexing / Clarity).
2026-09-05 13:12:59 +03:30

110 lines
3.1 KiB
TypeScript

'use client'
import { useState } from 'react'
import type { PaginationListColumnType } from '@/types'
import useDisclosure from '@/hooks/useDisclosure'
import PaginatedList from '@/components/PaginatedList'
import PageNavbar from '@/components/layouts/PageNavbar'
import AdminTableViewButton from '@/components/ui/AdminTableViewButton'
import GuestListItemsModal from '@/app/(dashboard)/guest-lists/_components/GuestListItemsModal'
import { API_ROUTES } from '@/services/config'
import { formatPersianDate, truncateValue } from '@/lib/formatters'
interface GuestListRow {
id: string
organizerId: string
name: string
description: string | null
createdAt: string
updatedAt: string
}
// Read-only admin visibility — GET /admin/guest-lists only supports
// filtering by organizerId and sorting by createdAt (see
// backend/src/modules/event-extras/admin-guest-lists.controller.ts,
// ADMIN_GUEST_LIST_FILTER_KEYS / GUEST_LIST_SORT_FIELDS). No write actions:
// creating/editing/deleting lists stays organizer self-service, and sending
// invitations isn't implemented in the backend yet (docs/workflows/guest-list-invitation.md).
// organizerId is filter-only (hideInTable) — the eye opens the list contacts modal.
const columns: PaginationListColumnType[] = [
{
field: 'name',
label: 'نام لیست',
filterable: false,
sortable: false,
},
{
field: 'organizerId',
label: 'میزبان',
filterable: true,
sortable: false,
type: 'text',
hideInTable: true,
},
{
field: 'description',
label: 'توضیحات',
filterable: false,
sortable: false,
},
{
field: 'createdAt',
label: 'تاریخ ثبت',
filterable: false,
sortable: true,
},
{
field: 'actions',
label: 'عملیات',
},
]
const GuestListsPage = () => {
const { isOpen, onOpenChange, onOpen } = useDisclosure()
const [activeList, setActiveList] = useState<{ id: string; name: string } | null>(null)
const openItemsModal = (list: GuestListRow) => {
setActiveList({ id: list.id, name: list.name })
onOpen()
}
return (
<section className="h-full w-full text-right">
<PageNavbar pageTitle="لیست‌های مهمان" />
<div className="admin-page-container">
<PaginatedList
columns={columns}
url={API_ROUTES.GUEST_LISTS.ADMIN_LIST}
>
{{
description: (_row, cellValue) => truncateValue(cellValue, 60),
createdAt: (_row, cellValue) => formatPersianDate(cellValue),
actions: (row) => {
const list = row as unknown as GuestListRow
return (
<AdminTableViewButton
label="مشاهده مخاطبین"
mode="open-detail"
onClick={() => {
openItemsModal(list)
}}
/>
)
},
}}
</PaginatedList>
</div>
<GuestListItemsModal
isOpen={isOpen}
list={activeList}
onOpenChange={onOpenChange}
/>
</section>
)
}
export default GuestListsPage