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