From 0b2dae79ac328cbc7ab6379b7eb37d6848b47cfb Mon Sep 17 00:00:00 2001
From: ilnaz <237x237@gmail.com>
Date: Sat, 7 Dec 2024 23:40:22 +0300
Subject: [PATCH] feat: add stub fetch admin (#44)
---
bro.config.js | 2 +-
locales/en.json | 4 +
locales/ru.json | 4 +
src/api/arm.ts | 34 +++++++++
src/components/MasterItem/MasterItem.tsx | 13 ++++
src/components/Masters/Masters.tsx | 63 ++++++++++++++--
src/components/Orders/Orders.tsx | 96 +++++++++++++++++++-----
stubs/api/index.js | 7 +-
8 files changed, 196 insertions(+), 27 deletions(-)
create mode 100644 src/api/arm.ts
diff --git a/bro.config.js b/bro.config.js
index f12638a..5cb04ae 100644
--- a/bro.config.js
+++ b/bro.config.js
@@ -24,6 +24,6 @@ module.exports = {
},
},
config: {
- 'dry-wash-pl.api': '/api',
+ 'dry-wash.api': '/api',
},
};
diff --git a/locales/en.json b/locales/en.json
index 5820580..35e36a8 100644
--- a/locales/en.json
+++ b/locales/en.json
@@ -16,6 +16,8 @@
"dry-wash.landing.social-proof-section.heading": "We are being chosen",
"dry-wash.arm.master.add": "Add",
"dry-wash.arm.order.title": "Orders",
+ "dry-wash.arm.order.table.empty": "Table empty",
+ "dry-wash.arm.order.error.title": "Error loading data",
"dry-wash.arm.order.status.progress": "In Progress",
"dry-wash.arm.order.status.complete": "Completed",
"dry-wash.arm.order.status.pending": "Pending",
@@ -30,6 +32,8 @@
"dry-wash.arm.order.table.header.location": "Location",
"dry-wash.arm.master.title": "Masters",
"dry-wash.arm.master.table.header.name": "Name",
+ "dry-wash.arm.master.table.empty": "Table empty",
+ "dry-wash.arm.master.error.title": "Error loading data",
"dry-wash.arm.master.table.header.currentJob": "Current Job",
"dry-wash.arm.master.table.header.phone": "Phone",
"dry-wash.arm.master.table.header.actions": "Actions",
diff --git a/locales/ru.json b/locales/ru.json
index 5c9d91c..fc04889 100644
--- a/locales/ru.json
+++ b/locales/ru.json
@@ -13,7 +13,11 @@
"dry-wash.arm.order.table.header.status": "Статус",
"dry-wash.arm.order.table.header.telephone": "Телефон",
"dry-wash.arm.order.table.header.location": "Расположение",
+ "dry-wash.arm.order.table.empty": "Список пуст",
+ "dry-wash.arm.order.error.title": "Ошибка при загрузке данных",
"dry-wash.arm.master.title": "Мастера",
+ "dry-wash.arm.master.table.empty": "Список пуст",
+ "dry-wash.arm.master.error.title": "Ошибка при загрузке данных",
"dry-wash.arm.master.table.header.name": "Имя",
"dry-wash.arm.master.table.header.currentJob": "Актуальная занятость",
"dry-wash.arm.master.table.header.phone": "Телефон",
diff --git a/src/api/arm.ts b/src/api/arm.ts
new file mode 100644
index 0000000..534440d
--- /dev/null
+++ b/src/api/arm.ts
@@ -0,0 +1,34 @@
+import { getConfigValue } from '@brojs/cli';
+
+enum ArmEndpoints {
+ ORDERS = '/arm/orders',
+ MASTERS = '/arm/masters',
+}
+
+const armService = () => {
+ const endpoint = getConfigValue('dry-wash.api');
+
+ const fetchOrders = async () => {
+ const response = await fetch(`${endpoint}${ArmEndpoints.ORDERS}`);
+
+ if (!response.ok) {
+ throw new Error(`Failed to fetch orders: ${response.status}`);
+ }
+
+ return await response.json();
+ };
+
+ const fetchMasters = async () => {
+ const response = await fetch(`${endpoint}${ArmEndpoints.MASTERS}`);
+
+ if (!response.ok) {
+ throw new Error(`Failed to fetch masters: ${response.status}`);
+ }
+
+ return await response.json();
+ };
+
+ return { fetchOrders, fetchMasters };
+};
+
+export { armService, ArmEndpoints };
diff --git a/src/components/MasterItem/MasterItem.tsx b/src/components/MasterItem/MasterItem.tsx
index 9895d29..825d621 100644
--- a/src/components/MasterItem/MasterItem.tsx
+++ b/src/components/MasterItem/MasterItem.tsx
@@ -4,6 +4,19 @@ 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 }) => {
return (
diff --git a/src/components/Masters/Masters.tsx b/src/components/Masters/Masters.tsx
index ea07603..7846fc8 100644
--- a/src/components/Masters/Masters.tsx
+++ b/src/components/Masters/Masters.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import React, { useEffect, useState } from 'react';
import {
Box,
Heading,
@@ -10,12 +10,17 @@ import {
Button,
useDisclosure,
Flex,
+ useToast,
+ Td,
+ Text,
+ Spinner,
} from '@chakra-ui/react';
import { useTranslation } from 'react-i18next';
import MasterItem from '../MasterItem';
import MasterDrawer from '../MasterDrawer';
-import data from '../../../stubs/json/arm-masters/success.json';
+import { armService } from '../../api/arm';
+import { MasterProps } from '../MasterItem/MasterItem';
const TABLE_HEADERS = [
'name' as const,
@@ -26,11 +31,41 @@ const TABLE_HEADERS = [
const Masters = () => {
const { isOpen, onOpen, onClose } = useDisclosure();
-
+ const toast = useToast();
const { t } = useTranslation('~', {
keyPrefix: 'dry-wash.arm.master',
});
+ const [masters, setMasters] = useState([]);
+ const [loading, setLoading] = useState(false);
+ const [error, setError] = useState(null);
+
+ const { fetchMasters } = armService();
+
+ useEffect(() => {
+ const loadMasters = async () => {
+ setLoading(true);
+
+ try {
+ const data = await fetchMasters();
+ setMasters(data.body);
+ } catch (err) {
+ setError(err.message);
+ toast({
+ title: t('error.title'),
+ status: 'error',
+ duration: 5000,
+ isClosable: true,
+ position: 'bottom-right',
+ });
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ loadMasters();
+ }, [toast, t]);
+
return (
@@ -48,9 +83,25 @@ const Masters = () => {
- {data.body.map((master, index) => (
-
- ))}
+ {loading && (
+
+
+
+ |
+
+ )}
+ {!loading && masters.length === 0 && !error && (
+
+
+ {t('table.empty')}
+ |
+
+ )}
+ {!loading &&
+ !error &&
+ masters.map((master, index) => (
+
+ ))}
diff --git a/src/components/Orders/Orders.tsx b/src/components/Orders/Orders.tsx
index 10831e7..e2dd6bc 100644
--- a/src/components/Orders/Orders.tsx
+++ b/src/components/Orders/Orders.tsx
@@ -1,24 +1,68 @@
-import React from 'react';
-import { Box, Heading, Table, Thead, Tbody, Tr, Th } from '@chakra-ui/react';
+import React, { useEffect, useState } from 'react';
+import {
+ Box,
+ Heading,
+ Table,
+ Thead,
+ Tbody,
+ Tr,
+ Th,
+ Spinner,
+ Text,
+ Td,
+ useToast,
+} from '@chakra-ui/react';
import { useTranslation } from 'react-i18next';
import OrderItem from '../OrderItem';
import { OrderProps } from '../OrderItem/OrderItem';
-import data from '../../../stubs/json/arm-orders/success.json';
+import { armService } from '../../api/arm';
+
+const TABLE_HEADERS = [
+ 'carNumber' as const,
+ 'washingTime' as const,
+ 'orderDate' as const,
+ 'status' as const,
+ 'telephone' as const,
+ 'location' as const,
+];
const Orders = () => {
const { t } = useTranslation('~', {
keyPrefix: 'dry-wash.arm.order',
});
- const TABLE_HEADERS = [
- 'carNumber' as const,
- 'washingTime' as const,
- 'orderDate' as const,
- 'status' as const,
- 'telephone' as const,
- 'location' as const,
- ];
+ const { fetchOrders } = armService();
+
+ const toast = useToast();
+
+ const [orders, setOrders] = useState([]);
+ const [loading, setLoading] = useState(false);
+ const [error, setError] = useState(null);
+
+ useEffect(() => {
+ const loadOrders = async () => {
+ setLoading(true);
+
+ try {
+ const data = await fetchOrders();
+ setOrders(data.body);
+ } catch (err) {
+ setError(err.message);
+ toast({
+ title: t('error.title'),
+ status: 'error',
+ duration: 5000,
+ isClosable: true,
+ position: 'bottom-right',
+ });
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ loadOrders();
+ }, [toast, t]);
return (
@@ -34,13 +78,29 @@ const Orders = () => {
- {data.body.map((order, index) => (
-
- ))}
+ {loading && (
+
+
+
+ |
+
+ )}
+ {!loading && orders.length === 0 && !error && (
+
+
+ {t('table.empty')}
+ |
+
+ )}
+ {!loading &&
+ !error &&
+ orders.map((order, index) => (
+
+ ))}
diff --git a/stubs/api/index.js b/stubs/api/index.js
index 22ac104..b4df477 100644
--- a/stubs/api/index.js
+++ b/stubs/api/index.js
@@ -6,7 +6,10 @@ const STUBS = require('./admin').STUBS;
const commonError = { success: false, message: 'Что-то пошло не так' };
-const sleep = (duration = 300) => (req, res, next) => setTimeout(next, duration);
+const sleep =
+ (duration = 1000) =>
+ (req, res, next) =>
+ setTimeout(next, duration);
router.use(sleep());
@@ -32,4 +35,4 @@ router.get('/arm/orders', (req, res) => {
router.use('/admin', require('./admin'));
-module.exports = router;
\ No newline at end of file
+module.exports = router;