Simplified DeleteShortUrlModal component and shortUrlDeletion reducer

This commit is contained in:
Alejandro Celaya 2020-01-31 20:12:22 +01:00
parent 30117bd121
commit 3e298f010b
5 changed files with 17 additions and 34 deletions

View file

@ -1,7 +1,7 @@
import React from 'react'; import React from 'react';
import { Modal, ModalBody, ModalFooter, ModalHeader } from 'reactstrap'; import { Modal, ModalBody, ModalFooter, ModalHeader } from 'reactstrap';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { identity } from 'ramda'; import { identity, pipe } from 'ramda';
import { shortUrlType } from '../reducers/shortUrlsList'; import { shortUrlType } from '../reducers/shortUrlsList';
import { shortUrlDeletionType } from '../reducers/shortUrlDeletion'; import { shortUrlDeletionType } from '../reducers/shortUrlDeletion';
@ -15,21 +15,17 @@ export default class DeleteShortUrlModal extends React.Component {
shortUrlDeletion: shortUrlDeletionType, shortUrlDeletion: shortUrlDeletionType,
deleteShortUrl: PropTypes.func, deleteShortUrl: PropTypes.func,
resetDeleteShortUrl: PropTypes.func, resetDeleteShortUrl: PropTypes.func,
shortUrlDeleted: PropTypes.func,
}; };
state = { inputValue: '' }; state = { inputValue: '' };
handleDeleteUrl = (e) => { handleDeleteUrl = (e) => {
e.preventDefault(); e.preventDefault();
const { deleteShortUrl, shortUrl, toggle, shortUrlDeleted } = this.props; const { deleteShortUrl, shortUrl, toggle } = this.props;
const { shortCode } = shortUrl; const { shortCode } = shortUrl;
deleteShortUrl(shortCode) deleteShortUrl(shortCode)
.then(() => { .then(toggle)
shortUrlDeleted(shortCode);
toggle();
})
.catch(identity); .catch(identity);
}; };
@ -40,16 +36,17 @@ export default class DeleteShortUrlModal extends React.Component {
} }
render() { render() {
const { shortUrl, toggle, isOpen, shortUrlDeletion } = this.props; const { shortUrl, toggle, isOpen, shortUrlDeletion, resetDeleteShortUrl } = this.props;
const { error, errorData } = shortUrlDeletion; const { error, errorData } = shortUrlDeletion;
const errorCode = error && (errorData.type || errorData.error); const errorCode = error && (errorData.type || errorData.error);
const hasThresholdError = errorCode === THRESHOLD_REACHED; const hasThresholdError = errorCode === THRESHOLD_REACHED;
const hasErrorOtherThanThreshold = error && errorCode !== THRESHOLD_REACHED; const hasErrorOtherThanThreshold = error && errorCode !== THRESHOLD_REACHED;
const close = pipe(resetDeleteShortUrl, toggle);
return ( return (
<Modal isOpen={isOpen} toggle={toggle} centered> <Modal isOpen={isOpen} toggle={close} centered>
<form onSubmit={this.handleDeleteUrl}> <form onSubmit={this.handleDeleteUrl}>
<ModalHeader toggle={toggle}> <ModalHeader toggle={close}>
<span className="text-danger">Delete short URL</span> <span className="text-danger">Delete short URL</span>
</ModalHeader> </ModalHeader>
<ModalBody> <ModalBody>
@ -77,7 +74,7 @@ export default class DeleteShortUrlModal extends React.Component {
)} )}
</ModalBody> </ModalBody>
<ModalFooter> <ModalFooter>
<button type="button" className="btn btn-link" onClick={toggle}>Cancel</button> <button type="button" className="btn btn-link" onClick={close}>Cancel</button>
<button <button
type="submit" type="submit"
className="btn btn-danger" className="btn btn-danger"

View file

@ -5,9 +5,8 @@ import { apiErrorType } from '../../utils/services/ShlinkApiClient';
/* eslint-disable padding-line-between-statements */ /* eslint-disable padding-line-between-statements */
export const DELETE_SHORT_URL_START = 'shlink/deleteShortUrl/DELETE_SHORT_URL_START'; export const DELETE_SHORT_URL_START = 'shlink/deleteShortUrl/DELETE_SHORT_URL_START';
export const DELETE_SHORT_URL_ERROR = 'shlink/deleteShortUrl/DELETE_SHORT_URL_ERROR'; export const DELETE_SHORT_URL_ERROR = 'shlink/deleteShortUrl/DELETE_SHORT_URL_ERROR';
export const DELETE_SHORT_URL = 'shlink/deleteShortUrl/DELETE_SHORT_URL';
export const RESET_DELETE_SHORT_URL = 'shlink/deleteShortUrl/RESET_DELETE_SHORT_URL';
export const SHORT_URL_DELETED = 'shlink/deleteShortUrl/SHORT_URL_DELETED'; export const SHORT_URL_DELETED = 'shlink/deleteShortUrl/SHORT_URL_DELETED';
export const RESET_DELETE_SHORT_URL = 'shlink/deleteShortUrl/RESET_DELETE_SHORT_URL';
/* eslint-enable padding-line-between-statements */ /* eslint-enable padding-line-between-statements */
export const shortUrlDeletionType = PropTypes.shape({ export const shortUrlDeletionType = PropTypes.shape({
@ -27,7 +26,7 @@ const initialState = {
export default handleActions({ export default handleActions({
[DELETE_SHORT_URL_START]: (state) => ({ ...state, loading: true, error: false }), [DELETE_SHORT_URL_START]: (state) => ({ ...state, loading: true, error: false }),
[DELETE_SHORT_URL_ERROR]: (state, { errorData }) => ({ ...state, errorData, loading: false, error: true }), [DELETE_SHORT_URL_ERROR]: (state, { errorData }) => ({ ...state, errorData, loading: false, error: true }),
[DELETE_SHORT_URL]: (state, { shortCode }) => ({ ...state, shortCode, loading: false, error: false }), [SHORT_URL_DELETED]: (state, { shortCode }) => ({ ...state, shortCode, loading: false, error: false }),
[RESET_DELETE_SHORT_URL]: () => initialState, [RESET_DELETE_SHORT_URL]: () => initialState,
}, initialState); }, initialState);
@ -38,7 +37,7 @@ export const deleteShortUrl = (buildShlinkApiClient) => (shortCode) => async (di
try { try {
await deleteShortUrl(shortCode); await deleteShortUrl(shortCode);
dispatch({ type: DELETE_SHORT_URL, shortCode }); dispatch({ type: SHORT_URL_DELETED, shortCode });
} catch (e) { } catch (e) {
dispatch({ type: DELETE_SHORT_URL_ERROR, errorData: e.response.data }); dispatch({ type: DELETE_SHORT_URL_ERROR, errorData: e.response.data });
@ -47,5 +46,3 @@ export const deleteShortUrl = (buildShlinkApiClient) => (shortCode) => async (di
}; };
export const resetDeleteShortUrl = createAction(RESET_DELETE_SHORT_URL); export const resetDeleteShortUrl = createAction(RESET_DELETE_SHORT_URL);
export const shortUrlDeleted = (shortCode) => ({ type: SHORT_URL_DELETED, shortCode });

View file

@ -12,7 +12,7 @@ import EditMetaModal from '../helpers/EditMetaModal';
import CreateShortUrlResult from '../helpers/CreateShortUrlResult'; import CreateShortUrlResult from '../helpers/CreateShortUrlResult';
import { listShortUrls } from '../reducers/shortUrlsList'; import { listShortUrls } from '../reducers/shortUrlsList';
import { createShortUrl, resetCreateShortUrl } from '../reducers/shortUrlCreation'; import { createShortUrl, resetCreateShortUrl } from '../reducers/shortUrlCreation';
import { deleteShortUrl, resetDeleteShortUrl, shortUrlDeleted } from '../reducers/shortUrlDeletion'; import { deleteShortUrl, resetDeleteShortUrl } from '../reducers/shortUrlDeletion';
import { editShortUrlTags, resetShortUrlsTags } from '../reducers/shortUrlTags'; import { editShortUrlTags, resetShortUrlsTags } from '../reducers/shortUrlTags';
import { editShortUrlMeta, resetShortUrlMeta } from '../reducers/shortUrlMeta'; import { editShortUrlMeta, resetShortUrlMeta } from '../reducers/shortUrlMeta';
import { resetShortUrlParams } from '../reducers/shortUrlsListParams'; import { resetShortUrlParams } from '../reducers/shortUrlsListParams';
@ -52,10 +52,7 @@ const provideServices = (bottle, connect) => {
); );
bottle.serviceFactory('DeleteShortUrlModal', () => DeleteShortUrlModal); bottle.serviceFactory('DeleteShortUrlModal', () => DeleteShortUrlModal);
bottle.decorator('DeleteShortUrlModal', connect( bottle.decorator('DeleteShortUrlModal', connect([ 'shortUrlDeletion' ], [ 'deleteShortUrl', 'resetDeleteShortUrl' ]));
[ 'shortUrlDeletion' ],
[ 'deleteShortUrl', 'resetDeleteShortUrl', 'shortUrlDeleted' ]
));
bottle.serviceFactory('EditTagsModal', EditTagsModal, 'TagsSelector'); bottle.serviceFactory('EditTagsModal', EditTagsModal, 'TagsSelector');
bottle.decorator('EditTagsModal', connect([ 'shortUrlTags' ], [ 'editShortUrlTags', 'resetShortUrlsTags' ])); bottle.decorator('EditTagsModal', connect([ 'shortUrlTags' ], [ 'editShortUrlTags', 'resetShortUrlsTags' ]));
@ -75,7 +72,6 @@ const provideServices = (bottle, connect) => {
bottle.serviceFactory('deleteShortUrl', deleteShortUrl, 'buildShlinkApiClient'); bottle.serviceFactory('deleteShortUrl', deleteShortUrl, 'buildShlinkApiClient');
bottle.serviceFactory('resetDeleteShortUrl', () => resetDeleteShortUrl); bottle.serviceFactory('resetDeleteShortUrl', () => resetDeleteShortUrl);
bottle.serviceFactory('shortUrlDeleted', () => shortUrlDeleted);
bottle.serviceFactory('editShortUrlMeta', editShortUrlMeta, 'buildShlinkApiClient'); bottle.serviceFactory('editShortUrlMeta', editShortUrlMeta, 'buildShlinkApiClient');
bottle.serviceFactory('resetShortUrlMeta', () => resetShortUrlMeta); bottle.serviceFactory('resetShortUrlMeta', () => resetShortUrlMeta);

View file

@ -21,7 +21,6 @@ describe('<DeleteShortUrlModal />', () => {
toggle={identity} toggle={identity}
deleteShortUrl={deleteShortUrl} deleteShortUrl={deleteShortUrl}
resetDeleteShortUrl={identity} resetDeleteShortUrl={identity}
shortUrlDeleted={identity}
/> />
); );

View file

@ -1,10 +1,9 @@
import reducer, { import reducer, {
DELETE_SHORT_URL, DELETE_SHORT_URL_ERROR, DELETE_SHORT_URL_ERROR,
DELETE_SHORT_URL_START, DELETE_SHORT_URL_START,
RESET_DELETE_SHORT_URL, RESET_DELETE_SHORT_URL,
SHORT_URL_DELETED, SHORT_URL_DELETED,
resetDeleteShortUrl, resetDeleteShortUrl,
shortUrlDeleted,
deleteShortUrl, deleteShortUrl,
} from '../../../src/short-urls/reducers/shortUrlDeletion'; } from '../../../src/short-urls/reducers/shortUrlDeletion';
@ -26,8 +25,8 @@ describe('shortUrlDeletionReducer', () => {
errorData: {}, errorData: {},
})); }));
it('returns shortCode on DELETE_SHORT_URL', () => it('returns shortCode on SHORT_URL_DELETED', () =>
expect(reducer(undefined, { type: DELETE_SHORT_URL, shortCode: 'foo' })).toEqual({ expect(reducer(undefined, { type: SHORT_URL_DELETED, shortCode: 'foo' })).toEqual({
shortCode: 'foo', shortCode: 'foo',
loading: false, loading: false,
error: false, error: false,
@ -51,11 +50,6 @@ describe('shortUrlDeletionReducer', () => {
expect(resetDeleteShortUrl()).toEqual({ type: RESET_DELETE_SHORT_URL })); expect(resetDeleteShortUrl()).toEqual({ type: RESET_DELETE_SHORT_URL }));
}); });
describe('shortUrlDeleted', () => {
it('returns expected action', () =>
expect(shortUrlDeleted('abc123')).toEqual({ type: SHORT_URL_DELETED, shortCode: 'abc123' }));
});
describe('deleteShortUrl', () => { describe('deleteShortUrl', () => {
const dispatch = jest.fn(); const dispatch = jest.fn();
const getState = jest.fn().mockReturnValue({ selectedServer: {} }); const getState = jest.fn().mockReturnValue({ selectedServer: {} });
@ -75,7 +69,7 @@ describe('shortUrlDeletionReducer', () => {
expect(dispatch).toHaveBeenCalledTimes(2); expect(dispatch).toHaveBeenCalledTimes(2);
expect(dispatch).toHaveBeenNthCalledWith(1, { type: DELETE_SHORT_URL_START }); expect(dispatch).toHaveBeenNthCalledWith(1, { type: DELETE_SHORT_URL_START });
expect(dispatch).toHaveBeenNthCalledWith(2, { type: DELETE_SHORT_URL, shortCode }); expect(dispatch).toHaveBeenNthCalledWith(2, { type: SHORT_URL_DELETED, shortCode });
expect(apiClientMock.deleteShortUrl).toHaveBeenCalledTimes(1); expect(apiClientMock.deleteShortUrl).toHaveBeenCalledTimes(1);
expect(apiClientMock.deleteShortUrl).toHaveBeenCalledWith(shortCode); expect(apiClientMock.deleteShortUrl).toHaveBeenCalledWith(shortCode);