Merge branch 'main' of ssh://85.143.175.152:222/dry_wash_inc/dry-wash-pl
All checks were successful
it-academy/dry-wash-pl/pipeline/head This commit looks good

This commit is contained in:
RustamRu 2025-01-19 10:55:56 +03:00
commit e73773f359
6 changed files with 195 additions and 24 deletions

View File

@ -73,6 +73,10 @@
"dry-wash.arm.master.table.header.phone": "Phone", "dry-wash.arm.master.table.header.phone": "Phone",
"dry-wash.arm.master.table.header.actions": "Actions", "dry-wash.arm.master.table.header.actions": "Actions",
"dry-wash.arm.master.table.actionsMenu.delete": "Delete Master", "dry-wash.arm.master.table.actionsMenu.delete": "Delete Master",
"dry-wash.arm.master.schedule.empty": "free",
"dry-wash.arm.master.editable.aria.cancel": "Undo changes",
"dry-wash.arm.master.editable.aria.save": "Save changes ",
"dry-wash.arm.master.editable.aria.edit": "Edit",
"dry-wash.arm.master.drawer.title": "Add New Master", "dry-wash.arm.master.drawer.title": "Add New Master",
"dry-wash.arm.master.drawer.inputName.label": "Full Name", "dry-wash.arm.master.drawer.inputName.label": "Full Name",
"dry-wash.arm.master.drawer.inputName.placeholder": "Enter Full Name", "dry-wash.arm.master.drawer.inputName.placeholder": "Enter Full Name",

View File

@ -24,6 +24,10 @@
"dry-wash.arm.master.table.header.phone": "Телефон", "dry-wash.arm.master.table.header.phone": "Телефон",
"dry-wash.arm.master.table.header.actions": "Действия", "dry-wash.arm.master.table.header.actions": "Действия",
"dry-wash.arm.master.table.actionsMenu.delete": "Удалить мастера", "dry-wash.arm.master.table.actionsMenu.delete": "Удалить мастера",
"dry-wash.arm.master.schedule.empty": "Свободен",
"dry-wash.arm.master.editable.aria.cancel": "Отменить изменения",
"dry-wash.arm.master.editable.aria.save": "Сохранить изменения",
"dry-wash.arm.master.editable.aria.edit": "Редактировать",
"dry-wash.arm.master.drawer.title": "Добавить нового мастера", "dry-wash.arm.master.drawer.title": "Добавить нового мастера",
"dry-wash.arm.master.drawer.inputName.label": "ФИО", "dry-wash.arm.master.drawer.inputName.label": "ФИО",
"dry-wash.arm.master.drawer.inputName.placeholder": "Введите ФИО", "dry-wash.arm.master.drawer.inputName.placeholder": "Введите ФИО",

View File

