import React from 'react'; import { UploadRunContent } from '@customTypes/Content'; import { ScoreboardTempUpdate, SourceDemoParser, NetMessages } from '@nekz/sdp'; import btn from "@css/Button.module.css"; import '@css/UploadRunDialog.css'; import { Game } from '@customTypes/Game'; import { Map } from '@customTypes/Map'; import { API } from '@api/Api'; import { useNavigate } from 'react-router-dom'; import useMessage from '@hooks/UseMessage'; import useConfirm from '@hooks/UseConfirm'; import useMessageLoad from "@hooks/UseMessageLoad"; interface UploadRunDialogProps { token?: string; open: boolean; onClose: (updateProfile: boolean) => void; games: Game[]; } const UploadRunDialog: React.FC = ({ token, open, onClose, games }) => { const { message, MessageDialogComponent } = useMessage(); const { confirm, ConfirmDialogComponent } = useConfirm(); const { messageLoad, messageLoadClose, MessageDialogLoadComponent } = useMessageLoad(); const navigate = useNavigate(); const [uploadRunContent, setUploadRunContent] = React.useState({ map_id: 0, host_demo: null, partner_demo: null, }); const [currentMap, setCurrentMap] = React.useState(""); const _set_current_map = (game_name: string) => { setCurrentMap(game_name); } const [selectedGameID, setSelectedGameID] = React.useState(0); const [selectedGameMaps, setSelectedGameMaps] = React.useState([]); const [selectedGameName, setSelectedGameName] = React.useState(""); // dropdowns const [dropdown1Vis, setDropdown1Vis] = React.useState(false); const [dropdown2Vis, setDropdown2Vis] = React.useState(false); const [loading, setLoading] = React.useState(false); const [dragHightlight, setDragHighlight] = React.useState(false); const [dragHightlightPartner, setDragHighlightPartner] = React.useState(false); const fileInputRef = React.useRef(null); const fileInputRefPartner = React.useRef(null); const _handle_file_click = (host: boolean) => { if (host) { fileInputRef.current?.click(); } else { fileInputRefPartner.current?.click(); } } const _handle_drag_over = (e: React.DragEvent, host: boolean) => { e.preventDefault(); e.stopPropagation(); if (host) { setDragHighlight(true); } else { setDragHighlightPartner(true); } } const _handle_drag_leave = (e: React.DragEvent, host: boolean) => { e.preventDefault(); e.stopPropagation(); if (host) { setDragHighlight(false); } else { setDragHighlightPartner(false); } } const _handle_drop = (e: React.DragEvent, host: boolean) => { e.preventDefault(); e.stopPropagation(); setDragHighlight(true); _handle_file_change(e.dataTransfer.files, host); } const _handle_dropdowns = (dropdown: number) => { setDropdown1Vis(false); setDropdown2Vis(false); if (dropdown == 1) { setDropdown1Vis(!dropdown1Vis); } else if (dropdown == 2) { setDropdown2Vis(!dropdown2Vis); document.querySelector("#dropdown2")?.scrollTo(0, 0); } } const _handle_game_select = async (game_id: string, game_name: string) => { setLoading(true); const gameMaps = await API.get_game_maps(game_id); setSelectedGameMaps(gameMaps); setUploadRunContent({ map_id: gameMaps.find((map) => !map.is_disabled)!.id, //gameMaps[0].id, host_demo: null, partner_demo: null, }); _set_current_map(gameMaps.find((map) => !map.is_disabled)!.name); setSelectedGameID(parseInt(game_id) - 1); setSelectedGameName(game_name); setLoading(false); }; const _handle_file_change = async (files: FileList | null, host: boolean) => { if (files) { if (host) { setUploadRunContent({ ...uploadRunContent, host_demo: files[0], }); } else { setUploadRunContent({ ...uploadRunContent, partner_demo: files[0], }); } } }; const _upload_run = async () => { if (token) { if (games[selectedGameID].is_coop) { if (uploadRunContent.host_demo === null) { await message("Error", "You must select a host demo to upload.") return } else if (uploadRunContent.partner_demo === null) { await message("Error", "You must select a partner demo to upload.") return } } else { if (uploadRunContent.host_demo === null) { await message("Error", "You must select a demo to upload.") return } } const demo = SourceDemoParser.default() .setOptions({ packets: true, header: true }) .parse(await uploadRunContent.host_demo.arrayBuffer()); const scoreboard = demo.findPacket((msg) => { return msg instanceof NetMessages.SvcUserMessage && msg.userMessage instanceof ScoreboardTempUpdate; }) if (!scoreboard) { 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.") return } const { portalScore, timeScore } = scoreboard.userMessage?.as() ?? {}; 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?`); if (!userConfirmed) { return; } messageLoad("Uploading..."); const [success, response] = await API.post_record(token, uploadRunContent); messageLoadClose(); await message("Upload Record", response); if (success) { onClose(success); navigate("/profile"); } } }; React.useEffect(() => { if (open) { setDragHighlightPartner(false); setDragHighlight(false); _handle_game_select("1", "Portal 2 - Singleplayer"); // a different approach?. } }, [open]); if (open) { return ( <>
{MessageDialogComponent} {MessageDialogLoadComponent} {ConfirmDialogComponent}

Select Game

_handle_dropdowns(1)} style={{ display: "flex", alignItems: "center", cursor: "pointer", justifyContent: "space-between", margin: "10px 0px" }}>
{selectedGameName}
{games.map((game) => (
{ _handle_game_select(game.id.toString(), game.name); _handle_dropdowns(1) }} key={game.id}>{game.name}
))}
{!loading && ( <>

Select Map

_handle_dropdowns(2)} style={{ display: "flex", alignItems: "center", cursor: "pointer", justifyContent: "space-between", margin: "10px 0px" }}> {currentMap}
)}
{ !loading && ( <>

Host Demo

{ _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" : ""}`}> _handle_file_change(e.target.files, true)} /> {!uploadRunContent.host_demo ?
Drag and drop
Or click here
: null} {uploadRunContent.host_demo?.name}
{ games[selectedGameID].is_coop && ( <>

Partner Demo

{ _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" : ""}`}> _handle_file_change(e.target.files, false)} /> {!uploadRunContent.partner_demo ?
Drag and drop
Or click here
: null} {uploadRunContent.partner_demo?.name}
) }
) }
); } return ( <> ); }; export default UploadRunDialog;