test commit

This commit is contained in:
Kirill
2026-05-21 14:22:03 +05:00
parent 058fa26e12
commit 47124a01a7
21 changed files with 535 additions and 527 deletions
-2
View File
@@ -2,13 +2,11 @@ import { lazy, Suspense } from 'react'
import { Route, Routes } from 'react-router-dom'
import { MainLayout } from '@/app/layout/MainLayout'
import { AboutPage } from '@/pages/about'
// import { AdminLayoutPage } from '@/pages/admin-layout'
import { AuthCallbackPage, AuthPage } from '@/pages/auth'
import { CartPage } from '@/pages/cart'
import { CheckoutPage } from '@/pages/checkout'
import { HomePage } from '@/pages/home'
import { InfoPage } from '@/pages/info'
// import { MeLayoutPage } from '@/pages/me'
import { NotFoundPage } from '@/pages/not-found'
import { PrivacyPolicyPage } from '@/pages/privacy-policy'
import { ProductPage } from '@/pages/product'
+3
View File
@@ -0,0 +1,3 @@
export type { CartItem } from './model/types'
export { fetchMyCart, addToCart, setCartQty, removeCartItem } from './api/cart-api'
export type { CartResponse } from './api/cart-api'
@@ -0,0 +1,7 @@
export {
fetchUserNotificationSettings,
updateUserNotificationSettings,
fetchAdminNotificationSettings,
updateAdminNotificationSettings,
} from './api/notifications-api'
export type { UserNotificationSettings, AdminNotificationSettings } from './api/notifications-api'
+9
View File
@@ -0,0 +1,9 @@
export {
fetchMyOrders,
createOrder,
confirmOrderReceived,
fetchMyOrder,
fetchOrderReviewEligibility,
} from './api/order-api'
export { createOrderPayment, getOrderPaymentStatus, postOrderMessage } from './api/order-api'
export type { OrderListResponse, OrderDetailResponse } from './api/order-api'
+2
View File
@@ -0,0 +1,2 @@
export { fetchPublicProducts, fetchPublicProduct, fetchCategories } from './api/product-api'
export type { PublicProductsResponse } from './api/product-api'
+12
View File
@@ -0,0 +1,12 @@
export {
postProductReview,
uploadReviewImage,
fetchLatestApprovedReviews,
fetchPublicProductReviews,
} from './api/reviews-api'
export type {
PublicReviewFeedItem,
PublicReviewsLatestResponse,
PublicProductReviewItem,
PublicProductReviewsResponse,
} from './api/reviews-api'
+10
View File
@@ -0,0 +1,10 @@
export type { AdminUser, ShippingAddress } from './model/types'
export { fetchAdminUsers, createAdminUser, updateAdminUser, deleteAdminUser } from './api/user-api'
export type { AdminUsersListResponse } from './api/user-api'
export {
fetchMyAddresses,
createMyAddress,
updateMyAddress,
deleteMyAddress,
setMyAddressDefault,
} from './api/address-api'
@@ -60,7 +60,7 @@ export function AdminLayoutPage() {
{ to: '/admin/orders', label: 'Заказы', icon: <ListOrdered /> },
{ to: '/admin/reviews', label: 'Отзывы', icon: <MessageSquare /> },
{ to: '/admin/users', label: 'Пользователи', icon: <Users /> },
{ to: '/admin/notifications', label: 'Оповещения', icon: <Bell /> },
{ to: '/admin/notifications', label: 'Уведомления', icon: <Bell /> },
],
[],
)
@@ -47,10 +47,10 @@ export function AdminNotificationsPage() {
return (
<Box>
<Typography variant="h4" gutterBottom>
Оповещения
Уведомления
</Typography>
<Typography color="text.secondary" sx={{ mb: 3 }}>
Настройка оповещений администратора.
Настройка уведомлений администратора.
</Typography>
{error && (
+1 -1
View File
@@ -57,7 +57,7 @@ export function MeLayoutPage() {
{ to: '/me/messages', label: 'Сообщения', icon: <MessageCircle /> },
{ to: '/me/settings', label: 'Настройки', icon: <Settings /> },
{ to: '/me/addresses', label: 'Адреса доставки', icon: <MapPin /> },
{ to: '/me/notifications', label: 'Оповещения', icon: <Bell /> },
{ to: '/me/notifications', label: 'Уведомления', icon: <Bell /> },
],
[],
)
-134
View File
@@ -1,134 +0,0 @@
import Alert from '@mui/material/Alert'
import Box from '@mui/material/Box'
import Button from '@mui/material/Button'
import Divider from '@mui/material/Divider'
import Stack from '@mui/material/Stack'
import TextField from '@mui/material/TextField'
import Typography from '@mui/material/Typography'
import { useUnit } from 'effector-react'
import { useForm } from 'react-hook-form'
import {
$requestEmailChangeCodeError,
$updateProfileError,
$user,
$verifyEmailChangeError,
requestEmailChangeCodeFx,
updateProfileFx,
verifyEmailChangeFx,
} from '@/shared/model/auth'
import type { AxiosError } from 'axios'
function getApiErrorMessage(error: unknown): string | null {
const e = error as AxiosError<{ error?: string }>
const msg = e?.response?.data?.error
return msg ? String(msg) : null
}
export function MePage() {
const user = useUnit($user)
const pendingEmailReq = useUnit(requestEmailChangeCodeFx.pending)
const pendingEmailVerify = useUnit(verifyEmailChangeFx.pending)
const pendingProfile = useUnit(updateProfileFx.pending)
const errorEmailReq = useUnit($requestEmailChangeCodeError)
const errorProfile = useUnit($updateProfileError)
const errorEmailVerify = useUnit($verifyEmailChangeError)
const emailForm = useForm<{ newEmail: string; code: string }>({
defaultValues: { newEmail: '', code: '' },
mode: 'onChange',
})
const profileForm = useForm<{ displayName: string }>({
defaultValues: { displayName: user?.displayName ? String(user.displayName) : '' },
mode: 'onChange',
})
const emailErrorMsg = getApiErrorMessage(errorEmailReq) ?? getApiErrorMessage(errorEmailVerify)
const profileErrorMsg = getApiErrorMessage(errorProfile)
if (!user) {
return <Alert severity="info">Нужно войти. Перейдите на страницу «Вход».</Alert>
}
return (
<Box>
<Typography variant="h4" gutterBottom>
Профиль
</Typography>
<Typography color="text.secondary" sx={{ mb: 3 }}>
Текущая почта: <b>{user.email}</b>
</Typography>
{emailErrorMsg && (
<Alert severity="error" sx={{ mb: 2 }}>
{emailErrorMsg}
</Alert>
)}
{profileErrorMsg && (
<Alert severity="error" sx={{ mb: 2 }}>
{profileErrorMsg}
</Alert>
)}
<Stack spacing={3} sx={{ maxWidth: 560 }}>
<Box>
<Typography variant="h6" gutterBottom>
Имя / ник
</Typography>
<Stack spacing={2}>
<TextField
label="Имя или ник"
helperText="До 40 символов"
slotProps={{ htmlInput: { maxLength: 40 } }}
{...profileForm.register('displayName')}
/>
<Button
variant="contained"
disabled={pendingProfile}
onClick={() => {
const raw = profileForm.getValues('displayName')
const name = raw.trim()
updateProfileFx({ displayName: name.length ? name : null })
}}
>
Сохранить имя
</Button>
</Stack>
</Box>
<Divider />
<Box>
<Typography variant="h6" gutterBottom>
Смена почты
</Typography>
<Stack spacing={2}>
<TextField label="Новая почта" {...emailForm.register('newEmail')} />
<Button
variant="outlined"
disabled={!emailForm.watch('newEmail') || pendingEmailReq}
onClick={() => requestEmailChangeCodeFx(emailForm.getValues('newEmail').trim())}
>
Отправить код на новую почту
</Button>
<Stack direction={{ xs: 'column', sm: 'row' }} spacing={2}>
<TextField label="Код (6 цифр)" inputMode="numeric" {...emailForm.register('code')} />
<Button
variant="contained"
disabled={emailForm.watch('code').trim().length !== 6 || pendingEmailVerify}
onClick={() =>
verifyEmailChangeFx({
newEmail: emailForm.getValues('newEmail').trim(),
code: emailForm.getValues('code').trim(),
})
}
>
Подтвердить
</Button>
</Stack>
</Stack>
</Box>
</Stack>
</Box>
)
}
@@ -57,7 +57,7 @@ export function NotificationsPage() {
return (
<Box>
<Typography variant="h4" gutterBottom>
Оповещения
Уведомления
</Typography>
<Typography color="text.secondary" sx={{ mb: 3 }}>
Настройте, какие уведомления вы хотите получать на почту.
@@ -78,7 +78,7 @@ export function NotificationsPage() {
onChange={(e) => handleToggle('globalEnabled', e.target.checked)}
/>
}
label={<Typography sx={{ fontWeight: 600 }}>Получать оповещения</Typography>}
label={<Typography sx={{ fontWeight: 600 }}>Получать уведомления</Typography>}
/>
<Typography variant="body2" color="text.secondary" sx={{ ml: 4 }}>
Включите, чтобы получать уведомления о заказах на почту.
+3 -3
View File
@@ -1,7 +1,7 @@
import Box from '@mui/material/Box'
import Paper from '@mui/material/Paper'
import Typography from '@mui/material/Typography'
import { STORE_EMAIL, STORE_PUBLIC_SITE_URL } from '@/shared/config'
import { STORE_EMAIL, STORE_PHONE, STORE_PUBLIC_SITE_URL } from '@/shared/config'
const SITE_URL = STORE_PUBLIC_SITE_URL || (typeof window !== 'undefined' ? window.location.origin : '')
@@ -138,8 +138,8 @@ const sections = [
`ИНН: ${OP_INN}`,
`ОГРН: ${OP_OGRN}`,
`Адрес: ${OP_ADDR}`,
`Телефон: +7 (900) 000-00-00`, // TODO: заменить на реальный номер телефона
`Email: ${STORE_EMAIL}`, // TODO: заменить на реальный email при настройке STORE_EMAIL
`Телефон: ${STORE_PHONE}`,
`Email: ${STORE_EMAIL}`,
],
},
]