From 6096cfc15c384b8800ef78cae1b8a15756638763 Mon Sep 17 00:00:00 2001
From: ilnaz <237x237@gmail.com>
Date: Sun, 22 Dec 2024 12:00:12 +0300
Subject: [PATCH] feat: add fetch for multi-stub (#59)
---
locales/ru.json | 3 +-
src/api/arm.ts | 36 ++++++++++-
.../MasterActionsMenu/MasterActionsMenu.tsx | 37 ++++++++++-
src/components/MasterDrawer/MasterDrawer.tsx | 62 +++++++++++++++----
src/components/MasterItem/MasterItem.tsx | 21 +++----
src/components/OrderItem/OrderItem.tsx | 20 ++++++
src/components/Orders/Orders.tsx | 21 +++++--
stubs/api/index.js | 34 +++++++++-
stubs/json/arm-masters/success.json | 20 ------
stubs/json/arm-orders/success.json | 10 ++-
10 files changed, 205 insertions(+), 59 deletions(-)
diff --git a/locales/ru.json b/locales/ru.json
index d3e17d6..a36cd02 100644
--- a/locales/ru.json
+++ b/locales/ru.json
@@ -11,6 +11,7 @@
"dry-wash.arm.order.table.header.washingTime": "Время мойки",
"dry-wash.arm.order.table.header.orderDate": "Дата заказа",
"dry-wash.arm.order.table.header.status": "Статус",
+ "dry-wash.arm.order.table.header.masters": "Мастер",
"dry-wash.arm.order.table.header.telephone": "Телефон",
"dry-wash.arm.order.table.header.location": "Расположение",
"dry-wash.arm.order.table.empty": "Список пуст",
@@ -89,4 +90,4 @@
"dry-wash.errorBoundary.description": "Мы уже работаем над исправлением проблемы",
"dry-wash.errorBoundary.button.reload": "Перезагрузить страницу",
"dry-wash.washTime.timeSlot": "{{start}} - {{end}}"
-}
\ No newline at end of file
+}
diff --git a/src/api/arm.ts b/src/api/arm.ts
index c406c54..e4003cb 100644
--- a/src/api/arm.ts
+++ b/src/api/arm.ts
@@ -34,7 +34,41 @@ const armService = () => {
return await response.json();
};
- return { fetchOrders, fetchMasters };
+ const addMaster = async ({
+ name,
+ phone,
+ }: {
+ name: string;
+ phone: string;
+ }) => {
+ const response = await fetch(`${endpoint}${ArmEndpoints.MASTERS}`, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify({ name, phone }),
+ });
+
+ if (!response.ok) {
+ throw new Error(`Failed to fetch masters: ${response.status}`);
+ }
+
+ return await response.json();
+ };
+
+ const deleteMaster = async ({ id }: { id: string }) => {
+ const response = await fetch(`${endpoint}${ArmEndpoints.MASTERS}/${id}`, {
+ method: 'DELETE',
+ });
+
+ if (!response.ok) {
+ throw new Error(`Failed to fetch masters: ${response.status}`);
+ }
+
+ return await response.json();
+ };
+
+ return { fetchOrders, fetchMasters, addMaster, deleteMaster };
};
export { armService, ArmEndpoints };
diff --git a/src/components/MasterActionsMenu/MasterActionsMenu.tsx b/src/components/MasterActionsMenu/MasterActionsMenu.tsx
index a11ab5b..27d9ea2 100644
--- a/src/components/MasterActionsMenu/MasterActionsMenu.tsx
+++ b/src/components/MasterActionsMenu/MasterActionsMenu.tsx
@@ -5,20 +5,53 @@ import {
MenuList,
MenuItem,
IconButton,
+ useToast,
} from '@chakra-ui/react';
import { EditIcon } from '@chakra-ui/icons';
import { useTranslation } from 'react-i18next';
+import { armService } from '../../api/arm';
-const MasterActionsMenu = () => {
+interface MasterActionsMenu {
+ id: string;
+}
+
+const MasterActionsMenu = ({ id }: MasterActionsMenu) => {
const { t } = useTranslation('~', {
keyPrefix: 'dry-wash.arm.master.table.actionsMenu',
});
+ const { deleteMaster } = armService();
+ const toast = useToast();
+
+ const handleClickDelete = async () => {
+ try {
+ await deleteMaster({ id });
+ toast({
+ title: 'Мастер удалён.',
+ description: `Мастер с ID "${id}" успешно удалён.`,
+ status: 'success',
+ duration: 5000,
+ isClosable: true,
+ position: 'top-right',
+ });
+ } catch (error) {
+ toast({
+ title: 'Ошибка удаления мастера.',
+ description: 'Не удалось удалить мастера. Попробуйте ещё раз.',
+ status: 'error',
+ duration: 5000,
+ isClosable: true,
+ position: 'top-right',
+ });
+ console.error(error);
+ }
+ };
+
return (
);
diff --git a/src/components/MasterDrawer/MasterDrawer.tsx b/src/components/MasterDrawer/MasterDrawer.tsx
index 03cc9d1..fa2b199 100644
--- a/src/components/MasterDrawer/MasterDrawer.tsx
+++ b/src/components/MasterDrawer/MasterDrawer.tsx
@@ -11,15 +11,47 @@ import {
DrawerFooter,
DrawerHeader,
DrawerOverlay,
+ useToast,
+ InputGroup,
+ InputLeftElement,
} from '@chakra-ui/react';
import { useTranslation } from 'react-i18next';
+import { armService } from '../../api/arm';
+import { PhoneIcon } from '@chakra-ui/icons';
const MasterDrawer = ({ isOpen, onClose }) => {
+ const { addMaster } = armService();
+ const toast = useToast();
+
const [newMaster, setNewMaster] = useState({ name: '', phone: '' });
- const handleSave = () => {
- console.log(`Сохранение мастера: ${newMaster}`);
- onClose();
+ const handleSave = async () => {
+ if (newMaster.name.trim() === '' || newMaster.phone.trim() === '') {
+ return;
+ }
+
+ try {
+ await addMaster(newMaster);
+ toast({
+ title: 'Мастер создан.',
+ description: `Мастер "${newMaster.name}" успешно добавлен.`,
+ status: 'success',
+ duration: 5000,
+ isClosable: true,
+ position: 'top-right',
+ });
+ onClose();
+ } catch (error) {
+ toast({
+ title: 'Ошибка при создании мастера.',
+ description: 'Не удалось добавить мастера. Попробуйте еще раз.',
+ status: 'error',
+ duration: 5000,
+ isClosable: true,
+ position: 'top-right',
+ });
+ console.error(error);
+ }
};
const { t } = useTranslation('~', {
@@ -36,6 +68,7 @@ const MasterDrawer = ({ isOpen, onClose }) => {
{t('inputName.label')}
setNewMaster({ ...newMaster, name: e.target.value })
@@ -44,14 +77,21 @@ const MasterDrawer = ({ isOpen, onClose }) => {
/>
- {t('inputPhone.label')}
-
- setNewMaster({ ...newMaster, phone: e.target.value })
- }
- placeholder={t('inputPhone.placeholder')}
- />
+ {t('inputPhone.label')}
+
+
+
+
+
+
+ setNewMaster({ ...newMaster, phone: e.target.value })
+ }
+ placeholder={t('inputPhone.placeholder')}
+ />
+
diff --git a/src/components/MasterItem/MasterItem.tsx b/src/components/MasterItem/MasterItem.tsx
index 825d621..15f590d 100644
--- a/src/components/MasterItem/MasterItem.tsx
+++ b/src/components/MasterItem/MasterItem.tsx
@@ -4,37 +4,30 @@ import { Badge, Link, Stack, Td, Tr } from '@chakra-ui/react';
import MasterActionsMenu from '../MasterActionsMenu';
import { getTimeSlot } from '../../lib/date-helpers';
-export interface Schedule {
- id: string;
- startWashTime: string;
- endWashTime: string;
-}
-
export type MasterProps = {
id: string;
name: string;
- schedule: Schedule[];
phone: string;
};
-const MasterItem = ({ name, schedule, phone }) => {
+const MasterItem = ({ name, phone, id }) => {
return (
{name} |
- {schedule.map(({ startWashTime, endWashTime }, index) => (
-
- {getTimeSlot(startWashTime, endWashTime)}
-
- ))}
+ {/*{schedule.map(({ startWashTime, endWashTime }, index) => (*/}
+ {/* */}
+ {/* {getTimeSlot(startWashTime, endWashTime)}*/}
+ {/* */}
+ {/*))}*/}
|
{phone}
|
-
+
|
);
diff --git a/src/components/OrderItem/OrderItem.tsx b/src/components/OrderItem/OrderItem.tsx
index 92e7041..5621d15 100644
--- a/src/components/OrderItem/OrderItem.tsx
+++ b/src/components/OrderItem/OrderItem.tsx
@@ -3,6 +3,7 @@ import { Td, Tr, Link, Select } from '@chakra-ui/react';
import { useTranslation } from 'react-i18next';
import dayjs from 'dayjs';
+import { MasterProps } from '../MasterItem/MasterItem';
import { getTimeSlot } from '../../lib';
const statuses = [
@@ -24,6 +25,9 @@ export type OrderProps = {
status?: GetArrItemType;
phone?: string;
location?: string;
+ master: MasterProps;
+ notes: '';
+ allMasters: MasterProps[];
};
type Status = (typeof statuses)[number];
@@ -44,6 +48,8 @@ const OrderItem = ({
status,
phone,
location,
+ master,
+ allMasters,
}: OrderProps) => {
const { t } = useTranslation('~', {
keyPrefix: 'dry-wash.arm.order',
@@ -51,6 +57,7 @@ const OrderItem = ({
const [statusSelect, setStatus] = useState(status);
const bgColor = statusColors[statusSelect];
+ const [masterSelect, setMaster] = useState(master?.name);
return (
@@ -71,6 +78,19 @@ const OrderItem = ({
))}
+
+
+ |
{phone}
|
diff --git a/src/components/Orders/Orders.tsx b/src/components/Orders/Orders.tsx
index de4070c..9fa95f9 100644
--- a/src/components/Orders/Orders.tsx
+++ b/src/components/Orders/Orders.tsx
@@ -19,12 +19,14 @@ import OrderItem from '../OrderItem';
import { OrderProps } from '../OrderItem/OrderItem';
import { armService } from '../../api/arm';
import DateNavigator from '../DateNavigator';
+import { MasterProps } from '../MasterItem/MasterItem';
const TABLE_HEADERS = [
'carNumber' as const,
'washingTime' as const,
'orderDate' as const,
'status' as const,
+ 'masters' as const,
'telephone' as const,
'location' as const,
];
@@ -35,21 +37,29 @@ const Orders = () => {
});
const { fetchOrders } = armService();
+ const { fetchMasters } = armService();
const toast = useToast();
const [orders, setOrders] = useState([]);
+ const [allMasters, setAllMasters] = useState([]);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const [currentDate, setCurrentDate] = useState(new Date());
useEffect(() => {
- const loadOrders = async () => {
+ const loadData = async () => {
setLoading(true);
+ setError(null);
try {
- const data = await fetchOrders({ date: currentDate });
- setOrders(data.body);
+ const [ordersData, mastersData] = await Promise.all([
+ fetchOrders({ date: currentDate }),
+ fetchMasters(),
+ ]);
+
+ setOrders(ordersData.body);
+ setAllMasters(mastersData.body);
} catch (err) {
setError(err.message);
toast({
@@ -64,8 +74,8 @@ const Orders = () => {
}
};
- loadOrders();
- }, [toast, t, currentDate]);
+ loadData();
+ }, [currentDate, toast, t]);
return (
@@ -112,6 +122,7 @@ const Orders = () => {
!error &&
orders.map((order, index) => (
- (req, res, next) =>
- setTimeout(next, duration);
+ (req, res, next) =>
+ setTimeout(next, duration);
router.use(sleep());
@@ -23,6 +23,36 @@ router.get('/arm/masters', (req, res) => {
);
});
+router.post('/arm/masters', (req, res) => {
+ res
+ .status(/error/.test(STUBS.masters) ? 500 : 200)
+ .send(
+ /^error$/.test(STUBS.masters)
+ ? commonError
+ : require(`../json/arm-masters/${STUBS.masters}.json`),
+ );
+});
+
+router.patch('/arm/masters/:id', (req, res) => {
+ res
+ .status(/error/.test(STUBS.masters) ? 500 : 200)
+ .send(
+ /^error$/.test(STUBS.masters)
+ ? commonError
+ : require(`../json/arm-masters/${STUBS.masters}.json`),
+ );
+});
+
+router.delete('/arm/masters/:id', (req, res) => {
+ res
+ .status(/error/.test(STUBS.masters) ? 500 : 200)
+ .send(
+ /^error$/.test(STUBS.masters)
+ ? commonError
+ : require(`../json/arm-masters/${STUBS.masters}.json`),
+ );
+});
+
router.post('/arm/orders', (req, res) => {
res
.status(/error/.test(STUBS.orders) ? 500 : 200)
diff --git a/stubs/json/arm-masters/success.json b/stubs/json/arm-masters/success.json
index ce50415..e392eb0 100644
--- a/stubs/json/arm-masters/success.json
+++ b/stubs/json/arm-masters/success.json
@@ -4,31 +4,11 @@
{
"id": "masters1",
"name": "Иван Иванов",
- "schedule": [ {
- "id": "order1",
- "startWashTime": "2024-11-24T10:30:00.000Z",
- "endWashTime": "2024-11-24T16:30:00.000Z"
- },
- {
- "id": "order2",
- "startWashTime": "2024-11-24T11:30:00.000Z",
- "endWashTime": "2024-11-24T17:30:00.000Z"
- }],
"phone": "+7 900 123 45 67"
},
{
"id": "masters12",
"name": "Иван Иванов",
- "schedule": [ {
- "id": "order1",
- "startWashTime": "2024-11-24T10:30:00.000Z",
- "endWashTime": "2024-11-24T16:30:00.000Z"
- },
- {
- "id": "order2",
- "startWashTime": "2024-11-24T11:30:00.000Z",
- "endWashTime": "2024-11-24T17:30:00.000Z"
- }],
"phone": "+7 900 123 45 67"
}
]
diff --git a/stubs/json/arm-orders/success.json b/stubs/json/arm-orders/success.json
index 15669e8..9cf7c26 100644
--- a/stubs/json/arm-orders/success.json
+++ b/stubs/json/arm-orders/success.json
@@ -9,7 +9,9 @@
"orderDate": "2024-11-24T08:41:46.366Z",
"status": "progress",
"phone": "79001234563",
- "location": "Казань, ул. Баумана, 1"
+ "location": "Казань, ул. Баумана, 1",
+ "master": [],
+ "notes": ""
},
{
"id": "order2",
@@ -19,7 +21,9 @@
"orderDate": "2024-11-24T07:40:46.366Z",
"status": "progress",
"phone": "79001234567",
- "location": "Казань, ул. Баумана, 43"
+ "location": "Казань, ул. Баумана, 43",
+ "master": [],
+ "notes": ""
}
]
-}
\ No newline at end of file
+}