@ -1,4 +1,5 @@
import { getConfigValue } from '@brojs/cli'; import { getConfigValue } from '@brojs/cli';
import dayjs from 'dayjs';
enum ArmEndpoints { enum ArmEndpoints {
ORDERS = '/arm/orders', ORDERS = '/arm/orders',
@ -9,12 +10,15 @@ const armService = () => {
const endpoint = getConfigValue('dry-wash.api'); const endpoint = getConfigValue('dry-wash.api');
const fetchOrders = async ({ date }: { date: Date }) => { const fetchOrders = async ({ date }: { date: Date }) => {
const startDate = dayjs(date).startOf('day').toISOString();
const endDate = dayjs(date).endOf('day').toISOString();
const response = await fetch(`${endpoint}${ArmEndpoints.ORDERS}`, { const response = await fetch(`${endpoint}${ArmEndpoints.ORDERS}`, {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
}, },
body: JSON.stringify({ date }), body: JSON.stringify({ startDate, endDate }),
}); });
if (!response.ok) { if (!response.ok) {
@ -68,7 +72,33 @@ const armService = () => {
return await response.json(); return await response.json();
}; };
return { fetchOrders, fetchMasters, addMaster, deleteMaster }; const updateMaster = async ({
id,
name,
phone,
}: {
id: string;
name?: string;
phone?: string;
}) => {
const body = JSON.stringify({ name, phone });
const response = await fetch(`${endpoint}${ArmEndpoints.MASTERS}/${id}`, {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
},
body,
});
if (!response.ok) {
throw new Error(`Failed to fetch update masters: ${response.status}`);
}
return await response.json();
};
return { fetchOrders, fetchMasters, addMaster, deleteMaster, updateMaster };
}; };
export { armService, ArmEndpoints }; export { armService, ArmEndpoints };

View File

@ -0,0 +1,119 @@
import React, { useState } from 'react';
import {
Editable,
EditableInput,
EditablePreview,
Flex,
IconButton,
Input,
useEditableControls,
ButtonGroup,
Stack,
useToast,
} from '@chakra-ui/react';
import { CheckIcon, CloseIcon, EditIcon } from '@chakra-ui/icons';
import { useTranslation } from 'react-i18next';
interface EditableWrapperProps {
value: string;
onSubmit: ({
id,
name,
phone,
}: {
id: string;
name?: string;
phone?: string;
}) => Promise<unknown>;
as: 'phone' | 'name';
id: string;
}
const EditableWrapper = ({ value, onSubmit, as, id }: EditableWrapperProps) => {
const { t } = useTranslation('~', {
keyPrefix: 'dry-wash.arm.master.editable',
});
const toast = useToast();
const [currentValue, setCurrentValue] = useState<string>(value);
const handleSubmit = async (newValue: string) => {
if (currentValue === newValue) return;
try {
await onSubmit({ id, [as]: newValue });
setCurrentValue(newValue);
toast({
title: 'Успешно!',
description: 'Данные обновлены.',
status: 'success',
duration: 2000,
isClosable: true,
position: 'top-right',
});
} catch (error) {
toast({
title: 'Ошибка!',
description: 'Не удалось обновить данные.',
status: 'error',
duration: 2000,
isClosable: true,
position: 'top-right',
});
console.error('Ошибка при обновлении данных:', error);
}
};
function EditableControls() {
const {
isEditing,
getSubmitButtonProps,
getCancelButtonProps,
getEditButtonProps,
} = useEditableControls();
return isEditing ? (
<ButtonGroup justifyContent='center' size='sm'>
<IconButton
aria-label={t('aria.save')}
icon={<CheckIcon />}
{...getSubmitButtonProps()}
/>
<IconButton
aria-label={t('aria.cancel')}
icon={<CloseIcon />}
{...getCancelButtonProps()}
/>
</ButtonGroup>
) : (
<Flex justifyContent='center'>
<IconButton
aria-label={t('aria.edit')}
size='sm'
icon={<EditIcon />}
{...getEditButtonProps()}
/>
</Flex>
);
}
return (
<Editable
textAlign='center'
defaultValue={currentValue}
fontSize='2xl'
isPreviewFocusable={false}
onSubmit={handleSubmit}
>
<Stack direction={['column', 'row']} spacing='15px'>
<EditablePreview />
<Input as={EditableInput} />
<EditableControls />
</Stack>
</Editable>
);
};
export default EditableWrapper;

View File

@ -1,8 +1,11 @@
import React from 'react'; import React from 'react';
import { Badge, Link, Stack, Td, Tr } from '@chakra-ui/react'; import { Badge, Stack, Td, Tr, Text } from '@chakra-ui/react';
import { useTranslation } from 'react-i18next';
import MasterActionsMenu from '../MasterActionsMenu'; import MasterActionsMenu from '../MasterActionsMenu';
import { getTimeSlot } from '../../lib'; import { getTimeSlot } from '../../lib';
import EditableWrapper from '../Editable/Editable';
import { armService } from '../../api/arm';
export interface Schedule { export interface Schedule {
id: string; id: string;
@ -18,20 +21,41 @@ export type MasterProps = {
}; };
const MasterItem = ({ name, phone, id, schedule }) => { const MasterItem = ({ name, phone, id, schedule }) => {
const { updateMaster } = armService();
const { t } = useTranslation('~', {
keyPrefix: 'dry-wash.arm.master',
});
return ( return (
<Tr> <Tr>
<Td>{name}</Td>
<Td> <Td>
<Stack direction='row'> <EditableWrapper
{schedule?.map(({ startWashTime, endWashTime }, index) => ( id={id}
<Badge colorScheme={'green'} key={index}> as={'name'}
{getTimeSlot(startWashTime, endWashTime)} value={name}
</Badge> onSubmit={updateMaster}
))} />
</Stack>
</Td> </Td>
<Td> <Td>
<Link href='tel:'>{phone}</Link> {schedule?.length > 0 ? (
<Stack direction='row'>
{schedule?.map(({ startWashTime, endWashTime }, index: number) => (
<Badge colorScheme={'green'} key={index}>
{getTimeSlot(startWashTime, endWashTime)}
</Badge>
))}
</Stack>
) : (
<Text color='gray.500'>{t('schedule.empty')}</Text>
)}
</Td>
<Td>
<EditableWrapper
id={id}
as={'phone'}
value={phone}
onSubmit={updateMaster}
/>
</Td> </Td>
<Td> <Td>
<MasterActionsMenu id={id} /> <MasterActionsMenu id={id} />

View File

@ -2,22 +2,12 @@
"success": true, "success": true,
"body": [ "body": [
{ {
"id": "masters1", "id": "4545423234",
"name": "Иван Иванов", "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" "phone": "+7 900 123 45 67"
}, },
{ {
"id": "masters12", "id": "345354234",
"name": "Иван Иванов", "name": "Иван Иванов",
"schedule": [ { "schedule": [ {
"id": "order1", "id": "order1",