Merge remote-tracking branch 'origin/main' into feat/landing
All checks were successful
it-academy/dry-wash-pl/pipeline/head This commit looks good
it-academy/dry-wash-pl/pipeline/pr-main This commit looks good

This commit is contained in:
RustamRu 2024-11-17 11:22:38 +03:00
commit 5822f5f7b0
12 changed files with 162 additions and 16 deletions

View File

@ -43,5 +43,11 @@
"dry-wash.landing.hero-section.headline": "Оживите свою поездку с помощью экологически чистого ухода!", "dry-wash.landing.hero-section.headline": "Оживите свою поездку с помощью экологически чистого ухода!",
"dry-wash.landing.make-order-button": "Сделать заказ", "dry-wash.landing.make-order-button": "Сделать заказ",
"dry-wash.landing.site-logo": "Логотип компании \u00ABDry Master\u00BB", "dry-wash.landing.site-logo": "Логотип компании \u00ABDry Master\u00BB",
"dry-wash.landing.social-proof-section.heading": "Нас выбирают" "dry-wash.landing.social-proof-section.heading": "Нас выбирают",
"dry-wash.notFound.title": "Страница не найдена",
"dry-wash.notFound.description": "К сожалению, запрашиваемая вами страница не существует.",
"dry-wash.notFound.button.back": " Вернуться на главную",
"dry-wash.errorBoundary.title":"Что-то пошло не так",
"dry-wash.errorBoundary.description": " Мы уже работаем над исправлением проблемы",
"dry-wash.errorBoundary.button.reload": "Перезагрузить страницу"
} }

17
package-lock.json generated
View File

