Use our own timers to dismiss alerts (#3641)

This commit is contained in:
Erik Jan de Wit 2022-10-27 14:00:02 +02:00 committed by GitHub
parent 66a448720a
commit 2f60e78c4f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 42 additions and 36 deletions

View file

@ -4,10 +4,10 @@ import {
AlertActionCloseButton, AlertActionCloseButton,
AlertVariant, AlertVariant,
} from "@patternfly/react-core"; } from "@patternfly/react-core";
import type { AlertType } from "./Alerts"; import type { AlertEntry } from "./Alerts";
type AlertPanelProps = { type AlertPanelProps = {
alerts: AlertType[]; alerts: AlertEntry[];
onCloseAlert: (id: number) => void; onCloseAlert: (id: number) => void;
}; };
@ -27,8 +27,6 @@ export function AlertPanel({ alerts, onCloseAlert }: AlertPanelProps) {
onClose={() => onCloseAlert(id)} onClose={() => onCloseAlert(id)}
/> />
} }
timeout
onTimeout={() => onCloseAlert(id)}
> >
{description && <p>{description}</p>} {description && <p>{description}</p>}
</Alert> </Alert>

View file

@ -1,22 +1,25 @@
import { FunctionComponent, useState } from "react";
import { useTranslation } from "react-i18next";
import { AlertVariant } from "@patternfly/react-core"; import { AlertVariant } from "@patternfly/react-core";
import axios from "axios";
import type { AxiosError } 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 { createNamedContext } from "../../utils/createNamedContext";
import useRequiredContext from "../../utils/useRequiredContext"; import useRequiredContext from "../../utils/useRequiredContext";
import useSetTimeout from "../../utils/useSetTimeout";
import { AlertPanel } from "./AlertPanel"; import { AlertPanel } from "./AlertPanel";
const ALERT_TIMEOUT = 8000;
export type AddAlertFunction = ( export type AddAlertFunction = (
message: string, message: string,
variant?: AlertVariant, variant?: AlertVariant,
description?: string description?: string
) => void; ) => void;
export type AddErrorFunction = (message: string, error: any) => void; export type AddErrorFunction = (message: string, error: unknown) => void;
type AlertProps = { export type AlertProps = {
addAlert: AddAlertFunction; addAlert: AddAlertFunction;
addError: AddErrorFunction; addError: AddErrorFunction;
}; };
@ -28,7 +31,7 @@ export const AlertContext = createNamedContext<AlertProps | undefined>(
export const useAlerts = () => useRequiredContext(AlertContext); export const useAlerts = () => useRequiredContext(AlertContext);
export type AlertType = { export type AlertEntry = {
id: number; id: number;
message: string; message: string;
variant: AlertVariant; variant: AlertVariant;
@ -37,65 +40,70 @@ export type AlertType = {
export const AlertProvider: FunctionComponent = ({ children }) => { export const AlertProvider: FunctionComponent = ({ children }) => {
const { t } = useTranslation(); 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)); setAlerts((alerts) => alerts.filter((alert) => alert.id !== id));
};
const addAlert = ( const addAlert = useCallback<AddAlertFunction>(
message: string, (message, variant = AlertVariant.success, description) => {
variant: AlertVariant = AlertVariant.success, const alert: AlertEntry = {
description?: string
) => {
setAlerts([
{
id: Math.random(), id: Math.random(),
message, message,
variant, variant,
description, 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( addAlert(
t(message, { t(message, {
error: getErrorMessage(error), error: getErrorMessage(error),
}), }),
AlertVariant.danger AlertVariant.danger
); );
}; }, []);
const value = useMemo(() => ({ addAlert, addError }), []);
return ( return (
<AlertContext.Provider value={{ addAlert, addError }}> <AlertContext.Provider value={value}>
<AlertPanel alerts={alerts} onCloseAlert={hideAlert} /> <AlertPanel alerts={alerts} onCloseAlert={removeAlert} />
{children} {children}
</AlertContext.Provider> </AlertContext.Provider>
); );
}; };
function getErrorMessage( function getErrorMessage(error: unknown) {
error: Error | AxiosError<Record<string, unknown>> | string
) {
if (typeof error === "string") { if (typeof error === "string") {
return error; return error;
} }
if (!axios.isAxiosError(error)) { if (axios.isAxiosError(error)) {
return getErrorMessageAxios(error);
}
if (error instanceof Error) {
return error.message; 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"]) { for (const key of ["error_description", "errorMessage", "error"]) {
const value = responseData[key]; const value = data[key];
if (typeof value === "string") { if (typeof value === "string") {
return value; return value;
} }
} }
return error.message;
} }