mirror of
https://github.com/shlinkio/shlink-web-client.git
synced 2024-12-23 17:40:23 +03:00
Ensured tags deleted are not removed from list until modal has been hidden
This commit is contained in:
parent
0571a4a88f
commit
dbb08a6ce0
4 changed files with 20 additions and 17 deletions
|
@ -13,15 +13,14 @@ interface DeleteTagConfirmModalProps extends TagModalProps {
|
||||||
export const DeleteTagConfirmModal = (
|
export const DeleteTagConfirmModal = (
|
||||||
{ tag, toggle, isOpen, deleteTag, tagDelete, tagDeleted }: DeleteTagConfirmModalProps,
|
{ tag, toggle, isOpen, deleteTag, tagDelete, tagDeleted }: DeleteTagConfirmModalProps,
|
||||||
) => {
|
) => {
|
||||||
const { deleting, error, errorData } = tagDelete;
|
const { deleting, error, deleted, errorData } = tagDelete;
|
||||||
const doDelete = async () => {
|
const doDelete = async () => {
|
||||||
await deleteTag(tag);
|
await deleteTag(tag);
|
||||||
tagDeleted(tag);
|
|
||||||
toggle();
|
toggle();
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal toggle={toggle} isOpen={isOpen} centered>
|
<Modal toggle={toggle} isOpen={isOpen} centered onClosed={() => deleted && tagDeleted(tag)}>
|
||||||
<ModalHeader toggle={toggle} className="text-danger">Delete tag</ModalHeader>
|
<ModalHeader toggle={toggle} className="text-danger">Delete tag</ModalHeader>
|
||||||
<ModalBody>
|
<ModalBody>
|
||||||
Are you sure you want to delete tag <b>{tag}</b>?
|
Are you sure you want to delete tag <b>{tag}</b>?
|
||||||
|
|
|
@ -13,6 +13,7 @@ export const TAG_DELETED = 'shlink/deleteTag/TAG_DELETED';
|
||||||
|
|
||||||
export interface TagDeletion {
|
export interface TagDeletion {
|
||||||
deleting: boolean;
|
deleting: boolean;
|
||||||
|
deleted: boolean;
|
||||||
error: boolean;
|
error: boolean;
|
||||||
errorData?: ProblemDetailsError;
|
errorData?: ProblemDetailsError;
|
||||||
}
|
}
|
||||||
|
@ -23,13 +24,14 @@ export interface DeleteTagAction extends Action<string> {
|
||||||
|
|
||||||
const initialState: TagDeletion = {
|
const initialState: TagDeletion = {
|
||||||
deleting: false,
|
deleting: false,
|
||||||
|
deleted: false,
|
||||||
error: false,
|
error: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default buildReducer<TagDeletion, ApiErrorAction>({
|
export default buildReducer<TagDeletion, ApiErrorAction>({
|
||||||
[DELETE_TAG_START]: () => ({ deleting: true, error: false }),
|
[DELETE_TAG_START]: () => ({ deleting: true, deleted: false, error: false }),
|
||||||
[DELETE_TAG_ERROR]: (_, { errorData }) => ({ deleting: false, error: true, errorData }),
|
[DELETE_TAG_ERROR]: (_, { errorData }) => ({ deleting: false, deleted: false, error: true, errorData }),
|
||||||
[DELETE_TAG]: () => ({ deleting: false, error: false }),
|
[DELETE_TAG]: () => ({ deleting: false, deleted: true, error: false }),
|
||||||
}, initialState);
|
}, initialState);
|
||||||
|
|
||||||
export const deleteTag = (buildShlinkApiClient: ShlinkApiClientBuilder) => (tag: string) => async (
|
export const deleteTag = (buildShlinkApiClient: ShlinkApiClientBuilder) => (tag: string) => async (
|
||||||
|
|
|
@ -6,14 +6,14 @@ import { renderWithEvents } from '../../__helpers__/setUpTest';
|
||||||
describe('<DeleteTagConfirmModal />', () => {
|
describe('<DeleteTagConfirmModal />', () => {
|
||||||
const tag = 'nodejs';
|
const tag = 'nodejs';
|
||||||
const deleteTag = jest.fn();
|
const deleteTag = jest.fn();
|
||||||
const tagDeleted = jest.fn();
|
const toggle = jest.fn();
|
||||||
const setUp = (tagDelete: TagDeletion) => renderWithEvents(
|
const setUp = (tagDelete: TagDeletion) => renderWithEvents(
|
||||||
<DeleteTagConfirmModal
|
<DeleteTagConfirmModal
|
||||||
tag={tag}
|
tag={tag}
|
||||||
toggle={() => ''}
|
toggle={toggle}
|
||||||
isOpen
|
isOpen
|
||||||
deleteTag={deleteTag}
|
deleteTag={deleteTag}
|
||||||
tagDeleted={tagDeleted}
|
tagDeleted={jest.fn()}
|
||||||
tagDelete={tagDelete}
|
tagDelete={tagDelete}
|
||||||
/>,
|
/>,
|
||||||
);
|
);
|
||||||
|
@ -21,7 +21,7 @@ describe('<DeleteTagConfirmModal />', () => {
|
||||||
afterEach(jest.resetAllMocks);
|
afterEach(jest.resetAllMocks);
|
||||||
|
|
||||||
it('asks confirmation for provided tag to be deleted', () => {
|
it('asks confirmation for provided tag to be deleted', () => {
|
||||||
setUp({ error: false, deleting: false });
|
setUp({ error: false, deleted: false, deleting: false });
|
||||||
|
|
||||||
const delBtn = screen.getByRole('button', { name: 'Delete tag' });
|
const delBtn = screen.getByRole('button', { name: 'Delete tag' });
|
||||||
|
|
||||||
|
@ -33,12 +33,12 @@ describe('<DeleteTagConfirmModal />', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('shows error message when deletion failed', () => {
|
it('shows error message when deletion failed', () => {
|
||||||
setUp({ error: true, deleting: false });
|
setUp({ error: true, deleted: false, deleting: false });
|
||||||
expect(screen.getByText('Something went wrong while deleting the tag :(')).toBeInTheDocument();
|
expect(screen.getByText('Something went wrong while deleting the tag :(')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('shows loading status while deleting', () => {
|
it('shows loading status while deleting', () => {
|
||||||
setUp({ error: false, deleting: true });
|
setUp({ error: false, deleted: false, deleting: true });
|
||||||
|
|
||||||
const delBtn = screen.getByRole('button', { name: 'Deleting tag...' });
|
const delBtn = screen.getByRole('button', { name: 'Deleting tag...' });
|
||||||
|
|
||||||
|
@ -48,22 +48,21 @@ describe('<DeleteTagConfirmModal />', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('hides tag modal when btn is clicked', async () => {
|
it('hides tag modal when btn is clicked', async () => {
|
||||||
const { user } = setUp({ error: false, deleting: false });
|
const { user } = setUp({ error: false, deleted: true, deleting: false });
|
||||||
|
|
||||||
await user.click(screen.getByRole('button', { name: 'Delete tag' }));
|
await user.click(screen.getByRole('button', { name: 'Delete tag' }));
|
||||||
|
|
||||||
expect(deleteTag).toHaveBeenCalledTimes(1);
|
expect(deleteTag).toHaveBeenCalledTimes(1);
|
||||||
expect(deleteTag).toHaveBeenCalledWith(tag);
|
expect(deleteTag).toHaveBeenCalledWith(tag);
|
||||||
expect(tagDeleted).toHaveBeenCalledTimes(1);
|
expect(toggle).toHaveBeenCalledTimes(1);
|
||||||
expect(tagDeleted).toHaveBeenCalledWith(tag);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('does no further actions when modal is closed without deleting tag', async () => {
|
it('does no further actions when modal is closed without deleting tag', async () => {
|
||||||
const { user } = setUp({ error: false, deleting: false });
|
const { user } = setUp({ error: false, deleted: true, deleting: false });
|
||||||
|
|
||||||
await user.click(screen.getByLabelText('Close'));
|
await user.click(screen.getByLabelText('Close'));
|
||||||
|
|
||||||
expect(deleteTag).not.toHaveBeenCalled();
|
expect(deleteTag).not.toHaveBeenCalled();
|
||||||
expect(tagDeleted).not.toHaveBeenCalled();
|
expect(toggle).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -15,6 +15,7 @@ describe('tagDeleteReducer', () => {
|
||||||
it('returns loading on DELETE_TAG_START', () => {
|
it('returns loading on DELETE_TAG_START', () => {
|
||||||
expect(reducer(undefined, { type: DELETE_TAG_START })).toEqual({
|
expect(reducer(undefined, { type: DELETE_TAG_START })).toEqual({
|
||||||
deleting: true,
|
deleting: true,
|
||||||
|
deleted: false,
|
||||||
error: false,
|
error: false,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -22,6 +23,7 @@ describe('tagDeleteReducer', () => {
|
||||||
it('returns error on DELETE_TAG_ERROR', () => {
|
it('returns error on DELETE_TAG_ERROR', () => {
|
||||||
expect(reducer(undefined, { type: DELETE_TAG_ERROR })).toEqual({
|
expect(reducer(undefined, { type: DELETE_TAG_ERROR })).toEqual({
|
||||||
deleting: false,
|
deleting: false,
|
||||||
|
deleted: false,
|
||||||
error: true,
|
error: true,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -29,6 +31,7 @@ describe('tagDeleteReducer', () => {
|
||||||
it('returns tag names on DELETE_TAG', () => {
|
it('returns tag names on DELETE_TAG', () => {
|
||||||
expect(reducer(undefined, { type: DELETE_TAG })).toEqual({
|
expect(reducer(undefined, { type: DELETE_TAG })).toEqual({
|
||||||
deleting: false,
|
deleting: false,
|
||||||
|
deleted: true,
|
||||||
error: false,
|
error: false,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue