From ffbeed38434ece7be28acdf7e3bd900c801a636d Mon Sep 17 00:00:00 2001 From: physcik Date: Thu, 7 May 2026 15:44:45 +0500 Subject: Ranged weapons edit page --- front/src/App.tsx | 18 +- front/src/Authentication/Models.ts | 1 + front/src/Emelents/Topbar.tsx | 2 +- front/src/ErrorHandler.tsx | 4 +- front/src/Pages/RangedWeapon.tsx | 359 +++++++++++++++++++++++++++++++++++-- front/src/Pages/Weapons.css | 4 + front/src/Pages/Weapons.tsx | 18 +- 7 files changed, 380 insertions(+), 26 deletions(-) (limited to 'front/src') diff --git a/front/src/App.tsx b/front/src/App.tsx index da9cbfd..c3d4b00 100644 --- a/front/src/App.tsx +++ b/front/src/App.tsx @@ -33,14 +33,15 @@ const router = createBrowserRouter([ path: "/weapons", element: (), }, - { - path: "/weapons/:id", - element: (), - }, { path: "/weapons/:id/edit", + errorElement: (), element: (), }, + { + path: "/weapons/:id", + element: (), + }, // auth { @@ -69,7 +70,14 @@ function App() { const [authCookie, ] = useCookies(['X-AUTH-TOKEN']); const [auth, setAuth] = useState(null); useEffect(() => { - GetUserInfo(authCookie['X-AUTH-TOKEN']).then(v => setAuth(v)); + GetUserInfo(authCookie['X-AUTH-TOKEN']).then( + v => { + console.log(v); + if (!v || v == undefined) + document.cookie = "X-AUTH-TOKEN=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;"; + setAuth(v); + } + ); }, []); return ( diff --git a/front/src/Authentication/Models.ts b/front/src/Authentication/Models.ts index 1918b85..8d8c144 100644 --- a/front/src/Authentication/Models.ts +++ b/front/src/Authentication/Models.ts @@ -1,4 +1,5 @@ export type User = { Username: string, Role: "user" | "editor" + status?: string } diff --git a/front/src/Emelents/Topbar.tsx b/front/src/Emelents/Topbar.tsx index 284cbb9..8845bc8 100644 --- a/front/src/Emelents/Topbar.tsx +++ b/front/src/Emelents/Topbar.tsx @@ -8,7 +8,7 @@ const defaultPathName = 'index'; function Topbar() { var language = useContext(LanguageContext); var user = useContext(AuthContext); - let path = getTopbarElement(window.location.pathname); + var path = getTopbarElement(window.location.pathname); function getTopText() { if (user == null) { diff --git a/front/src/ErrorHandler.tsx b/front/src/ErrorHandler.tsx index 177a9d0..9b0c5c7 100644 --- a/front/src/ErrorHandler.tsx +++ b/front/src/ErrorHandler.tsx @@ -28,8 +28,8 @@ function ErrorHandler() { function forbid(language: AllowedLanguages) { return (
-

{ GetLocalizedString("Forbidden", language) }

-

{ GetLocalizedString("*forbidden*", language) }

+

{ GetLocalizedString("Forbidden", language) }

+

{ GetLocalizedString("*forbidden*", language) }

); } diff --git a/front/src/Pages/RangedWeapon.tsx b/front/src/Pages/RangedWeapon.tsx index fa61644..5b66fad 100644 --- a/front/src/Pages/RangedWeapon.tsx +++ b/front/src/Pages/RangedWeapon.tsx @@ -1,17 +1,19 @@ -import { useContext, useState } from "react"; +import { useContext, useEffect, useState } from "react"; import { AllowedLanguages, LanguageContext } from "../Locales/Context"; import { BackendURL } from "../Config"; import axios from "axios"; -import { RangedWeapon } from "../Models/RangedWeapon"; +import { RangedWeapon, RangedWeaponRequest } from "../Models/RangedWeapon"; import { Description } from "../Models/Description"; -import { useParams } from "react-router"; +import { useNavigate, useParams } from "react-router"; import { GetLocalizedString } from "../Locales/Locales"; import "./Weapons.css" import { AuthContext } from "../Authentication/ContextProvider"; +import { useCookies } from 'react-cookie'; const RangedWeaponsURL = `${BackendURL}/weapons/ranged`; export function RangedWeaponPage() { + var user = useContext(AuthContext); const { id } = useParams(); const lang = useContext(LanguageContext); const [weapon, setWeapon] = useState(null); @@ -26,6 +28,14 @@ export function RangedWeaponPage() { return

Not found

; // ; } + function editButton() { + if (!user || user.Role != "editor") { + return (

); + } else { + return ( Edit ); + } + } + return (

{weapon?.Name}

@@ -70,15 +80,15 @@ export function RangedWeaponPage() {

{description?.Contents}

+ { editButton() }
); } - -async function getWeapon(id: string | undefined): Promise { +async function getWeaponDescription(id: string | undefined, lanuage: AllowedLanguages): Promise { if (id == undefined) return null; try { - const {data, status} = await axios.get( - `${RangedWeaponsURL}/${id}`, + const {data, status} = await axios.get( + `${RangedWeaponsURL}/${id}/description?lang=${lanuage}`, { headers: { Accept: "application/json" } } @@ -94,11 +104,276 @@ async function getWeapon(id: string | undefined): Promise } } -async function getWeaponDescription(id: string | undefined, lanuage: AllowedLanguages): Promise { +const defaultNewRangedWeapon: RangedWeapon = { + Id: "", + Name: "", + WeaponType: "Light pistol", + Accuracy: 0, + Concealability: "Pocket", + Avaliability: "Common", + Damage: "1d6", + Ammunition: "9mm", + NumberOfShots: 0, + RateOfFire: 0, + Reliability: "Standard", + Origin: "Corebook", + CreatedAt: 0, + UpdatedAt: 0, +} + +export function EditRangedWeaponPage() { + var user = useContext(AuthContext); + const [isLoading, setIsLoading] = useState(true); + const { id } = useParams(); + const lang = useContext(LanguageContext); + var [weapon, setWeapon] = useState(null); + const [description, setDescription] = useState(null); + const [authCookie, ] = useCookies(['X-AUTH-TOKEN']); + + const [Name, setName] = useState(); + const [WeaponType, setWeaponType] = useState(); + const [Accuracy, setAccuracy] = useState(); + const [Concealability, setConcealability] = useState(); + const [Avaliability, setAvaliability] = useState(); + const [Damage, setDamage] = useState(); + const [Ammunition, setAmmunition] = useState(); + const [NumberOfShots, setNumberOfShots] = useState(); + const [RateOfFire, setRateOfFire] = useState(); + const [Reliability, setReliability] = useState(); + const [Origin, setOrigin] = useState(); + const navigate = useNavigate(); + + useState(() => { + if (id == 'new') { + setWeapon(defaultNewRangedWeapon); + return + } + getWeapon(id).then(data => setWeapon(data)); + getWeaponDescription(id, lang).then(data => setDescription(data)); + }); + + useEffect(() => { + if (user !== null) { + setIsLoading(false); + } + }, [user]); + + useEffect(() => { + if (weapon) { + setName(weapon.Name); + setWeaponType(weapon.WeaponType); + setAccuracy(weapon.Accuracy); + setConcealability(weapon.Concealability); + setAvaliability(weapon.Avaliability); + setDamage(weapon.Damage); + setAmmunition(weapon.Ammunition); + setNumberOfShots(weapon.NumberOfShots); + setRateOfFire(weapon.RateOfFire); + setReliability(weapon.Reliability); + setOrigin(weapon.Origin); + } + }, [weapon]); + + function getUpdatedWeapon(): RangedWeaponRequest { + var outp: RangedWeaponRequest = { + Id: id || "", + Name: Name || "", + WeaponType: WeaponType || "", + Accuracy: Accuracy || 0, + Concealability: Concealability || "", + Avaliability: Avaliability || "", + Damage: Damage || "", + Ammunition: Ammunition || "", + NumberOfShots: NumberOfShots || 0, + RateOfFire: RateOfFire || 0, + Reliability: Reliability || "", + Origin: Origin || "", + }; + return outp; + } + + if (isLoading) { + return
Loading...
; + } + + if (!user || user.Role != "editor") { + throw new Response("Forbidden", { status: 403 }); + } + + if (weapon == null) { + return

Not found

; // ; + } + + return ( +
+ + { + setName(val.target.value); + }} /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
{ GetLocalizedString("Accuracy", lang) } + { + setAccuracy(+val.target.value); + }} /> +
{ GetLocalizedString("Concealability", lang) } + +
{ GetLocalizedString("Avaliability", lang) } + +
{ GetLocalizedString("Damage/Ammunition", lang) } + { + setDamage(val.target.value); + }}/> ( + { + setAmmunition(val.target.value); + }}/> + ) +
{ GetLocalizedString("Number Of Shots", lang) } + { + setNumberOfShots(+val.target.value); + }} /> +
{ GetLocalizedString("Rate Of Fire", lang) } + { + setRateOfFire(+val.target.value); + }} /> +
{ GetLocalizedString("Reliability", lang) } + +
{ GetLocalizedString("Origin", lang) } + +
+ + + + +

