Compare commits

..

10 Commits

Author SHA1 Message Date
5d208b1fc5 feat: delete word test(#22)
Some checks are pending
it-academy/dry-wash-pl/pipeline/pr-main Build started...
it-academy/dry-wash-pl/pipeline/head This commit looks good
2024-11-17 11:16:23 +03:00
1839136c9f feat: add not found page (#22) 2024-11-17 11:16:16 +03:00
a6ec94785a feat: test (#22) 2024-11-17 11:14:09 +03:00
18ca96bfe9 Merge pull request 'feat: add ErrorBoundary page (#23)' (#28) from feature/errorBoundary into main
Some checks failed
it-academy/dry-wash-pl/pipeline/pr-feat/landing There was a failure building this commit
Reviewed-on: #28
2024-11-17 11:07:38 +03:00
db918ba7c7 Merge pull request 'feat: add router to the arm page (#14)' (#20) from feature/router-arm into main
Some checks failed
it-academy/dry-wash-pl/pipeline/pr-feat/landing There was a failure building this commit
Reviewed-on: #20
2024-11-17 11:02:45 +03:00
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
dedc7e1608 feat: convert link to button (#14)
All checks were successful
it-academy/dry-wash-pl/pipeline/pr-main This commit looks good
it-academy/dry-wash-pl/pipeline/head This commit looks good
2024-11-16 18:24:51 +03:00
1c8348dee5 Merge remote-tracking branch 'origin/feature/router-arm' into feature/router-arm
All checks were successful
it-academy/dry-wash-pl/pipeline/pr-main This commit looks good
# Conflicts:
#	src/components/Sidebar/Sidebar.tsx
#	src/routes.tsx
2024-11-16 17:26:22 +03:00
04e4d011ff feat: add router to the arm page (#14) 2024-11-16 17:05:21 +03:00
116e883e91 feat: add router to the arm page (#14) 2024-11-09 19:34:12 +03:00
19 changed files with 183 additions and 88 deletions

View File

@@ -28,6 +28,11 @@
"dry-wash.arm.master.drawer.button.cancel": "Отменить",
"dry-wash.arm.master.sideBar.title": " Сухой мастер",
"dry-wash.arm.master.sideBar.title.master": "Мастера",
"dry-wash.arm.master.sideBar.title.orders": "Заказы"
"dry-wash.arm.master.sideBar.title.orders": "Заказы",
"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": "Перезагрузить страницу"
}

26
package-lock.json generated
View File

@@ -9,12 +9,13 @@
"version": "0.0.0",
"license": "ISC",
"dependencies": {
"@brojs/cli": "^1.6.2",
"@brojs/cli": "^1.6.1",
"@chakra-ui/icons": "^2.2.4",
"@chakra-ui/react": "^2.4.2",
"@emotion/react": "^11.4.1",
"@emotion/styled": "^11.3.0",
"@fontsource/open-sans": "^5.1.0",
"@lottiefiles/react-lottie-player": "^3.5.4",
"@types/react": "^18.3.12",
"express": "^4.21.1",
"framer-motion": "^6.2.8",
@@ -1564,10 +1565,9 @@
}
},
"node_modules/@brojs/cli": {
"version": "1.6.2",
"resolved": "https://git.bro-js.ru/api/packages/bro-js/npm/%40brojs%2Fcli/-/1.6.2/cli-1.6.2.tgz",
"integrity": "sha512-IDGX5SMt1VQxW2TfY6onazeSjQgUaRut4rwRZVWgBfzHrdp7cHgobciQkF65baT8SfAeaM3w/XHaQr8X1VKGEg==",
"license": "ISC",
"version": "1.6.1",
"resolved": "https://git.bro-js.ru/api/packages/bro-js/npm/%40brojs%2Fcli/-/1.6.1/cli-1.6.1.tgz",
"integrity": "sha512-jcRv68xUxQKYdVOH+eFcuV2DquOU1qHqduozghho02aGNUN8/oB2RL5WQ8ssi4wPJ+HpwRpmpqcqQAnnb9F7Cg==",
"dependencies": {
"@brojs/dev-server": "^1.6.1",
"@brojs/fire.app": "^1.6.1",
@@ -3448,6 +3448,17 @@
"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": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@@ -7807,6 +7818,11 @@
"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": {
"version": "10.4.3",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",

View File

@@ -17,12 +17,13 @@
"author": "",
"license": "ISC",
"dependencies": {
"@brojs/cli": "^1.6.2",
"@brojs/cli": "^1.6.1",
"@chakra-ui/icons": "^2.2.4",
"@chakra-ui/react": "^2.4.2",
"@emotion/react": "^11.4.1",
"@emotion/styled": "^11.3.0",
"@fontsource/open-sans": "^5.1.0",
"@lottiefiles/react-lottie-player": "^3.5.4",
"@types/react": "^18.3.12",
"express": "^4.21.1",
"framer-motion": "^6.2.8",

View File

@@ -1,24 +0,0 @@
import { generatePath } from "react-router-dom";
import { getNavigationValue } from "@brojs/cli";
import { Order } from "../models";
export const URLs = {
landing: {
url: getNavigationValue("dry-wash.main"),
getUrl() {
return this.url;
}
},
orderForm: {
url: getNavigationValue("dry-wash.create"),
getUrl() {
return this.url;
}
},
orderView: {
url: getNavigationValue("dry-wash.view.order"),
getUrl(orderId: Order.Id) {
return generatePath(this.url, { orderId });
}
}
};

View File

@@ -2,13 +2,16 @@ import React from 'react';
import { BrowserRouter } from 'react-router-dom';
import Routers from './routes';
import { ChakraProvider, theme as chakraTheme } from '@chakra-ui/react';
import ErrorBoundary from './components/ErrorBoundary';
const App = () => {
return (
<ChakraProvider theme={chakraTheme}>
<BrowserRouter>
<Routers></Routers>
</BrowserRouter>
<ErrorBoundary>
<BrowserRouter>
<Routers />
</BrowserRouter>
</ErrorBoundary>
</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 Masters from '../Masters';
import React from 'react';
import { Navigate, Route, Routes } from 'react-router-dom';
const LayoutArm = ({ currentPage, onSelectPage }) => (
const LayoutArm = () => (
<Flex h='100vh'>
<Sidebar onSelectPage={onSelectPage} />
<Sidebar />
<Box flex='1' bg='gray.50'>
{currentPage === 'orders' && <Orders />}
{currentPage === 'masters' && <Masters />}
<Routes>
<Route>
<Route index element={<Navigate to='orders' replace />} />
<Route path='orders' element={<Orders />} />
<Route path='masters' element={<Masters />} />
</Route>
</Routes>
</Box>
</Flex>
);

View File

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

View File

@@ -1,11 +1,10 @@
import React, { FC } from 'react';
import { Link as RouterLink } from 'react-router-dom';
import { ButtonProps, Button } from '@chakra-ui/react';
import { URLs } from '../../../__data__/urls';
export const CtaButton: FC<ButtonProps> = (props) => {
return (
<Button as={RouterLink} to={URLs.orderForm.getUrl()} colorScheme='primary' {...props}>
<Button as={RouterLink} to='/dry-wash/order-form' colorScheme='primary' {...props}>
Сделать заказ
</Button>
);

View File

@@ -1,5 +1,3 @@
import { Order } from "../../models";
type ReviewItem = {
id: string;
firstname: string;
@@ -33,10 +31,4 @@ export const mockReviews: ReviewItem[] = [
picture: 'https://img.freepik.com/free-photo/portrait-young-blonde-woman-with-plait-polka-dot-blouse_273609-10490.jpg',
text: "К сожалению, мой опыт с сухой мойкой автомобилей оказался неудачным. Ожидала увидеть чистую машину после процедуры, но многие участки остались незаделанными. Кроме того, процедура заняла больше времени, чем мне обещали. Возможно, в этом конкретном центре что-то пошло не так, но я бы не стала повторно обращаться за этой услугой."
},
].map((data, i) => ({ id: `review${i}`, ...data }));
export const mockOrders: Order.View[] = [
{ id: 'id1' },
{ id: 'id2' },
{ id: 'id3' },
];
].map((data, i) => ({ id: `review${i}`, ...data }));

View File

@@ -1 +0,0 @@
export * as Order from './order';

View File

@@ -1,5 +0,0 @@
export type Id = string;
export type View = {
id: Id;
};

View File

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

View File

@@ -1,5 +1,5 @@
import React, { FC } from 'react';
import { Container, VStack } from '@chakra-ui/react';
import { Box, Container, VStack } from '@chakra-ui/react';
import {
BenefitsSection,
Footer,
@@ -19,12 +19,14 @@ const Page: FC = () => {
bg='white'
centerContent
>
<VStack w='full' h='full' alignItems='stretch' flexGrow={1}>
<VStack w='full' h='full' alignItems='stretch'>
<HeroSection flexShrink={0} />
<VStack as='main' flexGrow={1}>
<BenefitsSection />
<SocialProofSection />
</VStack>
<Box flexGrow={1}>
<VStack as='main'>
<BenefitsSection />
<SocialProofSection />
</VStack>
</Box>
<Footer />
</VStack>
</Container>

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

@@ -1,20 +1,7 @@
import React from 'react';
import { Link as RouterLink } from 'react-router-dom';
import { Button } from '@chakra-ui/react';
import { URLs } from '../../__data__/urls';
import { mockOrders } from '../../mocks/landing';
import React from "react";
const Page = () => {
return (
<>
<h1>Order form</h1>
{mockOrders.map(({ id }) => (
<Button key={id} as={RouterLink} to={URLs.orderView.getUrl(id)}>
Посмотреть заказ {id}
</Button>
))}
</>
);
return <h1>Order form </h1>;
};
export default Page;

View File

@@ -2,7 +2,7 @@ import React, { lazy, Suspense } from 'react';
import { Routes, Route } from 'react-router-dom';
import { PageSpinner } from './components';
import Arm from './pages/arm';
import { URLs } from './__data__/urls';
import NotFound from './pages/notFound/notFound';
const Landing = lazy(() => import('./pages/landing'));
const OrderForm = lazy(() => import('./pages/order-form'));
@@ -12,10 +12,13 @@ const Routers = () => {
return (
<Suspense fallback={<PageSpinner />}>
<Routes>
<Route path={URLs.landing.url} element={<Landing />} />
<Route path={URLs.orderForm.url} element={<OrderForm />} />
<Route path={URLs.orderView.url} element={<OrderView />} />
<Route path='/dry-wash/arm' element={<Arm />}></Route>
<Route path='/dry-wash'>
<Route index element={<Landing />} />
<Route path='order-form' element={<OrderForm />} />
<Route path='order-view' element={<OrderView />} />
</Route>
<Route path='/dry-wash/arm/*' element={<Arm />}></Route>
<Route path='*' element={<NotFound />} />
</Routes>
</Suspense>
);