mirror of
https://github.com/exzork/gc-tools.git
synced 2024-11-22 07:08:12 +00:00
commit
76d979aab7
@ -28,6 +28,7 @@
|
|||||||
"react-router-dom": "^6.3.0",
|
"react-router-dom": "^6.3.0",
|
||||||
"react-scripts": "5.0.1",
|
"react-scripts": "5.0.1",
|
||||||
"react-select-search": "^3.0.9",
|
"react-select-search": "^3.0.9",
|
||||||
|
"sweetalert2": "^11.4.10",
|
||||||
"tailwindcss": "^3.0.24",
|
"tailwindcss": "^3.0.24",
|
||||||
"typescript": "^4.6.4",
|
"typescript": "^4.6.4",
|
||||||
"web-vitals": "^2.1.4"
|
"web-vitals": "^2.1.4"
|
||||||
|
4
public/locales/en-US/gcauth.json
Normal file
4
public/locales/en-US/gcauth.json
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"navigation": "GCAuth",
|
||||||
|
"title": "GCAuth Token Generator"
|
||||||
|
}
|
@ -20,6 +20,12 @@ export default function MenuDesktop(props:{handleHeaderTitleChange: (title:strin
|
|||||||
) : (
|
) : (
|
||||||
<Link to="/artifact" onClick={() => 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</Link>
|
<Link to="/artifact" onClick={() => 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</Link>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{location.pathname === "/gcauth" ? (
|
||||||
|
<Link to="/gcauth" className="menu-item block bg-gray-900 text-white px-3 py-2 rounded-md text-sm font-medium">GCAuth</Link>
|
||||||
|
) : (
|
||||||
|
<Link to="/gcauth" onClick={() => 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</Link>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
@ -20,6 +20,12 @@ export default function MenuMobile(props: any) {
|
|||||||
) : (
|
) : (
|
||||||
<Link to="/artifact" onClick={() => 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</Link>
|
<Link to="/artifact" onClick={() => 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</Link>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{location.pathname === "/gcauth" ? (
|
||||||
|
<Link to="/gcauth" className="menu-item block bg-gray-900 text-white px-3 py-2 rounded-md text-sm font-medium">GCAuth</Link>
|
||||||
|
) : (
|
||||||
|
<Link to="/gcauth" onClick={() => 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</Link>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
@ -1,14 +1,20 @@
|
|||||||
import React from "react";
|
import React, {useEffect} from "react";
|
||||||
import MenuDesktop from "./MenuDesktop";
|
import MenuDesktop from "./MenuDesktop";
|
||||||
import MenuMobile from "./MenuMobile";
|
import MenuMobile from "./MenuMobile";
|
||||||
import {Menu} from "@mui/material";
|
import {Menu} from "@mui/material";
|
||||||
import i18n from "i18next";
|
import i18n, {use} from "i18next";
|
||||||
import {useTranslation} from "react-i18next";
|
import {useTranslation} from "react-i18next";
|
||||||
import LanguageChange from "./LanguageChange";
|
import LanguageChange from "./LanguageChange";
|
||||||
|
import {useNavigate} from "react-router-dom";
|
||||||
|
|
||||||
class Navbar extends React.Component {
|
interface Props {
|
||||||
handleHeaderTitleChange;
|
handleHeaderTitleChange: (title: string) => void;
|
||||||
toggleMobileMenu = () => {
|
}
|
||||||
|
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 menuShow = document.querySelector(".menu-show");
|
||||||
const menuHide = document.querySelector(".menu-hide");
|
const menuHide = document.querySelector(".menu-hide");
|
||||||
const mobileMenu = document.querySelector("#mobile-menu");
|
const mobileMenu = document.querySelector("#mobile-menu");
|
||||||
@ -28,56 +34,54 @@ class Navbar extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
useEffect(() => {
|
||||||
constructor(props:{handleHeaderTitleChange: (title:string) => void}) {
|
switch (pathname){
|
||||||
super(props);
|
case "/":
|
||||||
const {handleHeaderTitleChange} = props;
|
handleHeaderTitleChange("Home")
|
||||||
|
break;
|
||||||
this.handleHeaderTitleChange = handleHeaderTitleChange;
|
case "/artifact":
|
||||||
const pathname =window.location.pathname;
|
handleHeaderTitleChange(t('title',{ns:"artifact"}))
|
||||||
|
break;
|
||||||
if(pathname==="/") handleHeaderTitleChange("Home")
|
case "/gcauth":
|
||||||
else if(pathname==="/artifact") handleHeaderTitleChange("Artifact Command Generator")
|
handleHeaderTitleChange(t('title',{ns:"gcauth"}))
|
||||||
}
|
break;
|
||||||
|
}
|
||||||
render() {
|
}, []);
|
||||||
return(
|
return(
|
||||||
<nav className="bg-gray-800">
|
<nav className="bg-gray-800">
|
||||||
<div className="max-w-7xl mx-auto px-2 sm:px-6 lg:px-8">
|
<div className="max-w-7xl mx-auto px-2 sm:px-6 lg:px-8">
|
||||||
<div className="relative flex items-center justify-between h-16">
|
<div className="relative flex items-center justify-between h-16">
|
||||||
<div className="absolute inset-y-0 left-0 flex items-center sm:hidden">
|
<div className="absolute inset-y-0 left-0 flex items-center sm:hidden">
|
||||||
{/* Mobile menu button */}
|
{/* Mobile menu button */}
|
||||||
<button onClick={this.toggleMobileMenu} className="inline-flex items-center justify-center p-2 rounded-md text-gray-400 hover:text-white hover:bg-gray-700 focus:outline-none focus:bg-gray-700 focus:text-white transition duration-150 ease-in-out">
|
<button onClick={toggleMobileMenu} className="inline-flex items-center justify-center p-2 rounded-md text-gray-400 hover:text-white hover:bg-gray-700 focus:outline-none focus:bg-gray-700 focus:text-white transition duration-150 ease-in-out">
|
||||||
<svg className="menu-show block h-6 w-6" stroke="currentColor" fill="none" viewBox="0 0 24 24">
|
<svg className="menu-show block h-6 w-6" stroke="currentColor" fill="none" viewBox="0 0 24 24">
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M4 6h16M4 12h16M4 18h16"/>
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M4 6h16M4 12h16M4 18h16"/>
|
||||||
</svg>
|
</svg>
|
||||||
<svg className="menu-hide hidden h-6 w-6" stroke="currentColor" fill="none" viewBox="0 0 24 24">
|
<svg className="menu-hide hidden h-6 w-6" stroke="currentColor" fill="none" viewBox="0 0 24 24">
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M6 18L18 6M6 6l12 12"/>
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M6 18L18 6M6 6l12 12"/>
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
|
</div>
|
||||||
|
<div className="flex-1 flex items-center justify-center sm:items-stretch sm:justify-start">
|
||||||
|
<div className="flex-shrink-0 flex items-center text-white text-lg">
|
||||||
|
Grasscutter Tools
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-1 flex items-center justify-center sm:items-stretch sm:justify-start">
|
<div className="hidden sm:block sm:ml-6 w-full">
|
||||||
<div className="flex-shrink-0 flex items-center text-white text-lg">
|
<div className="flex w-full">
|
||||||
Grasscutter Tools
|
<MenuDesktop handleHeaderTitleChange={handleHeaderTitleChange}/>
|
||||||
</div>
|
<LanguageChange/>
|
||||||
<div className="hidden sm:block sm:ml-6 w-full">
|
|
||||||
<div className="flex w-full">
|
|
||||||
<MenuDesktop handleHeaderTitleChange={this.handleHeaderTitleChange}/>
|
|
||||||
<LanguageChange/>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div className="hidden sm:hidden" id="mobile-menu">
|
||||||
|
<div className="px-2 pt2 pb-3 space-y-1">
|
||||||
|
<MenuMobile handleHeaderTitleChange={handleHeaderTitleChange}/>
|
||||||
|
<LanguageChange/>
|
||||||
</div>
|
</div>
|
||||||
<div className="hidden sm:hidden" id="mobile-menu">
|
</div>
|
||||||
<div className="px-2 pt2 pb-3 space-y-1">
|
</nav>
|
||||||
<MenuMobile handleHeaderTitleChange={this.handleHeaderTitleChange}/>
|
)
|
||||||
<LanguageChange/>
|
}
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
export default Navbar;
|
|
@ -1,6 +1,7 @@
|
|||||||
import {Routes, Route, RouteProps} from "react-router-dom";
|
import {Routes, Route, RouteProps} from "react-router-dom";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import Artifacts from "./pages/Artifacts";
|
import Artifacts from "./pages/Artifacts";
|
||||||
|
import GCAuth from "./pages/GCAuth";
|
||||||
|
|
||||||
interface RouteMenuProps extends RouteProps{
|
interface RouteMenuProps extends RouteProps{
|
||||||
handleHeaderTitleChange: (title: string) => void;
|
handleHeaderTitleChange: (title: string) => void;
|
||||||
@ -17,6 +18,9 @@ export default function RouteMenu(props: RouteMenuProps) {
|
|||||||
<Route path="/artifact" element={
|
<Route path="/artifact" element={
|
||||||
<Artifacts/>
|
<Artifacts/>
|
||||||
}/>
|
}/>
|
||||||
|
<Route path="/gcauth" element={
|
||||||
|
<GCAuth/>
|
||||||
|
}/>
|
||||||
</Routes>
|
</Routes>
|
||||||
);
|
);
|
||||||
}
|
}
|
322
src/components/pages/GCAuth.tsx
Normal file
322
src/components/pages/GCAuth.tsx
Normal file
@ -0,0 +1,322 @@
|
|||||||
|
import {FormEvent, useEffect, useState} from "react";
|
||||||
|
import Swal from "sweetalert2";
|
||||||
|
|
||||||
|
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(localStorage.getItem("dispatchServer") ?? "");
|
||||||
|
const [useSSl, setUseSSl] = useState(localStorage.getItem("useSSl")==="true" ?? true);
|
||||||
|
const [baseUrl, setBaseUrl] = useState("");
|
||||||
|
|
||||||
|
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") {
|
||||||
|
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 => {
|
||||||
|
console.log(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
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 (
|
||||||
|
<>
|
||||||
|
<div className="space-y-8 divide-y divide-gray-200 bg-white p-10">
|
||||||
|
<div className="space-y-8 divide-y divide-gray-200 sm:space-y-5">
|
||||||
|
<div className="flex" id="dispatch-server">
|
||||||
|
<input type="text" defaultValue={dispatchServer} onChange={(e) => 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"/>
|
||||||
|
<div className="flex mx-2">
|
||||||
|
<input type="checkbox" checked={useSSl} onChange={(e) => setUseSSl(e.currentTarget.checked)} id="with-ssl"
|
||||||
|
className="form-checkbox m-auto text-indigo-600 transition duration-150 ease-in-out"/>
|
||||||
|
<label htmlFor="with-ssl"
|
||||||
|
className="ml-2 my-auto block text-sm leading-5 text-gray-700">SSL</label>
|
||||||
|
</div>
|
||||||
|
<button onClick={checkGCAuth}
|
||||||
|
className="bg-indigo-600 hover:bg-indigo-500 text-white font-bold py-2 px-4 rounded-md">Check
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div className="grid grid-cols-3 gap-4">
|
||||||
|
<div className="col-span-1">
|
||||||
|
<form className="mt-3 h-full flex flex-col" onSubmit={handleLogin}>
|
||||||
|
<h3 className="text-lg font-medium text-gray-900 text-center">Login</h3>
|
||||||
|
<input type="text" placeholder="Username"
|
||||||
|
onChange={(e) => 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"/>
|
||||||
|
<input type="password" placeholder="Password"
|
||||||
|
onChange={(e) => 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"/>
|
||||||
|
<button
|
||||||
|
className="mt-auto bg-indigo-600 hover:bg-indigo-500 text-white font-bold py-2 px-4 rounded-md w-full">Login
|
||||||
|
</button>
|
||||||
|
<button onClick={handleCopyToken} className="mt-2 bg-indigo-600 hover:bg-indigo-500 text-white font-bold py-2 px-4 rounded-md w-full">Copy Token
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div className="col-span-1">
|
||||||
|
<form className="mt-3 h-full flex flex-col" onSubmit={handleRegister}>
|
||||||
|
<h3 className="text-lg font-medium text-gray-900 text-center">Register</h3>
|
||||||
|
<input type="text" placeholder="Username"
|
||||||
|
onChange={(e) => 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"/>
|
||||||
|
<input type="password" placeholder="Password"
|
||||||
|
onChange={(e) => 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"/>
|
||||||
|
<input type="password" placeholder="Confirm Password"
|
||||||
|
onChange={(e) => 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"/>
|
||||||
|
<button
|
||||||
|
className="mt-auto bg-indigo-600 hover:bg-indigo-500 text-white font-bold py-2 px-4 rounded-md w-full">Register
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div className="col-span-1">
|
||||||
|
<form className="mt-3 h-full flex flex-col" onSubmit={handleChangePassword}>
|
||||||
|
<h3 className="text-lg font-medium text-gray-900 text-center">Change Password</h3>
|
||||||
|
<input type="text" placeholder="Username"
|
||||||
|
onChange={(e) => 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"/>
|
||||||
|
<input type="password" placeholder="Password"
|
||||||
|
onChange={(e) => 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"/>
|
||||||
|
<input type="password" placeholder="Confirm Password"
|
||||||
|
onChange={(e) => 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"/>
|
||||||
|
<input type="password" placeholder="Old Password"
|
||||||
|
onChange={(e) => 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"/>
|
||||||
|
<button
|
||||||
|
className="mt-auto bg-indigo-600 hover:bg-indigo-500 text-white font-bold py-2 px-4 rounded-md w-full">Change
|
||||||
|
Password
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
@ -13,7 +13,7 @@ i18n
|
|||||||
interpolation: {
|
interpolation: {
|
||||||
escapeValue: false, // not needed for react!!
|
escapeValue: false, // not needed for react!!
|
||||||
},
|
},
|
||||||
ns: ["artifact"],
|
ns: ["artifact","gcauth"],
|
||||||
defaultNS: "",
|
defaultNS: "",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -8341,6 +8341,11 @@ svgo@^2.7.0:
|
|||||||
picocolors "^1.0.0"
|
picocolors "^1.0.0"
|
||||||
stable "^0.1.8"
|
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:
|
symbol-tree@^3.2.4:
|
||||||
version "3.2.4"
|
version "3.2.4"
|
||||||
resolved "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz"
|
resolved "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz"
|
||||||
|
Loading…
Reference in New Issue
Block a user