@ -15,6 +15,7 @@
"@emotion/react": "^11.4.1", "@emotion/react": "^11.4.1",
"@emotion/styled": "^11.3.0", "@emotion/styled": "^11.3.0",
"@fontsource/open-sans": "^5.1.0", "@fontsource/open-sans": "^5.1.0",
"@lottiefiles/react-lottie-player": "^3.5.4",
"@types/react": "^18.3.12", "@types/react": "^18.3.12",
"express": "^4.21.1", "express": "^4.21.1",
"framer-motion": "^6.2.8", "framer-motion": "^6.2.8",
@ -3449,6 +3450,17 @@
"tslib": "2" "tslib": "2"
} }
}, },
"node_modules/@lottiefiles/react-lottie-player": {
"version": "3.5.4",
"resolved": "https://registry.npmjs.org/@lottiefiles/react-lottie-player/-/react-lottie-player-3.5.4.tgz",
"integrity": "sha512-2FptWtHQ+o7MzdsMKSvNZ1Mz7xtKSYI0WL9HjZ1r+CvsXR3lbLQUDp7Pwx6qhg0Akm4VluQ+8/D1S1fcr1Ao4w==",
"dependencies": {
"lottie-web": "^5.12.2"
},
"peerDependencies": {
"react": "16 - 18"
}
},
"node_modules/@nodelib/fs.scandir": { "node_modules/@nodelib/fs.scandir": {
"version": "2.1.5", "version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@ -7808,6 +7820,11 @@
"loose-envify": "cli.js" "loose-envify": "cli.js"
} }
}, },
"node_modules/lottie-web": {
"version": "5.12.2",
"resolved": "https://registry.npmjs.org/lottie-web/-/lottie-web-5.12.2.tgz",
"integrity": "sha512-uvhvYPC8kGPjXT3MyKMrL3JitEAmDMp30lVkuq/590Mw9ok6pWcFCwXJveo0t5uqYw1UREQHofD+jVpdjBv8wg=="
},
"node_modules/lru-cache": { "node_modules/lru-cache": {
"version": "10.4.3", "version": "10.4.3",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",

View File

@ -23,6 +23,7 @@
"@emotion/react": "^11.4.1", "@emotion/react": "^11.4.1",
"@emotion/styled": "^11.3.0", "@emotion/styled": "^11.3.0",
"@fontsource/open-sans": "^5.1.0", "@fontsource/open-sans": "^5.1.0",
"@lottiefiles/react-lottie-player": "^3.5.4",
"@types/react": "^18.3.12", "@types/react": "^18.3.12",
"express": "^4.21.1", "express": "^4.21.1",
"framer-motion": "^6.2.8", "framer-motion": "^6.2.8",

View File

@ -2,13 +2,16 @@ import React from 'react';
import { BrowserRouter } from 'react-router-dom'; import { BrowserRouter } from 'react-router-dom';
import Routers from './routes'; import Routers from './routes';
import { ChakraProvider, theme as chakraTheme } from '@chakra-ui/react'; import { ChakraProvider, theme as chakraTheme } from '@chakra-ui/react';
import ErrorBoundary from './components/ErrorBoundary';
const App = () => { const App = () => {
return ( return (
<ChakraProvider theme={chakraTheme}> <ChakraProvider theme={chakraTheme}>
<BrowserRouter> <ErrorBoundary>
<Routers></Routers> <BrowserRouter>
</BrowserRouter> <Routers />
</BrowserRouter>
</ErrorBoundary>
</ChakraProvider> </ChakraProvider>
); );
}; };

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,64 @@
import React, { Component, ErrorInfo, ReactNode } from 'react';
import { Heading, Text, Button, Center, VStack } from '@chakra-ui/react';
import i18next from 'i18next';
interface ErrorBoundaryState {
hasError: boolean;
error: Error | null;
errorInfo: ErrorInfo | null;
}
interface ErrorBoundaryProps {
children: ReactNode;
}
class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
constructor(props: ErrorBoundaryProps) {
super(props);
this.state = {
hasError: false,
error: null,
errorInfo: null,
};
}
static getDerivedStateFromError(): Partial<ErrorBoundaryState> {
return { hasError: true };
}
componentDidCatch(error: Error, errorInfo: ErrorInfo): void {
console.error('Error caught by ErrorBoundary:', error, errorInfo);
this.setState({ error, errorInfo });
}
render() {
const { hasError } = this.state;
//TODO: добавить анимацию после залива 404 страницы
if (hasError) {
return (
<Center minH='100vh'>
<VStack spacing={4} textAlign='center'>
<Heading as='h1' size='2xl'>
{i18next.t('dry-wash.errorBoundary.title')}
</Heading>
<Text fontSize='lg'>
{i18next.t('dry-wash.errorBoundary.description')}
</Text>
<Button
colorScheme='teal'
size='lg'
variant='outline'
onClick={() => window.location.reload()}
>
{i18next.t('dry-wash.errorBoundary.button.reload')}
</Button>
</VStack>
</Center>
);
}
return this.props.children;
}
}
export default ErrorBoundary;

View File

@ -0,0 +1 @@
export { default } from './ErrorBoundary';

View File

@ -3,13 +3,19 @@ import Sidebar from '../Sidebar';
import Orders from '../Orders'; import Orders from '../Orders';
import Masters from '../Masters'; import Masters from '../Masters';
import React from 'react'; import React from 'react';
import { Navigate, Route, Routes } from 'react-router-dom';
const LayoutArm = ({ currentPage, onSelectPage }) => ( const LayoutArm = () => (
<Flex h='100vh'> <Flex h='100vh'>
<Sidebar onSelectPage={onSelectPage} /> <Sidebar />
<Box flex='1' bg='gray.50'> <Box flex='1' bg='gray.50'>
{currentPage === 'orders' && <Orders />} <Routes>
{currentPage === 'masters' && <Masters />} <Route>
<Route index element={<Navigate to='orders' replace />} />
<Route path='orders' element={<Orders />} />
<Route path='masters' element={<Masters />} />
</Route>
</Routes>
</Box> </Box>
</Flex> </Flex>
); );

View File

@ -2,7 +2,9 @@ import { Box, Button, Heading, VStack } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import { Divider } from '@chakra-ui/react'; import { Divider } from '@chakra-ui/react';
import i18next from 'i18next'; import i18next from 'i18next';
const Sidebar = ({ onSelectPage }) => ( import { Link } from 'react-router-dom';
const Sidebar = () => (
<Box <Box
borderRight='1px solid black' borderRight='1px solid black'
bg='gray.50' bg='gray.50'
@ -18,7 +20,8 @@ const Sidebar = ({ onSelectPage }) => (
<VStack align='start' spacing='4'> <VStack align='start' spacing='4'>
<Divider /> <Divider />
<Button <Button
onClick={() => onSelectPage('orders')} as={Link}
to='orders'
w='100%' w='100%'
colorScheme='green' colorScheme='green'
variant='ghost' variant='ghost'
@ -27,7 +30,8 @@ const Sidebar = ({ onSelectPage }) => (
</Button> </Button>
<Divider /> <Divider />
<Button <Button
onClick={() => onSelectPage('masters')} as={Link}
to='masters'
w='100%' w='100%'
colorScheme='green' colorScheme='green'
variant='ghost' variant='ghost'

View File

@ -2,9 +2,7 @@ import React, { useState } from 'react';
import LayoutArm from '../../components/LayoutArm'; import LayoutArm from '../../components/LayoutArm';
const Page = () => { const Page = () => {
const [currentPage, setCurrentPage] = useState('orders'); return <LayoutArm />;
return <LayoutArm currentPage={currentPage} onSelectPage={setCurrentPage} />;
}; };
export default Page; export default Page;

View File

@ -0,0 +1,43 @@
import React from 'react';
import { Text, Button, Center, VStack, Heading } from '@chakra-ui/react';
import { Link } from 'react-router-dom';
import { Player } from '@lottiefiles/react-lottie-player';
import animate from '../../assets/animation/notFound.json';
import i18next from 'i18next';
const NotFound = () => {
return (
<Center minH='100vh'>
<VStack spacing={4} textAlign='center'>
<Player
autoplay
loop
src={animate}
style={{
height: '100%',
width: '100%',
maxHeight: '450px',
maxWidth: '450px',
}}
/>
<Heading fontSize='xl'>
{i18next.t(`dry-wash.arm.notFound.title`)}
</Heading>
<Text fontSize='lg'>
{i18next.t(`dry-wash.arm.notFound.description`)}
</Text>
<Button
as={Link}
to='/dry-wash'
colorScheme='teal'
size='lg'
variant='outline'
>
{i18next.t(`dry-wash.arm.notFound.button.back`)}
</Button>
</VStack>
</Center>
);
};
export default NotFound;

View File

@ -3,6 +3,7 @@ import { Routes, Route } from 'react-router-dom';
import { PageSpinner } from './components'; import { PageSpinner } from './components';
import Arm from './pages/arm'; import Arm from './pages/arm';
import { URLs } from './__data__/urls'; import { URLs } from './__data__/urls';
import NotFound from './pages/notFound/notFound';
const Landing = lazy(() => import('./pages/landing')); const Landing = lazy(() => import('./pages/landing'));
const OrderForm = lazy(() => import('./pages/order-form')); const OrderForm = lazy(() => import('./pages/order-form'));
@ -15,7 +16,8 @@ const Routers = () => {
<Route path={URLs.landing.url} element={<Landing />} /> <Route path={URLs.landing.url} element={<Landing />} />
<Route path={URLs.orderForm.url} element={<OrderForm />} /> <Route path={URLs.orderForm.url} element={<OrderForm />} />
<Route path={URLs.orderView.url} element={<OrderView />} /> <Route path={URLs.orderView.url} element={<OrderView />} />
<Route path='/dry-wash/arm' element={<Arm />}></Route> <Route path='/dry-wash/arm/*' element={<Arm />}></Route>
<Route path='*' element={<NotFound />} />
</Routes> </Routes>
</Suspense> </Suspense>
); );