diff options
author | crupest <crupest@outlook.com> | 2021-02-14 16:41:40 +0800 |
---|---|---|
committer | crupest <crupest@outlook.com> | 2021-02-14 16:41:40 +0800 |
commit | 962eb6ef3096dc90149a286190096a99496dd90a (patch) | |
tree | 167d8ece87f9457f3c7b9e89348087ec6298569e | |
parent | 5f7c012f6815a7306448b715bec1975494acfd7f (diff) | |
download | timeline-962eb6ef3096dc90149a286190096a99496dd90a.tar.gz timeline-962eb6ef3096dc90149a286190096a99496dd90a.tar.bz2 timeline-962eb6ef3096dc90149a286190096a99496dd90a.zip |
refactor: Enhance code in alert.
-rw-r--r-- | FrontEnd/src/app/services/alert.ts | 4 | ||||
-rw-r--r-- | FrontEnd/src/app/views/common/alert/AlertHost.tsx | 70 |
2 files changed, 36 insertions, 38 deletions
diff --git a/FrontEnd/src/app/services/alert.ts b/FrontEnd/src/app/services/alert.ts index e4c0e653..b6d6be6e 100644 --- a/FrontEnd/src/app/services/alert.ts +++ b/FrontEnd/src/app/services/alert.ts @@ -1,9 +1,11 @@ import React from "react"; import pull from "lodash/pull"; +import { I18nText } from "@/common"; + export interface AlertInfo { type?: "primary" | "secondary" | "success" | "danger" | "warning" | "info"; - message: string | React.FC<unknown> | { type: "i18n"; key: string }; + message: React.FC<unknown> | I18nText; dismissTime?: number | "never"; } diff --git a/FrontEnd/src/app/views/common/alert/AlertHost.tsx b/FrontEnd/src/app/views/common/alert/AlertHost.tsx index f50e41ad..949be7ed 100644 --- a/FrontEnd/src/app/views/common/alert/AlertHost.tsx +++ b/FrontEnd/src/app/views/common/alert/AlertHost.tsx @@ -1,6 +1,5 @@ -import React, { useCallback } from "react"; +import React from "react"; import without from "lodash/without"; -import concat from "lodash/concat"; import { useTranslation } from "react-i18next"; import { Alert } from "react-bootstrap"; @@ -10,6 +9,7 @@ import { kAlertHostId, AlertInfo, } from "@/services/alert"; +import { convertI18nText } from "@/common"; interface AutoCloseAlertProps { alert: AlertInfo; @@ -17,39 +17,46 @@ interface AutoCloseAlertProps { } export const AutoCloseAlert: React.FC<AutoCloseAlertProps> = (props) => { - const { alert } = props; + const { alert, close } = props; const { dismissTime } = alert; const { t } = useTranslation(); const timerTag = React.useRef<number | null>(null); + const closeHandler = React.useRef<(() => void) | null>(null); + + React.useEffect(() => { + closeHandler.current = close; + }, [close]); React.useEffect(() => { const tag = dismissTime === "never" ? null : typeof dismissTime === "number" - ? window.setTimeout(props.close, dismissTime) - : window.setTimeout(props.close, 5000); + ? window.setTimeout(() => closeHandler.current?.(), dismissTime) + : window.setTimeout(() => closeHandler.current?.(), 5000); timerTag.current = tag; return () => { if (tag != null) { window.clearTimeout(tag); } }; - }, [dismissTime, props.close]); + }, [dismissTime]); + + const cancelTimer = (): void => { + const { current: tag } = timerTag; + if (tag != null) { + window.clearTimeout(tag); + } + }; return ( <Alert className="m-3" variant={alert.type ?? "primary"} - onClick={() => { - const { current: tag } = timerTag; - if (tag != null) { - window.clearTimeout(tag); - } - }} - onClose={props.close} + onClick={cancelTimer} + onClose={close} dismissible > {(() => { @@ -57,50 +64,39 @@ export const AutoCloseAlert: React.FC<AutoCloseAlertProps> = (props) => { if (typeof message === "function") { const Message = message; return <Message />; - } else if (typeof message === "object" && message.type === "i18n") { - return t(message.key); - } else return alert.message; + } else return convertI18nText(message, t); })()} </Alert> ); }; -// oh what a bad name! -interface AlertInfoExEx extends AlertInfoEx { - close: () => void; -} - const AlertHost: React.FC = () => { - const [alerts, setAlerts] = React.useState<AlertInfoExEx[]>([]); + const [alerts, setAlerts] = React.useState<AlertInfoEx[]>([]); // 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); - }); - }, + React.useEffect(() => { + const consume = (alert: AlertInfoEx): void => { + setAlerts((old) => [...old, alert]); }; - setAlerts((oldAlerts) => { - return concat(oldAlerts, alertEx); - }); - }, []); - React.useEffect(() => { alertService.registerConsumer(consume); return () => { alertService.unregisterConsumer(consume); }; - }, [consume]); + }, []); return ( <div id={kAlertHostId} className="alert-container"> {alerts.map((alert) => { return ( - <AutoCloseAlert key={alert.id} alert={alert} close={alert.close} /> + <AutoCloseAlert + key={alert.id} + alert={alert} + close={() => { + setAlerts((old) => without(old, alert)); + }} + /> ); })} </div> |