aboutsummaryrefslogtreecommitdiff
path: root/frontend/src/pages/User.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'frontend/src/pages/User.tsx')
-rw-r--r--frontend/src/pages/User.tsx320
1 files changed, 320 insertions, 0 deletions
diff --git a/frontend/src/pages/User.tsx b/frontend/src/pages/User.tsx
new file mode 100644
index 0000000..1f6d8d0
--- /dev/null
+++ b/frontend/src/pages/User.tsx
@@ -0,0 +1,320 @@
1import React from 'react';
2import { useLocation } from 'react-router-dom';
3
4import { SteamIcon, TwitchIcon, YouTubeIcon, PortalIcon, FlagIcon, StatisticsIcon, SortIcon, ThreedotIcon, DownloadIcon, HistoryIcon } from '../images/Images';
5import { UserProfile } from '../types/Profile';
6import { Game, GameChapters } from '../types/Game';
7import { Map } from '../types/Map';
8import { API } from '../api/Api';
9import { ticks_to_time } from '../utils/Time';
10import "../css/Profile.css";
11
12const User: React.FC = () => {
13 const location = useLocation();
14
15 const [user, setUser] = React.useState<UserProfile | undefined>(undefined);
16
17 const [navState, setNavState] = React.useState(0);
18 const [pageNumber, setPageNumber] = React.useState(1);
19 const [pageMax, setPageMax] = React.useState(0);
20
21 const [game, setGame] = React.useState("0")
22 const [gameData, setGameData] = React.useState<Game[]>([]);
23 const [chapter, setChapter] = React.useState("0")
24 const [chapterData, setChapterData] = React.useState<GameChapters | null>(null);
25 const [maps, setMaps] = React.useState<Map[]>([]);
26
27 function NavClick() {
28 if (user) {
29 const btn = document.querySelectorAll("#section2 button");
30 btn.forEach((e) => { (e as HTMLElement).style.backgroundColor = "#2b2e46" });
31 (btn[navState] as HTMLElement).style.backgroundColor = "#202232";
32
33 document.querySelectorAll("section").forEach((e, i) => i >= 2 ? e.style.display = "none" : "")
34 if (navState === 0) { document.querySelectorAll(".profile1").forEach((e) => { (e as HTMLElement).style.display = "block" }); }
35 if (navState === 1) { document.querySelectorAll(".profile2").forEach((e) => { (e as HTMLElement).style.display = "block" }); }
36 }
37 }
38
39 function UpdateProfile() {
40 fetch(`https://lp.ardapektezol.com/api/v1/profile`, {
41 method: 'POST',
42 headers: { Authorization: "" }
43 }).then(r => r.json())
44 .then(d => d.success ? window.alert("profile updated") : window.alert(`Error: ${d.message}`))
45 }
46
47 const _fetch_user = async () => {
48 const userData = await API.get_user(location.pathname.split("/")[2]);
49 setUser(userData);
50 };
51
52 React.useEffect(() => {
53 fetch("https://lp.ardapektezol.com/api/v1/games")
54 .then(r => r.json())
55 .then(d => {
56 setGameData(d.data)
57 setGame("0")
58 })
59
60 }, [location]);
61
62 React.useEffect(() => {
63 if (user) {
64 if (game && game !== "0") {
65 fetch(`https://lp.ardapektezol.com/api/v1/games/${game}`)
66 .then(r => r.json())
67 .then(d => {
68 setChapterData(d.data)
69 setChapter("0");
70 // (document.querySelector('#select-chapter') as HTMLInputElement).value = "0"
71 })
72
73 } else if (game && game === "0") {
74 setPageMax(Math.ceil(user.records.length / 20))
75 setPageNumber(1)
76 }
77 }
78 }, [user, game, location]);
79
80 React.useEffect(() => {
81 _fetch_user();
82 }, []);
83
84 React.useEffect(() => {
85 if (game !== "0") {
86 if (chapter === "0") {
87 fetch(`https://lp.ardapektezol.com/api/v1/games/${game}/maps`)
88 .then(r => r.json())
89 .then(d => {
90 setMaps(d.data.maps);
91 setPageMax(Math.ceil(d.data.maps.length / 20))
92 setPageNumber(1)
93 })
94 } else {
95 fetch(`https://lp.ardapektezol.com/api/v1/chapters/${chapter}`)
96 .then(r => r.json())
97 .then(d => {
98 setMaps(d.data.maps);
99 setPageMax(Math.ceil(d.data.maps.length / 20))
100 setPageNumber(1)
101 })
102
103 }
104 }
105 }, [game, chapter, chapterData])
106
107 if (!user) {
108 return (
109 <></>
110 );
111 };
112
113 return (
114 <main>
115 <section id='section1' className='profile'>
116
117 {user.profile
118 ? (
119 <div id='profile-image' onClick={() => UpdateProfile()}>
120 <img src={user.avatar_link} alt="profile-image"></img>
121 <span>Refresh</span>
122 </div>
123 ) : (
124 <div>
125 <img src={user.avatar_link} alt="profile-image"></img>
126 </div>
127 )}
128
129 <div id='profile-top'>
130 <div>
131 <div>{user.user_name}</div>
132 <div>
133 {user.country_code === "XX" ? "" : <img src={`https://flagcdn.com/w80/${user.country_code.toLowerCase()}.jpg`} alt={user.country_code} />}
134 </div>
135 <div>
136 {user.titles.map(e => (
137 <span className="titles" style={{ backgroundColor: `#${e.color}` }}>
138 {e.name}
139 </span>
140 ))}
141 </div>
142 </div>
143 <div>
144 {user.links.steam === "-" ? "" : <a href={user.links.steam}><img src={SteamIcon} alt="Steam" /></a>}
145 {user.links.twitch === "-" ? "" : <a href={user.links.twitch}><img src={TwitchIcon} alt="Twitch" /></a>}
146 {user.links.youtube === "-" ? "" : <a href={user.links.youtube}><img src={YouTubeIcon} alt="Youtube" /></a>}
147 {user.links.p2sr === "-" ? "" : <a href={user.links.p2sr}><img src={PortalIcon} alt="P2SR" style={{ padding: "0" }} /></a>}
148 </div>
149
150 </div>
151 <div id='profile-bottom'>
152 <div>
153 <span>Overall</span>
154 <span>{user.rankings.overall.rank === 0 ? "N/A " : "#" + user.rankings.overall.rank + " "}
155 <span>({user.rankings.overall.completion_count}/{user.rankings.overall.completion_total})</span>
156 </span>
157 </div>
158 <div>
159 <span>Singleplayer</span>
160 <span>{user.rankings.singleplayer.rank === 0 ? "N/A " : "#" + user.rankings.singleplayer.rank + " "}
161 <span>({user.rankings.singleplayer.completion_count}/{user.rankings.singleplayer.completion_total})</span>
162 </span>
163 </div>
164 <div>
165 <span>Cooperative</span>
166 <span>{user.rankings.cooperative.rank === 0 ? "N/A " : "#" + user.rankings.cooperative.rank + " "}
167 <span>({user.rankings.cooperative.completion_count}/{user.rankings.cooperative.completion_total})</span>
168 </span>
169 </div>
170 </div>
171 </section>
172
173
174 <section id='section2' className='profile'>
175 <button onClick={() => setNavState(0)}><img src={FlagIcon} alt="" />&nbsp;Player Records</button>
176 <button onClick={() => setNavState(1)}><img src={StatisticsIcon} alt="" />&nbsp;Statistics</button>
177 </section>
178
179
180
181
182
183 <section id='section3' className='profile1'>
184 <div id='profileboard-nav'>
185 {gameData === null ? <select>error</select> :
186
187 <select id='select-game'
188 onChange={() => setGame((document.querySelector('#select-game') as HTMLInputElement).value)}>
189 <option value={0} key={0}>All Scores</option>
190 {gameData.map((e, i) => (
191 <option value={e.id} key={i + 1}>{e.name}</option>
192 ))}</select>
193 }
194
195 {game === "0" ?
196 <select disabled>
197 <option>All Scores</option>
198 </select>
199 : chapterData === null ? <select></select> :
200
201 <select id='select-chapter'
202 onChange={() => setChapter((document.querySelector('#select-chapter') as HTMLInputElement).value)}>
203 <option value="0" key="0">All</option>
204 {chapterData.chapters.filter(e => e.is_disabled === false).map((e, i) => (
205 <option value={e.id} key={i + 1}>{e.name}</option>
206 ))}</select>
207 }
208 </div>
209 <div id='profileboard-top'>
210 <span><span>Map Name</span><img src={SortIcon} alt="" /></span>
211 <span style={{ justifyContent: 'center' }}><span>Portals</span><img src={SortIcon} alt="" /></span>
212 <span style={{ justifyContent: 'center' }}><span>WRΔ </span><img src={SortIcon} alt="" /></span>
213 <span style={{ justifyContent: 'center' }}><span>Time</span><img src={SortIcon} alt="" /></span>
214 <span> </span>
215 <span><span>Rank</span><img src={SortIcon} alt="" /></span>
216 <span><span>Date</span><img src={SortIcon} alt="" /></span>
217 <div id='page-number'>
218 <div>
219 <button onClick={() => pageNumber === 1 ? null : setPageNumber(prevPageNumber => prevPageNumber - 1)}
220 ><i className='triangle' style={{ position: 'relative', left: '-5px', }}></i> </button>
221 <span>{pageNumber}/{pageMax}</span>
222 <button onClick={() => pageNumber === pageMax ? null : setPageNumber(prevPageNumber => prevPageNumber + 1)}
223 ><i className='triangle' style={{ position: 'relative', left: '5px', transform: 'rotate(180deg)' }}></i> </button>
224 </div>
225 </div>
226 </div>
227 <hr />
228 <div id='profileboard-records'>
229
230 {game === "0"
231 ? (
232
233 user.records.sort((a, b) => a.map_id - b.map_id)
234 .map((r, index) => (
235
236 Math.ceil((index + 1) / 20) === pageNumber ? (
237 <button className="profileboard-record" key={index}>
238 {r.scores.map((e, i) => (<>
239 {i !== 0 ? <hr style={{ gridColumn: "1 / span 8" }} /> : ""}
240
241 <span>{r.map_name}</span>
242
243 <span style={{ display: "grid" }}>{e.score_count}</span>
244
245 <span style={{ display: "grid" }}>{e.score_count - r.map_wr_count}</span>
246 <span style={{ display: "grid" }}>{ticks_to_time(e.score_time)}</span>
247 <span> </span>
248 {i === 0 ? <span>#{r.placement}</span> : <span> </span>}
249 <span>{e.date.split("T")[0]}</span>
250 <span style={{ flexDirection: "row-reverse" }}>
251
252 <button onClick={() => { window.alert(`Demo ID: ${e.demo_id}`) }}><img src={ThreedotIcon} alt="demo_id" /></button>
253 <button onClick={() => window.location.href = `https://lp.ardapektezol.com/api/v1/demos?uuid=${e.demo_id}`}><img src={DownloadIcon} alt="download" /></button>
254 {i === 0 && r.scores.length > 1 ? <button onClick={() => {
255 (document.querySelectorAll(".profileboard-record")[index % 20] as HTMLInputElement).style.height === "44px" ||
256 (document.querySelectorAll(".profileboard-record")[index % 20] as HTMLInputElement).style.height === "" ?
257 (document.querySelectorAll(".profileboard-record")[index % 20] as HTMLInputElement).style.height = `${r.scores.length * 46}px` :
258 (document.querySelectorAll(".profileboard-record")[index % 20] as HTMLInputElement).style.height = "44px"
259 }
260 }><img src={HistoryIcon} alt="history" /></button> : ""}
261
262 </span>
263 </>))}
264
265 </button>
266 ) : ""
267 ))) : maps ?
268
269 maps.filter(e => e.is_disabled === false).sort((a, b) => a.id - b.id)
270 .map((r, index) => {
271 if (Math.ceil((index + 1) / 20) === pageNumber) {
272 let record = user.records.find((e) => e.map_id === r.id);
273 return record === undefined ? (
274 <button className="profileboard-record" key={index} style={{ backgroundColor: "#1b1b20" }}>
275 <span>{r.name}</span>
276 <span style={{ display: "grid" }}>N/A</span>
277 <span style={{ display: "grid" }}>N/A</span>
278 <span>N/A</span>
279 <span> </span>
280 <span>N/A</span>
281 <span>N/A</span>
282 <span style={{ flexDirection: "row-reverse" }}></span>
283 </button>
284 ) : (
285 <button className="profileboard-record" key={index}>
286 {record.scores.map((e, i) => (<>
287 {i !== 0 ? <hr style={{ gridColumn: "1 / span 8" }} /> : ""}
288 <span>{r.name}</span>
289 <span style={{ display: "grid" }}>{record!.scores[i].score_count}</span>
290 <span style={{ display: "grid" }}>{record!.scores[i].score_count - record!.map_wr_count}</span>
291 <span style={{ display: "grid" }}>{ticks_to_time(record!.scores[i].score_time)}</span>
292 <span> </span>
293 {i === 0 ? <span>#{record!.placement}</span> : <span> </span>}
294 <span>{record!.scores[i].date.split("T")[0]}</span>
295 <span style={{ flexDirection: "row-reverse" }}>
296
297 <button onClick={() => { window.alert(`Demo ID: ${e.demo_id}`) }}><img src={ThreedotIcon} alt="demo_id" /></button>
298 <button onClick={() => window.location.href = `https://lp.ardapektezol.com/api/v1/demos?uuid=${e.demo_id}`}><img src={DownloadIcon} alt="download" /></button>
299 {i === 0 && record!.scores.length > 1 ? <button onClick={() => {
300 (document.querySelectorAll(".profileboard-record")[index % 20] as HTMLInputElement).style.height === "44px" ||
301 (document.querySelectorAll(".profileboard-record")[index % 20] as HTMLInputElement).style.height === "" ?
302 (document.querySelectorAll(".profileboard-record")[index % 20] as HTMLInputElement).style.height = `${record!.scores.length * 46}px` :
303 (document.querySelectorAll(".profileboard-record")[index % 20] as HTMLInputElement).style.height = "44px"
304 }
305 }><img src={HistoryIcon} alt="history" /></button> : ""}
306
307 </span>
308 </>))}
309 </button>
310
311 )
312 } else { return null }
313 }) : (<>{console.warn(maps)}</>)}
314 </div>
315 </section>
316 </main>
317 );
318};
319
320export default User;