feat: category deleting

This commit is contained in:
Sergey Yarkov 2022-01-19 21:46:37 +03:00
parent 94fa16de07
commit 6e2aa84b4a
8 changed files with 117 additions and 4 deletions

View File

@ -0,0 +1,3 @@
import ConfirmDialog from './ConfirmDialog';
export default ConfirmDialog;

View File

@ -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;

View File

@ -0,0 +1,3 @@
import DeleteCategoryDialog from './DeleteCategoryDialog';
export default DeleteCategoryDialog;

View File

@ -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>

View File

@ -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>
); );
}; };

View 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 };

View File

@ -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,
}; };

View File

@ -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);