keycloak-scim/apps/admin-ui/src/components/alert/Alerts.tsx

109 lines
2.7 KiB
TypeScript
Raw Normal View History

import { NetworkError } from "@keycloak/keycloak-admin-client";
import { AlertVariant } from "@patternfly/react-core";
import { FunctionComponent, useCallback, useMemo, useState } from "react";
import { useTranslation } from "react-i18next";
2022-08-03 13:15:04 +00:00
import { createNamedContext } from "../../utils/createNamedContext";
import useRequiredContext from "../../utils/useRequiredContext";
import useSetTimeout from "../../utils/useSetTimeout";
2022-07-13 10:17:21 +00:00
import { AlertPanel } from "./AlertPanel";
2020-08-07 13:44:34 +00:00
const ALERT_TIMEOUT = 8000;
export type AddAlertFunction = (
message: string,
variant?: AlertVariant,
description?: string
) => void;
export type AddErrorFunction = (message: string, error: unknown) => void;
export type AlertProps = {
addAlert: AddAlertFunction;
addError: AddErrorFunction;
};
2022-08-03 13:15:04 +00:00
export const AlertContext = createNamedContext<AlertProps | undefined>(
"AlertContext",
undefined
);
export const useAlerts = () => useRequiredContext(AlertContext);
export type AlertEntry = {
2022-07-13 10:17:21 +00:00
id: number;
message: string;
variant: AlertVariant;
description?: string;
};
export const AlertProvider: FunctionComponent = ({ children }) => {
const { t } = useTranslation();
const setTimeout = useSetTimeout();
const [alerts, setAlerts] = useState<AlertEntry[]>([]);
2020-08-07 13:44:34 +00:00
const removeAlert = (id: number) =>
2022-07-13 10:17:21 +00:00
setAlerts((alerts) => alerts.filter((alert) => alert.id !== id));
const addAlert = useCallback<AddAlertFunction>(
(message, variant = AlertVariant.success, description) => {
const alert: AlertEntry = {
2022-07-13 10:17:21 +00:00
id: Math.random(),
message,
variant,
description,
};
setAlerts((alerts) => [alert, ...alerts]);
setTimeout(() => removeAlert(alert.id), ALERT_TIMEOUT);
},
[]
);
2020-08-07 13:44:34 +00:00
const addError = useCallback<AddErrorFunction>((message, error) => {
addAlert(
t(message, {
2022-05-10 09:50:00 +00:00
error: getErrorMessage(error),
}),
AlertVariant.danger
);
}, []);
const value = useMemo(() => ({ addAlert, addError }), []);
return (
<AlertContext.Provider value={value}>
<AlertPanel alerts={alerts} onCloseAlert={removeAlert} />
{children}
</AlertContext.Provider>
);
};
2022-05-10 09:50:00 +00:00
function getErrorMessage(error: unknown) {
2022-05-10 09:50:00 +00:00
if (typeof error === "string") {
return error;
}
if (error instanceof NetworkError) {
return getNetworkErrorMessage(error);
}
if (error instanceof Error) {
2022-05-10 09:50:00 +00:00
return error.message;
}
throw new Error("Unable to determine error message.");
}
function getNetworkErrorMessage({ responseData }: NetworkError) {
const data = responseData as Record<string, unknown>;
2022-05-10 09:50:00 +00:00
for (const key of ["error_description", "errorMessage", "error"]) {
const value = data[key];
2022-05-10 09:50:00 +00:00
if (typeof value === "string") {
return value;
}
}
}