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

205 lines
6.8 KiB
TypeScript

import {
Button,
Card,
CardContent,
CardHeader,
CardTitle,
FormField,
Input,
Label,
Switch,
} from '@/components/ui';
import { Text } from '@/components/ui/Typography.tsx';
import Textarea from '@/components/ui/Textarea.tsx';
import { usePage, useUpdatePage, useCreatePage, usePublishPage } from '@/hooks/api/useAdminAPI.ts';
import { useTranslation } from '@/hooks/useI18n.tsx';
import { ArrowLeft, Save, Eye } from 'lucide-react';
import { useEffect, useState } from 'react';
import { useNavigate, useParams } from 'react-router-dom';
import type { CreatePageRequest, UpdatePageRequest } from '@/services/admin-api.ts';
const ContentPageEditPage = () => {
const { t } = useTranslation();
const { id } = useParams<{ id: string }>();
const navigate = useNavigate();
const isNew = id === 'new';
const { data: page, isLoading } = usePage(isNew ? null : id);
const { mutate: updatePage, isPending: isUpdating } = useUpdatePage();
const { mutate: createPage, isPending: isCreating } = useCreatePage();
const { mutate: publishPage, isPending: isPublishing } = usePublishPage();
const [formData, setFormData] = useState<CreatePageRequest>({
slug: '',
title: '',
content: '',
status: 'draft',
visibility: 'public',
});
useEffect(() => {
if (page && !isNew) {
setFormData({
slug: page.slug,
title: page.title,
content: page.content || '',
status: page.status,
visibility: page.visibility,
});
}
}, [page, isNew]);
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
if (isNew) {
createPage(formData, {
onSuccess: (newPage) => {
navigate(`/admin/content/pages/${newPage.id}/edit`);
},
});
} else if (id) {
updatePage(
{
id,
request: formData as UpdatePageRequest,
},
{
onSuccess: () => {
// Show success message
},
}
);
}
};
const handlePublish = () => {
if (id && page?.status !== 'published') {
publishPage(id, {
onSuccess: () => {
// Show success message
},
});
}
};
return (
<div className="space-y-6">
<Button variant="ghost" onClick={() => navigate('/admin/content/pages')}>
<ArrowLeft className="h-4 w-4 mr-2" />
{t('adminPage.content.pages.backToList') || 'Back to Pages'}
</Button>
<form onSubmit={handleSubmit}>
<Card>
<CardHeader>
<div className="flex items-center justify-between">
<CardTitle>
{isNew
? t('adminPage.content.pages.newPage') || 'New Page'
: t('adminPage.content.pages.editPage') || 'Edit Page'}
</CardTitle>
{!isNew && page?.status !== 'published' && (
<Button type="button" onClick={handlePublish} disabled={isPublishing}>
{isPublishing
? t('adminPage.content.pages.publishing') || 'Publishing...'
: t('adminPage.content.pages.publish') || 'Publish'}
</Button>
)}
{!isNew && page?.slug && (
<Button
type="button"
variant="outline"
onClick={() => window.open(`/${page.slug}`, '_blank')}
>
<Eye className="h-4 w-4 mr-2" />
{t('adminPage.content.pages.preview') || 'Preview'}
</Button>
)}
</div>
</CardHeader>
<CardContent className="space-y-6">
<FormField>
<Label>{t('adminPage.content.pages.slug') || 'Slug'}</Label>
<Input
value={formData.slug}
onChange={(e) => setFormData({ ...formData, slug: e.target.value })}
placeholder="about-us"
required
disabled={!isNew}
/>
<Text variant="muted" className="text-sm">
{t('adminPage.content.pages.slugHint') ||
'URL-friendly identifier (e.g., about-us, contact)'}
</Text>
</FormField>
<FormField>
<Label>{t('adminPage.content.pages.title') || 'Title'}</Label>
<Input
value={formData.title}
onChange={(e) => setFormData({ ...formData, title: e.target.value })}
required
/>
</FormField>
<FormField>
<Label>{t('adminPage.content.pages.content') || 'Content'}</Label>
<Textarea
className="min-h-[300px]"
value={formData.content}
onChange={(e) => setFormData({ ...formData, content: e.target.value })}
placeholder={
t('adminPage.content.pages.contentPlaceholder') ||
'Enter page content (HTML or Markdown)...'
}
/>
<Text variant="muted" className="text-sm">
{t('adminPage.content.pages.contentHint') ||
'Supports HTML and Markdown formatting'}
</Text>
</FormField>
<FormField>
<div className="flex items-center justify-between">
<Label>{t('adminPage.content.pages.status') || 'Status'}</Label>
<div className="flex items-center gap-2">
<span className="text-sm text-muted-foreground">
{formData.status === 'published'
? t('adminPage.content.pages.published') || 'Published'
: t('adminPage.content.pages.draft') || 'Draft'}
</span>
<Switch
checked={formData.status === 'published'}
onCheckedChange={(checked) =>
setFormData({ ...formData, status: checked ? 'published' : 'draft' })
}
/>
</div>
</div>
</FormField>
<div className="flex justify-end gap-4">
<Button
type="button"
variant="outline"
onClick={() => navigate('/admin/content/pages')}
>
{t('adminPage.content.pages.cancel') || 'Cancel'}
</Button>
<Button type="submit" disabled={isUpdating || isCreating}>
<Save className="h-4 w-4 mr-2" />
{isUpdating || isCreating
? t('adminPage.content.pages.saving') || 'Saving...'
: t('adminPage.content.pages.save') || 'Save'}
</Button>
</div>
</CardContent>
</Card>
</form>
</div>
);
};
export default ContentPageEditPage;