Extract admin dashboard from ghabilee-frontend2 into a dedicated Next.js app for backoffice.ghabilee.ir (no SEO indexing / Clarity).
110 lines
3.1 KiB
TypeScript
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
|