1import React, {forwardRef, useContext, useRef, useImperativeHandle} from "react";
2import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
3import {
4 faArrowDown, faArrowUp, faClockRotateLeft, faClose,
5 faInfo, faPingPongPaddleBall, faTrashCan, faWaveSquare
6} from "@fortawesome/free-solid-svg-icons";
7import {useAlert} from "@/common/contexts/Alert";
8import {SpeedtestContext} from "@/common/contexts/Speedtests";
9import {deleteRequest} from "@/common/utils/RequestUtil";
10import "./styles.sass";
11import {averageResultDialog, resultDialog} from "@/pages/Home/components/Speedtest/utils/infos";
12import {errors} from "@/pages/Home/components/Speedtest/utils/errors";
13import {t} from "i18next";
14import {ConfigContext} from "@/common/contexts/Config";
15import {ToastNotificationContext} from "@/common/contexts/ToastNotification";
16import {PreferencesContext} from "@/common/contexts/Preferences";
17import {convertSpeed, formatShortTime} from "@/common/utils/FormatUtil";
18
19const SpeedtestComponent = forwardRef((props, forwardedRef) => {
20 const alert = useAlert();
21 const updateToast = useContext(ToastNotificationContext);
22 const [config] = useContext(ConfigContext);
23 const {deleteTest} = useContext(SpeedtestContext);
24 const [preferences] = useContext(PreferencesContext);
25
26 const ref = useRef();
27
28 useImperativeHandle(forwardedRef, () => ref.current);
29
30 let errorMessage = t("test.unknown_error") + " " + props.error;
31
32 let isAverage = props.type === "average";
33 let timeString = isAverage
34 ? String(props.time.getDate()).padStart(2, '0') + "." + String(props.time.getMonth() + 1).padStart(2, '0')
35 : formatShortTime(props.time, preferences);
36
37 const downValue = props.error ? "" : convertSpeed(props.down, preferences);
38 const upValue = props.error ? "" : convertSpeed(props.up, preferences);
39
40 if (props.error) {
41 for (let errorsKey in errors())
42 if (props.error.includes(errorsKey)) errorMessage = errors()[errorsKey];
43 }
44
45 const fadeOut = () => {
46 if (ref.current == null) return;
47 ref.current.classList.add("speedtest-hidden");
48 updateToast(t("test.deleted"), "green", faTrashCan);
49 setTimeout(() => deleteTest(props.id), 300);
50 }
51
52 const showErrorDialog = async () => {
53 await alert.openAlert(
54 t("test.failed"),
55 errorMessage + ". " + t("test.recheck"),
56 {
57 buttonText: t("dialog.okay"),
58 clearButton: t("test.delete"),
59 onClear: () => deleteRequest(`/speedtests/${props.id}`).then(fadeOut)
60 }
61 );
62 };
63
64 const showInfoDialog = async () => {
65 if (props.type === "average") {
66 await alert.openAlert(
67 t("test.average.title"),
68 averageResultDialog(timeString, {...props, down: downValue, up: upValue}),
69 {buttonText: t("dialog.okay")}
70 );
71 } else {
72 await alert.openAlert(
73 t("test.result.title"),
74 resultDialog({...props, down: downValue, up: upValue}),
75 {
76 buttonText: t("dialog.okay"),
77 clearButton: !config.viewMode ? t("test.delete") : undefined,
78 onClear: () => deleteRequest(`/speedtests/${props.id}`).then(fadeOut)
79 }
80 );
81 }
82 };
83
84 return (
85 <div className="speedtest" ref={ref} onClick={props.error ? showErrorDialog : showInfoDialog}>
86 <div className="date">
87 <FontAwesomeIcon icon={props.error ? faInfo : faClockRotateLeft}
88 className={"container-icon icon-" + (props.error ? "error" : "blue")}/>
89 <h2 className="date-text">{(t("time." + (isAverage ? "on" : "at"))) + " " + timeString}</h2>
90 </div>
91 <div className="speedtest-row">
92 <FontAwesomeIcon icon={props.error ? faClose : faPingPongPaddleBall}
93 className={"speedtest-icon icon-" + props.pingLevel}/>
94 <h2 className="speedtest-text">
95 {props.error ? "" : props.ping}
96 {!props.error && props.jitter !== null && props.jitter !== undefined && (
97 <span className="jitter-suffix"><FontAwesomeIcon icon={faWaveSquare} className="jitter-icon" />{props.jitter}</span>
98 )}
99 </h2>
100 </div>
101 <div className="speedtest-row">
102 <FontAwesomeIcon icon={props.error ? faClose : faArrowDown}
103 className={"speedtest-icon icon-" + props.downLevel}/>
104 <h2 className="speedtest-text">{downValue}</h2>
105 </div>
106 <div className="speedtest-row">
107 <FontAwesomeIcon icon={props.error ? faClose : faArrowUp}
108 className={"speedtest-icon icon-" + props.upLevel}/>
109 <h2 className="speedtest-text">{upValue}</h2>
110 </div>
111 </div>
112 );
113});
114
115export default SpeedtestComponent;