feat: add admin notification settings page

This commit is contained in:
Kirill
2026-05-18 11:55:45 +05:00
parent dfec821545
commit 6054ef4c06
2 changed files with 136 additions and 1 deletions
@@ -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>
)
}