Extract admin dashboard from ghabilee-frontend2 into a dedicated Next.js app for backoffice.ghabilee.ir (no SEO indexing / Clarity).
158 lines
4.6 KiB
TypeScript
158 lines
4.6 KiB
TypeScript
'use client'
|
||
|
||
import { useEffect, useState } from 'react'
|
||
|
||
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 { EVENT_STATUS_FILTER_ITEMS, getEventStatus } from '@/constants/status'
|
||
import { formatCurrency, formatPersonName, coerceToString } from '@/helpers'
|
||
import { formatPersianDate } from '@/lib/formatters'
|
||
import { API_ROUTES } from '@/services/config'
|
||
|
||
interface EventOrganizer {
|
||
id: string
|
||
firstName: string | null
|
||
lastName: string | null
|
||
}
|
||
|
||
interface EventRow {
|
||
id: string
|
||
title: string
|
||
status: string
|
||
isFree: boolean
|
||
price: number
|
||
endsAt: string
|
||
organizer?: EventOrganizer
|
||
[key: string]: unknown
|
||
}
|
||
|
||
/**
|
||
* Admin entry point for per-event discount codes. Codes are always scoped to
|
||
* one paid event — this page lists those events and deep-links into the
|
||
* discounts tab on the event detail page (where create / report / delete live).
|
||
*/
|
||
const columns: PaginationListColumnType[] = [
|
||
{
|
||
field: 'title',
|
||
label: 'رویداد',
|
||
filterable: true,
|
||
sortable: true,
|
||
type: 'text',
|
||
},
|
||
{
|
||
field: 'organizerId',
|
||
label: 'میزبان',
|
||
filterable: false,
|
||
sortable: false,
|
||
},
|
||
{
|
||
field: 'status',
|
||
label: 'وضعیت',
|
||
filterable: true,
|
||
sortable: true,
|
||
type: 'select',
|
||
filterItems: EVENT_STATUS_FILTER_ITEMS,
|
||
},
|
||
{
|
||
field: 'price',
|
||
label: 'قیمت',
|
||
filterable: false,
|
||
sortable: true,
|
||
},
|
||
{
|
||
field: 'endsAt',
|
||
label: 'پایان',
|
||
filterable: false,
|
||
sortable: true,
|
||
},
|
||
{
|
||
field: 'actions',
|
||
label: 'عملیات',
|
||
},
|
||
]
|
||
|
||
const DiscountCodesAdminPage = () => {
|
||
const [currentTime, setCurrentTime] = useState<number | null>(null)
|
||
|
||
useEffect(() => {
|
||
setCurrentTime(Date.now())
|
||
}, [])
|
||
|
||
return (
|
||
<section className="h-full w-full text-right">
|
||
<PageNavbar pageTitle="کد تخفیف" />
|
||
<div className="admin-page-container space-y-4">
|
||
<p className="rounded-2xl border border-secondary-40 bg-white px-4 py-3 text-sm leading-7 text-secondary-30">
|
||
کد تخفیف فقط برای رویدادهای <strong>پولی</strong> تعریف میشود. رویداد مورد نظر را انتخاب کنید و از تب «کد تخفیف» کد بسازید،
|
||
غیرفعال کنید یا گزارش مصرف را ببینید. هنگام ساخت میتوانید هزینه را از سهم پلتفرم یا میزبان کم کنید.
|
||
</p>
|
||
<PaginatedList
|
||
columns={columns}
|
||
url={API_ROUTES.EVENTS.ADMIN_LIST}
|
||
urlParams={{
|
||
page: 1,
|
||
pageSize: 20,
|
||
sort: '',
|
||
filters: { isFree: 'false' },
|
||
}}
|
||
>
|
||
{{
|
||
organizerId: (row) => {
|
||
const event = row as EventRow
|
||
const organizer = event.organizer
|
||
|
||
return formatPersonName(organizer?.firstName, organizer?.lastName)
|
||
},
|
||
status: (_row, cellValue) => {
|
||
const { label, chipColor } = getEventStatus(coerceToString(cellValue))
|
||
|
||
return (
|
||
<StatusChip
|
||
chipColor={chipColor}
|
||
label={label}
|
||
/>
|
||
)
|
||
},
|
||
price: (row, cellValue) => {
|
||
const event = row as EventRow
|
||
const amount = typeof cellValue === 'number' ? cellValue : Number(cellValue)
|
||
|
||
if (event.isFree || !Number.isFinite(amount)) return '—'
|
||
|
||
return formatCurrency(amount)
|
||
},
|
||
endsAt: (row, cellValue) => {
|
||
const event = row as EventRow
|
||
const ended = currentTime !== null && new Date(event.endsAt).getTime() <= currentTime
|
||
|
||
return (
|
||
<span className={ended ? 'text-fourth-700' : undefined}>
|
||
{formatPersianDate(cellValue)}
|
||
{ended ? ' (پایانیافته)' : ''}
|
||
</span>
|
||
)
|
||
},
|
||
actions: (row) => {
|
||
const event = row as EventRow
|
||
|
||
return (
|
||
<AdminTableViewButton
|
||
label="مدیریت کد تخفیف"
|
||
mode="navigate"
|
||
to={APP_ROUTES.MANAGE_EVENT_DISCOUNTS(event.id)}
|
||
/>
|
||
)
|
||
},
|
||
}}
|
||
</PaginatedList>
|
||
</div>
|
||
</section>
|
||
)
|
||
}
|
||
|
||
export default DiscountCodesAdminPage
|