mirror of
https://github.com/sergeyyarkov/educt-client.git
synced 2026-10-11 18:29:15 +03:00
feat: category deleting
This commit is contained in:
parent
94fa16de07
commit
6e2aa84b4a
3
src/components/ConfirmDialog/index.ts
Normal file
3
src/components/ConfirmDialog/index.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import ConfirmDialog from './ConfirmDialog';
|
||||||
|
|
||||||
|
export default ConfirmDialog;
|
||||||
@ -0,0 +1,47 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import ConfirmDialog from '@educt/components/ConfirmDialog';
|
||||||
|
import { ICategory } from '@educt/interfaces';
|
||||||
|
import useIsMountedRef from '@educt/hooks/useIsMountedRef';
|
||||||
|
import { useDeleteCategory } from '@educt/hooks/queries';
|
||||||
|
|
||||||
|
type DeleteCategoryDialogPropsType = {
|
||||||
|
category: ICategory;
|
||||||
|
isOpen: boolean;
|
||||||
|
onClose: () => void;
|
||||||
|
onDeleted?: (category: ICategory) => void | undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
const DeleteCategoryDialog: React.FC<DeleteCategoryDialogPropsType> = ({ onClose, onDeleted, isOpen, category }) => {
|
||||||
|
const { deleteCategory, isLoading } = useDeleteCategory();
|
||||||
|
const isMountedRef = useIsMountedRef();
|
||||||
|
const handleDelete = async (isConfirmed: boolean, id: string) => {
|
||||||
|
if (isConfirmed) {
|
||||||
|
try {
|
||||||
|
await deleteCategory(id);
|
||||||
|
onDeleted && onDeleted(category);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isMountedRef.current) {
|
||||||
|
/**
|
||||||
|
* Close dialog
|
||||||
|
*/
|
||||||
|
onClose();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ConfirmDialog
|
||||||
|
isOpen={isOpen}
|
||||||
|
isLoading={isLoading}
|
||||||
|
onClose={isConfirmed => handleDelete(isConfirmed, category.id)}
|
||||||
|
title='Confirm deleting'
|
||||||
|
message={`The category with title "${category.title}" will be removed from the system. After deleting a category, the courses in it will also be deleted.`}
|
||||||
|
confirmMessage='Delete'
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default DeleteCategoryDialog;
|
||||||
3
src/components/Dialogs/DeleteCategoryDialog/index.ts
Normal file
3
src/components/Dialogs/DeleteCategoryDialog/index.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import DeleteCategoryDialog from './DeleteCategoryDialog';
|
||||||
|
|
||||||
|
export default DeleteCategoryDialog;
|
||||||
@ -10,6 +10,7 @@ import { CategoryTableRowPropsType } from './CategoryTableRow';
|
|||||||
*/
|
*/
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import AddCategoryModal from '@educt/components/Modals/AddCategoryModal';
|
import AddCategoryModal from '@educt/components/Modals/AddCategoryModal';
|
||||||
|
import DeleteCategoryDialog from '@educt/components/Dialogs/DeleteCategoryDialog';
|
||||||
|
|
||||||
type CategoryTableListPropsType = {
|
type CategoryTableListPropsType = {
|
||||||
render: React.FC<CategoryTableRowPropsType>;
|
render: React.FC<CategoryTableRowPropsType>;
|
||||||
@ -19,14 +20,18 @@ type CategoryTableListPropsType = {
|
|||||||
const CategoryTableList: React.FC<CategoryTableListPropsType> = props => {
|
const CategoryTableList: React.FC<CategoryTableListPropsType> = props => {
|
||||||
const { render: Row, categories } = props;
|
const { render: Row, categories } = props;
|
||||||
const [rows, setRows] = useState<ICategory[]>(categories);
|
const [rows, setRows] = useState<ICategory[]>(categories);
|
||||||
|
const [deleting, setDeleting] = useState<ICategory | null>(null);
|
||||||
const { onOpen: onOpenCategoryModal, onClose: onCloseCategoryModal, isOpen: isOpenCategoryModal } = useDisclosure();
|
const { onOpen: onOpenCategoryModal, onClose: onCloseCategoryModal, isOpen: isOpenCategoryModal } = useDisclosure();
|
||||||
|
const { onOpen: onOpenDeleteDialog, onClose: onCloseDeleteDialog, isOpen: isOpenDeleteDialog } = useDisclosure();
|
||||||
|
|
||||||
const isEmptyRows = rows.length === 0;
|
const isEmptyRows = rows.length === 0;
|
||||||
|
|
||||||
const handleAddCategory = (category: ICategory) => setRows(prev => [...prev, category]);
|
const handleAddCategory = (category: ICategory) => setRows(prev => [...prev, category]);
|
||||||
|
|
||||||
// TODO make delete query
|
const handleDelete = (category: ICategory) => () => {
|
||||||
const handleDelete = () => () => undefined;
|
setDeleting(category);
|
||||||
|
onOpenDeleteDialog();
|
||||||
|
};
|
||||||
|
|
||||||
// TODO make edit query
|
// TODO make edit query
|
||||||
const handleEdit = () => () => undefined;
|
const handleEdit = () => () => undefined;
|
||||||
@ -38,6 +43,14 @@ const CategoryTableList: React.FC<CategoryTableListPropsType> = props => {
|
|||||||
onClose={onCloseCategoryModal}
|
onClose={onCloseCategoryModal}
|
||||||
onAdded={category => handleAddCategory(category)}
|
onAdded={category => handleAddCategory(category)}
|
||||||
/>
|
/>
|
||||||
|
{deleting && (
|
||||||
|
<DeleteCategoryDialog
|
||||||
|
category={deleting}
|
||||||
|
isOpen={isOpenDeleteDialog}
|
||||||
|
onClose={onCloseDeleteDialog}
|
||||||
|
onDeleted={deleted => setRows(prev => prev.filter(category => category.id !== deleted.id))}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<Flex justifyContent={'flex-end'}>
|
<Flex justifyContent={'flex-end'}>
|
||||||
<CreateButton onClick={onOpenCategoryModal} />
|
<CreateButton onClick={onOpenCategoryModal} />
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|||||||
@ -7,7 +7,7 @@ export type CategoryTableRowPropsType = {
|
|||||||
category: ICategory;
|
category: ICategory;
|
||||||
actions: {
|
actions: {
|
||||||
onEdit: (category: ICategory) => () => void;
|
onEdit: (category: ICategory) => () => void;
|
||||||
onDelete: (id: string) => () => void;
|
onDelete: (category: ICategory) => () => void;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -18,7 +18,7 @@ const CategoryTableRow: React.FC<CategoryTableRowPropsType> = ({ category, actio
|
|||||||
<NameCell name={category.title} />
|
<NameCell name={category.title} />
|
||||||
<CreatedCell created={category.created_at} />
|
<CreatedCell created={category.created_at} />
|
||||||
<UpdatedCell updated={category.updated_at} />
|
<UpdatedCell updated={category.updated_at} />
|
||||||
<ActionsCell onEdit={actions.onEdit(category)} onDelete={actions.onDelete(category.id)} />
|
<ActionsCell onEdit={actions.onEdit(category)} onDelete={actions.onDelete(category)} />
|
||||||
</Tr>
|
</Tr>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
34
src/hooks/queries/category/useDeleteCategory.ts
Normal file
34
src/hooks/queries/category/useDeleteCategory.ts
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
import axios from 'axios';
|
||||||
|
import { CategoryServiceInstance } from '@educt/services';
|
||||||
|
import { useErrorHandler } from 'react-error-boundary';
|
||||||
|
import { ICategory } from '@educt/interfaces';
|
||||||
|
import { useToast } from '@chakra-ui/react';
|
||||||
|
import useAsync from '@educt/hooks/useAsync';
|
||||||
|
|
||||||
|
const useDeleteCategory = () => {
|
||||||
|
const toast = useToast();
|
||||||
|
const handleError = useErrorHandler();
|
||||||
|
|
||||||
|
const query = async (id: string) => {
|
||||||
|
try {
|
||||||
|
const result = await CategoryServiceInstance.delete(id);
|
||||||
|
toast({ title: 'Category deleted.', status: 'info' });
|
||||||
|
return result.data;
|
||||||
|
} catch (error) {
|
||||||
|
if (axios.isAxiosError(error)) {
|
||||||
|
if (error.response) {
|
||||||
|
console.error('Error: ', error);
|
||||||
|
} else {
|
||||||
|
handleError(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Promise.reject(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const { execute: deleteCategory, ...state } = useAsync<ICategory, Parameters<typeof query>>(query);
|
||||||
|
|
||||||
|
return { deleteCategory, ...state };
|
||||||
|
};
|
||||||
|
|
||||||
|
export { useDeleteCategory };
|
||||||
@ -34,6 +34,7 @@ import { useUpdateUserEmail } from './user/useUpdateUserEmail';
|
|||||||
*/
|
*/
|
||||||
import { useFetchCategories } from './category/useFetchCategories';
|
import { useFetchCategories } from './category/useFetchCategories';
|
||||||
import { useCreateCategory } from './category/useCreateCategory';
|
import { useCreateCategory } from './category/useCreateCategory';
|
||||||
|
import { useDeleteCategory } from './category/useDeleteCategory';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
useLogin,
|
useLogin,
|
||||||
@ -52,5 +53,6 @@ export {
|
|||||||
useUpdateUser,
|
useUpdateUser,
|
||||||
useUpdateUserEmail,
|
useUpdateUserEmail,
|
||||||
useCreateCategory,
|
useCreateCategory,
|
||||||
|
useDeleteCategory,
|
||||||
useFetchCategories,
|
useFetchCategories,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -29,6 +29,17 @@ class CategoryService {
|
|||||||
const result = await this.api.post('/v1/categories', data);
|
const result = await this.api.post('/v1/categories', data);
|
||||||
return result.data;
|
return result.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete category by id
|
||||||
|
*
|
||||||
|
* @param id Category id
|
||||||
|
* @returns Deleted category
|
||||||
|
*/
|
||||||
|
public async delete(id: string): Promise<IApiRespose<ICategory>> {
|
||||||
|
const result = await this.api.delete(`/v1/categories/${id}`);
|
||||||
|
return result.data;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const CategoryServiceInstance = new CategoryService(ApiServiceInstance.api);
|
export const CategoryServiceInstance = new CategoryService(ApiServiceInstance.api);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user