feat: remove admin info page CRUD
This commit is contained in:
@@ -1 +0,0 @@
|
|||||||
export { AdminInfoPage } from './ui/AdminInfoPage'
|
|
||||||
@@ -1,216 +0,0 @@
|
|||||||
import Alert from '@mui/material/Alert'
|
|
||||||
import Box from '@mui/material/Box'
|
|
||||||
import Button from '@mui/material/Button'
|
|
||||||
import Dialog from '@mui/material/Dialog'
|
|
||||||
import DialogActions from '@mui/material/DialogActions'
|
|
||||||
import DialogContent from '@mui/material/DialogContent'
|
|
||||||
import DialogTitle from '@mui/material/DialogTitle'
|
|
||||||
import FormControlLabel from '@mui/material/FormControlLabel'
|
|
||||||
import Stack from '@mui/material/Stack'
|
|
||||||
import Switch from '@mui/material/Switch'
|
|
||||||
import Table from '@mui/material/Table'
|
|
||||||
import TableBody from '@mui/material/TableBody'
|
|
||||||
import TableCell from '@mui/material/TableCell'
|
|
||||||
import TableHead from '@mui/material/TableHead'
|
|
||||||
import TableRow from '@mui/material/TableRow'
|
|
||||||
import TextField from '@mui/material/TextField'
|
|
||||||
import Typography from '@mui/material/Typography'
|
|
||||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
|
|
||||||
import { Controller, useForm } from 'react-hook-form'
|
|
||||||
import {
|
|
||||||
createInfoBlock,
|
|
||||||
deleteInfoBlock,
|
|
||||||
fetchAdminInfoBlocks,
|
|
||||||
type InfoPageBlock,
|
|
||||||
updateInfoBlock,
|
|
||||||
} from '@/entities/info'
|
|
||||||
import { getErrorMessage } from '@/shared/lib/get-error-message'
|
|
||||||
import { invalidateQueryKeys } from '@/shared/lib/invalidate-query-keys'
|
|
||||||
import { useEditDialogState } from '@/shared/lib/use-edit-dialog-state'
|
|
||||||
import { EntityRowActions } from '@/shared/ui/EntityRowActions'
|
|
||||||
|
|
||||||
type FormState = {
|
|
||||||
key: string
|
|
||||||
title: string
|
|
||||||
body: string
|
|
||||||
sort: string
|
|
||||||
published: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
const emptyForm = (): FormState => ({ key: '', title: '', body: '', sort: '0', published: true })
|
|
||||||
|
|
||||||
export function AdminInfoPage() {
|
|
||||||
const qc = useQueryClient()
|
|
||||||
const { dialogOpen, editing, openCreateDialog, openEditDialog, closeDialog } = useEditDialogState<InfoPageBlock>()
|
|
||||||
const form = useForm<FormState>({ defaultValues: emptyForm(), mode: 'onChange' })
|
|
||||||
|
|
||||||
const blocksQuery = useQuery({
|
|
||||||
queryKey: ['admin', 'info-page', 'blocks'],
|
|
||||||
queryFn: fetchAdminInfoBlocks,
|
|
||||||
})
|
|
||||||
|
|
||||||
const saveMut = useMutation({
|
|
||||||
mutationFn: async () => {
|
|
||||||
const values = form.getValues()
|
|
||||||
const payload = {
|
|
||||||
key: values.key.trim(),
|
|
||||||
title: values.title.trim(),
|
|
||||||
body: values.body.trim(),
|
|
||||||
sort: Number(values.sort || 0),
|
|
||||||
published: values.published,
|
|
||||||
}
|
|
||||||
if (editing) return updateInfoBlock(editing.id, payload)
|
|
||||||
return createInfoBlock(payload)
|
|
||||||
},
|
|
||||||
onSuccess: async () => {
|
|
||||||
closeDialog()
|
|
||||||
form.reset(emptyForm())
|
|
||||||
await invalidateQueryKeys(qc, [
|
|
||||||
['admin', 'info-page', 'blocks'],
|
|
||||||
['info-page', 'public', 'blocks'],
|
|
||||||
])
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
const deleteMut = useMutation({
|
|
||||||
mutationFn: (id: string) => deleteInfoBlock(id),
|
|
||||||
onSuccess: async () => {
|
|
||||||
await invalidateQueryKeys(qc, [
|
|
||||||
['admin', 'info-page', 'blocks'],
|
|
||||||
['info-page', 'public', 'blocks'],
|
|
||||||
])
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
const openCreate = () => {
|
|
||||||
form.reset(emptyForm())
|
|
||||||
openCreateDialog()
|
|
||||||
}
|
|
||||||
|
|
||||||
const openEdit = (item: InfoPageBlock) => {
|
|
||||||
openEditDialog(item)
|
|
||||||
form.reset({
|
|
||||||
key: item.key,
|
|
||||||
title: item.title,
|
|
||||||
body: item.body,
|
|
||||||
sort: String(item.sort),
|
|
||||||
published: item.published,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const items = blocksQuery.data?.items ?? []
|
|
||||||
const err = saveMut.error ?? deleteMut.error
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Box>
|
|
||||||
<Stack direction="row" sx={{ mb: 2, alignItems: 'center', justifyContent: 'space-between' }}>
|
|
||||||
<Typography variant="h4">Информационная страница</Typography>
|
|
||||||
<Button variant="contained" onClick={openCreate}>
|
|
||||||
Новый блок
|
|
||||||
</Button>
|
|
||||||
</Stack>
|
|
||||||
|
|
||||||
<Typography color="text.secondary" sx={{ mb: 2 }}>
|
|
||||||
Управление блоками страницы с процессом покупки, оплаты и доставки.
|
|
||||||
</Typography>
|
|
||||||
|
|
||||||
{blocksQuery.isError && <Alert severity="error">Не удалось загрузить блоки.</Alert>}
|
|
||||||
{err && (
|
|
||||||
<Alert severity="error" sx={{ mb: 2 }}>
|
|
||||||
{getErrorMessage(err)}
|
|
||||||
</Alert>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<Table size="small">
|
|
||||||
<TableHead>
|
|
||||||
<TableRow>
|
|
||||||
<TableCell>Key</TableCell>
|
|
||||||
<TableCell>Заголовок</TableCell>
|
|
||||||
<TableCell>Порядок</TableCell>
|
|
||||||
<TableCell>Опубликован</TableCell>
|
|
||||||
<TableCell align="right">Действия</TableCell>
|
|
||||||
</TableRow>
|
|
||||||
</TableHead>
|
|
||||||
<TableBody>
|
|
||||||
{items.map((item) => (
|
|
||||||
<TableRow key={item.id} hover>
|
|
||||||
<TableCell>{item.key}</TableCell>
|
|
||||||
<TableCell>{item.title}</TableCell>
|
|
||||||
<TableCell>{item.sort}</TableCell>
|
|
||||||
<TableCell>{item.published ? 'Да' : 'Нет'}</TableCell>
|
|
||||||
<TableCell align="right">
|
|
||||||
<EntityRowActions
|
|
||||||
onEdit={() => openEdit(item)}
|
|
||||||
onDelete={() => deleteMut.mutate(item.id)}
|
|
||||||
deleteDisabled={deleteMut.isPending}
|
|
||||||
/>
|
|
||||||
</TableCell>
|
|
||||||
</TableRow>
|
|
||||||
))}
|
|
||||||
{items.length === 0 && !blocksQuery.isLoading && (
|
|
||||||
<TableRow>
|
|
||||||
<TableCell colSpan={5} sx={{ color: 'text.secondary' }}>
|
|
||||||
Блоков пока нет.
|
|
||||||
</TableCell>
|
|
||||||
</TableRow>
|
|
||||||
)}
|
|
||||||
</TableBody>
|
|
||||||
</Table>
|
|
||||||
|
|
||||||
<Dialog open={dialogOpen} onClose={closeDialog} fullWidth maxWidth="md">
|
|
||||||
<DialogTitle>{editing ? 'Редактировать блок' : 'Новый блок'}</DialogTitle>
|
|
||||||
<DialogContent>
|
|
||||||
<Stack spacing={2} sx={{ mt: 1 }}>
|
|
||||||
<Controller
|
|
||||||
control={form.control}
|
|
||||||
name="key"
|
|
||||||
render={({ field }) => <TextField label="Key (латиница, цифры, _-)" fullWidth required {...field} />}
|
|
||||||
/>
|
|
||||||
<Controller
|
|
||||||
control={form.control}
|
|
||||||
name="title"
|
|
||||||
render={({ field }) => <TextField label="Заголовок" fullWidth required {...field} />}
|
|
||||||
/>
|
|
||||||
<Controller
|
|
||||||
control={form.control}
|
|
||||||
name="body"
|
|
||||||
render={({ field }) => (
|
|
||||||
<TextField label="Содержимое" fullWidth multiline minRows={5} required {...field} />
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
<Controller
|
|
||||||
control={form.control}
|
|
||||||
name="sort"
|
|
||||||
render={({ field }) => <TextField label="Порядок сортировки" fullWidth {...field} />}
|
|
||||||
/>
|
|
||||||
<Controller
|
|
||||||
control={form.control}
|
|
||||||
name="published"
|
|
||||||
render={({ field }) => (
|
|
||||||
<FormControlLabel
|
|
||||||
control={<Switch checked={field.value} onChange={(_, v) => field.onChange(v)} />}
|
|
||||||
label="Показывать на публичной странице"
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</Stack>
|
|
||||||
</DialogContent>
|
|
||||||
<DialogActions>
|
|
||||||
<Button onClick={closeDialog}>Отмена</Button>
|
|
||||||
<Button
|
|
||||||
variant="contained"
|
|
||||||
onClick={() => saveMut.mutate()}
|
|
||||||
disabled={
|
|
||||||
saveMut.isPending ||
|
|
||||||
!form.watch('key').trim() ||
|
|
||||||
!form.watch('title').trim() ||
|
|
||||||
!form.watch('body').trim()
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{editing ? 'Сохранить' : 'Создать'}
|
|
||||||
</Button>
|
|
||||||
</DialogActions>
|
|
||||||
</Dialog>
|
|
||||||
</Box>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user