aboutsummaryrefslogtreecommitdiff
path: root/frontend/src/pages/User.tsx
diff options
context:
space:
mode:
authorFifthWit <fifthwitbusiness@gmail.com>2025-08-14 15:44:50 -0500
committerFifthWit <fifthwitbusiness@gmail.com>2025-08-14 15:44:50 -0500
commitcfd377e29c0fa6f10c4d6bf3f507de4ca2f0b10a (patch)
tree6e30957cf5119a8ab83dd2c719e907e988619841 /frontend/src/pages/User.tsx
parentSwitched to tailwind/vite (diff)
downloadlphub-cfd377e29c0fa6f10c4d6bf3f507de4ca2f0b10a.tar.gz
lphub-cfd377e29c0fa6f10c4d6bf3f507de4ca2f0b10a.tar.bz2
lphub-cfd377e29c0fa6f10c4d6bf3f507de4ca2f0b10a.zip
Mobile Design looking decent
Diffstat (limited to 'frontend/src/pages/User.tsx')
-rw-r--r--frontend/src/pages/User.tsx627
1 files changed, 233 insertions, 394 deletions
diff --git a/frontend/src/pages/User.tsx b/frontend/src/pages/User.tsx
index 4b8a456..8c699b1 100644
--- a/frontend/src/pages/User.tsx
+++ b/frontend/src/pages/User.tsx
@@ -97,473 +97,312 @@ const User: React.FC<UserProps> = ({ token, profile, gameData }) => {
97 }, [user, game, chapter, location, _get_game_maps]); 97 }, [user, game, chapter, location, _get_game_maps]);
98 98
99 if (!user) { 99 if (!user) {
100 return <></>; 100 return (
101 <div className="flex justify-center items-center h-[50vh] text-lg text-foreground">
102 Loading...
103 </div>
104 );
101 } 105 }
102 106
103 return ( 107 return (
104 <main> 108 <main className="ml-20 overflow-auto overflow-x-hidden relative w-[calc(100%px)] h-screen font-[--font-barlow-semicondensed-regular] text-foreground text-xl">
105 <Helmet> 109 <Helmet>
106 <title>LPHUB | {user.user_name}</title> 110 <title>LPHUB | {user.user_name}</title>
107 <meta name="description" content={user.user_name} /> 111 <meta name="description" content={user.user_name} />
108 </Helmet> 112 </Helmet>
113
109 {MessageDialogComponent} 114 {MessageDialogComponent}
110 <section id="section1" className="profile"> 115
111 <div> 116 <section className="m-5 bg-gradient-to-t from-[#202232] from-50% to-[#2b2e46] to-50% rounded-3xl p-[30px] mb-[30px] text-foreground">
112 <img src={user.avatar_link} alt="profile-image"></img> 117 <div className="grid grid-cols-[200px_1fr_auto] items-center gap-[25px] mb-[25px]">
113 </div> 118 <img
114 <div id="profile-top"> 119 src={user.avatar_link}
120 alt="Profile"
121 className="w-[120px] h-[120px] rounded-full border-[3px] border-[rgba(205,207,223,0.2)]"
122 />
115 <div> 123 <div>
116 <div>{user.user_name}</div> 124 <h1 className="m-0 mb-[10px] text-[50px] font-bold text-white font-[--font-barlow-semicondensed-regular]">
117 <div> 125 {user.user_name}
118 {user.country_code === "XX" ? ( 126 </h1>
119 "" 127 {user.country_code !== "XX" && (
120 ) : ( 128 <div className="flex items-center gap-3 mb-[15px]">
121 <img 129 <img
122 src={`https://flagcdn.com/w80/${user.country_code.toLowerCase()}.jpg`} 130 src={`https://flagcdn.com/w80/${user.country_code.toLowerCase()}.jpg`}
123 alt={user.country_code} 131 alt={user.country_code}
132 className="w-6 h-4 rounded-[10px]"
124 /> 133 />
125 )} 134 <span>{user.country_code}</span>
126 </div> 135 </div>
127 <div> 136 )}
128 {user.titles.map(e => ( 137 <div className="flex flex-wrap gap-2">
138 {user.titles.map((title, index) => (
129 <span 139 <span
130 className="titles" 140 key={index}
131 style={{ backgroundColor: `#${e.color}` }} 141 className="py-[6px] px-5 pt-[6px] rounded-[10px] text-lg font-normal text-white"
142 style={{ backgroundColor: `#${title.color}` }}
132 > 143 >
133 {e.name} 144 {title.name}
134 </span> 145 </span>
135 ))} 146 ))}
136 </div> 147 </div>
137 </div> 148 </div>
138 <div> 149 <div className="flex gap-[15px] items-center pr-[10px]">
139 {user.links.steam === "-" ? ( 150 {user.links.steam !== "-" && (
140 "" 151 <a href={user.links.steam} className="flex items-center justify-center transition-all duration-200 hover:-translate-y-0.5">
141 ) : ( 152 <img src={SteamIcon} alt="Steam" className="h-[50px] px-[5px] scale-90 brightness-200" />
142 <a href={user.links.steam}>
143 <img src={SteamIcon} alt="Steam" />
144 </a> 153 </a>
145 )} 154 )}
146 {user.links.twitch === "-" ? ( 155 {user.links.twitch !== "-" && (
147 "" 156 <a href={user.links.twitch} className="flex items-center justify-center transition-all duration-200 hover:-translate-y-0.5">
148 ) : ( 157 <img src={TwitchIcon} alt="Twitch" className="h-[50px] px-[5px] scale-90 brightness-200" />
149 <a href={user.links.twitch}>
150 <img src={TwitchIcon} alt="Twitch" />
151 </a> 158 </a>
152 )} 159 )}
153 {user.links.youtube === "-" ? ( 160 {user.links.youtube !== "-" && (
154 "" 161 <a href={user.links.youtube} className="flex items-center justify-center transition-all duration-200 hover:-translate-y-0.5">
155 ) : ( 162 <img src={YouTubeIcon} alt="YouTube" className="h-[50px] px-[5px] scale-90 brightness-200" />
156 <a href={user.links.youtube}>
157 <img src={YouTubeIcon} alt="Youtube" />
158 </a> 163 </a>
159 )} 164 )}
160 {user.links.p2sr === "-" ? ( 165 {user.links.p2sr !== "-" && (
161 "" 166 <a href={user.links.p2sr} className="flex items-center justify-center transition-all duration-200 hover:-translate-y-0.5">
162 ) : ( 167 <img src={PortalIcon} alt="P2SR" className="h-[50px] px-[5px] scale-90 brightness-200" />
163 <a href={user.links.p2sr}>
164 <img src={PortalIcon} alt="P2SR" style={{ padding: "0" }} />
165 </a> 168 </a>
166 )} 169 )}
167 </div> 170 </div>
168 </div> 171 </div>
169 <div id="profile-bottom"> 172
170 <div> 173 <div className="grid grid-cols-3 gap-3 mt-24">
171 <span>Overall</span> 174 <div className="m-3 bg-[#2b2e46] rounded-[20px] p-5 text-center grid place-items-center grid-rows-[40%_50%]">
172 <span> 175 <div className="text-inherit text-lg">Overall</div>
173 {user.rankings.overall.rank === 0 176 <div className="text-white text-[40px]">
174 ? "N/A " 177 {user.rankings.overall.rank === 0 ? "N/A" : `#${user.rankings.overall.rank}`}
175 : "#" + user.rankings.overall.rank + " "} 178 </div>
176 <span> 179 <div className="text-white text-xl">
177 ({user.rankings.overall.completion_count}/ 180 {user.rankings.overall.completion_count}/{user.rankings.overall.completion_total}
178 {user.rankings.overall.completion_total}) 181 </div>
179 </span>
180 </span>
181 </div> 182 </div>
182 <div> 183 <div className="m-3 bg-[#2b2e46] rounded-[20px] p-5 text-center grid place-items-center grid-rows-[40%_50%]">
183 <span>Singleplayer</span> 184 <div className="text-inherit text-lg">Singleplayer</div>
184 <span> 185 <div className="text-white text-[40px]">
185 {user.rankings.singleplayer.rank === 0 186 {user.rankings.singleplayer.rank === 0 ? "N/A" : `#${user.rankings.singleplayer.rank}`}
186 ? "N/A " 187 </div>
187 : "#" + user.rankings.singleplayer.rank + " "} 188 <div className="text-white text-xl">
188 <span> 189 {user.rankings.singleplayer.completion_count}/{user.rankings.singleplayer.completion_total}
189 ({user.rankings.singleplayer.completion_count}/ 190 </div>
190 {user.rankings.singleplayer.completion_total})
191 </span>
192 </span>
193 </div> 191 </div>
194 <div> 192 <div className="m-3 bg-[#2b2e46] rounded-[20px] p-5 text-center grid place-items-center grid-rows-[40%_50%]">
195 <span>Cooperative</span> 193 <div className="text-inherit text-lg">Cooperative</div>
196 <span> 194 <div className="text-white text-[40px]">
197 {user.rankings.cooperative.rank === 0 195 {user.rankings.cooperative.rank === 0 ? "N/A" : `#${user.rankings.cooperative.rank}`}
198 ? "N/A " 196 </div>
199 : "#" + user.rankings.cooperative.rank + " "} 197 <div className="text-white text-xl">
200 <span> 198 {user.rankings.cooperative.completion_count}/{user.rankings.cooperative.completion_total}
201 ({user.rankings.cooperative.completion_count}/ 199 </div>
202 {user.rankings.cooperative.completion_total})
203 </span>
204 </span>
205 </div> 200 </div>
206 </div> 201 </div>
207 </section> 202 </section>
208 203
209 <section id="section2" className="profile"> 204 <section className="m-5 h-[60px] grid grid-cols-2">
210 <button onClick={() => setNavState(0)}> 205 <button
211 <img src={FlagIcon} alt="" /> 206 className={`flex justify-center items-center gap-2 bg-[#2b2e46] border-0 text-inherit font-inherit text-2xl cursor-pointer transition-colors duration-100 rounded-l-3xl hover:bg-[#202232] ${
212 &nbsp;Player Records 207 navState === 0 ? 'bg-[#202232]' : ''
208 }`}
209 onClick={() => setNavState(0)}
210 >
211 <img src={FlagIcon} alt="" className="w-5 h-5 scale-[1.2]" />
212 Player Records
213 </button> 213 </button>
214 <button onClick={() => setNavState(1)}> 214 <button
215 <img src={StatisticsIcon} alt="" /> 215 className={`flex justify-center items-center gap-2 bg-[#2b2e46] border-0 text-inherit font-inherit text-2xl cursor-pointer transition-colors duration-100 rounded-r-3xl hover:bg-[#202232] ${
216 &nbsp;Statistics 216 navState === 1 ? 'bg-[#202232]' : ''
217 }`}
218 onClick={() => setNavState(1)}
219 >
220 <img src={StatisticsIcon} alt="" className="w-5 h-5 scale-[1.2]" />
221 Statistics
217 </button> 222 </button>
218 </section> 223 </section>
219 224
220 <section id="section3" className="profile1"> 225 {navState === 0 && (
221 <div id="profileboard-nav"> 226 <section className="m-5 block bg-[#202232] rounded-3xl overflow-hidden">
222 {gameData === null ? ( 227 <div className="grid grid-cols-2 mx-5 my-5 mt-[10px] mb-5">
223 <select>error</select>
224 ) : (
225 <select 228 <select
226 id="select-game" 229 className="h-[50px] rounded-3xl text-center text-inherit font-inherit text-2xl border-0 bg-[#2b2e46] mr-[10px]"
227 onChange={() => { 230 value={game}
228 setGame( 231 onChange={(e) => {
229 (document.querySelector("#select-game") as HTMLInputElement) 232 setGame(e.target.value);
230 .value
231 );
232 setChapter("0"); 233 setChapter("0");
233 const chapterSelect = document.querySelector(
234 "#select-chapter"
235 ) as HTMLSelectElement;
236 if (chapterSelect) {
237 chapterSelect.value = "0";
238 }
239 }} 234 }}
240 > 235 >
241 <option value={0} key={0}> 236 <option value="0">All Games</option>
242 All Scores 237 {gameData?.map((g) => (
243 </option> 238 <option key={g.id} value={g.id}>
244 {gameData.map((e, i) => ( 239 {g.name}
245 <option value={e.id} key={i + 1}>
246 {e.name}
247 </option> 240 </option>
248 ))} 241 ))}
249 </select> 242 </select>
250 )}
251 243
252 {game === "0" ? (
253 <select disabled>
254 <option>All Chapters</option>
255 </select>
256 ) : chapterData === null ? (
257 <select></select>
258 ) : (
259 <select 244 <select
260 id="select-chapter" 245 className="h-[50px] rounded-3xl text-center text-inherit font-inherit text-2xl border-0 bg-[#2b2e46] mr-[10px] disabled:opacity-50"
261 onChange={() => 246 value={chapter}
262 setChapter( 247 onChange={(e) => setChapter(e.target.value)}
263 ( 248 disabled={game === "0"}
264 document.querySelector(
265 "#select-chapter"
266 ) as HTMLInputElement
267 ).value
268 )
269 }
270 > 249 >
271 <option value="0" key="0"> 250 <option value="0">All Chapters</option>
272 All Chapters 251 {chapterData?.chapters
273 </option> 252 .filter(c => !c.is_disabled)
274 {chapterData.chapters 253 .map((c) => (
275 .filter(e => e.is_disabled === false) 254 <option key={c.id} value={c.id}>
276 .map((e, i) => ( 255 {c.name}
277 <option value={e.id} key={i + 1}>
278 {e.name}
279 </option> 256 </option>
280 ))} 257 ))}
281 </select> 258 </select>
282 )} 259 </div>
283 </div> 260
284 <div id="profileboard-top"> 261 <div className="h-[34px] grid text-xl pl-[60px] mx-5 my-0 grid-cols-[15%_15%_5%_15%_5%_15%_15%_15%]">
285 <span> 262 <div className="flex place-items-end cursor-pointer">
286 <span>Map Name</span> 263 <span>Map Name</span>
287 <img src={SortIcon} alt="" /> 264 <img src={SortIcon} alt="Sort" className="h-5 scale-[0.8]" />
288 </span> 265 </div>
289 <span style={{ justifyContent: "center" }}> 266 <div className="flex place-items-end cursor-pointer">
290 <span>Portals</span> 267 <span>Portals</span>
291 <img src={SortIcon} alt="" /> 268 <img src={SortIcon} alt="Sort" className="h-5 scale-[0.8]" />
292 </span> 269 </div>
293 <span style={{ justifyContent: "center" }}> 270 <div className="flex place-items-end cursor-pointer">
294 <span>WRΔ </span> 271 <span>WRΔ</span>
295 <img src={SortIcon} alt="" /> 272 <img src={SortIcon} alt="Sort" className="h-5 scale-[0.8]" />
296 </span> 273 </div>
297 <span style={{ justifyContent: "center" }}> 274 <div className="flex place-items-end cursor-pointer">
298 <span>Time</span> 275 <span>Time</span>
299 <img src={SortIcon} alt="" /> 276 <img src={SortIcon} alt="Sort" className="h-5 scale-[0.8]" />
300 </span> 277 </div>
301 <span> </span> 278 <div></div>
302 <span> 279 <div className="flex place-items-end cursor-pointer">
303 <span>Rank</span> 280 <span>Rank</span>
304 <img src={SortIcon} alt="" /> 281 <img src={SortIcon} alt="Sort" className="h-5 scale-[0.8]" />
305 </span> 282 </div>
306 <span> 283 <div className="flex place-items-end cursor-pointer">
307 <span>Date</span> 284 <span>Date</span>
308 <img src={SortIcon} alt="" /> 285 <img src={SortIcon} alt="Sort" className="h-5 scale-[0.8]" />
309 </span> 286 </div>
310 <div id="page-number"> 287 <div className="flex items-center gap-[10px] justify-center">
311 <div>
312 <button 288 <button
313 onClick={() => { 289 className="w-8 h-8 border border-[#2b2e46] bg-[#2b2e46] rounded cursor-pointer flex items-center justify-center text-foreground transition-colors duration-100 hover:bg-[#202232] disabled:opacity-50 disabled:cursor-not-allowed"
314 if (pageNumber !== 1) { 290 onClick={() => setPageNumber(Math.max(1, pageNumber - 1))}
315 setPageNumber(prevPageNumber => prevPageNumber - 1); 291 disabled={pageNumber === 1}
316 const records = document.querySelectorAll(
317 ".profileboard-record"
318 );
319 records.forEach(r => {
320 (r as HTMLInputElement).style.height = "44px";
321 });
322 }
323 }}
324 > 292 >
325 <i 293
326 className="triangle"
327 style={{ position: "relative", left: "-5px" }}
328 ></i>{" "}
329 </button> 294 </button>
330 <span> 295 <span className="text-sm text-foreground">{pageNumber}/{pageMax}</span>
331 {pageNumber}/{pageMax}
332 </span>
333 <button 296 <button
334 onClick={() => { 297 className="w-8 h-8 border border-[#2b2e46] bg-[#2b2e46] rounded cursor-pointer flex items-center justify-center text-foreground transition-colors duration-100 hover:bg-[#202232] disabled:opacity-50 disabled:cursor-not-allowed"
335 if (pageNumber !== pageMax) { 298 onClick={() => setPageNumber(Math.min(pageMax, pageNumber + 1))}
336 setPageNumber(prevPageNumber => prevPageNumber + 1); 299 disabled={pageNumber === pageMax}
337 const records = document.querySelectorAll(
338 ".profileboard-record"
339 );
340 records.forEach(r => {
341 (r as HTMLInputElement).style.height = "44px";
342 });
343 }
344 }}
345 > 300 >
346 <i 301
347 className="triangle"
348 style={{
349 position: "relative",
350 left: "5px",
351 transform: "rotate(180deg)",
352 }}
353 ></i>{" "}
354 </button> 302 </button>
355 </div> 303 </div>
356 </div> 304 </div>
357 </div>
358 <hr />
359 <div id="profileboard-records">
360 {game === "0" ? (
361 user.records
362 .sort((a, b) => a.map_id - b.map_id)
363 .map((r, index) =>
364 Math.ceil((index + 1) / 20) === pageNumber ? (
365 <button className="profileboard-record" key={index}>
366 {r.scores.map((e, i) => (
367 <>
368 {i !== 0 ? (
369 <hr style={{ gridColumn: "1 / span 8" }} />
370 ) : (
371 ""
372 )}
373
374 <Link to={`/maps/${r.map_id}`}>
375 <span>{r.map_name}</span>
376 </Link>
377 305
378 <span style={{ display: "grid" }}>{e.score_count}</span> 306 <div>
379 307 {game === "0" ? (
380 <span style={{ display: "grid" }}> 308 user.records
381 {e.score_count - r.map_wr_count > 0 309 .sort((a, b) => a.map_id - b.map_id)
382 ? `+${e.score_count - r.map_wr_count}` 310 .map((record, index) =>
383 : `-`} 311 Math.ceil((index + 1) / 20) === pageNumber ? (
384 </span> 312 <div key={index} className="w-[calc(100%-40px)] mx-5 my-0 mt-[10px] h-11 rounded-[20px] pl-[40px] text-xl text-inherit font-inherit border-0 transition-colors duration-100 bg-[#2b2e46] grid grid-cols-[15%_15%_5%_15%_5%_15%_15%_15%] overflow-hidden whitespace-nowrap cursor-pointer hover:bg-[#202232]">
385 <span style={{ display: "grid" }}> 313 <Link to={`/maps/${record.map_id}`} className="text-[#3c91e6] no-underline font-inherit flex place-items-center h-11 hover:underline">
386 {ticks_to_time(e.score_time)} 314 {record.map_name}
387 </span> 315 </Link>
388 <span> </span> 316 <span className="flex place-items-center h-11">{record.scores[0]?.score_count || 'N/A'}</span>
389 {i === 0 ? <span>#{r.placement}</span> : <span> </span>} 317 <span className={`flex place-items-center h-11 ${record.scores[0]?.score_count - record.map_wr_count > 0 ? 'text-[#dc3545]' : ''}`}>
390 <span>{e.date.split("T")[0]}</span> 318 {record.scores[0]?.score_count - record.map_wr_count > 0
391 <span style={{ flexDirection: "row-reverse" }}> 319 ? `+${record.scores[0].score_count - record.map_wr_count}`
392 <button 320 : '–'}
393 onClick={() => { 321 </span>
394 message( 322 <span className="flex place-items-center h-11">{record.scores[0] ? ticks_to_time(record.scores[0].score_time) : 'N/A'}</span>
395 "Demo Information", 323 <span className="flex place-items-center h-11"></span>
396 `Demo ID: ${e.demo_id}` 324 <span className="flex place-items-center h-11 font-semibold">#{record.placement}</span>
397 ); 325 <span className="flex place-items-center h-11">{record.scores[0]?.date.split("T")[0] || 'N/A'}</span>
398 }} 326 <div className="flex gap-[5px] justify-end flex-row-reverse place-items-center h-11">
399 > 327 <button
400 <img src={ThreedotIcon} alt="demo_id" /> 328 className="bg-transparent border-0 cursor-pointer transition-colors duration-100 p-0.5 hover:bg-[rgba(32,34,50,0.5)]"
401 </button> 329 onClick={() => message("Demo Information", `Demo ID: ${record.scores[0]?.demo_id}`)}
402 <button 330 title="Demo Info"
403 onClick={() => 331 >
404 (window.location.href = `/api/v1/demos?uuid=${e.demo_id}`) 332 <img src={ThreedotIcon} alt="Info" className="w-4 h-4" />
405 } 333 </button>
406 > 334 <button
407 <img src={DownloadIcon} alt="download" /> 335 className="bg-transparent border-0 cursor-pointer transition-colors duration-100 p-0.5 hover:bg-[rgba(32,34,50,0.5)]"
336 onClick={() => window.location.href = `/api/v1/demos?uuid=${record.scores[0]?.demo_id}`}
337 title="Download Demo"
338 >
339 <img src={DownloadIcon} alt="Download" className="w-4 h-4" />
340 </button>
341 {record.scores.length > 1 && (
342 <button className="bg-transparent border-0 cursor-pointer transition-colors duration-100 p-0.5 hover:bg-[rgba(32,34,50,0.5)]" title="View History">
343 <img src={HistoryIcon} alt="History" className="w-4 h-4" />
408 </button> 344 </button>
409 {i === 0 && r.scores.length > 1 ? ( 345 )}
410 <button 346 </div>
411 onClick={() => { 347 </div>
412 ( 348 ) : null
413 document.querySelectorAll(
414 ".profileboard-record"
415 )[index % 20] as HTMLInputElement
416 ).style.height === "44px" ||
417 (
418 document.querySelectorAll(
419 ".profileboard-record"
420 )[index % 20] as HTMLInputElement
421 ).style.height === ""
422 ? ((
423 document.querySelectorAll(
424 ".profileboard-record"
425 )[index % 20] as HTMLInputElement
426 ).style.height =
427 `${r.scores.length * 46}px`)
428 : ((
429 document.querySelectorAll(
430 ".profileboard-record"
431 )[index % 20] as HTMLInputElement
432 ).style.height = "44px");
433 }}
434 >
435 <img src={HistoryIcon} alt="history" />
436 </button>
437 ) : (
438 ""
439 )}
440 </span>
441 </>
442 ))}
443 </button>
444 ) : (
445 ""
446 ) 349 )
447 ) 350 ) : (
448 ) : maps ? ( 351 maps
449 maps 352 ?.filter(map => !map.is_disabled)
450 .filter(e => e.is_disabled === false) 353 .sort((a, b) => a.id - b.id)
451 .sort((a, b) => a.id - b.id) 354 .map((map, index) => {
452 .map((r, index) => { 355 if (Math.ceil((index + 1) / 20) !== pageNumber) return null;
453 if (Math.ceil((index + 1) / 20) === pageNumber) { 356
454 let record = user.records.find(e => e.map_id === r.id); 357 const record = user.records.find(r => r.map_id === map.id);
455 return record === undefined ? ( 358
456 <button 359 return (
457 className="profileboard-record" 360 <div key={index} className={`w-[calc(100%-40px)] mx-5 my-0 mt-[10px] h-11 rounded-[20px] pl-[40px] text-xl text-inherit font-inherit border-0 transition-colors duration-100 bg-[#2b2e46] grid grid-cols-[15%_15%_5%_15%_5%_15%_15%_15%] overflow-hidden whitespace-nowrap cursor-pointer hover:bg-[#202232] ${!record ? 'opacity-65' : ''}`}>
458 key={index} 361 <Link to={`/maps/${map.id}`} className="text-[#3c91e6] no-underline font-inherit flex place-items-center h-11 hover:underline">
459 style={{ backgroundColor: "#1b1b20" }} 362 {map.name}
460 >
461 <Link to={`/maps/${r.id}`}>
462 <span>{r.name}</span>
463 </Link> 363 </Link>
464 <span style={{ display: "grid" }}>N/A</span> 364 <span className="flex place-items-center h-11">{record?.scores[0]?.score_count || 'N/A'}</span>
465 <span style={{ display: "grid" }}>N/A</span> 365 <span className={`flex place-items-center h-11 ${record?.scores[0]?.score_count && record.scores[0].score_count - record.map_wr_count > 0 ? 'text-[#dc3545]' : ''}`}>
466 <span>N/A</span> 366 {record?.scores[0]?.score_count && record.scores[0].score_count - record.map_wr_count > 0
467 <span> </span> 367 ? `+${record.scores[0].score_count - record.map_wr_count}`
468 <span>N/A</span> 368 : '–'}
469 <span>N/A</span> 369 </span>
470 <span style={{ flexDirection: "row-reverse" }}></span> 370 <span className="flex place-items-center h-11">{record?.scores[0] ? ticks_to_time(record.scores[0].score_time) : 'N/A'}</span>
471 </button> 371 <span className="flex place-items-center h-11"></span>
472 ) : ( 372 <span className="flex place-items-center h-11 font-semibold">{record ? `#${record.placement}` : 'N/A'}</span>
473 <button className="profileboard-record" key={index}> 373 <span className="flex place-items-center h-11">{record?.scores[0]?.date.split("T")[0] || 'N/A'}</span>
474 {record.scores.map((e, i) => ( 374 <div className="flex gap-[5px] justify-end flex-row-reverse place-items-center h-11">
475 <> 375 {record?.scores[0] && (
476 {i !== 0 ? ( 376 <>
477 <hr style={{ gridColumn: "1 / span 8" }} />
478 ) : (
479 ""
480 )}
481 <Link to={`/maps/${r.id}`}>
482 <span>{r.name}</span>
483 </Link>
484 <span style={{ display: "grid" }}>
485 {record!.scores[i].score_count}
486 </span>
487 <span style={{ display: "grid" }}>
488 {record!.scores[i].score_count -
489 record!.map_wr_count >
490 0
491 ? `+${record!.scores[i].score_count - record!.map_wr_count}`
492 : `-`}
493 </span>
494 <span style={{ display: "grid" }}>
495 {ticks_to_time(record!.scores[i].score_time)}
496 </span>
497 <span> </span>
498 {i === 0 ? (
499 <span>#{record!.placement}</span>
500 ) : (
501 <span> </span>
502 )}
503 <span>{record!.scores[i].date.split("T")[0]}</span>
504 <span style={{ flexDirection: "row-reverse" }}>
505 <button 377 <button
506 onClick={() => { 378 className="bg-transparent border-0 cursor-pointer transition-colors duration-100 p-0.5 hover:bg-[rgba(32,34,50,0.5)]"
507 message( 379 onClick={() => message("Demo Information", `Demo ID: ${record.scores[0].demo_id}`)}
508 "Demo Information", 380 title="Demo Info"
509 `Demo ID: ${e.demo_id}`
510 );
511 }}
512 > 381 >
513 <img src={ThreedotIcon} alt="demo_id" /> 382 <img src={ThreedotIcon} alt="Info" className="w-4 h-4" />
514 </button> 383 </button>
515 <button 384 <button
516 onClick={() => 385 className="bg-transparent border-0 cursor-pointer transition-colors duration-100 p-0.5 hover:bg-[rgba(32,34,50,0.5)]"
517 (window.location.href = `/api/v1/demos?uuid=${e.demo_id}`) 386 onClick={() => window.location.href = `/api/v1/demos?uuid=${record.scores[0].demo_id}`}
518 } 387 title="Download Demo"
519 > 388 >
520 <img src={DownloadIcon} alt="download" /> 389 <img src={DownloadIcon} alt="Download" className="w-4 h-4" />
521 </button> 390 </button>
522 {i === 0 && record!.scores.length > 1 ? ( 391 {record.scores.length > 1 && (
523 <button 392 <button className="bg-transparent border-0 cursor-pointer transition-colors duration-100 p-0.5 hover:bg-[rgba(32,34,50,0.5)]" title="View History">
524 onClick={() => { 393 <img src={HistoryIcon} alt="History" className="w-4 h-4" />
525 (
526 document.querySelectorAll(
527 ".profileboard-record"
528 )[index % 20] as HTMLInputElement
529 ).style.height === "44px" ||
530 (
531 document.querySelectorAll(
532 ".profileboard-record"
533 )[index % 20] as HTMLInputElement
534 ).style.height === ""
535 ? ((
536 document.querySelectorAll(
537 ".profileboard-record"
538 )[index % 20] as HTMLInputElement
539 ).style.height =
540 `${record!.scores.length * 46}px`)
541 : ((
542 document.querySelectorAll(
543 ".profileboard-record"
544 )[index % 20] as HTMLInputElement
545 ).style.height = "44px");
546 }}
547 >
548 <img src={HistoryIcon} alt="history" />
549 </button> 394 </button>
550 ) : (
551 ""
552 )} 395 )}
553 </span> 396 </>
554 </> 397 )}
555 ))} 398 </div>
556 </button> 399 </div>
557 ); 400 );
558 } else { 401 })
559 return null; 402 )}
560 } 403 </div>
561 }) 404 </section>
562 ) : ( 405 )}
563 <>{console.warn(maps)}</>
564 )}
565 </div>
566 </section>
567 </main> 406 </main>
568 ); 407 );
569}; 408};