From a25c9f984674653c88f8323186137786028939c0 Mon Sep 17 00:00:00 2001 From: muhammadeko Date: Fri, 6 May 2022 16:13:57 +0700 Subject: [PATCH 1/3] wip --- public/locales/en-US/gcauth.json | 4 ++ src/components/MenuDesktop.tsx | 6 ++ src/components/MenuMobile.tsx | 6 ++ src/components/Navbar.tsx | 108 ++++++++++++++++--------------- src/components/RouteMenu.tsx | 4 ++ src/components/pages/GCAuth.tsx | 74 +++++++++++++++++++++ src/i18n.ts | 2 +- 7 files changed, 151 insertions(+), 53 deletions(-) create mode 100644 public/locales/en-US/gcauth.json create mode 100644 src/components/pages/GCAuth.tsx diff --git a/public/locales/en-US/gcauth.json b/public/locales/en-US/gcauth.json new file mode 100644 index 0000000..61a5e94 --- /dev/null +++ b/public/locales/en-US/gcauth.json @@ -0,0 +1,4 @@ +{ + "navigation": "GCAuth", + "title": "GCAuth Token Generator" +} \ No newline at end of file diff --git a/src/components/MenuDesktop.tsx b/src/components/MenuDesktop.tsx index 3a93fdb..342ffed 100644 --- a/src/components/MenuDesktop.tsx +++ b/src/components/MenuDesktop.tsx @@ -20,6 +20,12 @@ export default function MenuDesktop(props:{handleHeaderTitleChange: (title:strin ) : ( handleHeaderTitleChange("Artifact Command Generator")} className="menu-item text-gray-300 hover:bg-gray-700 hover:text-white px-3 py-2 rounded-md text-sm font-medium">Artifact )} + + {location.pathname === "/gcauth" ? ( + GCAuth + ) : ( + handleHeaderTitleChange("GCAuth Token Generator")} className="menu-item block text-gray-300 hover:bg-gray-700 hover:text-white px-3 py-2 rounded-md text-sm font-medium">GCAuth + )} ) } \ No newline at end of file diff --git a/src/components/MenuMobile.tsx b/src/components/MenuMobile.tsx index d81ac35..b24f03d 100644 --- a/src/components/MenuMobile.tsx +++ b/src/components/MenuMobile.tsx @@ -20,6 +20,12 @@ export default function MenuMobile(props: any) { ) : ( handleHeaderTitleChange("Artifact Command Generator")} className="menu-item block text-gray-300 hover:bg-gray-700 hover:text-white px-3 py-2 rounded-md text-sm font-medium">Artifact )} + + {location.pathname === "/gcauth" ? ( + GCAuth + ) : ( + handleHeaderTitleChange("GCAuth Token Generator")} className="menu-item block text-gray-300 hover:bg-gray-700 hover:text-white px-3 py-2 rounded-md text-sm font-medium">GCAuth + )} ) } \ No newline at end of file diff --git a/src/components/Navbar.tsx b/src/components/Navbar.tsx index def1893..4072a75 100644 --- a/src/components/Navbar.tsx +++ b/src/components/Navbar.tsx @@ -1,14 +1,20 @@ -import React from "react"; +import React, {useEffect} from "react"; import MenuDesktop from "./MenuDesktop"; import MenuMobile from "./MenuMobile"; import {Menu} from "@mui/material"; -import i18n from "i18next"; +import i18n, {use} from "i18next"; import {useTranslation} from "react-i18next"; import LanguageChange from "./LanguageChange"; +import {useNavigate} from "react-router-dom"; -class Navbar extends React.Component { - handleHeaderTitleChange; - toggleMobileMenu = () => { +interface Props { + handleHeaderTitleChange: (title: string) => void; +} +export default function Navbar(props: Props) { + const {handleHeaderTitleChange} = props; + const pathname = window.location.pathname; + const {t} = useTranslation(); + const toggleMobileMenu = () => { const menuShow = document.querySelector(".menu-show"); const menuHide = document.querySelector(".menu-hide"); const mobileMenu = document.querySelector("#mobile-menu"); @@ -28,56 +34,54 @@ class Navbar extends React.Component { } } } - - constructor(props:{handleHeaderTitleChange: (title:string) => void}) { - super(props); - const {handleHeaderTitleChange} = props; - - this.handleHeaderTitleChange = handleHeaderTitleChange; - const pathname =window.location.pathname; - - if(pathname==="/") handleHeaderTitleChange("Home") - else if(pathname==="/artifact") handleHeaderTitleChange("Artifact Command Generator") - } - - render() { - return( - + ) +} \ No newline at end of file diff --git a/src/components/RouteMenu.tsx b/src/components/RouteMenu.tsx index 6df7131..19078d8 100644 --- a/src/components/RouteMenu.tsx +++ b/src/components/RouteMenu.tsx @@ -1,6 +1,7 @@ import {Routes, Route, RouteProps} from "react-router-dom"; import React from "react"; import Artifacts from "./pages/Artifacts"; +import GCAuth from "./pages/GCAuth"; interface RouteMenuProps extends RouteProps{ handleHeaderTitleChange: (title: string) => void; @@ -17,6 +18,9 @@ export default function RouteMenu(props: RouteMenuProps) { }/> + + }/> ); } \ No newline at end of file diff --git a/src/components/pages/GCAuth.tsx b/src/components/pages/GCAuth.tsx new file mode 100644 index 0000000..b5f16e7 --- /dev/null +++ b/src/components/pages/GCAuth.tsx @@ -0,0 +1,74 @@ +import {useEffect, useState} from "react"; +import {Autocomplete, TextField} from "@mui/material"; + +interface IGCAuthResponse{ + status: string; + message: string; + jwt: string; +} + +interface IJWTPayload{ + token: string; + username: string; + uid: string; +} + +interface IGCAuthLogin{ + username: string; + password: string; +} + +interface IGCAuthRegister{ + username: string; + password: string; + password_confirmation: string; +} + +interface IGCAuthChangePassword{ + username: string; + new_password: string; + new_password_confirmation: string; + old_password: string; +} + +export default function GCAuth() { + const [jwt, setJwt] = useState(""); + const [dispatchServer, setDispatchServer] = useState(""); + const [useSSl, setUseSSl] = useState(true); + const [baseUrl, setBaseUrl] = useState(""); + + const checkGCAuth = async ()=>{ + fetch(baseUrl+"/authentication/type") + .then(res => res.text()) + .then(res => { + if (res === "me.exzork.gcauth.handler.GCAuthAuthenticationHandler"){ + console.log("GCAuth is installed"); + }else{ + console.log("GCAuth is not installed"); + } + }) + .catch(err => { + console.log(err); + }); + } + + useEffect(() => { + setBaseUrl(`http${useSSl ? "s" : ""}://${dispatchServer}`); + }, [useSSl, dispatchServer]); + return ( + <> +
+
+
+ setDispatchServer(e.currentTarget.value)} placeholder="Input server ip/domain with port, ex : genshin.exzork.me:443" className="block w-full shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm border-gray-300 rounded-md"/> +
+ setUseSSl(e.currentTarget.checked)} id="with-ssl" className="form-checkbox m-auto text-indigo-600 transition duration-150 ease-in-out"/> + +
+ +
+
+
+ + ) +} \ No newline at end of file diff --git a/src/i18n.ts b/src/i18n.ts index 3c5a4cd..2e6d058 100644 --- a/src/i18n.ts +++ b/src/i18n.ts @@ -13,7 +13,7 @@ i18n interpolation: { escapeValue: false, // not needed for react!! }, - ns: ["artifact"], + ns: ["artifact","gcauth"], defaultNS: "", }); From fc3d38d028b8379c5a17157c09d754b66ea7df2a Mon Sep 17 00:00:00 2001 From: muhammadeko Date: Fri, 6 May 2022 16:40:07 +0700 Subject: [PATCH 2/3] wip --- src/components/pages/GCAuth.tsx | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/components/pages/GCAuth.tsx b/src/components/pages/GCAuth.tsx index b5f16e7..1bdfe87 100644 --- a/src/components/pages/GCAuth.tsx +++ b/src/components/pages/GCAuth.tsx @@ -60,13 +60,26 @@ export default function GCAuth() {
- setDispatchServer(e.currentTarget.value)} placeholder="Input server ip/domain with port, ex : genshin.exzork.me:443" className="block w-full shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm border-gray-300 rounded-md"/> + setDispatchServer(e.currentTarget.value)} placeholder="Input server ip/domain with port if needed" className="block w-full shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm border-gray-300 rounded-md"/>
setUseSSl(e.currentTarget.checked)} id="with-ssl" className="form-checkbox m-auto text-indigo-600 transition duration-150 ease-in-out"/>
+
+
+
+

