diff --git a/client/src/pages/admin-layout/ui/AdminLayoutPage.tsx b/client/src/pages/admin-layout/ui/AdminLayoutPage.tsx index 72a6674..8dfb726 100644 --- a/client/src/pages/admin-layout/ui/AdminLayoutPage.tsx +++ b/client/src/pages/admin-layout/ui/AdminLayoutPage.tsx @@ -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: }, { to: '/admin/users', label: 'Пользователи', icon: }, { to: '/admin/info', label: 'Инфо-страница', icon: }, + { to: '/admin/notifications', label: 'Оповещения', icon: }, ], [], ) @@ -188,6 +190,7 @@ export function AdminLayoutPage() { } /> } /> } /> + } /> } /> diff --git a/client/src/pages/admin-layout/ui/AdminNotificationsPage.tsx b/client/src/pages/admin-layout/ui/AdminNotificationsPage.tsx new file mode 100644 index 0000000..3508376 --- /dev/null +++ b/client/src/pages/admin-layout/ui/AdminNotificationsPage.tsx @@ -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(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 Загрузка... + + const s = data?.settings + if (!s) return Не удалось загрузить настройки + + const save = (updates: Record) => { + setError(null) + mutation.mutate(updates) + } + + return ( + + + Оповещения + + + Настройка оповещений администратора. + + + {error && ( + + {error} + + )} + {success && ( + + Настройки сохранены + + )} + + + + + Email + + save({ emailEnabled: e.target.checked })} />} + label="Получать уведомления на почту" + /> + + + + + Telegram + + save({ telegramEnabled: e.target.checked })} /> + } + label="Получать уведомления в Telegram" + /> + {s.telegramEnabled && ( + + save({ telegramChatId: e.target.value })} + helperText="Заполняется автоматически при /start бота" + fullWidth + size="small" + /> + + )} + + + + + Типы уведомлений + + + save({ newOrder: e.target.checked })} />} + label="Новый заказ" + /> + save({ newOrderMessage: e.target.checked })} /> + } + label="Сообщение в заказе" + /> + save({ newReview: e.target.checked })} />} + label="Новый отзыв" + /> + save({ authCodeDuplicate: e.target.checked })} /> + } + label="Дублировать код входа в Telegram" + /> + + + + + ) +}