admin/components/ui/AdminTableViewButton.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

66 lines
2.2 KiB
TypeScript

'use client'
import Button from '@/components/formElements/Button'
import EyeIcon from '@/components/icons/EyeIcon'
type AdminTableViewButtonProps = {
/** Accessible label, e.g. «مشاهده کاربر» */
label: string
disabled?: boolean
isLoading?: boolean
} & (
| {
/** Client-side navigation to a real detail route. */
mode: 'navigate'
to: string
onClick?: never
}
| {
/** Opens a same-page modal (with its own fetch) instead of navigating. */
mode: 'open-detail'
onClick: () => void
to?: never
}
)
/**
* Canonical admin-table “view details” control.
* Use only in the `actions` column — never as a cell-content stand-in for names/titles.
*
* Callers must declare exactly one of two interaction models via `mode`:
* - `mode: 'navigate'` — routes to a real detail page via `to`. Used by most tables. In 7 of
* these navigate cases (`payments`, `bookings`, `sms-messages`, `withdrawal-requests`,
* `identity-verifications`, `audit-logs` → the admin user, `user-reports` → the reported
* user) the destination is a *related entity's* detail page rather than the row's own,
* because those row types (payments, bookings, SMS messages, audit-log entries, identity
* verifications, user reports) have no dedicated detail route of their own — the user's
* detail page is the most useful place to send the admin instead. This is an intentional,
* audited product decision, not a bug — do not "fix" these to point at a nonexistent
* own-entity route.
* - `mode: 'open-detail'` — opens a local `Modal` that does its own fetch, instead of
* navigating (e.g. `settlements/page.tsx`, `guest-lists/page.tsx`).
*/
const AdminTableViewButton = (props: AdminTableViewButtonProps) => {
const { label, disabled, isLoading } = props
const to = props.mode === 'navigate' ? props.to : undefined
const onClick = props.mode === 'open-detail' ? props.onClick : undefined
return (
<Button
iconOnly
aria-label={label}
color="warning"
disabled={disabled}
isLoading={isLoading}
size="sm"
to={to}
variant="flat"
onClick={onClick}
>
<EyeIcon className="size-4" />
</Button>
)
}
export default AdminTableViewButton