mirror of
https://github.com/SamyRai/turash.git
synced 2025-12-26 23:01:33 +00:00
Some checks failed
CI/CD Pipeline / backend-lint (push) Failing after 31s
CI/CD Pipeline / backend-build (push) Has been skipped
CI/CD Pipeline / frontend-lint (push) Failing after 1m37s
CI/CD Pipeline / frontend-build (push) Has been skipped
CI/CD Pipeline / e2e-test (push) Has been skipped
- Replace all 'any' types with proper TypeScript interfaces - Fix React hooks setState in useEffect issues with lazy initialization - Remove unused variables and imports across all files - Fix React Compiler memoization dependency issues - Add comprehensive i18n translation keys for admin interfaces - Apply consistent prettier formatting throughout codebase - Clean up unused bulk editing functionality - Improve type safety and code quality across frontend Files changed: 39 - ImpactMetrics.tsx: Fixed any types and interfaces - AdminVerificationQueuePage.tsx: Added i18n keys, removed unused vars - LocalizationUIPage.tsx: Fixed memoization, added translations - LocalizationDataPage.tsx: Added type safety and translations - And 35+ other files with various lint fixes
193 lines
6.6 KiB
TypeScript
193 lines
6.6 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 { 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 } = 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: page?.slug ?? '',
|
|
title: page?.title ?? '',
|
|
content: page?.content ?? '',
|
|
status: page?.status ?? 'draft',
|
|
visibility: page?.visibility ?? 'public',
|
|
}));
|
|
|
|
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;
|