Ignore:
Timestamp:
12/12/24 17:06:06 (5 weeks ago)
Author:
stefan toskovski <stefantoska84@…>
Branches:
main
Parents:
d565449
Message:

Pred finalna verzija

File:
1 edited

Legend:

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

    rd565449 r0c6b92a  
    1 import React, { useState } from "react";
     1import React, { useState, useEffect, useRef } from "react";
     2import ReactDOM from "react-dom";
    23import searchIcon from "../../assets/search_icon.png";
    34import routeIcon from "../../assets/route_icon.png";
     
    56import styles from "./SearchBar.module.css";
    67
    7 function SearchBar(props) {
     8function SearchBar({ map, handleDirectionsSubmit, setIsPanelOpen, setSelectedRoom, availableShapes,handleFloorChange }) {
    89  const [isExpanded, setIsExpanded] = useState(false);
    910  const [from, setFrom] = useState("");
    1011  const [to, setTo] = useState("");
     12  const [availableOptions, setAvailableOptions] = useState([]);
     13  const [filteredOptions, setFilteredOptions] = useState([]);
     14  const [dropdownVisible, setDropdownVisible] = useState(false);
     15  const [inputFieldType, setInputFieldType] = useState("");
     16  const dropdownRef = useRef(null);
    1117
    1218  const toggleExpanded = () => {
     
    1420  };
    1521
    16   function searchRoom(){
    17     props.map.search();
     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){
     26      handleFloorChange(foundRoom.floorNum);
     27    }
    1828
     29
     30    console.log("FOUND ROOM: " + foundRoom)
     31    map.highlightShape(from);
     32    setSelectedRoom(foundRoom);
     33    setIsPanelOpen(true);
    1934  }
    2035
    21   const handleDirectionsSubmit = () => {
    22     console.log(`From: ${from}, To: ${to}`);
    23     const url = new URL('http://localhost:8080/api/public/navigate');
    24     url.searchParams.append('from', from);
    25     url.searchParams.append('to', to);
     36  const handleInputFocus = (field) => {
     37    if (availableOptions.length === 0 && map) {
     38      setAvailableOptions(
     39          availableShapes
     40              .filter((sh) => sh.className === "RenderedRoom")
     41              .map((shape) => shape.info.name)
     42      );
     43    }
     44    setDropdownVisible(true);
     45    setInputFieldType(field);
     46  };
    2647
    27     fetch(url)
    28             .then(response => {
    29                 if (!response.ok) {
    30                     throw new Error('Network response was not ok');
    31                 }
    32                 return response.json();
    33             })
    34             .then(data => {
    35                 console.log('Success:', data);
    36                 const points = data.map(item => item.coordinates);
    37                 props.map.drawRoute(points);
    38             })
    39             .catch(error => {
    40                 console.error('Error:', error);
    41             });
     48  const handleInputChange = (setter) => (event) => {
     49    const value = event.target.value;
     50    setter(value);
     51    setDropdownVisible(true);
     52
     53    const filtered = availableOptions.filter((option) =>
     54        option.toLowerCase().includes(value.toLowerCase())
     55    );
     56    setFilteredOptions(filtered);
     57  };
     58
     59  const handleOptionClick = (option) => {
     60    if (inputFieldType === "from") {
     61      setFrom(option);
     62    } else if (inputFieldType === "to") {
     63      setTo(option);
     64    }
     65    setDropdownVisible(false);
     66  };
     67
     68  const renderDropdown = () => {
     69    if (!dropdownVisible || filteredOptions.length === 0) return null;
     70
     71    const position = dropdownRef.current?.getBoundingClientRect() || { top: 0, left: 0, width: 0 };
     72
     73    return ReactDOM.createPortal(
     74        <ul
     75            className={styles.dropdown}
     76            style={{
     77              position: "absolute",
     78              top: position.top + position.height,
     79              left: position.left,
     80              width: position.width,
     81            }}
     82        >
     83          {filteredOptions.map((option, index) => (
     84              <li
     85                  key={index}
     86                  className={styles.dropdownItem}
     87                  onClick={() => handleOptionClick(option)}
     88              >
     89                {option}
     90              </li>
     91          ))}
     92        </ul>,
     93        document.body // Portal renders outside the parent hierarchy
     94    );
    4295  };
    4396
    4497  return (
    45     <div className={styles.wrapper}>
    46       {/* Regular search bar */}
    47       {!isExpanded ? (
    48         <div className={styles.searchBar}>
    49           <input
    50             type="search"
    51             className={styles.inputField}
    52             placeholder="Search location"
    53             aria-label="Search"
    54           />
    55           <div className={styles.buttons}>
    56             <button type="button" className={styles.iconButton} onClick={searchRoom}>
    57               <img src={searchIcon} alt="Search Icon" />
    58             </button>
    59             <button type="button" className={styles.iconButton} onClick={toggleExpanded}>
    60               <img src={routeIcon} alt="Route Icon" />
    61             </button>
    62           </div>
    63         </div>
    64       ) : (
    65         /* Expanded view for directions */
    66         <div className={styles.directionsContainer}>
    67           <div className={styles.directionsInputs}>
    68             <input
    69               type="text"
    70               placeholder="From"
    71               aria-label="From"
    72               value={from}
    73               onChange={(e) => setFrom(e.target.value)}
    74               className={styles.inputField}
    75             />
    76             <input
    77               type="text"
    78               placeholder="To"
    79               aria-label="To"
    80               value={to}
    81               onChange={(e) => setTo(e.target.value)}
    82               className={styles.inputField}
    83             />
    84           </div>
    85           <div className={styles.buttons}>
    86             <button type="button" className={styles.iconButton} onClick={handleDirectionsSubmit}>
    87               <img src={searchIcon} alt="Submit Directions" />
    88             </button>
    89             <button type="button" className={styles.iconButton} onClick={toggleExpanded}>
    90               <img src={closeIcon} alt="Close Icon" />
    91             </button>
    92           </div>
    93         </div>
    94       )}
    95     </div>
     98      <div className={styles.wrapper}>
     99        {!isExpanded ? (
     100            <div className={styles.searchBar}>
     101              <input
     102                  type="search"
     103                  className={styles.inputField}
     104                  placeholder="Search location"
     105                  aria-label="Search"
     106                  ref={dropdownRef} // Attach the input to calculate dropdown position
     107                  onFocus={() => handleInputFocus("from")}
     108                  onChange={handleInputChange(setFrom)}
     109                  value={from}
     110              />
     111              {renderDropdown()}
     112              <div className={styles.buttons}>
     113                <button type="button" className={styles.iconButton} onClick={searchRoom}>
     114                  <img src={searchIcon} alt="Search Icon" />
     115                </button>
     116                <button type="button" className={styles.iconButton} onClick={toggleExpanded}>
     117                  <img src={routeIcon} alt="Route Icon" />
     118                </button>
     119              </div>
     120            </div>
     121        ) : (
     122            <div className={styles.directionsContainer}>
     123              <div className={styles.directionsInputs}>
     124                <input
     125                    type="text"
     126                    placeholder="From"
     127                    aria-label="From"
     128                    value={from}
     129                    onFocus={() => handleInputFocus("from")}
     130                    onChange={handleInputChange(setFrom)}
     131                    className={styles.inputField}
     132                    ref={inputFieldType === "from" ? dropdownRef : null}
     133                />
     134                <input
     135                    type="text"
     136                    placeholder="To"
     137                    aria-label="To"
     138                    value={to}
     139                    onFocus={() => handleInputFocus("to")}
     140                    onChange={handleInputChange(setTo)}
     141                    className={styles.inputField}
     142                    ref={inputFieldType === "to" ? dropdownRef : null}
     143                />
     144                {renderDropdown()}
     145              </div>
     146              <div className={styles.buttons}>
     147                <button
     148                    type="button"
     149                    className={styles.iconButton}
     150                    onClick={() => handleDirectionsSubmit(from, to)}
     151                >
     152                  <img src={searchIcon} alt="Submit Directions" />
     153                </button>
     154                <button type="button" className={styles.iconButton} onClick={toggleExpanded}>
     155                  <img src={closeIcon} alt="Close Icon" />
     156                </button>
     157              </div>
     158            </div>
     159        )}
     160      </div>
    96161  );
    97162}
Note: See TracChangeset for help on using the changeset viewer.