Ensured tags list is not updated until the edit modal is closed

This commit is contained in:
Alejandro Celaya 2022-11-07 21:32:19 +01:00
parent 2183b09ffe
commit 5ecc791b38
4 changed files with 19 additions and 21 deletions

View file

@ -1,3 +1,4 @@
import { pipe } from 'ramda';
import { useState } from 'react';
import { Button, Input, Modal, ModalBody, ModalFooter, ModalHeader, Popover, InputGroup } from 'reactstrap';
import { HexColorPicker } from 'react-colorful';
@ -24,16 +25,16 @@ export const EditTagModal = ({ getColorForKey }: ColorGenerator) => (
const [newTagName, setNewTagName] = useState(tag);
const [color, setColor] = useState(getColorForKey(tag));
const [showColorPicker, toggleColorPicker, , hideColorPicker] = useToggle();
const { editing, error, errorData } = tagEdit;
const { editing, error, edited, errorData } = tagEdit;
const saveTag = handleEventPreventingDefault(
async () => editTag(tag, newTagName, color)
.then(() => tagEdited(tag, newTagName, color))
.then(toggle)
.catch(() => {}),
);
const onClosed = pipe(hideColorPicker, () => edited && tagEdited(tag, newTagName, color));
return (
<Modal isOpen={isOpen} toggle={toggle} centered onClosed={hideColorPicker}>
<Modal isOpen={isOpen} toggle={toggle} centered onClosed={onClosed}>
<form name="editTag" onSubmit={saveTag}>
<ModalHeader toggle={toggle}>Edit tag</ModalHeader>
<ModalBody>

View file

@ -11,13 +11,13 @@ import { ProblemDetailsError } from '../../api/types/errors';
export const EDIT_TAG_START = 'shlink/editTag/EDIT_TAG_START';
export const EDIT_TAG_ERROR = 'shlink/editTag/EDIT_TAG_ERROR';
export const EDIT_TAG = 'shlink/editTag/EDIT_TAG';
export const TAG_EDITED = 'shlink/editTag/TAG_EDITED';
export interface TagEdition {
oldName: string;
newName: string;
oldName?: string;
newName?: string;
editing: boolean;
edited: boolean;
error: boolean;
errorData?: ProblemDetailsError;
}
@ -29,18 +29,18 @@ export interface EditTagAction extends Action<string> {
}
const initialState: TagEdition = {
oldName: '',
newName: '',
editing: false,
edited: false,
error: false,
};
export default buildReducer<TagEdition, EditTagAction & ApiErrorAction>({
[EDIT_TAG_START]: (state) => ({ ...state, editing: true, error: false }),
[EDIT_TAG_ERROR]: (state, { errorData }) => ({ ...state, editing: false, error: true, errorData }),
[EDIT_TAG_START]: () => ({ editing: true, edited: false, error: false }),
[EDIT_TAG_ERROR]: (_, { errorData }) => ({ editing: false, edited: false, error: true, errorData }),
[EDIT_TAG]: (_, action) => ({
...pick(['oldName', 'newName'], action),
editing: false,
edited: true,
error: false,
}),
}, initialState);
@ -56,7 +56,7 @@ export const editTag = (buildShlinkApiClient: ShlinkApiClientBuilder, colorGener
try {
await shlinkEditTag(oldName, newName);
colorGenerator.setColorForKey(newName, color);
dispatch({ type: EDIT_TAG, oldName, newName });
dispatch({ type: EDIT_TAG, oldName, newName, color });
} catch (e: any) {
dispatch<ApiErrorAction>({ type: EDIT_TAG_ERROR, errorData: parseApiError(e) });

View file

@ -9,12 +9,11 @@ import { ProblemDetailsError } from '../../../src/api/types/errors';
describe('<EditTagModal />', () => {
const EditTagModal = createEditTagModal(Mock.of<ColorGenerator>({ getColorForKey: jest.fn(() => 'green') }));
const editTag = jest.fn().mockReturnValue(Promise.resolve());
const tagEdited = jest.fn().mockReturnValue(Promise.resolve());
const toggle = jest.fn();
const setUp = (tagEdit: Partial<TagEdition> = {}) => {
const edition = Mock.of<TagEdition>(tagEdit);
return renderWithEvents(
<EditTagModal isOpen tag="foo" tagEdit={edition} editTag={editTag} tagEdited={tagEdited} toggle={toggle} />,
<EditTagModal isOpen tag="foo" tagEdit={edition} editTag={editTag} tagEdited={jest.fn()} toggle={toggle} />,
);
};
@ -30,7 +29,6 @@ describe('<EditTagModal />', () => {
expect(toggle).toHaveBeenCalledTimes(2);
expect(editTag).not.toHaveBeenCalled();
expect(tagEdited).not.toHaveBeenCalled();
});
it.each([
@ -63,12 +61,12 @@ describe('<EditTagModal />', () => {
const { user } = setUp();
expect(editTag).not.toHaveBeenCalled();
expect(tagEdited).not.toHaveBeenCalled();
expect(toggle).not.toHaveBeenCalled();
await user.click(screen.getByRole('button', { name: 'Save' }));
expect(editTag).toHaveBeenCalled();
expect(tagEdited).toHaveBeenCalled();
expect(toggle).toHaveBeenCalled();
});
it('changes color when changing on color picker', async () => {

View file

@ -21,24 +21,23 @@ describe('tagEditReducer', () => {
it('returns loading on EDIT_TAG_START', () => {
expect(reducer(undefined, Mock.of<EditTagAction>({ type: EDIT_TAG_START }))).toEqual({
editing: true,
edited: false,
error: false,
oldName: '',
newName: '',
});
});
it('returns error on EDIT_TAG_ERROR', () => {
expect(reducer(undefined, Mock.of<EditTagAction>({ type: EDIT_TAG_ERROR }))).toEqual({
editing: false,
edited: false,
error: true,
oldName: '',
newName: '',
});
});
it('returns tag names on EDIT_TAG', () => {
expect(reducer(undefined, { type: EDIT_TAG, oldName, newName, color })).toEqual({
editing: false,
edited: true,
error: false,
oldName: 'foo',
newName: 'bar',
@ -82,7 +81,7 @@ describe('tagEditReducer', () => {
expect(dispatch).toHaveBeenCalledTimes(2);
expect(dispatch).toHaveBeenNthCalledWith(1, { type: EDIT_TAG_START });
expect(dispatch).toHaveBeenNthCalledWith(2, { type: EDIT_TAG, oldName, newName });
expect(dispatch).toHaveBeenNthCalledWith(2, { type: EDIT_TAG, oldName, newName, color });
});
it('throws on error', async () => {