aboutsummaryrefslogtreecommitdiff
path: root/FrontEnd/src/components/alert/AlertHost.tsx
blob: b234ac033a9042347ec47a8a29e4103792ccd776 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
import * as React from "react";
import without from "lodash/without";
import { useTranslation } from "react-i18next";
import classNames from "classnames";

import { alertService, AlertInfoEx, AlertInfo } from "~src/services/alert";
import { convertI18nText } from "~src/common";

import IconButton from "../button/IconButton";

import "./alert.css";

interface AutoCloseAlertProps {
  alert: AlertInfo;
  close: () => void;
}

export const AutoCloseAlert: React.FC<AutoCloseAlertProps> = (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(() => closeHandler.current?.(), dismissTime)
        : window.setTimeout(() => closeHandler.current?.(), 5000);
    timerTag.current = tag;
    return () => {
      if (tag != null) {
        window.clearTimeout(tag);
      }
    };
  }, [dismissTime]);

  const cancelTimer = (): void => {
    const { current: tag } = timerTag;
    if (tag != null) {
      window.clearTimeout(tag);
    }
  };

  return (
    <div
      className={classNames(
        "m-3 cru-alert",
        "cru-" + (alert.type ?? "primary")
      )}
      onClick={cancelTimer}
    >
      <div className="cru-alert-content">
        {(() => {
          const { message, customMessage } = alert;
          if (customMessage != null) {
            return customMessage;
          } else {
            return convertI18nText(message, t);
          }
        })()}
      </div>
      <div className="cru-alert-close-button-container">
        <IconButton
          icon="x"
          className="cru-alert-close-button"
          onClick={close}
        />
      </div>
    </div>
  );
};

const AlertHost: React.FC = () => {
  const [alerts, setAlerts] = React.useState<AlertInfoEx[]>([]);

  React.useEffect(() => {
    const consume = (alert: AlertInfoEx): void => {
      setAlerts((old) => [...old, alert]);
    };

    alertService.registerConsumer(consume);
    return () => {
      alertService.unregisterConsumer(consume);
    };
  }, []);

  return (
    <div className="alert-container">
      {alerts.map((alert) => {
        return (
          <AutoCloseAlert
            key={alert.id}
            alert={alert}
            close={() => {
              setAlerts((old) => without(old, alert));
            }}
          />
        );
      })}
    </div>
  );
};

export default AlertHost;