diff --git a/locales/en.json b/locales/en.json index a185c8c..f0aa8f5 100644 --- a/locales/en.json +++ b/locales/en.json @@ -39,6 +39,8 @@ "dry-wash.order-create.car-body-select.options.sports-car" : "Sports-car", "dry-wash.order-create.car-body-select.options.other": "Other", "dry-wash.order-create.form.submit-button.label": "Submit", + "dry-wash.order-create.create-order-query.success.title": "The order is successfully created", + "dry-wash.order-create.create-order-query.error.title": "Failed to create an order", "dry-wash.order-view.title": "Your order", "dry-wash.order-view.error.title": "Error", "dry-wash.order-view.fetch.error": "Failed to fetch the details of order #{{number}}", diff --git a/locales/ru.json b/locales/ru.json index 06c21ff..368d3e4 100644 --- a/locales/ru.json +++ b/locales/ru.json @@ -78,6 +78,8 @@ "dry-wash.order-create.car-body-select.options.sports-car": "Спорткар", "dry-wash.order-create.car-body-select.options.other": "Другой", "dry-wash.order-create.form.submit-button.label": "Отправить", + "dry-wash.order-create.create-order-query.success.title": "Заказ успешно создан", + "dry-wash.order-create.create-order-query.error.title": "Не удалось создать заказ", "dry-wash.order-view.title": "Ваш заказ", "dry-wash.order-view.error.title": "Ошибка", "dry-wash.order-view.fetch.error": "Не удалось загрузить детали заказа №{{number}}", diff --git a/src/components/order-form/form/helper.ts b/src/components/order-form/form/helper.ts index 63ea809..37e2bb7 100644 --- a/src/components/order-form/form/helper.ts +++ b/src/components/order-form/form/helper.ts @@ -1,9 +1,4 @@ import { useTranslation } from "react-i18next"; -import { getConfigValue } from '@brojs/cli'; -import { InputProps, SelectProps } from "@chakra-ui/react"; -import dayjs from "dayjs"; - -import { Order } from "../../../models/landing"; import { FormFieldProps } from "./field"; import { OrderFormValues } from "./types"; @@ -31,50 +26,4 @@ export const useGetValidationRules = () => { validate: (value: string) => isValidCarNumber(value) || t('car-number-field.invalid') }, } satisfies Record; -}; - -const removeAllSpaces = (str: string) => str.replace(/\s+/g, ''); - -const getValidCarBodyStyle = (fieldValue: string) => { - const carBodyAsNumber = Number(fieldValue); - return Number.isNaN(carBodyAsNumber) ? undefined : carBodyAsNumber; -}; - -export const formatFormValues = ({ phone, carNumber, carBody, carColor, carLocation, availableDatetimeBegin, availableDatetimeEnd }: OrderFormValues): Order.Create => { - return { - customer: { - phone - }, - car: { - number: removeAllSpaces(carNumber), - body: getValidCarBodyStyle(carBody), - color: carColor - }, - washing: { - location: carLocation, - begin: dayjs(availableDatetimeBegin).toISOString(), - end: dayjs(availableDatetimeEnd).toISOString(), - } - }; -}; - -const endpoint = getConfigValue('dry-wash.api'); - -export const onSubmit = async (values: OrderFormValues) => { - const response = await fetch(`${endpoint}/order/create`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify(formatFormValues(values)), - }); - - if (!response.ok) { - throw new Error(`Failed to create order: ${response.status}`); - } - - return await response.json(); -}; - -export const inputCommonStyles: Partial = { }; \ No newline at end of file diff --git a/src/components/order-form/form/index.ts b/src/components/order-form/form/index.ts index c445fce..8d0176f 100644 --- a/src/components/order-form/form/index.ts +++ b/src/components/order-form/form/index.ts @@ -1 +1,2 @@ +export type { OrderFormValues, OrderFormProps } from './types'; export { OrderForm } from './order-form'; \ No newline at end of file diff --git a/src/components/order-form/form/order-form.tsx b/src/components/order-form/form/order-form.tsx index b368af6..988cbbb 100644 --- a/src/components/order-form/form/order-form.tsx +++ b/src/components/order-form/form/order-form.tsx @@ -1,4 +1,4 @@ -import React, { FC } from 'react'; +import React from 'react'; import { useForm } from 'react-hook-form'; import { useTranslation } from 'react-i18next'; import { Box, Flex, FormControl, FormLabel, VStack } from '@chakra-ui/react'; @@ -7,14 +7,19 @@ import { CarBodySelect } from './car-body'; import { CarColorInput } from './car-color'; import { CarNumberInput } from './car-number'; import { FormInputField, FormControllerField } from './field'; -import { OrderFormValues } from './types'; +import { OrderFormProps, OrderFormValues } from './types'; import { PhoneInput } from './phone'; import { SubmitButton } from './submit'; -import { defaultValues, onSubmit, useGetValidationRules } from './helper'; +import { defaultValues, useGetValidationRules } from './helper'; import { DateTimeInput } from './date-time'; -import { LocationInput, MapComponent, StringLocation, YMapsProvider } from './location'; +import { + LocationInput, + MapComponent, + StringLocation, + YMapsProvider, +} from './location'; -export const OrderForm: FC = () => { +export const OrderForm = ({ onSubmit, loading }: OrderFormProps) => { const { handleSubmit, control, @@ -123,7 +128,7 @@ export const OrderForm: FC = () => { }} /> - + ); diff --git a/src/components/order-form/form/types.ts b/src/components/order-form/form/types.ts index 9746d54..0285c60 100644 --- a/src/components/order-form/form/types.ts +++ b/src/components/order-form/form/types.ts @@ -1,3 +1,5 @@ +import { SubmitHandler } from "react-hook-form"; + export type OrderFormValues = { phone: string; carNumber: string; @@ -6,4 +8,9 @@ export type OrderFormValues = { carLocation: string; availableDatetimeBegin: string; availableDatetimeEnd: string; +}; + +export type OrderFormProps = { + onSubmit: SubmitHandler; + loading: boolean; }; \ No newline at end of file diff --git a/src/pages/order-create/helper.ts b/src/pages/order-create/helper.ts new file mode 100644 index 0000000..d3c3f2e --- /dev/null +++ b/src/pages/order-create/helper.ts @@ -0,0 +1,29 @@ +import dayjs from "dayjs"; + +import { Order } from "../../models/landing"; +import { OrderFormValues } from "../../components/order-form"; + +const removeAllSpaces = (str: string) => str.replace(/\s+/g, ''); + +const getValidCarBodyStyle = (fieldValue: string) => { + const carBodyAsNumber = Number(fieldValue); + return Number.isNaN(carBodyAsNumber) ? undefined : carBodyAsNumber; +}; + +export const formatFormValues = ({ phone, carNumber, carBody, carColor, carLocation, availableDatetimeBegin, availableDatetimeEnd }: OrderFormValues): Order.Create => { + return { + customer: { + phone + }, + car: { + number: removeAllSpaces(carNumber), + body: getValidCarBodyStyle(carBody), + color: carColor + }, + washing: { + location: carLocation, + begin: dayjs(availableDatetimeBegin).toISOString(), + end: dayjs(availableDatetimeEnd).toISOString(), + } + }; +}; \ No newline at end of file diff --git a/src/pages/order-create/index.tsx b/src/pages/order-create/index.tsx index e4dd2ad..4b91eb1 100644 --- a/src/pages/order-create/index.tsx +++ b/src/pages/order-create/index.tsx @@ -1,32 +1,63 @@ import React, { FC } from 'react'; import { useTranslation } from 'react-i18next'; -import { Container, Heading, VStack } from '@chakra-ui/react'; +import { Container, Heading, useToast, VStack } from '@chakra-ui/react'; +import { useNavigate } from 'react-router-dom'; -import { LandingThemeProvider } from '../../containers'; -import { OrderForm } from '../../components/order-form'; +import { withLandingThemeProvider } from '../../containers'; +import { OrderForm, OrderFormProps } from '../../components/order-form'; +import { useCreateOrderMutation } from '../../api'; +import { URLs } from '../../__data__/urls'; + +import { formatFormValues } from './helper'; const Page: FC = () => { const { t } = useTranslation('~', { keyPrefix: 'dry-wash.order-create', }); + const [createOrder, createOrderMutation] = useCreateOrderMutation(); + + const toast = useToast(); + const navigate = useNavigate(); + + 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, + }); + }); + }; + return ( - - - - {t('title')} - - - - + + + + {t('title')} + + + + ); }; -export default Page; \ No newline at end of file +export default withLandingThemeProvider(Page);