aboutsummaryrefslogtreecommitdiff
path: root/frontend/src/pages/Profile.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'frontend/src/pages/Profile.tsx')
-rw-r--r--frontend/src/pages/Profile.tsx672
1 files changed, 476 insertions, 196 deletions
diff --git a/frontend/src/pages/Profile.tsx b/frontend/src/pages/Profile.tsx
index 48233bf..f44f587 100644
--- a/frontend/src/pages/Profile.tsx
+++ b/frontend/src/pages/Profile.tsx
@@ -1,16 +1,27 @@
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 { SteamIcon, TwitchIcon, YouTubeIcon, PortalIcon, FlagIcon, StatisticsIcon, SortIcon, ThreedotIcon, DownloadIcon, HistoryIcon, DeleteIcon } from '@images/Images'; 5import {
6import { UserProfile } from '@customTypes/Profile'; 6 SteamIcon,
7import { Game, GameChapters } from '@customTypes/Game'; 7 TwitchIcon,
8import { Map } from '@customTypes/Map'; 8 YouTubeIcon,
9import { ticks_to_time } from '@utils/Time'; 9 PortalIcon,
10import "@css/Profile.css"; 10 FlagIcon,
11import { API } from '@api/Api'; 11 StatisticsIcon,
12import useConfirm from '@hooks/UseConfirm'; 12 SortIcon,
13import useMessage from '@hooks/UseMessage'; 13 ThreedotIcon,
14 DownloadIcon,
15 HistoryIcon,
16 DeleteIcon,
17} from "@images/Images";
18import { UserProfile } from "@customTypes/Profile";
19import { Game, GameChapters } from "@customTypes/Game";
20import { Map } from "@customTypes/Map";
21import { ticks_to_time } from "@utils/Time";
22import { API } from "@api/Api";
23import useConfirm from "@hooks/UseConfirm";
24import useMessage from "@hooks/UseMessage";
14import useMessageLoad from "@hooks/UseMessageLoad"; 25import useMessageLoad from "@hooks/UseMessageLoad";
15 26
16interface ProfileProps { 27interface ProfileProps {
@@ -20,17 +31,25 @@ interface ProfileProps {
20 onDeleteRecord: () => void; 31 onDeleteRecord: () => void;
21} 32}
22 33
23const Profile: React.FC<ProfileProps> = ({ profile, token, gameData, onDeleteRecord }) => { 34const Profile: React.FC<ProfileProps> = ({
35 profile,
36 token,
37 gameData,
38 onDeleteRecord,
39}) => {
24 const { confirm, ConfirmDialogComponent } = useConfirm(); 40 const { confirm, ConfirmDialogComponent } = useConfirm();
25 const { message, MessageDialogComponent } = useMessage(); 41 const { message, MessageDialogComponent } = useMessage();
26 const { messageLoad, messageLoadClose, MessageDialogLoadComponent } = useMessageLoad(); 42 const { messageLoad, messageLoadClose, MessageDialogLoadComponent } =
43 useMessageLoad();
27 const [navState, setNavState] = React.useState(0); 44 const [navState, setNavState] = React.useState(0);
28 const [pageNumber, setPageNumber] = React.useState(1); 45 const [pageNumber, setPageNumber] = React.useState(1);
29 const [pageMax, setPageMax] = React.useState(0); 46 const [pageMax, setPageMax] = React.useState(0);
30 47
31 const [game, setGame] = React.useState("0") 48 const [game, setGame] = React.useState("0");
32 const [chapter, setChapter] = React.useState("0") 49 const [chapter, setChapter] = React.useState("0");
33 const [chapterData, setChapterData] = React.useState<GameChapters | null>(null); 50 const [chapterData, setChapterData] = React.useState<GameChapters | null>(
51 null
52 );
34 const [maps, setMaps] = React.useState<Map[]>([]); 53 const [maps, setMaps] = React.useState<Map[]>([]);
35 54
36 const navigate = useNavigate(); 55 const navigate = useNavigate();
@@ -41,7 +60,7 @@ const Profile: React.FC<ProfileProps> = ({ profile, token, gameData, onDeleteRec
41 } 60 }
42 }; 61 };
43 62
44 const _get_game_chapters = async () => { 63 const _get_game_chapters = React.useCallback(async () => {
45 if (game && game !== "0") { 64 if (game && game !== "0") {
46 const gameChapters = await API.get_games_chapters(game); 65 const gameChapters = await API.get_games_chapters(game);
47 setChapterData(gameChapters); 66 setChapterData(gameChapters);
@@ -49,9 +68,9 @@ const Profile: React.FC<ProfileProps> = ({ profile, token, gameData, onDeleteRec
49 setPageMax(Math.ceil(profile!.records.length / 20)); 68 setPageMax(Math.ceil(profile!.records.length / 20));
50 setPageNumber(1); 69 setPageNumber(1);
51 } 70 }
52 }; 71 }, [game, profile]);
53 72
54 const _get_game_maps = async () => { 73 const _get_game_maps = React.useCallback(async () => {
55 if (chapter === "0") { 74 if (chapter === "0") {
56 const gameMaps = await API.get_game_maps(game); 75 const gameMaps = await API.get_game_maps(game);
57 setMaps(gameMaps); 76 setMaps(gameMaps);
@@ -63,10 +82,13 @@ const Profile: React.FC<ProfileProps> = ({ profile, token, gameData, onDeleteRec
63 setPageMax(Math.ceil(gameChapters.maps.length / 20)); 82 setPageMax(Math.ceil(gameChapters.maps.length / 20));
64 setPageNumber(1); 83 setPageNumber(1);
65 } 84 }
66 }; 85 }, [chapter, game]);
67 86
68 const _delete_submission = async (map_id: number, record_id: number) => { 87 const _delete_submission = async (map_id: number, record_id: number) => {
69 const userConfirmed = await confirm("Delete Record", "Are you sure you want to delete this record?"); 88 const userConfirmed = await confirm(
89 "Delete Record",
90 "Are you sure you want to delete this record?"
91 );
70 92
71 if (!userConfirmed) { 93 if (!userConfirmed) {
72 return; 94 return;
@@ -87,26 +109,24 @@ const Profile: React.FC<ProfileProps> = ({ profile, token, gameData, onDeleteRec
87 React.useEffect(() => { 109 React.useEffect(() => {
88 if (!profile) { 110 if (!profile) {
89 navigate("/"); 111 navigate("/");
90 }; 112 }
91 }, [profile]); 113 }, [profile, navigate]);
92 114
93 React.useEffect(() => { 115 React.useEffect(() => {
94 if (profile) { 116 if (profile) {
95 _get_game_chapters(); 117 _get_game_chapters();
96 } 118 }
97 }, [profile, game]); 119 }, [profile, game, _get_game_chapters]);
98 120
99 React.useEffect(() => { 121 React.useEffect(() => {
100 if (profile && game !== "0") { 122 if (profile && game !== "0") {
101 _get_game_maps(); 123 _get_game_maps();
102 } 124 }
103 }, [profile, game, chapter, chapterData]) 125 }, [profile, game, chapter, chapterData, _get_game_maps]);
104 126
105 if (!profile) { 127 if (!profile) {
106 return ( 128 return <></>;
107 <></> 129 }
108 );
109 };
110 130
111 return ( 131 return (
112 <div> 132 <div>
@@ -119,230 +139,490 @@ const Profile: React.FC<ProfileProps> = ({ profile, token, gameData, onDeleteRec
119 {ConfirmDialogComponent} 139 {ConfirmDialogComponent}
120 140
121 <main> 141 <main>
122 <section id='section1' className='profile'> 142 <section id="section1" className="profile">
123 143 {profile.profile ? (
124 {profile.profile 144 <div id="profile-image" onClick={_update_profile}>
125 ? ( 145 <img src={profile.avatar_link} alt="profile-image"></img>
126 <div id='profile-image' onClick={_update_profile}> 146 <span>Refresh</span>
127 <img src={profile.avatar_link} alt="profile-image"></img> 147 </div>
128 <span>Refresh</span> 148 ) : (
129 </div> 149 <div>
130 ) : ( 150 <img src={profile.avatar_link} alt="profile-image"></img>
131 <div> 151 </div>
132 <img src={profile.avatar_link} alt="profile-image"></img> 152 )}
133 </div>
134 )}
135 153
136 <div id='profile-top'> 154 <div id="profile-top">
137 <div> 155 <div>
138 <div>{profile.user_name}</div> 156 <div>{profile.user_name}</div>
139 <div> 157 <div>
140 {profile.country_code === "XX" ? "" : <img src={`https://flagcdn.com/w80/${profile.country_code.toLowerCase()}.jpg`} alt={profile.country_code} />} 158 {profile.country_code === "XX" ? (
159 ""
160 ) : (
161 <img
162 src={`https://flagcdn.com/w80/${profile.country_code.toLowerCase()}.jpg`}
163 alt={profile.country_code}
164 />
165 )}
141 </div> 166 </div>
142 <div> 167 <div>
143 {profile.titles.map(e => ( 168 {profile.titles.map(e => (
144 <span className="titles" style={{ backgroundColor: `#${e.color}` }}> 169 <span
170 className="titles"
171 style={{ backgroundColor: `#${e.color}` }}
172 >
145 {e.name} 173 {e.name}
146 </span> 174 </span>
147 ))} 175 ))}
148 </div> 176 </div>
149 </div> 177 </div>
150 <div> 178 <div>
151 {profile.links.steam === "-" ? "" : <a href={profile.links.steam}><img src={SteamIcon} alt="Steam" /></a>} 179 {profile.links.steam === "-" ? (
152 {profile.links.twitch === "-" ? "" : <a href={profile.links.twitch}><img src={TwitchIcon} alt="Twitch" /></a>} 180 ""
153 {profile.links.youtube === "-" ? "" : <a href={profile.links.youtube}><img src={YouTubeIcon} alt="Youtube" /></a>} 181 ) : (
154 {profile.links.p2sr === "-" ? "" : <a href={profile.links.p2sr}><img src={PortalIcon} alt="P2SR" style={{ padding: "0" }} /></a>} 182 <a href={profile.links.steam}>
183 <img src={SteamIcon} alt="Steam" />
184 </a>
185 )}
186 {profile.links.twitch === "-" ? (
187 ""
188 ) : (
189 <a href={profile.links.twitch}>
190 <img src={TwitchIcon} alt="Twitch" />
191 </a>
192 )}
193 {profile.links.youtube === "-" ? (
194 ""
195 ) : (
196 <a href={profile.links.youtube}>
197 <img src={YouTubeIcon} alt="Youtube" />
198 </a>
199 )}
200 {profile.links.p2sr === "-" ? (
201 ""
202 ) : (
203 <a href={profile.links.p2sr}>
204 <img src={PortalIcon} alt="P2SR" style={{ padding: "0" }} />
205 </a>
206 )}
155 </div> 207 </div>
156
157 </div> 208 </div>
158 <div id='profile-bottom'> 209 <div id="profile-bottom">
159 <div> 210 <div>
160 <span>Overall</span> 211 <span>Overall</span>
161 <span>{profile.rankings.overall.rank === 0 ? "N/A " : "#" + profile.rankings.overall.rank + " "} 212 <span>
162 <span>({profile.rankings.overall.completion_count}/{profile.rankings.overall.completion_total})</span> 213 {profile.rankings.overall.rank === 0
214 ? "N/A "
215 : "#" + profile.rankings.overall.rank + " "}
216 <span>
217 ({profile.rankings.overall.completion_count}/
218 {profile.rankings.overall.completion_total})
219 </span>
163 </span> 220 </span>
164 </div> 221 </div>
165 <div> 222 <div>
166 <span>Singleplayer</span> 223 <span>Singleplayer</span>
167 <span>{profile.rankings.singleplayer.rank === 0 ? "N/A " : "#" + profile.rankings.singleplayer.rank + " "} 224 <span>
168 <span>({profile.rankings.singleplayer.completion_count}/{profile.rankings.singleplayer.completion_total})</span> 225 {profile.rankings.singleplayer.rank === 0
226 ? "N/A "
227 : "#" + profile.rankings.singleplayer.rank + " "}
228 <span>
229 ({profile.rankings.singleplayer.completion_count}/
230 {profile.rankings.singleplayer.completion_total})
231 </span>
169 </span> 232 </span>
170 </div> 233 </div>
171 <div> 234 <div>
172 <span>Cooperative</span> 235 <span>Cooperative</span>
173 <span>{profile.rankings.cooperative.rank === 0 ? "N/A " : "#" + profile.rankings.cooperative.rank + " "} 236 <span>
174 <span>({profile.rankings.cooperative.completion_count}/{profile.rankings.cooperative.completion_total})</span> 237 {profile.rankings.cooperative.rank === 0
238 ? "N/A "
239 : "#" + profile.rankings.cooperative.rank + " "}
240 <span>
241 ({profile.rankings.cooperative.completion_count}/
242 {profile.rankings.cooperative.completion_total})
243 </span>
175 </span> 244 </span>
176 </div> 245 </div>
177 </div> 246 </div>
178 </section> 247 </section>
179 248
180 249 <section id="section2" className="profile">
181 <section id='section2' className='profile'> 250 <button onClick={() => setNavState(0)}>
182 <button onClick={() => setNavState(0)}><img src={FlagIcon} alt="" />&nbsp;Player Records</button> 251 <img src={FlagIcon} alt="" />
183 <button onClick={() => setNavState(1)}><img src={StatisticsIcon} alt="" />&nbsp;Statistics</button> 252 &nbsp;Player Records
253 </button>
254 <button onClick={() => setNavState(1)}>
255 <img src={StatisticsIcon} alt="" />
256 &nbsp;Statistics
257 </button>
184 </section> 258 </section>
185 259
186 260 <section id="section3" className="profile1">
187 261 <div id="profileboard-nav">
188 262 {gameData === null ? (
189 263 <select>error</select>
190 <section id='section3' className='profile1'> 264 ) : (
191 <div id='profileboard-nav'> 265 <select
192 {gameData === null ? <select>error</select> : 266 id="select-game"
193
194 <select id='select-game'
195 onChange={() => { 267 onChange={() => {
196 setGame((document.querySelector('#select-game') as HTMLInputElement).value); 268 setGame(
269 (document.querySelector("#select-game") as HTMLInputElement)
270 .value
271 );
197 setChapter("0"); 272 setChapter("0");
198 const chapterSelect = document.querySelector('#select-chapter') as HTMLSelectElement; 273 const chapterSelect = document.querySelector(
274 "#select-chapter"
275 ) as HTMLSelectElement;
199 if (chapterSelect) { 276 if (chapterSelect) {
200 chapterSelect.value = "0"; 277 chapterSelect.value = "0";
201 } 278 }
202 }}> 279 }}
203 <option value={0} key={0}>All Scores</option> 280 >
281 <option value={0} key={0}>
282 All Scores
283 </option>
204 {gameData.map((e, i) => ( 284 {gameData.map((e, i) => (
205 <option value={e.id} key={i + 1}>{e.name}</option> 285 <option value={e.id} key={i + 1}>
206 ))}</select> 286 {e.name}
207 } 287 </option>
288 ))}
289 </select>
290 )}
208 291
209 {game === "0" ? 292 {game === "0" ? (
210 <select disabled> 293 <select disabled>
211 <option>All Chapters</option> 294 <option>All Chapters</option>
212 </select> 295 </select>
213 : chapterData === null ? <select></select> : 296 ) : chapterData === null ? (
214 297 <select></select>
215 <select id='select-chapter' 298 ) : (
216 onChange={() => setChapter((document.querySelector('#select-chapter') as HTMLInputElement).value)}> 299 <select
217 <option value="0" key="0">All Chapters</option> 300 id="select-chapter"
218 {chapterData.chapters.filter(e => e.is_disabled === false).map((e, i) => ( 301 onChange={() =>
219 <option value={e.id} key={i + 1}>{e.name}</option> 302 setChapter(
220 ))}</select> 303 (
221 } 304 document.querySelector(
305 "#select-chapter"
306 ) as HTMLInputElement
307 ).value
308 )
309 }
310 >
311 <option value="0" key="0">
312 All Chapters
313 </option>
314 {chapterData.chapters
315 .filter(e => e.is_disabled === false)
316 .map((e, i) => (
317 <option value={e.id} key={i + 1}>
318 {e.name}
319 </option>
320 ))}
321 </select>
322 )}
222 </div> 323 </div>
223 <div id='profileboard-top'> 324 <div id="profileboard-top">
224 <span><span>Map Name</span><img src={SortIcon} alt="" /></span> 325 <span>
225 <span style={{ justifyContent: 'center' }}><span>Portals</span><img src={SortIcon} alt="" /></span> 326 <span>Map Name</span>
226 <span style={{ justifyContent: 'center' }}><span>WRΔ </span><img src={SortIcon} alt="" /></span> 327 <img src={SortIcon} alt="" />
227 <span style={{ justifyContent: 'center' }}><span>Time</span><img src={SortIcon} alt="" /></span> 328 </span>
329 <span style={{ justifyContent: "center" }}>
330 <span>Portals</span>
331 <img src={SortIcon} alt="" />
332 </span>
333 <span style={{ justifyContent: "center" }}>
334 <span>WRΔ </span>
335 <img src={SortIcon} alt="" />
336 </span>
337 <span style={{ justifyContent: "center" }}>
338 <span>Time</span>
339 <img src={SortIcon} alt="" />
340 </span>
228 <span> </span> 341 <span> </span>
229 <span><span>Rank</span><img src={SortIcon} alt="" /></span> 342 <span>
230 <span><span>Date</span><img src={SortIcon} alt="" /></span> 343 <span>Rank</span>
231 <div id='page-number'> 344 <img src={SortIcon} alt="" />
345 </span>
346 <span>
347 <span>Date</span>
348 <img src={SortIcon} alt="" />
349 </span>
350 <div id="page-number">
232 <div> 351 <div>
233 <button onClick={() => { 352 <button
234 if (pageNumber !== 1) { 353 onClick={() => {
235 setPageNumber(prevPageNumber => prevPageNumber - 1); 354 if (pageNumber !== 1) {
236 const records = document.querySelectorAll(".profileboard-record"); 355 setPageNumber(prevPageNumber => prevPageNumber - 1);
237 records.forEach((r) => { 356 const records = document.querySelectorAll(
238 (r as HTMLInputElement).style.height = "44px"; 357 ".profileboard-record"
239 }); 358 );
240 } 359 records.forEach(r => {
241 }} 360 (r as HTMLInputElement).style.height = "44px";
242 ><i className='triangle' style={{ position: 'relative', left: '-5px', }}></i> </button> 361 });
243 <span>{pageNumber}/{pageMax}</span> 362 }
244 <button onClick={() => { 363 }}
245 if (pageNumber !== pageMax) { 364 >
246 setPageNumber(prevPageNumber => prevPageNumber + 1); 365 <i
247 const records = document.querySelectorAll(".profileboard-record"); 366 className="triangle"
248 records.forEach((r) => { 367 style={{ position: "relative", left: "-5px" }}
249 (r as HTMLInputElement).style.height = "44px"; 368 ></i>{" "}
250 }); 369 </button>
251 } 370 <span>
252 }} 371 {pageNumber}/{pageMax}
253 ><i className='triangle' style={{ position: 'relative', left: '5px', transform: 'rotate(180deg)' }}></i> </button> 372 </span>
373 <button
374 onClick={() => {
375 if (pageNumber !== pageMax) {
376 setPageNumber(prevPageNumber => prevPageNumber + 1);
377 const records = document.querySelectorAll(
378 ".profileboard-record"
379 );
380 records.forEach(r => {
381 (r as HTMLInputElement).style.height = "44px";
382 });
383 }
384 }}
385 >
386 <i
387 className="triangle"
388 style={{
389 position: "relative",
390 left: "5px",
391 transform: "rotate(180deg)",
392 }}
393 ></i>{" "}
394 </button>
254 </div> 395 </div>
255 </div> 396 </div>
256 </div> 397 </div>
257 <hr /> 398 <hr />
258 <div id='profileboard-records'> 399 <div id="profileboard-records">
259 400 {game === "0" ? (
260 {game === "0" 401 profile.records
261 ? ( 402 .sort((a, b) => a.map_id - b.map_id)
262 403 .map((r, index) =>
263 profile.records.sort((a, b) => a.map_id - b.map_id) 404 Math.ceil((index + 1) / 20) === pageNumber ? (
264 .map((r, index) => ( 405 <button className="profileboard-record" key={index}>
265 406 {r.scores.map((e, i) => (
266 Math.ceil((index + 1) / 20) === pageNumber ? ( 407 <>
267 <button className="profileboard-record" key={index}> 408 {i !== 0 ? (
268 {r.scores.map((e, i) => (<> 409 <hr style={{ gridColumn: "1 / span 8" }} />
269 {i !== 0 ? <hr style={{ gridColumn: "1 / span 8" }} /> : ""} 410 ) : (
270 411 ""
271 <Link to={`/maps/${r.map_id}`}><span>{r.map_name}</span></Link> 412 )}
272 413
273 <span style={{ display: "grid" }}>{e.score_count}</span> 414 <Link to={`/maps/${r.map_id}`}>
415 <span>{r.map_name}</span>
416 </Link>
417
418 <span style={{ display: "grid" }}>
419 {e.score_count}
420 </span>
274 421
275 <span style={{ display: "grid" }}>{e.score_count - r.map_wr_count > 0 ? `+${e.score_count - r.map_wr_count}` : `-`}</span> 422 <span style={{ display: "grid" }}>
276 <span style={{ display: "grid" }}>{ticks_to_time(e.score_time)}</span> 423 {e.score_count - r.map_wr_count > 0
424 ? `+${e.score_count - r.map_wr_count}`
425 : `-`}
426 </span>
427 <span style={{ display: "grid" }}>
428 {ticks_to_time(e.score_time)}
429 </span>
277 <span> </span> 430 <span> </span>
278 {i === 0 ? <span>#{r.placement}</span> : <span> </span>} 431 {i === 0 ? (
432 <span>#{r.placement}</span>
433 ) : (
434 <span> </span>
435 )}
279 <span>{e.date.split("T")[0]}</span> 436 <span>{e.date.split("T")[0]}</span>
280 <span style={{ flexDirection: "row-reverse" }}> 437 <span style={{ flexDirection: "row-reverse" }}>
281 438 <button
282 <button style={{ marginRight: "10px" }} onClick={() => { message("Demo Information", `Demo ID: ${e.demo_id}`) }}><img src={ThreedotIcon} alt="demo_id" /></button> 439 style={{ marginRight: "10px" }}
283 <button onClick={() => { _delete_submission(r.map_id, e.record_id) }}><img src={DeleteIcon}></img></button> 440 onClick={() => {
284 <button onClick={() => window.location.href = `/api/v1/demos?uuid=${e.demo_id}`}><img src={DownloadIcon} alt="download" /></button> 441 message(
285 {i === 0 && r.scores.length > 1 ? <button onClick={() => { 442 "Demo Information",
286 (document.querySelectorAll(".profileboard-record")[index % 20] as HTMLInputElement).style.height === "44px" || 443 `Demo ID: ${e.demo_id}`
287 (document.querySelectorAll(".profileboard-record")[index % 20] as HTMLInputElement).style.height === "" ? 444 );
288 (document.querySelectorAll(".profileboard-record")[index % 20] as HTMLInputElement).style.height = `${r.scores.length * 46}px` : 445 }}
289 (document.querySelectorAll(".profileboard-record")[index % 20] as HTMLInputElement).style.height = "44px" 446 >
290 } 447 <img src={ThreedotIcon} alt="demo_id" />
291 }><img src={HistoryIcon} alt="history" /></button> : ""} 448 </button>
292 449 <button
450 onClick={() => {
451 _delete_submission(r.map_id, e.record_id);
452 }}
453 >
454 <img src={DeleteIcon} alt="delete icon"></img>
455 </button>
456 <button
457 onClick={() =>
458 (window.location.href = `/api/v1/demos?uuid=${e.demo_id}`)
459 }
460 >
461 <img src={DownloadIcon} alt="download" />
462 </button>
463 {i === 0 && r.scores.length > 1 ? (
464 <button
465 onClick={() => {
466 (
467 document.querySelectorAll(
468 ".profileboard-record"
469 )[index % 20] as HTMLInputElement
470 ).style.height === "44px" ||
471 (
472 document.querySelectorAll(
473 ".profileboard-record"
474 )[index % 20] as HTMLInputElement
475 ).style.height === ""
476 ? ((
477 document.querySelectorAll(
478 ".profileboard-record"
479 )[index % 20] as HTMLInputElement
480 ).style.height =
481 `${r.scores.length * 46}px`)
482 : ((
483 document.querySelectorAll(
484 ".profileboard-record"
485 )[index % 20] as HTMLInputElement
486 ).style.height = "44px");
487 }}
488 >
489 <img src={HistoryIcon} alt="history" />
490 </button>
491 ) : (
492 ""
493 )}
293 </span> 494 </span>
294 </>))} 495 </>
295 496 ))}
497 </button>
498 ) : (
499 ""
500 )
501 )
502 ) : maps ? (
503 maps
504 .filter(e => e.is_disabled === false)
505 .sort((a, b) => a.id - b.id)
506 .map((r, index) => {
507 if (Math.ceil((index + 1) / 20) === pageNumber) {
508 let record = profile.records.find(e => e.map_id === r.id);
509 return record === undefined ? (
510 <button
511 className="profileboard-record"
512 key={index}
513 style={{ backgroundColor: "#1b1b20" }}
514 >
515 <Link to={`/maps/${r.id}`}>
516 <span>{r.name}</span>
517 </Link>
518 <span style={{ display: "grid" }}>N/A</span>
519 <span style={{ display: "grid" }}>N/A</span>
520 <span>N/A</span>
521 <span> </span>
522 <span>N/A</span>
523 <span>N/A</span>
524 <span style={{ flexDirection: "row-reverse" }}></span>
296 </button> 525 </button>
297 ) : "" 526 ) : (
298 ))) : maps ? 527 <button className="profileboard-record" key={index}>
299 528 {record.scores.map((e, i) => (
300 maps.filter(e => e.is_disabled === false).sort((a, b) => a.id - b.id) 529 <>
301 .map((r, index) => { 530 {i !== 0 ? (
302 if (Math.ceil((index + 1) / 20) === pageNumber) { 531 <hr style={{ gridColumn: "1 / span 8" }} />
303 let record = profile.records.find((e) => e.map_id === r.id); 532 ) : (
304 return record === undefined ? ( 533 ""
305 <button className="profileboard-record" key={index} style={{ backgroundColor: "#1b1b20" }}> 534 )}
306 <Link to={`/maps/${r.id}`}><span>{r.name}</span></Link> 535 <Link to={`/maps/${r.id}`}>
307 <span style={{ display: "grid" }}>N/A</span> 536 <span>{r.name}</span>
308 <span style={{ display: "grid" }}>N/A</span> 537 </Link>
309 <span>N/A</span> 538 <span style={{ display: "grid" }}>
310 <span> </span> 539 {record!.scores[i].score_count}
311 <span>N/A</span> 540 </span>
312 <span>N/A</span> 541 <span style={{ display: "grid" }}>
313 <span style={{ flexDirection: "row-reverse" }}></span> 542 {record!.scores[i].score_count -
314 </button> 543 record!.map_wr_count >
315 ) : ( 544 0
316 <button className="profileboard-record" key={index}> 545 ? `+${record!.scores[i].score_count - record!.map_wr_count}`
317 {record.scores.map((e, i) => (<> 546 : `-`}
318 {i !== 0 ? <hr style={{ gridColumn: "1 / span 8" }} /> : ""} 547 </span>
319 <Link to={`/maps/${r.id}`}><span>{r.name}</span></Link> 548 <span style={{ display: "grid" }}>
320 <span style={{ display: "grid" }}>{record!.scores[i].score_count}</span> 549 {ticks_to_time(record!.scores[i].score_time)}
321 <span style={{ display: "grid" }}>{record!.scores[i].score_count - record!.map_wr_count > 0 ? `+${record!.scores[i].score_count - record!.map_wr_count}` : `-`}</span> 550 </span>
322 <span style={{ display: "grid" }}>{ticks_to_time(record!.scores[i].score_time)}</span>
323 <span> </span> 551 <span> </span>
324 {i === 0 ? <span>#{record!.placement}</span> : <span> </span>} 552 {i === 0 ? (
553 <span>#{record!.placement}</span>
554 ) : (
555 <span> </span>
556 )}
325 <span>{record!.scores[i].date.split("T")[0]}</span> 557 <span>{record!.scores[i].date.split("T")[0]}</span>
326 <span style={{ flexDirection: "row-reverse" }}> 558 <span style={{ flexDirection: "row-reverse" }}>
327 559 <button
328 <button onClick={() => { message("Demo Information", `Demo ID: ${e.demo_id}`) }}><img src={ThreedotIcon} alt="demo_id" /></button> 560 onClick={() => {
329 <button onClick={() => { _delete_submission(r.id, e.record_id) }}><img src={DeleteIcon}></img></button> 561 message(
330 <button onClick={() => window.location.href = `/api/v1/demos?uuid=${e.demo_id}`}><img src={DownloadIcon} alt="download" /></button> 562 "Demo Information",
331 {i === 0 && record!.scores.length > 1 ? <button onClick={() => { 563 `Demo ID: ${e.demo_id}`
332 (document.querySelectorAll(".profileboard-record")[index % 20] as HTMLInputElement).style.height === "44px" || 564 );
333 (document.querySelectorAll(".profileboard-record")[index % 20] as HTMLInputElement).style.height === "" ? 565 }}
334 (document.querySelectorAll(".profileboard-record")[index % 20] as HTMLInputElement).style.height = `${record!.scores.length * 46}px` : 566 >
335 (document.querySelectorAll(".profileboard-record")[index % 20] as HTMLInputElement).style.height = "44px" 567 <img src={ThreedotIcon} alt="demo_id" />
336 } 568 </button>
337 }><img src={HistoryIcon} alt="history" /></button> : ""} 569 <button
338 570 onClick={() => {
571 _delete_submission(r.id, e.record_id);
572 }}
573 >
574 <img src={DeleteIcon} alt="delete icon"></img>
575 </button>
576 <button
577 onClick={() =>
578 (window.location.href = `/api/v1/demos?uuid=${e.demo_id}`)
579 }
580 >
581 <img src={DownloadIcon} alt="download" />
582 </button>
583 {i === 0 && record!.scores.length > 1 ? (
584 <button
585 onClick={() => {
586 (
587 document.querySelectorAll(
588 ".profileboard-record"
589 )[index % 20] as HTMLInputElement
590 ).style.height === "44px" ||
591 (
592 document.querySelectorAll(
593 ".profileboard-record"
594 )[index % 20] as HTMLInputElement
595 ).style.height === ""
596 ? ((
597 document.querySelectorAll(
598 ".profileboard-record"
599 )[index % 20] as HTMLInputElement
600 ).style.height =
601 `${record!.scores.length * 46}px`)
602 : ((
603 document.querySelectorAll(
604 ".profileboard-record"
605 )[index % 20] as HTMLInputElement
606 ).style.height = "44px");
607 }}
608 >
609 <img src={HistoryIcon} alt="history" />
610 </button>
611 ) : (
612 ""
613 )}
339 </span> 614 </span>
340 </>))} 615 </>
341 </button> 616 ))}
342 617 </button>
343 ) 618 );
344 } else { return null } 619 } else {
345 }) : (<>{console.warn(maps)}</>)} 620 return null;
621 }
622 })
623 ) : (
624 <>{console.warn(maps)}</>
625 )}
346 </div> 626 </div>
347 </section> 627 </section>
348 </main> 628 </main>