From 4cf7889db937a38209143dcd243126a4db04fea6 Mon Sep 17 00:00:00 2001 From: Quaternions <krakow20@gmail.com> Date: Tue, 1 Apr 2025 14:58:58 -0700 Subject: [PATCH] web: add submit page at /maps/[mapId]/fix --- .../app/maps/[mapId]/fix/(styles)/page.scss | 54 ++++++++++ web/src/app/maps/[mapId]/fix/_game.tsx | 65 ++++++++++++ web/src/app/maps/[mapId]/fix/page.tsx | 98 +++++++++++++++++++ 3 files changed, 217 insertions(+) create mode 100644 web/src/app/maps/[mapId]/fix/(styles)/page.scss create mode 100644 web/src/app/maps/[mapId]/fix/_game.tsx create mode 100644 web/src/app/maps/[mapId]/fix/page.tsx diff --git a/web/src/app/maps/[mapId]/fix/(styles)/page.scss b/web/src/app/maps/[mapId]/fix/(styles)/page.scss new file mode 100644 index 0000000..8c7dcf8 --- /dev/null +++ b/web/src/app/maps/[mapId]/fix/(styles)/page.scss @@ -0,0 +1,54 @@ +@use "../../../../globals.scss"; + +::placeholder { + color: var(--placeholder-text) +} + +.form-spacer { + margin-bottom: 20px; + + &:last-of-type { + margin-top: 15px; + } +} + +#target-asset-radio { + color: var(--text-color); + font-size: globals.$form-label-fontsize; +} + +.form-field { + width: 850px; + + & label, & input { + color: var(--text-color); + } + & fieldset { + border-color: rgb(100,100,100); + } + & span { + color: white; + } +} + +main { + display: grid; + justify-content: center; + align-items: center; + margin-inline: auto; + width: 700px; +} + +header h1 { + text-align: center; + color: var(--text-color); +} + +form { + display: grid; + gap: 25px; + + fieldset { + border: blue + } +} diff --git a/web/src/app/maps/[mapId]/fix/_game.tsx b/web/src/app/maps/[mapId]/fix/_game.tsx new file mode 100644 index 0000000..e754601 --- /dev/null +++ b/web/src/app/maps/[mapId]/fix/_game.tsx @@ -0,0 +1,65 @@ +import { FormControl, Select, InputLabel, MenuItem } from "@mui/material"; +import { styled } from '@mui/material/styles'; +import InputBase from '@mui/material/InputBase'; +import React from "react"; +import { SelectChangeEvent } from "@mui/material"; + +// TODO: Properly style everything instead of pasting 🤚 + +type GameSelectionProps = { + game: number; + setGame: React.Dispatch<React.SetStateAction<number>>; +}; + +const BootstrapInput = styled(InputBase)(({ theme }) => ({ + 'label + &': { + marginTop: theme.spacing(3), + }, + '& .MuiInputBase-input': { + backgroundColor: '#0000', + color: '#FFF', + border: '1px solid rgba(175, 175, 175, 0.66)', + fontSize: 16, + padding: '10px 26px 10px 12px', + transition: theme.transitions.create(['border-color', 'box-shadow']), + fontFamily: [ + '-apple-system', + 'BlinkMacSystemFont', + '"Segoe UI"', + 'Roboto', + '"Helvetica Neue"', + 'Arial', + 'sans-serif', + '"Apple Color Emoji"', + '"Segoe UI Emoji"', + '"Segoe UI Symbol"', + ].join(','), + '&:focus': { + borderRadius: 4, + borderColor: '#80bdff', + boxShadow: '0 0 0 0.2rem rgba(0,123,255,.25)', + }, + }, + })); + +export default function GameSelection({ game, setGame }: GameSelectionProps) { + const handleChange = (event: SelectChangeEvent) => { + setGame(Number(event.target.value)); // TODO: Change later!! there's 100% a proper way of doing this + }; + + return ( + <FormControl> + <InputLabel sx={{ color: "#646464" }}>Game</InputLabel> + <Select + value={String(game)} + label="Game" + onChange={handleChange} + input={<BootstrapInput />} + > + <MenuItem value={1}>Bhop</MenuItem> + <MenuItem value={2}>Surf</MenuItem> + <MenuItem value={3}>Fly Trials</MenuItem> + </Select> + </FormControl> + ); +} \ No newline at end of file diff --git a/web/src/app/maps/[mapId]/fix/page.tsx b/web/src/app/maps/[mapId]/fix/page.tsx new file mode 100644 index 0000000..5e68374 --- /dev/null +++ b/web/src/app/maps/[mapId]/fix/page.tsx @@ -0,0 +1,98 @@ +"use client" + +import { Button, TextField } from "@mui/material" + +import GameSelection from "./_game"; +import SendIcon from '@mui/icons-material/Send'; +import Webpage from "@/app/_components/webpage"; +import { useParams } from "next/navigation"; +import React, { useState } from "react"; + +import "./(styles)/page.scss" + +interface MapfixPayload { + DisplayName: string; + Creator: string; + GameID: number; + AssetID: number; + AssetVersion: number; + TargetAssetID: number; +} +interface IdResponse { + ID: number; +} + +export default function MapfixInfoPage() { + const [game, setGame] = useState(1); + const dynamicId = useParams<{ mapId: string }>(); + + const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => { + event.preventDefault(); + + const form = event.currentTarget; + const formData = new FormData(form); + + const payload: MapfixPayload = { + DisplayName: (formData.get("display-name") as string) ?? "unknown", // TEMPORARY! TODO: Change + Creator: (formData.get("creator") as string) ?? "unknown", // TEMPORARY! TODO: Change + GameID: game, + AssetID: Number((formData.get("asset-id") as string) ?? "0"), + AssetVersion: 0, + TargetAssetID: Number(dynamicId.mapId), + }; + + console.log(payload) + console.log(JSON.stringify(payload)) + + try { + // Send the POST request + const response = await fetch("/api/mapfixes", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(payload), + }); + + // Check if the HTTP request was successful + if (!response.ok) { + const errorDetails = await response.text(); + + // Throw an error with detailed information + throw new Error(`HTTP error! status: ${response.status}, details: ${errorDetails}`); + } + + // Allow any HTTP status + const id_response:IdResponse = await response.json(); + + // navigate to newly created mapfix + window.location.assign(`/mapfixes/${id_response.ID}`) + + } catch (error) { + console.error("Error submitting data:", error); + } + }; + + return ( + <Webpage> + <main> + <header> + <h1>Submit Mapfix</h1> + <span className="spacer form-spacer"></span> + </header> + <form onSubmit={handleSubmit}> + {/* TODO: Add form data for mapfixes, such as changes they did, and any times that need to be deleted & what styles */} + <TextField className="form-field" id="display-name" name="display-name" label="Display Name" variant="outlined"/> + <TextField className="form-field" id="creator" name="creator" label="Creator" variant="outlined"/> + <TextField className="form-field" id="asset-id" name="asset-id" label="Asset ID" variant="outlined"/> + {/* I think this is Quat's job to figure this one out (to be set when someone clicks review(?)) */} {/* <TextField className="form-field" id="asset-version" label="Asset Version" variant="outlined"/> */} + <GameSelection game={game} setGame={setGame} /> + <span className="spacer form-spacer"></span> + <Button type="submit" variant="contained" startIcon={<SendIcon/>} sx={{ + width: "400px", + height: "50px", + marginInline: "auto" + }}>Submit</Button> + </form> + </main> + </Webpage> + ) +}