diff options
| author | Arda Serdar Pektezol <1669855+pektezol@users.noreply.github.com> | 2025-07-24 14:40:22 +0300 |
|---|---|---|
| committer | Arda Serdar Pektezol <1669855+pektezol@users.noreply.github.com> | 2025-07-24 14:40:22 +0300 |
| commit | b0d199936b546c75d4b19d99591237f0bf97fe55 (patch) | |
| tree | e9391880e7db2bd1ea8ff25d91aeea8dd98f186e /frontend/src/components/UploadRunDialog.tsx | |
| parent | fix/frontend: fixed sidebar title size, removed unnecessary imports (diff) | |
| parent | feat/backend: add newrelic integration (#274) (diff) | |
| download | lphub-css-overhaul.tar.gz lphub-css-overhaul.tar.bz2 lphub-css-overhaul.zip | |
Merge branch 'main' into css-overhaulcss-overhaul
Diffstat (limited to 'frontend/src/components/UploadRunDialog.tsx')
| -rw-r--r-- | frontend/src/components/UploadRunDialog.tsx | 106 |
1 files changed, 47 insertions, 59 deletions
diff --git a/frontend/src/components/UploadRunDialog.tsx b/frontend/src/components/UploadRunDialog.tsx index 951944b..971a747 100644 --- a/frontend/src/components/UploadRunDialog.tsx +++ b/frontend/src/components/UploadRunDialog.tsx | |||
| @@ -5,12 +5,12 @@ import { ScoreboardTempUpdate, SourceDemoParser, NetMessages } from '@nekz/sdp'; | |||
| 5 | import btn from "@css/Button.module.css"; | 5 | import btn from "@css/Button.module.css"; |
| 6 | import '@css/UploadRunDialog.css'; | 6 | import '@css/UploadRunDialog.css'; |
| 7 | import { Game } from '@customTypes/Game'; | 7 | import { Game } from '@customTypes/Game'; |
| 8 | import { Map } from '@customTypes/Map'; | ||
| 9 | import { API } from '@api/Api'; | 8 | import { API } from '@api/Api'; |
| 10 | import { useNavigate } from 'react-router-dom'; | 9 | import { useNavigate } from 'react-router-dom'; |
| 11 | import useMessage from '@hooks/UseMessage'; | 10 | import useMessage from '@hooks/UseMessage'; |
| 12 | import useConfirm from '@hooks/UseConfirm'; | 11 | import useConfirm from '@hooks/UseConfirm'; |
| 13 | import useMessageLoad from "@hooks/UseMessageLoad"; | 12 | import useMessageLoad from "@hooks/UseMessageLoad"; |
| 13 | import { MapNames } from '@customTypes/MapNames'; | ||
| 14 | 14 | ||
| 15 | interface UploadRunDialogProps { | 15 | interface UploadRunDialogProps { |
| 16 | token?: string; | 16 | token?: string; |
| @@ -28,19 +28,11 @@ const UploadRunDialog: React.FC<UploadRunDialogProps> = ({ token, open, onClose, | |||
| 28 | const navigate = useNavigate(); | 28 | const navigate = useNavigate(); |
| 29 | 29 | ||
| 30 | const [uploadRunContent, setUploadRunContent] = React.useState<UploadRunContent>({ | 30 | const [uploadRunContent, setUploadRunContent] = React.useState<UploadRunContent>({ |
| 31 | map_id: 0, | ||
| 32 | host_demo: null, | 31 | host_demo: null, |
| 33 | partner_demo: null, | 32 | partner_demo: null, |
| 34 | }); | 33 | }); |
| 35 | 34 | ||
| 36 | const [currentMap, setCurrentMap] = React.useState<string>(""); | ||
| 37 | |||
| 38 | const _set_current_map = (game_name: string) => { | ||
| 39 | setCurrentMap(game_name); | ||
| 40 | } | ||
| 41 | |||
| 42 | const [selectedGameID, setSelectedGameID] = React.useState<number>(0); | 35 | const [selectedGameID, setSelectedGameID] = React.useState<number>(0); |
| 43 | const [selectedGameMaps, setSelectedGameMaps] = React.useState<Map[]>([]); | ||
| 44 | const [selectedGameName, setSelectedGameName] = React.useState<string>(""); | 36 | const [selectedGameName, setSelectedGameName] = React.useState<string>(""); |
| 45 | 37 | ||
| 46 | // dropdowns | 38 | // dropdowns |
| @@ -51,6 +43,7 @@ const UploadRunDialog: React.FC<UploadRunDialogProps> = ({ token, open, onClose, | |||
| 51 | 43 | ||
| 52 | const [dragHightlight, setDragHighlight] = React.useState<boolean>(false); | 44 | const [dragHightlight, setDragHighlight] = React.useState<boolean>(false); |
| 53 | const [dragHightlightPartner, setDragHighlightPartner] = React.useState<boolean>(false); | 45 | const [dragHightlightPartner, setDragHighlightPartner] = React.useState<boolean>(false); |
| 46 | |||
| 54 | const fileInputRef = React.useRef<HTMLInputElement>(null); | 47 | const fileInputRef = React.useRef<HTMLInputElement>(null); |
| 55 | const fileInputRefPartner = React.useRef<HTMLInputElement>(null); | 48 | const fileInputRefPartner = React.useRef<HTMLInputElement>(null); |
| 56 | 49 | ||
| @@ -103,14 +96,6 @@ const UploadRunDialog: React.FC<UploadRunDialogProps> = ({ token, open, onClose, | |||
| 103 | 96 | ||
| 104 | const _handle_game_select = async (game_id: string, game_name: string) => { | 97 | const _handle_game_select = async (game_id: string, game_name: string) => { |
| 105 | setLoading(true); | 98 | setLoading(true); |
| 106 | const gameMaps = await API.get_game_maps(game_id); | ||
| 107 | setSelectedGameMaps(gameMaps); | ||
| 108 | setUploadRunContent({ | ||
| 109 | map_id: gameMaps.find((map) => !map.is_disabled)!.id, //gameMaps[0].id, | ||
| 110 | host_demo: null, | ||
| 111 | partner_demo: null, | ||
| 112 | }); | ||
| 113 | _set_current_map(gameMaps.find((map) => !map.is_disabled)!.name); | ||
| 114 | setSelectedGameID(parseInt(game_id) - 1); | 99 | setSelectedGameID(parseInt(game_id) - 1); |
| 115 | setSelectedGameName(game_name); | 100 | setSelectedGameName(game_name); |
| 116 | setLoading(false); | 101 | setLoading(false); |
| @@ -159,6 +144,20 @@ const UploadRunDialog: React.FC<UploadRunDialogProps> = ({ token, open, onClose, | |||
| 159 | await message("Error", "Error while processing demo: Unable to get scoreboard result. Either there is a demo that is corrupt or haven't been recorded in challenge mode.") | 144 | await message("Error", "Error while processing demo: Unable to get scoreboard result. Either there is a demo that is corrupt or haven't been recorded in challenge mode.") |
| 160 | return | 145 | return |
| 161 | } | 146 | } |
| 147 | |||
| 148 | if (!demo.mapName || !MapNames[demo.mapName]) { | ||
| 149 | await message("Error", "Error while processing demo: Invalid map name.") | ||
| 150 | return | ||
| 151 | } | ||
| 152 | |||
| 153 | if (selectedGameID === 0 && MapNames[demo.mapName] > 60) { | ||
| 154 | await message("Error", "Error while processing demo: Invalid cooperative demo in singleplayer submission.") | ||
| 155 | return | ||
| 156 | } else if (selectedGameID === 1 && MapNames[demo.mapName] <= 60) { | ||
| 157 | await message("Error", "Error while processing demo: Invalid singleplayer demo in cooperative submission.") | ||
| 158 | return | ||
| 159 | } | ||
| 160 | |||
| 162 | const { portalScore, timeScore } = scoreboard.userMessage?.as<ScoreboardTempUpdate>() ?? {}; | 161 | const { portalScore, timeScore } = scoreboard.userMessage?.as<ScoreboardTempUpdate>() ?? {}; |
| 163 | 162 | ||
| 164 | const userConfirmed = await confirm("Upload Record", `Map Name: ${demo.mapName}\nPortal Count: ${portalScore}\nTicks: ${timeScore}\n\nAre you sure you want to upload this demo?`); | 163 | const userConfirmed = await confirm("Upload Record", `Map Name: ${demo.mapName}\nPortal Count: ${portalScore}\nTicks: ${timeScore}\n\nAre you sure you want to upload this demo?`); |
| @@ -168,10 +167,14 @@ const UploadRunDialog: React.FC<UploadRunDialogProps> = ({ token, open, onClose, | |||
| 168 | } | 167 | } |
| 169 | 168 | ||
| 170 | messageLoad("Uploading..."); | 169 | messageLoad("Uploading..."); |
| 171 | const [success, response] = await API.post_record(token, uploadRunContent); | 170 | const [success, response] = await API.post_record(token, uploadRunContent, MapNames[demo.mapName]); |
| 172 | messageLoadClose(); | 171 | messageLoadClose(); |
| 173 | await message("Upload Record", response); | 172 | await message("Upload Record", response); |
| 174 | if (success) { | 173 | if (success) { |
| 174 | setUploadRunContent({ | ||
| 175 | host_demo: null, | ||
| 176 | partner_demo: null, | ||
| 177 | }); | ||
| 175 | onClose(success); | 178 | onClose(success); |
| 176 | navigate("/profile"); | 179 | navigate("/profile"); |
| 177 | } | 180 | } |
| @@ -180,7 +183,6 @@ const UploadRunDialog: React.FC<UploadRunDialogProps> = ({ token, open, onClose, | |||
| 180 | 183 | ||
| 181 | React.useEffect(() => { | 184 | React.useEffect(() => { |
| 182 | if (open) { | 185 | if (open) { |
| 183 | |||
| 184 | setDragHighlightPartner(false); | 186 | setDragHighlightPartner(false); |
| 185 | setDragHighlight(false); | 187 | setDragHighlight(false); |
| 186 | _handle_game_select("1", "Portal 2 - Singleplayer"); // a different approach?. | 188 | _handle_game_select("1", "Portal 2 - Singleplayer"); // a different approach?. |
| @@ -204,37 +206,20 @@ const UploadRunDialog: React.FC<UploadRunDialogProps> = ({ token, open, onClose, | |||
| 204 | <div className='dropdown-cur'>{selectedGameName}</div> | 206 | <div className='dropdown-cur'>{selectedGameName}</div> |
| 205 | <i style={{ rotate: "-90deg", transform: "translate(-5px, 10px)" }} className="triangle"></i> | 207 | <i style={{ rotate: "-90deg", transform: "translate(-5px, 10px)" }} className="triangle"></i> |
| 206 | </div> | 208 | </div> |
| 207 | <div style={{top: "110px"}} className={dropdown1Vis ? "upload-run-dropdown" : "upload-run-dropdown hidden"}> | 209 | <div style={{ top: "110px" }} className={dropdown1Vis ? "upload-run-dropdown" : "upload-run-dropdown hidden"}> |
| 208 | {games.map((game) => ( | 210 | {games.map((game) => ( |
| 209 | <div onClick={() => { _handle_game_select(game.id.toString(), game.name); _handle_dropdowns(1) }} key={game.id}>{game.name}</div> | 211 | <div onClick={() => { _handle_game_select(game.id.toString(), game.name); _handle_dropdowns(1) }} key={game.id}>{game.name}</div> |
| 210 | ))} | 212 | ))} |
| 211 | </div> | 213 | </div> |
| 212 | {!loading && ( | 214 | </div> |
| 213 | <> | ||
| 214 | <div style={{ padding: "25px 0px" }}> | ||
| 215 | <h3 style={{ margin: "0px 0px" }}>Select Map</h3> | ||
| 216 | <div onClick={() => _handle_dropdowns(2)} style={{ display: "flex", alignItems: "center", cursor: "pointer", justifyContent: "space-between", margin: "10px 0px" }}> | ||
| 217 | <span style={{ userSelect: "none" }}>{currentMap}</span> | ||
| 218 | <i style={{ rotate: "-90deg", transform: "translate(-5px, 10px)" }} className="triangle"></i> | ||
| 219 | </div> | ||
| 220 | </div> | ||
| 221 | <div style={{top: "220px"}} id='dropdown2' className={dropdown2Vis ? "upload-run-dropdown" : "upload-run-dropdown hidden"}> | ||
| 222 | {selectedGameMaps && selectedGameMaps.filter(gameMap => !gameMap.is_disabled).map((gameMap) => ( | ||
| 223 | <div onClick={() => { setUploadRunContent({ ...uploadRunContent, map_id: gameMap.id }); _set_current_map(gameMap.name); _handle_dropdowns(2); }} key={gameMap.id}>{gameMap.name}</div> | ||
| 224 | ))} | ||
| 225 | </div> | ||
| 226 | </> | ||
| 227 | |||
| 228 | )} | ||
| 229 | </div> | ||
| 230 | 215 | ||
| 231 | { | 216 | { |
| 232 | !loading && | 217 | !loading && |
| 233 | ( | 218 | ( |
| 234 | <> | 219 | <> |
| 235 | 220 | ||
| 236 | <div> | 221 | <div> |
| 237 | <h3 style={{margin: "10px 0px"}}>Host Demo</h3> | 222 | <h3 style={{ margin: "10px 0px" }}>Host Demo</h3> |
| 238 | <div onClick={() => { _handle_file_click(true) }} onDragOver={(e) => { _handle_drag_over(e, true) }} onDrop={(e) => { _handle_drop(e, true) }} onDragLeave={(e) => { _handle_drag_leave(e, true) }} className={`upload-run-drag-area ${dragHightlight ? "upload-run-drag-area-highlight" : ""} ${uploadRunContent.host_demo ? "upload-run-drag-area-hidden" : ""}`}> | 223 | <div onClick={() => { _handle_file_click(true) }} onDragOver={(e) => { _handle_drag_over(e, true) }} onDrop={(e) => { _handle_drop(e, true) }} onDragLeave={(e) => { _handle_drag_leave(e, true) }} className={`upload-run-drag-area ${dragHightlight ? "upload-run-drag-area-highlight" : ""} ${uploadRunContent.host_demo ? "upload-run-drag-area-hidden" : ""}`}> |
| 239 | <input ref={fileInputRef} type="file" name="host_demo" id="host_demo" accept=".dem" onChange={(e) => _handle_file_change(e.target.files, true)} /> | 224 | <input ref={fileInputRef} type="file" name="host_demo" id="host_demo" accept=".dem" onChange={(e) => _handle_file_change(e.target.files, true)} /> |
| 240 | {!uploadRunContent.host_demo ? | 225 | {!uploadRunContent.host_demo ? |
| @@ -253,38 +238,41 @@ const UploadRunDialog: React.FC<UploadRunDialogProps> = ({ token, open, onClose, | |||
| 253 | games[selectedGameID].is_coop && | 238 | games[selectedGameID].is_coop && |
| 254 | ( | 239 | ( |
| 255 | <> | 240 | <> |
| 256 | <div> | 241 | <div> |
| 257 | <h3 style={{margin: "10px 0px"}}>Partner Demo</h3> | 242 | <h3 style={{ margin: "10px 0px" }}>Partner Demo</h3> |
| 258 | <div onClick={() => { _handle_file_click(false) }} onDragOver={(e) => { _handle_drag_over(e, false) }} onDrop={(e) => { _handle_drop(e, false) }} onDragLeave={(e) => { _handle_drag_leave(e, false) }} className={`upload-run-drag-area ${dragHightlightPartner ? "upload-run-drag-area-highlight-partner" : ""} ${uploadRunContent.partner_demo ? "upload-run-drag-area-hidden" : ""}`}> | 243 | <div onClick={() => { _handle_file_click(false) }} onDragOver={(e) => { _handle_drag_over(e, false) }} onDrop={(e) => { _handle_drop(e, false) }} onDragLeave={(e) => { _handle_drag_leave(e, false) }} className={`upload-run-drag-area ${dragHightlightPartner ? "upload-run-drag-area-highlight-partner" : ""} ${uploadRunContent.partner_demo ? "upload-run-drag-area-hidden" : ""}`}> |
| 259 | <input ref={fileInputRefPartner} type="file" name="partner_demo" id="partner_demo" accept=".dem" onChange={(e) => _handle_file_change(e.target.files, false)} /> {!uploadRunContent.partner_demo ? | 244 | <input ref={fileInputRefPartner} type="file" name="partner_demo" id="partner_demo" accept=".dem" onChange={(e) => _handle_file_change(e.target.files, false)} /> {!uploadRunContent.partner_demo ? |
| 260 | <div> | ||
| 261 | <span>Drag and drop</span> | ||
| 262 | <div> | 245 | <div> |
| 263 | <span style={{ fontFamily: "BarlowSemiCondensed-Regular" }}>Or click here</span><br /> | 246 | <span style={{ fontFamily: "BarlowSemiCondensed-Regular" }}>Or click here</span><br /> |
| 264 | <button className={btn.default}>Upload</button> | 247 | <button className={btn.default}>Upload</button> |
| 265 | </div> | 248 | </div> |
| 266 | </div> | 249 | : null} |
| 267 | : null} | ||
| 268 | 250 | ||
| 269 | <span className="upload-run-demo-name">{uploadRunContent.partner_demo?.name}</span> | 251 | <span className="upload-run-demo-name">{uploadRunContent.partner_demo?.name}</span> |
| 252 | </div> | ||
| 270 | </div> | 253 | </div> |
| 271 | </div> | ||
| 272 | </> | 254 | </> |
| 273 | ) | 255 | ) |
| 274 | } | 256 | } |
| 275 | </div> | 257 | </div> |
| 276 | <div className='search-container'> | 258 | <div className='search-container'> |
| 259 | |||
| 260 | </div> | ||
| 277 | 261 | ||
| 278 | </div> | ||
| 279 | |||
| 280 | </> | 262 | </> |
| 281 | ) | 263 | ) |
| 282 | } | 264 | } |
| 283 | </div> | 265 | </div> |
| 284 | <div className='upload-run-buttons-container'> | 266 | <div className='upload-run-buttons-container'> |
| 285 | <button className={`${btn.defaultWide}`} onClick={_upload_run}>Submit</button> | 267 | <button className={`${btn.defaultWide}`} onClick={_upload_run}>Submit</button> |
| 286 | <button className={`${btn.defaultWide}`} onClick={() => onClose(false)}>Cancel</button> | 268 | <button className={`${btn.defaultWide}`} onClick={() => { |
| 287 | </div> | 269 | onClose(false); |
| 270 | setUploadRunContent({ | ||
| 271 | host_demo: null, | ||
| 272 | partner_demo: null, | ||
| 273 | }); | ||
| 274 | }}>Cancel</button> | ||
| 275 | </div> | ||
| 288 | </div> | 276 | </div> |
| 289 | </div> | 277 | </div> |
| 290 | </> | 278 | </> |