feat: add hook useShowToast.ts
All checks were successful
it-academy/dry-wash-pl/pipeline/pr-main This commit looks good

This commit is contained in:
Ильназ 2025-02-08 22:18:32 +03:00
parent a00aaff29d
commit ed8ae95436
9 changed files with 65 additions and 102 deletions

View File

@ -25,10 +25,16 @@
"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.table.actionsMenu.toast.success": "Мастер удалён",
"dry-wash.arm.master.table.actionsMenu.toast.error.title": "Ошибка!",
"dry-wash.arm.master.table.actionsMenu.toast.error.description": "Не удалось удалить мастера. Попробуйте ещё раз.",
"dry-wash.arm.master.schedule.empty": "Свободен", "dry-wash.arm.master.schedule.empty": "Свободен",
"dry-wash.arm.master.editable.aria.cancel": "Отменить изменения", "dry-wash.arm.master.editable.aria.cancel": "Отменить изменения",
"dry-wash.arm.master.editable.aria.save": "Сохранить изменения", "dry-wash.arm.master.editable.aria.save": "Сохранить изменения",
"dry-wash.arm.master.editable.aria.edit": "Редактировать", "dry-wash.arm.master.editable.aria.edit": "Редактировать",
"dry-wash.arm.master.editable.toast.success": "Успешно!",
"dry-wash.arm.master.editable.toast.error.description": "Не удалось обновить данные",
"dry-wash.arm.master.editable.toast.error.title": "Ошибка!",
"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

@ -9,20 +9,20 @@ import {
useEditableControls, useEditableControls,
ButtonGroup, ButtonGroup,
Stack, Stack,
useToast,
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import { CheckIcon, CloseIcon, EditIcon } from '@chakra-ui/icons'; import { CheckIcon, CloseIcon, EditIcon } from '@chakra-ui/icons';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useUpdateMasterMutation } from '../../__data__/service/api'; import { useUpdateMasterMutation } from '../../__data__/service/api';
import useShowToast from '../../hooks/useShowToast';
interface EditableWrapperProps { interface EditableWrapperProps {
value: string; value: string;
as: 'phone' | 'name'; fieldName: 'phone' | 'name';
id: string; id: string;
} }
const EditableWrapper = ({ value, as, id }: EditableWrapperProps) => { const EditableWrapper = ({ value, fieldName, id }: EditableWrapperProps) => {
const [updateMaster, { isError, isSuccess, error }] = const [updateMaster, { isError, isSuccess, error }] =
useUpdateMasterMutation(); useUpdateMasterMutation();
@ -30,41 +30,27 @@ const EditableWrapper = ({ value, as, id }: EditableWrapperProps) => {
keyPrefix: 'dry-wash.arm.master.editable', keyPrefix: 'dry-wash.arm.master.editable',
}); });
const toast = useToast(); const showToast = useShowToast();
const [currentValue, setCurrentValue] = useState<string>(value); const [currentValue, setCurrentValue] = useState<string>(value);
const handleSubmit = async (newValue: string) => { const handleSubmit = async (newValue: string) => {
if (currentValue === newValue) return; if (currentValue === newValue) return;
await updateMaster({ id, [as]: newValue }); await updateMaster({ id, [fieldName]: newValue });
setCurrentValue(newValue); setCurrentValue(newValue);
}; };
useEffect(() => { useEffect(() => {
if (isSuccess) { if (isSuccess) {
toast({ showToast(t('toast.success'), 'success');
title: 'Успешно!',
description: 'Данные обновлены.',
status: 'success',
duration: 2000,
isClosable: true,
position: 'top-right',
});
} }
}, [isSuccess]); }, [isSuccess]);
useEffect(() => { useEffect(() => {
if (isError) { if (isError) {
toast({ showToast(t('toast.error.title'), 'error', t('toast.error.description'));
title: 'Ошибка!', console.error(t('toast.error.description'), error);
description: 'Не удалось обновить данные.',
status: 'error',
duration: 2000,
isClosable: true,
position: 'top-right',
});
console.error('Ошибка при обновлении данных:', error);
} }
}, [isError, error]); }, [isError, error]);

View File

