source: imaps-frontend/src/pages/MyMaps/MyMaps.jsx@ 79a0317

main
Last change on this file since 79a0317 was 79a0317, checked in by stefan toskovski <stefantoska84@…>, 3 days ago

F4 Finalna Verzija

  • Property mode set to 100644
File size: 9.9 KB
RevLine 
[0c6b92a]1import React, {useEffect, useState} from "react";
2import styles from "./CreateMaps.module.css";
3import {TilesContainer} from "react-tiles-dnd";
4import MapInfoModal from "../../components/MapInfoModal/MapInfoModal.jsx";
5import CreateMapModal from "../../components/Modals/CreateMapModal/CreateMapModal.jsx";
6import HttpService from "../../scripts/net/HttpService.js";
7import card from "../../assets/card-map.png";
8import Logo from "../../components/Logo/Logo.jsx";
9import Profile from "../../components/Profile/Profile.jsx";
10import {useAppContext} from "../../components/AppContext/AppContext.jsx";
11import config from "../../scripts/net/netconfig.js";
12import Toast from "../../components/Toast/Toast.jsx";
[79a0317]13import plus_icon from "../../assets/plus_icon.png";
[0c6b92a]14
15const renderTile = ({data, isDragging}, openMapInfo) => (
16 <div style={{padding: "1rem", width: "100%"}}>
17 <div
18 className={`${styles.tile} ${isDragging ? styles.dragging : ""}`}
19 style={{width: "100%", height: "100%"}}
20 onClick={() => openMapInfo(data)}
21 >
22 <img src={card} className={styles.imgStyle} alt="Map Thumbnail"/>
23 <div className={styles.mapTitle}>{data.mapName}</div>
24 </div>
25 </div>
26);
27
28const tileSize = (tile) => ({
29 colSpan: tile.cols,
30 rowSpan: tile.rows,
31});
32
33export default function MyMaps() {
34 const [tiles, setTiles] = useState([]);
35 const [allTiles, setAllTiles] = useState([]);
36 const {username} = useAppContext();
37 const [selectedMap, setSelectedMap] = useState(null);
38 const [isMapInfoModalOpen, setIsMapInfoModalOpen] = useState(false);
39 const [isCreateModalOpen, setIsCreateModalOpen] = useState(false);
40 const [publicMaps, setPublicMaps] = useState([]);
41 const [privateMaps, setPrivateMaps] = useState([]);
42 const [pendingMaps, setPendingMaps] = useState([]);
43 const [toastMessage, setToastMessage] = useState(null);
44 const [toastType, setToastType] = useState(1);
45
46 const openMapInfoModal = (map) => {
47 setSelectedMap(map);
48 setIsMapInfoModalOpen(true);
49 };
50
51 const closeMapInfoModal = () => {
52 setIsMapInfoModalOpen(false);
53 setSelectedMap(null);
54 };
55
56 const openCreateModal = () => {
57 setIsCreateModalOpen(true);
58 };
59
60 const closeCreateModal = () => {
61 setIsCreateModalOpen(false);
62 };
63
64 const showToast = (message, type = 1) => {
65 setToastMessage(message);
66 setToastType(type);
[79a0317]67 setTimeout(() => setToastMessage(null), 3000);
[0c6b92a]68 };
69
70 const handleUpdate = async (updatedMap) => {
[79a0317]71 try {
72 let httpService = new HttpService(true);
73 const response = await httpService.post(
74 config.my_maps.edit_map_info,
75 updatedMap
76 );
77 closeMapInfoModal()
78 window.location.reload();
79
80 } catch (error) {
81 showToast("Map Name already taken", 0)
82 closeMapInfoModal()
83 }
[0c6b92a]84 };
85
86 const deleteMap = (mapName) => {
87 const httpService = new HttpService();
88 httpService.setAuthenticated();
89 const url = `${config.my_maps.delete}?mapName=${mapName}&username=${username}`;
90
91 httpService
92 .delete(url)
93 .then(() => {
94 setTiles((prevTiles) => prevTiles.filter((tile) => tile.mapName !== mapName));
95 setAllTiles((prevTiles) => prevTiles.filter((tile) => tile.mapName !== mapName));
[79a0317]96 showToast("Map deleted", 1);
[0c6b92a]97 })
98 .catch((error) => {
99 const errorMessage = error.response?.data?.error || error.message || "Unknown error";
[79a0317]100 showToast(`Error deleting the map: ${errorMessage}`, 0);
[0c6b92a]101 });
102 };
103
104 const addMap = (mapDetails) => {
105 const httpService = new HttpService();
106 httpService.setAuthenticated();
107
108 httpService
[79a0317]109 .put(`${config.my_maps.add}?username=${encodeURI(username)}`, mapDetails)
[0c6b92a]110 .then((respMap) => {
111 const mapTile = {
112 mapName: respMap.mapName,
113 cols: 1,
114 rows: 1,
115 status: respMap.mapStatus,
116 created_at: respMap.createdAt,
117 modified_at: respMap.modifiedAt,
118 published_at: respMap.published_at,
[79a0317]119 gmaps_url: respMap.gmapsUrl,
[0c6b92a]120 image_url: card,
121 is_published: respMap.is_published,
[79a0317]122 mapType: respMap.mapType
[0c6b92a]123 };
124
125 setAllTiles((prevTiles) => [...prevTiles, mapTile]);
126 setTiles((prevTiles) => [...prevTiles, mapTile]);
127 showToast("Map added successfully!");
128 })
129 .catch((error) => {
[79a0317]130 showToast("Map name already taken", 0);
[0c6b92a]131 });
132 };
133
134 useEffect(() => {
135 const loadMaps = async () => {
136 const httpService = new HttpService();
137 httpService.setAuthenticated();
138
[79a0317]139 const respMaps = await httpService.get(
140 `${config.my_maps.display}?username=${encodeURI(username)}`
141 );
[0c6b92a]142
143 const mapTiles = respMaps.map((elem) => ({
144 mapName: elem.mapName,
145 cols: 1,
146 rows: 1,
147 status: elem.mapStatus,
148 created_at: elem.createdAt,
149 modified_at: elem.modifiedAt,
150 published_at: elem.published_at,
[79a0317]151 gmaps_url: elem.gmapsUrl,
[0c6b92a]152 image_url: card,
153 numFavourites: elem.numFavourites,
154 }));
155
156 setTiles(mapTiles);
157 setAllTiles(mapTiles);
158 };
159 loadMaps();
160 }, [username]);
161
162 useEffect(() => {
163 setPublicMaps(tiles.filter((tile) => tile.status === "PUBLIC"));
164 setPrivateMaps(tiles.filter((tile) => tile.status === "PRIVATE"));
[79a0317]165 setPendingMaps(tiles.filter((tile) => tile.status === "PENDING"));
[0c6b92a]166 }, [tiles]);
167
168 const handleSearch = (e) => {
169 const query = e.target.value.toLowerCase();
170 setTiles(allTiles.filter((tile) => tile.mapName.toLowerCase().includes(query)));
171 };
172
173 return (
174 <div className={styles.container}>
175
[79a0317]176 <div className={`${styles.logoWrapper}`}>
177 <Logo/>
178 </div>
179 <h1>Your Maps</h1>
180 <div className={`${styles.profileWrapper}`}>
181 <Profile/>
[0c6b92a]182 </div>
183
[79a0317]184
[0c6b92a]185 <div className={styles.searchBar}>
[79a0317]186 <input
187 type="text"
188 placeholder="Search for maps..."
189 onChange={handleSearch}
190 />
[0c6b92a]191 </div>
192
193 <div className={styles.mapsContainer}>
194 <div className={styles.mapColumn}>
195 <h3 className={styles.categories}>Public Maps:</h3>
196 <hr/>
197 <TilesContainer
198 data={publicMaps}
199 renderTile={(tileProps) => renderTile(tileProps, openMapInfoModal)}
200 tileSize={tileSize}
201 forceTileWidth={150}
202 forceTileHeight={170}
203 />
204 </div>
205
206 <div className={styles.mapColumn}>
207 <h3 className={styles.categories}>Private Maps:</h3>
208 <hr/>
209 <TilesContainer
210 data={privateMaps}
211 renderTile={(tileProps) => renderTile(tileProps, openMapInfoModal)}
212 tileSize={tileSize}
213 forceTileWidth={150}
214 forceTileHeight={170}
215 />
[79a0317]216 <button className={styles.plusButton} onClick={openCreateModal}>
217 <img src={plus_icon} alt="Add Map"/>
218 </button>
[0c6b92a]219 </div>
220
221 <div className={styles.mapColumn}>
222 <h3 className={styles.categories}>Pending Approval:</h3>
223 <hr/>
224 <TilesContainer
225 data={pendingMaps}
226 renderTile={(tileProps) => renderTile(tileProps, openMapInfoModal)}
227 tileSize={tileSize}
228 forceTileWidth={150}
229 forceTileHeight={170}
230 />
231 </div>
232 </div>
233
234 <MapInfoModal
235 isOpen={isMapInfoModalOpen}
236 onClose={closeMapInfoModal}
237 map={selectedMap}
238 onDelete={deleteMap}
239 onUpdate={handleUpdate}
[79a0317]240 onPublish={(updatedMap = null) => {
241
242 const updatedTile = {
243 mapName: updatedMap.mapName,
244 cols: 1,
245 rows: 1,
246 status: updatedMap.mapStatus,
247 created_at: updatedMap.createdAt,
248 modified_at: updatedMap.modifiedAt,
249 published_at: updatedMap.published_at,
250 gmaps_url: updatedMap.gMapsUrl,
251 image_url: card,
252 numFavourites: updatedMap.numFavourites,
253 }
[0c6b92a]254 showToast(`Map ${selectedMap.mapName} published successfully!`);
255 setPrivateMaps((prevMaps) => prevMaps.filter(m => m.mapName !== selectedMap.mapName))
[79a0317]256 setPendingMaps((prevMaps) => [...prevMaps, updatedTile])
[0c6b92a]257 closeMapInfoModal()
258 }}
259 />
260
261 <CreateMapModal
262 isOpen={isCreateModalOpen}
263 onClose={closeCreateModal}
264 addMap={addMap}
265 />
266
[79a0317]267 {toastMessage && (
268 <Toast
269 message={toastMessage}
270 type={toastType}
271 onClose={() => setToastMessage(null)}
272 />
273 )}
[0c6b92a]274 </div>
275 );
276}
Note: See TracBrowser for help on using the repository browser.