diff --git a/locales/en.json b/locales/en.json index db39a54..4ef706d 100644 --- a/locales/en.json +++ b/locales/en.json @@ -50,6 +50,12 @@ "dry-wash.order-view.details.location": "Where", "dry-wash.order-view.details.datetime-range": "When", "dry-wash.order-view.details.alert": "The operator will contact you about the payment at the specified phone number", + "dry-wash.order-view.upload-car-image.field.label": "Upload a photo of your car, and our service will quickly calculate the pre-order price!", + "dry-wash.order-view.upload-car-image.field.help": "Allowed formats: .jpg, .png. Maximum size: 5MB", + "dry-wash.order-view.upload-car-image.file-input.placeholder": "Upload a file", + "dry-wash.order-view.upload-car-image.file-input.button": "Upload", + "dry-wash.order-view.upload-car-image-query.success.title": "The car image is successfully uploaded", + "dry-wash.order-view.upload-car-image-query.error.title": "Failed to upload the car image", "dry-wash.arm.master.add": "Add", "dry-wash.arm.order.title": "Orders", "dry-wash.arm.order.table.empty": "Table empty", diff --git a/locales/ru.json b/locales/ru.json index 15586fb..93abaff 100644 --- a/locales/ru.json +++ b/locales/ru.json @@ -105,6 +105,12 @@ "dry-wash.order-view.details.location": "Где", "dry-wash.order-view.details.datetime-range": "Когда", "dry-wash.order-view.details.alert": "С вами свяжется оператор насчет оплаты по указанному номеру телефона", + "dry-wash.order-view.upload-car-image.field.label": "Загрузите фото вашего автомобиля, и наш сервис быстро рассчитает предварительную стоимость заказа!", + "dry-wash.order-view.upload-car-image.field.help": "Допустимые форматы: .jpg, .png. Максимальный размер: 5МБ", + "dry-wash.order-view.upload-car-image.file-input.placeholder": "Загрузите файл", + "dry-wash.order-view.upload-car-image.file-input.button": "Загрузить", + "dry-wash.order-view.upload-car-image-query.success.title": "Изображение автомобиля успешно загружено", + "dry-wash.order-view.upload-car-image-query.error.title": "Не удалось загрузить изображение автомобиля", "dry-wash.notFound.title": "Страница не найдена", "dry-wash.notFound.description": "К сожалению, запрашиваемая вами страница не существует.", "dry-wash.notFound.button.back": "Вернуться на главную", diff --git a/src/components/order-view/car-img/car-img-form.tsx b/src/components/order-view/car-img/car-img-form.tsx new file mode 100644 index 0000000..76d84e6 --- /dev/null +++ b/src/components/order-view/car-img/car-img-form.tsx @@ -0,0 +1,102 @@ +import React, { FC, memo, useRef } from 'react'; +import { Controller, useForm } from 'react-hook-form'; +import { + Button, + FormControl, + FormErrorMessage, + FormHelperText, + FormLabel, + HStack, + Input, +} from '@chakra-ui/react'; +import { useTranslation } from 'react-i18next'; + +import { landingApi } from '../../../__data__/service/landing.api'; +import { UploadCarImage } from '../../../models/api'; + +import { useHandleUploadCarImageResponse } from './helper'; + +type FormValues = { + carImg: File & { + fileName: string; + }; +}; + +type CarImageFormProps = { + orderId: UploadCarImage.Params['orderId']; +}; + +export const CarImageForm: FC = memo(function CarImageForm({ + orderId, +}) { + const { + handleSubmit, + control, + formState: { errors, isSubmitting }, + } = useForm({ shouldFocusError: true }); + + const [uploadCarImage, uploadCarImageMutation] = + landingApi.useUploadCarImageMutation(); + useHandleUploadCarImageResponse(uploadCarImageMutation); + + const onSubmit = (formData: FormValues) => { + const body = new FormData(); + body.append('file', formData.carImg); + uploadCarImage({ orderId, body }); + }; + + const fileInputRef = useRef(null); + + const { t } = useTranslation('~', { + keyPrefix: 'dry-wash.order-view.upload-car-image', + }); + + return ( +
+ + {t('field.label')} + { + return ( + + { + onChange(event.target.files[0]); + handleSubmit(onSubmit)(); + }} + type='file' + hidden + /> + + + + ); + }} + /> + {errors.carImg?.message} + {t('field.help')} + +
+ ); +}); diff --git a/src/components/order-view/car-img/helper.ts b/src/components/order-view/car-img/helper.ts new file mode 100644 index 0000000..f299213 --- /dev/null +++ b/src/components/order-view/car-img/helper.ts @@ -0,0 +1,35 @@ +import { useEffect } from "react"; +import { useToast } from "@chakra-ui/react"; +import { useTranslation } from "react-i18next"; + +import { isErrorMessage } from "../../../models/api"; + +export const useHandleUploadCarImageResponse = (query: { + isSuccess: boolean; + isError: boolean; + error?: unknown; +}) => { + const toast = useToast(); + const { t } = useTranslation('~', { + keyPrefix: 'dry-wash.order-create.upload-car-image-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) { + toast({ + status: 'success', + title: t('success.title'), + }); + } + }, [query.isSuccess]); +}; \ No newline at end of file diff --git a/src/components/order-view/car-img/index.ts b/src/components/order-view/car-img/index.ts new file mode 100644 index 0000000..4a829cf --- /dev/null +++ b/src/components/order-view/car-img/index.ts @@ -0,0 +1 @@ +export { CarImageForm } from './car-img-form'; diff --git a/src/components/order-view/details/order-details.tsx b/src/components/order-view/details/order-details.tsx index 62c8563..9411404 100644 --- a/src/components/order-view/details/order-details.tsx +++ b/src/components/order-view/details/order-details.tsx @@ -5,11 +5,13 @@ import { Heading, HStack, UnorderedList, - VStack, ListItem, Text, } from '@chakra-ui/react'; import { useTranslation } from 'react-i18next'; +import dayjs from 'dayjs'; +import localizedFormat from "dayjs/plugin/localizedFormat"; +dayjs.extend(localizedFormat); import { Order } from '../../../models/landing'; import { formatDatetime } from '../../../lib'; @@ -41,7 +43,7 @@ export const OrderDetails: FC = ({ location, startWashTime, endWashTime, - ...props + created }) => { const { t } = useTranslation('~', { keyPrefix: 'dry-wash.order-view.details', @@ -51,7 +53,7 @@ export const OrderDetails: FC = ({ }); return ( - + <> = ({ gap={2} > - {t('title', { number: orderNumber })} + {t('title', { number: orderNumber })} ({dayjs(created).format('LLLL')}) @@ -105,7 +107,7 @@ export const OrderDetails: FC = ({ {t('alert')} - + ); }; diff --git a/src/pages/order-view/index.tsx b/src/pages/order-view/index.tsx index 2367388..fe783ce 100644 --- a/src/pages/order-view/index.tsx +++ b/src/pages/order-view/index.tsx @@ -21,6 +21,7 @@ import { Order } from '../../models/landing'; import { landingApi } from '../../__data__/service/landing.api'; import { isErrorMessage } from '../../models/api'; import { FEATURE } from '../../__data__/features'; +import { CarImageForm } from '../../components/order-view/car-img'; const Page: FC = () => { const { t } = useTranslation('~', { @@ -69,24 +70,31 @@ const Page: FC = () => { <> <> {isSuccess && ( - + + + + )} <> {isError && ( - +