feat: add admin notification settings page
This commit is contained in:
@@ -15,7 +15,7 @@ import Typography from '@mui/material/Typography'
|
||||
import useMediaQuery from '@mui/material/useMediaQuery'
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import { useUnit } from 'effector-react'
|
||||
import { FileText, Image, LayoutGrid, ListOrdered, MessageSquare, Store, Users } from 'lucide-react'
|
||||
import { Bell, FileText, Image, LayoutGrid, ListOrdered, MessageSquare, Store, Users } from 'lucide-react'
|
||||
import { Navigate, Route, Routes, useLocation, useNavigate } from 'react-router-dom'
|
||||
import { fetchAdminOrdersSummary } from '@/entities/order/api/admin-order-api'
|
||||
import { AdminCategoriesPage } from '@/pages/admin-categories'
|
||||
@@ -26,6 +26,7 @@ import { AdminProductsPage } from '@/pages/admin-products'
|
||||
import { AdminReviewsPage } from '@/pages/admin-reviews'
|
||||
import { AdminUsersPage } from '@/pages/admin-users'
|
||||
import { $user } from '@/shared/model/auth'
|
||||
import { AdminNotificationsPage } from './AdminNotificationsPage'
|
||||
|
||||
type NavItem = {
|
||||
to: string
|
||||
@@ -61,6 +62,7 @@ export function AdminLayoutPage() {
|
||||
{ to: '/admin/reviews', label: 'Отзывы', icon: <MessageSquare /> },
|
||||
{ to: '/admin/users', label: 'Пользователи', icon: <Users /> },
|
||||
{ to: '/admin/info', label: 'Инфо-страница', icon: <FileText /> },
|
||||
{ to: '/admin/notifications', label: 'Оповещения', icon: <Bell /> },
|
||||
],
|
||||
[],
|
||||
)
|
||||
@@ -188,6 +190,7 @@ export function AdminLayoutPage() {
|
||||
<Route path="reviews" element={<AdminReviewsPage />} />
|
||||
<Route path="users" element={<AdminUsersPage />} />
|
||||
<Route path="info" element={<AdminInfoPage />} />
|
||||
<Route path="notifications" element={<AdminNotificationsPage />} />
|
||||
<Route path="*" element={<Navigate to="/admin" replace />} />
|
||||
</Routes>
|
||||
</Box>
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
import { useState } from 'react'
|
||||
import Alert from '@mui/material/Alert'
|
||||
import Box from '@mui/material/Box'
|
||||
import FormControlLabel from '@mui/material/FormControlLabel'
|
||||
import Stack from '@mui/material/Stack'
|
||||
import Switch from '@mui/material/Switch'
|
||||
import TextField from '@mui/material/TextField'
|
||||
import Typography from '@mui/material/Typography'
|
||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
|
||||
import {
|
||||
fetchAdminNotificationSettings,
|
||||
updateAdminNotificationSettings,
|
||||
} from '@/entities/notification/api/notifications-api'
|
||||
|
||||
export function AdminNotificationsPage() {
|
||||
const queryClient = useQueryClient()
|
||||
const [error, setError] = useState<string | null>(null)
|
||||
const [success, setSuccess] = useState(false)
|
||||
|
||||
const { data, isLoading } = useQuery({
|
||||
queryKey: ['admin', 'notifications', 'settings'],
|
||||
queryFn: fetchAdminNotificationSettings,
|
||||
})
|
||||
|
||||
const mutation = useMutation({
|
||||
mutationFn: updateAdminNotificationSettings,
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['admin', 'notifications', 'settings'] })
|
||||
setSuccess(true)
|
||||
setTimeout(() => setSuccess(false), 3000)
|
||||
},
|
||||
onError: (err: { response?: { data?: { error?: string } } }) => {
|
||||
setError(err.response?.data?.error || 'Ошибка сохранения')
|
||||
},
|
||||
})
|
||||
|
||||
if (isLoading) return <Typography>Загрузка...</Typography>
|
||||
|
||||
const s = data?.settings
|
||||
if (!s) return <Alert severity="error">Не удалось загрузить настройки</Alert>
|
||||
|
||||
const save = (updates: Record<string, unknown>) => {
|
||||
setError(null)
|
||||
mutation.mutate(updates)
|
||||
}
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Typography variant="h4" gutterBottom>
|
||||
Оповещения
|
||||
</Typography>
|
||||
<Typography color="text.secondary" sx={{ mb: 3 }}>
|
||||
Настройка оповещений администратора.
|
||||
</Typography>
|
||||
|
||||
{error && (
|
||||
<Alert severity="error" sx={{ mb: 2 }}>
|
||||
{error}
|
||||
</Alert>
|
||||
)}
|
||||
{success && (
|
||||
<Alert severity="success" sx={{ mb: 2 }}>
|
||||
Настройки сохранены
|
||||
</Alert>
|
||||
)}
|
||||
|
||||
<Stack spacing={3} sx={{ maxWidth: 560 }}>
|
||||
<Box>
|
||||
<Typography variant="h6" gutterBottom>
|
||||
Email
|
||||
</Typography>
|
||||
<FormControlLabel
|
||||
control={<Switch checked={s.emailEnabled} onChange={(e) => save({ emailEnabled: e.target.checked })} />}
|
||||
label="Получать уведомления на почту"
|
||||
/>
|
||||
</Box>
|
||||
|
||||
<Box>
|
||||
<Typography variant="h6" gutterBottom>
|
||||
Telegram
|
||||
</Typography>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Switch checked={s.telegramEnabled} onChange={(e) => save({ telegramEnabled: e.target.checked })} />
|
||||
}
|
||||
label="Получать уведомления в Telegram"
|
||||
/>
|
||||
{s.telegramEnabled && (
|
||||
<Box sx={{ mt: 1, ml: 4 }}>
|
||||
<TextField
|
||||
label="Telegram Chat ID"
|
||||
value={s.telegramChatId || ''}
|
||||
onChange={(e) => save({ telegramChatId: e.target.value })}
|
||||
helperText="Заполняется автоматически при /start бота"
|
||||
fullWidth
|
||||
size="small"
|
||||
/>
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
|
||||
<Box>
|
||||
<Typography variant="h6" gutterBottom>
|
||||
Типы уведомлений
|
||||
</Typography>
|
||||
<Stack spacing={1}>
|
||||
<FormControlLabel
|
||||
control={<Switch checked={s.newOrder} onChange={(e) => save({ newOrder: e.target.checked })} />}
|
||||
label="Новый заказ"
|
||||
/>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Switch checked={s.newOrderMessage} onChange={(e) => save({ newOrderMessage: e.target.checked })} />
|
||||
}
|
||||
label="Сообщение в заказе"
|
||||
/>
|
||||
<FormControlLabel
|
||||
control={<Switch checked={s.newReview} onChange={(e) => save({ newReview: e.target.checked })} />}
|
||||
label="Новый отзыв"
|
||||
/>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Switch checked={s.authCodeDuplicate} onChange={(e) => save({ authCodeDuplicate: e.target.checked })} />
|
||||
}
|
||||
label="Дублировать код входа в Telegram"
|
||||
/>
|
||||
</Stack>
|
||||
</Box>
|
||||
</Stack>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user