import { NetworkError } from "@keycloak/keycloak-admin-client"; import { AlertVariant } from "@patternfly/react-core"; import { PropsWithChildren, useCallback, useMemo, useState } from "react"; import { useTranslation } from "react-i18next"; import { generateId } from "../../util"; import { createNamedContext, useRequiredContext } from "ui-shared"; 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: unknown) => void; export type AlertProps = { addAlert: AddAlertFunction; addError: AddErrorFunction; }; export const AlertContext = createNamedContext( "AlertContext", undefined ); export const useAlerts = () => useRequiredContext(AlertContext); export type AlertEntry = { id: number; message: string; variant: AlertVariant; description?: string; }; export const AlertProvider = ({ children }: PropsWithChildren) => { const { t } = useTranslation(); const setTimeout = useSetTimeout(); const [alerts, setAlerts] = useState([]); const removeAlert = (id: number) => setAlerts((alerts) => alerts.filter((alert) => alert.id !== id)); const addAlert = useCallback( (message, variant = AlertVariant.success, description) => { const alert: AlertEntry = { id: generateId(), message, variant, description, }; 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: unknown) { if (typeof error === "string") { return error; } if (error instanceof NetworkError) { return getNetworkErrorMessage(error); } if (error instanceof Error) { return error.message; } throw new Error("Unable to determine error message."); } function getNetworkErrorMessage({ responseData }: NetworkError) { const data = responseData as Record; for (const key of ["error_description", "errorMessage", "error"]) { const value = data[key]; if (typeof value === "string") { return value; } } }