From edff87fdf77b32fd03ee26892226068a53fbfaa6 Mon Sep 17 00:00:00 2001 From: Wolfboy248 <121288977+Wolfboy248@users.noreply.github.com> Date: Fri, 6 Sep 2024 13:05:39 +0200 Subject: refactor: rankings page --- frontend/src/App.tsx | 2 + frontend/src/api/Api.tsx | 8 +++ frontend/src/components/RankingEntry.tsx | 22 +++++++ frontend/src/css/Rankings.css | 107 +++++++++++++++++++++++++++++++ frontend/src/pages/Rankings.tsx | 92 ++++++++++++++++++++++++++ frontend/src/types/Ranking.tsx | 13 ++++ 6 files changed, 244 insertions(+) create mode 100644 frontend/src/components/RankingEntry.tsx create mode 100644 frontend/src/css/Rankings.css create mode 100644 frontend/src/pages/Rankings.tsx create mode 100644 frontend/src/types/Ranking.tsx (limited to 'frontend/src') diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index fdf1077..d45cd97 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -11,6 +11,7 @@ import Maps from './pages/Maps'; import User from './pages/User'; import Homepage from './pages/Homepage'; import Maplist from './pages/Maplist'; +import Rankings from './pages/Rankings'; const App: React.FC = () => { const [token, setToken] = React.useState(undefined); @@ -33,6 +34,7 @@ const App: React.FC = () => { } /> } /> }> + }> diff --git a/frontend/src/api/Api.tsx b/frontend/src/api/Api.tsx index 326052f..e62bb22 100644 --- a/frontend/src/api/Api.tsx +++ b/frontend/src/api/Api.tsx @@ -6,6 +6,7 @@ import { MapDiscussion, MapDiscussions, MapLeaderboard, MapSummary, Map } from ' import { MapDiscussionCommentContent, MapDiscussionContent, ModMenuContent } from '../types/Content'; import { Search } from '../types/Search'; import { UserProfile } from '../types/Profile'; +import { Ranking } from '../types/Ranking'; // add new api call function entries here // example usage: API.get_games(); @@ -17,6 +18,7 @@ export const API = { get_chapters: (chapter_id: string) => get_chapters(chapter_id), get_games_chapters: (game_id: string) => get_games_chapters(game_id), get_games_maps: (game_id: string) => get_games_maps(game_id), + get_rankings: () => get_rankings(), get_search: (q: string) => get_search(q), get_map_summary: (map_id: string) => get_map_summary(map_id), get_map_leaderboard: (map_id: string) => get_map_leaderboard(map_id), @@ -74,6 +76,12 @@ const get_games_maps = async (game_id: string): Promise => { return response.data.data; } +// RANKINGS +const get_rankings = async (): Promise => { + const response = await axios.get(url(`rankings`)); + return response.data.data; +} + // SEARCH const get_search = async (q: string): Promise => { diff --git a/frontend/src/components/RankingEntry.tsx b/frontend/src/components/RankingEntry.tsx new file mode 100644 index 0000000..b77bb3d --- /dev/null +++ b/frontend/src/components/RankingEntry.tsx @@ -0,0 +1,22 @@ +import React from 'react'; +import { Link } from "react-router-dom"; +import { RankingType } from '../types/Ranking'; + +interface RankingEntryProps { + curRankingData: RankingType; +}; + +const RankingEntry: React.FC = (curRankingData) => { + return ( +
+ {curRankingData.curRankingData.placement} +
+ + {curRankingData.curRankingData.user.user_name} +
+ {curRankingData.curRankingData.total_score} +
+ ) +} + +export default RankingEntry; diff --git a/frontend/src/css/Rankings.css b/frontend/src/css/Rankings.css new file mode 100644 index 0000000..8e49ef9 --- /dev/null +++ b/frontend/src/css/Rankings.css @@ -0,0 +1,107 @@ +.nav-container { + justify-content: center; + display: flex; +} + +.nav-container div { + display: flex; + width: 100%; + background-color: #202232; + margin-top: 20px; + border-radius: 2000px; + overflow: hidden; + gap: 3px; +} + +.nav-container button { + background-color: #2B2E46; + color: inherit; + border: none; + font-family: inherit; + cursor: pointer; + display: flex; + width: 100%; + justify-content: center; + font-size: 26px; + padding: 10px 0px; + transition: all 0.1s; +} + +.nav-container button:hover, .nav-container button.selected { + background-color: #202232; +} + +.nav-1 div { + width: 65%; +} + +.nav-2 div { + width: 80%; +} + +.rankings-leaderboard { + width: 100%; + display: flex; + justify-content: center; + font-size: 20px; + align-items: center; + margin-top: 20px; +} + +.ranks-container { + display: flex; + width: calc(60% - 20px); + padding: 8px 8px; + background-color: #202232; + border-radius: 32px; + flex-direction: column; + gap: 7px; +} + +.leaderboard-entry { + display: grid; + grid-template-columns: 20% 40% 40%; + text-align: center; + align-items: center; + width: 100%; + background-color: #2B2E46; + border-radius: 2000px; + padding: 6px 0px; +} + +.leaderboard-entry div:nth-child(2) { + text-align: left; +} + +.leaderboard-entry div { + display: flex; + align-items: center; +} + +.leaderboard-entry div span { + margin-left: 5px; +} + +.leaderboard-entry img { + height: 34px; + border-radius: 2000px; +} + +.leaderboard-entry.header { + background-color: rgba(0, 0, 0, 0); + font-family: "BarlowSemiCondensed-SemiBold"; + padding: 2px 0px; +} + +.leaderboard-entry.header span:nth-child(2) { + text-align: left; +} + +.ranks-container .splitter { + width: calc(100% - 20px); + display: flex; + height: 0.13em; + background-color: #b7b9c6; + border-radius: 200px; + transform: translateX(10px); +} diff --git a/frontend/src/pages/Rankings.tsx b/frontend/src/pages/Rankings.tsx new file mode 100644 index 0000000..377222f --- /dev/null +++ b/frontend/src/pages/Rankings.tsx @@ -0,0 +1,92 @@ +import React, { useEffect } from "react"; + +import RankingEntry from "../components/RankingEntry"; +import { Ranking, RankingType } from "../types/Ranking"; +import { API } from "../api/Api"; + +import "../css/Rankings.css"; + +const Rankings: React.FC = () => { + const [leaderboardData, setLeaderboardData] = React.useState(); + const [currentLeaderboardCat, setCurrentLeaderboardCat] = React.useState(); + const [currentLeaderboard, setCurrentLeaderboard] = React.useState(); + const [load, setLoad] = React.useState(false); + + enum RankingCategories { + rankings_overall, + rankings_multiplayer, + rankings_singleplayer + } + + const _fetch_rankings = async () => { + const rankings = await API.get_rankings(); + setLeaderboardData(rankings); + setLoad(true); + } + + 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); + } + } + + useEffect(() => { + _fetch_rankings(); + if (load) { + _set_current_leaderboard(RankingCategories.rankings_singleplayer); + } + }, [load]) + + return ( +
+
+
+ + +
+
+
+
+ + + +
+
+ + {load ? +
+
+
+ Rank + Player + Portals +
+ +
+ + {currentLeaderboard?.map((curRankingData, i) => { + return + }) + } +
+
+ : null} +
+ ) +} + +export default Rankings; diff --git a/frontend/src/types/Ranking.tsx b/frontend/src/types/Ranking.tsx new file mode 100644 index 0000000..ad4d8ae --- /dev/null +++ b/frontend/src/types/Ranking.tsx @@ -0,0 +1,13 @@ +import { UserShort } from "./Profile"; + +export interface RankingType { + placement: number; + user: UserShort; + total_score: number; +} + +export interface Ranking { + rankings_overall: RankingType[]; + rankings_singleplayer: RankingType[]; + rankings_multiplayer: RankingType[]; +} \ No newline at end of file -- cgit v1.2.3