admin/app/(dashboard)/discount-codes/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

158 lines
4.6 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

'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