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/User/User.tsx | 410 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 410 insertions(+) create mode 100644 frontend/src/pages/User/User.tsx (limited to 'frontend/src/pages/User') diff --git a/frontend/src/pages/User/User.tsx b/frontend/src/pages/User/User.tsx new file mode 100644 index 0000000..30c9e45 --- /dev/null +++ b/frontend/src/pages/User/User.tsx @@ -0,0 +1,410 @@ +import React from "react"; +import { Link, useLocation, useNavigate } from "react-router-dom"; +import { Helmet } from "react-helmet"; + +import { + SteamIcon, + TwitchIcon, + YouTubeIcon, + PortalIcon, + FlagIcon, + StatisticsIcon, + SortIcon, + ThreedotIcon, + DownloadIcon, + HistoryIcon, +} from "@images/Images"; +import { UserProfile } from "@customTypes/Profile.ts"; +import { Game, GameChapters } from "@customTypes/Game.ts"; +import { Map } from "@customTypes/Map.ts"; +import { API } from "@api/Api.ts"; +import { ticks_to_time } from "@utils/Time.ts"; +import useMessage from "@hooks/UseMessage.tsx"; + +interface UserProps { + profile?: UserProfile; + token?: string; + gameData: Game[]; +} + +const User: React.FC = ({ token, profile, gameData }) => { + const { message, MessageDialogComponent } = useMessage(); + + const [user, setUser] = React.useState(undefined); + + 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 location = useLocation(); + const navigate = useNavigate(); + + const _fetch_user = React.useCallback(async () => { + const userID = location.pathname.split("/")[2]; + if (token && profile && profile.profile && profile.steam_id === userID) { + navigate("/profile"); + return; + } + const userData = await API.get_user(userID); + setUser(userData); + }, [location.pathname, token, profile, navigate]); + + const _get_game_chapters = React.useCallback(async () => { + if (game !== "0") { + const gameChapters = await API.get_games_chapters(game); + setChapterData(gameChapters); + } else { + setPageMax(Math.ceil(user!.records.length / 20)); + setPageNumber(1); + } + }, [game, user]); + + 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]); + + React.useEffect(() => { + _fetch_user(); + }, [location, _fetch_user]); + + React.useEffect(() => { + if (user) { + _get_game_chapters(); + } + }, [user, game, location, _get_game_chapters]); + + React.useEffect(() => { + if (user && game !== "0") { + _get_game_maps(); + } + }, [user, game, chapter, location, _get_game_maps]); + + if (!user) { + return ( +
+ Loading... +
+ ); + } + + return ( +
+ + LPHUB | {user.user_name} + + + + {MessageDialogComponent} + +
+
+ Profile +
+

+ {user.user_name} +

+ {user.country_code !== "XX" && ( +
+ {user.country_code} + {user.country_code} +
+ )} +
+ {user.titles.map((title, index) => ( + + {title.name} + + ))} +
+
+
+ {user.links.steam !== "-" && ( + + Steam + + )} + {user.links.twitch !== "-" && ( + + Twitch + + )} + {user.links.youtube !== "-" && ( + + YouTube + + )} + {user.links.p2sr !== "-" && ( + + P2SR + + )} +
+
+ +
+
+
Overall
+
+ {user.rankings.overall.rank === 0 ? "N/A" : `#${user.rankings.overall.rank}`} +
+
+ {user.rankings.overall.completion_count}/{user.rankings.overall.completion_total} +
+
+
+
Singleplayer
+
+ {user.rankings.singleplayer.rank === 0 ? "N/A" : `#${user.rankings.singleplayer.rank}`} +
+
+ {user.rankings.singleplayer.completion_count}/{user.rankings.singleplayer.completion_total} +
+
+
+
Cooperative
+
+ {user.rankings.cooperative.rank === 0 ? "N/A" : `#${user.rankings.cooperative.rank}`} +
+
+ {user.rankings.cooperative.completion_count}/{user.rankings.cooperative.completion_total} +
+
+
+
+ +
+ + +
+ + {navState === 0 && ( +
+
+ + + +
+ +
+
+ Map Name + Sort +
+
+ Portals + Sort +
+
+ WRΔ + Sort +
+
+ Time + Sort +
+
+
+ Rank + Sort +
+
+ Date + Sort +
+
+ + {pageNumber}/{pageMax} + +
+
+ +
+ {game === "0" ? ( + user.records + .sort((a, b) => a.map_id - b.map_id) + .map((record, index) => + Math.ceil((index + 1) / 20) === pageNumber ? ( +
+ + {record.map_name} + + {record.scores[0]?.score_count || 'N/A'} + 0 ? 'text-[#dc3545]' : ''}`}> + {record.scores[0]?.score_count - record.map_wr_count > 0 + ? `+${record.scores[0].score_count - record.map_wr_count}` + : '–'} + + {record.scores[0] ? ticks_to_time(record.scores[0].score_time) : 'N/A'} + + #{record.placement} + {record.scores[0]?.date.split("T")[0] || 'N/A'} +
+ + + {record.scores.length > 1 && ( + + )} +
+
+ ) : null + ) + ) : ( + maps + ?.filter(map => !map.is_disabled) + .sort((a, b) => a.id - b.id) + .map((map, index) => { + if (Math.ceil((index + 1) / 20) !== pageNumber) return null; + + const record = user.records.find(r => r.map_id === map.id); + + return ( +
+ + {map.name} + + {record?.scores[0]?.score_count || 'N/A'} + 0 ? 'text-[#dc3545]' : ''}`}> + {record?.scores[0]?.score_count && record.scores[0].score_count - record.map_wr_count > 0 + ? `+${record.scores[0].score_count - record.map_wr_count}` + : '–'} + + {record?.scores[0] ? ticks_to_time(record.scores[0].score_time) : 'N/A'} + + {record ? `#${record.placement}` : 'N/A'} + {record?.scores[0]?.date.split("T")[0] || 'N/A'} +
+ {record?.scores[0] && ( + <> + + + {record.scores.length > 1 && ( + + )} + + )} +
+
+ ); + }) + )} +
+
+ )} +
+ ); +}; + +export default User; -- cgit v1.2.3