Updated editDomainRedirects action, to expect a payload DTO instead of multiple args

This commit is contained in:
Alejandro Celaya 2022-11-04 17:10:02 +01:00
parent 4fa6ae493d
commit b6d08e2203
8 changed files with 61 additions and 36 deletions

View file

@ -8,11 +8,12 @@ import { SelectedServer } from '../servers/data';
import { Domain } from './data';
import { DomainStatusIcon } from './helpers/DomainStatusIcon';
import { DomainDropdown } from './helpers/DomainDropdown';
import { EditDomainRedirects } from './reducers/domainRedirects';
interface DomainRowProps {
domain: Domain;
defaultRedirects?: ShlinkDomainRedirects;
editDomainRedirects: (domain: string, redirects: Partial<ShlinkDomainRedirects>) => Promise<void>;
editDomainRedirects: (redirects: EditDomainRedirects) => Promise<void>;
checkDomainHealth: (domain: string) => void;
selectedServer: SelectedServer;
}

View file

@ -4,7 +4,7 @@ import { Result } from '../utils/Result';
import { ShlinkApiError } from '../api/ShlinkApiError';
import { SimpleCard } from '../utils/SimpleCard';
import { SearchField } from '../utils/SearchField';
import { ShlinkDomainRedirects } from '../api/types';
import { EditDomainRedirects } from './reducers/domainRedirects';
import { SelectedServer } from '../servers/data';
import { DomainsList } from './reducers/domainsList';
import { DomainRow } from './DomainRow';
@ -12,7 +12,7 @@ import { DomainRow } from './DomainRow';
interface ManageDomainsProps {
listDomains: Function;
filterDomains: (searchTerm: string) => void;
editDomainRedirects: (domain: string, redirects: Partial<ShlinkDomainRedirects>) => Promise<void>;
editDomainRedirects: (redirects: EditDomainRedirects) => Promise<void>;
checkDomainHealth: (domain: string) => void;
domainsList: DomainsList;
selectedServer: SelectedServer;

View file

@ -7,14 +7,14 @@ import { useToggle } from '../../utils/helpers/hooks';
import { DropdownBtnMenu } from '../../utils/DropdownBtnMenu';
import { EditDomainRedirectsModal } from './EditDomainRedirectsModal';
import { Domain } from '../data';
import { ShlinkDomainRedirects } from '../../api/types';
import { EditDomainRedirects } from '../reducers/domainRedirects';
import { supportsDefaultDomainRedirectsEdition, supportsDomainVisits } from '../../utils/helpers/features';
import { getServerId, SelectedServer } from '../../servers/data';
import { DEFAULT_DOMAIN } from '../../visits/reducers/domainVisits';
interface DomainDropdownProps {
domain: Domain;
editDomainRedirects: (domain: string, redirects: Partial<ShlinkDomainRedirects>) => Promise<void>;
editDomainRedirects: (redirects: EditDomainRedirects) => Promise<void>;
selectedServer: SelectedServer;
}

View file

@ -1,15 +1,16 @@
import { FC, useState } from 'react';
import { Button, Modal, ModalBody, ModalFooter, ModalHeader } from 'reactstrap';
import { ShlinkDomain, ShlinkDomainRedirects } from '../../api/types';
import { ShlinkDomain } from '../../api/types';
import { InputFormGroup, InputFormGroupProps } from '../../utils/forms/InputFormGroup';
import { handleEventPreventingDefault, nonEmptyValueOrNull } from '../../utils/utils';
import { InfoTooltip } from '../../utils/InfoTooltip';
import { EditDomainRedirects } from '../reducers/domainRedirects';
interface EditDomainRedirectsModalProps {
domain: ShlinkDomain;
isOpen: boolean;
toggle: () => void;
editDomainRedirects: (domain: string, redirects: Partial<ShlinkDomainRedirects>) => Promise<void>;
editDomainRedirects: (redirects: EditDomainRedirects) => Promise<void>;
}
const FormGroup: FC<InputFormGroupProps & { isLast?: boolean }> = ({ isLast, ...rest }) => (
@ -30,10 +31,13 @@ export const EditDomainRedirectsModal: FC<EditDomainRedirectsModalProps> = (
const [invalidShortUrlRedirect, setInvalidShortUrlRedirect] = useState(
domain.redirects?.invalidShortUrlRedirect ?? '',
);
const handleSubmit = handleEventPreventingDefault(async () => editDomainRedirects(domain.domain, {
baseUrlRedirect: nonEmptyValueOrNull(baseUrlRedirect),
regular404Redirect: nonEmptyValueOrNull(regular404Redirect),
invalidShortUrlRedirect: nonEmptyValueOrNull(invalidShortUrlRedirect),
const handleSubmit = handleEventPreventingDefault(async () => editDomainRedirects({
domain: domain.domain,
redirects: {
baseUrlRedirect: nonEmptyValueOrNull(baseUrlRedirect),
regular404Redirect: nonEmptyValueOrNull(regular404Redirect),
invalidShortUrlRedirect: nonEmptyValueOrNull(invalidShortUrlRedirect),
},
}).then(toggle));
return (

View file

@ -9,15 +9,17 @@ export const EDIT_DOMAIN_REDIRECTS_START = 'shlink/domainRedirects/EDIT_DOMAIN_R
export const EDIT_DOMAIN_REDIRECTS_ERROR = 'shlink/domainRedirects/EDIT_DOMAIN_REDIRECTS_ERROR';
export const EDIT_DOMAIN_REDIRECTS = 'shlink/domainRedirects/EDIT_DOMAIN_REDIRECTS';
export interface EditDomainRedirectsAction extends Action<string> {
export interface EditDomainRedirects {
domain: string;
redirects: ShlinkDomainRedirects;
}
export const editDomainRedirects = (buildShlinkApiClient: ShlinkApiClientBuilder) => (
domain: string,
domainRedirects: Partial<ShlinkDomainRedirects>,
) => async (dispatch: Dispatch, getState: GetState) => {
export interface EditDomainRedirectsAction extends Action<string>, EditDomainRedirects {}
export const editDomainRedirects = (buildShlinkApiClient: ShlinkApiClientBuilder) => ({
domain,
redirects: domainRedirects,
}: EditDomainRedirects) => async (dispatch: Dispatch, getState: GetState) => {
dispatch({ type: EDIT_DOMAIN_REDIRECTS_START });
const { editDomainRedirects: shlinkEditDomainRedirects } = buildShlinkApiClient(getState);

View file

@ -71,7 +71,7 @@ describe('<DomainDropdown />', () => {
expect(editDomainRedirects).not.toHaveBeenCalled();
await user.click(screen.getByText('Save'));
expect(editDomainRedirects).toHaveBeenCalledWith(domain, expect.anything());
expect(editDomainRedirects).toHaveBeenCalledWith(expect.objectContaining({ domain }));
await waitForElementToBeRemoved(() => screen.queryByRole('dialog'));
});

View file

@ -40,37 +40,49 @@ describe('<EditDomainRedirectsModal />', () => {
expect(editDomainRedirects).not.toHaveBeenCalled();
submitForm();
await waitFor(() => expect(editDomainRedirects).toHaveBeenCalledWith('foo.com', {
baseUrlRedirect: 'baz',
regular404Redirect: null,
invalidShortUrlRedirect: null,
await waitFor(() => expect(editDomainRedirects).toHaveBeenCalledWith({
domain: 'foo.com',
redirects: {
baseUrlRedirect: 'baz',
regular404Redirect: null,
invalidShortUrlRedirect: null,
},
}));
await user.clear(screen.getByDisplayValue('baz'));
await user.type(screen.getAllByPlaceholderText('No redirect')[0], 'new_base_url');
await user.type(screen.getAllByPlaceholderText('No redirect')[2], 'new_invalid_short_url');
submitForm();
await waitFor(() => expect(editDomainRedirects).toHaveBeenCalledWith('foo.com', {
baseUrlRedirect: 'new_base_url',
regular404Redirect: null,
invalidShortUrlRedirect: 'new_invalid_short_url',
await waitFor(() => expect(editDomainRedirects).toHaveBeenCalledWith({
domain: 'foo.com',
redirects: {
baseUrlRedirect: 'new_base_url',
regular404Redirect: null,
invalidShortUrlRedirect: 'new_invalid_short_url',
},
}));
await user.type(screen.getAllByPlaceholderText('No redirect')[1], 'new_regular_404');
await user.clear(screen.getByDisplayValue('new_invalid_short_url'));
submitForm();
await waitFor(() => expect(editDomainRedirects).toHaveBeenCalledWith('foo.com', {
baseUrlRedirect: 'new_base_url',
regular404Redirect: 'new_regular_404',
invalidShortUrlRedirect: null,
await waitFor(() => expect(editDomainRedirects).toHaveBeenCalledWith({
domain: 'foo.com',
redirects: {
baseUrlRedirect: 'new_base_url',
regular404Redirect: 'new_regular_404',
invalidShortUrlRedirect: null,
},
}));
await Promise.all(screen.getAllByPlaceholderText('No redirect').map((element) => user.clear(element)));
submitForm();
await waitFor(() => expect(editDomainRedirects).toHaveBeenCalledWith('foo.com', {
baseUrlRedirect: null,
regular404Redirect: null,
invalidShortUrlRedirect: null,
await waitFor(() => expect(editDomainRedirects).toHaveBeenCalledWith({
domain: 'foo.com',
redirects: {
baseUrlRedirect: null,
regular404Redirect: null,
invalidShortUrlRedirect: null,
},
}));
});
});

View file

@ -3,7 +3,7 @@ import { ShlinkApiClient } from '../../../src/api/services/ShlinkApiClient';
import {
EDIT_DOMAIN_REDIRECTS,
EDIT_DOMAIN_REDIRECTS_ERROR,
EDIT_DOMAIN_REDIRECTS_START,
EDIT_DOMAIN_REDIRECTS_START, EditDomainRedirects,
editDomainRedirects as editDomainRedirectsAction,
} from '../../../src/domains/reducers/domainRedirects';
import { ShlinkDomainRedirects } from '../../../src/api/types';
@ -22,7 +22,10 @@ describe('domainRedirectsReducer', () => {
it('dispatches error when loading domains fails', async () => {
editDomainRedirects.mockRejectedValue(new Error('error'));
await editDomainRedirectsAction(buildShlinkApiClient)(domain, {})(dispatch, getState);
await editDomainRedirectsAction(buildShlinkApiClient)(Mock.of<EditDomainRedirects>({ domain }))(
dispatch,
getState,
);
expect(dispatch).toHaveBeenCalledTimes(2);
expect(dispatch).toHaveBeenNthCalledWith(1, { type: EDIT_DOMAIN_REDIRECTS_START });
@ -33,7 +36,10 @@ describe('domainRedirectsReducer', () => {
it('dispatches domain and redirects once loaded', async () => {
editDomainRedirects.mockResolvedValue(redirects);
await editDomainRedirectsAction(buildShlinkApiClient)(domain, {})(dispatch, getState);
await editDomainRedirectsAction(buildShlinkApiClient)(Mock.of<EditDomainRedirects>({ domain }))(
dispatch,
getState,
);
expect(dispatch).toHaveBeenCalledTimes(2);
expect(dispatch).toHaveBeenNthCalledWith(1, { type: EDIT_DOMAIN_REDIRECTS_START });