diff --git a/locales/en.json b/locales/en.json index 05600cb..7726b14 100644 --- a/locales/en.json +++ b/locales/en.json @@ -42,7 +42,7 @@ "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.get-order-query.error.title": "Failed to fetch the details of order #{{number}}", + "dry-wash.order-view.get-order-query.error.title": "Failed to fetch the details of order", "dry-wash.order-view.details.title": "Order #{{number}}", "dry-wash.order-view.details.owner": "Owner", "dry-wash.order-view.details.car": "Car", diff --git a/locales/ru.json b/locales/ru.json index c389cd8..94d00fd 100644 --- a/locales/ru.json +++ b/locales/ru.json @@ -82,7 +82,7 @@ "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.get-order-query.error.title": "Не удалось загрузить детали заказа №{{number}}", + "dry-wash.order-view.get-order-query.error.title": "Не удалось загрузить детали заказа", "dry-wash.order-view.details.title": "Заказ №{{number}}", "dry-wash.order-view.details.owner": "Владелец", "dry-wash.order-view.details.car": "Автомобиль", diff --git a/src/__data__/service/api.ts b/src/__data__/service/api.ts index 752f43d..29a8898 100644 --- a/src/__data__/service/api.ts +++ b/src/__data__/service/api.ts @@ -3,17 +3,7 @@ import { getConfigValue } from '@brojs/cli'; import { Master } from '../../models/api/master'; -type SuccessResponse = { - success: true; - body: Body; -}; - -type ErrorResponse = { - success: false; - message: string; -}; - -type BaseResponse = SuccessResponse | ErrorResponse; +import { extractBodyFromResponse } from './utils'; export const api = createApi({ reducerPath: 'api', @@ -22,11 +12,7 @@ export const api = createApi({ endpoints: (builder) => ({ getMasters: builder.query({ query: () => ({ url: '/arm/masters' }), - transformResponse: (response: BaseResponse) => { - if (response.success) { - return response.body; - } - }, + transformResponse: extractBodyFromResponse, providesTags: ['Masters'], }), addMaster: builder.mutation>({ diff --git a/src/__data__/service/landing.api.ts b/src/__data__/service/landing.api.ts new file mode 100644 index 0000000..d42f2cd --- /dev/null +++ b/src/__data__/service/landing.api.ts @@ -0,0 +1,14 @@ +import { GetOrder } from "../../models/api"; + +import { api } from "./api"; +import { extractBodyFromResponse, extractErrorMessageFromResponse } from "./utils"; + +export const landingApi = api.injectEndpoints({ + endpoints: ({ query }) => ({ + getOrder: query({ + query: ({ orderId }) => `/order/${orderId}`, + transformResponse: extractBodyFromResponse, + transformErrorResponse: extractErrorMessageFromResponse, + }) + }) +}); diff --git a/src/__data__/service/utils.ts b/src/__data__/service/utils.ts new file mode 100644 index 0000000..6ca45b2 --- /dev/null +++ b/src/__data__/service/utils.ts @@ -0,0 +1,15 @@ +import { FetchBaseQueryError } from "@reduxjs/toolkit/query"; + +import { BaseResponse } from "../../models/api"; + +export const extractBodyFromResponse = (response: BaseResponse) => { + if (response.success) { + return response.body; + } +}; + +export const extractErrorMessageFromResponse = ({ data }: FetchBaseQueryError) => { + if (typeof data === 'object' && 'message' in data && typeof data.message === 'string') { + return data.message; + } +}; \ No newline at end of file diff --git a/src/api/landing.tsx b/src/api/landing.tsx index 7348167..4c84e6c 100644 --- a/src/api/landing.tsx +++ b/src/api/landing.tsx @@ -1,12 +1,11 @@ import { getConfigValue } from '@brojs/cli'; -import { useEffect, useState } from 'react'; +import { useState } from 'react'; -import { CreateOrder, GetOrder } from '../models/api'; +import { CreateOrder } from '../models/api'; import { QueryState, Trigger } from './types'; enum LandingEndpoints { - ORDER = '/order', ORDER_CREATE = '/order/create', } @@ -63,45 +62,4 @@ const useCreateOrderMutation = (): [ return [createOrder, { isLoading, isSuccess, data, isError, error }]; }; -const useGetOrderQuery = ({ - orderId, -}: GetOrder.Params): QueryState => { - const [isLoading, setIsLoading] = useState['isLoading']>(true); - const [isSuccess, setIsSuccess] = useState['isSuccess']>(); - const [data, setData] = useState['data']>(); - const [isError, setIsError] = useState['isError']>(); - const [error, setError] = useState['error']>(); - - useEffect(() => { - (async () => { - try { - const response = await fetch( - `${endpoint}${LandingEndpoints.ORDER}/${orderId}`, - ); - - 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); - } catch (error) { - setIsError(true); - setError(error); - throw error; - } finally { - setIsLoading(false); - } - })(); - }, []); - - return { isLoading, isSuccess, data, isError, error }; -}; - -export { useCreateOrderMutation, useGetOrderQuery }; +export { useCreateOrderMutation }; diff --git a/src/components/order-view/details/order-details.tsx b/src/components/order-view/details/order-details.tsx index 5343fdf..92bbe73 100644 --- a/src/components/order-view/details/order-details.tsx +++ b/src/components/order-view/details/order-details.tsx @@ -19,7 +19,7 @@ import { OrderStatus } from './status'; type OrderDetailsProps = Pick< Order.View, - | 'id' + | 'orderNumber' | 'status' | 'phone' | 'carNumber' @@ -32,7 +32,7 @@ type OrderDetailsProps = Pick< >; export const OrderDetails: FC = ({ - id, + orderNumber, status, phone, carNumber, @@ -58,7 +58,7 @@ export const OrderDetails: FC = ({ gap={2} > - {t('title', { number: id })} + {t('title', { number: orderNumber })} diff --git a/src/components/order-view/details/status/order-status.tsx b/src/components/order-view/details/status/order-status.tsx index cc40c90..4910fe9 100644 --- a/src/components/order-view/details/status/order-status.tsx +++ b/src/components/order-view/details/status/order-status.tsx @@ -15,19 +15,19 @@ const getPropsByStatus = ( colorScheme: 'red', children: t('canceled'), }; - case 'progress': - return { - colorScheme: 'yellow', - children: t('progress'), - }; case 'pending': return { colorScheme: 'yellow', children: t('pending'), }; + case 'progress': + return { + colorScheme: 'orange', + children: t('progress'), + }; case 'working': return { - colorScheme: 'yellow', + colorScheme: 'orange', children: t('working'), }; case 'complete': diff --git a/src/models/api/common.ts b/src/models/api/common.ts new file mode 100644 index 0000000..7f24440 --- /dev/null +++ b/src/models/api/common.ts @@ -0,0 +1,13 @@ +type SuccessResponse = { + success: true; + body: Body; +}; + +export type ErrorMessage = string; + +type ErrorResponse = { + success: false; + message: ErrorMessage; +}; + +export type BaseResponse = SuccessResponse | ErrorResponse; \ No newline at end of file diff --git a/src/models/api/index.ts b/src/models/api/index.ts index f57351e..73fe494 100644 --- a/src/models/api/index.ts +++ b/src/models/api/index.ts @@ -1 +1,2 @@ +export * from './common'; export * from './order'; \ No newline at end of file diff --git a/src/models/api/order.ts b/src/models/api/order.ts index b22283b..e622348 100644 --- a/src/models/api/order.ts +++ b/src/models/api/order.ts @@ -1,6 +1,16 @@ /* eslint-disable @typescript-eslint/no-namespace */ import { Order } from "../landing"; +import { ErrorMessage } from "./common"; + +export namespace GetOrder { + export type Response = Order.View; + export type Params = { + orderId: Order.Id + }; + export type Error = ErrorMessage; +} + export namespace CreateOrder { export type Response = { id: Order.Id @@ -8,11 +18,4 @@ export namespace CreateOrder { export type Params = { body: Order.Create }; -}; - -export namespace GetOrder { - export type Response = Order.View; - export type Params = { - orderId: Order.Id - }; }; \ No newline at end of file diff --git a/src/models/landing/order.ts b/src/models/landing/order.ts index 58db543..88b2708 100644 --- a/src/models/landing/order.ts +++ b/src/models/landing/order.ts @@ -26,6 +26,8 @@ export type Create = { } }; +export type Number = string; + export type View = { phone: Customer.PhoneNumber; carNumber: Car.RegistrationNumber; @@ -34,6 +36,7 @@ export type View = { location: Washing.Location; startWashTime: Washing.AvailableBeginDateTime; endWashTime: Washing.AvailableEndDateTime; + orderNumber: Number, status: Status, notes: string; created: IsoDate; diff --git a/src/pages/order-view/index.tsx b/src/pages/order-view/index.tsx index c2b007d..1d43ab4 100644 --- a/src/pages/order-view/index.tsx +++ b/src/pages/order-view/index.tsx @@ -1,5 +1,13 @@ import React, { FC } from 'react'; -import { Alert, AlertDescription, AlertIcon, AlertTitle, HStack, Spinner } from '@chakra-ui/react'; +import { + Alert, + AlertDescription, + AlertIcon, + AlertTitle, + Box, + HStack, + Spinner, +} from '@chakra-ui/react'; import { useTranslation } from 'react-i18next'; import { Container, Heading, VStack } from '@chakra-ui/react'; import { useParams } from 'react-router-dom'; @@ -10,7 +18,8 @@ import { } from '../../containers'; import { OrderDetails } from '../../components/order-view'; import { Order } from '../../models/landing'; -import { useGetOrderQuery } from '../../api'; +import { landingApi } from '../../__data__/service/landing.api'; +import { ErrorMessage } from '../../models/api'; const Page: FC = () => { const { t } = useTranslation('~', { @@ -21,12 +30,15 @@ const Page: FC = () => { const { isLoading, isSuccess, - data: { body: order } = {}, + data: order, isError, error, - } = useGetOrderQuery({ - orderId, - }); + } = landingApi.useGetOrderQuery( + { + orderId, + }, + ); + const errorMessage = error as ErrorMessage; return ( @@ -51,7 +63,7 @@ const Page: FC = () => { <> {isSuccess && ( { <> {isError && ( - + - - {t('get-order-query.error.title', { - number: orderId, - })} - - {error.data?.error} + + + {t('get-order-query.error.title')} + + {errorMessage} + )} diff --git a/stubs/api/admin.js b/stubs/api/admin.js index 32cc16c..88e000b 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' }; +const STUBS = { masters: 'success', orders: 'success', orderView: 'success-pending' }; router.get('/set/:name/:value', (req, res) => { const { name, value } = req.params; @@ -28,7 +28,8 @@ router.get('/', (req, res) => {
Лендинг - Детали заказа - ${generateRadioInput('orderView', 'success')} + ${generateRadioInput('orderView', 'success-pending')} + ${generateRadioInput('orderView', 'success-working')} ${generateRadioInput('orderView', 'error')}
`); diff --git a/stubs/json/landing-order-view/id1-error.json b/stubs/json/landing-order-view/id1-error.json new file mode 100644 index 0000000..fa97f72 --- /dev/null +++ b/stubs/json/landing-order-view/id1-error.json @@ -0,0 +1,4 @@ +{ + "success": false, + "message": "Не удалось загрузить детали заказа" +} \ No newline at end of file diff --git a/stubs/json/landing-order-view/1-success.json b/stubs/json/landing-order-view/id1-success-pending.json similarity index 88% rename from stubs/json/landing-order-view/1-success.json rename to stubs/json/landing-order-view/id1-success-pending.json index bd5f926..a2e1e4a 100644 --- a/stubs/json/landing-order-view/1-success.json +++ b/stubs/json/landing-order-view/id1-success-pending.json @@ -8,10 +8,11 @@ "startWashTime": "2025-01-19T14:03:00.000Z", "endWashTime": "2025-01-19T14:03:00.000Z", "location": "55.793833888711006,49.19037910644527 Республика Татарстан (Татарстан), Казань, жилой район Седьмое Небо", - "status": "progress", + "orderNumber": "1", + "status": "pending", "notes": "", "created": "2025-01-19T14:04:02.985Z", "updated": "2025-01-19T14:04:02.987Z", - "id": "678d06527d78ec30be2679d8" + "id": "id1" } } \ No newline at end of file diff --git a/stubs/json/landing-order-view/id1-success-working.json b/stubs/json/landing-order-view/id1-success-working.json new file mode 100644 index 0000000..d075d8b --- /dev/null +++ b/stubs/json/landing-order-view/id1-success-working.json @@ -0,0 +1,18 @@ +{ + "success": true, + "body": { + "phone": "+79876543210", + "carNumber": "А123АА16", + "carBody": 2, + "carColor": "#ffffff", + "startWashTime": "2025-01-19T14:03:00.000Z", + "endWashTime": "2025-01-19T14:03:00.000Z", + "location": "55.793833888711006,49.19037910644527 Республика Татарстан (Татарстан), Казань, жилой район Седьмое Небо", + "orderNumber": "1", + "status": "working", + "notes": "", + "created": "2025-01-19T14:04:02.985Z", + "updated": "2025-01-19T14:04:02.987Z", + "id": "id1" + } +} \ No newline at end of file