Login

+ + + +
+
+
+ +
+
From 03472e382b6ca7a4fdb8e428e9b07dae3f31eaf6 Mon Sep 17 00:00:00 2001 From: muhammadeko Date: Fri, 6 May 2022 22:39:09 +0700 Subject: [PATCH 3/3] done, no translation for gcauth at the moment --- package.json | 1 + src/components/pages/GCAuth.tsx | 283 +++++++++++++++++++++++++++++--- yarn.lock | 5 + 3 files changed, 265 insertions(+), 24 deletions(-) diff --git a/package.json b/package.json index 51ebc9a..88626e3 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "react-router-dom": "^6.3.0", "react-scripts": "5.0.1", "react-select-search": "^3.0.9", + "sweetalert2": "^11.4.10", "tailwindcss": "^3.0.24", "typescript": "^4.6.4", "web-vitals": "^2.1.4" diff --git a/src/components/pages/GCAuth.tsx b/src/components/pages/GCAuth.tsx index 1bdfe87..da176f0 100644 --- a/src/components/pages/GCAuth.tsx +++ b/src/components/pages/GCAuth.tsx @@ -1,30 +1,30 @@ -import {useEffect, useState} from "react"; -import {Autocomplete, TextField} from "@mui/material"; +import {FormEvent, useEffect, useState} from "react"; +import Swal from "sweetalert2"; -interface IGCAuthResponse{ +interface IGCAuthResponse { status: string; message: string; jwt: string; } -interface IJWTPayload{ +interface IJWTPayload { token: string; username: string; uid: string; } -interface IGCAuthLogin{ +interface IGCAuthLogin { username: string; password: string; } -interface IGCAuthRegister{ +interface IGCAuthRegister { username: string; password: string; password_confirmation: string; } -interface IGCAuthChangePassword{ +interface IGCAuthChangePassword { username: string; new_password: string; new_password_confirmation: string; @@ -33,18 +33,47 @@ interface IGCAuthChangePassword{ export default function GCAuth() { const [jwt, setJwt] = useState(""); - const [dispatchServer, setDispatchServer] = useState(""); - const [useSSl, setUseSSl] = useState(true); + const [dispatchServer, setDispatchServer] = useState(localStorage.getItem("dispatchServer") ?? ""); + const [useSSl, setUseSSl] = useState(localStorage.getItem("useSSl")==="true" ?? true); const [baseUrl, setBaseUrl] = useState(""); - const checkGCAuth = async ()=>{ - fetch(baseUrl+"/authentication/type") + const [loginUsername, setLoginUsername] = useState(""); + const [loginPassword, setLoginPassword] = useState(""); + const [token, setToken] = useState(""); + + const [registerUsername, setRegisterUsername] = useState(""); + const [registerPassword, setRegisterPassword] = useState(""); + const [registerPasswordConfirmation, setRegisterPasswordConfirmation] = useState(""); + + const [changePasswordUsername, setChangePasswordUsername] = useState(""); + const [changePasswordNewPassword, setChangePasswordNewPassword] = useState(""); + const [changePasswordNewPasswordConfirmation, setChangePasswordNewPasswordConfirmation] = useState(""); + const [changePasswordOldPassword, setChangePasswordOldPassword] = useState(""); + + const checkGCAuth = async () => { + fetch(baseUrl + "/authentication/type") .then(res => res.text()) .then(res => { - if (res === "me.exzork.gcauth.handler.GCAuthAuthenticationHandler"){ - console.log("GCAuth is installed"); - }else{ - console.log("GCAuth is not installed"); + if (res === "me.exzork.gcauth.handler.GCAuthAuthenticationHandler") { + Swal.fire({ + toast: true, + position: "top-end", + showConfirmButton: false, + timer: 3000, + timerProgressBar: true, + title: "GCAuth is installed", + icon: "success" + }); + } else { + Swal.fire({ + toast: true, + position: "top-end", + showConfirmButton: false, + timer: 3000, + timerProgressBar: true, + title: "GCAuth is not installed", + icon: "error" + }); } }) .catch(err => { @@ -54,30 +83,236 @@ export default function GCAuth() { useEffect(() => { setBaseUrl(`http${useSSl ? "s" : ""}://${dispatchServer}`); + localStorage.setItem("dispatchServer", dispatchServer); + localStorage.setItem("useSSl", useSSl.toString()); }, [useSSl, dispatchServer]); + + const handleLogin = async (e: FormEvent) => { + e.preventDefault(); + const data: IGCAuthLogin = { + username: loginUsername, + password: loginPassword + } + fetch(baseUrl + "/authentication/login", {method: "POST", body: JSON.stringify(data)}) + .then(async (res) => { + const resText = await res.text(); + try { + let resJson = JSON.parse(resText); + if (resJson.success) { + await Swal.fire({ + toast: true, + position: "top-end", + showConfirmButton: false, + timer: 3000, + timerProgressBar: true, + title: "Login success", + icon: "success" + }); + setJwt(resJson.jwt); + const splitToken = resJson.jwt.split("."); + const payload = JSON.parse(atob(splitToken[1])); + setToken(payload.token); + } else { + await Swal.fire({ + title: "Login failed", + text: resJson.message ?? resJson, + icon: "error" + }); + } + } catch (e) { + await Swal.fire({ + title: "Login failed", + text: resText, + icon: "error" + }); + } + }).catch((err) => { + console.log(err); + Swal.fire({ + title: "Login failed", + text: err, + icon: "error" + }); + }); + } + + const handleRegister = async (e: FormEvent) => { + e.preventDefault(); + const data: IGCAuthRegister = { + username: registerUsername, + password: registerPassword, + password_confirmation: registerPasswordConfirmation + } + fetch(baseUrl + "/authentication/register", {method: "POST", body: JSON.stringify(data)}) + .then(async (res) => { + const resText = await res.text(); + try { + let resJson = JSON.parse(resText); + if (resJson.success) { + await Swal.fire({ + toast: true, + position: "top-end", + showConfirmButton: false, + timer: 3000, + timerProgressBar: true, + title: "Register success", + icon: "success" + }); + setJwt(resJson.jwt); + } else { + await Swal.fire({ + title: "Register failed", + text: resJson.message ?? resJson, + icon: "error" + }); + } + } catch (e) { + await Swal.fire({ + title: "Register failed", + text: resText, + icon: "error" + }); + } + }).catch((err) => { + console.log(err); + Swal.fire({ + title: "Register failed", + text: err, + icon: "error" + }); + }); + } + + const handleChangePassword = async (e: FormEvent) => { + e.preventDefault(); + const data: IGCAuthChangePassword = { + username: changePasswordUsername, + new_password: changePasswordNewPassword, + new_password_confirmation: changePasswordNewPasswordConfirmation, + old_password: changePasswordOldPassword + } + + fetch(baseUrl + "/authentication/change_password", {method: "POST", body: JSON.stringify(data)}) + .then(async (res) => { + const resText = await res.text(); + try { + let resJson = JSON.parse(resText); + if (resJson.success) { + await Swal.fire({ + toast: true, + position: "top-end", + showConfirmButton: false, + timer: 3000, + timerProgressBar: true, + title: "Change password success", + icon: "success" + }); + } else { + await Swal.fire({ + title: "Change password failed", + text: resJson.message ?? resJson, + icon: "error" + }); + } + } catch (e) { + await Swal.fire({ + title: "Change password failed", + text: resText, + icon: "error" + }); + } + }).catch((err) => { + console.log(err); + Swal.fire({ + title: "Change password failed", + text: err, + icon: "error" + }); + }); + } + + const handleCopyToken = (e:FormEvent) => { + e.preventDefault(); + if (token!==""){ + navigator.clipboard.writeText(token); + Swal.fire({toast: true, position: "top-end", showConfirmButton: false, timer: 3000, timerProgressBar: true, title: "Token copied", icon: "success"}); + }else{ + Swal.fire({title: "No token", text: "You need to login first", icon: "error"}); + } + } + return ( <>
- setDispatchServer(e.currentTarget.value)} placeholder="Input server ip/domain with port if needed" className="block w-full shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm border-gray-300 rounded-md"/> + setDispatchServer(e.currentTarget.value)} + placeholder="Input server ip/domain with port if needed" + className="block w-full shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm border-gray-300 rounded-md"/>
- setUseSSl(e.currentTarget.checked)} id="with-ssl" className="form-checkbox m-auto text-indigo-600 transition duration-150 ease-in-out"/> - + setUseSSl(e.currentTarget.checked)} id="with-ssl" + className="form-checkbox m-auto text-indigo-600 transition duration-150 ease-in-out"/> +
- +
-
+

Login

- - - + setLoginUsername(e.currentTarget.value)} + className="mt-2 block w-full shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm border-gray-300 rounded-md"/> + setLoginPassword(e.currentTarget.value)} + className="mt-2 block w-full shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm border-gray-300 rounded-md"/> + +
- +
+

Register

+ setRegisterUsername(e.currentTarget.value)} + className="mt-2 block w-full shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm border-gray-300 rounded-md"/> + setRegisterPassword(e.currentTarget.value)} + className="mt-2 block w-full shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm border-gray-300 rounded-md"/> + setRegisterPasswordConfirmation(e.currentTarget.value)} + className="mt-2 block w-full shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm border-gray-300 rounded-md"/> + +
+
+
+
+

Change Password

+ setChangePasswordUsername(e.currentTarget.value)} + className="mt-2 block w-full shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm border-gray-300 rounded-md"/> + setChangePasswordNewPassword(e.currentTarget.value)} + className="mt-2 block w-full shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm border-gray-300 rounded-md"/> + setChangePasswordNewPasswordConfirmation(e.currentTarget.value)} + className="mt-2 block w-full shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm border-gray-300 rounded-md"/> + setChangePasswordOldPassword(e.currentTarget.value)} + className="mt-2 block w-full shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm border-gray-300 rounded-md"/> + +
diff --git a/yarn.lock b/yarn.lock index ca3b6d9..dfe7806 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8341,6 +8341,11 @@ svgo@^2.7.0: picocolors "^1.0.0" stable "^0.1.8" +sweetalert2@^11.4.10: + version "11.4.10" + resolved "https://registry.yarnpkg.com/sweetalert2/-/sweetalert2-11.4.10.tgz#d0f7733a0997aad18b81c6f6b39a01c3a6cb4e21" + integrity sha512-Ms3mryLA/c5+llHNY0I9KXU8bv0N1a874gZr7xMPOiSnLD9veHZA92nZvJOkuN1hrdcR8kyj4IN8tBxlAIjVww== + symbol-tree@^3.2.4: version "3.2.4" resolved "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz"