From e40f07211f5f15dcb138e2520a76d13afd3c0cfd Mon Sep 17 00:00:00 2001 From: FifthWit Date: Thu, 30 Jan 2025 10:44:30 -0600 Subject: formatted with prettier --- frontend/src/pages/About.tsx | 54 ++-- frontend/src/pages/Games.tsx | 61 ++-- frontend/src/pages/Homepage.tsx | 39 ++- frontend/src/pages/Maplist.tsx | 165 ++++++---- frontend/src/pages/Maps.tsx | 129 ++++++-- frontend/src/pages/Profile.tsx | 669 ++++++++++++++++++++++++++++------------ frontend/src/pages/Rankings.tsx | 319 +++++++++++-------- frontend/src/pages/Rules.tsx | 56 ++-- frontend/src/pages/User.tsx | 599 ++++++++++++++++++++++++----------- 9 files changed, 1405 insertions(+), 686 deletions(-) (limited to 'frontend/src/pages') diff --git a/frontend/src/pages/About.tsx b/frontend/src/pages/About.tsx index a8b7826..a5d34f6 100644 --- a/frontend/src/pages/About.tsx +++ b/frontend/src/pages/About.tsx @@ -5,36 +5,34 @@ import { Helmet } from 'react-helmet'; import '@css/About.css'; const About: React.FC = () => { + const [aboutText, setAboutText] = React.useState(''); - const [aboutText, setAboutText] = React.useState(""); + React.useEffect(() => { + const fetchReadme = async () => { + try { + const response = await fetch( + 'https://raw.githubusercontent.com/pektezol/lphub/main/README.md' + ); + if (!response.ok) { + throw new Error('Failed to fetch README'); + } + const readmeText = await response.text(); + setAboutText(readmeText); + } catch (error) { + console.error('Error fetching README:', error); + } + }; + fetchReadme(); + }, []); - React.useEffect(() => { - const fetchReadme = async () => { - try { - const response = await fetch( - 'https://raw.githubusercontent.com/pektezol/lphub/main/README.md' - ); - if (!response.ok) { - throw new Error('Failed to fetch README'); - } - const readmeText = await response.text(); - setAboutText(readmeText); - } catch (error) { - console.error('Error fetching README:', error); - } - }; - fetchReadme(); - }, []); - - - return ( -
- - LPHUB | About - - {aboutText} -
- ); + return ( +
+ + LPHUB | About + + {aboutText} +
+ ); }; export default About; diff --git a/frontend/src/pages/Games.tsx b/frontend/src/pages/Games.tsx index 15cc891..ae0a2d6 100644 --- a/frontend/src/pages/Games.tsx +++ b/frontend/src/pages/Games.tsx @@ -3,44 +3,45 @@ import { Helmet } from 'react-helmet'; import GameEntry from '@components/GameEntry'; import { Game } from '@customTypes/Game'; -import "@css/Maps.css" +import '@css/Maps.css'; interface GamesProps { - games: Game[]; + games: Game[]; } const Games: React.FC = ({ games }) => { + const _page_load = () => { + const loaders = document.querySelectorAll('.loader'); + loaders.forEach(loader => { + (loader as HTMLElement).style.display = 'none'; + }); + }; - const _page_load = () => { - const loaders = document.querySelectorAll(".loader"); - loaders.forEach((loader) => { - (loader as HTMLElement).style.display = "none"; - }); - } + React.useEffect(() => { + document + .querySelectorAll('.games-page-item-body') + .forEach((game, index) => { + game.innerHTML = ''; + }); + _page_load(); + }, []); - React.useEffect(() => { - document.querySelectorAll(".games-page-item-body").forEach((game, index) => { - game.innerHTML = ""; - }); - _page_load(); - }, []); - - return ( -
- - LPHUB | Games - -
-
-
- {games.map((game, index) => ( - - ))} -
-
-
+ return ( +
+ + LPHUB | Games + +
+
+
+ {games.map((game, index) => ( + + ))} +
- ); +
+
+ ); }; export default Games; diff --git a/frontend/src/pages/Homepage.tsx b/frontend/src/pages/Homepage.tsx index 4f46af5..859af52 100644 --- a/frontend/src/pages/Homepage.tsx +++ b/frontend/src/pages/Homepage.tsx @@ -2,21 +2,30 @@ import React from 'react'; import { Helmet } from 'react-helmet'; const Homepage: React.FC = () => { - - return ( -
- - LPHUB | Homepage - -
-

-

Welcome to Least Portals Hub!

-

At the moment, LPHUB is in beta state. This means that the site has only the core functionalities enabled for providing both collaborative information and competitive leaderboards.

-

The website should feel intuitive to navigate around. For any type of feedback, reach us at LPHUB Discord server.

-

By using LPHUB, you agree that you have read the 'Leaderboard Rules' and the 'About LPHUB' pages.

-
-
- ); + return ( +
+ + LPHUB | Homepage + +
+

+

Welcome to Least Portals Hub!

+

+ At the moment, LPHUB is in beta state. This means that the site has + only the core functionalities enabled for providing both collaborative + information and competitive leaderboards. +

+

+ The website should feel intuitive to navigate around. For any type of + feedback, reach us at LPHUB Discord server. +

+

+ By using LPHUB, you agree that you have read the 'Leaderboard Rules' + and the 'About LPHUB' pages. +

+
+
+ ); }; export default Homepage; diff --git a/frontend/src/pages/Maplist.tsx b/frontend/src/pages/Maplist.tsx index 04938cf..5138964 100644 --- a/frontend/src/pages/Maplist.tsx +++ b/frontend/src/pages/Maplist.tsx @@ -1,11 +1,11 @@ -import React, { useEffect } from "react"; -import { Link, useLocation, useNavigate, useParams } from "react-router-dom"; -import { Helmet } from "react-helmet"; +import React, { useEffect } from 'react'; +import { Link, useLocation, useNavigate, useParams } from 'react-router-dom'; +import { Helmet } from 'react-helmet'; -import "@css/Maplist.css"; -import { API } from "@api/Api"; -import { Game } from "@customTypes/Game"; -import { GameChapter, GamesChapters } from "@customTypes/Chapters"; +import '@css/Maplist.css'; +import { API } from '@api/Api'; +import { Game } from '@customTypes/Game'; +import { GameChapter, GamesChapters } from '@customTypes/Chapters'; const Maplist: React.FC = () => { const [game, setGame] = React.useState(null); @@ -19,41 +19,41 @@ const Maplist: React.FC = () => { const [curChapter, setCurChapter] = React.useState(); const [numChapters, setNumChapters] = React.useState(0); - const [dropdownActive, setDropdownActive] = React.useState("none"); + const [dropdownActive, setDropdownActive] = React.useState('none'); - const params = useParams<{ id: string, chapter: string }>(); + const params = useParams<{ id: string; chapter: string }>(); const location = useLocation(); const navigate = useNavigate(); function _update_currently_selected(catNum2: number) { setCurrentlySelected(catNum2); - navigate("/games/" + game?.id + "?cat=" + catNum2); + navigate('/games/' + game?.id + '?cat=' + catNum2); setHasClicked(true); } const _fetch_chapters = async (chapter_id: string) => { const chapters = await API.get_chapters(chapter_id); setCurChapter(chapters); - } + }; const _handle_dropdown_click = () => { - if (dropdownActive == "none") { - setDropdownActive("block"); + if (dropdownActive == 'none') { + setDropdownActive('block'); } else { - setDropdownActive("none"); + setDropdownActive('none'); } - } + }; // im sorry but im too lazy to fix this right now useEffect(() => { // gameID - const gameId = parseFloat(params.id || ""); + const gameId = parseFloat(params.id || ''); setId(gameId); // location query params const queryParams = new URLSearchParams(location.search); - if (queryParams.get("chapter")) { - let cat = parseFloat(queryParams.get("chapter") || ""); + if (queryParams.get('chapter')) { + let cat = parseFloat(queryParams.get('chapter') || ''); if (gameId == 2) { cat += 10; } @@ -62,7 +62,7 @@ const Maplist: React.FC = () => { const _fetch_game = async () => { const games = await API.get_games(); - const foundGame = games.find((game) => game.id === gameId); + const foundGame = games.find(game => game.id === gameId); // console.log(foundGame) if (foundGame) { setGame(foundGame); @@ -74,7 +74,7 @@ const Maplist: React.FC = () => { const games_chapters = await API.get_games_chapters(gameId.toString()); setGameChapters(games_chapters); setNumChapters(games_chapters.chapters.length); - } + }; setLoad(true); _fetch_game(); @@ -83,21 +83,19 @@ const Maplist: React.FC = () => { useEffect(() => { const queryParams = new URLSearchParams(location.search); - if (gameChapters != undefined && !queryParams.get("chapter")) { + if (gameChapters != undefined && !queryParams.get('chapter')) { _fetch_chapters(gameChapters!.chapters[0].id.toString()); } - }, [gameChapters]) - - + }, [gameChapters]); return (
LPHUB | Maplist -
+
- @@ -117,7 +115,7 @@ const Maplist: React.FC = () => {

{ game?.category_portals.find( - (obj) => obj.category.id === catNum + 1 + obj => obj.category.id === catNum + 1 )?.portal_count }

@@ -125,7 +123,19 @@ const Maplist: React.FC = () => {
{game?.category_portals.map((cat, index) => ( - ))} @@ -136,45 +146,88 @@ const Maplist: React.FC = () => {
- {curChapter?.chapter.name.split(" - ")[0]} + + {curChapter?.chapter.name.split(' - ')[0]} +
- {curChapter?.chapter.name.split(" - ")[1]} + {curChapter?.chapter.name.split(' - ')[1]}
-
+
{gameChapters?.chapters.map((chapter, i) => { - return
{ _fetch_chapters(chapter.id.toString()); _handle_dropdown_click() }}>{chapter.name}
- }) - - } + return ( +
{ + _fetch_chapters(chapter.id.toString()); + _handle_dropdown_click(); + }} + > + {chapter.name} +
+ ); + })}
{curChapter?.maps.map((map, i) => { - return
- - {map.name} -
-
- {map.is_disabled ? map.category_portals[0].portal_count : map.category_portals.find( - (obj) => obj.category.id === catNum + 1 - )?.portal_count} - portals + return ( +
+ + {map.name} +
+
+ + {map.is_disabled + ? map.category_portals[0].portal_count + : map.category_portals.find( + obj => obj.category.id === catNum + 1 + )?.portal_count} + + portals +
-
-
- {/* Difficulty: */} -
-
-
-
-
-
+
+ {/* Difficulty: */} +
+
+
+
+
+
+
-
- -
+ +
+ ); })}
diff --git a/frontend/src/pages/Maps.tsx b/frontend/src/pages/Maps.tsx index fb13563..51a2020 100644 --- a/frontend/src/pages/Maps.tsx +++ b/frontend/src/pages/Maps.tsx @@ -9,26 +9,31 @@ import Discussions from '@components/Discussions'; import ModMenu from '@components/ModMenu'; import { MapDiscussions, MapLeaderboard, MapSummary } from '@customTypes/Map'; import { API } from '@api/Api'; -import "@css/Maps.css"; +import '@css/Maps.css'; interface MapProps { token?: string; isModerator: boolean; -}; +} const Maps: React.FC = ({ token, isModerator }) => { - const [selectedRun, setSelectedRun] = React.useState(0); - const [mapSummaryData, setMapSummaryData] = React.useState(undefined); - const [mapLeaderboardData, setMapLeaderboardData] = React.useState(undefined); - const [mapDiscussionsData, setMapDiscussionsData] = React.useState(undefined); + const [mapSummaryData, setMapSummaryData] = React.useState< + MapSummary | undefined + >(undefined); + const [mapLeaderboardData, setMapLeaderboardData] = React.useState< + MapLeaderboard | undefined + >(undefined); + const [mapDiscussionsData, setMapDiscussionsData] = React.useState< + MapDiscussions | undefined + >(undefined); const [navState, setNavState] = React.useState(0); const location = useLocation(); - const mapID = location.pathname.split("/")[2]; + const mapID = location.pathname.split('/')[2]; const _fetch_map_summary = async () => { const mapSummary = await API.get_map_summary(mapID); @@ -36,7 +41,7 @@ const Maps: React.FC = ({ token, isModerator }) => { }; const _fetch_map_leaderboards = async () => { - const mapLeaderboards = await API.get_map_leaderboard(mapID, "1"); + const mapLeaderboards = await API.get_map_leaderboard(mapID, '1'); setMapLeaderboardData(mapLeaderboards); }; @@ -56,19 +61,36 @@ const Maps: React.FC = ({ token, isModerator }) => { return ( <>
-
+
- + + +
-
- - - +
+ + +
-
+
); @@ -80,29 +102,80 @@ const Maps: React.FC = ({ token, isModerator }) => { LPHUB | {mapSummaryData.map.map_name} - {isModerator && } - -
+ {isModerator && ( + + )} + +
-
+
- - -
{mapSummaryData.map.map_name} + + + + + + +
+ + {mapSummaryData.map.map_name} +
-
- - - +
+ + +
- {navState === 0 && } + {navState === 0 && ( + + )} {navState === 1 && } - {navState === 2 && _fetch_map_discussions()} />} + {navState === 2 && ( + _fetch_map_discussions()} + /> + )}
); diff --git a/frontend/src/pages/Profile.tsx b/frontend/src/pages/Profile.tsx index 48233bf..7e3d603 100644 --- a/frontend/src/pages/Profile.tsx +++ b/frontend/src/pages/Profile.tsx @@ -2,16 +2,28 @@ 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 { + SteamIcon, + TwitchIcon, + YouTubeIcon, + PortalIcon, + FlagIcon, + StatisticsIcon, + SortIcon, + ThreedotIcon, + DownloadIcon, + HistoryIcon, + DeleteIcon, +} from '@images/Images'; import { UserProfile } from '@customTypes/Profile'; import { Game, GameChapters } from '@customTypes/Game'; import { Map } from '@customTypes/Map'; import { ticks_to_time } from '@utils/Time'; -import "@css/Profile.css"; +import '@css/Profile.css'; import { API } from '@api/Api'; import useConfirm from '@hooks/UseConfirm'; import useMessage from '@hooks/UseMessage'; -import useMessageLoad from "@hooks/UseMessageLoad"; +import useMessageLoad from '@hooks/UseMessageLoad'; interface ProfileProps { profile?: UserProfile; @@ -20,17 +32,25 @@ interface ProfileProps { onDeleteRecord: () => void; } -const Profile: React.FC = ({ profile, token, gameData, onDeleteRecord }) => { +const Profile: React.FC = ({ + profile, + token, + gameData, + onDeleteRecord, +}) => { const { confirm, ConfirmDialogComponent } = useConfirm(); const { message, MessageDialogComponent } = useMessage(); - const { messageLoad, messageLoadClose, MessageDialogLoadComponent } = useMessageLoad(); + 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 [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(); @@ -42,17 +62,17 @@ const Profile: React.FC = ({ profile, token, gameData, onDeleteRec }; const _get_game_chapters = async () => { - if (game && game !== "0") { + if (game && game !== '0') { const gameChapters = await API.get_games_chapters(game); setChapterData(gameChapters); - } else if (game && game === "0") { + } else if (game && game === '0') { setPageMax(Math.ceil(profile!.records.length / 20)); setPageNumber(1); } }; const _get_game_maps = async () => { - if (chapter === "0") { + if (chapter === '0') { const gameMaps = await API.get_game_maps(game); setMaps(gameMaps); setPageMax(Math.ceil(gameMaps.length / 20)); @@ -66,28 +86,31 @@ const Profile: React.FC = ({ profile, token, gameData, onDeleteRec }; 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?"); + const userConfirmed = await confirm( + 'Delete Record', + 'Are you sure you want to delete this record?' + ); if (!userConfirmed) { return; } - messageLoad("Deleting..."); + 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."); + await message('Delete Record', 'Successfully deleted record.'); onDeleteRecord(); } else { - await message("Delete Record", "Could not delete record."); + await message('Delete Record', 'Could not delete record.'); } }; React.useEffect(() => { if (!profile) { - navigate("/"); - }; + navigate('/'); + } }, [profile]); React.useEffect(() => { @@ -97,16 +120,14 @@ const Profile: React.FC = ({ profile, token, gameData, onDeleteRec }, [profile, game]); React.useEffect(() => { - if (profile && game !== "0") { + if (profile && game !== '0') { _get_game_maps(); } - }, [profile, game, chapter, chapterData]) + }, [profile, game, chapter, chapterData]); if (!profile) { - return ( - <> - ); - }; + return <>; + } return (
@@ -119,230 +140,490 @@ const Profile: React.FC = ({ profile, token, gameData, onDeleteRec {ConfirmDialogComponent}
-
- - {profile.profile - ? ( -
- profile-image - Refresh -
- ) : ( -
- profile-image -
- )} +
+ {profile.profile ? ( +
+ profile-image + Refresh +
+ ) : ( +
+ profile-image +
+ )} -
+
{profile.user_name}
- {profile.country_code === "XX" ? "" : {profile.country_code}} + {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} + {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}) + + {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}) + + {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}) + + {profile.rankings.cooperative.rank === 0 + ? 'N/A ' + : '#' + profile.rankings.cooperative.rank + ' '} + + ({profile.rankings.cooperative.completion_count}/ + {profile.rankings.cooperative.completion_total}) +
- -
- - +
+ +
- - - - -
-
- {gameData === null ? : - - error + ) : ( + - } + + ))} + + )} - {game === "0" ? + {game === '0' ? ( - : chapterData === null ? : - - - } + ) : chapterData === null ? ( + + ) : ( + + )}
-
- Map Name - Portals - WRΔ - Time +
+ + Map Name + + + + Portals + + + + WRΔ + + + + Time + + - Rank - Date -
+ + Rank + + + + Date + + +
- - {pageNumber}/{pageMax} - + + + {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 ? : ""} - +
+ {game === '0' ? ( + profile.records + .sort((a, b) => a.map_id - b.map_id) + .map((r, index) => + Math.ceil((index + 1) / 20) === pageNumber ? ( + - ) : "" - ))) : 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 ? + + : ""} - + > + download + + {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 ? ( + + ) : ( + - - ) - } else { return null } - }) : (<>{console.warn(maps)})} + + {record!.scores[i].score_count - + record!.map_wr_count > + 0 + ? `+${record!.scores[i].score_count - record!.map_wr_count}` + : `-`} + + + {ticks_to_time(record!.scores[i].score_time)} + + + {i === 0 ? ( + #{record!.placement} + ) : ( + + )} + {record!.scores[i].date.split('T')[0]} + + + + + {i === 0 && record!.scores.length > 1 ? ( + + ) : ( + '' + )} + + + ))} + + ); + } else { + return null; + } + }) + ) : ( + <>{console.warn(maps)} + )}
diff --git a/frontend/src/pages/Rankings.tsx b/frontend/src/pages/Rankings.tsx index 71aa427..885638d 100644 --- a/frontend/src/pages/Rankings.tsx +++ b/frontend/src/pages/Rankings.tsx @@ -1,147 +1,200 @@ -import React, { useEffect } from "react"; -import { Helmet } from "react-helmet"; +import React, { useEffect } from 'react'; +import { Helmet } from 'react-helmet'; -import RankingEntry from "@components/RankingEntry"; -import { Ranking, SteamRanking, RankingType, SteamRankingType } from "@customTypes/Ranking"; -import { API } from "@api/Api"; +import RankingEntry from '@components/RankingEntry'; +import { + Ranking, + SteamRanking, + RankingType, + SteamRankingType, +} from '@customTypes/Ranking'; +import { API } from '@api/Api'; -import "@css/Rankings.css"; +import '@css/Rankings.css'; const Rankings: React.FC = () => { - const [leaderboardData, setLeaderboardData] = React.useState(); - const [currentLeaderboard, setCurrentLeaderboard] = React.useState(); - enum LeaderboardTypes { - official, - unofficial + const [leaderboardData, setLeaderboardData] = React.useState< + Ranking | SteamRanking + >(); + const [currentLeaderboard, setCurrentLeaderboard] = React.useState< + RankingType[] | SteamRankingType[] + >(); + enum LeaderboardTypes { + official, + unofficial, + } + const [currentRankingType, setCurrentRankingType] = + React.useState(LeaderboardTypes.official); + + const [leaderboardLoad, setLeaderboardLoad] = React.useState(false); + + enum RankingCategories { + rankings_overall, + rankings_multiplayer, + rankings_singleplayer, + } + const [currentLeaderboardType, setCurrentLeaderboardType] = + React.useState(RankingCategories.rankings_singleplayer); + const [load, setLoad] = React.useState(false); + + const _fetch_rankings = async () => { + setLeaderboardLoad(false); + const rankings = await API.get_official_rankings(); + setLeaderboardData(rankings); + if (currentLeaderboardType == RankingCategories.rankings_singleplayer) { + setCurrentLeaderboard(rankings.rankings_singleplayer); + } else if ( + currentLeaderboardType == RankingCategories.rankings_multiplayer + ) { + setCurrentLeaderboard(rankings.rankings_multiplayer); + } else { + setCurrentLeaderboard(rankings.rankings_overall); } - const [currentRankingType, setCurrentRankingType] = React.useState(LeaderboardTypes.official); - - const [leaderboardLoad, setLeaderboardLoad] = React.useState(false); - - enum RankingCategories { - rankings_overall, - rankings_multiplayer, - rankings_singleplayer - } - const [currentLeaderboardType, setCurrentLeaderboardType] = React.useState(RankingCategories.rankings_singleplayer); - const [load, setLoad] = React.useState(false); - - const _fetch_rankings = async () => { - setLeaderboardLoad(false); - const rankings = await API.get_official_rankings(); - setLeaderboardData(rankings); - if (currentLeaderboardType == RankingCategories.rankings_singleplayer) { - setCurrentLeaderboard(rankings.rankings_singleplayer) - } else if (currentLeaderboardType == RankingCategories.rankings_multiplayer) { - setCurrentLeaderboard(rankings.rankings_multiplayer) - } else { - setCurrentLeaderboard(rankings.rankings_overall) - } - setLoad(true); - setLeaderboardLoad(true); + setLoad(true); + setLeaderboardLoad(true); + }; + + const __dev_fetch_unofficial_rankings = async () => { + try { + setLeaderboardLoad(false); + const rankings = await API.get_unofficial_rankings(); + setLeaderboardData(rankings); + if (currentLeaderboardType == RankingCategories.rankings_singleplayer) { + // console.log(_sort_rankings_steam(unofficialRanking.rankings_singleplayer)) + setCurrentLeaderboard(rankings.rankings_singleplayer); + } else if ( + currentLeaderboardType == RankingCategories.rankings_multiplayer + ) { + setCurrentLeaderboard(rankings.rankings_multiplayer); + } else { + setCurrentLeaderboard(rankings.rankings_overall); + } + setLeaderboardLoad(true); + } catch (e) { + console.log(e); } - - const __dev_fetch_unofficial_rankings = async () => { - try { - setLeaderboardLoad(false); - const rankings = await API.get_unofficial_rankings(); - setLeaderboardData(rankings); - if (currentLeaderboardType == RankingCategories.rankings_singleplayer) { - // console.log(_sort_rankings_steam(unofficialRanking.rankings_singleplayer)) - setCurrentLeaderboard(rankings.rankings_singleplayer) - } else if (currentLeaderboardType == RankingCategories.rankings_multiplayer) { - setCurrentLeaderboard(rankings.rankings_multiplayer) - } else { - setCurrentLeaderboard(rankings.rankings_overall) - } - setLeaderboardLoad(true); - } catch (e) { - console.log(e) - } + }; + + const _set_current_leaderboard = (ranking_cat: RankingCategories) => { + if (ranking_cat == RankingCategories.rankings_singleplayer) { + setCurrentLeaderboard(leaderboardData!.rankings_singleplayer); + } else if (ranking_cat == RankingCategories.rankings_multiplayer) { + setCurrentLeaderboard(leaderboardData!.rankings_multiplayer); + } else { + setCurrentLeaderboard(leaderboardData!.rankings_overall); } - const _set_current_leaderboard = (ranking_cat: RankingCategories) => { - if (ranking_cat == RankingCategories.rankings_singleplayer) { - setCurrentLeaderboard(leaderboardData!.rankings_singleplayer); - } else if (ranking_cat == RankingCategories.rankings_multiplayer) { - setCurrentLeaderboard(leaderboardData!.rankings_multiplayer); - } else { - setCurrentLeaderboard(leaderboardData!.rankings_overall); - } + setCurrentLeaderboardType(ranking_cat); + }; - setCurrentLeaderboardType(ranking_cat); + const _set_leaderboard_type = (leaderboard_type: LeaderboardTypes) => { + if (leaderboard_type == LeaderboardTypes.official) { + _fetch_rankings(); + } else { } + }; - const _set_leaderboard_type = (leaderboard_type: LeaderboardTypes) => { - if (leaderboard_type == LeaderboardTypes.official) { - _fetch_rankings(); - } else { - - } + useEffect(() => { + _fetch_rankings(); + if (load) { + _set_current_leaderboard(RankingCategories.rankings_singleplayer); } - - useEffect(() => { - _fetch_rankings(); - if (load) { - _set_current_leaderboard(RankingCategories.rankings_singleplayer); - } - }, [load]) - - return ( -
- - LPHUB | Rankings - -
-
- - -
-
-
-
- - - -
-
- - {load ? -
-
-
- Rank - Player - Portals -
- -
- - {leaderboardLoad && currentLeaderboard?.map((curRankingData, i) => { - return - }) - } - - {leaderboardLoad ? null : -
- -
- } -
-
- : null} -
- ) -} + }, [load]); + + return ( +
+ + LPHUB | Rankings + +
+
+ + +
+
+
+
+ + + +
+
+ + {load ? ( +
+
+
+ Rank + Player + Portals +
+ +
+ + {leaderboardLoad && + currentLeaderboard?.map((curRankingData, i) => { + return ( + + ); + })} + + {leaderboardLoad ? null : ( +
+ +
+ )} +
+
+ ) : null} +
+ ); +}; export default Rankings; diff --git a/frontend/src/pages/Rules.tsx b/frontend/src/pages/Rules.tsx index 9f57b7e..7a774bc 100644 --- a/frontend/src/pages/Rules.tsx +++ b/frontend/src/pages/Rules.tsx @@ -5,37 +5,35 @@ import { Helmet } from 'react-helmet'; import '@css/Rules.css'; const Rules: React.FC = () => { + const [rulesText, setRulesText] = React.useState(''); - const [rulesText, setRulesText] = React.useState(""); + React.useEffect(() => { + const fetchRules = async () => { + try { + const response = await fetch( + 'https://raw.githubusercontent.com/pektezol/lphub/main/RULES.md' + ); + if (!response.ok) { + throw new Error('Failed to fetch README'); + } + const rulesText = await response.text(); + setRulesText(rulesText); + } catch (error) { + console.error('Error fetching Rules:', error); + } + // setRulesText(rulesText) + }; + fetchRules(); + }, []); - React.useEffect(() => { - const fetchRules = async () => { - try { - const response = await fetch( - 'https://raw.githubusercontent.com/pektezol/lphub/main/RULES.md' - ); - if (!response.ok) { - throw new Error('Failed to fetch README'); - } - const rulesText = await response.text(); - setRulesText(rulesText); - } catch (error) { - console.error('Error fetching Rules:', error); - } - // setRulesText(rulesText) - }; - fetchRules(); - }, []); - - - return ( -
- - LPHUB | Rules - - {rulesText} -
- ); + return ( +
+ + LPHUB | Rules + + {rulesText} +
+ ); }; export default Rules; diff --git a/frontend/src/pages/User.tsx b/frontend/src/pages/User.tsx index d43c0c6..b6dfbd3 100644 --- a/frontend/src/pages/User.tsx +++ b/frontend/src/pages/User.tsx @@ -2,13 +2,24 @@ 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 { + SteamIcon, + TwitchIcon, + YouTubeIcon, + PortalIcon, + FlagIcon, + StatisticsIcon, + SortIcon, + ThreedotIcon, + DownloadIcon, + HistoryIcon, +} from '@images/Images'; import { UserProfile } from '@customTypes/Profile'; import { Game, GameChapters } from '@customTypes/Game'; import { Map } from '@customTypes/Map'; import { API } from '@api/Api'; import { ticks_to_time } from '@utils/Time'; -import "@css/Profile.css"; +import '@css/Profile.css'; import useMessage from '@hooks/UseMessage'; interface UserProps { @@ -18,7 +29,6 @@ interface UserProps { } const User: React.FC = ({ token, profile, gameData }) => { - const { message, MessageDialogComponent } = useMessage(); const [user, setUser] = React.useState(undefined); @@ -27,18 +37,20 @@ const User: React.FC = ({ token, profile, gameData }) => { 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 [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 = async () => { - const userID = location.pathname.split("/")[2]; + const userID = location.pathname.split('/')[2]; if (token && profile && profile.profile && profile.steam_id === userID) { - navigate("/profile"); + navigate('/profile'); return; } const userData = await API.get_user(userID); @@ -46,7 +58,7 @@ const User: React.FC = ({ token, profile, gameData }) => { }; const _get_game_chapters = async () => { - if (game !== "0") { + if (game !== '0') { const gameChapters = await API.get_games_chapters(game); setChapterData(gameChapters); } else { @@ -56,7 +68,7 @@ const User: React.FC = ({ token, profile, gameData }) => { }; const _get_game_maps = async () => { - if (chapter === "0") { + if (chapter === '0') { const gameMaps = await API.get_game_maps(game); setMaps(gameMaps); setPageMax(Math.ceil(gameMaps.length / 20)); @@ -80,16 +92,14 @@ const User: React.FC = ({ token, profile, gameData }) => { }, [user, game, location]); React.useEffect(() => { - if (user && game !== "0") { + if (user && game !== '0') { _get_game_maps(); } - }, [user, game, chapter, location]) + }, [user, game, chapter, location]); if (!user) { - return ( - <> - ); - }; + return <>; + } return (
@@ -98,218 +108,461 @@ const User: React.FC = ({ token, profile, gameData }) => { {MessageDialogComponent} -
+
profile-image
-
+
{user.user_name}
- {user.country_code === "XX" ? "" : {user.country_code}} + {user.country_code === 'XX' ? ( + '' + ) : ( + {user.country_code} + )}
{user.titles.map(e => ( - + {e.name} ))}
- {user.links.steam === "-" ? "" : Steam} - {user.links.twitch === "-" ? "" : Twitch} - {user.links.youtube === "-" ? "" : Youtube} - {user.links.p2sr === "-" ? "" : P2SR} + {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}) + + {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}) + + {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}) + + {user.rankings.cooperative.rank === 0 + ? 'N/A ' + : '#' + user.rankings.cooperative.rank + ' '} + + ({user.rankings.cooperative.completion_count}/ + {user.rankings.cooperative.completion_total}) +
- -
- - +
+ +
- - - - -
-
- {gameData === null ? : - - error + ) : ( + - } + + ))} + + )} - {game === "0" ? + {game === '0' ? ( - : chapterData === null ? : - - - } + ) : chapterData === null ? ( + + ) : ( + + )}
-
- Map Name - Portals - WRΔ - Time +
+ + Map Name + + + + Portals + + + + WRΔ + + + + Time + + - Rank - Date -
+ + Rank + + + + Date + + +
- - {pageNumber}/{pageMax} - + + + {pageNumber}/{pageMax} + +

-
- - {game === "0" - ? ( - - user.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 ? : ""} - + {e.date.split('T')[0]} + + + + {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 = user.records.find(e => e.map_id === r.id); + return record === undefined ? ( + - ) : "" - ))) : 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 = user.records.find((e) => e.map_id === r.id); - return record === undefined ? ( - - ) : ( - - - {i === 0 && record!.scores.length > 1 ? : ""} - + {i === 0 ? ( + #{record!.placement} + ) : ( + + )} + {record!.scores[i].date.split('T')[0]} + + + + {i === 0 && record!.scores.length > 1 ? ( + + ) : ( + '' + )} - ))} - - - ) - } else { return null } - }) : (<>{console.warn(maps)})} + + ))} + + ); + } else { + return null; + } + }) + ) : ( + <>{console.warn(maps)} + )}
-- cgit v1.2.3