From 5285ea4ad97cbf86a171d2c273d159d0e89fb7eb Mon Sep 17 00:00:00 2001 From: "Kaffi Y." Date: Sun, 6 Oct 2024 00:19:02 +0800 Subject: [PATCH] refactor: optimize ui of error toast (#766) --- .../ui/code-highlighter/copy-button.tsx | 1 + apps/renderer/src/lib/error-parser.ts | 70 ++++++++++++------- .../src/modules/discover/inbox-form.tsx | 9 +-- .../src/modules/discover/inbox-list-form.tsx | 5 +- .../src/modules/feed-column/index.tsx | 5 +- .../src/modules/settings/tabs/lists.tsx | 5 +- .../renderer/src/providers/root-providers.tsx | 2 +- 7 files changed, 56 insertions(+), 41 deletions(-) diff --git a/apps/renderer/src/components/ui/code-highlighter/copy-button.tsx b/apps/renderer/src/components/ui/code-highlighter/copy-button.tsx index fbd74a4b1..41862e494 100644 --- a/apps/renderer/src/components/ui/code-highlighter/copy-button.tsx +++ b/apps/renderer/src/components/ui/code-highlighter/copy-button.tsx @@ -41,6 +41,7 @@ export const CopyButton: Component<{ { if (error instanceof FetchError) { @@ -22,7 +24,17 @@ export const getFetchErrorMessage = (error: Error) => { return error.message } -export const toastFetchError = (error: Error) => { + +/** + * Just a wrapper around `toastFetchError` to create a function that can be used as a callback. + */ +export const createErrorToaster = (title?: string, toastOptions?: ExternalToast) => (err: Error) => + toastFetchError(err, { title, ...toastOptions }) + +export const toastFetchError = ( + error: Error, + { title: _title, ..._toastOptions }: ExternalToast & { title?: string } = {}, +) => { let message = "" let _reason = "" if (error instanceof FetchError) { @@ -43,30 +55,40 @@ export const toastFetchError = (error: Error) => { } } - if (!_reason) { - return toast.error(message) - } else { - return toast.error(message, { - duration: 5000, + const toastOptions: ExternalToast = { + ..._toastOptions, + classNames: { + toast: "items-start bg-theme-background", + title: "-mt-1 mb-1", // to align with the icon (actually cut the top space from line-height) + content: "w-full", + ..._toastOptions.classNames, + }, + } - description: createElement( - "div", - { - className: "min-w-0 flex relative", - }, - [ - createElement(CopyButton, { - className: "absolute right-0 top-0 z-[1]", - key: "copy", - value: _reason, - }), - createElement(Markdown, { - key: "reason", - className: "text-sm opacity-70 min-w-0", - children: _reason, - }), - ], - ), + if (!_reason) { + const title = _title || message + toastOptions.description = _title ? message : undefined + return toast.error(title, toastOptions) + } else { + return toast.error(message || _title, { + duration: 5000, + ...toastOptions, + description: createElement("div", {}, [ + createElement(CopyButton, { + className: cn( + "relative z-[1] float-end -mt-1", + "border-transparent bg-theme-background text-theme-foreground opacity-60 transition-opacity", + "hover:bg-theme-button-hover hover:opacity-100 focus:border-theme-foreground/80", + ), + key: "copy", + value: _reason, + }), + createElement(Markdown, { + key: "reason", + className: "text-sm opacity-70 min-w-0 flex-1", + children: _reason, + }), + ]), }) } } diff --git a/apps/renderer/src/modules/discover/inbox-form.tsx b/apps/renderer/src/modules/discover/inbox-form.tsx index 993abe0ee..a8e3f5163 100644 --- a/apps/renderer/src/modules/discover/inbox-form.tsx +++ b/apps/renderer/src/modules/discover/inbox-form.tsx @@ -21,6 +21,7 @@ import { import { Input } from "~/components/ui/input" import { apiClient } from "~/lib/api-fetch" import { FeedViewType } from "~/lib/enum" +import { createErrorToaster } from "~/lib/error-parser" import { cn } from "~/lib/utils" import type { InboxModel } from "~/models" import { useInbox } from "~/queries/inboxes" @@ -107,9 +108,7 @@ const InboxInnerForm = ({ subscriptionActions.fetchByView(FeedViewType.Articles) toast.success(t("discover.inbox_create_success")) }, - onError: () => { - toast.error(t("discover.inbox_create_error")) - }, + onError: createErrorToaster(t("discover.inbox_create_error")), }) const mutationChange = useMutation({ @@ -126,9 +125,7 @@ const InboxInnerForm = ({ subscriptionActions.fetchByView(FeedViewType.Articles) toast.success(t("discover.inbox_update_success")) }, - onError: () => { - toast.error(t("discover.inbox_update_error")) - }, + onError: createErrorToaster(t("discover.inbox_update_error")), }) function onSubmit(values: z.infer) { diff --git a/apps/renderer/src/modules/discover/inbox-list-form.tsx b/apps/renderer/src/modules/discover/inbox-list-form.tsx index ffaf4078d..c20258198 100644 --- a/apps/renderer/src/modules/discover/inbox-list-form.tsx +++ b/apps/renderer/src/modules/discover/inbox-list-form.tsx @@ -16,6 +16,7 @@ import { } from "~/components/ui/table" import { apiClient } from "~/lib/api-fetch" import { FeedViewType } from "~/lib/enum" +import { createErrorToaster } from "~/lib/error-parser" import { useInboxList } from "~/queries/inboxes" import { subscriptionActions } from "~/store/subscription" @@ -156,9 +157,7 @@ const ConfirmDestroyModalContent = ({ id, onSuccess }: { id: string; onSuccess: toast.success(t("discover.inbox_destroy_success")) onSuccess() }, - onError: () => { - toast.error(t("discover.inbox_destroy_error")) - }, + onError: createErrorToaster(t("discover.inbox_destroy_error")), }) return ( diff --git a/apps/renderer/src/modules/feed-column/index.tsx b/apps/renderer/src/modules/feed-column/index.tsx index aff114a7c..2c8571d4b 100644 --- a/apps/renderer/src/modules/feed-column/index.tsx +++ b/apps/renderer/src/modules/feed-column/index.tsx @@ -197,10 +197,7 @@ export function FeedColumn({ children, className }: PropsWithChildren<{ classNam
{views.map((item, index) => ( -
+
))} diff --git a/apps/renderer/src/modules/settings/tabs/lists.tsx b/apps/renderer/src/modules/settings/tabs/lists.tsx index 691513153..50660c169 100644 --- a/apps/renderer/src/modules/settings/tabs/lists.tsx +++ b/apps/renderer/src/modules/settings/tabs/lists.tsx @@ -39,6 +39,7 @@ import { Tooltip, TooltipContent, TooltipPortal, TooltipTrigger } from "~/compon import { views } from "~/constants" import { useAuthQuery, useI18n } from "~/hooks/common" import { apiClient } from "~/lib/api-fetch" +import { createErrorToaster } from "~/lib/error-parser" import { cn, isBizId } from "~/lib/utils" import type { FeedModel } from "~/models" import { ViewSelectorRadioGroup } from "~/modules/shared/ViewSelectorRadioGroup" @@ -241,9 +242,7 @@ const ListCreationModalContent = ({ dismiss, id }: { dismiss: () => void; id?: s if (!list) return if (id) subscriptionActions.changeListView(id, views[list.view].view, views[values.view].view) }, - async onError() { - toast.error(t(id ? "lists.edit.error" : "lists.created.error")) - }, + onError: createErrorToaster(id ? t("lists.edit.error") : t("lists.created.error")), }) function onSubmit(values: z.infer) { diff --git a/apps/renderer/src/providers/root-providers.tsx b/apps/renderer/src/providers/root-providers.tsx index 0cc92c4c0..df93836df 100644 --- a/apps/renderer/src/providers/root-providers.tsx +++ b/apps/renderer/src/providers/root-providers.tsx @@ -47,6 +47,7 @@ export const RootProviders: FC = ({ children }) => ( {import.meta.env.DEV && } {children} + @@ -54,7 +55,6 @@ export const RootProviders: FC = ({ children }) => ( - )