turash/bugulma/frontend/pages/admin/ContentPagesPage.tsx
2025-12-15 10:06:41 +01:00

160 lines
5.1 KiB
TypeScript

import { DataTable } from '@/components/admin/DataTable.tsx';
import { Badge, Button } from '@/components/ui';
import { usePages, useDeletePage } from '@/hooks/api/useAdminAPI.ts';
import { useTranslation } from '@/hooks/useI18n.tsx';
import type { StaticPage } from '@/services/admin-api.ts';
import { Edit, Plus, Trash2, Eye } from 'lucide-react';
import { useState } from 'react';
import { useNavigate } from 'react-router-dom';
const ContentPagesPage = () => {
const { t } = useTranslation();
const navigate = useNavigate();
const [currentPage, setCurrentPage] = useState(1);
const pageSize = 25;
const { data, isLoading } = usePages();
const { mutate: deletePage } = useDeletePage();
const handleDelete = (page: StaticPage) => {
if (
window.confirm(
t('adminPage.content.pages.confirmDelete', { title: page.title }) ||
`Delete "${page.title}"?`
)
) {
deletePage(page.id, {
onSuccess: () => {
// Query will refetch automatically
},
});
}
};
const getStatusBadge = (status: string) => {
switch (status) {
case 'published':
return (
<Badge variant="success">{t('adminPage.content.pages.published') || 'Published'}</Badge>
);
case 'draft':
return <Badge variant="secondary">{t('adminPage.content.pages.draft') || 'Draft'}</Badge>;
case 'archived':
return (
<Badge variant="outline">{t('adminPage.content.pages.archived') || 'Archived'}</Badge>
);
default:
return <Badge variant="secondary">{status}</Badge>;
}
};
const columns = [
{
key: 'slug',
header: t('adminPage.content.pages.table.slug') || 'Slug',
render: (page: StaticPage) => <span className="font-mono text-sm">{page.slug}</span>,
},
{
key: 'title',
header: t('adminPage.content.pages.table.title') || 'Title',
render: (page: StaticPage) => <span className="font-medium">{page.title}</span>,
},
{
key: 'status',
header: t('adminPage.content.pages.table.status') || 'Status',
render: (page: StaticPage) => getStatusBadge(page.status),
},
{
key: 'visibility',
header: t('adminPage.content.pages.table.visibility') || 'Visibility',
render: (page: StaticPage) => <Badge variant="outline">{page.visibility || 'public'}</Badge>,
},
{
key: 'updatedAt',
header: t('adminPage.content.pages.table.updated') || 'Updated',
render: (page: StaticPage) => {
try {
const date = new Date(page.updatedAt);
return <span className="text-sm text-muted-foreground">{date.toLocaleDateString()}</span>;
} catch {
return <span className="text-sm text-muted-foreground"></span>;
}
},
},
];
const actions = [
{
label: t('adminPage.content.pages.edit') || 'Edit',
icon: <Edit className="h-4 w-4" />,
onClick: (page: StaticPage) => navigate(`/admin/content/pages/${page.id}/edit`),
},
{
label: t('adminPage.content.pages.view') || 'View',
icon: <Eye className="h-4 w-4" />,
onClick: (page: StaticPage) => window.open(`/${page.slug}`, '_blank'),
},
{
label: t('adminPage.content.pages.delete') || 'Delete',
icon: <Trash2 className="h-4 w-4" />,
variant: 'destructive' as const,
onClick: (page: StaticPage) => handleDelete(page),
},
];
const pages = data?.pages || [];
return (
<div className="space-y-6">
{/* Header */}
<div className="flex items-center justify-between">
<div>
<h1 className="text-2xl font-bold">
{t('adminPage.content.pages.title') || 'Static Pages'}
</h1>
<p className="text-muted-foreground">
{t('adminPage.content.pages.description') ||
'Manage static content pages like About, Contact, Privacy Policy, etc.'}
</p>
</div>
<Button onClick={() => navigate('/admin/content/pages/new')}>
<Plus className="h-4 w-4 mr-2" />
{t('adminPage.content.pages.newPage') || 'New Page'}
</Button>
</div>
{/* Table */}
<DataTable
columns={columns}
data={pages}
getRowId={(page) => page.id}
isLoading={isLoading}
actions={actions}
pagination={
pages.length > 0
? {
currentPage,
totalPages: Math.ceil(pages.length / pageSize),
pageSize,
totalItems: pages.length,
onPageChange: setCurrentPage,
}
: undefined
}
emptyMessage={t('adminPage.content.pages.noPages') || 'No pages found'}
emptyDescription={
t('adminPage.content.pages.createFirst') || 'Create your first static page to get started'
}
emptyAction={
<Button onClick={() => navigate('/admin/content/pages/new')}>
<Plus className="h-4 w-4 mr-2" />
{t('adminPage.content.pages.newPage') || 'New Page'}
</Button>
}
/>
</div>
);
};
export default ContentPagesPage;