Changeset 79a0317 for imaps-frontend/src/components
- Timestamp:
- 01/21/25 03:08:24 (3 days ago)
- Branches:
- main
- Parents:
- 0c6b92a
- Location:
- imaps-frontend/src/components
- Files:
-
- 8 added
- 24 edited
Legend:
- Unmodified
- Added
- Removed
-
imaps-frontend/src/components/DrawGuide/DrawGuide.jsx
r0c6b92a r79a0317 18 18 <div onClick={toggleModal} className={styles.overlay}></div> 19 19 <div className={styles.modalContent}> 20 <h2 >How to Use the Map Builder</h2>21 <p >Welcome to the Map Builder! Here you can create an indoor map, render it and enjoy!:</p>20 <h2 className={styles.title}>How to Use the Map Builder</h2> 21 <p className={styles.paragraph}>Welcome to the Map Builder! Here you can create an indoor map, render it and enjoy!:</p> 22 22 <br></br> 23 23 <ul> … … 35 35 </ul> 36 36 <br></br> 37 <p >After completing your map, click the render button and go to the View page to see your full featured map!</p>37 <p className={styles.paragraph}>After completing your map, click the render button and go to the View page to see your full featured map!</p> 38 38 39 39 <button className={styles.closeModal} onClick={toggleModal}> -
imaps-frontend/src/components/DrawGuide/DrawGuide.module.css
r0c6b92a r79a0317 18 18 backdrop-filter: blur(5px); /* Optional blur effect */ 19 19 z-index: 999; 20 21 } 22 23 .title{ 24 color: white; 25 } 26 27 .paragraph{ 28 color: #ababab; 20 29 } 21 30 … … 25 34 left: 50%; 26 35 transform: translate(-50%, -50%); 27 background-color: #2c2f33; /* Darker background for modal content */36 background-color: #2c2f33; 28 37 color: #ffffff; /* White text for contrast */ 29 38 padding: 20px; … … 35 44 } 36 45 37 h2 { 38 margin-bottom: 15px; 39 color: #ffffff; /* White text for the heading*/40 } 46 /*h2 {*/ 47 /* margin-bottom: 15px;*/ 48 /* color: #ffffff; !* White text for the heading *!*/ 49 /*}*/ 41 50 42 51 .btnModal { -
imaps-frontend/src/components/FilterBar/FilterBar.module.css
r0c6b92a r79a0317 1 /* Filter Bar.module.css */1 /* FilterMaps.module.css */ 2 2 * { 3 3 font-family: "Poppins", sans-serif; … … 18 18 padding: 0px 0; /* Adds some space around the buttons */ 19 19 width: 100%; 20 overflow-y: hidden; 20 21 } 21 22 22 23 .buttonValue { 23 border: 2px solid #6759ff;24 border: 2px solid rgb(37,111,123); 24 25 padding: 0.5em 1.5em; 25 26 border-radius: 3em; 26 27 background-color: transparent; 27 color: #6759ff;28 color: rgb(37,111,123); 28 29 cursor: pointer; 29 30 transition: background-color 0.3s, color 0.3s; … … 33 34 .buttonValue:hover, 34 35 .buttonValue:focus { 35 background-color: #6759ff;36 background-color: rgb(33, 98, 108); 36 37 color: #ffffff; 37 38 } 38 39 39 40 .active { 40 background-color: #6759ff;41 background-color: rgb(37,111,123); 41 42 color: #ffffff; 42 43 } … … 47 48 48 49 .scrollableContainer::-webkit-scrollbar-thumb { 49 background-color: #6759ff;50 background-color: rgb(37,111,123); 50 51 border-radius: 3px; 51 52 } -
imaps-frontend/src/components/LoadingContainer/LoadingContainer.jsx
r0c6b92a r79a0317 1 1 import React from "react"; 2 import styles from "./LoadingContainer.module.css" 2 3 3 4 export const LoadingContainer = () => { … … 5 6 <div className="loading-container"> 6 7 <div className="spinner"></div> 7 <p>Loading, please wait...</p>8 8 </div> 9 9 ); -
imaps-frontend/src/components/Logo/Logo.jsx
r0c6b92a r79a0317 1 1 import React from "react"; 2 2 import { useNavigate } from "react-router-dom"; 3 import logoImage from "../../assets/logo_icon.png";3 import novo_logo from "../../assets/novo_logo_nobg_cropped.png"; 4 4 import styles from "./Logo.module.css"; 5 5 … … 16 16 onClick={handleClick} 17 17 > 18 <img src={ logoImage} alt="Logo" className={styles.logoImage} />18 <img src={novo_logo} alt="Logo" className={styles.logoImage} /> 19 19 </div> 20 20 ); -
imaps-frontend/src/components/Logo/Logo.module.css
r0c6b92a r79a0317 8 8 9 9 .logoImage { 10 width: 50px; /* Adjust the size as needed */10 width: 80px; 11 11 height: auto; 12 12 transition: opacity 0.2s ease; 13 border-radius: 20px; 13 14 } 14 15 … … 30 31 } 31 32 32 .logoImage {33 width: 50px; /* Adjust size as needed */34 height: auto;35 transition: opacity 0.2s ease;36 }37 38 33 .logoImage:hover { 39 34 opacity: 0.8; /* Hover effect */ -
imaps-frontend/src/components/MapInfoModal/MapInfoModal.jsx
r0c6b92a r79a0317 1 import React, { useEffect, useState} from "react";1 import React, { useEffect, useState } from "react"; 2 2 import styles from "./MapInfoModal.module.css"; 3 import {json, useNavigate} from "react-router-dom";4 3 import edit_icon from "../../assets/edit_icon_black.png"; 5 4 import PublishForm from "../PublishForm/PublishForm.jsx"; 6 5 import HttpService from "../../scripts/net/HttpService.js"; 7 6 import config from "../../scripts/net/netconfig.js"; 8 import {useAppContext} from "../AppContext/AppContext.jsx"; 9 10 export default function MapInfoModal({isOpen, onClose, map, onDelete, onUpdate, onPublish, published=false}) { 7 import { useAppContext } from "../AppContext/AppContext.jsx"; 8 import { useNavigate } from "react-router-dom"; 9 10 export default function MapInfoModal({ 11 isOpen, 12 onClose, 13 map, 14 onDelete, 15 onUpdate, 16 onPublish, 17 published = false, 18 }) { 11 19 const [isEditPopupOpen, setEditPopupOpen] = useState(false); 12 const [editedName, setEditedName] = useState(map?.mapName || ""); 13 const [editedGmapsUrl, setEditedGmapsUrl] = useState(map?.gmaps_url || ""); 14 const [publishFormOpen,setPublishFormOpen] = useState(false) 20 const [editedName, setEditedName] = useState(""); 21 const [editedGmapsUrl, setEditedGmapsUrl] = useState(""); 22 const [editedType, setEditedType] = useState(""); 23 const [publishFormOpen, setPublishFormOpen] = useState(false); 15 24 const navigate = useNavigate(); 16 const[loadedFormData,setLoadedFormData] = useState(null) 17 25 const [loadedFormData, setLoadedFormData] = useState(null); 26 const { setLoading } = useAppContext(); 27 const { loading } = useAppContext(); 28 const { username } = useAppContext(); 18 29 19 30 useEffect(() => { 20 console.log("GMAPS: " + JSON.stringify(map)) 21 }, []); 22 23 const {username} = useAppContext(); 31 if (map) { 32 setEditedName(map.mapName || ""); 33 setEditedGmapsUrl(map.gmaps_url || ""); 34 setEditedType(map.mapType || ""); 35 } 36 }, [map, isEditPopupOpen]); 24 37 25 38 if (!isOpen || !map) return null; 26 39 27 40 const handleView = () => { 28 navigate(`/myMaps/ ${map.mapName}/View`)41 navigate(`/myMaps/View/${map.mapName}`); 29 42 }; 30 43 31 44 const handleEdit = () => { 32 navigate(`/myMaps/ ${map.mapName}/Draw`)45 navigate(`/myMaps/Draw/${map.mapName}`); 33 46 }; 34 47 35 48 const handleDelete = () => { 36 if (window.confirm(`Are you sure you want to delete the map "${map.mapName}"?`)) { 49 if ( 50 window.confirm(`Are you sure you want to delete the map "${map.mapName}"?`) 51 ) { 37 52 onDelete(map.mapName); 38 53 onClose(); … … 40 55 }; 41 56 42 43 57 const openEditPopup = () => { 44 58 setEditPopupOpen(true); … … 51 65 const handleEditSubmit = async () => { 52 66 const updatedMap = { 53 ...map, 54 mapName: editedName, 55 gmaps_url: editedGmapsUrl, 67 initialName: map.mapName, 68 name: editedName, 69 gmapsUrl: editedGmapsUrl, 70 type: editedType, 56 71 }; 57 58 try { 59 //await onUpdate(updatedMap); 60 setEditPopupOpen(false); 61 } catch (error) { 62 console.error("Error updating map:", error); 63 } 64 }; 65 66 const openPublishModal = async () => { 67 const httpService = new HttpService(true); 68 const respForm = await httpService.get(`${config.my_maps.publish_get}?mapName=${map.mapName}`) 69 setLoadedFormData(respForm); 70 setPublishFormOpen(true) 71 }; 72 73 const sendPublishRequest = async (formData) => { 74 const httpService = new HttpService(true); 75 formData.mapName = map.mapName; 76 console.log("FORMDATA: "+JSON.stringify(formData)) 77 await httpService.post(`${config.my_maps.publish}?username=${username}`,formData); 78 setPublishFormOpen(false) 79 onPublish() 80 } 72 onUpdate(updatedMap); 73 closeEditPopup() 74 }; 81 75 82 76 return ( 83 77 <div className={styles.modalOverlay} onClick={onClose}> 84 <div className={styles.modalContent} onClick={(e) => e.stopPropagation()}> 85 {publishFormOpen && ( 86 <PublishForm mapName={map.mapName} formData={loadedFormData} onSubmit={sendPublishRequest} onCancel={() => setPublishFormOpen(false)}/> 87 )} 88 89 <img src={map.image_url} alt="Map Thumbnail" className={styles.mapImage}/> 90 <h2 className={styles.title}> 91 {map.mapName} 92 <img 93 src={edit_icon} 94 alt="Edit" 95 className={styles.editIcon} 96 onClick={openEditPopup} 97 /> 98 </h2> 99 <p><strong>Status:</strong> {map.status}</p> 100 101 <p><strong>Created At:</strong> {new Date(map.created_at).toLocaleString()}</p> 102 <p><strong>Modified At:</strong> {new Date(map.modified_at).toLocaleString()}</p> 103 <p><strong>Published 104 At:</strong> {map.published_at ? new Date(map.published_at).toLocaleString() : "Not published yet"} 105 </p> 106 <p> 107 <strong>Google Maps URL:</strong> 108 <a href={map.gMapsUrl} rel="noopener noreferrer"> 109 Open in Google Maps 110 </a> 111 </p> 112 113 <div className={styles.buttonContainer}> 114 <button className={styles.viewButton} onClick={handleView}> 115 View 116 </button> 117 <button className={styles.editButton} onClick={handleEdit}> 118 Edit 119 </button> 120 <button className={styles.deleteButton} onClick={handleDelete}> 121 Delete 122 </button> 123 {!map.is_published && !published && ( 124 <button className={styles.publishButton} onClick={openPublishModal}> 125 Publish 78 <div 79 className={styles.modalContent} 80 onClick={(e) => e.stopPropagation()} 81 > 82 {!loading && ( 83 <> 84 <img 85 src={map.image_url} 86 alt="Map Thumbnail" 87 className={styles.mapImage} 88 /> 89 <h2 className={styles.title}> 90 {map.mapName} 91 <img 92 src={edit_icon} 93 alt="Edit" 94 className={styles.editIcon} 95 onClick={openEditPopup} 96 /> 97 </h2> 98 <p> 99 <strong>Status:</strong> {map.status} 100 </p> 101 <p> 102 <strong>Created At:</strong>{" "} 103 {new Date(map.created_at).toLocaleString()} 104 </p> 105 <p> 106 <strong>Modified At:</strong>{" "} 107 {new Date(map.modified_at).toLocaleString()} 108 </p> 109 <p> 110 <strong>Published At:</strong>{" "} 111 {map.published_at 112 ? new Date(map.published_at).toLocaleString() 113 : "Not published yet"} 114 </p> 115 <p> 116 <strong>Google Maps URL:</strong>{" "} 117 <a href={`${map.gmaps_url}`} rel="noopener noreferrer"> 118 Open in Google Maps 119 </a> 120 </p> 121 122 <div className={styles.buttonContainer}> 123 <button className={styles.viewButton} onClick={handleView}> 124 View 125 </button> 126 <button className={styles.editButton} onClick={handleEdit}> 127 Edit 128 </button> 129 <button className={styles.deleteButton} onClick={handleDelete}> 130 Delete 131 </button> 132 {!map.is_published && !published && ( 133 <button 134 className={styles.publishButton} 135 onClick={() => setPublishFormOpen(true)} 136 > 137 Publish 138 </button> 139 )} 140 </div> 141 <button className={styles.closeButton} onClick={onClose}> 142 Close 126 143 </button> 127 )} 128 </div> 129 <button className={styles.closeButton} onClick={onClose}> 130 Close 131 </button> 132 133 {isEditPopupOpen && ( 134 <div className={styles.editPopupOverlay} onClick={closeEditPopup}> 135 <div 136 className={styles.editPopupContent} 137 onClick={(e) => e.stopPropagation()} 138 > 139 <h3 className={styles.title}>Edit Map Details</h3> 140 <div className={styles.editField}> 141 <label>Map Name:</label> 142 <input 143 type="text" 144 value={editedName} 145 onChange={(e) => setEditedName(e.target.value)} 146 /> 144 145 {isEditPopupOpen && ( 146 <div 147 className={styles.editPopupOverlay} 148 onClick={closeEditPopup} 149 > 150 <div 151 className={styles.editPopupContent} 152 onClick={(e) => e.stopPropagation()} 153 > 154 <h3 className={styles.title}>Edit Map Details</h3> 155 <div className={styles.editField}> 156 <label>Map Name:</label> 157 <input 158 type="text" 159 value={editedName} 160 onChange={(e) => setEditedName(e.target.value)} 161 /> 162 </div> 163 <div className={styles.editField}> 164 <label>Google Maps URL:</label> 165 <input 166 type="text" 167 value={editedGmapsUrl} 168 onChange={(e) => setEditedGmapsUrl(e.target.value)} 169 /> 170 </div> 171 <div className={styles.editField}> 172 <label>Map Type:</label> 173 <input 174 type="text" 175 value={editedType} 176 onChange={(e) => setEditedType(e.target.value)} 177 /> 178 </div> 179 <div className={styles.editPopupButtons}> 180 <button 181 className={styles.submitButton} 182 onClick={handleEditSubmit} 183 > 184 Submit 185 </button> 186 <button 187 className={styles.cancelButton} 188 onClick={closeEditPopup} 189 > 190 Cancel 191 </button> 192 </div> 193 </div> 147 194 </div> 148 <div className={styles.editField}> 149 <label>Google Maps URL:</label> 150 <input 151 type="text" 152 value={editedGmapsUrl} 153 onChange={(e) => setEditedGmapsUrl(e.target.value)} 154 /> 155 </div> 156 <div className={styles.editPopupButtons}> 157 <button className={styles.submitButton} onClick={handleEditSubmit}> 158 Submit 159 </button> 160 <button className={styles.cancelButton} onClick={closeEditPopup}> 161 Cancel 162 </button> 163 </div> 164 </div> 165 </div> 195 )} 196 </> 166 197 )} 167 198 </div> -
imaps-frontend/src/components/MapInfoModal/MapInfoModal.module.css
r0c6b92a r79a0317 14 14 15 15 .modalContent { 16 position: relative; 16 17 background-color: white; 17 18 padding: 20px; … … 22 23 text-align: center; 23 24 animation: fadeIn 0.3s ease-out; 25 24 26 } 25 27 -
imaps-frontend/src/components/Modals/CreateMapModal/CreateMapModal.jsx
r0c6b92a r79a0317 10 10 const mapDetails = { 11 11 name: mapName, 12 type: mapType,13 12 }; 14 13 … … 34 33 /> 35 34 </label> 36 <label>37 Map Type:38 <input39 type="text"40 value={mapType}41 onChange={(e) => setMapType(e.target.value)}42 required43 />44 </label>45 35 <div className={styles.modalButtons}> 46 36 <button type="submit" className={styles.modalSubmitButton}> -
imaps-frontend/src/components/Modals/CreateMapModal/CreateMapModal.module.css
r0c6b92a r79a0317 36 36 /* Modal Buttons Container */ 37 37 .modalButtons { 38 margin-top: 1.5rem;39 38 display: flex; 40 39 justify-content: space-between; -
imaps-frontend/src/components/Modals/EntranceModal/EntranceModal.jsx
r0c6b92a r79a0317 42 42 setConnections(connections); 43 43 setIsOpen(true); 44 event.detail.map.detachKeyPressEventListeners(); 44 45 console.log(connections, "Loaded pins on modal open"); 45 46 },"openEntranceModalEvent") … … 52 53 <ModalSelectRoom shapeInfo={shapeInfo} availableRooms={ShapeQuery.findAllByTypeAndFloor(shape?.floorNum,"Room")} updateModalData={updateModalData}/> 53 54 <ModalSelectConnections2 54 availableShapes={ShapeQuery.findAllByType ("InfoPin","Entrance")} // najubo ke e entrance samo so room da mozit55 availableShapes={ShapeQuery.findAllByTypeAndFloor(map?.floorNum,"Entrance","InfoPin")} // najubo ke e entrance samo so room da mozit 55 56 addConnection={addConnection} 56 57 updateModalData={updateModalData} -
imaps-frontend/src/components/Modals/EntranceModal/EntranceModal.module.css
r0c6b92a r79a0317 34 34 left: 50%; 35 35 transform: translate(-50%, -50%); 36 background-color: #2c2f33 ;36 background-color: #2c2f33f7; 37 37 color: #ffffff !important; 38 38 padding: 20px; … … 90 90 margin-bottom: 15px; 91 91 } 92 93 /*tuka novo start*/ 94 95 label { 96 font-size: 16px; 97 font-weight: bold; 98 margin-bottom: 8px; 99 } 100 101 .customFileInput { 102 position: relative; 103 } 104 105 .uploadButton { 106 background-color: #007bff; 107 color: white; 108 border: none; 109 padding: 10px 20px; 110 border-radius: 5px; 111 cursor: pointer; 112 font-size: 16px; 113 transition: background-color 0.3s ease; 114 } 115 116 .uploadButton:hover { 117 background-color: #0056b3; 118 } 119 120 .uploadButton:focus { 121 outline: none; 122 box-shadow: 0 0 4px rgba(0, 123, 255, 0.6); 123 } 124 125 .uploadButton:active { 126 background-color: #003f7f; 127 } 128 129 /*tuka novo end*/ 92 130 93 131 .formGroup label { -
imaps-frontend/src/components/Modals/Hooks/useConnections.jsx
r0c6b92a r79a0317 5 5 6 6 const addConnection = () => { 7 console.log("TOSKA",shapeInfo)8 7 if (!shapeInfo.selectedPin || connections.includes(shapeInfo.selectedPin)) return; 9 8 -
imaps-frontend/src/components/Modals/Hooks/useModalState.jsx
r0c6b92a r79a0317 13 13 map.updateRoomNames(); 14 14 triggerMapSave(); 15 console.log("SHAPE BEF CLOSE:",shape.info)15 map.attachKeyPressEventListeners(); 16 16 } 17 17 setIsOpen(!isOpen); -
imaps-frontend/src/components/Modals/InfoPinModal/InfoPinModal.jsx
r0c6b92a r79a0317 37 37 setConnections(shape.info.selectedPins || []); 38 38 setIsOpen(true); 39 event.detail.map.detachKeyPressEventListeners(); 39 40 40 41 console.log(shape.info.selectedPins, "Loaded pins on modal open"); -
imaps-frontend/src/components/Modals/RoomModal/RoomModal.jsx
r0c6b92a r79a0317 7 7 import useModalState from "../Hooks/useModalState.jsx"; 8 8 import {useModalEvent} from "../Hooks/useModalEvent.jsx"; 9 import ModalUploadRoomImage from "../Components/ModalUploadRoomImage.jsx"; 9 10 10 11 export default function RoomModal({map,roomTypes}) { … … 20 21 setShapeInfo(shape.info); 21 22 setIsOpen(true); 23 event.detail.map.detachKeyPressEventListeners(); 22 24 23 25 },"openRoomModalEvent") … … 30 32 <ModalRoomTypes updateModalData={updateModalData} shapeInfo={shapeInfo} roomTypes={roomTypes}/> 31 33 <ModalDescriptionField shapeInfo={shapeInfo} updateModalData={updateModalData}/> 34 <ModalUploadRoomImage></ModalUploadRoomImage> 32 35 <ModalSaveButton saveDetails={saveDetails}/> 33 36 </Modal> -
imaps-frontend/src/components/Modals/RoomTypeModal/RoomTypeModal.jsx
r0c6b92a r79a0317 31 31 <div onClick={toggleModal} className={styles.overlay}></div> 32 32 <div className={styles.modalContent}> 33 <h2 >Manage Room Types</h2>33 <h2 style={{color: 'white'}}>Manage Room Types</h2> 34 34 35 35 <form className={styles.form}> -
imaps-frontend/src/components/Modals/StairsModal/StairsModal.jsx
r0c6b92a r79a0317 33 33 setIsOpen(true); 34 34 console.log(roomObj.info.selectedPins, "Loaded pins on modal open"); 35 event.detail.map.detachKeyPressEventListeners(); 35 36 },"openStairsModalEvent") 36 37 -
imaps-frontend/src/components/Profile/Profile.jsx
r0c6b92a r79a0317 1 import React, { useState, useRef, useEffect, useContext } from "react"; 2 import { useNavigate, Link } from "react-router-dom"; 1 import React, { useState, useRef, useEffect } from "react"; 2 import ReactDOM from "react-dom"; 3 import { useNavigate } from "react-router-dom"; 3 4 import profile from "../../assets/person_icon.png"; 4 5 import styles from "./Profile.module.css"; … … 8 9 const { username, isAuthenticated } = useAppContext(); 9 10 const [open, setOpen] = useState(false); 10 const menuRef = useRef(null);11 const [menuPosition, setMenuPosition] = useState({ top: 0, left: 0 }); 11 12 const imgRef = useRef(null); 12 13 const navigate = useNavigate(); … … 16 17 useEffect(() => { 17 18 const handleClickOutside = (e) => { 18 if (menuRef.current && imgRef.current) { 19 if (!menuRef.current.contains(e.target) && !imgRef.current.contains(e.target)) { 20 setOpen(false); 21 } 19 if (imgRef.current && !imgRef.current.contains(e.target)) { 20 setOpen(false); 22 21 } 23 22 }; … … 30 29 }, []); 31 30 31 const toggleMenu = () => { 32 if (imgRef.current) { 33 const rect = imgRef.current.getBoundingClientRect(); 34 setMenuPosition({ 35 top: rect.bottom + window.scrollY, 36 left: rect.left + window.scrollX, 37 }); 38 } 39 setOpen(!open); 40 }; 41 32 42 const handleMenuClick = (menu) => { 33 43 if (menu === "My Maps") { … … 36 46 localStorage.removeItem("token"); 37 47 window.location.reload(); 48 } else if (menu === "Login") { 49 navigate("/Login"); 38 50 } 39 51 setOpen(false); 40 52 }; 41 53 54 const renderDropdown = () => { 55 if (!open) return null; 56 57 return ReactDOM.createPortal( 58 <div 59 className={styles.dropdownMenu} 60 style={{ 61 position: "absolute", 62 top: menuPosition.top, 63 left: menuPosition.left, 64 }} 65 > 66 {isAuthenticated && <div className={styles.username}>{username}</div>} 67 <ul className={styles.menuList}> 68 {menus.map((menu) => ( 69 <li 70 key={menu} 71 className={styles.menuItem} 72 onClick={() => handleMenuClick(menu)} 73 > 74 {menu} 75 </li> 76 ))} 77 </ul> 78 </div>, 79 document.body 80 ); 81 }; 82 42 83 return ( 43 <div className={position === "fixed" ? styles.fixedProfileContainer : styles.inlineProfileContainer}> 84 <div 85 className={ 86 position === "fixed" ? styles.fixedProfileContainer : styles.inlineProfileContainer 87 } 88 > 44 89 <div className={styles.profileWrapper}> 45 <div className={styles.profileIconContainer} onClick={() => setOpen(!open)}> 46 <img src={profile} alt="profile" className={styles.profileImage} ref={imgRef} /> 90 <div 91 className={styles.profileIconContainer} 92 onClick={toggleMenu} 93 ref={imgRef} 94 > 95 <img src={profile} alt="profile" className={styles.profileImage} /> 47 96 </div> 48 {open && ( 49 <div ref={menuRef} className={styles.dropdownMenu}> 50 {isAuthenticated && <div className={styles.username}>{username}</div>} 51 <ul className={styles.menuList}> 52 {menus.map((menu) => 53 menu === "Login" ? ( 54 <li key={menu} className={styles.menuItem}> 55 <Link to="/login" className={styles.linkStyle}>{menu}</Link> 56 </li> 57 ) : ( 58 <li key={menu} onClick={() => handleMenuClick(menu)} className={styles.menuItem}> 59 {menu} 60 </li> 61 ) 62 )} 63 </ul> 64 </div> 65 )} 97 {renderDropdown()} 66 98 </div> 67 99 </div> -
imaps-frontend/src/components/PublishForm/PublishForm.jsx
r0c6b92a r79a0317 15 15 ); 16 16 const [errors, setErrors] = useState({}); 17 const [denyReason, setDenyReason] = useState(''); 18 const [isDenying, setIsDenying] = useState(false); 17 19 18 20 const mapTypeOptions = ['Hospital', 'Faculty', 'House', 'Other']; … … 42 44 onSubmit(form); 43 45 } 46 }; 47 48 const handleDeny = () => { 49 if (!denyReason.trim()) { 50 alert('Please provide a reason for denial.'); 51 return; 52 } 53 onDeny(form.id, form.mapName, denyReason); 54 setIsDenying(false); 44 55 }; 45 56 … … 130 141 <button 131 142 className={styles.cancelButton} 132 onClick={onCancel} 143 onClick={() => { 144 setIsDenying(false); 145 onCancel(); 146 }} 133 147 > 134 148 Cancel … … 136 150 <button 137 151 className={styles.approveButton} 138 onClick={() => onApprove(form.id, form.mapName)}152 onClick={() => onApprove(form.id, form.mapName)} 139 153 > 140 154 Approve … … 142 156 <button 143 157 className={styles.denyButton} 144 onClick={() => onDeny(form.id,form.mapName,"Reason")}158 onClick={() => setIsDenying(true)} 145 159 > 146 160 Deny 147 161 </button> 148 162 </div> 163 {isDenying && ( 164 <div className={styles.denyReason}> 165 <textarea className={styles.denyReasonTextArea} 166 placeholder="Enter reason for denial..." 167 value={denyReason} 168 onChange={(e) => setDenyReason(e.target.value)} 169 /> 170 <div className={styles.buttonGroup}> 171 <button 172 className={styles.denySubmitButton} 173 onClick={handleDeny} 174 > 175 Submit 176 </button> 177 </div> 178 </div> 179 )} 149 180 </div> 150 181 )} -
imaps-frontend/src/components/PublishForm/PublishForm.module.css
r0c6b92a r79a0317 10 10 z-index: 999; /* Behind the modal */ 11 11 } 12 13 .denyReason { 14 display: flex; 15 flex-direction: column; 16 margin-top: 10px; 17 border-radius: 20px; 18 } 19 .denyReasonTextArea{ 20 padding-bottom: 4rem; 21 } 22 23 .denySubmitButton { 24 color: white; 25 margin-right: 10px; 26 } 27 12 28 13 29 /* Modal styles */ -
imaps-frontend/src/components/RoomInfoPanel/RoomInfoPanel.jsx
r0c6b92a r79a0317 56 56 Navigate 57 57 </button> 58 <p style={{fontSize: '0.8em'}}><i>From Main Entrance</i></p> 58 59 </> 59 60 ) : ( -
imaps-frontend/src/components/SearchBar/SearchBar.jsx
r0c6b92a r79a0317 6 6 import styles from "./SearchBar.module.css"; 7 7 8 function SearchBar({ map, handleDirectionsSubmit, setIsPanelOpen, setSelectedRoom, availableShapes,handleFloorChange }) { 8 function SearchBar({ 9 map, 10 handleDirectionsSubmit, 11 setIsPanelOpen, 12 setSelectedRoom, 13 availableShapes, 14 handleFloorChange, 15 }) { 9 16 const [isExpanded, setIsExpanded] = useState(false); 10 17 const [from, setFrom] = useState(""); … … 14 21 const [dropdownVisible, setDropdownVisible] = useState(false); 15 22 const [inputFieldType, setInputFieldType] = useState(""); 16 const dropdownRef = useRef(null); 17 18 const toggleExpanded = () => { 19 setIsExpanded(!isExpanded); 20 }; 21 22 function searchRoom() { 23 let foundRoom = availableShapes.find(sh => sh.info.name === from) 24 console.log("map fnum",map.floorNum) 25 if(foundRoom.floorNum !== map.floorNum){ 23 24 const wrapperRef = useRef(null); 25 const dropdownContainerRef = useRef(null); 26 const activeInputRef = useRef(null); // Track the currently focused input field 27 28 const toggleExpanded = () => setIsExpanded(!isExpanded); 29 30 const handleClickOutside = (event) => { 31 if ( 32 wrapperRef.current && 33 !wrapperRef.current.contains(event.target) && 34 dropdownContainerRef.current && 35 !dropdownContainerRef.current.contains(event.target) 36 ) { 37 setDropdownVisible(false); 38 } 39 }; 40 41 useEffect(() => { 42 document.addEventListener("mousedown", handleClickOutside); 43 return () => { 44 document.removeEventListener("mousedown", handleClickOutside); 45 }; 46 }, []); 47 48 const searchRoom = () => { 49 const foundRoom = availableShapes.find((sh) => sh.info.name === from); 50 if (foundRoom && foundRoom.floorNum !== map.floorNum) { 26 51 handleFloorChange(foundRoom.floorNum); 27 52 } 28 29 30 console.log("FOUND ROOM: " + foundRoom)31 53 map.highlightShape(from); 32 54 setSelectedRoom(foundRoom); 33 55 setIsPanelOpen(true); 34 } 35 36 const handleInputFocus = (field ) => {56 }; 57 58 const handleInputFocus = (field, inputRef) => { 37 59 if (availableOptions.length === 0 && map) { 38 60 setAvailableOptions( … … 42 64 ); 43 65 } 66 setInputFieldType(field); 44 67 setDropdownVisible(true); 45 setInputFieldType(field);68 activeInputRef.current = inputRef; // Set the active input ref 46 69 }; 47 70 … … 69 92 if (!dropdownVisible || filteredOptions.length === 0) return null; 70 93 71 const position = dropdownRef.current?.getBoundingClientRect() || { top: 0, left: 0, width: 0 }; 94 const position = activeInputRef.current?.getBoundingClientRect() || { 95 top: 0, 96 left: 0, 97 width: 0, 98 }; 72 99 73 100 return ReactDOM.createPortal( 74 101 <ul 102 ref={dropdownContainerRef} 75 103 className={styles.dropdown} 76 104 style={{ 77 105 position: "absolute", 78 top: position.top + position.height ,79 left: position.left ,106 top: position.top + position.height + window.scrollY, 107 left: position.left + window.scrollX, 80 108 width: position.width, 81 109 }} … … 91 119 ))} 92 120 </ul>, 93 document.body // Portal renders outside the parent hierarchy121 document.body 94 122 ); 95 123 }; 96 124 97 125 return ( 98 <div className={styles.wrapper} >126 <div className={styles.wrapper} ref={wrapperRef}> 99 127 {!isExpanded ? ( 100 128 <div className={styles.searchBar}> … … 104 132 placeholder="Search location" 105 133 aria-label="Search" 106 ref={dropdownRef} // Attach the input to calculate dropdown position 107 onFocus={() => handleInputFocus("from")} 134 onFocus={(e) => handleInputFocus("from", e.target)} 108 135 onChange={handleInputChange(setFrom)} 109 136 value={from} … … 111 138 {renderDropdown()} 112 139 <div className={styles.buttons}> 113 <button type="button" className={styles.iconButton} onClick={searchRoom}> 140 <button 141 type="button" 142 className={styles.iconButton} 143 onClick={searchRoom} 144 > 114 145 <img src={searchIcon} alt="Search Icon" /> 115 146 </button> 116 <button type="button" className={styles.iconButton} onClick={toggleExpanded}> 147 <button 148 type="button" 149 className={styles.iconButton} 150 onClick={toggleExpanded} 151 > 117 152 <img src={routeIcon} alt="Route Icon" /> 118 153 </button> … … 127 162 aria-label="From" 128 163 value={from} 129 onFocus={( ) => handleInputFocus("from")}164 onFocus={(e) => handleInputFocus("from", e.target)} 130 165 onChange={handleInputChange(setFrom)} 131 166 className={styles.inputField} 132 ref={inputFieldType === "from" ? dropdownRef : null}133 167 /> 134 168 <input … … 137 171 aria-label="To" 138 172 value={to} 139 onFocus={( ) => handleInputFocus("to")}173 onFocus={(e) => handleInputFocus("to", e.target)} 140 174 onChange={handleInputChange(setTo)} 141 175 className={styles.inputField} 142 ref={inputFieldType === "to" ? dropdownRef : null}143 176 /> 144 177 {renderDropdown()} … … 152 185 <img src={searchIcon} alt="Submit Directions" /> 153 186 </button> 154 <button type="button" className={styles.iconButton} onClick={toggleExpanded}> 187 <button 188 type="button" 189 className={styles.iconButton} 190 onClick={toggleExpanded} 191 > 155 192 <img src={closeIcon} alt="Close Icon" /> 156 193 </button> -
imaps-frontend/src/components/SearchBar/SearchBar.module.css
r0c6b92a r79a0317 26 26 .inputField { 27 27 flex-grow: 1; 28 padding: 10px 15px;28 /*padding: 10px 15px;*/ 29 29 font-size: 16px; 30 30 border: 1px solid #ddd; … … 33 33 margin-right: 10px; 34 34 min-width: 0; 35 35 margin-top: 12px; 36 36 } 37 37
Note:
See TracChangeset
for help on using the changeset viewer.