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.tsx633
1 files changed, 0 insertions, 633 deletions
diff --git a/frontend/src/pages/Profile.tsx b/frontend/src/pages/Profile.tsx
deleted file mode 100644
index f44f587..0000000
--- a/frontend/src/pages/Profile.tsx
+++ /dev/null
@@ -1,633 +0,0 @@
1import React from "react";
2import { Link, useNavigate } from "react-router-dom";
3import { Helmet } from "react-helmet";
4
5import {
6 SteamIcon,
7 TwitchIcon,
8 YouTubeIcon,
9 PortalIcon,
10 FlagIcon,
11 StatisticsIcon,
12 SortIcon,
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";
25import useMessageLoad from "@hooks/UseMessageLoad";
26
27interface ProfileProps {
28 profile?: UserProfile;
29 token?: string;
30 gameData: Game[];
31 onDeleteRecord: () => void;
32}
33
34const Profile: React.FC<ProfileProps> = ({
35 profile,
36 token,
37 gameData,
38 onDeleteRecord,
39}) => {
40 const { confirm, ConfirmDialogComponent } = useConfirm();
41 const { message, MessageDialogComponent } = useMessage();
42 const { messageLoad, messageLoadClose, MessageDialogLoadComponent } =
43 useMessageLoad();
44 const [navState, setNavState] = React.useState(0);
45 const [pageNumber, setPageNumber] = React.useState(1);
46 const [pageMax, setPageMax] = React.useState(0);
47
48 const [game, setGame] = React.useState("0");
49 const [chapter, setChapter] = React.useState("0");
50 const [chapterData, setChapterData] = React.useState<GameChapters | null>(
51 null
52 );
53 const [maps, setMaps] = React.useState<Map[]>([]);
54
55 const navigate = useNavigate();
56
57 const _update_profile = () => {
58 if (token) {
59 API.post_profile(token).then(() => navigate(0));
60 }
61 };
62
63 const _get_game_chapters = React.useCallback(async () => {
64 if (game && game !== "0") {
65 const gameChapters = await API.get_games_chapters(game);
66 setChapterData(gameChapters);
67 } else if (game && game === "0") {
68 setPageMax(Math.ceil(profile!.records.length / 20));
69 setPageNumber(1);
70 }
71 }, [game, profile]);
72
73 const _get_game_maps = React.useCallback(async () => {
74 if (chapter === "0") {
75 const gameMaps = await API.get_game_maps(game);
76 setMaps(gameMaps);
77 setPageMax(Math.ceil(gameMaps.length / 20));
78 setPageNumber(1);
79 } else {
80 const gameChapters = await API.get_chapters(chapter);
81 setMaps(gameChapters.maps);
82 setPageMax(Math.ceil(gameChapters.maps.length / 20));
83 setPageNumber(1);
84 }
85 }, [chapter, game]);
86
87 const _delete_submission = async (map_id: number, record_id: number) => {
88 const userConfirmed = await confirm(
89 "Delete Record",
90 "Are you sure you want to delete this record?"
91 );
92
93 if (!userConfirmed) {
94 return;
95 }
96
97 messageLoad("Deleting...");
98
99 const api_success = await API.delete_map_record(token!, map_id, record_id);
100 messageLoadClose();
101 if (api_success) {
102 await message("Delete Record", "Successfully deleted record.");
103 onDeleteRecord();
104 } else {
105 await message("Delete Record", "Could not delete record.");
106 }
107 };
108
109 React.useEffect(() => {
110 if (!profile) {
111 navigate("/");
112 }
113 }, [profile, navigate]);
114
115 React.useEffect(() => {
116 if (profile) {
117 _get_game_chapters();
118 }
119 }, [profile, game, _get_game_chapters]);
120
121 React.useEffect(() => {
122 if (profile && game !== "0") {
123 _get_game_maps();
124 }
125 }, [profile, game, chapter, chapterData, _get_game_maps]);
126
127 if (!profile) {
128 return <></>;
129 }
130
131 return (
132 <div>
133 <Helmet>
134 <title>LPHUB | {profile.user_name}</title>
135 <meta name="description" content={profile.user_name} />
136 </Helmet>
137 {MessageDialogComponent}
138 {MessageDialogLoadComponent}
139 {ConfirmDialogComponent}
140
141 <main>
142 <section id="section1" className="profile">
143 {profile.profile ? (
144 <div id="profile-image" onClick={_update_profile}>
145 <img src={profile.avatar_link} alt="profile-image"></img>
146 <span>Refresh</span>
147 </div>
148 ) : (
149 <div>
150 <img src={profile.avatar_link} alt="profile-image"></img>
151 </div>
152 )}
153
154 <div id="profile-top">
155 <div>
156 <div>{profile.user_name}</div>
157 <div>
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 )}
166 </div>
167 <div>
168 {profile.titles.map(e => (
169 <span
170 className="titles"
171 style={{ backgroundColor: `#${e.color}` }}
172 >
173 {e.name}
174 </span>
175 ))}
176 </div>
177 </div>
178 <div>
179 {profile.links.steam === "-" ? (
180 ""
181 ) : (
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 )}
207 </div>
208 </div>
209 <div id="profile-bottom">
210 <div>
211 <span>Overall</span>
212 <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>
220 </span>
221 </div>
222 <div>
223 <span>Singleplayer</span>
224 <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>
232 </span>
233 </div>
234 <div>
235 <span>Cooperative</span>
236 <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>
244 </span>
245 </div>
246 </div>
247 </section>
248
249 <section id="section2" className="profile">
250 <button onClick={() => setNavState(0)}>
251 <img src={FlagIcon} alt="" />
252 &nbsp;Player Records
253 </button>
254 <button onClick={() => setNavState(1)}>
255 <img src={StatisticsIcon} alt="" />
256 &nbsp;Statistics
257 </button>
258 </section>
259
260 <section id="section3" className="profile1">
261 <div id="profileboard-nav">
262 {gameData === null ? (
263 <select>error</select>
264 ) : (
265 <select
266 id="select-game"
267 onChange={() => {
268 setGame(
269 (document.querySelector("#select-game") as HTMLInputElement)
270 .value
271 );
272 setChapter("0");
273 const chapterSelect = document.querySelector(
274 "#select-chapter"
275 ) as HTMLSelectElement;
276 if (chapterSelect) {
277 chapterSelect.value = "0";
278 }
279 }}
280 >
281 <option value={0} key={0}>
282 All Scores
283 </option>
284 {gameData.map((e, i) => (
285 <option value={e.id} key={i + 1}>
286 {e.name}
287 </option>
288 ))}
289 </select>
290 )}
291
292 {game === "0" ? (
293 <select disabled>
294 <option>All Chapters</option>
295 </select>
296 ) : chapterData === null ? (
297 <select></select>
298 ) : (
299 <select
300 id="select-chapter"
301 onChange={() =>
302 setChapter(
303 (
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 )}
323 </div>
324 <div id="profileboard-top">
325 <span>
326 <span>Map Name</span>
327 <img src={SortIcon} alt="" />
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>
341 <span> </span>
342 <span>
343 <span>Rank</span>
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">
351 <div>
352 <button
353 onClick={() => {
354 if (pageNumber !== 1) {
355 setPageNumber(prevPageNumber => prevPageNumber - 1);
356 const records = document.querySelectorAll(
357 ".profileboard-record"
358 );
359 records.forEach(r => {
360 (r as HTMLInputElement).style.height = "44px";
361 });
362 }
363 }}
364 >
365 <i
366 className="triangle"
367 style={{ position: "relative", left: "-5px" }}
368 ></i>{" "}
369 </button>
370 <span>
371 {pageNumber}/{pageMax}
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>
395 </div>
396 </div>
397 </div>
398 <hr />
399 <div id="profileboard-records">
400 {game === "0" ? (
401 profile.records
402 .sort((a, b) => a.map_id - b.map_id)
403 .map((r, index) =>
404 Math.ceil((index + 1) / 20) === pageNumber ? (
405 <button className="profileboard-record" key={index}>
406 {r.scores.map((e, i) => (
407 <>
408 {i !== 0 ? (
409 <hr style={{ gridColumn: "1 / span 8" }} />
410 ) : (
411 ""
412 )}
413
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>
421
422 <span style={{ display: "grid" }}>
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>
430 <span> </span>
431 {i === 0 ? (
432 <span>#{r.placement}</span>
433 ) : (
434 <span> </span>
435 )}
436 <span>{e.date.split("T")[0]}</span>
437 <span style={{ flexDirection: "row-reverse" }}>
438 <button
439 style={{ marginRight: "10px" }}
440 onClick={() => {
441 message(
442 "Demo Information",
443 `Demo ID: ${e.demo_id}`
444 );
445 }}
446 >
447 <img src={ThreedotIcon} alt="demo_id" />
448 </button>
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 )}
494 </span>
495 </>
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>
525 </button>
526 ) : (
527 <button className="profileboard-record" key={index}>
528 {record.scores.map((e, i) => (
529 <>
530 {i !== 0 ? (
531 <hr style={{ gridColumn: "1 / span 8" }} />
532 ) : (
533 ""
534 )}
535 <Link to={`/maps/${r.id}`}>
536 <span>{r.name}</span>
537 </Link>
538 <span style={{ display: "grid" }}>
539 {record!.scores[i].score_count}
540 </span>
541 <span style={{ display: "grid" }}>
542 {record!.scores[i].score_count -
543 record!.map_wr_count >
544 0
545 ? `+${record!.scores[i].score_count - record!.map_wr_count}`
546 : `-`}
547 </span>
548 <span style={{ display: "grid" }}>
549 {ticks_to_time(record!.scores[i].score_time)}
550 </span>
551 <span> </span>
552 {i === 0 ? (
553 <span>#{record!.placement}</span>
554 ) : (
555 <span> </span>
556 )}
557 <span>{record!.scores[i].date.split("T")[0]}</span>
558 <span style={{ flexDirection: "row-reverse" }}>
559 <button
560 onClick={() => {
561 message(
562 "Demo Information",
563 `Demo ID: ${e.demo_id}`
564 );
565 }}
566 >
567 <img src={ThreedotIcon} alt="demo_id" />
568 </button>
569 <button
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 )}
614 </span>
615 </>
616 ))}
617 </button>
618 );
619 } else {
620 return null;
621 }
622 })
623 ) : (
624 <>{console.warn(maps)}</>
625 )}
626 </div>
627 </section>
628 </main>
629 </div>
630 );
631};
632
633export default Profile;