Ignore:
Timestamp:
01/21/25 03:08:24 (3 days ago)
Author:
stefan toskovski <stefantoska84@…>
Branches:
main
Parents:
0c6b92a
Message:

F4 Finalna Verzija

Location:
imaps-frontend/src/components
Files:
8 added
24 edited

Legend:

Unmodified
Added
Removed
  • imaps-frontend/src/components/DrawGuide/DrawGuide.jsx

    r0c6b92a r79a0317  
    1818          <div onClick={toggleModal} className={styles.overlay}></div>
    1919          <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>
    2222            <br></br>
    2323            <ul>
     
    3535            </ul>
    3636            <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>
    3838
    3939            <button className={styles.closeModal} onClick={toggleModal}>
  • imaps-frontend/src/components/DrawGuide/DrawGuide.module.css

    r0c6b92a r79a0317  
    1818  backdrop-filter: blur(5px); /* Optional blur effect */
    1919  z-index: 999;
     20
     21}
     22
     23.title{
     24  color: white;
     25}
     26
     27.paragraph{
     28  color: #ababab;
    2029}
    2130
     
    2534  left: 50%;
    2635  transform: translate(-50%, -50%);
    27   background-color: #2c2f33; /* Darker background for modal content */
     36  background-color: #2c2f33;
    2837  color: #ffffff; /* White text for contrast */
    2938  padding: 20px;
     
    3544}
    3645
    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/*}*/
    4150
    4251.btnModal {
  • imaps-frontend/src/components/FilterBar/FilterBar.module.css

    r0c6b92a r79a0317  
    1 /* FilterBar.module.css */
     1/* FilterMaps.module.css */
    22* {
    33  font-family: "Poppins", sans-serif;
     
    1818  padding: 0px 0; /* Adds some space around the buttons */
    1919  width: 100%;
     20  overflow-y: hidden;
    2021}
    2122
    2223.buttonValue {
    23   border: 2px solid #6759ff;
     24  border: 2px solid rgb(37,111,123);
    2425  padding: 0.5em 1.5em;
    2526  border-radius: 3em;
    2627  background-color: transparent;
    27   color: #6759ff;
     28  color: rgb(37,111,123);
    2829  cursor: pointer;
    2930  transition: background-color 0.3s, color 0.3s;
     
    3334.buttonValue:hover,
    3435.buttonValue:focus {
    35   background-color: #6759ff;
     36  background-color: rgb(33, 98, 108);
    3637  color: #ffffff;
    3738}
    3839
    3940.active {
    40   background-color: #6759ff;
     41  background-color: rgb(37,111,123);
    4142  color: #ffffff;
    4243}
     
    4748
    4849.scrollableContainer::-webkit-scrollbar-thumb {
    49   background-color: #6759ff;
     50  background-color: rgb(37,111,123);
    5051  border-radius: 3px;
    5152}
  • imaps-frontend/src/components/LoadingContainer/LoadingContainer.jsx

    r0c6b92a r79a0317  
    11import React from "react";
     2import styles from "./LoadingContainer.module.css"
    23
    34export const LoadingContainer = () => {
     
    56        <div className="loading-container">
    67            <div className="spinner"></div>
    7             <p>Loading, please wait...</p>
    88        </div>
    99    );
  • imaps-frontend/src/components/Logo/Logo.jsx

    r0c6b92a r79a0317  
    11import React from "react";
    22import { useNavigate } from "react-router-dom";
    3 import logoImage from "../../assets/logo_icon.png";
     3import novo_logo from "../../assets/novo_logo_nobg_cropped.png";
    44import styles from "./Logo.module.css";
    55
     
    1616      onClick={handleClick}
    1717    >
    18       <img src={logoImage} alt="Logo" className={styles.logoImage} />
     18      <img src={novo_logo} alt="Logo" className={styles.logoImage} />
    1919    </div>
    2020  );
  • imaps-frontend/src/components/Logo/Logo.module.css

    r0c6b92a r79a0317  
    88
    99.logoImage {
    10   width: 50px; /* Adjust the size as needed */
     10  width: 80px;
    1111  height: auto;
    1212  transition: opacity 0.2s ease;
     13  border-radius: 20px;
    1314}
    1415
     
    3031}
    3132
    32 .logoImage {
    33   width: 50px; /* Adjust size as needed */
    34   height: auto;
    35   transition: opacity 0.2s ease;
    36 }
    37 
    3833.logoImage:hover {
    3934  opacity: 0.8; /* Hover effect */
  • imaps-frontend/src/components/MapInfoModal/MapInfoModal.jsx

    r0c6b92a r79a0317  
    1 import React, {useEffect, useState} from "react";
     1import React, { useEffect, useState } from "react";
    22import styles from "./MapInfoModal.module.css";
    3 import {json, useNavigate} from "react-router-dom";
    43import edit_icon from "../../assets/edit_icon_black.png";
    54import PublishForm from "../PublishForm/PublishForm.jsx";
    65import HttpService from "../../scripts/net/HttpService.js";
    76import 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}) {
     7import { useAppContext } from "../AppContext/AppContext.jsx";
     8import { useNavigate } from "react-router-dom";
     9
     10export default function MapInfoModal({
     11                                         isOpen,
     12                                         onClose,
     13                                         map,
     14                                         onDelete,
     15                                         onUpdate,
     16                                         onPublish,
     17                                         published = false,
     18                                     }) {
    1119    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);
    1524    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();
    1829
    1930    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]);
    2437
    2538    if (!isOpen || !map) return null;
    2639
    2740    const handleView = () => {
    28         navigate(`/myMaps/${map.mapName}/View`)
     41        navigate(`/myMaps/View/${map.mapName}`);
    2942    };
    3043
    3144    const handleEdit = () => {
    32         navigate(`/myMaps/${map.mapName}/Draw`)
     45        navigate(`/myMaps/Draw/${map.mapName}`);
    3346    };
    3447
    3548    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        ) {
    3752            onDelete(map.mapName);
    3853            onClose();
     
    4055    };
    4156
    42 
    4357    const openEditPopup = () => {
    4458        setEditPopupOpen(true);
     
    5165    const handleEditSubmit = async () => {
    5266        const updatedMap = {
    53             ...map,
    54             mapName: editedName,
    55             gmaps_url: editedGmapsUrl,
     67            initialName: map.mapName,
     68            name: editedName,
     69            gmapsUrl: editedGmapsUrl,
     70            type: editedType,
    5671        };
    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    };
    8175
    8276    return (
    8377        <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
    126143                        </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>
    147194                            </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                    </>
    166197                )}
    167198            </div>
  • imaps-frontend/src/components/MapInfoModal/MapInfoModal.module.css

    r0c6b92a r79a0317  
    1414
    1515.modalContent {
     16    position: relative;
    1617    background-color: white;
    1718    padding: 20px;
     
    2223    text-align: center;
    2324    animation: fadeIn 0.3s ease-out;
     25
    2426}
    2527
  • imaps-frontend/src/components/Modals/CreateMapModal/CreateMapModal.jsx

    r0c6b92a r79a0317  
    1010        const mapDetails = {
    1111            name: mapName,
    12             type: mapType,
    1312        };
    1413
     
    3433                        />
    3534                    </label>
    36                     <label>
    37                         Map Type:
    38                         <input
    39                             type="text"
    40                             value={mapType}
    41                             onChange={(e) => setMapType(e.target.value)}
    42                             required
    43                         />
    44                     </label>
    4535                    <div className={styles.modalButtons}>
    4636                        <button type="submit" className={styles.modalSubmitButton}>
  • imaps-frontend/src/components/Modals/CreateMapModal/CreateMapModal.module.css

    r0c6b92a r79a0317  
    3636/* Modal Buttons Container */
    3737.modalButtons {
    38     margin-top: 1.5rem;
    3938    display: flex;
    4039    justify-content: space-between;
  • imaps-frontend/src/components/Modals/EntranceModal/EntranceModal.jsx

    r0c6b92a r79a0317  
    4242        setConnections(connections);
    4343        setIsOpen(true);
     44        event.detail.map.detachKeyPressEventListeners();
    4445        console.log(connections, "Loaded pins on modal open");
    4546    },"openEntranceModalEvent")
     
    5253            <ModalSelectRoom shapeInfo={shapeInfo} availableRooms={ShapeQuery.findAllByTypeAndFloor(shape?.floorNum,"Room")} updateModalData={updateModalData}/>
    5354            <ModalSelectConnections2
    54                 availableShapes={ShapeQuery.findAllByType("InfoPin","Entrance")} // najubo ke e entrance samo so room da mozit
     55                availableShapes={ShapeQuery.findAllByTypeAndFloor(map?.floorNum,"Entrance","InfoPin")} // najubo ke e entrance samo so room da mozit
    5556                addConnection={addConnection}
    5657                updateModalData={updateModalData}
  • imaps-frontend/src/components/Modals/EntranceModal/EntranceModal.module.css

    r0c6b92a r79a0317  
    3434  left: 50%;
    3535  transform: translate(-50%, -50%);
    36   background-color: #2c2f33;
     36  background-color: #2c2f33f7;
    3737  color: #ffffff !important;
    3838  padding: 20px;
     
    9090  margin-bottom: 15px;
    9191}
     92
     93/*tuka novo start*/
     94
     95label {
     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*/
    92130
    93131.formGroup label {
  • imaps-frontend/src/components/Modals/Hooks/useConnections.jsx

    r0c6b92a r79a0317  
    55
    66    const addConnection = () => {
    7         console.log("TOSKA",shapeInfo)
    87        if (!shapeInfo.selectedPin || connections.includes(shapeInfo.selectedPin)) return;
    98
  • imaps-frontend/src/components/Modals/Hooks/useModalState.jsx

    r0c6b92a r79a0317  
    1313            map.updateRoomNames();
    1414            triggerMapSave();
    15             console.log("SHAPE BEF CLOSE:",shape.info)
     15            map.attachKeyPressEventListeners();
    1616        }
    1717        setIsOpen(!isOpen);
  • imaps-frontend/src/components/Modals/InfoPinModal/InfoPinModal.jsx

    r0c6b92a r79a0317  
    3737        setConnections(shape.info.selectedPins || []);
    3838        setIsOpen(true);
     39        event.detail.map.detachKeyPressEventListeners();
    3940
    4041        console.log(shape.info.selectedPins, "Loaded pins on modal open");
  • imaps-frontend/src/components/Modals/RoomModal/RoomModal.jsx

    r0c6b92a r79a0317  
    77import useModalState from "../Hooks/useModalState.jsx";
    88import {useModalEvent} from "../Hooks/useModalEvent.jsx";
     9import ModalUploadRoomImage from "../Components/ModalUploadRoomImage.jsx";
    910
    1011export default function RoomModal({map,roomTypes}) {
     
    2021        setShapeInfo(shape.info);
    2122        setIsOpen(true);
     23        event.detail.map.detachKeyPressEventListeners();
    2224
    2325    },"openRoomModalEvent")
     
    3032            <ModalRoomTypes updateModalData={updateModalData} shapeInfo={shapeInfo} roomTypes={roomTypes}/>
    3133            <ModalDescriptionField shapeInfo={shapeInfo} updateModalData={updateModalData}/>
     34            <ModalUploadRoomImage></ModalUploadRoomImage>
    3235            <ModalSaveButton saveDetails={saveDetails}/>
    3336        </Modal>
  • imaps-frontend/src/components/Modals/RoomTypeModal/RoomTypeModal.jsx

    r0c6b92a r79a0317  
    3131          <div onClick={toggleModal} className={styles.overlay}></div>
    3232          <div className={styles.modalContent}>
    33             <h2>Manage Room Types</h2>
     33            <h2 style={{color: 'white'}}>Manage Room Types</h2>
    3434
    3535            <form className={styles.form}>
  • imaps-frontend/src/components/Modals/StairsModal/StairsModal.jsx

    r0c6b92a r79a0317  
    3333        setIsOpen(true);
    3434        console.log(roomObj.info.selectedPins, "Loaded pins on modal open");
     35        event.detail.map.detachKeyPressEventListeners();
    3536    },"openStairsModalEvent")
    3637
  • 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";
     1import React, { useState, useRef, useEffect } from "react";
     2import ReactDOM from "react-dom";
     3import { useNavigate } from "react-router-dom";
    34import profile from "../../assets/person_icon.png";
    45import styles from "./Profile.module.css";
     
    89    const { username, isAuthenticated } = useAppContext();
    910    const [open, setOpen] = useState(false);
    10     const menuRef = useRef(null);
     11    const [menuPosition, setMenuPosition] = useState({ top: 0, left: 0 });
    1112    const imgRef = useRef(null);
    1213    const navigate = useNavigate();
     
    1617    useEffect(() => {
    1718        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);
    2221            }
    2322        };
     
    3029    }, []);
    3130
     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
    3242    const handleMenuClick = (menu) => {
    3343        if (menu === "My Maps") {
     
    3646            localStorage.removeItem("token");
    3747            window.location.reload();
     48        } else if (menu === "Login") {
     49            navigate("/Login");
    3850        }
    3951        setOpen(false);
    4052    };
    4153
     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
    4283    return (
    43         <div className={position === "fixed" ? styles.fixedProfileContainer : styles.inlineProfileContainer}>
     84        <div
     85            className={
     86                position === "fixed" ? styles.fixedProfileContainer : styles.inlineProfileContainer
     87            }
     88        >
    4489            <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} />
    4796                </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()}
    6698            </div>
    6799        </div>
  • imaps-frontend/src/components/PublishForm/PublishForm.jsx

    r0c6b92a r79a0317  
    1515    );
    1616    const [errors, setErrors] = useState({});
     17    const [denyReason, setDenyReason] = useState('');
     18    const [isDenying, setIsDenying] = useState(false);
    1719
    1820    const mapTypeOptions = ['Hospital', 'Faculty', 'House', 'Other'];
     
    4244            onSubmit(form);
    4345        }
     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);
    4455    };
    4556
     
    130141                                <button
    131142                                    className={styles.cancelButton}
    132                                     onClick={onCancel}
     143                                    onClick={() => {
     144                                        setIsDenying(false);
     145                                        onCancel();
     146                                    }}
    133147                                >
    134148                                    Cancel
     
    136150                                <button
    137151                                    className={styles.approveButton}
    138                                     onClick={() => onApprove(form.id,form.mapName)}
     152                                    onClick={() => onApprove(form.id, form.mapName)}
    139153                                >
    140154                                    Approve
     
    142156                                <button
    143157                                    className={styles.denyButton}
    144                                     onClick={() => onDeny(form.id,form.mapName,"Reason")}
     158                                    onClick={() => setIsDenying(true)}
    145159                                >
    146160                                    Deny
    147161                                </button>
    148162                            </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                            )}
    149180                        </div>
    150181                    )}
  • imaps-frontend/src/components/PublishForm/PublishForm.module.css

    r0c6b92a r79a0317  
    1010    z-index: 999; /* Behind the modal */
    1111}
     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
    1228
    1329/* Modal styles */
  • imaps-frontend/src/components/RoomInfoPanel/RoomInfoPanel.jsx

    r0c6b92a r79a0317  
    5656                Navigate
    5757              </button>
     58              <p style={{fontSize: '0.8em'}}><i>From Main Entrance</i></p>
    5859            </>
    5960        ) : (
  • imaps-frontend/src/components/SearchBar/SearchBar.jsx

    r0c6b92a r79a0317  
    66import styles from "./SearchBar.module.css";
    77
    8 function SearchBar({ map, handleDirectionsSubmit, setIsPanelOpen, setSelectedRoom, availableShapes,handleFloorChange }) {
     8function SearchBar({
     9                     map,
     10                     handleDirectionsSubmit,
     11                     setIsPanelOpen,
     12                     setSelectedRoom,
     13                     availableShapes,
     14                     handleFloorChange,
     15                   }) {
    916  const [isExpanded, setIsExpanded] = useState(false);
    1017  const [from, setFrom] = useState("");
     
    1421  const [dropdownVisible, setDropdownVisible] = useState(false);
    1522  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) {
    2651      handleFloorChange(foundRoom.floorNum);
    2752    }
    28 
    29 
    30     console.log("FOUND ROOM: " + foundRoom)
    3153    map.highlightShape(from);
    3254    setSelectedRoom(foundRoom);
    3355    setIsPanelOpen(true);
    34   }
    35 
    36   const handleInputFocus = (field) => {
     56  };
     57
     58  const handleInputFocus = (field, inputRef) => {
    3759    if (availableOptions.length === 0 && map) {
    3860      setAvailableOptions(
     
    4264      );
    4365    }
     66    setInputFieldType(field);
    4467    setDropdownVisible(true);
    45     setInputFieldType(field);
     68    activeInputRef.current = inputRef; // Set the active input ref
    4669  };
    4770
     
    6992    if (!dropdownVisible || filteredOptions.length === 0) return null;
    7093
    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    };
    7299
    73100    return ReactDOM.createPortal(
    74101        <ul
     102            ref={dropdownContainerRef}
    75103            className={styles.dropdown}
    76104            style={{
    77105              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,
    80108              width: position.width,
    81109            }}
     
    91119          ))}
    92120        </ul>,
    93         document.body // Portal renders outside the parent hierarchy
     121        document.body
    94122    );
    95123  };
    96124
    97125  return (
    98       <div className={styles.wrapper}>
     126      <div className={styles.wrapper} ref={wrapperRef}>
    99127        {!isExpanded ? (
    100128            <div className={styles.searchBar}>
     
    104132                  placeholder="Search location"
    105133                  aria-label="Search"
    106                   ref={dropdownRef} // Attach the input to calculate dropdown position
    107                   onFocus={() => handleInputFocus("from")}
     134                  onFocus={(e) => handleInputFocus("from", e.target)}
    108135                  onChange={handleInputChange(setFrom)}
    109136                  value={from}
     
    111138              {renderDropdown()}
    112139              <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                >
    114145                  <img src={searchIcon} alt="Search Icon" />
    115146                </button>
    116                 <button type="button" className={styles.iconButton} onClick={toggleExpanded}>
     147                <button
     148                    type="button"
     149                    className={styles.iconButton}
     150                    onClick={toggleExpanded}
     151                >
    117152                  <img src={routeIcon} alt="Route Icon" />
    118153                </button>
     
    127162                    aria-label="From"
    128163                    value={from}
    129                     onFocus={() => handleInputFocus("from")}
     164                    onFocus={(e) => handleInputFocus("from", e.target)}
    130165                    onChange={handleInputChange(setFrom)}
    131166                    className={styles.inputField}
    132                     ref={inputFieldType === "from" ? dropdownRef : null}
    133167                />
    134168                <input
     
    137171                    aria-label="To"
    138172                    value={to}
    139                     onFocus={() => handleInputFocus("to")}
     173                    onFocus={(e) => handleInputFocus("to", e.target)}
    140174                    onChange={handleInputChange(setTo)}
    141175                    className={styles.inputField}
    142                     ref={inputFieldType === "to" ? dropdownRef : null}
    143176                />
    144177                {renderDropdown()}
     
    152185                  <img src={searchIcon} alt="Submit Directions" />
    153186                </button>
    154                 <button type="button" className={styles.iconButton} onClick={toggleExpanded}>
     187                <button
     188                    type="button"
     189                    className={styles.iconButton}
     190                    onClick={toggleExpanded}
     191                >
    155192                  <img src={closeIcon} alt="Close Icon" />
    156193                </button>
  • imaps-frontend/src/components/SearchBar/SearchBar.module.css

    r0c6b92a r79a0317  
    2626.inputField {
    2727  flex-grow: 1;
    28   padding: 10px 15px;
     28  /*padding: 10px 15px;*/
    2929  font-size: 16px;
    3030  border: 1px solid #ddd;
     
    3333  margin-right: 10px;
    3434  min-width: 0;
    35 
     35  margin-top: 12px;
    3636}
    3737
Note: See TracChangeset for help on using the changeset viewer.