+ {description?.Contents} +

+
+ ); +} + +async function getWeapon(id: string | undefined): Promise { if (id == undefined) return null; try { - const {data, status} = await axios.get( - `${RangedWeaponsURL}/${id}/description?lang=${lanuage}`, + const {data, status} = await axios.get( + `${RangedWeaponsURL}/${id}`, { headers: { Accept: "application/json" } } @@ -114,14 +389,64 @@ async function getWeaponDescription(id: string | undefined, lanuage: AllowedLang } } -export function EditRangedWeaponPage() { - var user = useContext(AuthContext); +async function UpdateRangedWeapon(id: string | undefined, model: RangedWeaponRequest, token: string) { + if (id == undefined) return null; + const uri = `${RangedWeaponsURL}/${id}`; - if (user == null || user.Role != "editor") { + await axios.put(uri, model, { + headers: { + Authorization: `Bearer ${token}` + } + }) + .then(resp => { + console.log(resp); + }) + .catch(err => { + console.log(`Failed to update the model: ${err}`) + }); +} + +function generateId(Name: string): string { + return Name.toLowerCase().replaceAll(' ', '_'); +} + +async function CreateRangedWeapon(model: RangedWeaponRequest, token: string) { + if (model.Name.length == 0) { + throw new Error('The model name should not be empty'); + } + model.Id = generateId(model.Name); + if (model.Id == "new") { + throw new Error("Forbidden name"); } - return ( -
-
- ); + await axios.post(RangedWeaponsURL, model, { + headers: { + Authorization: `Bearer ${token}` + } + }) + .then(resp => { + console.log(resp); + }) + .catch(err => { + console.log(`Failed to create the model: ${err}`) + }); +} + +async function DeleteRangedWeapon(id: string | undefined, token: string) { + if (id == undefined || id == "new" || id.length < 1) { + throw new Error("Invalid ID"); + } + + const uri = `${RangedWeaponsURL}/${id}`; + await axios.delete(uri, { + headers: { + Authorization: `Bearer ${token}` + } + }) + .then(resp => { + console.log(resp); + }) + .catch(err => { + console.log(`Failed to create the model: ${err}`) + }); } diff --git a/front/src/Pages/Weapons.css b/front/src/Pages/Weapons.css index 41d820c..7f29770 100644 --- a/front/src/Pages/Weapons.css +++ b/front/src/Pages/Weapons.css @@ -23,3 +23,7 @@ td { .WeaponPage > span { display: flex; } + +.DmgInput { + max-width: 40%; +} diff --git a/front/src/Pages/Weapons.tsx b/front/src/Pages/Weapons.tsx index 1b72f16..d083ebf 100644 --- a/front/src/Pages/Weapons.tsx +++ b/front/src/Pages/Weapons.tsx @@ -5,11 +5,14 @@ import { LanguageContext } from "../Locales/Context"; import { GetLocalizedString } from "../Locales/Locales"; import { AllowedLanguages } from "../Locales/Context"; import { RangedWeapon } from "../Models/RangedWeapon"; +import { AuthContext } from "../Authentication/ContextProvider"; +import { User } from "../Authentication/Models"; const RangedWeaponsURL = `${BackendURL}/weapons/ranged`; function WeaponsIndex() { const lang = useContext(LanguageContext); + var user = useContext(AuthContext); const [rangedWeapons, setRangedWeapons] = useState(null); useState(() => { @@ -22,7 +25,8 @@ function WeaponsIndex() {

{GetLocalizedString("Weapons index", lang)}

{GetLocalizedString("Ranged weapons", lang)}

- {generatedRangedWeaponsList(rangedWeapons, lang)} + { generatedRangedWeaponsList(rangedWeapons, lang) } + { adminButtons(user) } ); } @@ -109,4 +113,16 @@ async function getRangedWeapons(): Promise { } } +function adminButtons(user: User | null) { + if (!user || user.Role != "editor") { + return (

); + } else { + return ( + + ) + } +} + export default WeaponsIndex; -- cgit v1.3