From c8c07c470d2f350f04d91cb474c9336ec753b2e3 Mon Sep 17 00:00:00 2001 From: Jan Jakes Date: Tue, 6 Sep 2022 14:05:11 +0200 Subject: [PATCH] Add middleware for displaying API errors as notices [MAILPOET-4523] --- .../assets/js/src/automation/api/index.ts | 10 ++++++ .../automation/editor/api-error-handler.tsx | 36 +++++++++++++++++++ .../editor/components/workflow/index.tsx | 2 -- .../assets/js/src/automation/editor/index.tsx | 10 +++++- .../js/src/automation/editor/store/actions.ts | 6 ++-- 5 files changed, 58 insertions(+), 6 deletions(-) create mode 100644 mailpoet/assets/js/src/automation/editor/api-error-handler.tsx diff --git a/mailpoet/assets/js/src/automation/api/index.ts b/mailpoet/assets/js/src/automation/api/index.ts index 37e5b8f5aa..be5cd4dd05 100644 --- a/mailpoet/assets/js/src/automation/api/index.ts +++ b/mailpoet/assets/js/src/automation/api/index.ts @@ -5,6 +5,16 @@ export * from './hooks'; const apiUrl = `${api.root}/mailpoet/v1/automation/`; +export type ApiError = { + code?: string; + message?: string; + data?: { + status?: number; + details?: Error; + params?: Record; + }; +}; + export const initializeApi = () => { apiFetch.use(apiFetch.createRootURLMiddleware(apiUrl)); apiFetch.use(apiFetch.createNonceMiddleware(api.nonce)); diff --git a/mailpoet/assets/js/src/automation/editor/api-error-handler.tsx b/mailpoet/assets/js/src/automation/editor/api-error-handler.tsx new file mode 100644 index 0000000000..eeba8a3246 --- /dev/null +++ b/mailpoet/assets/js/src/automation/editor/api-error-handler.tsx @@ -0,0 +1,36 @@ +import apiFetch, { APIFetchOptions } from '@wordpress/api-fetch'; +import { dispatch, StoreDescriptor } from '@wordpress/data'; +import { __ } from '@wordpress/i18n'; +import { store as noticesStore } from '@wordpress/notices'; +import { ApiError } from '../api'; + +export const registerApiErrorHandler = (): void => + apiFetch.use( + async ( + options: APIFetchOptions, + next: (nextOptions: APIFetchOptions) => Promise, + ) => { + try { + const result = await next(options); + return result; + } catch (error) { + const errorObject = error as ApiError; + const status = errorObject.data?.status; + + if (status && status >= 400 && status < 500) { + const message = errorObject.message; + void dispatch(noticesStore as StoreDescriptor).createErrorNotice( + message ?? __('An unknown error occurred.', 'mailpoet'), + { explicitDismiss: true }, + ); + return undefined; + } + + void dispatch(noticesStore as StoreDescriptor).createErrorNotice( + __('An unknown error occurred.', 'mailpoet'), + { explicitDismiss: true }, + ); + throw error; + } + }, + ); diff --git a/mailpoet/assets/js/src/automation/editor/components/workflow/index.tsx b/mailpoet/assets/js/src/automation/editor/components/workflow/index.tsx index 0f66a40544..1099fa680c 100644 --- a/mailpoet/assets/js/src/automation/editor/components/workflow/index.tsx +++ b/mailpoet/assets/js/src/automation/editor/components/workflow/index.tsx @@ -12,7 +12,6 @@ import { Separator } from './separator'; import { Step } from './step'; import { Step as StepData } from './types'; import { InserterPopover } from '../inserter-popover'; -import { EditorNotices } from '../notices'; import { storeName } from '../../store'; import { AddTrigger } from './add-trigger'; @@ -95,7 +94,6 @@ export function Workflow(): JSX.Element { return ( - } - content={} + content={ + <> + + + + } sidebar={} secondarySidebar={ showInserterSidebar && isInserterOpened ? : null @@ -96,6 +103,7 @@ window.addEventListener('DOMContentLoaded', () => { const root = document.getElementById('mailpoet_automation_editor'); if (root) { + registerApiErrorHandler(); initializeApi(); initializeCoreIntegration(); initializeMailPoetIntegration(); diff --git a/mailpoet/assets/js/src/automation/editor/store/actions.ts b/mailpoet/assets/js/src/automation/editor/store/actions.ts index 823690619b..4c8f366e4c 100644 --- a/mailpoet/assets/js/src/automation/editor/store/actions.ts +++ b/mailpoet/assets/js/src/automation/editor/store/actions.ts @@ -54,12 +54,12 @@ export function* save() { const data = yield apiFetch({ path: `/workflows/${workflow.id}`, method: 'PUT', - data: workflow, + data: { ...workflow }, }); return { type: 'SAVE', - workflow: data.data, + workflow: data?.data ?? workflow, } as const; } @@ -76,7 +76,7 @@ export function* activate() { return { type: 'ACTIVATE', - workflow: data.data, + workflow: data?.data ?? workflow, } as const; }