aboutsummaryrefslogtreecommitdiff
path: root/frontend
diff options
context:
space:
mode:
authorFifthWit <fifthwitbusiness@gmail.com>2025-01-30 13:11:48 -0600
committerFifthWit <fifthwitbusiness@gmail.com>2025-01-30 13:11:48 -0600
commit81342e2579165ebfdb28c749dc5225141721a419 (patch)
tree8e5759c20b92408048fe5ac44f48e2df2a00ab9b /frontend
parentfixed issues with useCallback (diff)
downloadlphub-81342e2579165ebfdb28c749dc5225141721a419.tar.gz
lphub-81342e2579165ebfdb28c749dc5225141721a419.tar.bz2
lphub-81342e2579165ebfdb28c749dc5225141721a419.zip
switched to double quotes
Diffstat (limited to 'frontend')
-rw-r--r--frontend/.prettierrc2
-rw-r--r--frontend/src/App.tsx40
-rw-r--r--frontend/src/api/Api.ts18
-rw-r--r--frontend/src/api/Auth.ts6
-rw-r--r--frontend/src/api/Games.ts12
-rw-r--r--frontend/src/api/Maps.ts12
-rw-r--r--frontend/src/api/Mod.ts6
-rw-r--r--frontend/src/api/Rankings.ts6
-rw-r--r--frontend/src/api/User.ts6
-rw-r--r--frontend/src/components/ConfirmDialog.tsx4
-rw-r--r--frontend/src/components/Discussions.tsx54
-rw-r--r--frontend/src/components/GameCategory.tsx10
-rw-r--r--frontend/src/components/GameEntry.tsx12
-rw-r--r--frontend/src/components/Leaderboards.tsx68
-rw-r--r--frontend/src/components/Login.tsx16
-rw-r--r--frontend/src/components/MapEntry.tsx4
-rw-r--r--frontend/src/components/MessageDialog.tsx4
-rw-r--r--frontend/src/components/MessageDialogLoad.tsx6
-rw-r--r--frontend/src/components/ModMenu.tsx96
-rw-r--r--frontend/src/components/RankingEntry.tsx8
-rw-r--r--frontend/src/components/Sidebar.tsx100
-rw-r--r--frontend/src/components/Summary.tsx68
-rw-r--r--frontend/src/components/UploadRunDialog.tsx108
-rw-r--r--frontend/src/hooks/UseConfirm.tsx8
-rw-r--r--frontend/src/hooks/UseMessage.tsx8
-rw-r--r--frontend/src/hooks/UseMessageLoad.tsx6
-rw-r--r--frontend/src/images/Images.tsx46
-rw-r--r--frontend/src/index.tsx10
-rw-r--r--frontend/src/pages/About.tsx16
-rw-r--r--frontend/src/pages/Games.tsx18
-rw-r--r--frontend/src/pages/Homepage.tsx4
-rw-r--r--frontend/src/pages/Maplist.tsx64
-rw-r--r--frontend/src/pages/Maps.tsx36
-rw-r--r--frontend/src/pages/Profile.tsx200
-rw-r--r--frontend/src/pages/Rankings.tsx28
-rw-r--r--frontend/src/pages/Rules.tsx16
-rw-r--r--frontend/src/pages/User.tsx184
-rw-r--r--frontend/src/react-app-env.d.ts4
-rw-r--r--frontend/src/types/Chapters.ts4
-rw-r--r--frontend/src/types/Game.ts2
-rw-r--r--frontend/src/types/Map.ts10
-rw-r--r--frontend/src/types/Profile.ts2
-rw-r--r--frontend/src/types/Ranking.ts2
-rw-r--r--frontend/src/types/Search.ts2
-rw-r--r--frontend/src/utils/Jwt.ts20
-rw-r--r--frontend/src/utils/Time.ts26
46 files changed, 691 insertions, 691 deletions
diff --git a/frontend/.prettierrc b/frontend/.prettierrc
index 680faf0..30dce81 100644
--- a/frontend/.prettierrc
+++ b/frontend/.prettierrc
@@ -2,7 +2,7 @@
2 "tabWidth": 2, 2 "tabWidth": 2,
3 "useTabs": false, 3 "useTabs": false,
4 "semi": true, 4 "semi": true,
5 "singleQuote": true, 5 "singleQuote": false,
6 "trailingComma": "es5", 6 "trailingComma": "es5",
7 "printWidth": 80, 7 "printWidth": 80,
8 "bracketSpacing": true, 8 "bracketSpacing": true,
diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx
index 4a99625..fbfa59f 100644
--- a/frontend/src/App.tsx
+++ b/frontend/src/App.tsx
@@ -1,24 +1,24 @@
1import React, { useCallback } from 'react'; 1import React, { useCallback } from "react";
2import { Routes, Route } from 'react-router-dom'; 2import { Routes, Route } from "react-router-dom";
3import { Helmet } from 'react-helmet'; 3import { Helmet } from "react-helmet";
4 4
5import { UserProfile } from '@customTypes/Profile'; 5import { UserProfile } from "@customTypes/Profile";
6import Sidebar from './components/Sidebar'; 6import Sidebar from "./components/Sidebar";
7import './App.css'; 7import "./App.css";
8 8
9import Profile from '@pages/Profile'; 9import Profile from "@pages/Profile";
10import Games from '@pages/Games'; 10import Games from "@pages/Games";
11import Maps from '@pages/Maps'; 11import Maps from "@pages/Maps";
12import User from '@pages/User'; 12import User from "@pages/User";
13import Homepage from '@pages/Homepage'; 13import Homepage from "@pages/Homepage";
14import UploadRunDialog from './components/UploadRunDialog'; 14import UploadRunDialog from "./components/UploadRunDialog";
15import Rules from '@pages/Rules'; 15import Rules from "@pages/Rules";
16import About from '@pages/About'; 16import About from "@pages/About";
17import { Game } from '@customTypes/Game'; 17import { Game } from "@customTypes/Game";
18import { API } from './api/Api'; 18import { API } from "./api/Api";
19import Maplist from '@pages/Maplist'; 19import Maplist from "@pages/Maplist";
20import Rankings from '@pages/Rankings'; 20import Rankings from "@pages/Rankings";
21import { get_user_id_from_token, get_user_mod_from_token } from './utils/Jwt'; 21import { get_user_id_from_token, get_user_mod_from_token } from "./utils/Jwt";
22 22
23const App: React.FC = () => { 23const App: React.FC = () => {
24 const [token, setToken] = React.useState<string | undefined>(undefined); 24 const [token, setToken] = React.useState<string | undefined>(undefined);
@@ -119,7 +119,7 @@ const App: React.FC = () => {
119 <Route path="/rules" element={<Rules />} /> 119 <Route path="/rules" element={<Rules />} />
120 <Route path="/about" element={<About />} /> 120 <Route path="/about" element={<About />} />
121 <Route path="/rankings" element={<Rankings />}></Route> 121 <Route path="/rankings" element={<Rankings />}></Route>
122 <Route path="*" element={'404'} /> 122 <Route path="*" element={"404"} />
123 </Routes> 123 </Routes>
124 </> 124 </>
125 ); 125 );
diff --git a/frontend/src/api/Api.ts b/frontend/src/api/Api.ts
index b98dda3..0e1658c 100644
--- a/frontend/src/api/Api.ts
+++ b/frontend/src/api/Api.ts
@@ -1,14 +1,14 @@
1import { MapDiscussionContent, ModMenuContent } from '@customTypes/Content'; 1import { MapDiscussionContent, ModMenuContent } from "@customTypes/Content";
2import { delete_token, get_token } from '@api/Auth'; 2import { delete_token, get_token } from "@api/Auth";
3import { get_user, get_profile, post_profile } from '@api/User'; 3import { get_user, get_profile, post_profile } from "@api/User";
4import { 4import {
5 get_games, 5 get_games,
6 get_chapters, 6 get_chapters,
7 get_games_chapters, 7 get_games_chapters,
8 get_game_maps, 8 get_game_maps,
9 get_search, 9 get_search,
10} from '@api/Games'; 10} from "@api/Games";
11import { get_official_rankings, get_unofficial_rankings } from '@api/Rankings'; 11import { get_official_rankings, get_unofficial_rankings } from "@api/Rankings";
12import { 12import {
13 get_map_summary, 13 get_map_summary,
14 get_map_leaderboard, 14 get_map_leaderboard,
@@ -19,14 +19,14 @@ import {
19 delete_map_discussion, 19 delete_map_discussion,
20 post_record, 20 post_record,
21 delete_map_record, 21 delete_map_record,
22} from '@api/Maps'; 22} from "@api/Maps";
23import { 23import {
24 delete_map_summary, 24 delete_map_summary,
25 post_map_summary, 25 post_map_summary,
26 put_map_image, 26 put_map_image,
27 put_map_summary, 27 put_map_summary,
28} from '@api/Mod'; 28} from "@api/Mod";
29import { UploadRunContent } from '@customTypes/Content'; 29import { UploadRunContent } from "@customTypes/Content";
30 30
31// add new api call function entries here 31// add new api call function entries here
32// example usage: API.get_games(); 32// example usage: API.get_games();
@@ -91,7 +91,7 @@ export const API = {
91 delete_map_summary(token, map_id, route_id), 91 delete_map_summary(token, map_id, route_id),
92}; 92};
93 93
94const BASE_API_URL: string = '/api/v1/'; 94const BASE_API_URL: string = "/api/v1/";
95 95
96export function url(path: string): string { 96export function url(path: string): string {
97 return BASE_API_URL + path; 97 return BASE_API_URL + path;
diff --git a/frontend/src/api/Auth.ts b/frontend/src/api/Auth.ts
index e495d47..98c6d36 100644
--- a/frontend/src/api/Auth.ts
+++ b/frontend/src/api/Auth.ts
@@ -1,5 +1,5 @@
1import axios from 'axios'; 1import axios from "axios";
2import { url } from '@api/Api'; 2import { url } from "@api/Api";
3 3
4export const get_token = async (): Promise<string | undefined> => { 4export const get_token = async (): Promise<string | undefined> => {
5 const response = await axios.get(url(`token`)); 5 const response = await axios.get(url(`token`));
@@ -10,5 +10,5 @@ export const get_token = async (): Promise<string | undefined> => {
10}; 10};
11 11
12export const delete_token = async () => { 12export const delete_token = async () => {
13 await axios.delete(url('token')); 13 await axios.delete(url("token"));
14}; 14};
diff --git a/frontend/src/api/Games.ts b/frontend/src/api/Games.ts
index 0e47091..b739f80 100644
--- a/frontend/src/api/Games.ts
+++ b/frontend/src/api/Games.ts
@@ -1,9 +1,9 @@
1import axios from 'axios'; 1import axios from "axios";
2import { url } from '@api/Api'; 2import { url } from "@api/Api";
3import { GameChapter, GamesChapters } from '@customTypes/Chapters'; 3import { GameChapter, GamesChapters } from "@customTypes/Chapters";
4import { Game } from '@customTypes/Game'; 4import { Game } from "@customTypes/Game";
5import { Map } from '@customTypes/Map'; 5import { Map } from "@customTypes/Map";
6import { Search } from '@customTypes/Search'; 6import { Search } from "@customTypes/Search";
7 7
8export const get_games = async (): Promise<Game[]> => { 8export const get_games = async (): Promise<Game[]> => {
9 const response = await axios.get(url(`games`)); 9 const response = await axios.get(url(`games`));
diff --git a/frontend/src/api/Maps.ts b/frontend/src/api/Maps.ts
index 3a22f88..2485941 100644
--- a/frontend/src/api/Maps.ts
+++ b/frontend/src/api/Maps.ts
@@ -1,12 +1,12 @@
1import axios from 'axios'; 1import axios from "axios";
2import { url } from '@api/Api'; 2import { url } from "@api/Api";
3import { MapDiscussionContent, UploadRunContent } from '@customTypes/Content'; 3import { MapDiscussionContent, UploadRunContent } from "@customTypes/Content";
4import { 4import {
5 MapSummary, 5 MapSummary,
6 MapLeaderboard, 6 MapLeaderboard,
7 MapDiscussions, 7 MapDiscussions,
8 MapDiscussion, 8 MapDiscussion,
9} from '@customTypes/Map'; 9} from "@customTypes/Map";
10 10
11export const get_map_summary = async (map_id: string): Promise<MapSummary> => { 11export const get_map_summary = async (map_id: string): Promise<MapSummary> => {
12 const response = await axios.get(url(`maps/${map_id}/summary`)); 12 const response = await axios.get(url(`maps/${map_id}/summary`));
@@ -27,9 +27,9 @@ export const get_map_leaderboard = async (
27 // map the kind of leaderboard 27 // map the kind of leaderboard
28 data.records = data.records.map((record: any) => { 28 data.records = data.records.map((record: any) => {
29 if (record.host && record.partner) { 29 if (record.host && record.partner) {
30 return { ...record, kind: 'multiplayer' }; 30 return { ...record, kind: "multiplayer" };
31 } else { 31 } else {
32 return { ...record, kind: 'singleplayer' }; 32 return { ...record, kind: "singleplayer" };
33 } 33 }
34 }); 34 });
35 return data; 35 return data;
diff --git a/frontend/src/api/Mod.ts b/frontend/src/api/Mod.ts
index 69e76c5..d682f1a 100644
--- a/frontend/src/api/Mod.ts
+++ b/frontend/src/api/Mod.ts
@@ -1,6 +1,6 @@
1import axios from 'axios'; 1import axios from "axios";
2import { url } from '@api/Api'; 2import { url } from "@api/Api";
3import { ModMenuContent } from '@customTypes/Content'; 3import { ModMenuContent } from "@customTypes/Content";
4 4
5export const put_map_image = async ( 5export const put_map_image = async (
6 token: string, 6 token: string,
diff --git a/frontend/src/api/Rankings.ts b/frontend/src/api/Rankings.ts
index 9afd999..b8d9bec 100644
--- a/frontend/src/api/Rankings.ts
+++ b/frontend/src/api/Rankings.ts
@@ -1,6 +1,6 @@
1import axios from 'axios'; 1import axios from "axios";
2import { url } from '@api/Api'; 2import { url } from "@api/Api";
3import { Ranking, SteamRanking } from '@customTypes/Ranking'; 3import { Ranking, SteamRanking } from "@customTypes/Ranking";
4 4
5export const get_official_rankings = async (): Promise<Ranking> => { 5export const get_official_rankings = async (): Promise<Ranking> => {
6 const response = await axios.get(url(`rankings/lphub`)); 6 const response = await axios.get(url(`rankings/lphub`));
diff --git a/frontend/src/api/User.ts b/frontend/src/api/User.ts
index 4ce21e1..004aa22 100644
--- a/frontend/src/api/User.ts
+++ b/frontend/src/api/User.ts
@@ -1,6 +1,6 @@
1import axios from 'axios'; 1import axios from "axios";
2import { url } from '@api/Api'; 2import { url } from "@api/Api";
3import { UserProfile } from '@customTypes/Profile'; 3import { UserProfile } from "@customTypes/Profile";
4 4
5export const get_user = async (user_id: string): Promise<UserProfile> => { 5export const get_user = async (user_id: string): Promise<UserProfile> => {
6 const response = await axios.get(url(`users/${user_id}`)); 6 const response = await axios.get(url(`users/${user_id}`));
diff --git a/frontend/src/components/ConfirmDialog.tsx b/frontend/src/components/ConfirmDialog.tsx
index 925118d..c89d9ea 100644
--- a/frontend/src/components/ConfirmDialog.tsx
+++ b/frontend/src/components/ConfirmDialog.tsx
@@ -1,6 +1,6 @@
1import React from 'react'; 1import React from "react";
2 2
3import '@css/Dialog.css'; 3import "@css/Dialog.css";
4 4
5interface ConfirmDialogProps { 5interface ConfirmDialogProps {
6 title: string; 6 title: string;
diff --git a/frontend/src/components/Discussions.tsx b/frontend/src/components/Discussions.tsx
index 994cd8e..7aa8901 100644
--- a/frontend/src/components/Discussions.tsx
+++ b/frontend/src/components/Discussions.tsx
@@ -1,16 +1,16 @@
1import React from 'react'; 1import React from "react";
2 2
3import { 3import {
4 MapDiscussion, 4 MapDiscussion,
5 MapDiscussions, 5 MapDiscussions,
6 MapDiscussionsDetail, 6 MapDiscussionsDetail,
7} from '@customTypes/Map'; 7} from "@customTypes/Map";
8import { MapDiscussionContent } from '@customTypes/Content'; 8import { MapDiscussionContent } from "@customTypes/Content";
9import { time_ago } from '@utils/Time'; 9import { time_ago } from "@utils/Time";
10import { API } from '@api/Api'; 10import { API } from "@api/Api";
11import '@css/Maps.css'; 11import "@css/Maps.css";
12import { Link } from 'react-router-dom'; 12import { Link } from "react-router-dom";
13import useConfirm from '@hooks/UseConfirm'; 13import useConfirm from "@hooks/UseConfirm";
14 14
15interface DiscussionsProps { 15interface DiscussionsProps {
16 token?: string; 16 token?: string;
@@ -32,17 +32,17 @@ const Discussions: React.FC<DiscussionsProps> = ({
32 const [discussionThread, setDiscussionThread] = React.useState< 32 const [discussionThread, setDiscussionThread] = React.useState<
33 MapDiscussion | undefined 33 MapDiscussion | undefined
34 >(undefined); 34 >(undefined);
35 const [discussionSearch, setDiscussionSearch] = React.useState<string>(''); 35 const [discussionSearch, setDiscussionSearch] = React.useState<string>("");
36 36
37 const [createDiscussion, setCreateDiscussion] = 37 const [createDiscussion, setCreateDiscussion] =
38 React.useState<boolean>(false); 38 React.useState<boolean>(false);
39 const [createDiscussionContent, setCreateDiscussionContent] = 39 const [createDiscussionContent, setCreateDiscussionContent] =
40 React.useState<MapDiscussionContent>({ 40 React.useState<MapDiscussionContent>({
41 title: '', 41 title: "",
42 content: '', 42 content: "",
43 }); 43 });
44 const [createDiscussionCommentContent, setCreateDiscussionCommentContent] = 44 const [createDiscussionCommentContent, setCreateDiscussionCommentContent] =
45 React.useState<string>(''); 45 React.useState<string>("");
46 46
47 const _open_map_discussion = async (discussion_id: number) => { 47 const _open_map_discussion = async (discussion_id: number) => {
48 const mapDiscussion = await API.get_map_discussion(mapID, discussion_id); 48 const mapDiscussion = await API.get_map_discussion(mapID, discussion_id);
@@ -72,7 +72,7 @@ const Discussions: React.FC<DiscussionsProps> = ({
72 const _delete_map_discussion = async (discussion: MapDiscussionsDetail) => { 72 const _delete_map_discussion = async (discussion: MapDiscussionsDetail) => {
73 if ( 73 if (
74 await confirm( 74 await confirm(
75 'Delete Map Discussion', 75 "Delete Map Discussion",
76 `Are you sure you want to remove post: ${discussion.title}?` 76 `Are you sure you want to remove post: ${discussion.title}?`
77 ) 77 )
78 ) { 78 ) {
@@ -90,7 +90,7 @@ const Discussions: React.FC<DiscussionsProps> = ({
90 <input 90 <input
91 type="text" 91 type="text"
92 value={discussionSearch} 92 value={discussionSearch}
93 placeholder={'Search for posts...'} 93 placeholder={"Search for posts..."}
94 onChange={e => setDiscussionSearch(e.target.value)} 94 onChange={e => setDiscussionSearch(e.target.value)}
95 /> 95 />
96 <div> 96 <div>
@@ -104,7 +104,7 @@ const Discussions: React.FC<DiscussionsProps> = ({
104 <div id="discussion-create"> 104 <div id="discussion-create">
105 <span>Create Post</span> 105 <span>Create Post</span>
106 <button onClick={() => setCreateDiscussion(false)}>X</button> 106 <button onClick={() => setCreateDiscussion(false)}>X</button>
107 <div style={{ gridColumn: '1 / span 2' }}> 107 <div style={{ gridColumn: "1 / span 2" }}>
108 <input 108 <input
109 id="discussion-create-title" 109 id="discussion-create-title"
110 placeholder="Title..." 110 placeholder="Title..."
@@ -126,7 +126,7 @@ const Discussions: React.FC<DiscussionsProps> = ({
126 } 126 }
127 /> 127 />
128 </div> 128 </div>
129 <div style={{ placeItems: 'end', gridColumn: '1 / span 2' }}> 129 <div style={{ placeItems: "end", gridColumn: "1 / span 2" }}>
130 <button 130 <button
131 id="discussion-create-button" 131 id="discussion-create-button"
132 onClick={() => _create_map_discussion()} 132 onClick={() => _create_map_discussion()}
@@ -157,8 +157,8 @@ const Discussions: React.FC<DiscussionsProps> = ({
157 {time_ago( 157 {time_ago(
158 new Date( 158 new Date(
159 discussionThread.discussion.created_at 159 discussionThread.discussion.created_at
160 .replace('T', ' ') 160 .replace("T", " ")
161 .replace('Z', '') 161 .replace("Z", "")
162 ) 162 )
163 )} 163 )}
164 </span> 164 </span>
@@ -180,7 +180,7 @@ const Discussions: React.FC<DiscussionsProps> = ({
180 <span> 180 <span>
181 {time_ago( 181 {time_ago(
182 new Date( 182 new Date(
183 e.date.replace('T', ' ').replace('Z', '') 183 e.date.replace("T", " ").replace("Z", "")
184 ) 184 )
185 )} 185 )}
186 </span> 186 </span>
@@ -188,15 +188,15 @@ const Discussions: React.FC<DiscussionsProps> = ({
188 </div> 188 </div>
189 </> 189 </>
190 )) 190 ))
191 : ''} 191 : ""}
192 </div> 192 </div>
193 <div id="discussion-send"> 193 <div id="discussion-send">
194 <input 194 <input
195 type="text" 195 type="text"
196 value={createDiscussionCommentContent} 196 value={createDiscussionCommentContent}
197 placeholder={'Message'} 197 placeholder={"Message"}
198 onKeyDown={e => 198 onKeyDown={e =>
199 e.key === 'Enter' && 199 e.key === "Enter" &&
200 _create_map_discussion_comment(discussionThread.discussion.id) 200 _create_map_discussion_comment(discussionThread.discussion.id)
201 } 201 }
202 onChange={e => 202 onChange={e =>
@@ -206,11 +206,11 @@ const Discussions: React.FC<DiscussionsProps> = ({
206 <div> 206 <div>
207 <button 207 <button
208 onClick={() => { 208 onClick={() => {
209 if (createDiscussionCommentContent !== '') { 209 if (createDiscussionCommentContent !== "") {
210 _create_map_discussion_comment( 210 _create_map_discussion_comment(
211 discussionThread.discussion.id 211 discussionThread.discussion.id
212 ); 212 );
213 setCreateDiscussionCommentContent(''); 213 setCreateDiscussionCommentContent("");
214 } 214 }
215 }} 215 }}
216 > 216 >
@@ -248,10 +248,10 @@ const Discussions: React.FC<DiscussionsProps> = ({
248 <b>{e.creator.user_name}:</b> {e.content} 248 <b>{e.creator.user_name}:</b> {e.content}
249 </span> 249 </span>
250 <span> 250 <span>
251 Last Updated:{' '} 251 Last Updated:{" "}
252 {time_ago( 252 {time_ago(
253 new Date( 253 new Date(
254 e.updated_at.replace('T', ' ').replace('Z', '') 254 e.updated_at.replace("T", " ").replace("Z", "")
255 ) 255 )
256 )} 256 )}
257 </span> 257 </span>
@@ -260,7 +260,7 @@ const Discussions: React.FC<DiscussionsProps> = ({
260 ))} 260 ))}
261 </> 261 </>
262 ) : ( 262 ) : (
263 <span style={{ textAlign: 'center', display: 'block' }}> 263 <span style={{ textAlign: "center", display: "block" }}>
264 No Discussions... 264 No Discussions...
265 </span> 265 </span>
266 ) 266 )
diff --git a/frontend/src/components/GameCategory.tsx b/frontend/src/components/GameCategory.tsx
index b13be48..2bb6d42 100644
--- a/frontend/src/components/GameCategory.tsx
+++ b/frontend/src/components/GameCategory.tsx
@@ -1,8 +1,8 @@
1import React from 'react'; 1import React from "react";
2import { Link } from 'react-router-dom'; 2import { Link } from "react-router-dom";
3 3
4import { Game, GameCategoryPortals } from '@customTypes/Game'; 4import { Game, GameCategoryPortals } from "@customTypes/Game";
5import '@css/Games.css'; 5import "@css/Games.css";
6 6
7interface GameCategoryProps { 7interface GameCategoryProps {
8 game: Game; 8 game: Game;
@@ -13,7 +13,7 @@ const GameCategory: React.FC<GameCategoryProps> = ({ cat, game }) => {
13 return ( 13 return (
14 <Link 14 <Link
15 className="games-page-item-body-item" 15 className="games-page-item-body-item"
16 to={'/games/' + game.id + '?cat=' + cat.category.id} 16 to={"/games/" + game.id + "?cat=" + cat.category.id}
17 > 17 >
18 <div> 18 <div>
19 <span className="games-page-item-body-item-title"> 19 <span className="games-page-item-body-item-title">
diff --git a/frontend/src/components/GameEntry.tsx b/frontend/src/components/GameEntry.tsx
index b58bbdd..04c3483 100644
--- a/frontend/src/components/GameEntry.tsx
+++ b/frontend/src/components/GameEntry.tsx
@@ -1,10 +1,10 @@
1import React from 'react'; 1import React from "react";
2import { Link } from 'react-router-dom'; 2import { Link } from "react-router-dom";
3 3
4import { Game, GameCategoryPortals } from '@customTypes/Game'; 4import { Game, GameCategoryPortals } from "@customTypes/Game";
5import '@css/Games.css'; 5import "@css/Games.css";
6 6
7import GameCategory from '@components/GameCategory'; 7import GameCategory from "@components/GameCategory";
8 8
9interface GameEntryProps { 9interface GameEntryProps {
10 game: Game; 10 game: Game;
@@ -18,7 +18,7 @@ const GameEntry: React.FC<GameEntryProps> = ({ game }) => {
18 }, [game.category_portals]); 18 }, [game.category_portals]);
19 19
20 return ( 20 return (
21 <Link to={'/games/' + game.id}> 21 <Link to={"/games/" + game.id}>
22 <div className="games-page-item"> 22 <div className="games-page-item">
23 <div className="games-page-item-header"> 23 <div className="games-page-item-header">
24 <div 24 <div
diff --git a/frontend/src/components/Leaderboards.tsx b/frontend/src/components/Leaderboards.tsx
index 801f331..b388aba 100644
--- a/frontend/src/components/Leaderboards.tsx
+++ b/frontend/src/components/Leaderboards.tsx
@@ -1,12 +1,12 @@
1import React, { useCallback } from 'react'; 1import React, { useCallback } from "react";
2import { Link, useNavigate } from 'react-router-dom'; 2import { Link, useNavigate } from "react-router-dom";
3 3
4import { DownloadIcon, ThreedotIcon } from '@images/Images'; 4import { DownloadIcon, ThreedotIcon } from "@images/Images";
5import { MapLeaderboard } from '@customTypes/Map'; 5import { MapLeaderboard } from "@customTypes/Map";
6import { ticks_to_time, time_ago } from '@utils/Time'; 6import { ticks_to_time, time_ago } from "@utils/Time";
7import { API } from '@api/Api'; 7import { API } from "@api/Api";
8import useMessage from '@hooks/UseMessage'; 8import useMessage from "@hooks/UseMessage";
9import '@css/Maps.css'; 9import "@css/Maps.css";
10 10
11interface LeaderboardsProps { 11interface LeaderboardsProps {
12 mapID: string; 12 mapID: string;
@@ -35,7 +35,7 @@ const Leaderboards: React.FC<LeaderboardsProps> = ({ mapID }) => {
35 if (!data) { 35 if (!data) {
36 return ( 36 return (
37 <section id="section6" className="summary2"> 37 <section id="section6" className="summary2">
38 <h1 style={{ textAlign: 'center' }}> 38 <h1 style={{ textAlign: "center" }}>
39 Map is not available for competitive boards. 39 Map is not available for competitive boards.
40 </h1> 40 </h1>
41 </section> 41 </section>
@@ -45,7 +45,7 @@ const Leaderboards: React.FC<LeaderboardsProps> = ({ mapID }) => {
45 if (data.records.length === 0) { 45 if (data.records.length === 0) {
46 return ( 46 return (
47 <section id="section6" className="summary2"> 47 <section id="section6" className="summary2">
48 <h1 style={{ textAlign: 'center' }}>No records found.</h1> 48 <h1 style={{ textAlign: "center" }}>No records found.</h1>
49 </section> 49 </section>
50 ); 50 );
51 } 51 }
@@ -58,8 +58,8 @@ const Leaderboards: React.FC<LeaderboardsProps> = ({ mapID }) => {
58 id="leaderboard-top" 58 id="leaderboard-top"
59 style={ 59 style={
60 data.map.is_coop 60 data.map.is_coop
61 ? { gridTemplateColumns: '7.5% 40% 7.5% 15% 15% 15%' } 61 ? { gridTemplateColumns: "7.5% 40% 7.5% 15% 15% 15%" }
62 : { gridTemplateColumns: '7.5% 30% 10% 20% 17.5% 15%' } 62 : { gridTemplateColumns: "7.5% 30% 10% 20% 17.5% 15%" }
63 } 63 }
64 > 64 >
65 <span>Place</span> 65 <span>Place</span>
@@ -87,8 +87,8 @@ const Leaderboards: React.FC<LeaderboardsProps> = ({ mapID }) => {
87 > 87 >
88 <i 88 <i
89 className="triangle" 89 className="triangle"
90 style={{ position: 'relative', left: '-5px' }} 90 style={{ position: "relative", left: "-5px" }}
91 ></i>{' '} 91 ></i>{" "}
92 </button> 92 </button>
93 <span> 93 <span>
94 {data.pagination.current_page}/{data.pagination.total_pages} 94 {data.pagination.current_page}/{data.pagination.total_pages}
@@ -103,11 +103,11 @@ const Leaderboards: React.FC<LeaderboardsProps> = ({ mapID }) => {
103 <i 103 <i
104 className="triangle" 104 className="triangle"
105 style={{ 105 style={{
106 position: 'relative', 106 position: "relative",
107 left: '5px', 107 left: "5px",
108 transform: 'rotate(180deg)', 108 transform: "rotate(180deg)",
109 }} 109 }}
110 ></i>{' '} 110 ></i>{" "}
111 </button> 111 </button>
112 </div> 112 </div>
113 </div> 113 </div>
@@ -120,33 +120,33 @@ const Leaderboards: React.FC<LeaderboardsProps> = ({ mapID }) => {
120 key={index} 120 key={index}
121 style={ 121 style={
122 data.map.is_coop 122 data.map.is_coop
123 ? { gridTemplateColumns: '3% 4.5% 40% 4% 3.5% 15% 15% 14.5%' } 123 ? { gridTemplateColumns: "3% 4.5% 40% 4% 3.5% 15% 15% 14.5%" }
124 : { gridTemplateColumns: '3% 4.5% 30% 4% 6% 20% 17% 15%' } 124 : { gridTemplateColumns: "3% 4.5% 30% 4% 6% 20% 17% 15%" }
125 } 125 }
126 > 126 >
127 <span>{r.placement}</span> 127 <span>{r.placement}</span>
128 <span> </span> 128 <span> </span>
129 {r.kind === 'multiplayer' ? ( 129 {r.kind === "multiplayer" ? (
130 <div> 130 <div>
131 <Link to={`/users/${r.host.steam_id}`}> 131 <Link to={`/users/${r.host.steam_id}`}>
132 <span> 132 <span>
133 <img src={r.host.avatar_link} alt="" /> &nbsp;{' '} 133 <img src={r.host.avatar_link} alt="" /> &nbsp;{" "}
134 {r.host.user_name} 134 {r.host.user_name}
135 </span> 135 </span>
136 </Link> 136 </Link>
137 <Link to={`/users/${r.partner.steam_id}`}> 137 <Link to={`/users/${r.partner.steam_id}`}>
138 <span> 138 <span>
139 <img src={r.partner.avatar_link} alt="" /> &nbsp;{' '} 139 <img src={r.partner.avatar_link} alt="" /> &nbsp;{" "}
140 {r.partner.user_name} 140 {r.partner.user_name}
141 </span> 141 </span>
142 </Link> 142 </Link>
143 </div> 143 </div>
144 ) : ( 144 ) : (
145 r.kind === 'singleplayer' && ( 145 r.kind === "singleplayer" && (
146 <div> 146 <div>
147 <Link to={`/users/${r.user.steam_id}`}> 147 <Link to={`/users/${r.user.steam_id}`}>
148 <span> 148 <span>
149 <img src={r.user.avatar_link} alt="" /> &nbsp;{' '} 149 <img src={r.user.avatar_link} alt="" /> &nbsp;{" "}
150 {r.user.user_name} 150 {r.user.user_name}
151 </span> 151 </span>
152 </Link> 152 </Link>
@@ -158,25 +158,25 @@ const Leaderboards: React.FC<LeaderboardsProps> = ({ mapID }) => {
158 <span> </span> 158 <span> </span>
159 <span 159 <span
160 className="hover-popup" 160 className="hover-popup"
161 popup-text={r.score_time + ' ticks'} 161 popup-text={r.score_time + " ticks"}
162 > 162 >
163 {ticks_to_time(r.score_time)} 163 {ticks_to_time(r.score_time)}
164 </span> 164 </span>
165 <span 165 <span
166 className="hover-popup" 166 className="hover-popup"
167 popup-text={r.record_date.replace('T', ' ').split('.')[0]} 167 popup-text={r.record_date.replace("T", " ").split(".")[0]}
168 > 168 >
169 {time_ago( 169 {time_ago(
170 new Date(r.record_date.replace('T', ' ').replace('Z', '')) 170 new Date(r.record_date.replace("T", " ").replace("Z", ""))
171 )} 171 )}
172 </span> 172 </span>
173 173
174 {r.kind === 'multiplayer' ? ( 174 {r.kind === "multiplayer" ? (
175 <span> 175 <span>
176 <button 176 <button
177 onClick={() => { 177 onClick={() => {
178 message( 178 message(
179 'Demo Information', 179 "Demo Information",
180 `Host Demo ID: ${r.host_demo_id} \nParnter Demo ID: ${r.partner_demo_id}` 180 `Host Demo ID: ${r.host_demo_id} \nParnter Demo ID: ${r.partner_demo_id}`
181 ); 181 );
182 }} 182 }}
@@ -193,7 +193,7 @@ const Leaderboards: React.FC<LeaderboardsProps> = ({ mapID }) => {
193 alt="download" 193 alt="download"
194 style={{ 194 style={{
195 filter: 195 filter:
196 'hue-rotate(160deg) contrast(60%) saturate(1000%)', 196 "hue-rotate(160deg) contrast(60%) saturate(1000%)",
197 }} 197 }}
198 /> 198 />
199 </button> 199 </button>
@@ -207,17 +207,17 @@ const Leaderboards: React.FC<LeaderboardsProps> = ({ mapID }) => {
207 alt="download" 207 alt="download"
208 style={{ 208 style={{
209 filter: 209 filter:
210 'hue-rotate(300deg) contrast(60%) saturate(1000%)', 210 "hue-rotate(300deg) contrast(60%) saturate(1000%)",
211 }} 211 }}
212 /> 212 />
213 </button> 213 </button>
214 </span> 214 </span>
215 ) : ( 215 ) : (
216 r.kind === 'singleplayer' && ( 216 r.kind === "singleplayer" && (
217 <span> 217 <span>
218 <button 218 <button
219 onClick={() => { 219 onClick={() => {
220 message('Demo Information', `Demo ID: ${r.demo_id}`); 220 message("Demo Information", `Demo ID: ${r.demo_id}`);
221 }} 221 }}
222 > 222 >
223 <img src={ThreedotIcon} alt="demo_id" /> 223 <img src={ThreedotIcon} alt="demo_id" />
diff --git a/frontend/src/components/Login.tsx b/frontend/src/components/Login.tsx
index 093e406..1858c48 100644
--- a/frontend/src/components/Login.tsx
+++ b/frontend/src/components/Login.tsx
@@ -1,10 +1,10 @@
1import React from 'react'; 1import React from "react";
2import { Link, useNavigate } from 'react-router-dom'; 2import { Link, useNavigate } from "react-router-dom";
3 3
4import { ExitIcon, UserIcon, LoginIcon } from '@images/Images'; 4import { ExitIcon, UserIcon, LoginIcon } from "@images/Images";
5import { UserProfile } from '@customTypes/Profile'; 5import { UserProfile } from "@customTypes/Profile";
6import { API } from '@api/Api'; 6import { API } from "@api/Api";
7import '@css/Login.css'; 7import "@css/Login.css";
8 8
9interface LoginProps { 9interface LoginProps {
10 setToken: React.Dispatch<React.SetStateAction<string | undefined>>; 10 setToken: React.Dispatch<React.SetStateAction<string | undefined>>;
@@ -16,14 +16,14 @@ const Login: React.FC<LoginProps> = ({ setToken, profile, setProfile }) => {
16 const navigate = useNavigate(); 16 const navigate = useNavigate();
17 17
18 const _login = () => { 18 const _login = () => {
19 window.location.href = '/api/v1/login'; 19 window.location.href = "/api/v1/login";
20 }; 20 };
21 21
22 const _logout = () => { 22 const _logout = () => {
23 setProfile(undefined); 23 setProfile(undefined);
24 setToken(undefined); 24 setToken(undefined);
25 API.delete_token(); 25 API.delete_token();
26 navigate('/'); 26 navigate("/");
27 }; 27 };
28 28
29 return ( 29 return (
diff --git a/frontend/src/components/MapEntry.tsx b/frontend/src/components/MapEntry.tsx
index f1dee5b..985e806 100644
--- a/frontend/src/components/MapEntry.tsx
+++ b/frontend/src/components/MapEntry.tsx
@@ -1,5 +1,5 @@
1import React from 'react'; 1import React from "react";
2import { Link } from 'react-router-dom'; 2import { Link } from "react-router-dom";
3 3
4const MapEntry: React.FC = () => { 4const MapEntry: React.FC = () => {
5 return <div></div>; 5 return <div></div>;
diff --git a/frontend/src/components/MessageDialog.tsx b/frontend/src/components/MessageDialog.tsx
index b739ebc..fcf4d8d 100644
--- a/frontend/src/components/MessageDialog.tsx
+++ b/frontend/src/components/MessageDialog.tsx
@@ -1,6 +1,6 @@
1import React from 'react'; 1import React from "react";
2 2
3import '@css/Dialog.css'; 3import "@css/Dialog.css";
4 4
5interface MessageDialogProps { 5interface MessageDialogProps {
6 title: string; 6 title: string;
diff --git a/frontend/src/components/MessageDialogLoad.tsx b/frontend/src/components/MessageDialogLoad.tsx
index acea27d..64cdd29 100644
--- a/frontend/src/components/MessageDialogLoad.tsx
+++ b/frontend/src/components/MessageDialogLoad.tsx
@@ -1,6 +1,6 @@
1import React from 'react'; 1import React from "react";
2 2
3import '@css/Dialog.css'; 3import "@css/Dialog.css";
4 4
5interface MessageDialogLoadProps { 5interface MessageDialogLoadProps {
6 title: string; 6 title: string;
@@ -18,7 +18,7 @@ const MessageDialogLoad: React.FC<MessageDialogLoadProps> = ({
18 <span>{title}</span> 18 <span>{title}</span>
19 </div> 19 </div>
20 <div className="dialog-element dialog-description"> 20 <div className="dialog-element dialog-description">
21 <div style={{ display: 'flex', justifyContent: 'center' }}> 21 <div style={{ display: "flex", justifyContent: "center" }}>
22 <span className="loader"></span> 22 <span className="loader"></span>
23 </div> 23 </div>
24 </div> 24 </div>
diff --git a/frontend/src/components/ModMenu.tsx b/frontend/src/components/ModMenu.tsx
index 140d6a3..618d1a7 100644
--- a/frontend/src/components/ModMenu.tsx
+++ b/frontend/src/components/ModMenu.tsx
@@ -1,12 +1,12 @@
1import React from 'react'; 1import React from "react";
2import ReactMarkdown from 'react-markdown'; 2import ReactMarkdown from "react-markdown";
3import { useNavigate } from 'react-router-dom'; 3import { useNavigate } from "react-router-dom";
4 4
5import { MapSummary } from '@customTypes/Map'; 5import { MapSummary } from "@customTypes/Map";
6import { ModMenuContent } from '@customTypes/Content'; 6import { ModMenuContent } from "@customTypes/Content";
7import { API } from '@api/Api'; 7import { API } from "@api/Api";
8import '@css/ModMenu.css'; 8import "@css/ModMenu.css";
9import useConfirm from '@hooks/UseConfirm'; 9import useConfirm from "@hooks/UseConfirm";
10 10
11interface ModMenuProps { 11interface ModMenuProps {
12 token?: string; 12 token?: string;
@@ -28,16 +28,16 @@ const ModMenu: React.FC<ModMenuProps> = ({
28 28
29 const [routeContent, setRouteContent] = React.useState<ModMenuContent>({ 29 const [routeContent, setRouteContent] = React.useState<ModMenuContent>({
30 id: 0, 30 id: 0,
31 name: '', 31 name: "",
32 score: 0, 32 score: 0,
33 date: '', 33 date: "",
34 showcase: '', 34 showcase: "",
35 description: 'No description available.', 35 description: "No description available.",
36 category_id: 1, 36 category_id: 1,
37 }); 37 });
38 38
39 const [image, setImage] = React.useState<string>(''); 39 const [image, setImage] = React.useState<string>("");
40 const [md, setMd] = React.useState<string>(''); 40 const [md, setMd] = React.useState<string>("");
41 41
42 const navigate = useNavigate(); 42 const navigate = useNavigate();
43 43
@@ -47,7 +47,7 @@ const ModMenu: React.FC<ModMenuProps> = ({
47 return new Promise(resolve => { 47 return new Promise(resolve => {
48 reader.onload = () => { 48 reader.onload = () => {
49 const img = new Image(); 49 const img = new Image();
50 if (typeof reader.result === 'string') { 50 if (typeof reader.result === "string") {
51 img.src = reader.result; 51 img.src = reader.result;
52 img.onload = () => { 52 img.onload = () => {
53 let { width, height } = img; 53 let { width, height } = img;
@@ -59,10 +59,10 @@ const ModMenu: React.FC<ModMenuProps> = ({
59 width *= 320 / height; 59 width *= 320 / height;
60 height = 320; 60 height = 320;
61 } 61 }
62 const canvas = document.createElement('canvas'); 62 const canvas = document.createElement("canvas");
63 canvas.width = width; 63 canvas.width = width;
64 canvas.height = height; 64 canvas.height = height;
65 canvas.getContext('2d')!.drawImage(img, 0, 0, width, height); 65 canvas.getContext("2d")!.drawImage(img, 0, 0, width, height);
66 resolve(canvas.toDataURL(file.type, 0.6)); 66 resolve(canvas.toDataURL(file.type, 0.6));
67 }; 67 };
68 } 68 }
@@ -73,8 +73,8 @@ const ModMenu: React.FC<ModMenuProps> = ({
73 const _edit_map_summary_image = async () => { 73 const _edit_map_summary_image = async () => {
74 if ( 74 if (
75 await confirm( 75 await confirm(
76 'Edit Map Summary Image', 76 "Edit Map Summary Image",
77 'Are you sure you want to submit this to the database?' 77 "Are you sure you want to submit this to the database?"
78 ) 78 )
79 ) { 79 ) {
80 if (token) { 80 if (token) {
@@ -82,7 +82,7 @@ const ModMenu: React.FC<ModMenuProps> = ({
82 if (success) { 82 if (success) {
83 navigate(0); 83 navigate(0);
84 } else { 84 } else {
85 alert('Error. Check logs.'); 85 alert("Error. Check logs.");
86 } 86 }
87 } 87 }
88 } 88 }
@@ -91,17 +91,17 @@ const ModMenu: React.FC<ModMenuProps> = ({
91 const _edit_map_summary_route = async () => { 91 const _edit_map_summary_route = async () => {
92 if ( 92 if (
93 await confirm( 93 await confirm(
94 'Edit Map Summary Route', 94 "Edit Map Summary Route",
95 'Are you sure you want to submit this to the database?' 95 "Are you sure you want to submit this to the database?"
96 ) 96 )
97 ) { 97 ) {
98 if (token) { 98 if (token) {
99 routeContent.date += 'T00:00:00Z'; 99 routeContent.date += "T00:00:00Z";
100 const success = await API.put_map_summary(token, mapID, routeContent); 100 const success = await API.put_map_summary(token, mapID, routeContent);
101 if (success) { 101 if (success) {
102 navigate(0); 102 navigate(0);
103 } else { 103 } else {
104 alert('Error. Check logs.'); 104 alert("Error. Check logs.");
105 } 105 }
106 } 106 }
107 } 107 }
@@ -110,17 +110,17 @@ const ModMenu: React.FC<ModMenuProps> = ({
110 const _create_map_summary_route = async () => { 110 const _create_map_summary_route = async () => {
111 if ( 111 if (
112 await confirm( 112 await confirm(
113 'Create Map Summary Route', 113 "Create Map Summary Route",
114 'Are you sure you want to submit this to the database?' 114 "Are you sure you want to submit this to the database?"
115 ) 115 )
116 ) { 116 ) {
117 if (token) { 117 if (token) {
118 routeContent.date += 'T00:00:00Z'; 118 routeContent.date += "T00:00:00Z";
119 const success = await API.post_map_summary(token, mapID, routeContent); 119 const success = await API.post_map_summary(token, mapID, routeContent);
120 if (success) { 120 if (success) {
121 navigate(0); 121 navigate(0);
122 } else { 122 } else {
123 alert('Error. Check logs.'); 123 alert("Error. Check logs.");
124 } 124 }
125 } 125 }
126 } 126 }
@@ -129,7 +129,7 @@ const ModMenu: React.FC<ModMenuProps> = ({
129 const _delete_map_summary_route = async () => { 129 const _delete_map_summary_route = async () => {
130 if ( 130 if (
131 await confirm( 131 await confirm(
132 'Delete Map Summary Route', 132 "Delete Map Summary Route",
133 `Are you sure you want to submit this to the database?\n 133 `Are you sure you want to submit this to the database?\n
134 ${data.summary.routes[selectedRun].category.name}\n${data.summary.routes[selectedRun].history.score_count} portals\n${data.summary.routes[selectedRun].history.runner_name}` 134 ${data.summary.routes[selectedRun].category.name}\n${data.summary.routes[selectedRun].history.score_count} portals\n${data.summary.routes[selectedRun].history.runner_name}`
135 ) 135 )
@@ -143,7 +143,7 @@ const ModMenu: React.FC<ModMenuProps> = ({
143 if (success) { 143 if (success) {
144 navigate(0); 144 navigate(0);
145 } else { 145 } else {
146 alert('Error. Check logs.'); 146 alert("Error. Check logs.");
147 } 147 }
148 } 148 }
149 } 149 }
@@ -154,14 +154,14 @@ const ModMenu: React.FC<ModMenuProps> = ({
154 // add route 154 // add route
155 setRouteContent({ 155 setRouteContent({
156 id: 0, 156 id: 0,
157 name: '', 157 name: "",
158 score: 0, 158 score: 0,
159 date: '', 159 date: "",
160 showcase: '', 160 showcase: "",
161 description: 'No description available.', 161 description: "No description available.",
162 category_id: 1, 162 category_id: 1,
163 }); 163 });
164 setMd('No description available.'); 164 setMd("No description available.");
165 } 165 }
166 if (menu === 2) { 166 if (menu === 2) {
167 // edit route 167 // edit route
@@ -169,7 +169,7 @@ const ModMenu: React.FC<ModMenuProps> = ({
169 id: data.summary.routes[selectedRun].route_id, 169 id: data.summary.routes[selectedRun].route_id,
170 name: data.summary.routes[selectedRun].history.runner_name, 170 name: data.summary.routes[selectedRun].history.runner_name,
171 score: data.summary.routes[selectedRun].history.score_count, 171 score: data.summary.routes[selectedRun].history.score_count,
172 date: data.summary.routes[selectedRun].history.date.split('T')[0], 172 date: data.summary.routes[selectedRun].history.date.split("T")[0],
173 showcase: data.summary.routes[selectedRun].showcase, 173 showcase: data.summary.routes[selectedRun].showcase,
174 description: data.summary.routes[selectedRun].description, 174 description: data.summary.routes[selectedRun].description,
175 category_id: data.summary.routes[selectedRun].category.id, 175 category_id: data.summary.routes[selectedRun].category.id,
@@ -179,20 +179,20 @@ const ModMenu: React.FC<ModMenuProps> = ({
179 }, [menu, data.summary.routes, selectedRun]); 179 }, [menu, data.summary.routes, selectedRun]);
180 180
181 React.useEffect(() => { 181 React.useEffect(() => {
182 const modview = document.querySelector('div#modview') as HTMLElement; 182 const modview = document.querySelector("div#modview") as HTMLElement;
183 if (modview) { 183 if (modview) {
184 showButton 184 showButton
185 ? (modview.style.transform = 'translateY(-68%)') 185 ? (modview.style.transform = "translateY(-68%)")
186 : (modview.style.transform = 'translateY(0%)'); 186 : (modview.style.transform = "translateY(0%)");
187 } 187 }
188 188
189 const modview_block = document.querySelector( 189 const modview_block = document.querySelector(
190 '#modview_block' 190 "#modview_block"
191 ) as HTMLElement; 191 ) as HTMLElement;
192 if (modview_block) { 192 if (modview_block) {
193 showButton 193 showButton
194 ? (modview_block.style.display = 'none') 194 ? (modview_block.style.display = "none")
195 : (modview_block.style.display = 'block'); 195 : (modview_block.style.display = "block");
196 } 196 }
197 }, [showButton]); 197 }, [showButton]);
198 198
@@ -322,7 +322,7 @@ const ModMenu: React.FC<ModMenuProps> = ({
322 </div> 322 </div>
323 <div 323 <div
324 id="modview-route-description" 324 id="modview-route-description"
325 style={{ height: '180px', gridColumn: '1 / span 5' }} 325 style={{ height: "180px", gridColumn: "1 / span 5" }}
326 > 326 >
327 <span>Description:</span> 327 <span>Description:</span>
328 <textarea 328 <textarea
@@ -337,7 +337,7 @@ const ModMenu: React.FC<ModMenuProps> = ({
337 /> 337 />
338 </div> 338 </div>
339 <button 339 <button
340 style={{ gridColumn: '2 / span 3', height: '40px' }} 340 style={{ gridColumn: "2 / span 3", height: "40px" }}
341 onClick={_edit_map_summary_route} 341 onClick={_edit_map_summary_route}
342 > 342 >
343 Apply 343 Apply
@@ -391,8 +391,8 @@ const ModMenu: React.FC<ModMenuProps> = ({
391 <option value="2" key="2"> 391 <option value="2" key="2">
392 No SLA 392 No SLA
393 </option> 393 </option>
394 {data.map.game_name === 'Portal 2 - Cooperative' ? ( 394 {data.map.game_name === "Portal 2 - Cooperative" ? (
395 '' 395 ""
396 ) : ( 396 ) : (
397 <option value="3" key="3"> 397 <option value="3" key="3">
398 Inbounds SLA 398 Inbounds SLA
@@ -457,7 +457,7 @@ const ModMenu: React.FC<ModMenuProps> = ({
457 </div> 457 </div>
458 <div 458 <div
459 id="modview-route-description" 459 id="modview-route-description"
460 style={{ height: '180px', gridColumn: '1 / span 5' }} 460 style={{ height: "180px", gridColumn: "1 / span 5" }}
461 > 461 >
462 <span>Description:</span> 462 <span>Description:</span>
463 <textarea 463 <textarea
@@ -472,7 +472,7 @@ const ModMenu: React.FC<ModMenuProps> = ({
472 /> 472 />
473 </div> 473 </div>
474 <button 474 <button
475 style={{ gridColumn: '2 / span 3', height: '40px' }} 475 style={{ gridColumn: "2 / span 3", height: "40px" }}
476 onClick={_create_map_summary_route} 476 onClick={_create_map_summary_route}
477 > 477 >
478 Apply 478 Apply
diff --git a/frontend/src/components/RankingEntry.tsx b/frontend/src/components/RankingEntry.tsx
index f45ca35..f28eabf 100644
--- a/frontend/src/components/RankingEntry.tsx
+++ b/frontend/src/components/RankingEntry.tsx
@@ -1,6 +1,6 @@
1import React from 'react'; 1import React from "react";
2import { Link } from 'react-router-dom'; 2import { Link } from "react-router-dom";
3import { RankingType, SteamRankingType } from '@customTypes/Ranking'; 3import { RankingType, SteamRankingType } from "@customTypes/Ranking";
4 4
5enum RankingCategories { 5enum RankingCategories {
6 rankings_overall, 6 rankings_overall,
@@ -14,7 +14,7 @@ interface RankingEntryProps {
14} 14}
15 15
16const RankingEntry: React.FC<RankingEntryProps> = prop => { 16const RankingEntry: React.FC<RankingEntryProps> = prop => {
17 if ('placement' in prop.curRankingData) { 17 if ("placement" in prop.curRankingData) {
18 return ( 18 return (
19 <div className="leaderboard-entry"> 19 <div className="leaderboard-entry">
20 <span>{prop.curRankingData.placement}</span> 20 <span>{prop.curRankingData.placement}</span>
diff --git a/frontend/src/components/Sidebar.tsx b/frontend/src/components/Sidebar.tsx
index 8216cff..b55d56b 100644
--- a/frontend/src/components/Sidebar.tsx
+++ b/frontend/src/components/Sidebar.tsx
@@ -1,5 +1,5 @@
1import React, { useCallback } from 'react'; 1import React, { useCallback } from "react";
2import { Link, useLocation } from 'react-router-dom'; 2import { Link, useLocation } from "react-router-dom";
3 3
4import { 4import {
5 BookIcon, 5 BookIcon,
@@ -10,12 +10,12 @@ import {
10 PortalIcon, 10 PortalIcon,
11 SearchIcon, 11 SearchIcon,
12 UploadIcon, 12 UploadIcon,
13} from '@images/Images'; 13} from "@images/Images";
14import Login from '@components/Login'; 14import Login from "@components/Login";
15import { UserProfile } from '@customTypes/Profile'; 15import { UserProfile } from "@customTypes/Profile";
16import { Search } from '@customTypes/Search'; 16import { Search } from "@customTypes/Search";
17import { API } from '@api/Api'; 17import { API } from "@api/Api";
18import '@css/Sidebar.css'; 18import "@css/Sidebar.css";
19 19
20interface SidebarProps { 20interface SidebarProps {
21 setToken: React.Dispatch<React.SetStateAction<string | undefined>>; 21 setToken: React.Dispatch<React.SetStateAction<string | undefined>>;
@@ -41,81 +41,81 @@ const Sidebar: React.FC<SidebarProps> = ({
41 41
42 const _handle_sidebar_hide = useCallback(() => { 42 const _handle_sidebar_hide = useCallback(() => {
43 var btn = document.querySelectorAll( 43 var btn = document.querySelectorAll(
44 'button.sidebar-button' 44 "button.sidebar-button"
45 ) as NodeListOf<HTMLElement>; 45 ) as NodeListOf<HTMLElement>;
46 const span = document.querySelectorAll( 46 const span = document.querySelectorAll(
47 'button.sidebar-button>span' 47 "button.sidebar-button>span"
48 ) as NodeListOf<HTMLElement>; 48 ) as NodeListOf<HTMLElement>;
49 const side = document.querySelector('#sidebar-list') as HTMLElement; 49 const side = document.querySelector("#sidebar-list") as HTMLElement;
50 const searchbar = document.querySelector('#searchbar') as HTMLInputElement; 50 const searchbar = document.querySelector("#searchbar") as HTMLInputElement;
51 const uploadRunBtn = document.querySelector( 51 const uploadRunBtn = document.querySelector(
52 '#upload-run' 52 "#upload-run"
53 ) as HTMLInputElement; 53 ) as HTMLInputElement;
54 const uploadRunSpan = document.querySelector( 54 const uploadRunSpan = document.querySelector(
55 '#upload-run>span' 55 "#upload-run>span"
56 ) as HTMLInputElement; 56 ) as HTMLInputElement;
57 57
58 if (isSidebarOpen) { 58 if (isSidebarOpen) {
59 if (profile) { 59 if (profile) {
60 const login = document.querySelectorAll( 60 const login = document.querySelectorAll(
61 '.login>button' 61 ".login>button"
62 )[1] as HTMLElement; 62 )[1] as HTMLElement;
63 login.style.opacity = '1'; 63 login.style.opacity = "1";
64 uploadRunBtn.style.width = '310px'; 64 uploadRunBtn.style.width = "310px";
65 uploadRunBtn.style.padding = '0.4em 0 0 11px'; 65 uploadRunBtn.style.padding = "0.4em 0 0 11px";
66 uploadRunSpan.style.opacity = '0'; 66 uploadRunSpan.style.opacity = "0";
67 setTimeout(() => { 67 setTimeout(() => {
68 uploadRunSpan.style.opacity = '1'; 68 uploadRunSpan.style.opacity = "1";
69 }, 100); 69 }, 100);
70 } 70 }
71 setSidebarOpen(false); 71 setSidebarOpen(false);
72 side.style.width = '320px'; 72 side.style.width = "320px";
73 btn.forEach((e, i) => { 73 btn.forEach((e, i) => {
74 e.style.width = '310px'; 74 e.style.width = "310px";
75 e.style.padding = '0.4em 0 0 11px'; 75 e.style.padding = "0.4em 0 0 11px";
76 setTimeout(() => { 76 setTimeout(() => {
77 span[i].style.opacity = '1'; 77 span[i].style.opacity = "1";
78 }, 100); 78 }, 100);
79 }); 79 });
80 side.style.zIndex = '2'; 80 side.style.zIndex = "2";
81 } else { 81 } else {
82 if (profile) { 82 if (profile) {
83 const login = document.querySelectorAll( 83 const login = document.querySelectorAll(
84 '.login>button' 84 ".login>button"
85 )[1] as HTMLElement; 85 )[1] as HTMLElement;
86 login.style.opacity = '0'; 86 login.style.opacity = "0";
87 uploadRunBtn.style.width = '40px'; 87 uploadRunBtn.style.width = "40px";
88 uploadRunBtn.style.padding = '0.4em 0 0 5px'; 88 uploadRunBtn.style.padding = "0.4em 0 0 5px";
89 uploadRunSpan.style.opacity = '0'; 89 uploadRunSpan.style.opacity = "0";
90 } 90 }
91 setSidebarOpen(true); 91 setSidebarOpen(true);
92 side.style.width = '40px'; 92 side.style.width = "40px";
93 searchbar.focus(); 93 searchbar.focus();
94 btn.forEach((e, i) => { 94 btn.forEach((e, i) => {
95 e.style.width = '40px'; 95 e.style.width = "40px";
96 e.style.padding = '0.4em 0 0 5px'; 96 e.style.padding = "0.4em 0 0 5px";
97 span[i].style.opacity = '0'; 97 span[i].style.opacity = "0";
98 }); 98 });
99 setTimeout(() => { 99 setTimeout(() => {
100 side.style.zIndex = '0'; 100 side.style.zIndex = "0";
101 }, 300); 101 }, 300);
102 } 102 }
103 }, [isSidebarOpen, profile]); 103 }, [isSidebarOpen, profile]);
104 104
105 const handle_sidebar_click = useCallback( 105 const handle_sidebar_click = useCallback(
106 (clicked_sidebar_idx: number) => { 106 (clicked_sidebar_idx: number) => {
107 const btn = document.querySelectorAll('button.sidebar-button'); 107 const btn = document.querySelectorAll("button.sidebar-button");
108 if (isSidebarOpen) { 108 if (isSidebarOpen) {
109 setSidebarOpen(false); 109 setSidebarOpen(false);
110 _handle_sidebar_hide(); 110 _handle_sidebar_hide();
111 } 111 }
112 // clusterfuck 112 // clusterfuck
113 btn.forEach((e, i) => { 113 btn.forEach((e, i) => {
114 btn[i].classList.remove('sidebar-button-selected'); 114 btn[i].classList.remove("sidebar-button-selected");
115 btn[i].classList.add('sidebar-button-deselected'); 115 btn[i].classList.add("sidebar-button-deselected");
116 }); 116 });
117 btn[clicked_sidebar_idx].classList.add('sidebar-button-selected'); 117 btn[clicked_sidebar_idx].classList.add("sidebar-button-selected");
118 btn[clicked_sidebar_idx].classList.remove('sidebar-button-deselected'); 118 btn[clicked_sidebar_idx].classList.remove("sidebar-button-deselected");
119 }, 119 },
120 [isSidebarOpen, _handle_sidebar_hide] 120 [isSidebarOpen, _handle_sidebar_hide]
121 ); 121 );
@@ -134,20 +134,20 @@ const Sidebar: React.FC<SidebarProps> = ({
134 }; 134 };
135 135
136 React.useEffect(() => { 136 React.useEffect(() => {
137 if (path === '/') { 137 if (path === "/") {
138 handle_sidebar_click(1); 138 handle_sidebar_click(1);
139 } else if (path.includes('games')) { 139 } else if (path.includes("games")) {
140 handle_sidebar_click(2); 140 handle_sidebar_click(2);
141 } else if (path.includes('rankings')) { 141 } else if (path.includes("rankings")) {
142 handle_sidebar_click(3); 142 handle_sidebar_click(3);
143 } 143 }
144 // else if (path.includes("news")) { handle_sidebar_click(4) } 144 // else if (path.includes("news")) { handle_sidebar_click(4) }
145 // else if (path.includes("scorelog")) { handle_sidebar_click(5) } 145 // else if (path.includes("scorelog")) { handle_sidebar_click(5) }
146 else if (path.includes('profile')) { 146 else if (path.includes("profile")) {
147 handle_sidebar_click(4); 147 handle_sidebar_click(4);
148 } else if (path.includes('rules')) { 148 } else if (path.includes("rules")) {
149 handle_sidebar_click(5); 149 handle_sidebar_click(5);
150 } else if (path.includes('about')) { 150 } else if (path.includes("about")) {
151 handle_sidebar_click(6); 151 handle_sidebar_click(6);
152 } 152 }
153 }, [path, handle_sidebar_click]); 153 }, [path, handle_sidebar_click]);
@@ -156,9 +156,9 @@ const Sidebar: React.FC<SidebarProps> = ({
156 <div id="sidebar"> 156 <div id="sidebar">
157 <Link to="/" tabIndex={-1}> 157 <Link to="/" tabIndex={-1}>
158 <div id="logo"> 158 <div id="logo">
159 {' '} 159 {" "}
160 {/* logo */} 160 {/* logo */}
161 <img src={LogoIcon} alt="" height={'80px'} /> 161 <img src={LogoIcon} alt="" height={"80px"} />
162 <div id="logo-text"> 162 <div id="logo-text">
163 <span> 163 <span>
164 <b>PORTAL 2</b> 164 <b>PORTAL 2</b>
@@ -169,10 +169,10 @@ const Sidebar: React.FC<SidebarProps> = ({
169 </div> 169 </div>
170 </Link> 170 </Link>
171 <div id="sidebar-list"> 171 <div id="sidebar-list">
172 {' '} 172 {" "}
173 {/* List */} 173 {/* List */}
174 <div id="sidebar-toplist"> 174 <div id="sidebar-toplist">
175 {' '} 175 {" "}
176 {/* Top */} 176 {/* Top */}
177 <button 177 <button
178 className="sidebar-button" 178 className="sidebar-button"
diff --git a/frontend/src/components/Summary.tsx b/frontend/src/components/Summary.tsx
index 9f39506..61e52d4 100644
--- a/frontend/src/components/Summary.tsx
+++ b/frontend/src/components/Summary.tsx
@@ -1,8 +1,8 @@
1import React from 'react'; 1import React from "react";
2import ReactMarkdown from 'react-markdown'; 2import ReactMarkdown from "react-markdown";
3 3
4import { MapSummary } from '@customTypes/Map'; 4import { MapSummary } from "@customTypes/Map";
5import '@css/Maps.css'; 5import "@css/Maps.css";
6 6
7interface SummaryProps { 7interface SummaryProps {
8 selectedRun: number; 8 selectedRun: number;
@@ -20,9 +20,9 @@ const Summary: React.FC<SummaryProps> = ({
20 20
21 const _select_run = React.useCallback( 21 const _select_run = React.useCallback(
22 (idx: number, category_id: number) => { 22 (idx: number, category_id: number) => {
23 let r = document.querySelectorAll('button.record'); 23 let r = document.querySelectorAll("button.record");
24 r.forEach(e => ((e as HTMLElement).style.backgroundColor = '#2b2e46')); 24 r.forEach(e => ((e as HTMLElement).style.backgroundColor = "#2b2e46"));
25 (r[idx] as HTMLElement).style.backgroundColor = '#161723'; 25 (r[idx] as HTMLElement).style.backgroundColor = "#161723";
26 26
27 if (data && data.summary.routes.length !== 0) { 27 if (data && data.summary.routes.length !== 0) {
28 idx += data.summary.routes.filter( 28 idx += data.summary.routes.filter(
@@ -42,9 +42,9 @@ const Summary: React.FC<SummaryProps> = ({
42 } 42 }
43 43
44 const _category_change = React.useCallback(() => { 44 const _category_change = React.useCallback(() => {
45 const btn = document.querySelectorAll('#section3 #category span button'); 45 const btn = document.querySelectorAll("#section3 #category span button");
46 btn.forEach(e => { 46 btn.forEach(e => {
47 (e as HTMLElement).style.backgroundColor = '#2b2e46'; 47 (e as HTMLElement).style.backgroundColor = "#2b2e46";
48 }); 48 });
49 // heavenly father forgive me for i have sinned. TODO: fix this bullshit with dynamic categories 49 // heavenly father forgive me for i have sinned. TODO: fix this bullshit with dynamic categories
50 const idx = 50 const idx =
@@ -53,18 +53,18 @@ const Summary: React.FC<SummaryProps> = ({
53 : data.map.is_coop 53 : data.map.is_coop
54 ? selectedCategory - 3 54 ? selectedCategory - 3
55 : selectedCategory - 1; 55 : selectedCategory - 1;
56 (btn[idx] as HTMLElement).style.backgroundColor = '#202232'; 56 (btn[idx] as HTMLElement).style.backgroundColor = "#202232";
57 }, [selectedCategory, data.map.is_coop]); 57 }, [selectedCategory, data.map.is_coop]);
58 58
59 const _history_change = React.useCallback(() => { 59 const _history_change = React.useCallback(() => {
60 const btn = document.querySelectorAll('#section3 #history span button'); 60 const btn = document.querySelectorAll("#section3 #history span button");
61 btn.forEach(e => { 61 btn.forEach(e => {
62 (e as HTMLElement).style.backgroundColor = '#2b2e46'; 62 (e as HTMLElement).style.backgroundColor = "#2b2e46";
63 }); 63 });
64 (historySelected 64 (historySelected
65 ? (btn[1] as HTMLElement) 65 ? (btn[1] as HTMLElement)
66 : (btn[0] as HTMLElement) 66 : (btn[0] as HTMLElement)
67 ).style.backgroundColor = '#202232'; 67 ).style.backgroundColor = "#202232";
68 }, [historySelected]); 68 }, [historySelected]);
69 69
70 React.useEffect(() => { 70 React.useEffect(() => {
@@ -85,7 +85,7 @@ const Summary: React.FC<SummaryProps> = ({
85 <section id="section3" className="summary1"> 85 <section id="section3" className="summary1">
86 <div 86 <div
87 id="category" 87 id="category"
88 style={data.map.image === '' ? { backgroundColor: '#202232' } : {}} 88 style={data.map.image === "" ? { backgroundColor: "#202232" } : {}}
89 > 89 >
90 <img src={data.map.image} alt="" id="category-image"></img> 90 <img src={data.map.image} alt="" id="category-image"></img>
91 <p> 91 <p>
@@ -97,7 +97,7 @@ const Summary: React.FC<SummaryProps> = ({
97 : ` portals`} 97 : ` portals`}
98 </p> 98 </p>
99 {data.map.is_coop ? ( // TODO: make this part dynamic 99 {data.map.is_coop ? ( // TODO: make this part dynamic
100 <span style={{ gridTemplateColumns: '1fr 1fr 1fr' }}> 100 <span style={{ gridTemplateColumns: "1fr 1fr 1fr" }}>
101 <button onClick={() => setSelectedCategory(1)}>CM</button> 101 <button onClick={() => setSelectedCategory(1)}>CM</button>
102 <button onClick={() => setSelectedCategory(4)}>Any%</button> 102 <button onClick={() => setSelectedCategory(4)}>Any%</button>
103 <button onClick={() => setSelectedCategory(5)}> 103 <button onClick={() => setSelectedCategory(5)}>
@@ -105,7 +105,7 @@ const Summary: React.FC<SummaryProps> = ({
105 </button> 105 </button>
106 </span> 106 </span>
107 ) : ( 107 ) : (
108 <span style={{ gridTemplateColumns: '1fr 1fr 1fr 1fr' }}> 108 <span style={{ gridTemplateColumns: "1fr 1fr 1fr 1fr" }}>
109 <button onClick={() => setSelectedCategory(1)}>CM</button> 109 <button onClick={() => setSelectedCategory(1)}>CM</button>
110 <button onClick={() => setSelectedCategory(2)}>NoSLA</button> 110 <button onClick={() => setSelectedCategory(2)}>NoSLA</button>
111 <button onClick={() => setSelectedCategory(3)}> 111 <button onClick={() => setSelectedCategory(3)}>
@@ -117,7 +117,7 @@ const Summary: React.FC<SummaryProps> = ({
117 </div> 117 </div>
118 118
119 <div id="history"> 119 <div id="history">
120 <div style={{ display: historySelected ? 'none' : 'block' }}> 120 <div style={{ display: historySelected ? "none" : "block" }}>
121 {data.summary.routes.filter(e => e.category.id === selectedCategory) 121 {data.summary.routes.filter(e => e.category.id === selectedCategory)
122 .length === 0 ? ( 122 .length === 0 ? (
123 <h5>There are no records for this map.</h5> 123 <h5>There are no records for this map.</h5>
@@ -142,8 +142,8 @@ const Summary: React.FC<SummaryProps> = ({
142 > 142 >
143 <span> 143 <span>
144 {new Date(r.history.date).toLocaleDateString( 144 {new Date(r.history.date).toLocaleDateString(
145 'en-US', 145 "en-US",
146 { month: 'long', day: 'numeric', year: 'numeric' } 146 { month: "long", day: "numeric", year: "numeric" }
147 )} 147 )}
148 </span> 148 </span>
149 <span>{r.history.score_count}</span> 149 <span>{r.history.score_count}</span>
@@ -155,7 +155,7 @@ const Summary: React.FC<SummaryProps> = ({
155 )} 155 )}
156 </div> 156 </div>
157 157
158 <div style={{ display: historySelected ? 'block' : 'none' }}> 158 <div style={{ display: historySelected ? "block" : "none" }}>
159 {data.summary.routes.filter(e => e.category.id === selectedCategory) 159 {data.summary.routes.filter(e => e.category.id === selectedCategory)
160 .length === 0 ? ( 160 .length === 0 ? (
161 <h5>There are no records for this map.</h5> 161 <h5>There are no records for this map.</h5>
@@ -178,25 +178,25 @@ const Summary: React.FC<SummaryProps> = ({
178 <span>Difficulty</span> 178 <span>Difficulty</span>
179 {data.summary.routes[selectedRun].rating === 0 && <span>N/A</span>} 179 {data.summary.routes[selectedRun].rating === 0 && <span>N/A</span>}
180 {data.summary.routes[selectedRun].rating === 1 && ( 180 {data.summary.routes[selectedRun].rating === 1 && (
181 <span style={{ color: 'lime' }}>Very easy</span> 181 <span style={{ color: "lime" }}>Very easy</span>
182 )} 182 )}
183 {data.summary.routes[selectedRun].rating === 2 && ( 183 {data.summary.routes[selectedRun].rating === 2 && (
184 <span style={{ color: 'green' }}>Easy</span> 184 <span style={{ color: "green" }}>Easy</span>
185 )} 185 )}
186 {data.summary.routes[selectedRun].rating === 3 && ( 186 {data.summary.routes[selectedRun].rating === 3 && (
187 <span style={{ color: 'yellow' }}>Medium</span> 187 <span style={{ color: "yellow" }}>Medium</span>
188 )} 188 )}
189 {data.summary.routes[selectedRun].rating === 4 && ( 189 {data.summary.routes[selectedRun].rating === 4 && (
190 <span style={{ color: 'orange' }}>Hard</span> 190 <span style={{ color: "orange" }}>Hard</span>
191 )} 191 )}
192 {data.summary.routes[selectedRun].rating === 5 && ( 192 {data.summary.routes[selectedRun].rating === 5 && (
193 <span style={{ color: 'red' }}>Very hard</span> 193 <span style={{ color: "red" }}>Very hard</span>
194 )} 194 )}
195 <div> 195 <div>
196 {data.summary.routes[selectedRun].rating === 1 ? ( 196 {data.summary.routes[selectedRun].rating === 1 ? (
197 <div 197 <div
198 className="difficulty-rating" 198 className="difficulty-rating"
199 style={{ backgroundColor: 'lime' }} 199 style={{ backgroundColor: "lime" }}
200 ></div> 200 ></div>
201 ) : ( 201 ) : (
202 <div className="difficulty-rating"></div> 202 <div className="difficulty-rating"></div>
@@ -204,7 +204,7 @@ const Summary: React.FC<SummaryProps> = ({
204 {data.summary.routes[selectedRun].rating === 2 ? ( 204 {data.summary.routes[selectedRun].rating === 2 ? (
205 <div 205 <div
206 className="difficulty-rating" 206 className="difficulty-rating"
207 style={{ backgroundColor: 'green' }} 207 style={{ backgroundColor: "green" }}
208 ></div> 208 ></div>
209 ) : ( 209 ) : (
210 <div className="difficulty-rating"></div> 210 <div className="difficulty-rating"></div>
@@ -212,7 +212,7 @@ const Summary: React.FC<SummaryProps> = ({
212 {data.summary.routes[selectedRun].rating === 3 ? ( 212 {data.summary.routes[selectedRun].rating === 3 ? (
213 <div 213 <div
214 className="difficulty-rating" 214 className="difficulty-rating"
215 style={{ backgroundColor: 'yellow' }} 215 style={{ backgroundColor: "yellow" }}
216 ></div> 216 ></div>
217 ) : ( 217 ) : (
218 <div className="difficulty-rating"></div> 218 <div className="difficulty-rating"></div>
@@ -220,7 +220,7 @@ const Summary: React.FC<SummaryProps> = ({
220 {data.summary.routes[selectedRun].rating === 4 ? ( 220 {data.summary.routes[selectedRun].rating === 4 ? (
221 <div 221 <div
222 className="difficulty-rating" 222 className="difficulty-rating"
223 style={{ backgroundColor: 'orange' }} 223 style={{ backgroundColor: "orange" }}
224 ></div> 224 ></div>
225 ) : ( 225 ) : (
226 <div className="difficulty-rating"></div> 226 <div className="difficulty-rating"></div>
@@ -228,7 +228,7 @@ const Summary: React.FC<SummaryProps> = ({
228 {data.summary.routes[selectedRun].rating === 5 ? ( 228 {data.summary.routes[selectedRun].rating === 5 ? (
229 <div 229 <div
230 className="difficulty-rating" 230 className="difficulty-rating"
231 style={{ backgroundColor: 'red' }} 231 style={{ backgroundColor: "red" }}
232 ></div> 232 ></div>
233 ) : ( 233 ) : (
234 <div className="difficulty-rating"></div> 234 <div className="difficulty-rating"></div>
@@ -243,18 +243,18 @@ const Summary: React.FC<SummaryProps> = ({
243 243
244 <section id="section5" className="summary1"> 244 <section id="section5" className="summary1">
245 <div id="description"> 245 <div id="description">
246 {data.summary.routes[selectedRun].showcase !== '' ? ( 246 {data.summary.routes[selectedRun].showcase !== "" ? (
247 <iframe 247 <iframe
248 title="Showcase video" 248 title="Showcase video"
249 src={ 249 src={
250 'https://www.youtube.com/embed/' + 250 "https://www.youtube.com/embed/" +
251 _get_youtube_id(data.summary.routes[selectedRun].showcase) 251 _get_youtube_id(data.summary.routes[selectedRun].showcase)
252 } 252 }
253 > 253 >
254 {' '} 254 {" "}
255 </iframe> 255 </iframe>
256 ) : ( 256 ) : (
257 '' 257 ""
258 )} 258 )}
259 <h3>Route Description</h3> 259 <h3>Route Description</h3>
260 <span id="description-text"> 260 <span id="description-text">
diff --git a/frontend/src/components/UploadRunDialog.tsx b/frontend/src/components/UploadRunDialog.tsx
index 5bad80f..d5eabcd 100644
--- a/frontend/src/components/UploadRunDialog.tsx
+++ b/frontend/src/components/UploadRunDialog.tsx
@@ -1,15 +1,15 @@
1import React from 'react'; 1import React from "react";
2import { UploadRunContent } from '@customTypes/Content'; 2import { UploadRunContent } from "@customTypes/Content";
3import { ScoreboardTempUpdate, SourceDemoParser, NetMessages } from '@nekz/sdp'; 3import { ScoreboardTempUpdate, SourceDemoParser, NetMessages } from "@nekz/sdp";
4 4
5import '@css/UploadRunDialog.css'; 5import "@css/UploadRunDialog.css";
6import { Game } from '@customTypes/Game'; 6import { Game } from "@customTypes/Game";
7import { API } from '@api/Api'; 7import { API } from "@api/Api";
8import { useNavigate } from 'react-router-dom'; 8import { useNavigate } from "react-router-dom";
9import useMessage from '@hooks/UseMessage'; 9import useMessage from "@hooks/UseMessage";
10import useConfirm from '@hooks/UseConfirm'; 10import useConfirm from "@hooks/UseConfirm";
11import useMessageLoad from '@hooks/UseMessageLoad'; 11import useMessageLoad from "@hooks/UseMessageLoad";
12import { MapNames } from '@customTypes/MapNames'; 12import { MapNames } from "@customTypes/MapNames";
13 13
14interface UploadRunDialogProps { 14interface UploadRunDialogProps {
15 token?: string; 15 token?: string;
@@ -38,7 +38,7 @@ const UploadRunDialog: React.FC<UploadRunDialogProps> = ({
38 }); 38 });
39 39
40 const [selectedGameID, setSelectedGameID] = React.useState<number>(0); 40 const [selectedGameID, setSelectedGameID] = React.useState<number>(0);
41 const [selectedGameName, setSelectedGameName] = React.useState<string>(''); 41 const [selectedGameName, setSelectedGameName] = React.useState<string>("");
42 42
43 // dropdowns 43 // dropdowns
44 const [dropdown1Vis, setDropdown1Vis] = React.useState<boolean>(false); 44 const [dropdown1Vis, setDropdown1Vis] = React.useState<boolean>(false);
@@ -102,7 +102,7 @@ const UploadRunDialog: React.FC<UploadRunDialogProps> = ({
102 setDropdown1Vis(!dropdown1Vis); 102 setDropdown1Vis(!dropdown1Vis);
103 } else if (dropdown === 2) { 103 } else if (dropdown === 2) {
104 setDropdown2Vis(!dropdown2Vis); 104 setDropdown2Vis(!dropdown2Vis);
105 document.querySelector('#dropdown2')?.scrollTo(0, 0); 105 document.querySelector("#dropdown2")?.scrollTo(0, 0);
106 } 106 }
107 }; 107 };
108 108
@@ -133,15 +133,15 @@ const UploadRunDialog: React.FC<UploadRunDialogProps> = ({
133 if (token) { 133 if (token) {
134 if (games[selectedGameID].is_coop) { 134 if (games[selectedGameID].is_coop) {
135 if (uploadRunContent.host_demo === null) { 135 if (uploadRunContent.host_demo === null) {
136 await message('Error', 'You must select a host demo to upload.'); 136 await message("Error", "You must select a host demo to upload.");
137 return; 137 return;
138 } else if (uploadRunContent.partner_demo === null) { 138 } else if (uploadRunContent.partner_demo === null) {
139 await message('Error', 'You must select a partner demo to upload.'); 139 await message("Error", "You must select a partner demo to upload.");
140 return; 140 return;
141 } 141 }
142 } else { 142 } else {
143 if (uploadRunContent.host_demo === null) { 143 if (uploadRunContent.host_demo === null) {
144 await message('Error', 'You must select a demo to upload.'); 144 await message("Error", "You must select a demo to upload.");
145 return; 145 return;
146 } 146 }
147 } 147 }
@@ -157,7 +157,7 @@ const UploadRunDialog: React.FC<UploadRunDialogProps> = ({
157 157
158 if (!scoreboard) { 158 if (!scoreboard) {
159 await message( 159 await message(
160 'Error', 160 "Error",
161 "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." 161 "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."
162 ); 162 );
163 return; 163 return;
@@ -165,22 +165,22 @@ const UploadRunDialog: React.FC<UploadRunDialogProps> = ({
165 165
166 if (!demo.mapName || !MapNames[demo.mapName]) { 166 if (!demo.mapName || !MapNames[demo.mapName]) {
167 await message( 167 await message(
168 'Error', 168 "Error",
169 'Error while processing demo: Invalid map name.' 169 "Error while processing demo: Invalid map name."
170 ); 170 );
171 return; 171 return;
172 } 172 }
173 173
174 if (selectedGameID === 0 && MapNames[demo.mapName] > 60) { 174 if (selectedGameID === 0 && MapNames[demo.mapName] > 60) {
175 await message( 175 await message(
176 'Error', 176 "Error",
177 'Error while processing demo: Invalid cooperative demo in singleplayer submission.' 177 "Error while processing demo: Invalid cooperative demo in singleplayer submission."
178 ); 178 );
179 return; 179 return;
180 } else if (selectedGameID === 1 && MapNames[demo.mapName] <= 60) { 180 } else if (selectedGameID === 1 && MapNames[demo.mapName] <= 60) {
181 await message( 181 await message(
182 'Error', 182 "Error",
183 'Error while processing demo: Invalid singleplayer demo in cooperative submission.' 183 "Error while processing demo: Invalid singleplayer demo in cooperative submission."
184 ); 184 );
185 return; 185 return;
186 } 186 }
@@ -189,7 +189,7 @@ const UploadRunDialog: React.FC<UploadRunDialogProps> = ({
189 scoreboard.userMessage?.as<ScoreboardTempUpdate>() ?? {}; 189 scoreboard.userMessage?.as<ScoreboardTempUpdate>() ?? {};
190 190
191 const userConfirmed = await confirm( 191 const userConfirmed = await confirm(
192 'Upload Record', 192 "Upload Record",
193 `Map Name: ${demo.mapName}\nPortal Count: ${portalScore}\nTicks: ${timeScore}\n\nAre you sure you want to upload this demo?` 193 `Map Name: ${demo.mapName}\nPortal Count: ${portalScore}\nTicks: ${timeScore}\n\nAre you sure you want to upload this demo?`
194 ); 194 );
195 195
@@ -197,21 +197,21 @@ const UploadRunDialog: React.FC<UploadRunDialogProps> = ({
197 return; 197 return;
198 } 198 }
199 199
200 messageLoad('Uploading...'); 200 messageLoad("Uploading...");
201 const [success, response] = await API.post_record( 201 const [success, response] = await API.post_record(
202 token, 202 token,
203 uploadRunContent, 203 uploadRunContent,
204 MapNames[demo.mapName] 204 MapNames[demo.mapName]
205 ); 205 );
206 messageLoadClose(); 206 messageLoadClose();
207 await message('Upload Record', response); 207 await message("Upload Record", response);
208 if (success) { 208 if (success) {
209 setUploadRunContent({ 209 setUploadRunContent({
210 host_demo: null, 210 host_demo: null,
211 partner_demo: null, 211 partner_demo: null,
212 }); 212 });
213 onClose(success); 213 onClose(success);
214 navigate('/profile'); 214 navigate("/profile");
215 } 215 }
216 } 216 }
217 }; 217 };
@@ -220,7 +220,7 @@ const UploadRunDialog: React.FC<UploadRunDialogProps> = ({
220 if (open) { 220 if (open) {
221 setDragHighlightPartner(false); 221 setDragHighlightPartner(false);
222 setDragHighlight(false); 222 setDragHighlight(false);
223 _handle_game_select('1', 'Portal 2 - Singleplayer'); // a different approach?. 223 _handle_game_select("1", "Portal 2 - Singleplayer"); // a different approach?.
224 } 224 }
225 }, [open]); 225 }, [open]);
226 226
@@ -236,35 +236,35 @@ const UploadRunDialog: React.FC<UploadRunDialogProps> = ({
236 <div id="upload-run-menu-add"> 236 <div id="upload-run-menu-add">
237 <div id="upload-run-route-category"> 237 <div id="upload-run-route-category">
238 <div 238 <div
239 style={{ padding: '15px 0px' }} 239 style={{ padding: "15px 0px" }}
240 className="upload-run-dropdown-container upload-run-item" 240 className="upload-run-dropdown-container upload-run-item"
241 > 241 >
242 <h3 style={{ margin: '0px 0px' }}>Select Game</h3> 242 <h3 style={{ margin: "0px 0px" }}>Select Game</h3>
243 <div 243 <div
244 onClick={() => _handle_dropdowns(1)} 244 onClick={() => _handle_dropdowns(1)}
245 style={{ 245 style={{
246 display: 'flex', 246 display: "flex",
247 alignItems: 'center', 247 alignItems: "center",
248 cursor: 'pointer', 248 cursor: "pointer",
249 justifyContent: 'space-between', 249 justifyContent: "space-between",
250 margin: '10px 0px', 250 margin: "10px 0px",
251 }} 251 }}
252 > 252 >
253 <div className="dropdown-cur">{selectedGameName}</div> 253 <div className="dropdown-cur">{selectedGameName}</div>
254 <i 254 <i
255 style={{ 255 style={{
256 rotate: '-90deg', 256 rotate: "-90deg",
257 transform: 'translate(-5px, 10px)', 257 transform: "translate(-5px, 10px)",
258 }} 258 }}
259 className="triangle" 259 className="triangle"
260 ></i> 260 ></i>
261 </div> 261 </div>
262 <div 262 <div
263 style={{ top: '110px' }} 263 style={{ top: "110px" }}
264 className={ 264 className={
265 dropdown1Vis 265 dropdown1Vis
266 ? 'upload-run-dropdown' 266 ? "upload-run-dropdown"
267 : 'upload-run-dropdown hidden' 267 : "upload-run-dropdown hidden"
268 } 268 }
269 > 269 >
270 {games.map(game => ( 270 {games.map(game => (
@@ -284,7 +284,7 @@ const UploadRunDialog: React.FC<UploadRunDialogProps> = ({
284 {!loading && ( 284 {!loading && (
285 <> 285 <>
286 <div> 286 <div>
287 <h3 style={{ margin: '10px 0px' }}>Host Demo</h3> 287 <h3 style={{ margin: "10px 0px" }}>Host Demo</h3>
288 <div 288 <div
289 onClick={() => { 289 onClick={() => {
290 _handle_file_click(true); 290 _handle_file_click(true);
@@ -298,7 +298,7 @@ const UploadRunDialog: React.FC<UploadRunDialogProps> = ({
298 onDragLeave={e => { 298 onDragLeave={e => {
299 _handle_drag_leave(e, true); 299 _handle_drag_leave(e, true);
300 }} 300 }}
301 className={`upload-run-drag-area ${dragHightlight ? 'upload-run-drag-area-highlight' : ''} ${uploadRunContent.host_demo ? 'upload-run-drag-area-hidden' : ''}`} 301 className={`upload-run-drag-area ${dragHightlight ? "upload-run-drag-area-highlight" : ""} ${uploadRunContent.host_demo ? "upload-run-drag-area-hidden" : ""}`}
302 > 302 >
303 <input 303 <input
304 ref={fileInputRef} 304 ref={fileInputRef}
@@ -316,7 +316,7 @@ const UploadRunDialog: React.FC<UploadRunDialogProps> = ({
316 <div> 316 <div>
317 <span 317 <span
318 style={{ 318 style={{
319 fontFamily: 'BarlowSemiCondensed-Regular', 319 fontFamily: "BarlowSemiCondensed-Regular",
320 }} 320 }}
321 > 321 >
322 Or click here 322 Or click here
@@ -324,9 +324,9 @@ const UploadRunDialog: React.FC<UploadRunDialogProps> = ({
324 <br /> 324 <br />
325 <button 325 <button
326 style={{ 326 style={{
327 borderRadius: '24px', 327 borderRadius: "24px",
328 padding: '5px 8px', 328 padding: "5px 8px",
329 margin: '5px 0px', 329 margin: "5px 0px",
330 }} 330 }}
331 > 331 >
332 Upload 332 Upload
@@ -342,7 +342,7 @@ const UploadRunDialog: React.FC<UploadRunDialogProps> = ({
342 {games[selectedGameID].is_coop && ( 342 {games[selectedGameID].is_coop && (
343 <> 343 <>
344 <div> 344 <div>
345 <h3 style={{ margin: '10px 0px' }}>Partner Demo</h3> 345 <h3 style={{ margin: "10px 0px" }}>Partner Demo</h3>
346 <div 346 <div
347 onClick={() => { 347 onClick={() => {
348 _handle_file_click(false); 348 _handle_file_click(false);
@@ -356,7 +356,7 @@ const UploadRunDialog: React.FC<UploadRunDialogProps> = ({
356 onDragLeave={e => { 356 onDragLeave={e => {
357 _handle_drag_leave(e, false); 357 _handle_drag_leave(e, false);
358 }} 358 }}
359 className={`upload-run-drag-area ${dragHightlightPartner ? 'upload-run-drag-area-highlight-partner' : ''} ${uploadRunContent.partner_demo ? 'upload-run-drag-area-hidden' : ''}`} 359 className={`upload-run-drag-area ${dragHightlightPartner ? "upload-run-drag-area-highlight-partner" : ""} ${uploadRunContent.partner_demo ? "upload-run-drag-area-hidden" : ""}`}
360 > 360 >
361 <input 361 <input
362 ref={fileInputRefPartner} 362 ref={fileInputRefPartner}
@@ -367,14 +367,14 @@ const UploadRunDialog: React.FC<UploadRunDialogProps> = ({
367 onChange={e => 367 onChange={e =>
368 _handle_file_change(e.target.files, false) 368 _handle_file_change(e.target.files, false)
369 } 369 }
370 />{' '} 370 />{" "}
371 {!uploadRunContent.partner_demo ? ( 371 {!uploadRunContent.partner_demo ? (
372 <div> 372 <div>
373 <span>Drag and drop</span> 373 <span>Drag and drop</span>
374 <div> 374 <div>
375 <span 375 <span
376 style={{ 376 style={{
377 fontFamily: 'BarlowSemiCondensed-Regular', 377 fontFamily: "BarlowSemiCondensed-Regular",
378 }} 378 }}
379 > 379 >
380 Or click here 380 Or click here
@@ -382,9 +382,9 @@ const UploadRunDialog: React.FC<UploadRunDialogProps> = ({
382 <br /> 382 <br />
383 <button 383 <button
384 style={{ 384 style={{
385 borderRadius: '24px', 385 borderRadius: "24px",
386 padding: '5px 8px', 386 padding: "5px 8px",
387 margin: '5px 0px', 387 margin: "5px 0px",
388 }} 388 }}
389 > 389 >
390 Upload 390 Upload
diff --git a/frontend/src/hooks/UseConfirm.tsx b/frontend/src/hooks/UseConfirm.tsx
index 7b4bffa..4692d53 100644
--- a/frontend/src/hooks/UseConfirm.tsx
+++ b/frontend/src/hooks/UseConfirm.tsx
@@ -1,10 +1,10 @@
1import React, { useState } from 'react'; 1import React, { useState } from "react";
2import ConfirmDialog from '@components/ConfirmDialog'; 2import ConfirmDialog from "@components/ConfirmDialog";
3 3
4const useConfirm = () => { 4const useConfirm = () => {
5 const [isOpen, setIsOpen] = useState(false); 5 const [isOpen, setIsOpen] = useState(false);
6 const [title, setTitle] = useState<string>(''); 6 const [title, setTitle] = useState<string>("");
7 const [subtitle, setSubtitle] = useState<string>(''); 7 const [subtitle, setSubtitle] = useState<string>("");
8 const [resolvePromise, setResolvePromise] = useState< 8 const [resolvePromise, setResolvePromise] = useState<
9 ((value: boolean) => void) | null 9 ((value: boolean) => void) | null
10 >(null); 10 >(null);
diff --git a/frontend/src/hooks/UseMessage.tsx b/frontend/src/hooks/UseMessage.tsx
index e0afa59..b639fac 100644
--- a/frontend/src/hooks/UseMessage.tsx
+++ b/frontend/src/hooks/UseMessage.tsx
@@ -1,11 +1,11 @@
1import React, { useState } from 'react'; 1import React, { useState } from "react";
2import MessageDialog from '@components/MessageDialog'; 2import MessageDialog from "@components/MessageDialog";
3 3
4const useMessage = () => { 4const useMessage = () => {
5 const [isOpen, setIsOpen] = useState(false); 5 const [isOpen, setIsOpen] = useState(false);
6 6
7 const [title, setTitle] = useState<string>(''); 7 const [title, setTitle] = useState<string>("");
8 const [subtitle, setSubtitle] = useState<string>(''); 8 const [subtitle, setSubtitle] = useState<string>("");
9 const [resolvePromise, setResolvePromise] = useState<(() => void) | null>( 9 const [resolvePromise, setResolvePromise] = useState<(() => void) | null>(
10 null 10 null
11 ); 11 );
diff --git a/frontend/src/hooks/UseMessageLoad.tsx b/frontend/src/hooks/UseMessageLoad.tsx
index ea0b5d8..4cbd0f7 100644
--- a/frontend/src/hooks/UseMessageLoad.tsx
+++ b/frontend/src/hooks/UseMessageLoad.tsx
@@ -1,10 +1,10 @@
1import React, { useState } from 'react'; 1import React, { useState } from "react";
2import MessageDialogLoad from '@components/MessageDialogLoad'; 2import MessageDialogLoad from "@components/MessageDialogLoad";
3 3
4const useMessageLoad = () => { 4const useMessageLoad = () => {
5 const [isOpen, setIsOpen] = useState(false); 5 const [isOpen, setIsOpen] = useState(false);
6 6
7 const [title, setTitle] = useState<string>(''); 7 const [title, setTitle] = useState<string>("");
8 const [resolvePromise, setResolvePromise] = useState<(() => void) | null>( 8 const [resolvePromise, setResolvePromise] = useState<(() => void) | null>(
9 null 9 null
10 ); 10 );
diff --git a/frontend/src/images/Images.tsx b/frontend/src/images/Images.tsx
index 9972662..eb12588 100644
--- a/frontend/src/images/Images.tsx
+++ b/frontend/src/images/Images.tsx
@@ -1,26 +1,26 @@
1import logo from './png/logo.png'; 1import logo from "./png/logo.png";
2import login from './png/login.png'; 2import login from "./png/login.png";
3import img1 from './png/1.png'; 3import img1 from "./png/1.png";
4import img2 from './png/2.png'; 4import img2 from "./png/2.png";
5import img3 from './png/3.png'; 5import img3 from "./png/3.png";
6import img4 from './png/4.png'; 6import img4 from "./png/4.png";
7import img5 from './png/5.png'; 7import img5 from "./png/5.png";
8import img6 from './png/6.png'; 8import img6 from "./png/6.png";
9import img7 from './png/7.png'; 9import img7 from "./png/7.png";
10import img8 from './png/8.png'; 10import img8 from "./png/8.png";
11import img9 from './png/9.png'; 11import img9 from "./png/9.png";
12import img10 from './png/10.png'; 12import img10 from "./png/10.png";
13import img11 from './png/11.png'; 13import img11 from "./png/11.png";
14import img12 from './png/12.png'; 14import img12 from "./png/12.png";
15import img13 from './png/13.png'; 15import img13 from "./png/13.png";
16import img14 from './png/14.png'; 16import img14 from "./png/14.png";
17import img15 from './png/15.png'; 17import img15 from "./png/15.png";
18import img16 from './png/16.png'; 18import img16 from "./png/16.png";
19import img17 from './png/17.png'; 19import img17 from "./png/17.png";
20import img18 from './png/18.png'; 20import img18 from "./png/18.png";
21import img19 from './png/19.png'; 21import img19 from "./png/19.png";
22import img20 from './png/20.png'; 22import img20 from "./png/20.png";
23import img21 from './png/21.png'; 23import img21 from "./png/21.png";
24 24
25export const LogoIcon = logo; 25export const LogoIcon = logo;
26export const LoginIcon = login; 26export const LoginIcon = login;
diff --git a/frontend/src/index.tsx b/frontend/src/index.tsx
index 2eef1bc..13d180c 100644
--- a/frontend/src/index.tsx
+++ b/frontend/src/index.tsx
@@ -1,11 +1,11 @@
1import React from 'react'; 1import React from "react";
2import ReactDOM from 'react-dom/client'; 2import ReactDOM from "react-dom/client";
3import { BrowserRouter } from 'react-router-dom'; 3import { BrowserRouter } from "react-router-dom";
4 4
5import App from './App'; 5import App from "./App";
6 6
7const root = ReactDOM.createRoot( 7const root = ReactDOM.createRoot(
8 document.getElementById('root') as HTMLElement 8 document.getElementById("root") as HTMLElement
9); 9);
10 10
11root.render( 11root.render(
diff --git a/frontend/src/pages/About.tsx b/frontend/src/pages/About.tsx
index a5d34f6..5a69bfe 100644
--- a/frontend/src/pages/About.tsx
+++ b/frontend/src/pages/About.tsx
@@ -1,25 +1,25 @@
1import React from 'react'; 1import React from "react";
2import ReactMarkdown from 'react-markdown'; 2import ReactMarkdown from "react-markdown";
3import { Helmet } from 'react-helmet'; 3import { Helmet } from "react-helmet";
4 4
5import '@css/About.css'; 5import "@css/About.css";
6 6
7const About: React.FC = () => { 7const About: React.FC = () => {
8 const [aboutText, setAboutText] = React.useState<string>(''); 8 const [aboutText, setAboutText] = React.useState<string>("");
9 9
10 React.useEffect(() => { 10 React.useEffect(() => {
11 const fetchReadme = async () => { 11 const fetchReadme = async () => {
12 try { 12 try {
13 const response = await fetch( 13 const response = await fetch(
14 'https://raw.githubusercontent.com/pektezol/lphub/main/README.md' 14 "https://raw.githubusercontent.com/pektezol/lphub/main/README.md"
15 ); 15 );
16 if (!response.ok) { 16 if (!response.ok) {
17 throw new Error('Failed to fetch README'); 17 throw new Error("Failed to fetch README");
18 } 18 }
19 const readmeText = await response.text(); 19 const readmeText = await response.text();
20 setAboutText(readmeText); 20 setAboutText(readmeText);
21 } catch (error) { 21 } catch (error) {
22 console.error('Error fetching README:', error); 22 console.error("Error fetching README:", error);
23 } 23 }
24 }; 24 };
25 fetchReadme(); 25 fetchReadme();
diff --git a/frontend/src/pages/Games.tsx b/frontend/src/pages/Games.tsx
index ae0a2d6..d7dacde 100644
--- a/frontend/src/pages/Games.tsx
+++ b/frontend/src/pages/Games.tsx
@@ -1,9 +1,9 @@
1import React from 'react'; 1import React from "react";
2import { Helmet } from 'react-helmet'; 2import { Helmet } from "react-helmet";
3 3
4import GameEntry from '@components/GameEntry'; 4import GameEntry from "@components/GameEntry";
5import { Game } from '@customTypes/Game'; 5import { Game } from "@customTypes/Game";
6import '@css/Maps.css'; 6import "@css/Maps.css";
7 7
8interface GamesProps { 8interface GamesProps {
9 games: Game[]; 9 games: Game[];
@@ -11,17 +11,17 @@ interface GamesProps {
11 11
12const Games: React.FC<GamesProps> = ({ games }) => { 12const Games: React.FC<GamesProps> = ({ games }) => {
13 const _page_load = () => { 13 const _page_load = () => {
14 const loaders = document.querySelectorAll('.loader'); 14 const loaders = document.querySelectorAll(".loader");
15 loaders.forEach(loader => { 15 loaders.forEach(loader => {
16 (loader as HTMLElement).style.display = 'none'; 16 (loader as HTMLElement).style.display = "none";
17 }); 17 });
18 }; 18 };
19 19
20 React.useEffect(() => { 20 React.useEffect(() => {
21 document 21 document
22 .querySelectorAll('.games-page-item-body') 22 .querySelectorAll(".games-page-item-body")
23 .forEach((game, index) => { 23 .forEach((game, index) => {
24 game.innerHTML = ''; 24 game.innerHTML = "";
25 }); 25 });
26 _page_load(); 26 _page_load();
27 }, []); 27 }, []);
diff --git a/frontend/src/pages/Homepage.tsx b/frontend/src/pages/Homepage.tsx
index 859af52..f0c5821 100644
--- a/frontend/src/pages/Homepage.tsx
+++ b/frontend/src/pages/Homepage.tsx
@@ -1,5 +1,5 @@
1import React from 'react'; 1import React from "react";
2import { Helmet } from 'react-helmet'; 2import { Helmet } from "react-helmet";
3 3
4const Homepage: React.FC = () => { 4const Homepage: React.FC = () => {
5 return ( 5 return (
diff --git a/frontend/src/pages/Maplist.tsx b/frontend/src/pages/Maplist.tsx
index 372b800..a7242ef 100644
--- a/frontend/src/pages/Maplist.tsx
+++ b/frontend/src/pages/Maplist.tsx
@@ -1,11 +1,11 @@
1import React, { useEffect } from 'react'; 1import React, { useEffect } from "react";
2import { Link, useLocation, useNavigate, useParams } from 'react-router-dom'; 2import { Link, useLocation, useNavigate, useParams } from "react-router-dom";
3import { Helmet } from 'react-helmet'; 3import { Helmet } from "react-helmet";
4 4
5import '@css/Maplist.css'; 5import "@css/Maplist.css";
6import { API } from '@api/Api'; 6import { API } from "@api/Api";
7import { Game } from '@customTypes/Game'; 7import { Game } from "@customTypes/Game";
8import { GameChapter, GamesChapters } from '@customTypes/Chapters'; 8import { GameChapter, GamesChapters } from "@customTypes/Chapters";
9 9
10const Maplist: React.FC = () => { 10const Maplist: React.FC = () => {
11 const [game, setGame] = React.useState<Game | null>(null); 11 const [game, setGame] = React.useState<Game | null>(null);
@@ -18,7 +18,7 @@ const Maplist: React.FC = () => {
18 const [curChapter, setCurChapter] = React.useState<GameChapter>(); 18 const [curChapter, setCurChapter] = React.useState<GameChapter>();
19 const [numChapters, setNumChapters] = React.useState<number>(0); 19 const [numChapters, setNumChapters] = React.useState<number>(0);
20 20
21 const [dropdownActive, setDropdownActive] = React.useState('none'); 21 const [dropdownActive, setDropdownActive] = React.useState("none");
22 22
23 const params = useParams<{ id: string; chapter: string }>(); 23 const params = useParams<{ id: string; chapter: string }>();
24 const location = useLocation(); 24 const location = useLocation();
@@ -26,7 +26,7 @@ const Maplist: React.FC = () => {
26 26
27 function _update_currently_selected(catNum2: number) { 27 function _update_currently_selected(catNum2: number) {
28 setCurrentlySelected(catNum2); 28 setCurrentlySelected(catNum2);
29 navigate('/games/' + game?.id + '?cat=' + catNum2); 29 navigate("/games/" + game?.id + "?cat=" + catNum2);
30 setHasClicked(true); 30 setHasClicked(true);
31 } 31 }
32 32
@@ -36,23 +36,23 @@ const Maplist: React.FC = () => {
36 }; 36 };
37 37
38 const _handle_dropdown_click = () => { 38 const _handle_dropdown_click = () => {
39 if (dropdownActive === 'none') { 39 if (dropdownActive === "none") {
40 setDropdownActive('block'); 40 setDropdownActive("block");
41 } else { 41 } else {
42 setDropdownActive('none'); 42 setDropdownActive("none");
43 } 43 }
44 }; 44 };
45 45
46 // im sorry but im too lazy to fix this right now 46 // im sorry but im too lazy to fix this right now
47 useEffect(() => { 47 useEffect(() => {
48 // gameID 48 // gameID
49 const gameId = parseFloat(params.id || ''); 49 const gameId = parseFloat(params.id || "");
50 setId(gameId); 50 setId(gameId);
51 51
52 // location query params 52 // location query params
53 const queryParams = new URLSearchParams(location.search); 53 const queryParams = new URLSearchParams(location.search);
54 if (queryParams.get('chapter')) { 54 if (queryParams.get("chapter")) {
55 let cat = parseFloat(queryParams.get('chapter') || ''); 55 let cat = parseFloat(queryParams.get("chapter") || "");
56 if (gameId === 2) { 56 if (gameId === 2) {
57 cat += 10; 57 cat += 10;
58 } 58 }
@@ -82,7 +82,7 @@ const Maplist: React.FC = () => {
82 82
83 useEffect(() => { 83 useEffect(() => {
84 const queryParams = new URLSearchParams(location.search); 84 const queryParams = new URLSearchParams(location.search);
85 if (gameChapters !== undefined && !queryParams.get('chapter')) { 85 if (gameChapters !== undefined && !queryParams.get("chapter")) {
86 _fetch_chapters(gameChapters!.chapters[0].id.toString()); 86 _fetch_chapters(gameChapters!.chapters[0].id.toString());
87 } 87 }
88 }, [gameChapters, location.search]); 88 }, [gameChapters, location.search]);
@@ -92,9 +92,9 @@ const Maplist: React.FC = () => {
92 <Helmet> 92 <Helmet>
93 <title>LPHUB | Maplist</title> 93 <title>LPHUB | Maplist</title>
94 </Helmet> 94 </Helmet>
95 <section style={{ marginTop: '20px' }}> 95 <section style={{ marginTop: "20px" }}>
96 <Link to="/games"> 96 <Link to="/games">
97 <button className="nav-button" style={{ borderRadius: '20px' }}> 97 <button className="nav-button" style={{ borderRadius: "20px" }}>
98 <i className="triangle"></i> 98 <i className="triangle"></i>
99 <span>Games List</span> 99 <span>Games List</span>
100 </button> 100 </button>
@@ -127,8 +127,8 @@ const Maplist: React.FC = () => {
127 className={ 127 className={
128 currentlySelected === cat.category.id || 128 currentlySelected === cat.category.id ||
129 (cat.category.id - 1 === catNum && !hasClicked) 129 (cat.category.id - 1 === catNum && !hasClicked)
130 ? 'game-cat-button selected' 130 ? "game-cat-button selected"
131 : 'game-cat-button' 131 : "game-cat-button"
132 } 132 }
133 onClick={() => { 133 onClick={() => {
134 setCatNum(cat.category.id - 1); 134 setCatNum(cat.category.id - 1);
@@ -147,17 +147,17 @@ const Maplist: React.FC = () => {
147 <div> 147 <div>
148 <span 148 <span
149 style={{ 149 style={{
150 fontSize: '18px', 150 fontSize: "18px",
151 transform: 'translateY(5px)', 151 transform: "translateY(5px)",
152 display: 'block', 152 display: "block",
153 marginTop: '10px', 153 marginTop: "10px",
154 }} 154 }}
155 > 155 >
156 {curChapter?.chapter.name.split(' - ')[0]} 156 {curChapter?.chapter.name.split(" - ")[0]}
157 </span> 157 </span>
158 </div> 158 </div>
159 <div onClick={_handle_dropdown_click} className="dropdown"> 159 <div onClick={_handle_dropdown_click} className="dropdown">
160 <span>{curChapter?.chapter.name.split(' - ')[1]}</span> 160 <span>{curChapter?.chapter.name.split(" - ")[1]}</span>
161 <i className="triangle"></i> 161 <i className="triangle"></i>
162 </div> 162 </div>
163 <div 163 <div
@@ -205,16 +205,16 @@ const Maplist: React.FC = () => {
205 <div 205 <div
206 className={ 206 className={
207 map.difficulty === 0 207 map.difficulty === 0
208 ? 'one' 208 ? "one"
209 : map.difficulty === 1 209 : map.difficulty === 1
210 ? 'two' 210 ? "two"
211 : map.difficulty === 2 211 : map.difficulty === 2
212 ? 'three' 212 ? "three"
213 : map.difficulty === 3 213 : map.difficulty === 3
214 ? 'four' 214 ? "four"
215 : map.difficulty === 4 215 : map.difficulty === 4
216 ? 'five' 216 ? "five"
217 : 'one' 217 : "one"
218 } 218 }
219 > 219 >
220 <div className="difficulty-point"></div> 220 <div className="difficulty-point"></div>
diff --git a/frontend/src/pages/Maps.tsx b/frontend/src/pages/Maps.tsx
index 33bd05b..fbdb8f3 100644
--- a/frontend/src/pages/Maps.tsx
+++ b/frontend/src/pages/Maps.tsx
@@ -1,15 +1,15 @@
1import React from 'react'; 1import React from "react";
2import { Link, useLocation } from 'react-router-dom'; 2import { Link, useLocation } from "react-router-dom";
3import { Helmet } from 'react-helmet'; 3import { Helmet } from "react-helmet";
4 4
5import { PortalIcon, FlagIcon, ChatIcon } from '@images/Images'; 5import { PortalIcon, FlagIcon, ChatIcon } from "@images/Images";
6import Summary from '@components/Summary'; 6import Summary from "@components/Summary";
7import Leaderboards from '@components/Leaderboards'; 7import Leaderboards from "@components/Leaderboards";
8import Discussions from '@components/Discussions'; 8import Discussions from "@components/Discussions";
9import ModMenu from '@components/ModMenu'; 9import ModMenu from "@components/ModMenu";
10import { MapDiscussions, MapLeaderboard, MapSummary } from '@customTypes/Map'; 10import { MapDiscussions, MapLeaderboard, MapSummary } from "@customTypes/Map";
11import { API } from '@api/Api'; 11import { API } from "@api/Api";
12import '@css/Maps.css'; 12import "@css/Maps.css";
13 13
14interface MapProps { 14interface MapProps {
15 token?: string; 15 token?: string;
@@ -33,7 +33,7 @@ const Maps: React.FC<MapProps> = ({ token, isModerator }) => {
33 33
34 const location = useLocation(); 34 const location = useLocation();
35 35
36 const mapID = location.pathname.split('/')[2]; 36 const mapID = location.pathname.split("/")[2];
37 37
38 const _fetch_map_summary = React.useCallback(async () => { 38 const _fetch_map_summary = React.useCallback(async () => {
39 const mapSummary = await API.get_map_summary(mapID); 39 const mapSummary = await API.get_map_summary(mapID);
@@ -41,7 +41,7 @@ const Maps: React.FC<MapProps> = ({ token, isModerator }) => {
41 }, [mapID]); 41 }, [mapID]);
42 42
43 const _fetch_map_leaderboards = React.useCallback(async () => { 43 const _fetch_map_leaderboards = React.useCallback(async () => {
44 const mapLeaderboards = await API.get_map_leaderboard(mapID, '1'); 44 const mapLeaderboards = await API.get_map_leaderboard(mapID, "1");
45 setMapLeaderboardData(mapLeaderboards); 45 setMapLeaderboardData(mapLeaderboards);
46 }, [mapID]); 46 }, [mapID]);
47 47
@@ -71,7 +71,7 @@ const Maps: React.FC<MapProps> = ({ token, isModerator }) => {
71 <Link to="/games"> 71 <Link to="/games">
72 <button 72 <button
73 className="nav-button" 73 className="nav-button"
74 style={{ borderRadius: '20px 20px 20px 20px' }} 74 style={{ borderRadius: "20px 20px 20px 20px" }}
75 > 75 >
76 <i className="triangle"></i> 76 <i className="triangle"></i>
77 <span>Games List</span> 77 <span>Games List</span>
@@ -125,18 +125,18 @@ const Maps: React.FC<MapProps> = ({ token, isModerator }) => {
125 <Link to="/games"> 125 <Link to="/games">
126 <button 126 <button
127 className="nav-button" 127 className="nav-button"
128 style={{ borderRadius: '20px 0px 0px 20px' }} 128 style={{ borderRadius: "20px 0px 0px 20px" }}
129 > 129 >
130 <i className="triangle"></i> 130 <i className="triangle"></i>
131 <span>Games List</span> 131 <span>Games List</span>
132 </button> 132 </button>
133 </Link> 133 </Link>
134 <Link 134 <Link
135 to={`/games/${mapSummaryData.map.is_coop ? '2' : '1'}?chapter=${mapSummaryData.map.chapter_name.split(' ')[1]}`} 135 to={`/games/${mapSummaryData.map.is_coop ? "2" : "1"}?chapter=${mapSummaryData.map.chapter_name.split(" ")[1]}`}
136 > 136 >
137 <button 137 <button
138 className="nav-button" 138 className="nav-button"
139 style={{ borderRadius: '0px 20px 20px 0px', marginLeft: '2px' }} 139 style={{ borderRadius: "0px 20px 20px 0px", marginLeft: "2px" }}
140 > 140 >
141 <i className="triangle"></i> 141 <i className="triangle"></i>
142 <span>{mapSummaryData.map.chapter_name}</span> 142 <span>{mapSummaryData.map.chapter_name}</span>
diff --git a/frontend/src/pages/Profile.tsx b/frontend/src/pages/Profile.tsx
index 8acf746..e2d6000 100644
--- a/frontend/src/pages/Profile.tsx
+++ b/frontend/src/pages/Profile.tsx
@@ -1,6 +1,6 @@
1import React from 'react'; 1import React from "react";
2import { Link, useNavigate } from 'react-router-dom'; 2import { Link, useNavigate } from "react-router-dom";
3import { Helmet } from 'react-helmet'; 3import { Helmet } from "react-helmet";
4 4
5import { 5import {
6 SteamIcon, 6 SteamIcon,
@@ -14,16 +14,16 @@ import {
14 DownloadIcon, 14 DownloadIcon,
15 HistoryIcon, 15 HistoryIcon,
16 DeleteIcon, 16 DeleteIcon,
17} from '@images/Images'; 17} from "@images/Images";
18import { UserProfile } from '@customTypes/Profile'; 18import { UserProfile } from "@customTypes/Profile";
19import { Game, GameChapters } from '@customTypes/Game'; 19import { Game, GameChapters } from "@customTypes/Game";
20import { Map } from '@customTypes/Map'; 20import { Map } from "@customTypes/Map";
21import { ticks_to_time } from '@utils/Time'; 21import { ticks_to_time } from "@utils/Time";
22import '@css/Profile.css'; 22import "@css/Profile.css";
23import { API } from '@api/Api'; 23import { API } from "@api/Api";
24import useConfirm from '@hooks/UseConfirm'; 24import useConfirm from "@hooks/UseConfirm";
25import useMessage from '@hooks/UseMessage'; 25import useMessage from "@hooks/UseMessage";
26import useMessageLoad from '@hooks/UseMessageLoad'; 26import useMessageLoad from "@hooks/UseMessageLoad";
27 27
28interface ProfileProps { 28interface ProfileProps {
29 profile?: UserProfile; 29 profile?: UserProfile;
@@ -46,8 +46,8 @@ const Profile: React.FC<ProfileProps> = ({
46 const [pageNumber, setPageNumber] = React.useState(1); 46 const [pageNumber, setPageNumber] = React.useState(1);
47 const [pageMax, setPageMax] = React.useState(0); 47 const [pageMax, setPageMax] = React.useState(0);
48 48
49 const [game, setGame] = React.useState('0'); 49 const [game, setGame] = React.useState("0");
50 const [chapter, setChapter] = React.useState('0'); 50 const [chapter, setChapter] = React.useState("0");
51 const [chapterData, setChapterData] = React.useState<GameChapters | null>( 51 const [chapterData, setChapterData] = React.useState<GameChapters | null>(
52 null 52 null
53 ); 53 );
@@ -62,17 +62,17 @@ const Profile: React.FC<ProfileProps> = ({
62 }; 62 };
63 63
64 const _get_game_chapters = React.useCallback(async () => { 64 const _get_game_chapters = React.useCallback(async () => {
65 if (game && game !== '0') { 65 if (game && game !== "0") {
66 const gameChapters = await API.get_games_chapters(game); 66 const gameChapters = await API.get_games_chapters(game);
67 setChapterData(gameChapters); 67 setChapterData(gameChapters);
68 } else if (game && game === '0') { 68 } else if (game && game === "0") {
69 setPageMax(Math.ceil(profile!.records.length / 20)); 69 setPageMax(Math.ceil(profile!.records.length / 20));
70 setPageNumber(1); 70 setPageNumber(1);
71 } 71 }
72 }, [game, profile]); 72 }, [game, profile]);
73 73
74 const _get_game_maps = React.useCallback(async () => { 74 const _get_game_maps = React.useCallback(async () => {
75 if (chapter === '0') { 75 if (chapter === "0") {
76 const gameMaps = await API.get_game_maps(game); 76 const gameMaps = await API.get_game_maps(game);
77 setMaps(gameMaps); 77 setMaps(gameMaps);
78 setPageMax(Math.ceil(gameMaps.length / 20)); 78 setPageMax(Math.ceil(gameMaps.length / 20));
@@ -87,29 +87,29 @@ const Profile: React.FC<ProfileProps> = ({
87 87
88 const _delete_submission = async (map_id: number, record_id: number) => { 88 const _delete_submission = async (map_id: number, record_id: number) => {
89 const userConfirmed = await confirm( 89 const userConfirmed = await confirm(
90 'Delete Record', 90 "Delete Record",
91 'Are you sure you want to delete this record?' 91 "Are you sure you want to delete this record?"
92 ); 92 );
93 93
94 if (!userConfirmed) { 94 if (!userConfirmed) {
95 return; 95 return;
96 } 96 }
97 97
98 messageLoad('Deleting...'); 98 messageLoad("Deleting...");
99 99
100 const api_success = await API.delete_map_record(token!, map_id, record_id); 100 const api_success = await API.delete_map_record(token!, map_id, record_id);
101 messageLoadClose(); 101 messageLoadClose();
102 if (api_success) { 102 if (api_success) {
103 await message('Delete Record', 'Successfully deleted record.'); 103 await message("Delete Record", "Successfully deleted record.");
104 onDeleteRecord(); 104 onDeleteRecord();
105 } else { 105 } else {
106 await message('Delete Record', 'Could not delete record.'); 106 await message("Delete Record", "Could not delete record.");
107 } 107 }
108 }; 108 };
109 109
110 React.useEffect(() => { 110 React.useEffect(() => {
111 if (!profile) { 111 if (!profile) {
112 navigate('/'); 112 navigate("/");
113 } 113 }
114 }, [profile, navigate]); 114 }, [profile, navigate]);
115 115
@@ -120,7 +120,7 @@ const Profile: React.FC<ProfileProps> = ({
120 }, [profile, game, _get_game_chapters]); 120 }, [profile, game, _get_game_chapters]);
121 121
122 React.useEffect(() => { 122 React.useEffect(() => {
123 if (profile && game !== '0') { 123 if (profile && game !== "0") {
124 _get_game_maps(); 124 _get_game_maps();
125 } 125 }
126 }, [profile, game, chapter, chapterData, _get_game_maps]); 126 }, [profile, game, chapter, chapterData, _get_game_maps]);
@@ -156,8 +156,8 @@ const Profile: React.FC<ProfileProps> = ({
156 <div> 156 <div>
157 <div>{profile.user_name}</div> 157 <div>{profile.user_name}</div>
158 <div> 158 <div>
159 {profile.country_code === 'XX' ? ( 159 {profile.country_code === "XX" ? (
160 '' 160 ""
161 ) : ( 161 ) : (
162 <img 162 <img
163 src={`https://flagcdn.com/w80/${profile.country_code.toLowerCase()}.jpg`} 163 src={`https://flagcdn.com/w80/${profile.country_code.toLowerCase()}.jpg`}
@@ -177,32 +177,32 @@ const Profile: React.FC<ProfileProps> = ({
177 </div> 177 </div>
178 </div> 178 </div>
179 <div> 179 <div>
180 {profile.links.steam === '-' ? ( 180 {profile.links.steam === "-" ? (
181 '' 181 ""
182 ) : ( 182 ) : (
183 <a href={profile.links.steam}> 183 <a href={profile.links.steam}>
184 <img src={SteamIcon} alt="Steam" /> 184 <img src={SteamIcon} alt="Steam" />
185 </a> 185 </a>
186 )} 186 )}
187 {profile.links.twitch === '-' ? ( 187 {profile.links.twitch === "-" ? (
188 '' 188 ""
189 ) : ( 189 ) : (
190 <a href={profile.links.twitch}> 190 <a href={profile.links.twitch}>
191 <img src={TwitchIcon} alt="Twitch" /> 191 <img src={TwitchIcon} alt="Twitch" />
192 </a> 192 </a>
193 )} 193 )}
194 {profile.links.youtube === '-' ? ( 194 {profile.links.youtube === "-" ? (
195 '' 195 ""
196 ) : ( 196 ) : (
197 <a href={profile.links.youtube}> 197 <a href={profile.links.youtube}>
198 <img src={YouTubeIcon} alt="Youtube" /> 198 <img src={YouTubeIcon} alt="Youtube" />
199 </a> 199 </a>
200 )} 200 )}
201 {profile.links.p2sr === '-' ? ( 201 {profile.links.p2sr === "-" ? (
202 '' 202 ""
203 ) : ( 203 ) : (
204 <a href={profile.links.p2sr}> 204 <a href={profile.links.p2sr}>
205 <img src={PortalIcon} alt="P2SR" style={{ padding: '0' }} /> 205 <img src={PortalIcon} alt="P2SR" style={{ padding: "0" }} />
206 </a> 206 </a>
207 )} 207 )}
208 </div> 208 </div>
@@ -212,8 +212,8 @@ const Profile: React.FC<ProfileProps> = ({
212 <span>Overall</span> 212 <span>Overall</span>
213 <span> 213 <span>
214 {profile.rankings.overall.rank === 0 214 {profile.rankings.overall.rank === 0
215 ? 'N/A ' 215 ? "N/A "
216 : '#' + profile.rankings.overall.rank + ' '} 216 : "#" + profile.rankings.overall.rank + " "}
217 <span> 217 <span>
218 ({profile.rankings.overall.completion_count}/ 218 ({profile.rankings.overall.completion_count}/
219 {profile.rankings.overall.completion_total}) 219 {profile.rankings.overall.completion_total})
@@ -224,8 +224,8 @@ const Profile: React.FC<ProfileProps> = ({
224 <span>Singleplayer</span> 224 <span>Singleplayer</span>
225 <span> 225 <span>
226 {profile.rankings.singleplayer.rank === 0 226 {profile.rankings.singleplayer.rank === 0
227 ? 'N/A ' 227 ? "N/A "
228 : '#' + profile.rankings.singleplayer.rank + ' '} 228 : "#" + profile.rankings.singleplayer.rank + " "}
229 <span> 229 <span>
230 ({profile.rankings.singleplayer.completion_count}/ 230 ({profile.rankings.singleplayer.completion_count}/
231 {profile.rankings.singleplayer.completion_total}) 231 {profile.rankings.singleplayer.completion_total})
@@ -236,8 +236,8 @@ const Profile: React.FC<ProfileProps> = ({
236 <span>Cooperative</span> 236 <span>Cooperative</span>
237 <span> 237 <span>
238 {profile.rankings.cooperative.rank === 0 238 {profile.rankings.cooperative.rank === 0
239 ? 'N/A ' 239 ? "N/A "
240 : '#' + profile.rankings.cooperative.rank + ' '} 240 : "#" + profile.rankings.cooperative.rank + " "}
241 <span> 241 <span>
242 ({profile.rankings.cooperative.completion_count}/ 242 ({profile.rankings.cooperative.completion_count}/
243 {profile.rankings.cooperative.completion_total}) 243 {profile.rankings.cooperative.completion_total})
@@ -267,15 +267,15 @@ const Profile: React.FC<ProfileProps> = ({
267 id="select-game" 267 id="select-game"
268 onChange={() => { 268 onChange={() => {
269 setGame( 269 setGame(
270 (document.querySelector('#select-game') as HTMLInputElement) 270 (document.querySelector("#select-game") as HTMLInputElement)
271 .value 271 .value
272 ); 272 );
273 setChapter('0'); 273 setChapter("0");
274 const chapterSelect = document.querySelector( 274 const chapterSelect = document.querySelector(
275 '#select-chapter' 275 "#select-chapter"
276 ) as HTMLSelectElement; 276 ) as HTMLSelectElement;
277 if (chapterSelect) { 277 if (chapterSelect) {
278 chapterSelect.value = '0'; 278 chapterSelect.value = "0";
279 } 279 }
280 }} 280 }}
281 > 281 >
@@ -290,7 +290,7 @@ const Profile: React.FC<ProfileProps> = ({
290 </select> 290 </select>
291 )} 291 )}
292 292
293 {game === '0' ? ( 293 {game === "0" ? (
294 <select disabled> 294 <select disabled>
295 <option>All Chapters</option> 295 <option>All Chapters</option>
296 </select> 296 </select>
@@ -303,7 +303,7 @@ const Profile: React.FC<ProfileProps> = ({
303 setChapter( 303 setChapter(
304 ( 304 (
305 document.querySelector( 305 document.querySelector(
306 '#select-chapter' 306 "#select-chapter"
307 ) as HTMLInputElement 307 ) as HTMLInputElement
308 ).value 308 ).value
309 ) 309 )
@@ -327,15 +327,15 @@ const Profile: React.FC<ProfileProps> = ({
327 <span>Map Name</span> 327 <span>Map Name</span>
328 <img src={SortIcon} alt="" /> 328 <img src={SortIcon} alt="" />
329 </span> 329 </span>
330 <span style={{ justifyContent: 'center' }}> 330 <span style={{ justifyContent: "center" }}>
331 <span>Portals</span> 331 <span>Portals</span>
332 <img src={SortIcon} alt="" /> 332 <img src={SortIcon} alt="" />
333 </span> 333 </span>
334 <span style={{ justifyContent: 'center' }}> 334 <span style={{ justifyContent: "center" }}>
335 <span>WRΔ </span> 335 <span>WRΔ </span>
336 <img src={SortIcon} alt="" /> 336 <img src={SortIcon} alt="" />
337 </span> 337 </span>
338 <span style={{ justifyContent: 'center' }}> 338 <span style={{ justifyContent: "center" }}>
339 <span>Time</span> 339 <span>Time</span>
340 <img src={SortIcon} alt="" /> 340 <img src={SortIcon} alt="" />
341 </span> 341 </span>
@@ -355,18 +355,18 @@ const Profile: React.FC<ProfileProps> = ({
355 if (pageNumber !== 1) { 355 if (pageNumber !== 1) {
356 setPageNumber(prevPageNumber => prevPageNumber - 1); 356 setPageNumber(prevPageNumber => prevPageNumber - 1);
357 const records = document.querySelectorAll( 357 const records = document.querySelectorAll(
358 '.profileboard-record' 358 ".profileboard-record"
359 ); 359 );
360 records.forEach(r => { 360 records.forEach(r => {
361 (r as HTMLInputElement).style.height = '44px'; 361 (r as HTMLInputElement).style.height = "44px";
362 }); 362 });
363 } 363 }
364 }} 364 }}
365 > 365 >
366 <i 366 <i
367 className="triangle" 367 className="triangle"
368 style={{ position: 'relative', left: '-5px' }} 368 style={{ position: "relative", left: "-5px" }}
369 ></i>{' '} 369 ></i>{" "}
370 </button> 370 </button>
371 <span> 371 <span>
372 {pageNumber}/{pageMax} 372 {pageNumber}/{pageMax}
@@ -376,10 +376,10 @@ const Profile: React.FC<ProfileProps> = ({
376 if (pageNumber !== pageMax) { 376 if (pageNumber !== pageMax) {
377 setPageNumber(prevPageNumber => prevPageNumber + 1); 377 setPageNumber(prevPageNumber => prevPageNumber + 1);
378 const records = document.querySelectorAll( 378 const records = document.querySelectorAll(
379 '.profileboard-record' 379 ".profileboard-record"
380 ); 380 );
381 records.forEach(r => { 381 records.forEach(r => {
382 (r as HTMLInputElement).style.height = '44px'; 382 (r as HTMLInputElement).style.height = "44px";
383 }); 383 });
384 } 384 }
385 }} 385 }}
@@ -387,18 +387,18 @@ const Profile: React.FC<ProfileProps> = ({
387 <i 387 <i
388 className="triangle" 388 className="triangle"
389 style={{ 389 style={{
390 position: 'relative', 390 position: "relative",
391 left: '5px', 391 left: "5px",
392 transform: 'rotate(180deg)', 392 transform: "rotate(180deg)",
393 }} 393 }}
394 ></i>{' '} 394 ></i>{" "}
395 </button> 395 </button>
396 </div> 396 </div>
397 </div> 397 </div>
398 </div> 398 </div>
399 <hr /> 399 <hr />
400 <div id="profileboard-records"> 400 <div id="profileboard-records">
401 {game === '0' ? ( 401 {game === "0" ? (
402 profile.records 402 profile.records
403 .sort((a, b) => a.map_id - b.map_id) 403 .sort((a, b) => a.map_id - b.map_id)
404 .map((r, index) => 404 .map((r, index) =>
@@ -407,25 +407,25 @@ const Profile: React.FC<ProfileProps> = ({
407 {r.scores.map((e, i) => ( 407 {r.scores.map((e, i) => (
408 <> 408 <>
409 {i !== 0 ? ( 409 {i !== 0 ? (
410 <hr style={{ gridColumn: '1 / span 8' }} /> 410 <hr style={{ gridColumn: "1 / span 8" }} />
411 ) : ( 411 ) : (
412 '' 412 ""
413 )} 413 )}
414 414
415 <Link to={`/maps/${r.map_id}`}> 415 <Link to={`/maps/${r.map_id}`}>
416 <span>{r.map_name}</span> 416 <span>{r.map_name}</span>
417 </Link> 417 </Link>
418 418
419 <span style={{ display: 'grid' }}> 419 <span style={{ display: "grid" }}>
420 {e.score_count} 420 {e.score_count}
421 </span> 421 </span>
422 422
423 <span style={{ display: 'grid' }}> 423 <span style={{ display: "grid" }}>
424 {e.score_count - r.map_wr_count > 0 424 {e.score_count - r.map_wr_count > 0
425 ? `+${e.score_count - r.map_wr_count}` 425 ? `+${e.score_count - r.map_wr_count}`
426 : `-`} 426 : `-`}
427 </span> 427 </span>
428 <span style={{ display: 'grid' }}> 428 <span style={{ display: "grid" }}>
429 {ticks_to_time(e.score_time)} 429 {ticks_to_time(e.score_time)}
430 </span> 430 </span>
431 <span> </span> 431 <span> </span>
@@ -434,13 +434,13 @@ const Profile: React.FC<ProfileProps> = ({
434 ) : ( 434 ) : (
435 <span> </span> 435 <span> </span>
436 )} 436 )}
437 <span>{e.date.split('T')[0]}</span> 437 <span>{e.date.split("T")[0]}</span>
438 <span style={{ flexDirection: 'row-reverse' }}> 438 <span style={{ flexDirection: "row-reverse" }}>
439 <button 439 <button
440 style={{ marginRight: '10px' }} 440 style={{ marginRight: "10px" }}
441 onClick={() => { 441 onClick={() => {
442 message( 442 message(
443 'Demo Information', 443 "Demo Information",
444 `Demo ID: ${e.demo_id}` 444 `Demo ID: ${e.demo_id}`
445 ); 445 );
446 }} 446 }}
@@ -466,38 +466,38 @@ const Profile: React.FC<ProfileProps> = ({
466 onClick={() => { 466 onClick={() => {
467 ( 467 (
468 document.querySelectorAll( 468 document.querySelectorAll(
469 '.profileboard-record' 469 ".profileboard-record"
470 )[index % 20] as HTMLInputElement 470 )[index % 20] as HTMLInputElement
471 ).style.height === '44px' || 471 ).style.height === "44px" ||
472 ( 472 (
473 document.querySelectorAll( 473 document.querySelectorAll(
474 '.profileboard-record' 474 ".profileboard-record"
475 )[index % 20] as HTMLInputElement 475 )[index % 20] as HTMLInputElement
476 ).style.height === '' 476 ).style.height === ""
477 ? (( 477 ? ((
478 document.querySelectorAll( 478 document.querySelectorAll(
479 '.profileboard-record' 479 ".profileboard-record"
480 )[index % 20] as HTMLInputElement 480 )[index % 20] as HTMLInputElement
481 ).style.height = 481 ).style.height =
482 `${r.scores.length * 46}px`) 482 `${r.scores.length * 46}px`)
483 : (( 483 : ((
484 document.querySelectorAll( 484 document.querySelectorAll(
485 '.profileboard-record' 485 ".profileboard-record"
486 )[index % 20] as HTMLInputElement 486 )[index % 20] as HTMLInputElement
487 ).style.height = '44px'); 487 ).style.height = "44px");
488 }} 488 }}
489 > 489 >
490 <img src={HistoryIcon} alt="history" /> 490 <img src={HistoryIcon} alt="history" />
491 </button> 491 </button>
492 ) : ( 492 ) : (
493 '' 493 ""
494 )} 494 )}
495 </span> 495 </span>
496 </> 496 </>
497 ))} 497 ))}
498 </button> 498 </button>
499 ) : ( 499 ) : (
500 '' 500 ""
501 ) 501 )
502 ) 502 )
503 ) : maps ? ( 503 ) : maps ? (
@@ -511,42 +511,42 @@ const Profile: React.FC<ProfileProps> = ({
511 <button 511 <button
512 className="profileboard-record" 512 className="profileboard-record"
513 key={index} 513 key={index}
514 style={{ backgroundColor: '#1b1b20' }} 514 style={{ backgroundColor: "#1b1b20" }}
515 > 515 >
516 <Link to={`/maps/${r.id}`}> 516 <Link to={`/maps/${r.id}`}>
517 <span>{r.name}</span> 517 <span>{r.name}</span>
518 </Link> 518 </Link>
519 <span style={{ display: 'grid' }}>N/A</span> 519 <span style={{ display: "grid" }}>N/A</span>
520 <span style={{ display: 'grid' }}>N/A</span> 520 <span style={{ display: "grid" }}>N/A</span>
521 <span>N/A</span> 521 <span>N/A</span>
522 <span> </span> 522 <span> </span>
523 <span>N/A</span> 523 <span>N/A</span>
524 <span>N/A</span> 524 <span>N/A</span>
525 <span style={{ flexDirection: 'row-reverse' }}></span> 525 <span style={{ flexDirection: "row-reverse" }}></span>
526 </button> 526 </button>
527 ) : ( 527 ) : (
528 <button className="profileboard-record" key={index}> 528 <button className="profileboard-record" key={index}>
529 {record.scores.map((e, i) => ( 529 {record.scores.map((e, i) => (
530 <> 530 <>
531 {i !== 0 ? ( 531 {i !== 0 ? (
532 <hr style={{ gridColumn: '1 / span 8' }} /> 532 <hr style={{ gridColumn: "1 / span 8" }} />
533 ) : ( 533 ) : (
534 '' 534 ""
535 )} 535 )}
536 <Link to={`/maps/${r.id}`}> 536 <Link to={`/maps/${r.id}`}>
537 <span>{r.name}</span> 537 <span>{r.name}</span>
538 </Link> 538 </Link>
539 <span style={{ display: 'grid' }}> 539 <span style={{ display: "grid" }}>
540 {record!.scores[i].score_count} 540 {record!.scores[i].score_count}
541 </span> 541 </span>
542 <span style={{ display: 'grid' }}> 542 <span style={{ display: "grid" }}>
543 {record!.scores[i].score_count - 543 {record!.scores[i].score_count -
544 record!.map_wr_count > 544 record!.map_wr_count >
545 0 545 0
546 ? `+${record!.scores[i].score_count - record!.map_wr_count}` 546 ? `+${record!.scores[i].score_count - record!.map_wr_count}`
547 : `-`} 547 : `-`}
548 </span> 548 </span>
549 <span style={{ display: 'grid' }}> 549 <span style={{ display: "grid" }}>
550 {ticks_to_time(record!.scores[i].score_time)} 550 {ticks_to_time(record!.scores[i].score_time)}
551 </span> 551 </span>
552 <span> </span> 552 <span> </span>
@@ -555,12 +555,12 @@ const Profile: React.FC<ProfileProps> = ({
555 ) : ( 555 ) : (
556 <span> </span> 556 <span> </span>
557 )} 557 )}
558 <span>{record!.scores[i].date.split('T')[0]}</span> 558 <span>{record!.scores[i].date.split("T")[0]}</span>
559 <span style={{ flexDirection: 'row-reverse' }}> 559 <span style={{ flexDirection: "row-reverse" }}>
560 <button 560 <button
561 onClick={() => { 561 onClick={() => {
562 message( 562 message(
563 'Demo Information', 563 "Demo Information",
564 `Demo ID: ${e.demo_id}` 564 `Demo ID: ${e.demo_id}`
565 ); 565 );
566 }} 566 }}
@@ -586,31 +586,31 @@ const Profile: React.FC<ProfileProps> = ({
586 onClick={() => { 586 onClick={() => {
587 ( 587 (
588 document.querySelectorAll( 588 document.querySelectorAll(
589 '.profileboard-record' 589 ".profileboard-record"
590 )[index % 20] as HTMLInputElement 590 )[index % 20] as HTMLInputElement
591 ).style.height === '44px' || 591 ).style.height === "44px" ||
592 ( 592 (
593 document.querySelectorAll( 593 document.querySelectorAll(
594 '.profileboard-record' 594 ".profileboard-record"
595 )[index % 20] as HTMLInputElement 595 )[index % 20] as HTMLInputElement
596 ).style.height === '' 596 ).style.height === ""
597 ? (( 597 ? ((
598 document.querySelectorAll( 598 document.querySelectorAll(
599 '.profileboard-record' 599 ".profileboard-record"
600 )[index % 20] as HTMLInputElement 600 )[index % 20] as HTMLInputElement
601 ).style.height = 601 ).style.height =
602 `${record!.scores.length * 46}px`) 602 `${record!.scores.length * 46}px`)
603 : (( 603 : ((
604 document.querySelectorAll( 604 document.querySelectorAll(
605 '.profileboard-record' 605 ".profileboard-record"
606 )[index % 20] as HTMLInputElement 606 )[index % 20] as HTMLInputElement
607 ).style.height = '44px'); 607 ).style.height = "44px");
608 }} 608 }}
609 > 609 >
610 <img src={HistoryIcon} alt="history" /> 610 <img src={HistoryIcon} alt="history" />
611 </button> 611 </button>
612 ) : ( 612 ) : (
613 '' 613 ""
614 )} 614 )}
615 </span> 615 </span>
616 </> 616 </>
diff --git a/frontend/src/pages/Rankings.tsx b/frontend/src/pages/Rankings.tsx
index ab82931..275f9d0 100644
--- a/frontend/src/pages/Rankings.tsx
+++ b/frontend/src/pages/Rankings.tsx
@@ -1,16 +1,16 @@
1import React, { useEffect } from 'react'; 1import React, { useEffect } from "react";
2import { Helmet } from 'react-helmet'; 2import { Helmet } from "react-helmet";
3 3
4import RankingEntry from '@components/RankingEntry'; 4import RankingEntry from "@components/RankingEntry";
5import { 5import {
6 Ranking, 6 Ranking,
7 SteamRanking, 7 SteamRanking,
8 RankingType, 8 RankingType,
9 SteamRankingType, 9 SteamRankingType,
10} from '@customTypes/Ranking'; 10} from "@customTypes/Ranking";
11import { API } from '@api/Api'; 11import { API } from "@api/Api";
12 12
13import '@css/Rankings.css'; 13import "@css/Rankings.css";
14 14
15const Rankings: React.FC = () => { 15const Rankings: React.FC = () => {
16 const [leaderboardData, setLeaderboardData] = React.useState< 16 const [leaderboardData, setLeaderboardData] = React.useState<
@@ -122,7 +122,7 @@ const Rankings: React.FC = () => {
122 _fetch_rankings(); 122 _fetch_rankings();
123 setCurrentRankingType(LeaderboardTypes.official); 123 setCurrentRankingType(LeaderboardTypes.official);
124 }} 124 }}
125 className={`nav-1-btn ${currentRankingType === LeaderboardTypes.official ? 'selected' : ''}`} 125 className={`nav-1-btn ${currentRankingType === LeaderboardTypes.official ? "selected" : ""}`}
126 > 126 >
127 <span>Official (LPHUB)</span> 127 <span>Official (LPHUB)</span>
128 </button> 128 </button>
@@ -131,7 +131,7 @@ const Rankings: React.FC = () => {
131 __dev_fetch_unofficial_rankings(); 131 __dev_fetch_unofficial_rankings();
132 setCurrentRankingType(LeaderboardTypes.unofficial); 132 setCurrentRankingType(LeaderboardTypes.unofficial);
133 }} 133 }}
134 className={`nav-1-btn ${currentRankingType === LeaderboardTypes.unofficial ? 'selected' : ''}`} 134 className={`nav-1-btn ${currentRankingType === LeaderboardTypes.unofficial ? "selected" : ""}`}
135 > 135 >
136 <span>Unofficial (Steam)</span> 136 <span>Unofficial (Steam)</span>
137 </button> 137 </button>
@@ -143,7 +143,7 @@ const Rankings: React.FC = () => {
143 onClick={() => 143 onClick={() =>
144 _set_current_leaderboard(RankingCategories.rankings_singleplayer) 144 _set_current_leaderboard(RankingCategories.rankings_singleplayer)
145 } 145 }
146 className={`nav-2-btn ${currentLeaderboardType === RankingCategories.rankings_singleplayer ? 'selected' : ''}`} 146 className={`nav-2-btn ${currentLeaderboardType === RankingCategories.rankings_singleplayer ? "selected" : ""}`}
147 > 147 >
148 <span>Singleplayer</span> 148 <span>Singleplayer</span>
149 </button> 149 </button>
@@ -151,7 +151,7 @@ const Rankings: React.FC = () => {
151 onClick={() => 151 onClick={() =>
152 _set_current_leaderboard(RankingCategories.rankings_multiplayer) 152 _set_current_leaderboard(RankingCategories.rankings_multiplayer)
153 } 153 }
154 className={`nav-2-btn ${currentLeaderboardType === RankingCategories.rankings_multiplayer ? 'selected' : ''}`} 154 className={`nav-2-btn ${currentLeaderboardType === RankingCategories.rankings_multiplayer ? "selected" : ""}`}
155 > 155 >
156 <span>Cooperative</span> 156 <span>Cooperative</span>
157 </button> 157 </button>
@@ -159,7 +159,7 @@ const Rankings: React.FC = () => {
159 onClick={() => 159 onClick={() =>
160 _set_current_leaderboard(RankingCategories.rankings_overall) 160 _set_current_leaderboard(RankingCategories.rankings_overall)
161 } 161 }
162 className={`nav-2-btn ${currentLeaderboardType === RankingCategories.rankings_overall ? 'selected' : ''}`} 162 className={`nav-2-btn ${currentLeaderboardType === RankingCategories.rankings_overall ? "selected" : ""}`}
163 > 163 >
164 <span>Overall</span> 164 <span>Overall</span>
165 </button> 165 </button>
@@ -191,9 +191,9 @@ const Rankings: React.FC = () => {
191 {leaderboardLoad ? null : ( 191 {leaderboardLoad ? null : (
192 <div 192 <div
193 style={{ 193 style={{
194 display: 'flex', 194 display: "flex",
195 justifyContent: 'center', 195 justifyContent: "center",
196 margin: '30px 0px', 196 margin: "30px 0px",
197 }} 197 }}
198 > 198 >
199 <span className="loader"></span> 199 <span className="loader"></span>
diff --git a/frontend/src/pages/Rules.tsx b/frontend/src/pages/Rules.tsx
index 7a774bc..91027a0 100644
--- a/frontend/src/pages/Rules.tsx
+++ b/frontend/src/pages/Rules.tsx
@@ -1,25 +1,25 @@
1import React from 'react'; 1import React from "react";
2import ReactMarkdown from 'react-markdown'; 2import ReactMarkdown from "react-markdown";
3import { Helmet } from 'react-helmet'; 3import { Helmet } from "react-helmet";
4 4
5import '@css/Rules.css'; 5import "@css/Rules.css";
6 6
7const Rules: React.FC = () => { 7const Rules: React.FC = () => {
8 const [rulesText, setRulesText] = React.useState<string>(''); 8 const [rulesText, setRulesText] = React.useState<string>("");
9 9
10 React.useEffect(() => { 10 React.useEffect(() => {
11 const fetchRules = async () => { 11 const fetchRules = async () => {
12 try { 12 try {
13 const response = await fetch( 13 const response = await fetch(
14 'https://raw.githubusercontent.com/pektezol/lphub/main/RULES.md' 14 "https://raw.githubusercontent.com/pektezol/lphub/main/RULES.md"
15 ); 15 );
16 if (!response.ok) { 16 if (!response.ok) {
17 throw new Error('Failed to fetch README'); 17 throw new Error("Failed to fetch README");
18 } 18 }
19 const rulesText = await response.text(); 19 const rulesText = await response.text();
20 setRulesText(rulesText); 20 setRulesText(rulesText);
21 } catch (error) { 21 } catch (error) {
22 console.error('Error fetching Rules:', error); 22 console.error("Error fetching Rules:", error);
23 } 23 }
24 // setRulesText(rulesText) 24 // setRulesText(rulesText)
25 }; 25 };
diff --git a/frontend/src/pages/User.tsx b/frontend/src/pages/User.tsx
index 29d0041..0198034 100644
--- a/frontend/src/pages/User.tsx
+++ b/frontend/src/pages/User.tsx
@@ -1,6 +1,6 @@
1import React from 'react'; 1import React from "react";
2import { Link, useLocation, useNavigate } from 'react-router-dom'; 2import { Link, useLocation, useNavigate } from "react-router-dom";
3import { Helmet } from 'react-helmet'; 3import { Helmet } from "react-helmet";
4 4
5import { 5import {
6 SteamIcon, 6 SteamIcon,
@@ -13,14 +13,14 @@ import {
13 ThreedotIcon, 13 ThreedotIcon,
14 DownloadIcon, 14 DownloadIcon,
15 HistoryIcon, 15 HistoryIcon,
16} from '@images/Images'; 16} from "@images/Images";
17import { UserProfile } from '@customTypes/Profile'; 17import { UserProfile } from "@customTypes/Profile";
18import { Game, GameChapters } from '@customTypes/Game'; 18import { Game, GameChapters } from "@customTypes/Game";
19import { Map } from '@customTypes/Map'; 19import { Map } from "@customTypes/Map";
20import { API } from '@api/Api'; 20import { API } from "@api/Api";
21import { ticks_to_time } from '@utils/Time'; 21import { ticks_to_time } from "@utils/Time";
22import '@css/Profile.css'; 22import "@css/Profile.css";
23import useMessage from '@hooks/UseMessage'; 23import useMessage from "@hooks/UseMessage";
24 24
25interface UserProps { 25interface UserProps {
26 profile?: UserProfile; 26 profile?: UserProfile;
@@ -37,8 +37,8 @@ const User: React.FC<UserProps> = ({ token, profile, gameData }) => {
37 const [pageNumber, setPageNumber] = React.useState(1); 37 const [pageNumber, setPageNumber] = React.useState(1);
38 const [pageMax, setPageMax] = React.useState(0); 38 const [pageMax, setPageMax] = React.useState(0);
39 39
40 const [game, setGame] = React.useState('0'); 40 const [game, setGame] = React.useState("0");
41 const [chapter, setChapter] = React.useState('0'); 41 const [chapter, setChapter] = React.useState("0");
42 const [chapterData, setChapterData] = React.useState<GameChapters | null>( 42 const [chapterData, setChapterData] = React.useState<GameChapters | null>(
43 null 43 null
44 ); 44 );
@@ -48,9 +48,9 @@ const User: React.FC<UserProps> = ({ token, profile, gameData }) => {
48 const navigate = useNavigate(); 48 const navigate = useNavigate();
49 49
50 const _fetch_user = React.useCallback(async () => { 50 const _fetch_user = React.useCallback(async () => {
51 const userID = location.pathname.split('/')[2]; 51 const userID = location.pathname.split("/")[2];
52 if (token && profile && profile.profile && profile.steam_id === userID) { 52 if (token && profile && profile.profile && profile.steam_id === userID) {
53 navigate('/profile'); 53 navigate("/profile");
54 return; 54 return;
55 } 55 }
56 const userData = await API.get_user(userID); 56 const userData = await API.get_user(userID);
@@ -58,7 +58,7 @@ const User: React.FC<UserProps> = ({ token, profile, gameData }) => {
58 }, [location.pathname, token, profile, navigate]); 58 }, [location.pathname, token, profile, navigate]);
59 59
60 const _get_game_chapters = React.useCallback(async () => { 60 const _get_game_chapters = React.useCallback(async () => {
61 if (game !== '0') { 61 if (game !== "0") {
62 const gameChapters = await API.get_games_chapters(game); 62 const gameChapters = await API.get_games_chapters(game);
63 setChapterData(gameChapters); 63 setChapterData(gameChapters);
64 } else { 64 } else {
@@ -68,7 +68,7 @@ const User: React.FC<UserProps> = ({ token, profile, gameData }) => {
68 }, [game, user]); 68 }, [game, user]);
69 69
70 const _get_game_maps = React.useCallback(async () => { 70 const _get_game_maps = React.useCallback(async () => {
71 if (chapter === '0') { 71 if (chapter === "0") {
72 const gameMaps = await API.get_game_maps(game); 72 const gameMaps = await API.get_game_maps(game);
73 setMaps(gameMaps); 73 setMaps(gameMaps);
74 setPageMax(Math.ceil(gameMaps.length / 20)); 74 setPageMax(Math.ceil(gameMaps.length / 20));
@@ -92,7 +92,7 @@ const User: React.FC<UserProps> = ({ token, profile, gameData }) => {
92 }, [user, game, location, _get_game_chapters]); 92 }, [user, game, location, _get_game_chapters]);
93 93
94 React.useEffect(() => { 94 React.useEffect(() => {
95 if (user && game !== '0') { 95 if (user && game !== "0") {
96 _get_game_maps(); 96 _get_game_maps();
97 } 97 }
98 }, [user, game, chapter, location, _get_game_maps]); 98 }, [user, game, chapter, location, _get_game_maps]);
@@ -116,8 +116,8 @@ const User: React.FC<UserProps> = ({ token, profile, gameData }) => {
116 <div> 116 <div>
117 <div>{user.user_name}</div> 117 <div>{user.user_name}</div>
118 <div> 118 <div>
119 {user.country_code === 'XX' ? ( 119 {user.country_code === "XX" ? (
120 '' 120 ""
121 ) : ( 121 ) : (
122 <img 122 <img
123 src={`https://flagcdn.com/w80/${user.country_code.toLowerCase()}.jpg`} 123 src={`https://flagcdn.com/w80/${user.country_code.toLowerCase()}.jpg`}
@@ -137,32 +137,32 @@ const User: React.FC<UserProps> = ({ token, profile, gameData }) => {
137 </div> 137 </div>
138 </div> 138 </div>
139 <div> 139 <div>
140 {user.links.steam === '-' ? ( 140 {user.links.steam === "-" ? (
141 '' 141 ""
142 ) : ( 142 ) : (
143 <a href={user.links.steam}> 143 <a href={user.links.steam}>
144 <img src={SteamIcon} alt="Steam" /> 144 <img src={SteamIcon} alt="Steam" />
145 </a> 145 </a>
146 )} 146 )}
147 {user.links.twitch === '-' ? ( 147 {user.links.twitch === "-" ? (
148 '' 148 ""
149 ) : ( 149 ) : (
150 <a href={user.links.twitch}> 150 <a href={user.links.twitch}>
151 <img src={TwitchIcon} alt="Twitch" /> 151 <img src={TwitchIcon} alt="Twitch" />
152 </a> 152 </a>
153 )} 153 )}
154 {user.links.youtube === '-' ? ( 154 {user.links.youtube === "-" ? (
155 '' 155 ""
156 ) : ( 156 ) : (
157 <a href={user.links.youtube}> 157 <a href={user.links.youtube}>
158 <img src={YouTubeIcon} alt="Youtube" /> 158 <img src={YouTubeIcon} alt="Youtube" />
159 </a> 159 </a>
160 )} 160 )}
161 {user.links.p2sr === '-' ? ( 161 {user.links.p2sr === "-" ? (
162 '' 162 ""
163 ) : ( 163 ) : (
164 <a href={user.links.p2sr}> 164 <a href={user.links.p2sr}>
165 <img src={PortalIcon} alt="P2SR" style={{ padding: '0' }} /> 165 <img src={PortalIcon} alt="P2SR" style={{ padding: "0" }} />
166 </a> 166 </a>
167 )} 167 )}
168 </div> 168 </div>
@@ -172,8 +172,8 @@ const User: React.FC<UserProps> = ({ token, profile, gameData }) => {
172 <span>Overall</span> 172 <span>Overall</span>
173 <span> 173 <span>
174 {user.rankings.overall.rank === 0 174 {user.rankings.overall.rank === 0
175 ? 'N/A ' 175 ? "N/A "
176 : '#' + user.rankings.overall.rank + ' '} 176 : "#" + user.rankings.overall.rank + " "}
177 <span> 177 <span>
178 ({user.rankings.overall.completion_count}/ 178 ({user.rankings.overall.completion_count}/
179 {user.rankings.overall.completion_total}) 179 {user.rankings.overall.completion_total})
@@ -184,8 +184,8 @@ const User: React.FC<UserProps> = ({ token, profile, gameData }) => {
184 <span>Singleplayer</span> 184 <span>Singleplayer</span>
185 <span> 185 <span>
186 {user.rankings.singleplayer.rank === 0 186 {user.rankings.singleplayer.rank === 0
187 ? 'N/A ' 187 ? "N/A "
188 : '#' + user.rankings.singleplayer.rank + ' '} 188 : "#" + user.rankings.singleplayer.rank + " "}
189 <span> 189 <span>
190 ({user.rankings.singleplayer.completion_count}/ 190 ({user.rankings.singleplayer.completion_count}/
191 {user.rankings.singleplayer.completion_total}) 191 {user.rankings.singleplayer.completion_total})
@@ -196,8 +196,8 @@ const User: React.FC<UserProps> = ({ token, profile, gameData }) => {
196 <span>Cooperative</span> 196 <span>Cooperative</span>
197 <span> 197 <span>
198 {user.rankings.cooperative.rank === 0 198 {user.rankings.cooperative.rank === 0
199 ? 'N/A ' 199 ? "N/A "
200 : '#' + user.rankings.cooperative.rank + ' '} 200 : "#" + user.rankings.cooperative.rank + " "}
201 <span> 201 <span>
202 ({user.rankings.cooperative.completion_count}/ 202 ({user.rankings.cooperative.completion_count}/
203 {user.rankings.cooperative.completion_total}) 203 {user.rankings.cooperative.completion_total})
@@ -227,15 +227,15 @@ const User: React.FC<UserProps> = ({ token, profile, gameData }) => {
227 id="select-game" 227 id="select-game"
228 onChange={() => { 228 onChange={() => {
229 setGame( 229 setGame(
230 (document.querySelector('#select-game') as HTMLInputElement) 230 (document.querySelector("#select-game") as HTMLInputElement)
231 .value 231 .value
232 ); 232 );
233 setChapter('0'); 233 setChapter("0");
234 const chapterSelect = document.querySelector( 234 const chapterSelect = document.querySelector(
235 '#select-chapter' 235 "#select-chapter"
236 ) as HTMLSelectElement; 236 ) as HTMLSelectElement;
237 if (chapterSelect) { 237 if (chapterSelect) {
238 chapterSelect.value = '0'; 238 chapterSelect.value = "0";
239 } 239 }
240 }} 240 }}
241 > 241 >
@@ -250,7 +250,7 @@ const User: React.FC<UserProps> = ({ token, profile, gameData }) => {
250 </select> 250 </select>
251 )} 251 )}
252 252
253 {game === '0' ? ( 253 {game === "0" ? (
254 <select disabled> 254 <select disabled>
255 <option>All Chapters</option> 255 <option>All Chapters</option>
256 </select> 256 </select>
@@ -263,7 +263,7 @@ const User: React.FC<UserProps> = ({ token, profile, gameData }) => {
263 setChapter( 263 setChapter(
264 ( 264 (
265 document.querySelector( 265 document.querySelector(
266 '#select-chapter' 266 "#select-chapter"
267 ) as HTMLInputElement 267 ) as HTMLInputElement
268 ).value 268 ).value
269 ) 269 )
@@ -287,15 +287,15 @@ const User: React.FC<UserProps> = ({ token, profile, gameData }) => {
287 <span>Map Name</span> 287 <span>Map Name</span>
288 <img src={SortIcon} alt="" /> 288 <img src={SortIcon} alt="" />
289 </span> 289 </span>
290 <span style={{ justifyContent: 'center' }}> 290 <span style={{ justifyContent: "center" }}>
291 <span>Portals</span> 291 <span>Portals</span>
292 <img src={SortIcon} alt="" /> 292 <img src={SortIcon} alt="" />
293 </span> 293 </span>
294 <span style={{ justifyContent: 'center' }}> 294 <span style={{ justifyContent: "center" }}>
295 <span>WRΔ </span> 295 <span>WRΔ </span>
296 <img src={SortIcon} alt="" /> 296 <img src={SortIcon} alt="" />
297 </span> 297 </span>
298 <span style={{ justifyContent: 'center' }}> 298 <span style={{ justifyContent: "center" }}>
299 <span>Time</span> 299 <span>Time</span>
300 <img src={SortIcon} alt="" /> 300 <img src={SortIcon} alt="" />
301 </span> 301 </span>
@@ -315,18 +315,18 @@ const User: React.FC<UserProps> = ({ token, profile, gameData }) => {
315 if (pageNumber !== 1) { 315 if (pageNumber !== 1) {
316 setPageNumber(prevPageNumber => prevPageNumber - 1); 316 setPageNumber(prevPageNumber => prevPageNumber - 1);
317 const records = document.querySelectorAll( 317 const records = document.querySelectorAll(
318 '.profileboard-record' 318 ".profileboard-record"
319 ); 319 );
320 records.forEach(r => { 320 records.forEach(r => {
321 (r as HTMLInputElement).style.height = '44px'; 321 (r as HTMLInputElement).style.height = "44px";
322 }); 322 });
323 } 323 }
324 }} 324 }}
325 > 325 >
326 <i 326 <i
327 className="triangle" 327 className="triangle"
328 style={{ position: 'relative', left: '-5px' }} 328 style={{ position: "relative", left: "-5px" }}
329 ></i>{' '} 329 ></i>{" "}
330 </button> 330 </button>
331 <span> 331 <span>
332 {pageNumber}/{pageMax} 332 {pageNumber}/{pageMax}
@@ -336,10 +336,10 @@ const User: React.FC<UserProps> = ({ token, profile, gameData }) => {
336 if (pageNumber !== pageMax) { 336 if (pageNumber !== pageMax) {
337 setPageNumber(prevPageNumber => prevPageNumber + 1); 337 setPageNumber(prevPageNumber => prevPageNumber + 1);
338 const records = document.querySelectorAll( 338 const records = document.querySelectorAll(
339 '.profileboard-record' 339 ".profileboard-record"
340 ); 340 );
341 records.forEach(r => { 341 records.forEach(r => {
342 (r as HTMLInputElement).style.height = '44px'; 342 (r as HTMLInputElement).style.height = "44px";
343 }); 343 });
344 } 344 }
345 }} 345 }}
@@ -347,18 +347,18 @@ const User: React.FC<UserProps> = ({ token, profile, gameData }) => {
347 <i 347 <i
348 className="triangle" 348 className="triangle"
349 style={{ 349 style={{
350 position: 'relative', 350 position: "relative",
351 left: '5px', 351 left: "5px",
352 transform: 'rotate(180deg)', 352 transform: "rotate(180deg)",
353 }} 353 }}
354 ></i>{' '} 354 ></i>{" "}
355 </button> 355 </button>
356 </div> 356 </div>
357 </div> 357 </div>
358 </div> 358 </div>
359 <hr /> 359 <hr />
360 <div id="profileboard-records"> 360 <div id="profileboard-records">
361 {game === '0' ? ( 361 {game === "0" ? (
362 user.records 362 user.records
363 .sort((a, b) => a.map_id - b.map_id) 363 .sort((a, b) => a.map_id - b.map_id)
364 .map((r, index) => 364 .map((r, index) =>
@@ -367,33 +367,33 @@ const User: React.FC<UserProps> = ({ token, profile, gameData }) => {
367 {r.scores.map((e, i) => ( 367 {r.scores.map((e, i) => (
368 <> 368 <>
369 {i !== 0 ? ( 369 {i !== 0 ? (
370 <hr style={{ gridColumn: '1 / span 8' }} /> 370 <hr style={{ gridColumn: "1 / span 8" }} />
371 ) : ( 371 ) : (
372 '' 372 ""
373 )} 373 )}
374 374
375 <Link to={`/maps/${r.map_id}`}> 375 <Link to={`/maps/${r.map_id}`}>
376 <span>{r.map_name}</span> 376 <span>{r.map_name}</span>
377 </Link> 377 </Link>
378 378
379 <span style={{ display: 'grid' }}>{e.score_count}</span> 379 <span style={{ display: "grid" }}>{e.score_count}</span>
380 380
381 <span style={{ display: 'grid' }}> 381 <span style={{ display: "grid" }}>
382 {e.score_count - r.map_wr_count > 0 382 {e.score_count - r.map_wr_count > 0
383 ? `+${e.score_count - r.map_wr_count}` 383 ? `+${e.score_count - r.map_wr_count}`
384 : `-`} 384 : `-`}
385 </span> 385 </span>
386 <span style={{ display: 'grid' }}> 386 <span style={{ display: "grid" }}>
387 {ticks_to_time(e.score_time)} 387 {ticks_to_time(e.score_time)}
388 </span> 388 </span>
389 <span> </span> 389 <span> </span>
390 {i === 0 ? <span>#{r.placement}</span> : <span> </span>} 390 {i === 0 ? <span>#{r.placement}</span> : <span> </span>}
391 <span>{e.date.split('T')[0]}</span> 391 <span>{e.date.split("T")[0]}</span>
392 <span style={{ flexDirection: 'row-reverse' }}> 392 <span style={{ flexDirection: "row-reverse" }}>
393 <button 393 <button
394 onClick={() => { 394 onClick={() => {
395 message( 395 message(
396 'Demo Information', 396 "Demo Information",
397 `Demo ID: ${e.demo_id}` 397 `Demo ID: ${e.demo_id}`
398 ); 398 );
399 }} 399 }}
@@ -412,38 +412,38 @@ const User: React.FC<UserProps> = ({ token, profile, gameData }) => {
412 onClick={() => { 412 onClick={() => {
413 ( 413 (
414 document.querySelectorAll( 414 document.querySelectorAll(
415 '.profileboard-record' 415 ".profileboard-record"
416 )[index % 20] as HTMLInputElement 416 )[index % 20] as HTMLInputElement
417 ).style.height === '44px' || 417 ).style.height === "44px" ||
418 ( 418 (
419 document.querySelectorAll( 419 document.querySelectorAll(
420 '.profileboard-record' 420 ".profileboard-record"
421 )[index % 20] as HTMLInputElement 421 )[index % 20] as HTMLInputElement
422 ).style.height === '' 422 ).style.height === ""
423 ? (( 423 ? ((
424 document.querySelectorAll( 424 document.querySelectorAll(
425 '.profileboard-record' 425 ".profileboard-record"
426 )[index % 20] as HTMLInputElement 426 )[index % 20] as HTMLInputElement
427 ).style.height = 427 ).style.height =
428 `${r.scores.length * 46}px`) 428 `${r.scores.length * 46}px`)
429 : (( 429 : ((
430 document.querySelectorAll( 430 document.querySelectorAll(
431 '.profileboard-record' 431 ".profileboard-record"
432 )[index % 20] as HTMLInputElement 432 )[index % 20] as HTMLInputElement
433 ).style.height = '44px'); 433 ).style.height = "44px");
434 }} 434 }}
435 > 435 >
436 <img src={HistoryIcon} alt="history" /> 436 <img src={HistoryIcon} alt="history" />
437 </button> 437 </button>
438 ) : ( 438 ) : (
439 '' 439 ""
440 )} 440 )}
441 </span> 441 </span>
442 </> 442 </>
443 ))} 443 ))}
444 </button> 444 </button>
445 ) : ( 445 ) : (
446 '' 446 ""
447 ) 447 )
448 ) 448 )
449 ) : maps ? ( 449 ) : maps ? (
@@ -457,42 +457,42 @@ const User: React.FC<UserProps> = ({ token, profile, gameData }) => {
457 <button 457 <button
458 className="profileboard-record" 458 className="profileboard-record"
459 key={index} 459 key={index}
460 style={{ backgroundColor: '#1b1b20' }} 460 style={{ backgroundColor: "#1b1b20" }}
461 > 461 >
462 <Link to={`/maps/${r.id}`}> 462 <Link to={`/maps/${r.id}`}>
463 <span>{r.name}</span> 463 <span>{r.name}</span>
464 </Link> 464 </Link>
465 <span style={{ display: 'grid' }}>N/A</span> 465 <span style={{ display: "grid" }}>N/A</span>
466 <span style={{ display: 'grid' }}>N/A</span> 466 <span style={{ display: "grid" }}>N/A</span>
467 <span>N/A</span> 467 <span>N/A</span>
468 <span> </span> 468 <span> </span>
469 <span>N/A</span> 469 <span>N/A</span>
470 <span>N/A</span> 470 <span>N/A</span>
471 <span style={{ flexDirection: 'row-reverse' }}></span> 471 <span style={{ flexDirection: "row-reverse" }}></span>
472 </button> 472 </button>
473 ) : ( 473 ) : (
474 <button className="profileboard-record" key={index}> 474 <button className="profileboard-record" key={index}>
475 {record.scores.map((e, i) => ( 475 {record.scores.map((e, i) => (
476 <> 476 <>
477 {i !== 0 ? ( 477 {i !== 0 ? (
478 <hr style={{ gridColumn: '1 / span 8' }} /> 478 <hr style={{ gridColumn: "1 / span 8" }} />
479 ) : ( 479 ) : (
480 '' 480 ""
481 )} 481 )}
482 <Link to={`/maps/${r.id}`}> 482 <Link to={`/maps/${r.id}`}>
483 <span>{r.name}</span> 483 <span>{r.name}</span>
484 </Link> 484 </Link>
485 <span style={{ display: 'grid' }}> 485 <span style={{ display: "grid" }}>
486 {record!.scores[i].score_count} 486 {record!.scores[i].score_count}
487 </span> 487 </span>
488 <span style={{ display: 'grid' }}> 488 <span style={{ display: "grid" }}>
489 {record!.scores[i].score_count - 489 {record!.scores[i].score_count -
490 record!.map_wr_count > 490 record!.map_wr_count >
491 0 491 0
492 ? `+${record!.scores[i].score_count - record!.map_wr_count}` 492 ? `+${record!.scores[i].score_count - record!.map_wr_count}`
493 : `-`} 493 : `-`}
494 </span> 494 </span>
495 <span style={{ display: 'grid' }}> 495 <span style={{ display: "grid" }}>
496 {ticks_to_time(record!.scores[i].score_time)} 496 {ticks_to_time(record!.scores[i].score_time)}
497 </span> 497 </span>
498 <span> </span> 498 <span> </span>
@@ -501,12 +501,12 @@ const User: React.FC<UserProps> = ({ token, profile, gameData }) => {
501 ) : ( 501 ) : (
502 <span> </span> 502 <span> </span>
503 )} 503 )}
504 <span>{record!.scores[i].date.split('T')[0]}</span> 504 <span>{record!.scores[i].date.split("T")[0]}</span>
505 <span style={{ flexDirection: 'row-reverse' }}> 505 <span style={{ flexDirection: "row-reverse" }}>
506 <button 506 <button
507 onClick={() => { 507 onClick={() => {
508 message( 508 message(
509 'Demo Information', 509 "Demo Information",
510 `Demo ID: ${e.demo_id}` 510 `Demo ID: ${e.demo_id}`
511 ); 511 );
512 }} 512 }}
@@ -525,31 +525,31 @@ const User: React.FC<UserProps> = ({ token, profile, gameData }) => {
525 onClick={() => { 525 onClick={() => {
526 ( 526 (
527 document.querySelectorAll( 527 document.querySelectorAll(
528 '.profileboard-record' 528 ".profileboard-record"
529 )[index % 20] as HTMLInputElement 529 )[index % 20] as HTMLInputElement
530 ).style.height === '44px' || 530 ).style.height === "44px" ||
531 ( 531 (
532 document.querySelectorAll( 532 document.querySelectorAll(
533 '.profileboard-record' 533 ".profileboard-record"
534 )[index % 20] as HTMLInputElement 534 )[index % 20] as HTMLInputElement
535 ).style.height === '' 535 ).style.height === ""
536 ? (( 536 ? ((
537 document.querySelectorAll( 537 document.querySelectorAll(
538 '.profileboard-record' 538 ".profileboard-record"
539 )[index % 20] as HTMLInputElement 539 )[index % 20] as HTMLInputElement
540 ).style.height = 540 ).style.height =
541 `${record!.scores.length * 46}px`) 541 `${record!.scores.length * 46}px`)
542 : (( 542 : ((
543 document.querySelectorAll( 543 document.querySelectorAll(
544 '.profileboard-record' 544 ".profileboard-record"
545 )[index % 20] as HTMLInputElement 545 )[index % 20] as HTMLInputElement
546 ).style.height = '44px'); 546 ).style.height = "44px");
547 }} 547 }}
548 > 548 >
549 <img src={HistoryIcon} alt="history" /> 549 <img src={HistoryIcon} alt="history" />
550 </button> 550 </button>
551 ) : ( 551 ) : (
552 '' 552 ""
553 )} 553 )}
554 </span> 554 </span>
555 </> 555 </>
diff --git a/frontend/src/react-app-env.d.ts b/frontend/src/react-app-env.d.ts
index 9bf083a..8265915 100644
--- a/frontend/src/react-app-env.d.ts
+++ b/frontend/src/react-app-env.d.ts
@@ -1,2 +1,2 @@
1declare module '*.png'; 1declare module "*.png";
2declare module '*.css'; 2declare module "*.css";
diff --git a/frontend/src/types/Chapters.ts b/frontend/src/types/Chapters.ts
index 8924b97..5b494ca 100644
--- a/frontend/src/types/Chapters.ts
+++ b/frontend/src/types/Chapters.ts
@@ -1,5 +1,5 @@
1import type { Game } from '@customTypes/Game'; 1import type { Game } from "@customTypes/Game";
2import type { Map } from '@customTypes/Map'; 2import type { Map } from "@customTypes/Map";
3 3
4interface Chapter { 4interface Chapter {
5 id: number; 5 id: number;
diff --git a/frontend/src/types/Game.ts b/frontend/src/types/Game.ts
index be2cd73..0e7dc80 100644
--- a/frontend/src/types/Game.ts
+++ b/frontend/src/types/Game.ts
@@ -1,4 +1,4 @@
1import type { Map } from '@customTypes/Map'; 1import type { Map } from "@customTypes/Map";
2 2
3export interface Game { 3export interface Game {
4 id: number; 4 id: number;
diff --git a/frontend/src/types/Map.ts b/frontend/src/types/Map.ts
index 6bc6369..6a42c2a 100644
--- a/frontend/src/types/Map.ts
+++ b/frontend/src/types/Map.ts
@@ -1,6 +1,6 @@
1import type { Category, GameCategoryPortals } from '@customTypes/Game'; 1import type { Category, GameCategoryPortals } from "@customTypes/Game";
2import type { Pagination } from '@customTypes/Pagination'; 2import type { Pagination } from "@customTypes/Pagination";
3import type { UserShort } from '@customTypes/Profile'; 3import type { UserShort } from "@customTypes/Profile";
4 4
5export interface Map { 5export interface Map {
6 id: number; 6 id: number;
@@ -44,7 +44,7 @@ export interface MapLeaderboard {
44} 44}
45 45
46export interface MapLeaderboardRecordSingleplayer { 46export interface MapLeaderboardRecordSingleplayer {
47 kind: 'singleplayer'; 47 kind: "singleplayer";
48 placement: number; 48 placement: number;
49 record_id: number; 49 record_id: number;
50 score_count: number; 50 score_count: number;
@@ -55,7 +55,7 @@ export interface MapLeaderboardRecordSingleplayer {
55} 55}
56 56
57export interface MapLeaderboardRecordMultiplayer { 57export interface MapLeaderboardRecordMultiplayer {
58 kind: 'multiplayer'; 58 kind: "multiplayer";
59 placement: number; 59 placement: number;
60 record_id: number; 60 record_id: number;
61 score_count: number; 61 score_count: number;
diff --git a/frontend/src/types/Profile.ts b/frontend/src/types/Profile.ts
index 8051ae5..3c83d29 100644
--- a/frontend/src/types/Profile.ts
+++ b/frontend/src/types/Profile.ts
@@ -1,4 +1,4 @@
1import type { Pagination } from '@customTypes/Pagination'; 1import type { Pagination } from "@customTypes/Pagination";
2 2
3export interface UserShort { 3export interface UserShort {
4 steam_id: string; 4 steam_id: string;
diff --git a/frontend/src/types/Ranking.ts b/frontend/src/types/Ranking.ts
index 06a5ca4..800f4be 100644
--- a/frontend/src/types/Ranking.ts
+++ b/frontend/src/types/Ranking.ts
@@ -1,4 +1,4 @@
1import type { UserShort } from '@customTypes/Profile'; 1import type { UserShort } from "@customTypes/Profile";
2 2
3export interface RankingType { 3export interface RankingType {
4 placement: number; 4 placement: number;
diff --git a/frontend/src/types/Search.ts b/frontend/src/types/Search.ts
index 48b9169..b258ee3 100644
--- a/frontend/src/types/Search.ts
+++ b/frontend/src/types/Search.ts
@@ -1,4 +1,4 @@
1import type { UserShort } from '@customTypes/Profile'; 1import type { UserShort } from "@customTypes/Profile";
2 2
3export interface Search { 3export interface Search {
4 players: UserShort[]; 4 players: UserShort[];
diff --git a/frontend/src/utils/Jwt.ts b/frontend/src/utils/Jwt.ts
index affcd36..dc6ec92 100644
--- a/frontend/src/utils/Jwt.ts
+++ b/frontend/src/utils/Jwt.ts
@@ -5,20 +5,20 @@ export function get_user_id_from_token(
5 if (!token) { 5 if (!token) {
6 return undefined; 6 return undefined;
7 } 7 }
8 const parts = token.split('.'); 8 const parts = token.split(".");
9 if (parts.length !== 3) { 9 if (parts.length !== 3) {
10 return undefined; 10 return undefined;
11 } 11 }
12 const base64Url = parts[1]; 12 const base64Url = parts[1];
13 const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/'); 13 const base64 = base64Url.replace(/-/g, "+").replace(/_/g, "/");
14 14
15 const jsonPayload = decodeURIComponent( 15 const jsonPayload = decodeURIComponent(
16 atob(base64) 16 atob(base64)
17 .split('') 17 .split("")
18 .map(function (c) { 18 .map(function (c) {
19 return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2); 19 return "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2);
20 }) 20 })
21 .join('') 21 .join("")
22 ); 22 );
23 return JSON.parse(jsonPayload).sub; 23 return JSON.parse(jsonPayload).sub;
24} 24}
@@ -29,20 +29,20 @@ export function get_user_mod_from_token(
29 if (!token) { 29 if (!token) {
30 return undefined; 30 return undefined;
31 } 31 }
32 const parts = token.split('.'); 32 const parts = token.split(".");
33 if (parts.length !== 3) { 33 if (parts.length !== 3) {
34 return undefined; 34 return undefined;
35 } 35 }
36 const base64Url = parts[1]; 36 const base64Url = parts[1];
37 const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/'); 37 const base64 = base64Url.replace(/-/g, "+").replace(/_/g, "/");
38 38
39 const jsonPayload = decodeURIComponent( 39 const jsonPayload = decodeURIComponent(
40 atob(base64) 40 atob(base64)
41 .split('') 41 .split("")
42 .map(function (c) { 42 .map(function (c) {
43 return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2); 43 return "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2);
44 }) 44 })
45 .join('') 45 .join("")
46 ); 46 );
47 return JSON.parse(jsonPayload).mod; 47 return JSON.parse(jsonPayload).mod;
48} 48}
diff --git a/frontend/src/utils/Time.ts b/frontend/src/utils/Time.ts
index 34830b0..8f2c03c 100644
--- a/frontend/src/utils/Time.ts
+++ b/frontend/src/utils/Time.ts
@@ -6,47 +6,47 @@ export function time_ago(date: any) {
6 6
7 let interval = Math.floor(seconds / 31536000); 7 let interval = Math.floor(seconds / 31536000);
8 if (interval === 1) { 8 if (interval === 1) {
9 return interval + ' year ago'; 9 return interval + " year ago";
10 } 10 }
11 if (interval > 1) { 11 if (interval > 1) {
12 return interval + ' years ago'; 12 return interval + " years ago";
13 } 13 }
14 14
15 interval = Math.floor(seconds / 2592000); 15 interval = Math.floor(seconds / 2592000);
16 if (interval === 1) { 16 if (interval === 1) {
17 return interval + ' month ago'; 17 return interval + " month ago";
18 } 18 }
19 if (interval > 1) { 19 if (interval > 1) {
20 return interval + ' months ago'; 20 return interval + " months ago";
21 } 21 }
22 22
23 interval = Math.floor(seconds / 86400); 23 interval = Math.floor(seconds / 86400);
24 if (interval === 1) { 24 if (interval === 1) {
25 return interval + ' day ago'; 25 return interval + " day ago";
26 } 26 }
27 if (interval > 1) { 27 if (interval > 1) {
28 return interval + ' days ago'; 28 return interval + " days ago";
29 } 29 }
30 30
31 interval = Math.floor(seconds / 3600); 31 interval = Math.floor(seconds / 3600);
32 if (interval === 1) { 32 if (interval === 1) {
33 return interval + ' hour ago'; 33 return interval + " hour ago";
34 } 34 }
35 if (interval > 1) { 35 if (interval > 1) {
36 return interval + ' hours ago'; 36 return interval + " hours ago";
37 } 37 }
38 38
39 interval = Math.floor(seconds / 60); 39 interval = Math.floor(seconds / 60);
40 if (interval === 1) { 40 if (interval === 1) {
41 return interval + ' minute ago'; 41 return interval + " minute ago";
42 } 42 }
43 if (interval > 1) { 43 if (interval > 1) {
44 return interval + ' minutes ago'; 44 return interval + " minutes ago";
45 } 45 }
46 46
47 if (seconds < 10) return 'just now'; 47 if (seconds < 10) return "just now";
48 48
49 return Math.floor(seconds) + ' seconds ago'; 49 return Math.floor(seconds) + " seconds ago";
50} 50}
51 51
52export function ticks_to_time(ticks: number) { 52export function ticks_to_time(ticks: number) {
@@ -58,5 +58,5 @@ export function ticks_to_time(ticks: number) {
58 seconds = seconds % 60; 58 seconds = seconds % 60;
59 minutes = minutes % 60; 59 minutes = minutes % 60;
60 60
61 return `${hours === 0 ? '' : hours + ':'}${minutes === 0 ? '' : hours > 0 ? minutes.toString().padStart(2, '0') + ':' : minutes + ':'}${minutes > 0 ? seconds.toString().padStart(2, '0') : seconds}.${milliseconds.toString().padStart(3, '0')}`; 61 return `${hours === 0 ? "" : hours + ":"}${minutes === 0 ? "" : hours > 0 ? minutes.toString().padStart(2, "0") + ":" : minutes + ":"}${minutes > 0 ? seconds.toString().padStart(2, "0") : seconds}.${milliseconds.toString().padStart(3, "0")}`;
62} 62}