Compare commits

..

1 Commits

Author SHA1 Message Date
d1d92c63e8 feat: add ErrorBoundary page (#23)
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
2024-11-16 20:09:02 +03:00
8 changed files with 86 additions and 25 deletions

View File

@@ -28,6 +28,8 @@
"dry-wash.arm.master.drawer.button.cancel": "Отменить", "dry-wash.arm.master.drawer.button.cancel": "Отменить",
"dry-wash.arm.master.sideBar.title": " Сухой мастер", "dry-wash.arm.master.sideBar.title": " Сухой мастер",
"dry-wash.arm.master.sideBar.title.master": "Мастера", "dry-wash.arm.master.sideBar.title.master": "Мастера",
"dry-wash.arm.master.sideBar.title.orders": "Заказы" "dry-wash.arm.master.sideBar.title.orders": "Заказы",
"dry-wash.errorBoundary.title":"Что-то пошло не так",
"dry-wash.errorBoundary.description": " Мы уже работаем над исправлением проблемы",
"dry-wash.errorBoundary.button.reload": "Перезагрузить страницу"
} }

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>
); );
}; };

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,19 +3,13 @@ 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 = () => ( const LayoutArm = ({ currentPage, onSelectPage }) => (
<Flex h='100vh'> <Flex h='100vh'>
<Sidebar /> <Sidebar onSelectPage={onSelectPage} />
<Box flex='1' bg='gray.50'> <Box flex='1' bg='gray.50'>
<Routes> {currentPage === 'orders' && <Orders />}
<Route> {currentPage === 'masters' && <Masters />}
<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,9 +2,7 @@ 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';
import { Link } from 'react-router-dom'; const Sidebar = ({ onSelectPage }) => (
const Sidebar = () => (
<Box <Box
borderRight='1px solid black' borderRight='1px solid black'
bg='gray.50' bg='gray.50'
@@ -20,8 +18,7 @@ const Sidebar = () => (
<VStack align='start' spacing='4'> <VStack align='start' spacing='4'>
<Divider /> <Divider />
<Button <Button
as={Link} onClick={() => onSelectPage('orders')}
to='orders'
w='100%' w='100%'
colorScheme='green' colorScheme='green'
variant='ghost' variant='ghost'
@@ -30,8 +27,7 @@ const Sidebar = () => (
</Button> </Button>
<Divider /> <Divider />
<Button <Button
as={Link} onClick={() => onSelectPage('masters')}
to='masters'
w='100%' w='100%'
colorScheme='green' colorScheme='green'
variant='ghost' variant='ghost'

View File

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

View File

@@ -16,10 +16,9 @@ const Routers = () => {
<Route path='order-form' element={<OrderForm />} /> <Route path='order-form' element={<OrderForm />} />
<Route path='order-view' element={<OrderView />} /> <Route path='order-view' element={<OrderView />} />
</Route> </Route>
<Route path='/dry-wash/arm/*' element={<Arm />}></Route> <Route path='/dry-wash/arm' element={<Arm />}></Route>
</Routes> </Routes>
</Suspense> </Suspense>
); );
}; };