From bd038c077a2f96b7a8ff3f5903933fc918764cbf Mon Sep 17 00:00:00 2001 From: Adrian Smijulj Date: Tue, 19 Nov 2024 07:16:12 +0100 Subject: [PATCH] fix: persist error snackbars (#4392) --- packages/app-admin/src/hooks/useSnackbar.ts | 23 ---------- packages/app-admin/src/hooks/useSnackbar.tsx | 45 +++++++++++++++++++ .../Decorators/ShowConfirmationOnDelete.tsx | 4 +- .../ShowConfirmationOnDeleteRevision.tsx | 4 +- .../Decorators/ShowConfirmationOnPublish.tsx | 6 ++- .../ShowConfirmationOnUnpublish.tsx | 4 +- .../admin/components/FieldEditor/Field.tsx | 8 ++-- .../defaultBar/SaveContentModelButton.tsx | 4 +- .../RevisionsList/useRevision.tsx | 4 +- 9 files changed, 63 insertions(+), 39 deletions(-) delete mode 100644 packages/app-admin/src/hooks/useSnackbar.ts create mode 100644 packages/app-admin/src/hooks/useSnackbar.tsx diff --git a/packages/app-admin/src/hooks/useSnackbar.ts b/packages/app-admin/src/hooks/useSnackbar.ts deleted file mode 100644 index 62921f15123..00000000000 --- a/packages/app-admin/src/hooks/useSnackbar.ts +++ /dev/null @@ -1,23 +0,0 @@ -import React from "react"; -import { useUi } from "@webiny/app/hooks/useUi"; - -interface UseSnackbarResponse { - showSnackbar: (message: React.ReactNode, options?: Record) => void; - hideSnackbar: () => void; -} -export const useSnackbar = (): UseSnackbarResponse => { - const ui = useUi(); - - return { - showSnackbar: (message, options = {}) => { - ui.setState(ui => { - return { ...ui, snackbar: { message, options } }; - }); - }, - hideSnackbar: () => { - ui.setState(ui => { - return { ...ui, snackbar: null }; - }); - } - }; -}; diff --git a/packages/app-admin/src/hooks/useSnackbar.tsx b/packages/app-admin/src/hooks/useSnackbar.tsx new file mode 100644 index 00000000000..9f8ac0b9158 --- /dev/null +++ b/packages/app-admin/src/hooks/useSnackbar.tsx @@ -0,0 +1,45 @@ +import React from "react"; +import { useUi } from "@webiny/app/hooks/useUi"; +import { SnackbarAction } from "@webiny/ui/Snackbar"; + +interface UseSnackbarResponse { + showSnackbar: (message: React.ReactNode, options?: Record) => void; + showErrorSnackbar: ( + message: React.ReactNode, + options?: Record + ) => void; + hideSnackbar: () => void; +} + +export const useSnackbar = (): UseSnackbarResponse => { + const ui = useUi(); + + return { + showSnackbar: (message, options = {}) => { + ui.setState(ui => { + return { ...ui, snackbar: { message, options } }; + }); + }, + showErrorSnackbar: (message, options = {}) => { + ui.setState(ui => { + return { + ...ui, + snackbar: { + message, + options: { + timeout: -1, + dismissesOnAction: true, + action: , + ...options + } + } + }; + }); + }, + hideSnackbar: () => { + ui.setState(ui => { + return { ...ui, snackbar: null }; + }); + } + }; +}; diff --git a/packages/app-headless-cms/src/admin/components/Decorators/ShowConfirmationOnDelete.tsx b/packages/app-headless-cms/src/admin/components/Decorators/ShowConfirmationOnDelete.tsx index 32eee9e45d6..f869d566a62 100644 --- a/packages/app-headless-cms/src/admin/components/Decorators/ShowConfirmationOnDelete.tsx +++ b/packages/app-headless-cms/src/admin/components/Decorators/ShowConfirmationOnDelete.tsx @@ -43,13 +43,13 @@ export const ShowConfirmationOnDelete = useContentEntry.createDecorator(baseHook return () => { const hook = baseHook(); const dialogs = useDialogs(); - const { showSnackbar } = useSnackbar(); + const { showSnackbar, showErrorSnackbar } = useSnackbar(); const onAccept = async (entry: CmsContentEntry) => { const response = await hook.deleteEntry({ id: entry.entryId }); if (typeof response !== "boolean") { - showSnackbar( + showErrorSnackbar( `Could not move ${entry.meta.title} to trash! (${response.error.message})` ); diff --git a/packages/app-headless-cms/src/admin/components/Decorators/ShowConfirmationOnDeleteRevision.tsx b/packages/app-headless-cms/src/admin/components/Decorators/ShowConfirmationOnDeleteRevision.tsx index e931764dc57..0debf3392c8 100644 --- a/packages/app-headless-cms/src/admin/components/Decorators/ShowConfirmationOnDeleteRevision.tsx +++ b/packages/app-headless-cms/src/admin/components/Decorators/ShowConfirmationOnDeleteRevision.tsx @@ -44,7 +44,7 @@ export const ShowConfirmationOnDeleteRevision = useContentEntry.createDecorator( return () => { const hook = baseHook(); const dialogs = useDialogs(); - const { showSnackbar } = useSnackbar(); + const { showSnackbar, showErrorSnackbar } = useSnackbar(); const onAccept = async (params: DeleteEntryRevisionParams) => { const revisionToDelete = hook.revisions.find(rev => rev.id === params.id)!; @@ -52,7 +52,7 @@ export const ShowConfirmationOnDeleteRevision = useContentEntry.createDecorator( const response = await hook.deleteEntryRevision(revisionToDelete); if (typeof response === "object" && response.error) { const { error } = response; - showSnackbar(error.message); + showErrorSnackbar(error.message); return response; } diff --git a/packages/app-headless-cms/src/admin/components/Decorators/ShowConfirmationOnPublish.tsx b/packages/app-headless-cms/src/admin/components/Decorators/ShowConfirmationOnPublish.tsx index 5a285b64e09..b31ba7530d9 100644 --- a/packages/app-headless-cms/src/admin/components/Decorators/ShowConfirmationOnPublish.tsx +++ b/packages/app-headless-cms/src/admin/components/Decorators/ShowConfirmationOnPublish.tsx @@ -47,7 +47,7 @@ const EntryMessage = ({ id, entryType, getEntry }: EntryMessageProps) => { export const ShowConfirmationOnPublish = useContentEntry.createDecorator(baseHook => { return () => { - const { showSnackbar } = useSnackbar(); + const { showSnackbar, showErrorSnackbar } = useSnackbar(); const dialogs = useDialogs(); const hook = baseHook(); const { contentModel } = hook; @@ -57,7 +57,9 @@ export const ShowConfirmationOnPublish = useContentEntry.createDecorator(baseHoo const response = await hook.publishEntryRevision({ id: entry.id }); if (response.error) { - showSnackbar(`Could not publish ${entry.meta.title}! (${response.error.message})`); + showErrorSnackbar( + `Could not publish ${entry.meta.title}! (${response.error.message})` + ); return response; } diff --git a/packages/app-headless-cms/src/admin/components/Decorators/ShowConfirmationOnUnpublish.tsx b/packages/app-headless-cms/src/admin/components/Decorators/ShowConfirmationOnUnpublish.tsx index 46ff5f31d6d..b24f87f4aeb 100644 --- a/packages/app-headless-cms/src/admin/components/Decorators/ShowConfirmationOnUnpublish.tsx +++ b/packages/app-headless-cms/src/admin/components/Decorators/ShowConfirmationOnUnpublish.tsx @@ -47,7 +47,7 @@ const EntryMessage = ({ id, entryType, getEntry }: EntryMessageProps) => { export const ShowConfirmationOnUnpublish = useContentEntry.createDecorator(baseHook => { return () => { - const { showSnackbar } = useSnackbar(); + const { showSnackbar, showErrorSnackbar } = useSnackbar(); const dialogs = useDialogs(); const hook = baseHook(); const { contentModel } = hook; @@ -57,7 +57,7 @@ export const ShowConfirmationOnUnpublish = useContentEntry.createDecorator(baseH const response = await hook.unpublishEntryRevision({ id: entry.id }); if (response.error) { - showSnackbar( + showErrorSnackbar( `Could not unpublish ${entry.meta.title}! (${response.error.message})` ); diff --git a/packages/app-headless-cms/src/admin/components/FieldEditor/Field.tsx b/packages/app-headless-cms/src/admin/components/FieldEditor/Field.tsx index 6806d5f7d56..65e53401424 100644 --- a/packages/app-headless-cms/src/admin/components/FieldEditor/Field.tsx +++ b/packages/app-headless-cms/src/admin/components/FieldEditor/Field.tsx @@ -147,7 +147,7 @@ export interface FieldProps { const Field = (props: FieldProps) => { const { field, onEdit, parent } = props; - const { showSnackbar } = useSnackbar(); + const { showSnackbar, showErrorSnackbar } = useSnackbar(); const { setData: setModel, data: model } = useModelEditor(); const { getFieldPlugin, getFieldRendererPlugin } = useModelFieldEditor(); @@ -208,7 +208,7 @@ const Field = (props: FieldProps) => { }); if (response && response.error) { - return showSnackbar(response.error.message); + return showErrorSnackbar(response.error.message); } showSnackbar(t`Title field set successfully.`); @@ -220,7 +220,7 @@ const Field = (props: FieldProps) => { }); if (response && response.error) { - return showSnackbar(response.error.message); + return showErrorSnackbar(response.error.message); } showSnackbar(t`Description field set successfully.`); @@ -232,7 +232,7 @@ const Field = (props: FieldProps) => { }); if (response && response.error) { - return showSnackbar(response.error.message); + return showErrorSnackbar(response.error.message); } showSnackbar(t`Image field set successfully.`); diff --git a/packages/app-headless-cms/src/admin/plugins/editor/defaultBar/SaveContentModelButton.tsx b/packages/app-headless-cms/src/admin/plugins/editor/defaultBar/SaveContentModelButton.tsx index e972a46cbfa..af698649147 100644 --- a/packages/app-headless-cms/src/admin/plugins/editor/defaultBar/SaveContentModelButton.tsx +++ b/packages/app-headless-cms/src/admin/plugins/editor/defaultBar/SaveContentModelButton.tsx @@ -9,7 +9,7 @@ const t = i18n.namespace("app-headless-cms/admin/editor/top-bar/save-button"); const SaveContentModelButton = () => { const { saveContentModel } = useModelEditor(); const [loading, setLoading] = useState(false); - const { showSnackbar } = useSnackbar(); + const { showSnackbar, showErrorSnackbar } = useSnackbar(); const onClick = useCallback(async () => { setLoading(true); @@ -17,7 +17,7 @@ const SaveContentModelButton = () => { setLoading(false); if (response.error) { - showSnackbar(response.error.message); + showErrorSnackbar(response.error.message); return; } diff --git a/packages/app-headless-cms/src/admin/views/contentEntries/ContentEntry/RevisionsList/useRevision.tsx b/packages/app-headless-cms/src/admin/views/contentEntries/ContentEntry/RevisionsList/useRevision.tsx index d2a03766896..521a2ce9d2b 100644 --- a/packages/app-headless-cms/src/admin/views/contentEntries/ContentEntry/RevisionsList/useRevision.tsx +++ b/packages/app-headless-cms/src/admin/views/contentEntries/ContentEntry/RevisionsList/useRevision.tsx @@ -43,7 +43,7 @@ export interface UseRevisionProps { export const useRevision = ({ revision }: UseRevisionProps) => { const contentEntry = useContentEntry(); const { history } = useRouter(); - const { showSnackbar } = useSnackbar(); + const { showSnackbar, showErrorSnackbar } = useSnackbar(); const { contentModel } = contentEntry; const { modelId } = contentModel; @@ -107,7 +107,7 @@ export const useRevision = ({ revision }: UseRevisionProps) => { }); if (response.error) { - showSnackbar(response.error.message); + showErrorSnackbar(response.error.message); return response; }