Binary files /dev/null and b/public/images/network-error.png differ Binary files /dev/null and b/public/images/not-found.png differ Binary files /dev/null and b/public/images/update-service.png differ @@ -1,3 +1,6 @@ import { NotFoundPage } from '#/views/not-found' +import { getDefaultLayout } from '#/widgets/layouts' + +NotFoundPage.getLayout = getDefaultLayout({ titlePage: 'Страница не найдена' }) export default NotFoundPage @@ -52,6 +52,15 @@ axios.interceptors.response.use(async (response) => { return response }) +axios.interceptors.response.use( + (response) => response, + (error) => { + if (!error.response) { + window.location.href = '/network-error' + } + return error + } +) const inter = Raleway({ subsets: ['latin'] }) @@ -0,0 +1,6 @@ +import ServiceUpdatePage from '#/views/service-update/ui/service-update' +import { getDefaultLayout } from '#/widgets/layouts' + +ServiceUpdatePage.getLayout = getDefaultLayout({ titlePage: 'Обновляемся' }) + +export default ServiceUpdatePage @@ -0,0 +1,6 @@ +import { NetworkError } from '#/views/network-error/' +import { getDefaultLayout } from '#/widgets/layouts' + +NetworkError.getLayout = getDefaultLayout({ titlePage: 'Сетевая ошибка' }) + +export default NetworkError @@ -4,3 +4,13 @@ export const api = axios.create({ validateStatus: () => true, baseURL: process.env.NEXT_PUBLIC_API_HOST, }) + +api.interceptors.response.use( + (response) => response, + (error) => { + if (!error.response) { + window.location.href = '/network-error' + } + return error + } +) @@ -0,0 +1 @@ +export * from './info-page-template' @@ -0,0 +1,141 @@ +.container { + position: relative; + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; + height: 80dvh; + gap: 47px; + + &__content { + display: flex; + flex-direction: column; + + gap: 50px; + h1 { + color: #ffffff; + font-weight: 700; + font-size: 96px; + letter-spacing: -0.02em; + line-height: 1; + margin: 0; + } + + h2 { + color: #ffffff; + font-weight: 600; + font-size: 32px; + letter-spacing: -0.02em; + line-height: 1.2; + margin: 0 0 20px 0; + } + + p { + color: #a4aab5; + font-weight: 500; + font-size: 18px; + letter-spacing: -0.01em; + line-height: 1.4; + margin: 0; + } + } + + &__image { + width: 403px; + height: 382px; + background-size: cover; + } + &__button { + width: fit-content; + padding: 14.5px 51px; + + font-size: 15px; + font-weight: 500; + line-height: 140%; + letter-spacing: -1%; + } +} + +.footer { + bottom: 0; + left: 50%; + transform: translateX(-50%); + position: absolute; + display: flex; + flex-direction: row; + gap: 20px; + justify-content: center; + margin-bottom: 20px; + + & a { + text-decoration: none; + color: #a4aab5; + font-weight: 500; + font-size: 12px; + letter-spacing: -1%; + line-height: 100%; + padding: 4px 9px; + margin: 0; + } + & .accent { + background-color: #272729; + border-radius: 20px; + } +} + +[data-theme='light'] { + & .container__content h1 { + color: #2b2b42; + } + & .container__content h2 { + color: #2b2b42; + } + & .footer .accent { + background-color: #a4aab533; + } +} + +@media screen and (max-width: 950px) { + .container { + flex-direction: column-reverse; + text-align: center; + + &__content { + align-items: center; + } + } + .footer { + display: none; + } +} + +@media screen and (max-width: 600px) { + .container__image { + width: 305px; + height: 289px; + } + .container__content { + width: 95dvw; + } + .container__content h1 { + font-size: 64px; + } + .container__content h2 { + font-size: 28px; + } + .container__content p { + font-size: 16px; + } +} + +@media screen and (max-width: 450px) { + .container__image { + width: 207px; + height: 196px; + } +} +@media screen and (max-width: 400px) { + .container__content h1 { + font-size: 48px; + } +} @@ -0,0 +1,52 @@ +import Link from 'next/link' +import { CommonButton } from '../../button' +import styles from './info-page-template.module.scss' +import Image from 'next/image' + +interface InfoPageTemplateProps { + primaryTitle: string + secondaryTitle: string + description: string + buttonText: string + buttonOnClick: () => void + imageUrl: string + imageAlt: string +} + +export const InfoPageTemplate = ({ + primaryTitle, + secondaryTitle, + description, + buttonText, + buttonOnClick, + imageUrl, + imageAlt, +}: InfoPageTemplateProps) => { + return ( + <> +
+
+

{primaryTitle}

+
+

{secondaryTitle}

+

{description}

+
+ + {buttonText} + +
+ {imageAlt} +
+ + + ) +} @@ -0,0 +1 @@ +export * from './ui' @@ -0,0 +1 @@ +export * from './network-error' @@ -0,0 +1,22 @@ +import React from 'react' +import { useRouter } from 'next/router' +import { NextPageWithLayout } from '#/pages/_app' +import { InfoPageTemplate } from '#/shared/ui/info-page-template' + +export const NetworkError: NextPageWithLayout = () => { + const { push } = useRouter() + + return ( + <> + push('/')} + buttonText='На главную' + imageUrl='/images/network-error.png' + imageAlt='network-error' + /> + + ) +} @@ -0,0 +1 @@ +export * from './ui' @@ -1,13 +1,9 @@ import React, { useEffect } from 'react' -import { Box, Typography } from '@mui/material' -import Link from 'next/link' import { useRouter } from 'next/router' -import { Layout } from '#/app/layout' -import { useAppSelector } from '#/app/store/store' - -const NotFoundPage = () => { - const theme = useAppSelector((state) => state.theme.theme) +import { NextPageWithLayout } from '#/pages/_app' +import { InfoPageTemplate } from '#/shared/ui/info-page-template' +const NotFoundPage: NextPageWithLayout = () => { const { push } = useRouter() useEffect(() => { @@ -17,40 +13,17 @@ const NotFoundPage = () => { }, []) return ( - - - - - Ошибка 404 - - - К сожалению, такая страница не найдена 😢 - - - - Вернуться на главную - - - - - + <> + push('/')} + buttonText='На главную' + imageUrl='/images/not-found.png' + imageAlt='not-found' + /> + ) } @@ -0,0 +1 @@ +export * from './service-update' @@ -0,0 +1,24 @@ +import React from 'react' +import { useRouter } from 'next/router' +import { NextPageWithLayout } from '#/pages/_app' +import { InfoPageTemplate } from '#/shared/ui/info-page-template' + +const ServiceUpdatePage: NextPageWithLayout = () => { + const { push } = useRouter() + + return ( + <> + push('/')} + buttonText='На главную' + imageUrl='/images/update-service.png' + imageAlt='update-service' + /> + + ) +} + +export default ServiceUpdatePage @@ -0,0 +1 @@ +export * from './ui'