1import {Dialog, DialogHeader, DialogBody, DialogFooter} from "@/common/contexts/Dialog";
2import {useAlert} from "@/common/contexts/Alert";
3import React, {useContext, useState} from "react";
4import "./styles.sass";
5import {t} from "i18next";
6import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
7import {faCircleInfo, faServer, faSpinner} from "@fortawesome/free-solid-svg-icons";
8import {baseRequest} from "@/common/utils/RequestUtil";
9import {ToastNotificationContext} from "@/common/contexts/ToastNotification";
10import {NodeContext} from "@/common/contexts/Node";
11
12export const CreateNodeDialog = ({open, onClose}) => {
13 const alert = useAlert();
14 const updateNodes = useContext(NodeContext)[1];
15 const updateToast = useContext(ToastNotificationContext);
16 const [invalidUrl, setInvalidUrl] = useState(false);
17 const [serverName, setServerName] = useState("");
18 const [serverUrl, setServerUrl] = useState("");
19 const [checking, setChecking] = useState(false);
20
21 const runPasswordProcess = async (wrong = false) => {
22 const password = await alert.openInput(t("dialog.password.title"), {
23 inputType: "password",
24 description: wrong ? <span className="icon-red">{t("dialog.password.wrong")}</span> : t("nodes.password_required"),
25 placeholder: t("dialog.password.placeholder"),
26 buttonText: t("nodes.create")
27 });
28 if (password) {
29 const res = await (await baseRequest("/nodes", "PUT", {
30 name: serverName, url: serverUrl, password
31 })).json();
32 if (res.type === "PASSWORD_REQUIRED") runPasswordProcess(true);
33 else if (res.type === "NODE_CREATED") {
34 updateNodes();
35 updateToast(t("nodes.created"), "green", faServer);
36 }
37 }
38 };
39
40 const createNode = async (close) => {
41 setChecking(true);
42
43 try {
44 const response = await (await baseRequest("/nodes", "PUT", {name: serverName, url: serverUrl})).json();
45 if (response.type === "INVALID_URL") setInvalidUrl(true);
46 else if (response.type === "PASSWORD_REQUIRED") {
47 close();
48 runPasswordProcess();
49 } else if (response.type === "NODE_CREATED") {
50 updateNodes();
51 close();
52 updateToast(t("nodes.created"), "green", faServer);
53 }
54 } catch {
55 setInvalidUrl(true);
56 } finally {
57 setChecking(false);
58 }
59 };
60
61 return (
62 <Dialog open={open} onClose={onClose} className="create-node-dialog">
63 {({close}) => (
64 <>
65 <DialogHeader onClose={close}>{t("nodes.add")}</DialogHeader>
66 <DialogBody>
67 <div className="server-dialog">
68 <div className="server-group">
69 <div className="server-label">
70 <FontAwesomeIcon icon={faCircleInfo}/>
71 <h3>{t("nodes.group.name")}</h3>
72 </div>
73 <input type="text" className="dialog-input server-input" placeholder={t("nodes.placeholder.name")} value={serverName}
74 onChange={(e) => setServerName(e.target.value)}/>
75 </div>
76 <div className={"server-group" + (invalidUrl ? " server-error" : "")}>
77 <div className="server-label">
78 <FontAwesomeIcon icon={faServer}/>
79 <h3>{t("nodes.group.url")}</h3>
80 </div>
81 <input type="text" className="dialog-input server-input" placeholder={t("nodes.placeholder.url")} value={serverUrl}
82 onChange={(e) => { setServerUrl(e.target.value); setInvalidUrl(false); }}/>
83 </div>
84 </div>
85 </DialogBody>
86 <DialogFooter>
87 <button className="dialog-btn" disabled={checking} onClick={() => createNode(close)}>
88 {checking && <FontAwesomeIcon icon={faSpinner} spin/>}
89 {t("nodes.create")}
90 </button>
91 </DialogFooter>
92 </>
93 )}
94 </Dialog>
95 );
96}