Reapply "Add missing admin action files and navigation links"
This reverts commit 4d515bc400.
This commit is contained in:
1 parent
96ed768f14
commit
5b4228261a
338 files changed
+28143
-5948
No files matched your search
@@ -0,0 +1,178 @@
|
||||
'use client'
|
||||
|
||||
import { Pencil } from 'lucide-react'
|
||||
import Link from 'next/link'
|
||||
import { toggleCatalogPage } from '@/actions/catalog'
|
||||
import { toggleBcPage } from '@/actions/catalog-bc'
|
||||
import { DataTable } from '@/components/admin/data-table'
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { useServerAction } from '@/hooks/use-server-action'
|
||||
import type { DataTableColumn, PaginatedResult } from '@/types'
|
||||
|
||||
interface CatalogPageRow {
|
||||
id: number
|
||||
caption: string
|
||||
parentId: number
|
||||
parentCaption: string
|
||||
pageLayout: string
|
||||
enabled: string
|
||||
visible: string
|
||||
minRank: number
|
||||
orderNum: number
|
||||
itemCount: number
|
||||
childCount: number
|
||||
}
|
||||
|
||||
interface CatalogTableProps {
|
||||
data: PaginatedResult<CatalogPageRow>
|
||||
canEdit: boolean
|
||||
catalogType?: 'normal' | 'bc'
|
||||
}
|
||||
|
||||
export function CatalogTable({ data, canEdit, catalogType = 'normal' }: CatalogTableProps) {
|
||||
const { run, isPending } = useServerAction()
|
||||
const isBc = catalogType === 'bc'
|
||||
|
||||
// Parent URLs stay in the same catalog; root takes you to the catalog index.
|
||||
const detailHref = (id: number) =>
|
||||
isBc ? `/admin/catalog/builder-club/${id}` : `/admin/catalog/${id}`
|
||||
|
||||
function handleToggle(id: number, action: 'toggleEnabled' | 'toggleVisible') {
|
||||
if (isBc) {
|
||||
const field = action === 'toggleEnabled' ? 'enabled' : 'visible'
|
||||
run(() => toggleBcPage({ id, field }), { successMessage: 'Updated.' })
|
||||
} else {
|
||||
run(() => toggleCatalogPage({ id, action }), { successMessage: 'Updated.' })
|
||||
}
|
||||
}
|
||||
|
||||
const columns: DataTableColumn<CatalogPageRow>[] = [
|
||||
{ key: 'id', label: 'ID', sortable: true },
|
||||
{
|
||||
key: 'caption',
|
||||
label: 'Caption',
|
||||
sortable: true,
|
||||
render: (value, row) => (
|
||||
<Link href={detailHref(row.id)} className="font-medium text-primary hover:underline">
|
||||
{String(value)}
|
||||
</Link>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: 'parentId',
|
||||
label: 'Parent',
|
||||
sortable: true,
|
||||
render: (_, row) =>
|
||||
row.parentId === -1 ? (
|
||||
<span className="text-xs text-muted-foreground">Root</span>
|
||||
) : (
|
||||
<Link href={detailHref(row.parentId)} className="text-xs hover:underline">
|
||||
{row.parentCaption}
|
||||
</Link>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: 'pageLayout',
|
||||
label: 'Layout',
|
||||
render: (value) => <Badge variant="secondary">{String(value)}</Badge>,
|
||||
},
|
||||
{
|
||||
key: 'enabled',
|
||||
label: 'Enabled',
|
||||
sortable: true,
|
||||
filterKey: 'filter_enabled',
|
||||
filterOptions: [
|
||||
{ label: 'Enabled', value: '1' },
|
||||
{ label: 'Disabled', value: '0' },
|
||||
],
|
||||
render: (value, row) =>
|
||||
canEdit ? (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handleToggle(row.id, 'toggleEnabled')}
|
||||
disabled={isPending}
|
||||
className="cursor-pointer disabled:opacity-50"
|
||||
>
|
||||
<Badge variant={value === '1' ? 'default' : 'outline'}>
|
||||
{value === '1' ? 'Yes' : 'No'}
|
||||
</Badge>
|
||||
</button>
|
||||
) : (
|
||||
<Badge variant={value === '1' ? 'default' : 'outline'}>
|
||||
{value === '1' ? 'Yes' : 'No'}
|
||||
</Badge>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: 'visible',
|
||||
label: 'Visible',
|
||||
sortable: true,
|
||||
filterKey: 'filter_visible',
|
||||
filterOptions: [
|
||||
{ label: 'Visible', value: '1' },
|
||||
{ label: 'Hidden', value: '0' },
|
||||
],
|
||||
render: (value, row) =>
|
||||
canEdit ? (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handleToggle(row.id, 'toggleVisible')}
|
||||
disabled={isPending}
|
||||
className="cursor-pointer disabled:opacity-50"
|
||||
>
|
||||
<Badge variant={value === '1' ? 'default' : 'outline'}>
|
||||
{value === '1' ? 'Yes' : 'No'}
|
||||
</Badge>
|
||||
</button>
|
||||
) : (
|
||||
<Badge variant={value === '1' ? 'default' : 'outline'}>
|
||||
{value === '1' ? 'Yes' : 'No'}
|
||||
</Badge>
|
||||
),
|
||||
},
|
||||
...(isBc
|
||||
? []
|
||||
: [
|
||||
{
|
||||
key: 'minRank' as const,
|
||||
label: 'Min Rank',
|
||||
sortable: true,
|
||||
} satisfies DataTableColumn<CatalogPageRow>,
|
||||
]),
|
||||
{
|
||||
key: 'itemCount',
|
||||
label: 'Items',
|
||||
render: (value) => <span>{String(value)}</span>,
|
||||
},
|
||||
{
|
||||
key: 'childCount',
|
||||
label: 'Children',
|
||||
render: (value) => <span>{String(value)}</span>,
|
||||
},
|
||||
{
|
||||
key: 'actions',
|
||||
label: 'Actions',
|
||||
render: (_, row) => (
|
||||
<Button variant="ghost" size="icon" asChild>
|
||||
<Link href={detailHref(row.id)}>
|
||||
<Pencil className="h-4 w-4" />
|
||||
</Link>
|
||||
</Button>
|
||||
),
|
||||
},
|
||||
]
|
||||
|
||||
return (
|
||||
<DataTable
|
||||
data={data}
|
||||
columns={columns}
|
||||
searchPlaceholder="Search by caption, layout or item..."
|
||||
bulkActions={
|
||||
canEdit
|
||||
? [{ label: 'Delete Selected', value: 'delete', variant: 'destructive' }]
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
)
|
||||
}
|
||||
Reference in new issue
Block a user