source: imaps-frontend/src/pages/MyMaps/MyMaps.jsx@ 0c6b92a

main
Last change on this file since 0c6b92a was 0c6b92a, checked in by stefan toskovski <stefantoska84@…>, 5 weeks ago

Pred finalna verzija

  • Property mode set to 100644
File size: 8.8 KB
Line 
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 {element} from "prop-types";
13import Toast from "../../components/Toast/Toast.jsx";
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);
67 setTimeout(() => setToastMessage(null), 3000); // Automatically hide the toast after 3 seconds
68 };
69
70
71 const handleUpdate = async (updatedMap) => {
72 // Placeholder for map update logic
73 };
74
75 const deleteMap = (mapName) => {
76 const httpService = new HttpService();
77 httpService.setAuthenticated();
78 const url = `${config.my_maps.delete}?mapName=${mapName}&username=${username}`;
79
80 httpService
81 .delete(url)
82 .then(() => {
83 setTiles((prevTiles) => prevTiles.filter((tile) => tile.mapName !== mapName));
84 setAllTiles((prevTiles) => prevTiles.filter((tile) => tile.mapName !== mapName));
85 showToast("Map deleted", 1)
86 })
87 .catch((error) => {
88 const errorMessage = error.response?.data?.error || error.message || "Unknown error";
89 // alert(`Error deleting the map: ${errorMessage}`);
90 showToast(`Error deleting the map: ${errorMessage}`, 0)
91 });
92 };
93
94 const addMap = (mapDetails) => {
95 const httpService = new HttpService();
96 httpService.setAuthenticated();
97
98 httpService
99 .put(`${config.my_maps.add}?username=${username}`, mapDetails)
100 .then((respMap) => {
101 console.log("RESP NEW MAP: " + respMap)
102 const mapTile = {
103 mapName: respMap.mapName,
104 cols: 1,
105 rows: 1,
106 status: respMap.mapStatus,
107 created_at: respMap.createdAt,
108 modified_at: respMap.modifiedAt,
109 published_at: respMap.published_at,
110 gmaps_url: respMap.gmaps_url,
111 image_url: card,
112 is_published: respMap.is_published,
113 };
114
115 setAllTiles((prevTiles) => [...prevTiles, mapTile]);
116 setTiles((prevTiles) => [...prevTiles, mapTile]);
117 showToast("Map added successfully!");
118
119
120 })
121 .catch((error) => {
122 showToast("Map name already taken", 0)
123 });
124 };
125
126 useEffect(() => {
127 const loadMaps = async () => {
128 const httpService = new HttpService();
129 httpService.setAuthenticated();
130
131 const respMaps = await httpService.get(`${config.my_maps.display}?username=${username}`);
132
133 const mapTiles = respMaps.map((elem) => ({
134 mapName: elem.mapName,
135 cols: 1,
136 rows: 1,
137 status: elem.mapStatus,
138 created_at: elem.createdAt,
139 modified_at: elem.modifiedAt,
140 published_at: elem.published_at,
141 gmaps_url: elem.gMapsUrl,
142 image_url: card,
143 numFavourites: elem.numFavourites,
144 }));
145
146
147 setTiles(mapTiles);
148 setAllTiles(mapTiles);
149 };
150 loadMaps();
151 }, [username]);
152
153 useEffect(() => {
154 setPublicMaps(tiles.filter((tile) => tile.status === "PUBLIC"));
155 setPrivateMaps(tiles.filter((tile) => tile.status === "PRIVATE"));
156 setPendingMaps(tiles.filter((tile) => tile.status === "INVALID"));
157 }, [tiles]);
158
159 const handleSearch = (e) => {
160 const query = e.target.value.toLowerCase();
161 setTiles(allTiles.filter((tile) => tile.mapName.toLowerCase().includes(query)));
162 };
163
164 return (
165 <div className={styles.container}>
166 <Logo/>
167 <Profile/>
168 <h1>Your Maps</h1>
169
170 <div className={styles.actionButtons}>
171 <button className={styles.createMapsButton} onClick={openCreateModal}>
172 Create Map
173 </button>
174 </div>
175
176 <div className={styles.searchBar}>
177 <input type="text" placeholder="Search for maps..." onChange={handleSearch}/>
178 </div>
179
180 <div className={styles.mapsContainer}>
181 <div className={styles.mapColumn}>
182 <h3 className={styles.categories}>Public Maps:</h3>
183 <hr/>
184 <TilesContainer
185 data={publicMaps}
186 renderTile={(tileProps) => renderTile(tileProps, openMapInfoModal)}
187 tileSize={tileSize}
188 forceTileWidth={150}
189 forceTileHeight={170}
190 />
191 </div>
192
193 <div className={styles.mapColumn}>
194 <h3 className={styles.categories}>Private Maps:</h3>
195 <hr/>
196 <TilesContainer
197 data={privateMaps}
198 renderTile={(tileProps) => renderTile(tileProps, openMapInfoModal)}
199 tileSize={tileSize}
200 forceTileWidth={150}
201 forceTileHeight={170}
202 />
203 </div>
204
205 <div className={styles.mapColumn}>
206 <h3 className={styles.categories}>Pending Approval:</h3>
207 <hr/>
208 <TilesContainer
209 data={pendingMaps}
210 renderTile={(tileProps) => renderTile(tileProps, openMapInfoModal)}
211 tileSize={tileSize}
212 forceTileWidth={150}
213 forceTileHeight={170}
214 />
215 </div>
216 </div>
217
218 <MapInfoModal
219 isOpen={isMapInfoModalOpen}
220 onClose={closeMapInfoModal}
221 map={selectedMap}
222 onDelete={deleteMap}
223 onUpdate={handleUpdate}
224 onPublish={() => {
225 showToast(`Map ${selectedMap.mapName} published successfully!`);
226 setPrivateMaps((prevMaps) => prevMaps.filter(m => m.mapName !== selectedMap.mapName))
227 setPendingMaps((prevMaps) => [...prevMaps,allTiles.find(m => m.mapName = selectedMap.mapName)])
228 closeMapInfoModal()
229 }}
230 />
231
232 <CreateMapModal
233 isOpen={isCreateModalOpen}
234 onClose={closeCreateModal}
235 addMap={addMap}
236 />
237
238 {toastMessage && <Toast message={toastMessage} type={toastType} onClose={() => setToastMessage(null)}/>}
239 </div>
240 );
241}
Note: See TracBrowser for help on using the repository browser.