@ -5,12 +5,12 @@ import {
MenuList, MenuList,
MenuItem, MenuItem,
IconButton, IconButton,
useToast,
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import { EditIcon } from '@chakra-ui/icons'; import { EditIcon } from '@chakra-ui/icons';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useDeleteMasterMutation } from '../../__data__/service/api'; import { useDeleteMasterMutation } from '../../__data__/service/api';
import useShowToast from '../../hooks/useShowToast';
interface MasterActionsMenu { interface MasterActionsMenu {
id: string; id: string;
@ -24,7 +24,7 @@ const MasterActionsMenu = ({ id }: MasterActionsMenu) => {
const [deleteMaster, { isSuccess, isError, error, isLoading }] = const [deleteMaster, { isSuccess, isError, error, isLoading }] =
useDeleteMasterMutation(); useDeleteMasterMutation();
const toast = useToast(); const showToast = useShowToast();
const handleClickDelete = async () => { const handleClickDelete = async () => {
await deleteMaster({ id }); await deleteMaster({ id });
@ -32,27 +32,13 @@ const MasterActionsMenu = ({ id }: MasterActionsMenu) => {
useEffect(() => { useEffect(() => {
if (isSuccess) { if (isSuccess) {
toast({ showToast(t('toast.success'), 'success');
title: 'Мастер удалён.',
description: `Мастер с ID "${id}" успешно удалён.`,
status: 'success',
duration: 5000,
isClosable: true,
position: 'top-right',
});
} }
}, [isSuccess]); }, [isSuccess]);
useEffect(() => { useEffect(() => {
if (isError) { if (isError) {
toast({ showToast(t('toast.error.title'), 'error', t('toast.error.description'));
title: 'Ошибка удаления мастера.',
description: 'Не удалось удалить мастера. Попробуйте ещё раз.',
status: 'error',
duration: 5000,
isClosable: true,
position: 'top-right',
});
console.error(error); console.error(error);
} }
}, [isError]); }, [isError]);

View File

@ -12,7 +12,6 @@ import {
DrawerFooter, DrawerFooter,
DrawerHeader, DrawerHeader,
DrawerOverlay, DrawerOverlay,
useToast,
InputGroup, InputGroup,
InputLeftElement, InputLeftElement,
FormErrorMessage, FormErrorMessage,
@ -21,8 +20,8 @@ import { useTranslation } from 'react-i18next';
import { PhoneIcon } from '@chakra-ui/icons'; import { PhoneIcon } from '@chakra-ui/icons';
import { api } from '../../__data__/service/api'; import { api } from '../../__data__/service/api';
import showToast from '../../helpers/showToast';
import { DrawerInputs } from '../../models/arm/form'; import { DrawerInputs } from '../../models/arm/form';
import useShowToast from '../../hooks/useShowToast';
interface MasterDrawerProps { interface MasterDrawerProps {
isOpen: boolean; isOpen: boolean;
@ -50,12 +49,7 @@ const MasterDrawer = ({ isOpen, onClose }: MasterDrawerProps) => {
const isEmptyFields = trimMaster.name === '' || trimMaster.phone === ''; const isEmptyFields = trimMaster.name === '' || trimMaster.phone === '';
if (isEmptyFields) { if (isEmptyFields) {
showToast({ showToast(t('toast.error.base'), 'error', t('toast.error.empty-fields'));
toast,
title: t('toast.error.base'),
description: t('toast.error.empty-fields'),
status: 'error',
});
return; return;
} }
@ -63,15 +57,11 @@ const MasterDrawer = ({ isOpen, onClose }: MasterDrawerProps) => {
}; };
const [addMaster, { error, isSuccess }] = api.useAddMasterMutation(); const [addMaster, { error, isSuccess }] = api.useAddMasterMutation();
const toast = useToast(); const showToast = useShowToast();
useEffect(() => { useEffect(() => {
if (isSuccess) { if (isSuccess) {
showToast({ showToast(t('toast.create-master'), 'success');
toast,
title: t('toast.create-master'),
status: 'success',
});
reset(); reset();
onClose(); onClose();
} }
@ -79,12 +69,11 @@ const MasterDrawer = ({ isOpen, onClose }: MasterDrawerProps) => {
useEffect(() => { useEffect(() => {
if (error) { if (error) {
showToast({ showToast(
toast, t('toast.error.create-master'),
title: t('toast.error.create-master'), 'error',
description: t('toast.error.create-master-details'), t('toast.error.create-master-details'),
status: 'error', );
});
console.error(error); console.error(error);
} }
}, [error]); }, [error]);

View File

@ -14,7 +14,7 @@ const MasterItem = ({ name, phone, id, schedule }) => {
return ( return (
<Tr> <Tr>
<Td> <Td>
<EditableWrapper id={id} as={'name'} value={name} /> <EditableWrapper id={id} fieldName={'name'} value={name} />
</Td> </Td>
<Td> <Td>
{schedule?.length > 0 ? ( {schedule?.length > 0 ? (
@ -30,7 +30,7 @@ const MasterItem = ({ name, phone, id, schedule }) => {
)} )}
</Td> </Td>
<Td> <Td>
<EditableWrapper id={id} as={'phone'} value={phone} /> <EditableWrapper id={id} fieldName={'phone'} value={phone} />
</Td> </Td>
<Td> <Td>
<MasterActionsMenu id={id} /> <MasterActionsMenu id={id} />

View File

@ -10,7 +10,6 @@ import {
Button, Button,
useDisclosure, useDisclosure,
Flex, Flex,
useToast,
Td, Td,
Text, Text,
Spinner, Spinner,
@ -20,6 +19,7 @@ import { useTranslation } from 'react-i18next';
import MasterItem from '../MasterItem'; import MasterItem from '../MasterItem';
import MasterDrawer from '../MasterDrawer'; import MasterDrawer from '../MasterDrawer';
import { useGetMastersQuery } from '../../__data__/service/api'; import { useGetMastersQuery } from '../../__data__/service/api';
import useShowToast from '../../hooks/useShowToast';
const TABLE_HEADERS = [ const TABLE_HEADERS = [
'name' as const, 'name' as const,
@ -30,7 +30,8 @@ const TABLE_HEADERS = [
const Masters = () => { const Masters = () => {
const { isOpen, onOpen, onClose } = useDisclosure(); const { isOpen, onOpen, onClose } = useDisclosure();
const toast = useToast(); const showToast = useShowToast();
const { t } = useTranslation('~', { const { t } = useTranslation('~', {
keyPrefix: 'dry-wash.arm.master', keyPrefix: 'dry-wash.arm.master',
}); });
@ -39,12 +40,7 @@ const Masters = () => {
useEffect(() => { useEffect(() => {
if (error) { if (error) {
toast({ showToast(t('error.title'), 'error');
title: t('error.title'),
status: 'error',
isClosable: true,
position: 'bottom-right',
});
} }
}, [error]); }, [error]);

View File

@ -10,7 +10,6 @@ import {
Spinner, Spinner,
Text, Text,
Td, Td,
useToast,
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
@ -22,6 +21,7 @@ import {
useGetMastersQuery, useGetMastersQuery,
useGetOrdersQuery, useGetOrdersQuery,
} from '../../__data__/service/api'; } from '../../__data__/service/api';
import useShowToast from '../../hooks/useShowToast';
const TABLE_HEADERS = [ const TABLE_HEADERS = [
'carNumber' as const, 'carNumber' as const,
@ -36,7 +36,7 @@ const Orders = () => {
const { t } = useTranslation('~', { const { t } = useTranslation('~', {
keyPrefix: 'dry-wash.arm.order', keyPrefix: 'dry-wash.arm.order',
}); });
const toast = useToast(); const showToast = useShowToast();
const [currentDate, setCurrentDate] = useState(new Date()); const [currentDate, setCurrentDate] = useState(new Date());
const { const {
@ -61,16 +61,9 @@ const Orders = () => {
useEffect(() => { useEffect(() => {
if (isError) { if (isError) {
toast({ showToast(t('error.title'), 'error');
title: t('error.title'),
// description: errorMessage,
status: 'error',
duration: 5000,
isClosable: true,
position: 'bottom-right',
});
} }
}, [isError, ordersError, mastersError, toast, t]); }, [isError, ordersError, mastersError, t]);
return ( return (
<Box p='8'> <Box p='8'>

View File

@ -1,21 +0,0 @@
import { UseToastOptions } from '@chakra-ui/react';
interface ShowToast {
toast: (options: UseToastOptions) => void;
title: string;
description?: string;
status: 'info' | 'warning' | 'success' | 'error';
}
const showToast = ({ toast, title, description, status }: ShowToast) => {
toast({
title,
description,
status,
duration: 5000,
isClosable: true,
position: 'top-right',
});
};
export default showToast;

28
src/hooks/useShowToast.ts Normal file
View File

@ -0,0 +1,28 @@
import { useToast } from '@chakra-ui/react';
import { useCallback } from 'react';
const useShowToast = () => {
const toast = useToast();
const showToast = useCallback(
(
title: string,
status: 'info' | 'warning' | 'success' | 'error',
description?: string,
) => {
toast({
title,
description,
status,
duration: 5000,
isClosable: true,
position: 'top-right',
});
},
[toast],
);
return showToast;
};
export default useShowToast;