diff --git a/src/__data__/service/landing.api.ts b/src/__data__/service/landing.api.ts index d42f2cd..47095a1 100644 --- a/src/__data__/service/landing.api.ts +++ b/src/__data__/service/landing.api.ts @@ -1,14 +1,23 @@ -import { GetOrder } from "../../models/api"; +import { GetOrder, CreateOrder } from "../../models/api"; import { api } from "./api"; import { extractBodyFromResponse, extractErrorMessageFromResponse } from "./utils"; export const landingApi = api.injectEndpoints({ - endpoints: ({ query }) => ({ + endpoints: ({ mutation, query }) => ({ getOrder: query({ query: ({ orderId }) => `/order/${orderId}`, transformResponse: extractBodyFromResponse, transformErrorResponse: extractErrorMessageFromResponse, - }) + }), + createOrder: mutation({ + query: ({ body }) => ({ + url: `/order/create`, + params: { body }, + method: 'POST' + }), + transformResponse: extractBodyFromResponse, + transformErrorResponse: extractErrorMessageFromResponse, + }), }) }); diff --git a/src/api/index.ts b/src/api/index.ts deleted file mode 100644 index c8f65fc..0000000 --- a/src/api/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './landing'; \ No newline at end of file diff --git a/src/api/landing.tsx b/src/api/landing.tsx deleted file mode 100644 index 4c84e6c..0000000 --- a/src/api/landing.tsx +++ /dev/null @@ -1,65 +0,0 @@ -import { getConfigValue } from '@brojs/cli'; -import { useState } from 'react'; - -import { CreateOrder } from '../models/api'; - -import { QueryState, Trigger } from './types'; - -enum LandingEndpoints { - ORDER_CREATE = '/order/create', -} - -const endpoint = getConfigValue('dry-wash.api'); - -const useCreateOrderMutation = (): [ - Trigger['data']>, - QueryState, -] => { - const [isLoading, setIsLoading] = useState['isLoading']>(false); - const [isSuccess, setIsSuccess] = useState['isSuccess']>(); - const [data, setData] = useState['data']>(); - const [isError, setIsError] = useState['isError']>(); - const [error, setError] = useState['error']>(); - - const createOrder = async ({ body }: CreateOrder.Params) => { - setIsLoading(true); - - try { - const response = await fetch( - `${endpoint}${LandingEndpoints.ORDER_CREATE}`, - { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify(body), - }, - ); - - if (!response.ok) { - const errorResponseObject = - (await response.json()) as QueryState['error']; - setIsError(true); - setError(errorResponseObject); - throw errorResponseObject; - } - - const dataResponseObject = - (await response.json()) as QueryState['data']; - setIsSuccess(true); - setData(dataResponseObject); - - return dataResponseObject; - } catch (error) { - setIsError(true); - setError(error); - throw error; - } finally { - setIsLoading(false); - } - }; - - return [createOrder, { isLoading, isSuccess, data, isError, error }]; -}; - -export { useCreateOrderMutation }; diff --git a/src/api/types.ts b/src/api/types.ts deleted file mode 100644 index 98d4848..0000000 --- a/src/api/types.ts +++ /dev/null @@ -1,22 +0,0 @@ -export type QueryData = { - success: true; - body: D; -}; - -export type QueryErrorData = { - success: false; - error: string; -}; - -export type QueryState = { - isLoading: boolean; - isSuccess: boolean; - data: QueryData; - isError: boolean; - error: { - status: number; - data: QueryErrorData; - }; -}; - -export type Trigger = (params: P) => Promise; diff --git a/src/models/api/common.ts b/src/models/api/common.ts index 7f24440..e8451b9 100644 --- a/src/models/api/common.ts +++ b/src/models/api/common.ts @@ -5,6 +5,8 @@ type SuccessResponse = { export type ErrorMessage = string; +export const isErrorMessage = (error: unknown): error is ErrorMessage => typeof error === 'string'; + type ErrorResponse = { success: false; message: ErrorMessage; diff --git a/src/pages/order-create/helper.ts b/src/pages/order-create/helper.ts index d3c3f2e..9771d0c 100644 --- a/src/pages/order-create/helper.ts +++ b/src/pages/order-create/helper.ts @@ -1,7 +1,13 @@ import dayjs from "dayjs"; +import { useToast } from "@chakra-ui/react"; +import { useNavigate } from "react-router-dom"; +import { useEffect } from "react"; +import { useTranslation } from "react-i18next"; import { Order } from "../../models/landing"; import { OrderFormValues } from "../../components/order-form"; +import { isErrorMessage } from "../../models/api"; +import { URLs } from '../../__data__/urls'; const removeAllSpaces = (str: string) => str.replace(/\s+/g, ''); @@ -26,4 +32,40 @@ export const formatFormValues = ({ phone, carNumber, carBody, carColor, carLocat end: dayjs(availableDatetimeEnd).toISOString(), } }; -}; \ No newline at end of file +}; + +export const useHandleCreateOrderMutationResponse = (query: { + isSuccess: boolean; + data?: { + id: Parameters[0]; + }; + isError: boolean; + error?: unknown; +}) => { + const toast = useToast(); + const navigate = useNavigate(); + const { t } = useTranslation('~', { + keyPrefix: 'dry-wash.order-create.create-order-query', + }); + + useEffect(() => { + if (query.isError) { + toast({ + status: 'error', + title: t('error.title'), + description: isErrorMessage(query.error) ? query.error : undefined, + }); + } + }, [query.isError]); + + useEffect(() => { + if (query.isSuccess) { + const orderId = query.data.id; + navigate({ pathname: URLs.orderView.getUrl(orderId) }); + toast({ + status: 'success', + title: t('success.title'), + }); + } + }, [query.isSuccess]); +}; diff --git a/src/pages/order-create/index.tsx b/src/pages/order-create/index.tsx index 4b91eb1..acb21fe 100644 --- a/src/pages/order-create/index.tsx +++ b/src/pages/order-create/index.tsx @@ -1,41 +1,27 @@ import React, { FC } from 'react'; import { useTranslation } from 'react-i18next'; -import { Container, Heading, useToast, VStack } from '@chakra-ui/react'; -import { useNavigate } from 'react-router-dom'; +import { Container, Heading, VStack } from '@chakra-ui/react'; import { withLandingThemeProvider } from '../../containers'; import { OrderForm, OrderFormProps } from '../../components/order-form'; -import { useCreateOrderMutation } from '../../api'; -import { URLs } from '../../__data__/urls'; +import { landingApi } from '../../__data__/service/landing.api'; -import { formatFormValues } from './helper'; +import { + formatFormValues, + useHandleCreateOrderMutationResponse, +} from './helper'; const Page: FC = () => { const { t } = useTranslation('~', { keyPrefix: 'dry-wash.order-create', }); - const [createOrder, createOrderMutation] = useCreateOrderMutation(); - - const toast = useToast(); - const navigate = useNavigate(); + const [createOrder, createOrderMutation] = + landingApi.useCreateOrderMutation(); + useHandleCreateOrderMutationResponse(createOrderMutation); const onOrderFormSubmit: OrderFormProps['onSubmit'] = (values) => { - createOrder({ body: formatFormValues(values) }) - .then(({ body: { id: orderId } }) => { - navigate({ pathname: URLs.orderView.getUrl(orderId) }); - toast({ - status: 'success', - title: t('create-order-query.success.title'), - }); - }) - .catch(({ error: errorMessage }) => { - toast({ - status: 'error', - title: t('create-order-query.error.title'), - description: errorMessage, - }); - }); + createOrder({ body: formatFormValues(values) }); }; return ( diff --git a/src/pages/order-view/index.tsx b/src/pages/order-view/index.tsx index a500250..b5039ca 100644 --- a/src/pages/order-view/index.tsx +++ b/src/pages/order-view/index.tsx @@ -19,7 +19,7 @@ import { import { OrderDetails } from '../../components/order-view'; import { Order } from '../../models/landing'; import { landingApi } from '../../__data__/service/landing.api'; -import { ErrorMessage } from '../../models/api'; +import { isErrorMessage } from '../../models/api'; import { FEATURE } from '../../__data__/features'; const Page: FC = () => { @@ -45,7 +45,7 @@ const Page: FC = () => { } : undefined, ); - const errorMessage = error as ErrorMessage; + const errorMessage = isErrorMessage(error) ? error : undefined; return ( @@ -91,7 +91,9 @@ const Page: FC = () => { {t('get-order-query.error.title')} - {errorMessage} + {errorMessage && ( + {errorMessage} + )} )} diff --git a/stubs/api/admin.js b/stubs/api/admin.js index 88e000b..cf071cf 100644 --- a/stubs/api/admin.js +++ b/stubs/api/admin.js @@ -2,7 +2,7 @@ /* eslint-disable @typescript-eslint/no-require-imports */ const router = require('express').Router(); -const STUBS = { masters: 'success', orders: 'success', orderView: 'success-pending' }; +const STUBS = { masters: 'success', orders: 'success', orderCreate: 'success', orderView: 'success-pending' }; router.get('/set/:name/:value', (req, res) => { const { name, value } = req.params; @@ -14,19 +14,24 @@ router.get('/set/:name/:value', (req, res) => { router.get('/', (req, res) => { res.send(`
-
+
Мастера ${generateRadioInput('masters', 'success')} ${generateRadioInput('masters', 'error')} ${generateRadioInput('masters', 'empty')}
-
+
Заказы ${generateRadioInput('orders', 'success')} ${generateRadioInput('orders', 'error')} ${generateRadioInput('orders', 'empty')}
-
+
+ Лендинг - Сделать заказ + ${generateRadioInput('orderCreate', 'success')} + ${generateRadioInput('orderCreate', 'error')} +
+
Лендинг - Детали заказа ${generateRadioInput('orderView', 'success-pending')} ${generateRadioInput('orderView', 'success-working')} diff --git a/stubs/api/index.js b/stubs/api/index.js index f21ace4..3ddef8b 100644 --- a/stubs/api/index.js +++ b/stubs/api/index.js @@ -87,7 +87,15 @@ router.get('/order/:orderId', ({ params }, res) => { }); router.post('/order/create', (req, res) => { - res.status(200).send({ success: true, body: { ok: true } }); + const stubName = STUBS.orderCreate; + + res + .status(/error/.test(stubName) ? 500 : 200) + .send( + /^error$/.test(stubName) + ? commonError + : require(`../json/landing-order-create/${stubName}.json`), + ); }); router.use('/admin', require('./admin')); diff --git a/stubs/json/landing-order-create/error.json b/stubs/json/landing-order-create/error.json new file mode 100644 index 0000000..3770aac --- /dev/null +++ b/stubs/json/landing-order-create/error.json @@ -0,0 +1,4 @@ +{ + "success": false, + "message": "Не удалось создать заказ" +} \ No newline at end of file diff --git a/stubs/json/landing-order-create/success.json b/stubs/json/landing-order-create/success.json new file mode 100644 index 0000000..d1a2293 --- /dev/null +++ b/stubs/json/landing-order-create/success.json @@ -0,0 +1,6 @@ +{ + "success": true, + "body": { + "id": "id1" + } +} \ No newline at end of file