Use our own timers to dismiss alerts (#3641)
This commit is contained in:
parent
66a448720a
commit
2f60e78c4f
2 changed files with 42 additions and 36 deletions
|
@ -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 && <p>{description}</p>}
|
||||
</Alert>
|
||||
|
|
|
@ -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<AlertProps | undefined>(
|
|||
|
||||
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<AlertType[]>([]);
|
||||
const setTimeout = useSetTimeout();
|
||||
const [alerts, setAlerts] = useState<AlertEntry[]>([]);
|
||||
|
||||
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<AddAlertFunction>(
|
||||
(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<AddErrorFunction>((message, error) => {
|
||||
addAlert(
|
||||
t(message, {
|
||||
error: getErrorMessage(error),
|
||||
}),
|
||||
AlertVariant.danger
|
||||
);
|
||||
};
|
||||
}, []);
|
||||
|
||||
const value = useMemo(() => ({ addAlert, addError }), []);
|
||||
|
||||
return (
|
||||
<AlertContext.Provider value={{ addAlert, addError }}>
|
||||
<AlertPanel alerts={alerts} onCloseAlert={hideAlert} />
|
||||
<AlertContext.Provider value={value}>
|
||||
<AlertPanel alerts={alerts} onCloseAlert={removeAlert} />
|
||||
{children}
|
||||
</AlertContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
function getErrorMessage(
|
||||
error: Error | AxiosError<Record<string, unknown>> | 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<string, unknown>;
|
||||
throw new Error("Unable to determine error message.");
|
||||
}
|
||||
|
||||
function getErrorMessageAxios(error: AxiosError) {
|
||||
const data = (error.response?.data ?? {}) as Record<string, unknown>;
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue