Binary files /dev/null and b/public/images/promo-cards/grok-image.png differ @@ -496,8 +496,8 @@ button { @media (max-width: 599px) { .MuiSnackbar-root { - left: 50% !important; - right: auto !important; - transform: translateX(-50%) !important; + left: 20px !important; + right: 20px !important; + transform: none !important; } } \ No newline at end of file @@ -0,0 +1,93 @@ +.banner { + position: fixed; + z-index: 9999; + background: #1d1d21; + border: 1px solid rgba(164, 170, 181, 0.1); + border-radius: 16px; + padding: 20px; + display: flex; + flex-direction: column; + gap: 24px; +} + +.desktop { + right: 24px; + bottom: 24px; + width: 450px; +} + +.mobile { + left: 50%; + bottom: 16px; + transform: translateX(-50%); + width: calc(100% - 32px); + max-width: 335px; +} + +.content { + display: flex; + flex-direction: column; + gap: 12px; +} + +.title { + font-size: 24px; + font-weight: 600; + color: #fff; + line-height: 1; +} + +.text { + font-size: 14px; + color: #a4aab5; + line-height: 1.4; +} + +.link { + color: #8280ff; + text-decoration: underline; +} + +.actions { + display: flex; + flex-direction: column; + gap: 10px; +} + +.row { + display: flex; + gap: 10px; +} + +.btnPrimary { + flex: 1; + height: 40px; + border-radius: 10px; + background: #fff; + color: #000; + font-size: 14px; + font-weight: 500; + cursor: pointer; +} + +.btnOutline { + width: 100%; + height: 40px; + border: 1px solid #a4aab5; + border-radius: 10px; + background: transparent; + color: #fff; + font-size: 14px; + font-weight: 500; + cursor: pointer; +} + +.mobile .row { + flex-direction: column; +} + +.mobile .btnPrimary, +.mobile .btnOutline { + width: 100%; + flex: none; +} @@ -0,0 +1,73 @@ +import React from 'react' +import Link from 'next/link' +import { useSession } from 'next-auth/react' + +import { useAppSelector } from '#/app/store/store' +import { getDeviceType } from '#/shared/lib/helpers' +import { initYandexMetrika, stopYandexMetrika } from '#/shared/lib/yandex-metrika' + +import styles from './cookie-consent.module.scss' + +function getConsent(): string | null { + if (typeof window === 'undefined') return null + const value = localStorage.getItem('cookie-consent') + if (value === 'all' || value === 'necessary' || value === 'declined') return value + return null +} + +export function CookieConsent() { + const { status } = useSession() + const account_type = useAppSelector((state) => state.user.account_type) + const meStatus = useAppSelector((state) => state.user.status) + const [consent, setConsent] = React.useState(undefined) + const desktop = getDeviceType() === 'desktop' + + React.useEffect(() => { + if (meStatus !== 'succeeded') return + if (account_type.startsWith('business')) { + stopYandexMetrika() + return + } + const stored = getConsent() + setConsent(stored) + if (stored === 'all') initYandexMetrika() + }, [account_type, meStatus]) + + const choose = (value: string) => { + localStorage.setItem('cookie-consent', value) + setConsent(value) + if (value === 'all') initYandexMetrika() + } + + if (status !== 'authenticated' || meStatus !== 'succeeded') return null + if (account_type.startsWith('business') || consent !== null) return null + + return ( +
+
+

Cookies и аналитика

+

+ Мы используем технические cookies для работы сайта и аналитические cookies для улучшения + сервиса. Подробнее — в{' '} + + Политике обработки персональных данных + + . +

+
+
+
+ + +
+ +
+
+ ) +} @@ -15,6 +15,7 @@ import { pingFangFont } from '#/shared/lib/constants/font/font' import { getDeviceType } from '#/shared/lib/helpers' import { useBlockTelegram } from '#/shared/lib/hooks/use-block-telegram' import { useEnv } from '#/shared/lib/hooks/use-env' +import { CookieConsent } from '#/features/cookie-consent/ui/cookie-consent' import { Providers } from '#/widgets/providers' import { setupAxios } from '#/shared/api/axios-interceptors' @@ -70,6 +71,7 @@ function AppContent({ {Component.getLayout ? Component.getLayout() : } + @@ -3,37 +3,9 @@ import { Head, Html, Main, NextScript } from 'next/document' export default function Document() { return ( - -