From c04bc9a36ebfcdf6d8e2db8a6cdeb44062b66bec Mon Sep 17 00:00:00 2001 From: Wolfboy248 Date: Tue, 19 Aug 2025 13:23:17 +0200 Subject: organised pages, started work on theme --- frontend/src/pages/Profile/Profile.tsx | 633 +++++++++++++++++++++++++++++++++ 1 file changed, 633 insertions(+) create mode 100644 frontend/src/pages/Profile/Profile.tsx (limited to 'frontend/src/pages/Profile') diff --git a/frontend/src/pages/Profile/Profile.tsx b/frontend/src/pages/Profile/Profile.tsx new file mode 100644 index 0000000..9aac386 --- /dev/null +++ b/frontend/src/pages/Profile/Profile.tsx @@ -0,0 +1,633 @@ +import React from "react"; +import { Link, useNavigate } from "react-router-dom"; +import { Helmet } from "react-helmet"; + +import { + SteamIcon, + TwitchIcon, + YouTubeIcon, + PortalIcon, + FlagIcon, + StatisticsIcon, + SortIcon, + ThreedotIcon, + DownloadIcon, + HistoryIcon, + DeleteIcon, +} from "@images/Images"; +import { UserProfile } from "@customTypes/Profile.ts"; +import { Game, GameChapters } from "@customTypes/Game.ts"; +import { Map } from "@customTypes/Map.ts"; +import { ticks_to_time } from "@utils/Time.ts"; +import { API } from "@api/Api.ts"; +import useConfirm from "@hooks/UseConfirm.tsx"; +import useMessage from "@hooks/UseMessage.tsx"; +import useMessageLoad from "@hooks/UseMessageLoad.tsx"; + +interface ProfileProps { + profile?: UserProfile; + token?: string; + gameData: Game[]; + onDeleteRecord: () => void; +} + +const Profile: React.FC = ({ + profile, + token, + gameData, + onDeleteRecord, +}) => { + const { confirm, ConfirmDialogComponent } = useConfirm(); + const { message, MessageDialogComponent } = useMessage(); + const { messageLoad, messageLoadClose, MessageDialogLoadComponent } = + useMessageLoad(); + const [navState, setNavState] = React.useState(0); + const [pageNumber, setPageNumber] = React.useState(1); + const [pageMax, setPageMax] = React.useState(0); + + const [game, setGame] = React.useState("0"); + const [chapter, setChapter] = React.useState("0"); + const [chapterData, setChapterData] = React.useState( + null + ); + const [maps, setMaps] = React.useState([]); + + const navigate = useNavigate(); + + const _update_profile = () => { + if (token) { + API.post_profile(token).then(() => navigate(0)); + } + }; + + const _get_game_chapters = React.useCallback(async () => { + if (game && game !== "0") { + const gameChapters = await API.get_games_chapters(game); + setChapterData(gameChapters); + } else if (game && game === "0") { + setPageMax(Math.ceil(profile!.records.length / 20)); + setPageNumber(1); + } + }, [game, profile]); + + const _get_game_maps = React.useCallback(async () => { + if (chapter === "0") { + const gameMaps = await API.get_game_maps(game); + setMaps(gameMaps); + setPageMax(Math.ceil(gameMaps.length / 20)); + setPageNumber(1); + } else { + const gameChapters = await API.get_chapters(chapter); + setMaps(gameChapters.maps); + setPageMax(Math.ceil(gameChapters.maps.length / 20)); + setPageNumber(1); + } + }, [chapter, game]); + + const _delete_submission = async (map_id: number, record_id: number) => { + const userConfirmed = await confirm( + "Delete Record", + "Are you sure you want to delete this record?" + ); + + if (!userConfirmed) { + return; + } + + messageLoad("Deleting..."); + + const api_success = await API.delete_map_record(token!, map_id, record_id); + messageLoadClose(); + if (api_success) { + await message("Delete Record", "Successfully deleted record."); + onDeleteRecord(); + } else { + await message("Delete Record", "Could not delete record."); + } + }; + + React.useEffect(() => { + if (!profile) { + navigate("/"); + } + }, [profile, navigate]); + + React.useEffect(() => { + if (profile) { + _get_game_chapters(); + } + }, [profile, game, _get_game_chapters]); + + React.useEffect(() => { + if (profile && game !== "0") { + _get_game_maps(); + } + }, [profile, game, chapter, chapterData, _get_game_maps]); + + if (!profile) { + return <>; + } + + return ( +
+ + LPHUB | {profile.user_name} + + + {MessageDialogComponent} + {MessageDialogLoadComponent} + {ConfirmDialogComponent} + +
+
+ {profile.profile ? ( +
+ profile-image + Refresh +
+ ) : ( +
+ profile-image +
+ )} + +
+
+
{profile.user_name}
+
+ {profile.country_code === "XX" ? ( + "" + ) : ( + {profile.country_code} + )} +
+
+ {profile.titles.map(e => ( + + {e.name} + + ))} +
+
+
+ {profile.links.steam === "-" ? ( + "" + ) : ( + + Steam + + )} + {profile.links.twitch === "-" ? ( + "" + ) : ( + + Twitch + + )} + {profile.links.youtube === "-" ? ( + "" + ) : ( + + Youtube + + )} + {profile.links.p2sr === "-" ? ( + "" + ) : ( + + P2SR + + )} +
+
+
+
+ Overall + + {profile.rankings.overall.rank === 0 + ? "N/A " + : "#" + profile.rankings.overall.rank + " "} + + ({profile.rankings.overall.completion_count}/ + {profile.rankings.overall.completion_total}) + + +
+
+ Singleplayer + + {profile.rankings.singleplayer.rank === 0 + ? "N/A " + : "#" + profile.rankings.singleplayer.rank + " "} + + ({profile.rankings.singleplayer.completion_count}/ + {profile.rankings.singleplayer.completion_total}) + + +
+
+ Cooperative + + {profile.rankings.cooperative.rank === 0 + ? "N/A " + : "#" + profile.rankings.cooperative.rank + " "} + + ({profile.rankings.cooperative.completion_count}/ + {profile.rankings.cooperative.completion_total}) + + +
+
+
+ +
+ + +
+ +
+
+ {gameData === null ? ( + + ) : ( + + )} + + {game === "0" ? ( + + ) : chapterData === null ? ( + + ) : ( + + )} +
+
+ + Map Name + + + + Portals + + + + WRΔ + + + + Time + + + + + Rank + + + + Date + + +
+
+ + + {pageNumber}/{pageMax} + + +
+
+
+
+
+ {game === "0" ? ( + profile.records + .sort((a, b) => a.map_id - b.map_id) + .map((r, index) => + Math.ceil((index + 1) / 20) === pageNumber ? ( + + + + {i === 0 && r.scores.length > 1 ? ( + + ) : ( + "" + )} + + + ))} + + ) : ( + "" + ) + ) + ) : maps ? ( + maps + .filter(e => e.is_disabled === false) + .sort((a, b) => a.id - b.id) + .map((r, index) => { + if (Math.ceil((index + 1) / 20) === pageNumber) { + let record = profile.records.find(e => e.map_id === r.id); + return record === undefined ? ( + + ) : ( + + + + {i === 0 && record!.scores.length > 1 ? ( + + ) : ( + "" + )} + + + ))} + + ); + } else { + return null; + } + }) + ) : ( + <>{console.warn(maps)} + )} +
+
+
+
+ ); +}; + +export default Profile; -- cgit v1.2.3