import React, { useCallback } from 'react'; import { Alert } from 'reactstrap'; import without from 'lodash/without'; import concat from 'lodash/concat'; import { alertService, AlertInfoEx, kAlertHostId, AlertInfo, } from './alert-service'; import { useTranslation } from 'react-i18next'; interface AutoCloseAlertProps { alert: AlertInfo; close: () => void; } export const AutoCloseAlert: React.FC = (props) => { const { alert } = props; const { dismissTime } = alert; const { t } = useTranslation(); React.useEffect(() => { const tag = dismissTime === 'never' ? null : typeof dismissTime === 'number' ? window.setTimeout(props.close, dismissTime) : window.setTimeout(props.close, 5000); return () => { if (tag != null) { window.clearTimeout(tag); } }; }, [dismissTime, props.close]); return ( {(() => { const { message } = alert; if (typeof message === 'function') { const Message = message; return ; } else if (typeof message === 'object' && message.type === 'i18n') { return t(message.key); } else return alert.message; })()} ); }; // oh what a bad name! interface AlertInfoExEx extends AlertInfoEx { close: () => void; } export const AlertHost: React.FC = () => { const [alerts, setAlerts] = React.useState([]); // react guarantee that state setters are stable, so we don't need to add it to dependency list const consume = useCallback((alert: AlertInfoEx): void => { const alertEx: AlertInfoExEx = { ...alert, close: () => { setAlerts((oldAlerts) => { return without(oldAlerts, alertEx); }); }, }; setAlerts((oldAlerts) => { return concat(oldAlerts, alertEx); }); }, []); React.useEffect(() => { alertService.registerConsumer(consume); return () => { alertService.unregisterConsumer(consume); }; }, [consume]); return (
{alerts.map((alert) => { return ( ); })}
); }; export default AlertHost;