From 533c04d9558bd0a575671c157ca42236f59a2c5a Mon Sep 17 00:00:00 2001 From: physcik Date: Tue, 28 Apr 2026 23:33:59 +0500 Subject: frontend auth --- front/src/App.css | 1 + front/src/App.tsx | 42 +++++++++++++------- front/src/Authentication/ContextProvider.ts | 38 ++++++++++++++++++ front/src/Authentication/LoginPage.tsx | 60 +++++++++++++++++++++++++++++ front/src/Authentication/Models.ts | 4 ++ front/src/Emelents/Elements.css | 7 ++++ front/src/Emelents/Sidebar.tsx | 1 + front/src/Emelents/Topbar.tsx | 12 +++++- front/src/Locales/ru_RU.ts | 7 ++++ front/src/index.tsx | 10 +++-- 10 files changed, 165 insertions(+), 17 deletions(-) create mode 100644 front/src/Authentication/ContextProvider.ts create mode 100644 front/src/Authentication/LoginPage.tsx create mode 100644 front/src/Authentication/Models.ts (limited to 'front/src') diff --git a/front/src/App.css b/front/src/App.css index dcfa013..d58f45b 100644 --- a/front/src/App.css +++ b/front/src/App.css @@ -19,3 +19,4 @@ padding-left: 10px; padding-right: 10px; } + diff --git a/front/src/App.tsx b/front/src/App.tsx index 2f69086..c106139 100644 --- a/front/src/App.tsx +++ b/front/src/App.tsx @@ -6,11 +6,15 @@ import IndexElement from './Emelents/IndexElement'; import ClassesList from './Emelents/ClassList'; import Topbar from './Emelents/Topbar'; import { AllowedLanguages, LanguageContext } from './Locales/Context'; -import { useState } from 'react'; +import { useEffect, useState } from 'react'; import { ReadCurrentLocale, SaveCurrentLocale } from './Locales/Locales'; import LegalNote from './Emelents/LegalNote'; import WeaponsIndex from './Pages/Weapons'; import RangedWeaponPage from './Pages/RangedWeapon'; +import { AuthContext, Authentication, GetUserInfo } from './Authentication/ContextProvider'; +import { useCookies } from 'react-cookie'; +import LoginPage from './Authentication/LoginPage'; +import { User } from './Authentication/Models'; const router = createBrowserRouter([ { @@ -29,6 +33,10 @@ const router = createBrowserRouter([ path: "/weapons/:id", element: (), }, + { + path: "/login", + element: (), + }, ]); function App() { @@ -40,20 +48,28 @@ function App() { setLang(newLang); } + const [authCookie, ] = useCookies(['X-AUTH-TOKEN']); + const [auth, setAuth] = useState(null); + useEffect(() => { + GetUserInfo(authCookie['X-AUTH-TOKEN']).then(v => setAuth(v)); + }, []); + return ( - -
- -
- - + + +
+ +
+ + +
+
- -
- + + ); } -export default App; +export default App; diff --git a/front/src/Authentication/ContextProvider.ts b/front/src/Authentication/ContextProvider.ts new file mode 100644 index 0000000..040d22e --- /dev/null +++ b/front/src/Authentication/ContextProvider.ts @@ -0,0 +1,38 @@ +import axios from "axios" +import { createContext } from "react" +import { BackendURL } from "../Config" +import { User } from "./Models" + +export type Authentication = { + User: User + Token: string +} + +const UserInfoURL = `${BackendURL}/auth`; + +export const AuthContext = createContext(null); + +export function SaveState(data: Authentication | null, setCookie: (cookie: string) => void) { + if (data == null) return; + setCookie(data.Token); +} + +export async function GetUserInfo(displayToken: string): Promise { + if (!displayToken || displayToken.length == 0) return null; + try { + const { data, status } = await axios.get( + UserInfoURL, + { + headers: { + Accept: "application/json", + Authorization: `Bearer ${displayToken}` + } + } + ); + if (status != 200) return null; + return data; + } catch (err) { + console.log(`Failed to get user info: ${err}`); + return null; + } +} diff --git a/front/src/Authentication/LoginPage.tsx b/front/src/Authentication/LoginPage.tsx new file mode 100644 index 0000000..e98c506 --- /dev/null +++ b/front/src/Authentication/LoginPage.tsx @@ -0,0 +1,60 @@ +import axios from "axios"; +import { useContext, useState } from "react"; +import { useNavigate } from "react-router"; +import { BackendURL } from "../Config"; +import { Authentication, SaveState } from "./ContextProvider"; +import { useCookies } from 'react-cookie'; +import { GetLocalizedString } from "../Locales/Locales"; +import { LanguageContext } from "../Locales/Context"; + +const LoginURL = `${BackendURL}/auth/login`; + +function LoginPage() { + const lang = useContext(LanguageContext); + + const [username, setUsername] = useState(""); + const [passw, setPassw] = useState(""); + const navigate = useNavigate(); + + function SetAuthState(newAuthState: Authentication | null) { + if (newAuthState) { + console.log(`Logging in as ${newAuthState.User}...`); + } else { + console.log(`Logging out...`); + } + SaveState(newAuthState, (cookie: string) => { + document.cookie = `X-AUTH-TOKEN=${cookie}; path=/;`; + }) + } + + return ( +
+

{ GetLocalizedString("Username", lang) }

+ setUsername(ev.target.value)} /> +

{ GetLocalizedString("Password", lang) }

+ setPassw(ev.target.value)} /> + +
+ ); +} + +async function Login(username: string, passw: string, onSuccess: (data: Authentication) => void) { + await axios.post( + LoginURL, { + Username: username, + Password: passw + } + ).then(resp => { + onSuccess(resp.data); + }).catch(err => { + console.log(`Failed to send a login responce: ${err}`); + }); +} + +export default LoginPage; diff --git a/front/src/Authentication/Models.ts b/front/src/Authentication/Models.ts new file mode 100644 index 0000000..1918b85 --- /dev/null +++ b/front/src/Authentication/Models.ts @@ -0,0 +1,4 @@ +export type User = { + Username: string, + Role: "user" | "editor" +} diff --git a/front/src/Emelents/Elements.css b/front/src/Emelents/Elements.css index 6f23c13..7c8c15f 100644 --- a/front/src/Emelents/Elements.css +++ b/front/src/Emelents/Elements.css @@ -21,9 +21,16 @@ } .Topbar > h1 { + margin-top: 0px; + flex-direction: row; margin-bottom: 0px; } +.Topbar > h1 > img { + height: 1em; + width: auto; +} + .TopbarContents { border-top: 2px solid var(--colorscheme-black); display: flex; diff --git a/front/src/Emelents/Sidebar.tsx b/front/src/Emelents/Sidebar.tsx index c650145..ad565fa 100644 --- a/front/src/Emelents/Sidebar.tsx +++ b/front/src/Emelents/Sidebar.tsx @@ -19,6 +19,7 @@ function Sidebar({setLang}: SidebarProps) { +