diff --git a/src/api/ShlinkApiError.tsx b/src/api/ShlinkApiError.tsx
new file mode 100644
index 00000000..8c9e51f5
--- /dev/null
+++ b/src/api/ShlinkApiError.tsx
@@ -0,0 +1,15 @@
+import { isInvalidArgumentError, ProblemDetailsError } from '../utils/services/types';
+
+interface ShlinkApiErrorProps {
+ errorData?: ProblemDetailsError;
+ fallbackMessage?: string;
+}
+
+export const ShlinkApiError = ({ errorData, fallbackMessage }: ShlinkApiErrorProps) => (
+ <>
+ {errorData?.detail ?? fallbackMessage}
+ {isInvalidArgumentError(errorData) &&
+
Invalid elements: [{errorData.invalidElements.join(', ')}]
+ }
+ >
+);
diff --git a/src/short-urls/helpers/CreateShortUrlResult.tsx b/src/short-urls/helpers/CreateShortUrlResult.tsx
index ad4fa3bc..f5a75ded 100644
--- a/src/short-urls/helpers/CreateShortUrlResult.tsx
+++ b/src/short-urls/helpers/CreateShortUrlResult.tsx
@@ -9,7 +9,7 @@ import { ShortUrlCreation } from '../reducers/shortUrlCreation';
import { StateFlagTimeout } from '../../utils/helpers/hooks';
import { Result } from '../../utils/Result';
import './CreateShortUrlResult.scss';
-import { isInvalidArgumentError } from '../../utils/services/types';
+import { ShlinkApiError } from '../../api/ShlinkApiError';
export interface CreateShortUrlResultProps extends ShortUrlCreation {
resetCreateShortUrl: () => void;
@@ -29,8 +29,7 @@ const CreateShortUrlResult = (useStateFlagTimeout: StateFlagTimeout) => (
return (
{canBeClosed && }
- {errorData?.detail ?? 'An error occurred while creating the URL :('}
- {isInvalidArgumentError(errorData) && Invalid elements: [{errorData.invalidElements.join(', ')}]
}
+
);
}
diff --git a/src/short-urls/helpers/DeleteShortUrlModal.tsx b/src/short-urls/helpers/DeleteShortUrlModal.tsx
index 9fd714f9..119892d2 100644
--- a/src/short-urls/helpers/DeleteShortUrlModal.tsx
+++ b/src/short-urls/helpers/DeleteShortUrlModal.tsx
@@ -6,6 +6,7 @@ import { ShortUrlModalProps } from '../data';
import { handleEventPreventingDefault, OptionalString } from '../../utils/utils';
import { Result } from '../../utils/Result';
import { isInvalidDeletionError } from '../../utils/services/types';
+import { ShlinkApiError } from '../../api/ShlinkApiError';
interface DeleteShortUrlModalConnectProps extends ShortUrlModalProps {
shortUrlDeletion: ShortUrlDeletion;
@@ -49,15 +50,9 @@ const DeleteShortUrlModal = (
onChange={(e) => setInputValue(e.target.value)}
/>
- {error && isInvalidDeletionError(errorData) && (
-
- {errorData.threshold && `This short URL has received more than ${errorData.threshold} visits, and therefore, it cannot be deleted.`}
- {!errorData.threshold && 'This short URL has received too many visits, and therefore, it cannot be deleted.'}
-
- )}
- {error && !isInvalidDeletionError(errorData) && (
-
- {errorData?.detail ?? 'Something went wrong while deleting the URL :('}
+ {error && (
+
+
)}
diff --git a/src/short-urls/helpers/EditMetaModal.tsx b/src/short-urls/helpers/EditMetaModal.tsx
index ca22c2a1..688cf9be 100644
--- a/src/short-urls/helpers/EditMetaModal.tsx
+++ b/src/short-urls/helpers/EditMetaModal.tsx
@@ -11,6 +11,7 @@ import { formatIsoDate } from '../../utils/helpers/date';
import { ShortUrl, ShortUrlMeta, ShortUrlModalProps } from '../data';
import { handleEventPreventingDefault, Nullable, OptionalString } from '../../utils/utils';
import { Result } from '../../utils/Result';
+import { ShlinkApiError } from '../../api/ShlinkApiError';
interface EditMetaModalConnectProps extends ShortUrlModalProps {
shortUrlMeta: ShortUrlMetaEdition;
@@ -27,7 +28,7 @@ const dateOrNull = (shortUrl: ShortUrl | undefined, dateName: 'validSince' | 'va
const EditMetaModal = (
{ isOpen, toggle, shortUrl, shortUrlMeta, editShortUrlMeta, resetShortUrlMeta }: EditMetaModalConnectProps,
) => {
- const { saving, error } = shortUrlMeta;
+ const { saving, error, errorData } = shortUrlMeta;
const url = shortUrl && (shortUrl.shortUrl || '');
const [ validSince, setValidSince ] = useState(dateOrNull(shortUrl, 'validSince'));
const [ validUntil, setValidUntil ] = useState(dateOrNull(shortUrl, 'validUntil'));
@@ -78,9 +79,13 @@ const EditMetaModal = (
onChange={(e: ChangeEvent) => setMaxVisits(Number(e.target.value))}
/>
+
{error && (
- Something went wrong while saving the metadata :(
+
)}
diff --git a/src/short-urls/reducers/shortUrlMeta.ts b/src/short-urls/reducers/shortUrlMeta.ts
index 8b4e8a51..c867bf0d 100644
--- a/src/short-urls/reducers/shortUrlMeta.ts
+++ b/src/short-urls/reducers/shortUrlMeta.ts
@@ -4,6 +4,7 @@ import { GetState } from '../../container/types';
import { buildActionCreator, buildReducer } from '../../utils/helpers/redux';
import { OptionalString } from '../../utils/utils';
import { ShlinkApiClientBuilder } from '../../utils/services/ShlinkApiClientBuilder';
+import { ProblemDetailsError } from '../../utils/services/types';
/* eslint-disable padding-line-between-statements */
export const EDIT_SHORT_URL_META_START = 'shlink/shortUrlMeta/EDIT_SHORT_URL_META_START';
@@ -17,12 +18,17 @@ export interface ShortUrlMetaEdition {
meta: ShortUrlMeta;
saving: boolean;
error: boolean;
+ errorData?: ProblemDetailsError;
}
export interface ShortUrlMetaEditedAction extends Action, ShortUrlIdentifier {
meta: ShortUrlMeta;
}
+export interface ShortUrlMetaEditionFailedAction extends Action {
+ errorData?: ProblemDetailsError;
+}
+
const initialState: ShortUrlMetaEdition = {
shortCode: null,
meta: {},
@@ -30,9 +36,9 @@ const initialState: ShortUrlMetaEdition = {
error: false,
};
-export default buildReducer({
+export default buildReducer({
[EDIT_SHORT_URL_META_START]: (state) => ({ ...state, saving: true, error: false }),
- [EDIT_SHORT_URL_META_ERROR]: (state) => ({ ...state, saving: false, error: true }),
+ [EDIT_SHORT_URL_META_ERROR]: (state, { errorData }) => ({ ...state, saving: false, error: true, errorData }),
[SHORT_URL_META_EDITED]: (_, { shortCode, meta }) => ({ shortCode, meta, saving: false, error: false }),
[RESET_EDIT_SHORT_URL_META]: () => initialState,
}, initialState);
@@ -49,7 +55,7 @@ export const editShortUrlMeta = (buildShlinkApiClient: ShlinkApiClientBuilder) =
await updateShortUrlMeta(shortCode, domain, meta);
dispatch({ shortCode, meta, domain, type: SHORT_URL_META_EDITED });
} catch (e) {
- dispatch({ type: EDIT_SHORT_URL_META_ERROR });
+ dispatch({ type: EDIT_SHORT_URL_META_ERROR, errorData: e.response?.data });
throw e;
}
diff --git a/src/utils/services/ShlinkApiClient.ts b/src/utils/services/ShlinkApiClient.ts
index 706a72eb..b04b7738 100644
--- a/src/utils/services/ShlinkApiClient.ts
+++ b/src/utils/services/ShlinkApiClient.ts
@@ -18,6 +18,8 @@ import {
ShlinkVisitsOverview,
} from './types';
+// TODO Move this file to api module
+
const buildShlinkBaseUrl = (url: string, apiVersion: number) => url ? `${url}/rest/v${apiVersion}` : '';
const rejectNilProps = reject(isNil);
diff --git a/src/utils/services/ShlinkApiClientBuilder.ts b/src/utils/services/ShlinkApiClientBuilder.ts
index d2ba24cd..328a1c8a 100644
--- a/src/utils/services/ShlinkApiClientBuilder.ts
+++ b/src/utils/services/ShlinkApiClientBuilder.ts
@@ -4,6 +4,8 @@ import { hasServerData, SelectedServer, ServerWithId } from '../../servers/data'
import { GetState } from '../../container/types';
import ShlinkApiClient from './ShlinkApiClient';
+// TODO Move this file to api module
+
const apiClients: Record = {};
const isGetState = (getStateOrSelectedServer: GetState | ServerWithId): getStateOrSelectedServer is GetState =>
diff --git a/src/utils/services/types.ts b/src/utils/services/types.ts
index b515ff06..9f5f9225 100644
--- a/src/utils/services/types.ts
+++ b/src/utils/services/types.ts
@@ -2,6 +2,8 @@ import { Visit } from '../../visits/types'; // FIXME Should be defined as part o
import { ShortUrl, ShortUrlMeta } from '../../short-urls/data'; // FIXME Should be defined as part of this module
import { OptionalString } from '../utils';
+// TODO Move this file to api module
+
export interface ShlinkShortUrlsResponse {
data: ShortUrl[];
pagination: ShlinkPaginator;
diff --git a/test/short-urls/helpers/DeleteShortUrlModal.test.tsx b/test/short-urls/helpers/DeleteShortUrlModal.test.tsx
index 06ce4864..d39fdb27 100644
--- a/test/short-urls/helpers/DeleteShortUrlModal.test.tsx
+++ b/test/short-urls/helpers/DeleteShortUrlModal.test.tsx
@@ -33,28 +33,6 @@ describe('', () => {
afterEach(() => wrapper?.unmount());
afterEach(jest.clearAllMocks);
- it.each([
- [
- { type: 'INVALID_SHORTCODE_DELETION' },
- 'This short URL has received too many visits, and therefore, it cannot be deleted.',
- ],
- [
- { type: 'INVALID_SHORTCODE_DELETION', threshold: 8 },
- 'This short URL has received more than 8 visits, and therefore, it cannot be deleted.',
- ],
- ])('shows threshold error message when threshold error occurs', (errorData: Partial, expectedMessage) => {
- const wrapper = createWrapper({
- loading: false,
- error: true,
- shortCode: 'abc123',
- errorData: Mock.of(errorData),
- });
- const warning = wrapper.find(Result).filterWhere((result) => result.prop('type') === 'warning');
-
- expect(warning).toHaveLength(1);
- expect(warning.html()).toContain(expectedMessage);
- });
-
it('shows generic error when non-threshold error occurs', () => {
const wrapper = createWrapper({
loading: false,