aboutsummaryrefslogtreecommitdiff
path: root/frontend/src/pages/Maplist
diff options
context:
space:
mode:
Diffstat (limited to 'frontend/src/pages/Maplist')
-rw-r--r--frontend/src/pages/Maplist/Maplist.tsx249
1 files changed, 249 insertions, 0 deletions
diff --git a/frontend/src/pages/Maplist/Maplist.tsx b/frontend/src/pages/Maplist/Maplist.tsx
new file mode 100644
index 0000000..572eb27
--- /dev/null
+++ b/frontend/src/pages/Maplist/Maplist.tsx
@@ -0,0 +1,249 @@
1import React, { useEffect } from "react";
2import { Link, useLocation, useNavigate, useParams } from "react-router-dom";
3import { Helmet } from "react-helmet";
4
5import { API } from "@api/Api.ts";
6import { Game } from "@customTypes/Game.ts";
7import { GameChapter, GamesChapters } from "@customTypes/Chapters.ts";
8
9const Maplist: React.FC = () => {
10 const [game, setGame] = React.useState<Game | null>(null);
11 const [catNum, setCatNum] = React.useState(0);
12 const [id, setId] = React.useState(0);
13 const [load, setLoad] = React.useState(false);
14 const [currentlySelected, setCurrentlySelected] = React.useState<number>(0);
15 const [hasClicked, setHasClicked] = React.useState(false);
16 const [gameChapters, setGameChapters] = React.useState<GamesChapters>();
17 const [curChapter, setCurChapter] = React.useState<GameChapter>();
18 const [numChapters, setNumChapters] = React.useState<number>(0);
19
20 const [dropdownActive, setDropdownActive] = React.useState("none");
21
22 const params = useParams<{ id: string; chapter: string }>();
23 const location = useLocation();
24 const navigate = useNavigate();
25
26 function _update_currently_selected(catNum2: number) {
27 setCurrentlySelected(catNum2);
28 navigate("/games/" + game?.id + "?cat=" + catNum2);
29 setHasClicked(true);
30 }
31
32 const _fetch_chapters = async (chapter_id: string) => {
33 const chapters = await API.get_chapters(chapter_id);
34 setCurChapter(chapters);
35 };
36
37 const _handle_dropdown_click = () => {
38 if (dropdownActive === "none") {
39 setDropdownActive("block");
40 } else {
41 setDropdownActive("none");
42 }
43 };
44
45 // im sorry but im too lazy to fix this right now
46 useEffect(() => {
47 // gameID
48 const gameId = parseFloat(params.id || "");
49 setId(gameId);
50
51 // location query params
52 const queryParams = new URLSearchParams(location.search);
53 if (queryParams.get("chapter")) {
54 let cat = parseFloat(queryParams.get("chapter") || "");
55 if (gameId === 2) {
56 cat += 10;
57 }
58 _fetch_chapters(cat.toString());
59 }
60
61 const _fetch_game = async () => {
62 const games = await API.get_games();
63 const foundGame = games.find(game => game.id === gameId);
64 // console.log(foundGame)
65 if (foundGame) {
66 setGame(foundGame);
67 setLoad(false);
68 }
69 };
70
71 const _fetch_game_chapters = async () => {
72 const games_chapters = await API.get_games_chapters(gameId.toString());
73 setGameChapters(games_chapters);
74 setNumChapters(games_chapters.chapters.length);
75 };
76
77 setLoad(true);
78 _fetch_game();
79 _fetch_game_chapters();
80 }, [location.search]);
81
82 useEffect(() => {
83 const queryParams = new URLSearchParams(location.search);
84 if (gameChapters !== undefined && !queryParams.get("chapter")) {
85 _fetch_chapters(gameChapters!.chapters[0].id.toString());
86 }
87 }, [gameChapters, location.search]);
88
89 return (
90 <main className="*:text-foreground w-[calc(100vw-80px)] relative left-0 ml-20 min-h-screen p-4 sm:p-8">
91 <Helmet>
92 <title>LPHUB | Maplist</title>
93 </Helmet>
94
95 <section className="mt-5">
96 <Link to="/games">
97 <button className="nav-button rounded-[20px] h-10 bg-surface border-0 text-foreground text-lg font-[--font-barlow-semicondensed-regular] transition-colors duration-100 hover:bg-surface2 flex items-center px-2">
98 <i className="triangle mr-2"></i>
99 <span className="px-2">Games List</span>
100 </button>
101 </Link>
102 </section>
103
104 {load ? (
105 <div></div>
106 ) : (
107 <section>
108 <h1 className="font-[--font-barlow-condensed-bold] text-3xl sm:text-6xl my-0 text-foreground">
109 {game?.name}
110 </h1>
111
112 <div
113 className="text-center rounded-3xl overflow-hidden bg-cover bg-[25%] mt-3 relative"
114 style={{ backgroundImage: `url(${game?.image})` }}
115 >
116 <div className="backdrop-blur-sm flex flex-col w-full">
117 <div className="h-full flex flex-col justify-center items-center py-6">
118 <h2 className="my-5 font-[--font-barlow-semicondensed-semibold] text-4xl sm:text-8xl text-foreground">
119 {
120 game?.category_portals.find(
121 obj => obj.category.id === catNum + 1
122 )?.portal_count
123 }
124 </h2>
125 <h3 className="font-[--font-barlow-semicondensed-regular] mx-2.5 text-2xl sm:text-4xl my-0 text-foreground">
126 portals
127 </h3>
128 </div>
129
130 <div className="flex h-12 bg-surface gap-0.5">
131 {game?.category_portals.map((cat, index) => (
132 <button
133 key={index}
134 className={`border-0 text-foreground font-[--font-barlow-semicondensed-regular] text-sm sm:text-xl cursor-pointer transition-all duration-100 w-full ${
135 currentlySelected === cat.category.id ||
136 (cat.category.id - 1 === catNum && !hasClicked)
137 ? "bg-surface"
138 : "bg-surface1 hover:bg-surface"
139 }`}
140 onClick={() => {
141 setCatNum(cat.category.id - 1);
142 _update_currently_selected(cat.category.id);
143 }}
144 >
145 <span className="truncate">{cat.category.name}</span>
146 </button>
147 ))}
148 </div>
149 </div>
150 </div>
151
152 <div>
153 <section>
154 <div>
155 <span className="text-lg sm:text-lg translate-y-1.5 block mt-2.5 text-foreground">
156 {curChapter?.chapter.name.split(" - ")[0]}
157 </span>
158 </div>
159 <div
160 onClick={_handle_dropdown_click}
161 className="cursor-pointer select-none flex w-fit items-center"
162 >
163 <span className="text-foreground text-base sm:text-2xl">
164 {curChapter?.chapter.name.split(" - ")[1]}
165 </span>
166 <i className="triangle translate-x-1.5 translate-y-2 -rotate-90"></i>
167 </div>
168 \
169 <div
170 className={`absolute z-[1000] bg-surface1 rounded-2xl overflow-hidden p-1 animate-in fade-in duration-100 ${
171 dropdownActive === "none" ? "hidden" : "block"
172 }`}
173 >
174 {gameChapters?.chapters.map((chapter, i) => {
175 return (
176 <div
177 key={i}
178 className="cursor-pointer text-base sm:text-xl rounded-[2000px] p-1 hover:bg-surface text-foreground"
179 onClick={() => {
180 _fetch_chapters(chapter.id.toString());
181 _handle_dropdown_click();
182 }}
183 >
184 {chapter.name}
185 </div>
186 );
187 })}
188 </div>
189 </section>
190
191 <section className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-5 my-5">
192 {curChapter?.maps.map((map, i) => {
193 return (
194 <div key={i} className="bg-surface rounded-3xl overflow-hidden">
195 <Link to={`/maps/${map.id}`}>
196 <span className="text-center text-base sm:text-xl w-full block my-1.5 text-foreground truncate">
197 {map.name}
198 </span>
199 <div
200 className="flex h-40 sm:h-48 bg-cover relative"
201 style={{ backgroundImage: `url(${map.image})` }}
202 >
203 <div className="backdrop-blur-sm w-full flex items-center justify-center">
204 <span className="text-2xl sm:text-4xl font-[--font-barlow-semicondensed-semibold] text-white mr-1.5">
205 {map.is_disabled
206 ? map.category_portals[0].portal_count
207 : map.category_portals.find(
208 obj => obj.category.id === catNum + 1
209 )?.portal_count}
210 </span>
211 <span className="text-2xl sm:text-4xl font-[--font-barlow-semicondensed-regular] text-white">
212 portals
213 </span>
214 </div>
215 </div>
216
217 <div className="flex mx-2.5 my-4">
218 <div className="flex w-full items-center justify-center gap-1.5 rounded-[2000px] ml-0.5 translate-y-px">
219 {[1, 2, 3, 4, 5].map((point) => (
220 <div
221 key={point}
222 className={`flex h-0.5 w-full rounded-3xl ${
223 point <= (map.difficulty + 1)
224 ? map.difficulty === 0
225 ? "bg-green-500"
226 : map.difficulty === 1 || map.difficulty === 2
227 ? "bg-lime-500"
228 : map.difficulty === 3
229 ? "bg-red-400"
230 : "bg-red-600"
231 : "bg-surface1"
232 }`}
233 />
234 ))}
235 </div>
236 </div>
237 </Link>
238 </div>
239 );
240 })}
241 </section>
242 </div>
243 </section>
244 )}
245 </main>
246 );
247};
248
249export default Maplist;