diff --git a/client/src/app/layout/MainLayout.tsx b/client/src/app/layout/MainLayout.tsx index ddc01f2..04900e2 100644 --- a/client/src/app/layout/MainLayout.tsx +++ b/client/src/app/layout/MainLayout.tsx @@ -18,7 +18,7 @@ export function MainLayout({ children }: PropsWithChildren) { - + {children} @@ -29,32 +29,29 @@ export function MainLayout({ children }: PropsWithChildren) { borderTop: 1, borderColor: 'divider', bgcolor: 'background.default', - py: { xs: 3, md: 4 }, + py: { xs: 4, md: 6 }, }} > - - - + + + Магазин - + Каталог - - Политика конфиденциальности - Изделия ручной работы: вещи с характером и вниманием к деталям. - - + + Покупателям - + Личный кабинет @@ -66,11 +63,11 @@ export function MainLayout({ children }: PropsWithChildren) { - - + + Контакты - + Email:{' '} @@ -97,15 +94,26 @@ export function MainLayout({ children }: PropsWithChildren) { + + + Юридическая информация + + + + Политика конфиденциальности + + + Пользовательское соглашение + + + - - - © {year} {STORE_NAME} - + + + + © {year} {STORE_NAME} + + diff --git a/client/src/app/providers/AppProviders.tsx b/client/src/app/providers/AppProviders.tsx index ad90173..c1eb273 100644 --- a/client/src/app/providers/AppProviders.tsx +++ b/client/src/app/providers/AppProviders.tsx @@ -24,97 +24,135 @@ function AppThemeInner({ children }: PropsWithChildren) { case 'forest': return { ...common, - primary: { main: isDark ? '#4CAF50' : '#2E7D32' }, - secondary: { main: isDark ? '#A1887F' : '#6D4C41' }, - info: { main: isDark ? '#29B6F6' : '#0288D1' }, - success: { main: isDark ? '#66BB6A' : '#2E7D32' }, - warning: { main: isDark ? '#FFB74D' : '#ED6C02' }, - error: { main: isDark ? '#EF5350' : '#D32F2F' }, - divider: isDark ? 'rgba(255,255,255,0.10)' : 'rgba(0,0,0,0.10)', + primary: { main: isDark ? '#8FBC8F' : '#2E8B57' }, + secondary: { main: isDark ? '#CD853F' : '#8B4513' }, + info: { main: isDark ? '#4682B4' : '#1E90FF' }, + success: { main: isDark ? '#90EE90' : '#32CD32' }, + warning: { main: isDark ? '#FFD700' : '#FFA500' }, + error: { main: isDark ? '#F08080' : '#CD5C5C' }, + divider: isDark ? 'rgba(255,255,255,0.12)' : 'rgba(0,0,0,0.08)', text, chip, background: isDark - ? { default: '#0E1510', paper: '#121B14' } - : { default: '#F6FAF6', paper: '#FFFFFF' }, + ? { default: '#0F1720', paper: '#1A242E' } + : { default: '#F8F6F3', paper: '#FFFFFF' }, } case 'ocean': return { ...common, - primary: { main: isDark ? '#42A5F5' : '#1565C0' }, - secondary: { main: isDark ? '#4DD0E1' : '#00838F' }, - info: { main: isDark ? '#4FC3F7' : '#0288D1' }, - success: { main: isDark ? '#26C6DA' : '#00838F' }, - warning: { main: isDark ? '#FFCC80' : '#ED6C02' }, - error: { main: isDark ? '#EF5350' : '#D32F2F' }, - divider: isDark ? 'rgba(255,255,255,0.10)' : 'rgba(0,0,0,0.10)', + primary: { main: isDark ? '#5F9EA0' : '#20B2AA' }, + secondary: { main: isDark ? '#7B68EE' : '#6A5ACD' }, + info: { main: isDark ? '#87CEEB' : '#00BFFF' }, + success: { main: isDark ? '#98FB98' : '#00FA9A' }, + warning: { main: isDark ? '#FFE4B5' : '#FFDAB9' }, + error: { main: isDark ? '#FF6347' : '#FF4500' }, + divider: isDark ? 'rgba(255,255,255,0.12)' : 'rgba(0,0,0,0.08)', text, chip, background: isDark - ? { default: '#0B1220', paper: '#0F172A' } - : { default: '#F6FAFF', paper: '#FFFFFF' }, + ? { default: '#0A1A2A', paper: '#0F1D35' } + : { default: '#F0F8FF', paper: '#FFFFFF' }, } case 'berry': return { ...common, - primary: { main: isDark ? '#BA68C8' : '#7B1FA2' }, - secondary: { main: isDark ? '#F06292' : '#C2185B' }, - info: { main: isDark ? '#64B5F6' : '#1976D2' }, - success: { main: isDark ? '#81C784' : '#2E7D32' }, - warning: { main: isDark ? '#FFB74D' : '#ED6C02' }, - error: { main: isDark ? '#EF5350' : '#D32F2F' }, - divider: isDark ? 'rgba(255,255,255,0.10)' : 'rgba(0,0,0,0.10)', + primary: { main: isDark ? '#9370DB' : '#8A2BE2' }, + secondary: { main: isDark ? '#FF69B4' : '#FF1493' }, + info: { main: isDark ? '#00CED1' : '#00BFFF' }, + success: { main: isDark ? '#00FF7F' : '#7CFC00' }, + warning: { main: isDark ? '#FFD700' : '#FFA500' }, + error: { main: isDark ? '#FF4500' : '#FF6347' }, + divider: isDark ? 'rgba(255,255,255,0.12)' : 'rgba(0,0,0,0.08)', text, chip, background: isDark - ? { default: '#140A17', paper: '#1B0F20' } - : { default: '#FFF7FD', paper: '#FFFFFF' }, + ? { default: '#1A0A1A', paper: '#250E25' } + : { default: '#FFF0F5', paper: '#FFFFFF' }, } case 'craft': default: return { ...common, - primary: { main: isDark ? '#BCAAA4' : '#6D4C41' }, - secondary: { main: isDark ? '#FFCCBC' : '#8D6E63' }, - info: { main: isDark ? '#90CAF9' : '#1976D2' }, - success: { main: isDark ? '#A5D6A7' : '#2E7D32' }, - warning: { main: isDark ? '#FFB74D' : '#ED6C02' }, - error: { main: isDark ? '#EF9A9A' : '#D32F2F' }, - divider: isDark ? 'rgba(255,255,255,0.10)' : 'rgba(0,0,0,0.10)', + primary: { main: isDark ? '#90A4AE' : '#546E7A' }, + secondary: { main: isDark ? '#78909C' : '#78909C' }, + info: { main: isDark ? '#7986CB' : '#3F51B5' }, + success: { main: isDark ? '#66BB6A' : '#43A047' }, + warning: { main: isDark ? '#FFB74D' : '#F57C00' }, + error: { main: isDark ? '#EF5350' : '#D32F2F' }, + divider: isDark ? 'rgba(255,255,255,0.12)' : 'rgba(0,0,0,0.08)', text, chip, background: isDark - ? { default: '#12100F', paper: '#191615' } - : { default: '#FAF8F5', paper: '#FFFFFF' }, + ? { default: '#121212', paper: '#1E1E1E' } + : { default: '#F5F5F5', paper: '#FFFFFF' }, } } })(), shape: { borderRadius: 12 }, typography: { - fontFamily: '"Segoe UI", system-ui, sans-serif', - h4: { fontWeight: 700 }, - h5: { fontWeight: 600 }, + fontFamily: '"Outfit", "Segoe UI", system-ui, sans-serif', + h4: { fontWeight: 700, letterSpacing: '-0.5px' }, + h5: { fontWeight: 600, letterSpacing: '-0.25px' }, + h6: { fontWeight: 600 }, + subtitle1: { fontWeight: 600 }, + subtitle2: { fontWeight: 500 }, + body1: { fontSize: '0.875rem' }, + body2: { fontSize: '0.75rem' }, + button: { textTransform: 'none', fontWeight: 600 }, }, components: { MuiButton: { styleOverrides: { - root: { textTransform: 'none', borderRadius: 12, fontWeight: 600 }, + root: { + textTransform: 'none', + borderRadius: 12, + fontWeight: 600, + transition: 'all 0.2s ease-in-out', + }, contained: { boxShadow: '0 4px 14px 0 rgba(0,0,0,0.15)', '&:hover': { boxShadow: '0 6px 20px 0 rgba(0,0,0,0.25)', - transform: 'translateY(-1px)', + transform: 'translateY(-2px)', + }, + '&:active': { + boxShadow: '0 2px 8px 0 rgba(0,0,0,0.15)', + transform: 'translateY(0)', }, }, outlined: { - '&:hover': { boxShadow: '0 2px 8px 0 rgba(0,0,0,0.1)' }, + border: '1px solid', + '&:hover': { + boxShadow: '0 2px 8px 0 rgba(0,0,0,0.1)', + borderWidth: '2px', + }, + '&:active': { + boxShadow: 'none', + }, + }, + text: { + '&:hover': { + boxShadow: '0 1px 3px 0 rgba(0,0,0,0.1)', + backgroundColor: 'action.hover', + }, + '&:active': { + backgroundColor: 'action.selected', + }, }, }, }, MuiIconButton: { styleOverrides: { root: { - transition: 'all 0.2s ease', - '&:hover': { transform: 'scale(1.1)' }, + transition: 'all 0.2s ease-in-out', + '&:hover': { + backgroundColor: 'action.hover', + transform: 'scale(1.1)', + }, + '&:active': { + backgroundColor: 'action.selected', + transform: 'scale(0.95)', + }, }, }, }, diff --git a/client/src/app/routes/index.tsx b/client/src/app/routes/index.tsx index b40af29..a2b1a20 100644 --- a/client/src/app/routes/index.tsx +++ b/client/src/app/routes/index.tsx @@ -1,5 +1,5 @@ import { lazy, Suspense } from 'react' -import { Navigate, Route, Routes } from 'react-router-dom' +import { Route, Routes } from 'react-router-dom' import { MainLayout } from '@/app/layout/MainLayout' import { AboutPage } from '@/pages/about' // import { AdminLayoutPage } from '@/pages/admin-layout' @@ -9,8 +9,10 @@ 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' +import { TermsPage } from '@/pages/terms' import { SkeletonPage } from '@/shared/ui/SkeletonPage' const AdminLayoutPage = lazy(() => import('@/pages/admin-layout').then((m) => ({ default: m.AdminLayoutPage }))) @@ -36,6 +38,7 @@ export function AppRoutes() { } /> } /> } /> + } /> } /> - } /> + } /> ) diff --git a/client/src/pages/not-found/index.ts b/client/src/pages/not-found/index.ts new file mode 100644 index 0000000..4773243 --- /dev/null +++ b/client/src/pages/not-found/index.ts @@ -0,0 +1 @@ +export { NotFoundPage } from './ui/NotFoundPage' diff --git a/client/src/pages/not-found/ui/NotFoundPage.tsx b/client/src/pages/not-found/ui/NotFoundPage.tsx new file mode 100644 index 0000000..2ac2831 --- /dev/null +++ b/client/src/pages/not-found/ui/NotFoundPage.tsx @@ -0,0 +1,46 @@ +import { Box, Typography, Button, Stack, Paper } from '@mui/material' +import { Link as RouterLink } from 'react-router-dom' + +export function NotFoundPage() { + return ( + + + + 404 + + Страница не найдена + + + Извините, но запрашиваемая страница не существует или была удалена. + + + + + + + + + ) +} diff --git a/client/src/pages/product/ui/ProductPage.tsx b/client/src/pages/product/ui/ProductPage.tsx index 0cc428e..7b95c27 100644 --- a/client/src/pages/product/ui/ProductPage.tsx +++ b/client/src/pages/product/ui/ProductPage.tsx @@ -194,7 +194,14 @@ export function ProductPage() { {reviewsQuery.isLoading && Загрузка отзывов…} {reviewsQuery.isError && Не удалось загрузить отзывы.} {reviewsQuery.data && reviewsQuery.data.total === 0 && ( - Пока нет опубликованных отзывов на этот товар. + + + Отзывов пока нет + + + Будьте первым, кто оставит отзыв на этот товар. Ваше мнение поможет улучшить качество наших изделий. + + )} {reviewsQuery.data && reviewsQuery.data.items.length > 0 && ( diff --git a/client/src/pages/terms/index.ts b/client/src/pages/terms/index.ts new file mode 100644 index 0000000..2f6018a --- /dev/null +++ b/client/src/pages/terms/index.ts @@ -0,0 +1 @@ +export { TermsPage } from './ui/TermsPage' diff --git a/client/src/pages/terms/ui/TermsPage.tsx b/client/src/pages/terms/ui/TermsPage.tsx new file mode 100644 index 0000000..e5340bf --- /dev/null +++ b/client/src/pages/terms/ui/TermsPage.tsx @@ -0,0 +1,211 @@ +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' + +const SITE_URL = STORE_PUBLIC_SITE_URL || (typeof window !== 'undefined' ? window.location.origin : '') + +const OP_NAME = 'Индивидуальный предприниматель Новоселова Наталия Владимировна' +const OP_INN = '402900832341' +const OP_OGRN = '305402922700051' +const OP_ADDR = '248000, Россия, г. Калуга, ул. Никитина, д. 12А' + +const sections = [ + { + title: '1. Общие положения', + items: [ + `1.1. Настоящее Пользовательское соглашение (далее — «Соглашение») определяет порядок и условия использования материалов и сервисов, размещённых в сети Интернет по адресу ${SITE_URL} (далее — «Сайт»), Пользователями данного Сайта.`, + `1.2. Использование Пользователями Сайта означает, что они безоговорочно принимают и обязуются соблюдать все условия настоящего Соглашения.`, + '1.3. В настоящем Соглашении используются следующие термины:', + `— Администратор — ${OP_NAME}, ИНН ${OP_INN}, ОГРН ${OP_OGRN}, адрес: ${OP_ADDR}, которому принадлежат все соответствующие права на Сайт.`, + `— Акцепт — полное и безоговорочное принятие условий настоящего Соглашения, размещённого на Сайте по адресу ${SITE_URL}/terms, осуществляемое путём совершения Пользователем любых действий по использованию Сайта.`, + '— Аутентификационные данные Пользователя — адрес электронной почты Пользователя и пароль (код доступа), которые в совокупности признаются простой электронной подписью Пользователя.', + '— Пользователь — лицо, осуществляющее доступ к Сайту и использующее материалы и сервисы, размещённые на Сайте.', + '— Контент — любое информационно значимое наполнение Сайта, включая фото, текст и иные медиаматериалы.', + '— Личный кабинет — персонализированная часть Сайта, посредством которой обеспечивается обмен информацией между Пользователем и Сайтом.', + '— Персональные данные — любая информация, относящаяся к определённому или определяемому на основании такой информации физическому лицу.', + '— Обработка персональных данных — любое действие (операция) или совокупность действий с персональными данными, включая сбор, запись, систематизацию, накопление, хранение, уточнение, использование, передачу, обезличивание, блокирование, удаление, уничтожение.', + `— Сайт — ресурс в сети Интернет по адресу ${SITE_URL}, представляющий собой совокупность информации и объектов интеллектуальной собственности.`, + ], + }, + { + title: '2. Предмет соглашения', + items: [ + '2.1. В соответствии с настоящим Соглашением Администратор предоставляет любому Пользователю право безвозмездного использования Сайта в пределах его объявленных функциональных возможностей.', + '2.2. Использование Сайта осуществляется в соответствии с принципом «как есть» (as is). Администратор не гарантирует, что Сайт будет работать непрерывно, быстро и без ошибок.', + '2.3. Пользователь считается присоединившимся к Соглашению в соответствии со ст. 438 ГК РФ при совершении любых из следующих действий:', + '— просмотр материалов, размещённых на Сайте;', + '— использование сервисов Сайта;', + '— регистрация в Личном кабинете;', + '— направление сообщений с использованием онлайн-форм на Сайте;', + '— иное использование Сайта.', + '2.4. Используя Сайт, Пользователь подтверждает, что ознакомился с условиями Соглашения в полном объёме и безоговорочно принимает их.', + '2.5. Положения Соглашения не устанавливают между Администратором и Пользователем агентских отношений, отношений товарищества или иных отношений, прямо не предусмотренных Соглашением.', + '2.6. Все возможные споры, вытекающие из Соглашения, подлежат разрешению в соответствии с действующим законодательством РФ.', + ], + }, + { + title: '3. Регистрация', + items: [ + '3.1. Для использования отдельных функций Сайта Пользователю необходимо пройти процедуру регистрации, в результате которой ему будет предоставлен доступ в Личный кабинет.', + '3.2. При регистрации Пользователь обязуется предоставить достоверную и полную информацию и поддерживать её в актуальном состоянии.', + '3.3. В случае предоставления неверной информации Администратор вправе заблокировать Личный кабинет либо удалить учётную запись Пользователя.', + '3.4. Пользователь самостоятельно несёт ответственность за сохранность своих Аутентификационных данных и за все действия, совершённые с их использованием.', + '3.5. Пользователь обязан незамедлительно уведомить Администратора о любом случае несанкционированного доступа к Личному кабинету.', + '3.6. Пользователь не вправе воспроизводить, копировать, продавать и использовать в коммерческих целях Сайт или его Контент без разрешения Администратора.', + '3.7. При регистрации Пользователь даёт согласие на получение информационных и рекламных сообщений от Администратора на указанный адрес электронной почты.', + ], + }, + { + title: '4. Права и обязанности Администратора', + items: [ + '4.1. Администратор вправе осуществлять сбор мнений и отзывов Пользователей для формирования статистических данных и улучшения качества Сайта.', + '4.2. Администратор вправе направлять Пользователю информационные сообщения, связанные с функционированием Сайта, исполнением договоров, восстановлением пароля.', + '4.3. Администратор оставляет за собой право заблокировать Личный кабинет Пользователя в случае нарушения условий Соглашения.', + '4.4. Сайт может быть частично или полностью недоступен по причине проведения технических работ. Администратор вправе приостанавливать работу Сайта по своему усмотрению.', + '4.5. Администратор не несёт ответственности за ошибки, сбои линий связи, неправомерный доступ к информации Пользователя, возникшие не по вине Администратора.', + '4.6. Администратор предпримет разумные усилия для устранения технических сбоев и ошибок, но не гарантирует их полного отсутствия.', + '4.7. Пользователю не предоставляется никаких интеллектуальных прав на Сайт и его составные части, кроме прямо предусмотренных Соглашением.', + ], + }, + { + title: '5. Права и обязанности Пользователя', + items: [ + '5.1. Пользователь обязуется знакомиться с актуальной версией Соглашения при каждом посещении Сайта.', + '5.2. Пользователь обязуется предоставлять достоверную информацию при использовании Сайта.', + '5.3. Пользователь обязуется не совершать действий, нарушающих российское законодательство, нормы морали и нравственности, а также действий, приводящих к нарушению работы Сайта.', + '5.4. Использование материалов Сайта без согласия правообладателей не допускается. При цитировании материалов Сайта ссылка на Сайт обязательна.', + '5.5. Пользователь обязуется не нарушать права и законные интересы третьих лиц, не причинять вред деловой репутации.', + '5.6. Пользователь не вправе нарушать нормальную работу отдельных сервисов и Сайта в целом.', + '5.7. Пользователь обязан самостоятельно отслеживать внесение изменений в настоящее Соглашение.', + '5.8. Пользователь вправе прекратить доступ к Личному кабинету, направив уведомление Администратору.', + ], + }, + { + title: '6. Ограничение ответственности', + items: [ + '6.1. Администратор гарантирует достоверность и полноту только той информации, которую он разместил на Сайте самостоятельно.', + '6.2. Администратор не несёт ответственности за недостоверность информации, размещённой третьими лицами, в том числе Пользователями.', + '6.3. Администратор не гарантирует, что Сайт будет соответствовать требованиям Пользователя, работать непрерывно и без ошибок.', + '6.4. Администратор не несёт ответственности перед Пользователем за любые убытки, включая упущенную выгоду, потерю данных, вред деловой репутации, причинённые в связи с использованием Сайта.', + '6.5. Администратор исходит из того, что все формы на Сайте заполняет непосредственно Пользователь. Ответственность за достоверность предоставленных данных несёт Пользователь.', + '6.6. Администратор не несёт ответственности за утрату или порчу данных в результате невыполнения Пользователем условий Соглашения.', + ], + }, + { + title: '7. Доступ к ресурсам третьих лиц', + items: [ + '7.1. Доступ Пользователя к Сайту может вызывать обращение к интернет-ресурсам третьих лиц (реклама, сбор статистики).', + '7.2. Владельцы таких ресурсов имеют техническую возможность собирать информацию о Пользователях и самостоятельно определяют условия её использования.', + '7.3. При переходе на сторонние ресурсы Пользователи самостоятельно определяют пределы использования своей информации согласно правилам соответствующих ресурсов.', + ], + }, + { + title: '8. Информация, хранящаяся на стороне браузера', + items: [ + '8.1. Администратор использует cookie-файлы для определения уникального идентификатора доступа Пользователя к Сайту.', + '8.2. Цели использования cookie:', + '— поддержка функциональности Сайта, требующей использования cookie;', + '— измерение аудитории Сайта;', + '— определение статистических предпочтений Пользователей;', + '— исследование корреляции статистических данных.', + '8.3. Пользователь может запретить использование cookie в настройках браузера, однако это может привести к частичной или полной потере функциональности Сайта.', + ], + }, + { + title: '9. Согласие на обработку персональных данных', + items: [ + `9.1. Обработка персональных данных Пользователей осуществляется Администратором в соответствии с Политикой конфиденциальности, размещённой по адресу ${SITE_URL}/privacy.`, + '9.2. Передавая свои персональные данные при регистрации или заполнении форм на Сайте, Пользователь даёт согласие на их обработку Администратором.', + '9.3. Администратор обрабатывает следующие персональные данные: Ф. И. О., адрес электронной почты, номер телефона, IP-адрес, тип браузера, данные о действиях на Сайте.', + '9.4. Цели обработки персональных данных: обеспечение функционирования Сайта, оказание информационной поддержки, предоставление персонализированных сервисов, направление информационных сообщений.', + `9.5. Согласие на обработку персональных данных может быть отозвано Пользователем путём направления заявления на адрес электронной почты: ${STORE_EMAIL}.`, + ], + }, + { + title: '10. Изменение условий и расторжение соглашения', + items: [ + '10.1. Соглашение может быть расторгнуто в любое время по инициативе любой из сторон. Администратор уведомляет о расторжении путём размещения информации на Сайте.', + `10.2. Пользователь может расторгнуть Соглашение, направив уведомление на адрес электронной почты: ${STORE_EMAIL}.`, + '10.3. Администратор вправе в одностороннем порядке изменять условия Соглашения. Новая редакция вступает в силу с момента размещения на Сайте.', + '10.4. Продолжение использования Сайта после изменения условий означает согласие Пользователя с новой редакцией. При несогласии Пользователь обязуется прекратить использование Сайта.', + ], + }, + { + title: '11. Информация об Администраторе', + items: [ + `${OP_NAME}`, + `ИНН: ${OP_INN}`, + `ОГРН: ${OP_OGRN}`, + `Адрес: ${OP_ADDR}`, + `Телефон: +7 (900) 000-00-00`, // TODO: заменить на реальный номер телефона + `Email: ${STORE_EMAIL}`, // TODO: заменить на реальный email при настройке STORE_EMAIL + ], + }, +] + +export function TermsPage() { + return ( + + + Пользовательское соглашение + + + + Последнее обновление: 19 мая 2026 г. + + + + {sections.map((section) => ( + + + {section.title} + + + + {section.items.map((item, idx) => ( + + {item} + + ))} + + + ))} + + + ) +} diff --git a/client/src/shared/ui/SchemeSwitcher/SchemeSwitcher.tsx b/client/src/shared/ui/SchemeSwitcher/SchemeSwitcher.tsx index 62e1f0e..c9baf9b 100644 --- a/client/src/shared/ui/SchemeSwitcher/SchemeSwitcher.tsx +++ b/client/src/shared/ui/SchemeSwitcher/SchemeSwitcher.tsx @@ -10,10 +10,10 @@ type Props = { } const SCHEMES: { key: ColorScheme; color: string; label: string; icon: React.ReactNode }[] = [ - { key: 'craft', color: '#6D4C41', label: 'Крафт', icon: }, - { key: 'forest', color: '#2E7D32', label: 'Лес', icon: }, - { key: 'ocean', color: '#1565C0', label: 'Океан', icon: }, - { key: 'berry', color: '#7B1FA2', label: 'Ягоды', icon: }, + { key: 'craft', color: '#546E7A', label: 'Крафт', icon: }, + { key: 'forest', color: '#2E8B57', label: 'Лес', icon: }, + { key: 'ocean', color: '#20B2AA', label: 'Океан', icon: }, + { key: 'berry', color: '#8A2BE2', label: 'Ягоды', icon: }, ] export function SchemeSwitcher({ value, onChange, orientation = 'horizontal' }: Props) { diff --git a/client/src/widgets/reviews-block/ui/ReviewsBlock.tsx b/client/src/widgets/reviews-block/ui/ReviewsBlock.tsx index 0acc819..5bf0127 100644 --- a/client/src/widgets/reviews-block/ui/ReviewsBlock.tsx +++ b/client/src/widgets/reviews-block/ui/ReviewsBlock.tsx @@ -53,7 +53,15 @@ export function ReviewsBlock() { )} {q.isError && Не удалось загрузить отзывы.} {!q.isLoading && !q.isError && q.data && items.length === 0 && ( - Пока нет опубликованных отзывов о товарах. + + + Отзывов пока нет + + + Будьте первым, кто оставит отзыв о наших товарах. Ваше мнение поможет другим покупателям сделать правильный + выбор. + + )} {items.length > 0 && ( @@ -71,8 +79,34 @@ export function ReviewsBlock() { ...(zebra ? { bgcolor: 'action.hover' } : {}), }} > - - + + {r.imageUrl && ( + + + + )} + {initials(r.authorDisplay)} @@ -111,31 +145,6 @@ export function ReviewsBlock() { - {r.imageUrl && ( - - - - )} ) })}