-
Notifications
You must be signed in to change notification settings - Fork 4
Enhance error handling in user settings routes with user-facing error mapping #1618
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: 11-19-_ts-api-react-actions_enhance_error_handling_in_api_actions_and_hooks_with_user-facing_error_mapping
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,12 +1,17 @@ | ||
| import { faTrashCan } from "@fortawesome/pro-solid-svg-icons"; | ||
| import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; | ||
| import { useStrongForm } from "cyberstorm/utils/StrongForm/useStrongForm"; | ||
| import { | ||
| NimbusErrorBoundary, | ||
| NimbusErrorBoundaryFallback, | ||
| type NimbusErrorBoundaryFallbackProps, | ||
| } from "cyberstorm/utils/errors/NimbusErrorBoundary"; | ||
| import { useReducer } from "react"; | ||
| import { useNavigate, useOutletContext, useRevalidator } from "react-router"; | ||
| import { useHydrated } from "remix-utils/use-hydrated"; | ||
| import { Loading } from "~/commonComponents/Loading/Loading"; | ||
| import { NotLoggedIn } from "~/commonComponents/NotLoggedIn/NotLoggedIn"; | ||
| import { type OutletContextShape } from "~/root"; | ||
| import type { OutletContextShape } from "~/root"; | ||
|
|
||
| import { | ||
| NewAlert, | ||
|
|
@@ -15,8 +20,12 @@ import { | |
| NewTextInput, | ||
| useToast, | ||
| } from "@thunderstore/cyberstorm"; | ||
| import { UserFacingError, userDelete } from "@thunderstore/thunderstore-api"; | ||
|
|
||
| import { | ||
| UserFacingError, | ||
| formatUserFacingError, | ||
| userDelete, | ||
| } from "../../../../../../packages/thunderstore-api/src"; | ||
| import "./Account.css"; | ||
|
|
||
| export default function Account() { | ||
|
|
@@ -32,44 +41,70 @@ export default function Account() { | |
| } | ||
|
|
||
| return ( | ||
| <div className="settings-items user-account"> | ||
| <div className="settings-items__item"> | ||
| <div className="settings-items__meta"> | ||
| <p className="settings-items__title">Delete Account</p> | ||
| <p className="settings-items__description"> | ||
| Delete your Thunderstore account permanently | ||
| </p> | ||
| </div> | ||
| <div className="settings-items__content"> | ||
| <div className="user-account__delete-user-form"> | ||
| <NewAlert csVariant="warning"> | ||
| You are about to delete your account. Once deleted, it will be | ||
| gone forever. Please be certain. | ||
| </NewAlert> | ||
| <p className="user-account__instructions"> | ||
| The mods that have been uploaded on this account will remain | ||
| public on the site even after deletion. If you need them to be | ||
| taken down as well, please contact an administrator on the | ||
| community Discord server. | ||
| <br /> | ||
| <span> | ||
| As a precaution, to delete your account, please input{" "} | ||
| <span className="user-account__username"> | ||
| {outletContext.currentUser.username} | ||
| </span>{" "} | ||
| into the field below. | ||
| </span> | ||
| <NimbusErrorBoundary | ||
| fallback={AccountSettingsFallback} | ||
| onRetry={({ reset }) => reset()} | ||
| > | ||
| <div className="settings-items user-account"> | ||
| <div className="settings-items__item"> | ||
| <div className="settings-items__meta"> | ||
| <p className="settings-items__title">Delete Account</p> | ||
| <p className="settings-items__description"> | ||
| Delete your Thunderstore account permanently | ||
| </p> | ||
| <div className="user-account__actions"> | ||
| <DeleteAccountForm | ||
| currentUser={outletContext.currentUser} | ||
| requestConfig={outletContext.requestConfig} | ||
| /> | ||
| </div> | ||
| <div className="settings-items__content"> | ||
| <div className="user-account__delete-user-form"> | ||
| <NewAlert csVariant="warning"> | ||
| You are about to delete your account. Once deleted, it will be | ||
| gone forever. Please be certain. | ||
| </NewAlert> | ||
| <p className="user-account__instructions"> | ||
| The mods that have been uploaded on this account will remain | ||
| public on the site even after deletion. If you need them to be | ||
| taken down as well, please contact an administrator on the | ||
| community Discord server. | ||
| <br /> | ||
| <span> | ||
| As a precaution, to delete your account, please input{" "} | ||
| <span className="user-account__username"> | ||
| {outletContext.currentUser.username} | ||
| </span>{" "} | ||
| into the field below. | ||
| </span> | ||
| </p> | ||
| <div className="user-account__actions"> | ||
| <DeleteAccountForm | ||
| currentUser={outletContext.currentUser} | ||
| requestConfig={outletContext.requestConfig} | ||
| /> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </NimbusErrorBoundary> | ||
| ); | ||
| } | ||
|
|
||
| /** | ||
| * Displays fallback messaging when the account settings view fails to render. | ||
| */ | ||
| function AccountSettingsFallback(props: NimbusErrorBoundaryFallbackProps) { | ||
| const { | ||
| title = "Account settings failed to load", | ||
| description = "Reload the account tab or return to settings.", | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is the "return to settings" part helpful to the user if the error view doesn't provide a way to do so? If my assumption that the error message is shown only as a reaction to error when submitting an action, would something like "Reload the page to try again" be more suitable? |
||
| retryLabel = "Reload", | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nitpick: Haven't checked the rest of the PRs but I assume "Reload" will be quite common label, so it should probably be the default value instead of the current "Retry"? Would save us some boilerplate. |
||
| ...rest | ||
| } = props; | ||
|
|
||
| return ( | ||
| <NimbusErrorBoundaryFallback | ||
| {...rest} | ||
| title={title} | ||
| description={description} | ||
| retryLabel={retryLabel} | ||
| /> | ||
| ); | ||
| } | ||
|
|
||
|
|
@@ -143,7 +178,7 @@ function DeleteAccountForm(props: { | |
| onSubmitError: (error) => { | ||
| toast.addToast({ | ||
| csVariant: "danger", | ||
| children: `Error occurred: ${error.message || "Unknown error"}`, | ||
| children: formatUserFacingError(error), | ||
| duration: 8000, | ||
| }); | ||
| }, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,6 +5,11 @@ import { NewLink, Tabs } from "@thunderstore/cyberstorm"; | |
|
|
||
| import { type OutletContextShape } from "../../root"; | ||
| import "./Settings.css"; | ||
| import { | ||
| NimbusErrorBoundary, | ||
| NimbusErrorBoundaryFallback, | ||
| } from "cyberstorm/utils/errors/NimbusErrorBoundary"; | ||
| import type { NimbusErrorBoundaryFallbackProps } from "cyberstorm/utils/errors/NimbusErrorBoundary"; | ||
|
|
||
| export default function UserSettings() { | ||
| const context = useOutletContext<OutletContextShape>(); | ||
|
|
@@ -16,7 +21,10 @@ export default function UserSettings() { | |
| } | ||
|
|
||
| return ( | ||
| <> | ||
| <NimbusErrorBoundary | ||
| fallback={UserSettingsFallback} | ||
| onRetry={({ reset }) => reset()} | ||
| > | ||
| <PageHeader headingLevel="1" headingSize="2"> | ||
| Settings | ||
| </PageHeader> | ||
|
|
@@ -47,6 +55,27 @@ export default function UserSettings() { | |
| <Outlet context={context} /> | ||
| </section> | ||
| </div> | ||
| </> | ||
| </NimbusErrorBoundary> | ||
| ); | ||
| } | ||
|
|
||
| /** | ||
| * Provides fallback messaging when the user settings shell fails to render. | ||
| */ | ||
| function UserSettingsFallback(props: NimbusErrorBoundaryFallbackProps) { | ||
| const { | ||
| title = "Settings failed to load", | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can this page fail to load? This time there doesn't seem to be any actions either. Do we want to wrap all the things just in case? |
||
| description = "Reload the settings page or return to the dashboard.", | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What dashboard? |
||
| retryLabel = "Reload", | ||
| ...rest | ||
| } = props; | ||
|
|
||
| return ( | ||
| <NimbusErrorBoundaryFallback | ||
| {...rest} | ||
| title={title} | ||
| description={description} | ||
| retryLabel={retryLabel} | ||
| /> | ||
| ); | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this page even fail to load when it has no loader? I guess the error boundary can catch errors from the actions, but for those errors this error message is a bit off?