diff --git a/apps/admin-ui/src/components/alert/AlertPanel.tsx b/apps/admin-ui/src/components/alert/AlertPanel.tsx index 37884f9d62..e9895cd020 100644 --- a/apps/admin-ui/src/components/alert/AlertPanel.tsx +++ b/apps/admin-ui/src/components/alert/AlertPanel.tsx @@ -4,10 +4,10 @@ import { AlertActionCloseButton, AlertVariant, } from "@patternfly/react-core"; -import type { AlertType } from "./Alerts"; +import type { AlertEntry } from "./Alerts"; type AlertPanelProps = { - alerts: AlertType[]; + alerts: AlertEntry[]; onCloseAlert: (id: number) => void; }; @@ -27,8 +27,6 @@ export function AlertPanel({ alerts, onCloseAlert }: AlertPanelProps) { onClose={() => onCloseAlert(id)} /> } - timeout - onTimeout={() => onCloseAlert(id)} > {description &&

{description}

} diff --git a/apps/admin-ui/src/components/alert/Alerts.tsx b/apps/admin-ui/src/components/alert/Alerts.tsx index 390ebea766..df631940e6 100644 --- a/apps/admin-ui/src/components/alert/Alerts.tsx +++ b/apps/admin-ui/src/components/alert/Alerts.tsx @@ -1,22 +1,25 @@ -import { FunctionComponent, useState } from "react"; -import { useTranslation } from "react-i18next"; import { AlertVariant } from "@patternfly/react-core"; -import axios from "axios"; import type { AxiosError } from "axios"; +import axios from "axios"; +import { FunctionComponent, useCallback, useMemo, useState } from "react"; +import { useTranslation } from "react-i18next"; import { createNamedContext } from "../../utils/createNamedContext"; import useRequiredContext from "../../utils/useRequiredContext"; +import useSetTimeout from "../../utils/useSetTimeout"; import { AlertPanel } from "./AlertPanel"; +const ALERT_TIMEOUT = 8000; + export type AddAlertFunction = ( message: string, variant?: AlertVariant, description?: string ) => void; -export type AddErrorFunction = (message: string, error: any) => void; +export type AddErrorFunction = (message: string, error: unknown) => void; -type AlertProps = { +export type AlertProps = { addAlert: AddAlertFunction; addError: AddErrorFunction; }; @@ -28,7 +31,7 @@ export const AlertContext = createNamedContext( export const useAlerts = () => useRequiredContext(AlertContext); -export type AlertType = { +export type AlertEntry = { id: number; message: string; variant: AlertVariant; @@ -37,65 +40,70 @@ export type AlertType = { export const AlertProvider: FunctionComponent = ({ children }) => { const { t } = useTranslation(); - const [alerts, setAlerts] = useState([]); + const setTimeout = useSetTimeout(); + const [alerts, setAlerts] = useState([]); - const hideAlert = (id: number) => { + const removeAlert = (id: number) => setAlerts((alerts) => alerts.filter((alert) => alert.id !== id)); - }; - const addAlert = ( - message: string, - variant: AlertVariant = AlertVariant.success, - description?: string - ) => { - setAlerts([ - { + const addAlert = useCallback( + (message, variant = AlertVariant.success, description) => { + const alert: AlertEntry = { id: Math.random(), message, variant, description, - }, - ...alerts, - ]); - }; + }; - const addError = (message: string, error: Error | AxiosError | string) => { + setAlerts((alerts) => [alert, ...alerts]); + setTimeout(() => removeAlert(alert.id), ALERT_TIMEOUT); + }, + [] + ); + + const addError = useCallback((message, error) => { addAlert( t(message, { error: getErrorMessage(error), }), AlertVariant.danger ); - }; + }, []); + + const value = useMemo(() => ({ addAlert, addError }), []); return ( - - + + {children} ); }; -function getErrorMessage( - error: Error | AxiosError> | string -) { +function getErrorMessage(error: unknown) { if (typeof error === "string") { return error; } - if (!axios.isAxiosError(error)) { + if (axios.isAxiosError(error)) { + return getErrorMessageAxios(error); + } + + if (error instanceof Error) { return error.message; } - const responseData = (error.response?.data ?? {}) as Record; + throw new Error("Unable to determine error message."); +} + +function getErrorMessageAxios(error: AxiosError) { + const data = (error.response?.data ?? {}) as Record; for (const key of ["error_description", "errorMessage", "error"]) { - const value = responseData[key]; + const value = data[key]; if (typeof value === "string") { return value; } } - - return error.message; }