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

Pred finalna verzija

Location:
imaps-frontend/src/pages
Files:
13 added
4 deleted
12 edited
1 moved

Legend:

Unmodified
Added
Removed
  • imaps-frontend/src/pages/BrowseMaps/Maps.module.css

    rd565449 r0c6b92a  
     1
     2
    13.container {
    24  max-width: 1200px;
     
    79
    810h1 {
     11  font-family: exo, sans-serif;
    912  font-size: 2.5rem;
    10   color: #34495e;
     13  color: #0f71da;
    1114  margin-bottom: 20px;
    1215}
     
    6265}
    6366
     67.favorite{
     68  position: absolute;
     69  top: 20px;
     70  right: 20px;
     71  cursor: pointer;
     72}
     73
    6474/* When dragging a tile */
    6575.dragging {
  • imaps-frontend/src/pages/Draw/Draw.jsx

    rd565449 r0c6b92a  
    1 import { useEffect, useState } from "react";
    2 import { MapBuilder } from "../../scripts/main/MapBuilder.js";
     1import { useContext, useEffect, useState } from "react";
    32import styles from "./Draw.module.css";
    4 import RoomModal from "../../components/RoomModal/RoomModal.jsx";
    5 import SideBar from "../../components/SideBar/SideBar.jsx";
    6 import EntranceModal from "../../components/EntranceModal/EntranceModal.jsx";
     3import RoomModal from "../../components/Modals/RoomModal/RoomModal.jsx";
     4import EntranceModal from "../../components/Modals/EntranceModal/EntranceModal.jsx";
    75import DrawGuide from "../../components/DrawGuide/DrawGuide.jsx";
    8 import RoomTypeModal from "../../components/RoomTypeModal/RoomTypeModal.jsx";
    9 import InfoPinModal from "../../components/InfoPinModal/InfoPinModal.jsx";
     6import RoomTypeModal from "../../components/Modals/RoomTypeModal/RoomTypeModal.jsx";
     7import InfoPinModal from "../../components/Modals/InfoPinModal/InfoPinModal.jsx";
     8import SaveMap from "../../components/SaveMap/SaveMap.jsx";
     9import Logo from "../../components/Logo/Logo.jsx";
     10import { Link, useNavigate, useParams, useSearchParams } from "react-router-dom";
     11import Profile from "../../components/Profile/Profile.jsx";
    1012import HttpService from "../../scripts/net/HttpService.js";
    11 import SaveMap from "../../components/SaveMap/SaveMap.jsx";
    12 import logo from "../../assets/logo_icon.png";
    13 import MapTemplateSelector from "../../components/MapTemplateSelector/LoadMap.jsx";
    14 import KeymapPanel from "../../components/KeyMappingsGuidePanel/KeymapPanel.jsx";
    15 import { Link } from "react-router-dom";
     13import StairsModal from "../../components/Modals/StairsModal/StairsModal.jsx";
     14import useMapLoader from "./Hooks/useMapLoader.js";
     15import {FloorSelector} from "./FloorSelector.jsx";
     16import {useRoomTypesLoader} from "./Hooks/useRoomTypesLoader.js";
     17import {useAppContext} from "../../components/AppContext/AppContext.jsx";
     18import config from "../../scripts/net/netconfig.js";
     19import ShapeRegistry from "../../scripts/util/ShapeRegistry.js";
    1620
    1721function Draw() {
    18   const [selectedFloor, setSelectedFloor] = useState(1);
    19   const [app, setApp] = useState(null);
     22  const { mapName } = useParams();
     23  const { username } = useAppContext();
     24
    2025  const [isPopupVisible, setIsPopupVisible] = useState(false);
     26  const [errorMessage, setErrorMessage] = useState("Error");
     27  const [hasError, setHasError] = useState(false);
     28  const [searchParams, setSearchParams] = useSearchParams();
     29
     30  const[roomTypes,setRoomTypes] = useState([]);
     31
     32  const {app,floors,saveFloor,setFloors} = useMapLoader(mapName,username,searchParams,setSearchParams)
     33  const {addRoomType} = useRoomTypesLoader(setRoomTypes,mapName,username);
     34
     35  const addFloorHandler = async (newFloorNum) => {
     36    const httpService = new HttpService();
     37    httpService.setAuthenticated();
     38
     39    const payload = {
     40      num: newFloorNum,
     41      mapName: mapName,
     42    };
     43
     44    try {
     45      await httpService.put(`${config.floors.add}`, payload);
     46      console.log(`Added floor ${newFloorNum}`);
     47      setFloors((prevFloors) => [...prevFloors, { num: newFloorNum }]);
     48    } catch (error) {
     49      console.error("Error adding floor:", error);
     50    }
     51  };
     52
     53  const deleteFloorHandler = async (floorNum) => {
     54    if(floorNum === 0) return
     55
     56    const httpService = new HttpService();
     57    httpService.setAuthenticated();
     58
     59    try {
     60      await httpService.delete(`${config.floors.delete}?floorNum=${floorNum}&mapName=${mapName}`);
     61      setFloors((prevFloors) => prevFloors.filter(f => f.num !== floorNum))
     62
     63      const currFloor = searchParams.get("floor");
     64      if(currFloor == floorNum){
     65        setSearchParams({floor:"0"},{replace:true})
     66      }
     67      console.log(`Deleted floor ${floorNum}`);
     68    } catch (error) {
     69      console.error("Error deleting floor:", error);
     70    }
     71  };
     72
    2173  useEffect(() => {
    22     const app = new MapBuilder("container");
    23     setApp(app);
    24     // fpsCounterLoop();
     74    return () => {
     75      ShapeRegistry.clear();
     76    }
    2577  }, []);
    2678
    27   const handleFloorChange = (event) => {
    28     setSelectedFloor(event.target.value);
    29     console.log(`Floor changed to: ${event.target.value}`);
    30   };
    3179
    32   const handleRenderClick = () => {
    33     setIsPopupVisible(true);
     80  const handleSaveClick = async () => {
     81    saveFloor().then(r => {
     82     floors.forEach(flr => {
     83       setIsPopupVisible(true);
     84       setTimeout(() => {
     85         setIsPopupVisible(false);},
     86           3000);
     87       console.log("floor after save: " + JSON.stringify(flr))
     88     })
     89    });
    3490
    35     setTimeout(() => {
    36       setIsPopupVisible(false);
    37     }, 3000);
    38   };
    3991
    40   const handleSaveClick = async (mapName) => {
    41     const resp = await app.saveMap(mapName);
    42   };
    43   const handleLoadMapClick = (data) => {
    44     app.deserializeMap(data);
    4592  };
    4693
    4794  return (
    4895    <div className={styles.wrapper} id="wrapper">
    49       <SideBar></SideBar>
     96      {/* <SideBar></SideBar> */}
     97      <Logo></Logo>
    5098      <div id="container" className={styles.cont}></div>
    5199      <div className={styles.panel}>
    52         <Link to="/">
    53           <img src={logo} alt="Finki Logo" className={styles.logo} />
     100        <div className={styles.topPanelH}>
     101          <Profile position="inline"></Profile>
     102        </div>
     103        <Link to={`/myMaps/${mapName}/View`} className={styles.titleLink}>
     104          <h1 className={styles.title}>{mapName}</h1>
    54105        </Link>
    55         <h1 className={styles.title}>Map Builder</h1>
    56         {/* <div id="fpscont" className={styles.fpscounter}>
    57           <p id="fpsCounter"></p>
    58         </div> */}
    59106        <div className={styles.guideWrapper}>
    60           <DrawGuide />
     107          <DrawGuide/>
    61108        </div>
    62 
    63         {/* <div className={styles.floorSelector}>
    64           <label htmlFor="floorSelect">Select Floor:</label>
    65           <select
    66             id="floorSelect"
    67             value={selectedFloor}
    68             onChange={handleFloorChange}
    69             className={styles.floorDropdown}
    70           >
    71             <option value={1}>1st Floor</option>
    72             <option value={2}>2nd Floor</option>
    73             <option value={3}>3rd Floor</option>
    74             <option value={4}>4th Floor</option>
    75           </select>
    76         </div> */}
    77         {/* <h2 className={styles.paragraph}>Objects:</h2> */}
     109        <hr/>
     110        <br/>
     111        {/* {<h2 className={styles.paragraph}>Objects:</h2>} */}
    78112        <ul className={styles.shapeOptions} id="shapeOptions">
    79113          <li data-info="Entrance" className={`${styles.shapeOption} ${styles.entrance}`}></li>
    80114          <li data-info="Wall" className={`${styles.shapeOption} ${styles.wall}`} id="wall"></li>
    81115          <li data-info="Room" className={`${styles.shapeOption} ${styles.room}`} id="room"></li>
     116          <li data-info="Stairs" className={`${styles.shapeOption} ${styles.stairs}`} id="stairs"></li>
    82117        </ul>
    83         <br />
    84         <RoomTypeModal map={app}></RoomTypeModal>
     118        <RoomTypeModal map={app} roomTypes={roomTypes} addRoomTypeDB={addRoomType}></RoomTypeModal>
     119        <br/>
     120        <hr/>
     121        <br/>
     122        <FloorSelector floorConfig={{
     123          floors,searchParams,
     124          setSearchParams,addFloorHandler,
     125          deleteFloorHandler
     126        }}></FloorSelector>
    85127
    86         <div id="render" className={styles.buttonContainer}>
    87           <button
    88             id="render-button"
    89             type="button"
    90             className={styles.renderButton}
    91             onClick={handleRenderClick}
    92           >
    93             Render
    94           </button>
    95         </div>
     128        <br/>
     129
     130        <hr/>
     131        <br/>
     132        {hasError && <p style={{color: "red", textAlign: "center"}}>{errorMessage}</p>}
    96133        <div className={styles.templateCont}>
    97134          <SaveMap submitHandler={handleSaveClick}></SaveMap>
    98           <MapTemplateSelector loadHandler={handleLoadMapClick}></MapTemplateSelector>
    99135        </div>
    100136
    101137        <div className={styles.hide}>
    102           <RoomModal map={app}></RoomModal>
     138          <RoomModal map={app} roomTypes={roomTypes}></RoomModal>
    103139          <EntranceModal map={app}></EntranceModal>
    104140          <InfoPinModal map={app}></InfoPinModal>
     141          <StairsModal map={app}></StairsModal>
    105142        </div>
    106143      </div>
    107144
    108145      {isPopupVisible && (
    109         <div className={styles.popup}>
    110           <div className={styles.popupContent}>
    111             <h2>Map Rendered!</h2>
    112             <p>Your map has been successfully rendered.</p>
     146          <div className={styles.popup}>
     147            <div className={styles.popupContent}>
     148              <h2>Map Saved!</h2>
     149              <p>Your map has been successfully saved.</p>
     150            </div>
    113151          </div>
    114         </div>
    115152      )}
    116153    </div>
  • imaps-frontend/src/pages/Draw/Draw.module.css

    rd565449 r0c6b92a  
    44  padding: 0;
    55  height: 100%;
    6   overflow: hidden;
     6  overflow-x: hidden;
    77  background-color: #141414;
    88}
    99
     10.topPanelH {
     11  width: 100%;
     12  display: flex;
     13  justify-content: center;
     14  align-items: center;
     15  margin-bottom: 20px;
     16}
     17
    1018.logo {
    11   width: 100px;
    12   margin: 10px;
    13   align-self: center;
     19  width: 80px;
    1420}
    1521
    1622.title {
    17   margin-top: 20px;
    18   color: #804047;
    19   font-size: 120%;
     23  text-align: center;
     24  font-size: 2.5em;
     25  font-weight: 700;
     26  text-transform: uppercase;
     27  color: #333333;
     28  font-family: "Oswald", sans-serif;
     29  margin-bottom: 0;
     30  text-decoration: none;
     31}
     32
     33.titleLink {
     34  text-decoration: none;
     35}
     36.titleLink:hover{
     37  text-decoration: none;
    2038}
    2139
     
    2341  color: #cccccc;
    2442}
     43
    2544.guideWrapper {
    2645  display: flex;
     
    2847  align-items: center;
    2948  margin: 0;
     49  width: 100%;
    3050}
    3151
     
    5171  display: flex;
    5272  flex-direction: column;
     73  align-items: center; /* Center elements horizontally */
    5374  padding: 20px;
    5475  background-color: #1c1c1c;
     
    5879  margin-right: 10px;
    5980  border-radius: 20px;
     81  overflow-x: hidden;
    6082}
    6183
    6284.buttonContainer {
    6385  display: flex;
    64   justify-content: space-between;
     86  justify-content: center;
    6587  align-items: center;
    6688  margin-top: 2rem;
    6789  gap: 10px;
    68 }
    69 
    70 /* .hide {
    71   visibility: hidden;
    72 } */
     90  width: 100%;
     91}
    7392
    7493.renderButton {
     
    104123  list-style: none;
    105124  padding: 0;
    106   margin: 0 0;
    107   display: flex;
    108   flex-direction: column;
     125  margin: 0;
     126  display: grid;
     127  grid-template-columns: repeat(2, 1fr);
    109128  gap: 15px;
     129  justify-items: center;
    110130  align-items: center;
    111131}
     
    127147}
    128148
    129 .templateCont {
    130   display: flex;
    131   flex-direction: column;
    132 }
    133 
    134149.shapeOption:hover {
    135150  background-color: #94183b;
     
    137152}
    138153
     154.templateCont {
     155  display: flex;
     156  flex-direction: column;
     157  align-items: center; /* Center section horizontally */
     158  width: 100%;
     159}
     160
    139161.fpscounter {
    140162  border: 1px solid #00b822;
    141163  margin: 20px 0;
     164  text-align: center;
     165  width: 100%;
    142166}
    143167
     
    145169  color: #00740c;
    146170  font-weight: bold;
    147   text-align: center;
    148171  margin: 0;
    149172  padding: 5px 0;
    150173}
    151174
    152 .floorSelector {
    153   margin-bottom: 20px;
    154   display: flex;
    155   flex-direction: column;
    156   gap: 8px;
    157   color: #ffffff;
    158 }
    159 
    160 .floorSelector label {
    161   font-size: 14px;
    162 }
    163 
    164 .floorDropdown {
    165   padding: 8px;
    166   font-size: 14px;
    167   border-radius: 5px;
    168   border: 1px solid #ccc;
    169   background-color: #3a3a3a;
    170   color: #ffffff;
    171   cursor: pointer;
    172   width: 100%;
    173   transition: border-color 0.3s;
    174 }
    175 
    176 .floorDropdown:focus {
    177   outline: none;
    178   border-color: #1e90ff;
    179 }
    180175
    181176.popup {
     
    226221  background-image: url("./shapeImages/room_icon.png");
    227222}
     223.stairs {
     224  background-image: url("./shapeImages/stairs_icon.png");
     225}
     226.floorSection {
     227  display: flex;
     228  flex-direction: column;
     229  align-items: center;
     230  gap: 20px;
     231  background-color: #2d2d2d;
     232  padding: 20px;
     233  border-radius: 8px;
     234  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.2);
     235  width: 100%;
     236}
     237
     238.floorLabel {
     239  font-size: 16px;
     240  font-weight: bold;
     241  color: #ffffff;
     242  margin-bottom: 10px;
     243  text-align: center;
     244}
     245
     246.floorList {
     247  display: flex;
     248  flex-direction: column;
     249  align-items: center;
     250  gap: 15px;
     251  width: 100%;
     252}
     253
     254.floorItems {
     255  display: flex;
     256  flex-direction: column;
     257  align-items: center;
     258  gap: 10px;
     259  width: 100%;
     260}
     261
     262.addFloorButton {
     263  background-color: #e67e22;
     264  border: none;
     265  border-radius: 50%;
     266  width: 40px;
     267  height: 40px;
     268  display: flex;
     269  justify-content: center;
     270  align-items: center;
     271  cursor: pointer;
     272  transition: background-color 0.3s, transform 0.2s;
     273}
     274
     275.addFloorButton:hover {
     276  background-color: #d2691e;
     277  transform: scale(1.1);
     278}
     279
     280.addFloorButton:active {
     281  background-color: #b35418;
     282  transform: scale(0.95);
     283}
     284
     285.icon {
     286  width: 20px;
     287  height: 20px;
     288  filter: invert(1);
     289}
     290
     291.floorButton {
     292  padding: 10px 15px;
     293  font-size: 14px;
     294  color: #ffffff;
     295  background-color: #3a3a3a;
     296  border: 1px solid #555555;
     297  border-radius: 8px;
     298  width: 100%;
     299  text-align: center;
     300  cursor: pointer;
     301  transition: background-color 0.3s, transform 0.2s;
     302}
     303
     304.floorButton:hover {
     305  background-color: #4a4a4a;
     306}
     307
     308.floorButton.active {
     309  background-color: #1e90ff;
     310  color: #ffffff;
     311  font-weight: bold;
     312}
     313
     314.floorInput {
     315  width: 60%;
     316  padding: 8px;
     317  font-size: 14px;
     318  border: 1px solid #ccc;
     319  border-radius: 5px;
     320  background-color: #3a3a3a;
     321  color: #ffffff;
     322  text-align: center;
     323  transition: border-color 0.3s;
     324}
     325
     326.floorInput:focus {
     327  outline: none;
     328  border-color: #1e90ff;
     329}
     330
     331.floorActions {
     332  display: flex;
     333  gap: 10px;
     334  justify-content: center;
     335  align-items: center;
     336  margin-top: 10px;
     337}
     338
     339.errorMessage {
     340  color: red;
     341  font-size: 12px;
     342  margin-top: 10px;
     343  text-align: center;
     344}
     345.floorItemWrapper {
     346  display: flex;
     347  align-items: center;
     348  gap: 10px;
     349  width: 100%;
     350}
     351
     352.floorItem {
     353  padding: 10px 15px;
     354  font-size: 14px;
     355  color: #ffffff;
     356  background-color: #3a3a3a;
     357  border: 1px solid #555555;
     358  border-radius: 8px;
     359  text-align: center;
     360  cursor: pointer;
     361  flex-grow: 1;
     362  transition: background-color 0.3s;
     363}
     364
     365.floorItem:hover {
     366  background-color: #4a4a4a;
     367}
     368
     369.activeFloor {
     370  background-color: #1e90ff;
     371  color: #ffffff;
     372  font-weight: bold;
     373}
     374
     375.deleteFloorButton {
     376  background-color: #ff4d4d;
     377  border: none;
     378  border-radius: 8px;
     379  padding: 10px;
     380  color: white;
     381  cursor: pointer;
     382  transition: background-color 0.3s, transform 0.2s;
     383}
     384
     385.deleteFloorButton:hover {
     386  background-color: #e60000;
     387  transform: scale(1.1);
     388}
     389
     390.deleteFloorButton:active {
     391  background-color: #cc0000;
     392  transform: scale(0.95);
     393}
  • imaps-frontend/src/pages/IMaps/IMaps.jsx

    rd565449 r0c6b92a  
    44import styles from "./IMaps.module.css";
    55import Home from "./components/pages/Home";
     6import Profile from "../../components/Profile/Profile";
     7import Logo from "../../components/Logo/Logo";
     8import Cards from "./components/Cards";
    69
    710function IMaps() {
    811  return (
    9     <>
    10       <div className={styles.home}>
    11         <Navbar></Navbar>
    12         <Home></Home>
    13       </div>
    14     </>
     12    <div className="homebg">
     13      <Navbar></Navbar>
     14      <Home></Home>
     15    </div>
    1516  );
    1617}
  • imaps-frontend/src/pages/IMaps/IMaps.module.css

    rd565449 r0c6b92a  
    55html,
    66body {
    7   overflow: auto;
    8   overflow-x: hidden;
     7  margin: 0;
    98}
  • imaps-frontend/src/pages/IMaps/components/Button.css

    rd565449 r0c6b92a  
     1@import url(https://fonts.googleapis.com/css?family=Exo:500);
    12:root {
    2   --primary: #fff;
     3  --primary: #252627;
    34}
    45
    56.btn {
    67  padding: 8px 20px;
    7 
     8  font-family: exo, sans-serif;
    89  border-radius: 20px;
    910  outline: none;
     
    1415.btn--primary {
    1516  background-color: var(--primary);
    16 
    17   color: #242424;
     17  color: #ffffff;
    1818  border: 1px solid var(--primary);
    1919}
     
    2424  color: #fff;
    2525  padding: 8px 20px;
    26   border: 1px solid var(--primary);
     26  /* border: 1px solid var(--primary); */
    2727  transition: all 0.3s ease-out;
    2828}
     
    3030.btn--medium {
    3131  padding: 8px 20px;
    32   font-size: 18px;
     32  font-size: 22px;
    3333}
    3434
    3535.btn--large {
    3636  padding: 12px 26px;
    37   font-size: 20px;
     37  font-size: 24px;
    3838}
    3939
     
    4141.btn--medium:hover {
    4242  transition: all 0.3s ease-out;
    43   background: #fff;
    44   color: #242424;
     43  background: #ffffffc2;
     44  color: #000000;
    4545  transition: 250ms;
    4646}
  • imaps-frontend/src/pages/IMaps/components/HeroSection.css

    rd565449 r0c6b92a  
     1@import url(https://fonts.googleapis.com/css?family=Exo:500);
     2
    13video {
    24  object-fit: cover;
     
    79}
    810
     11
     12
     13
    914.hero-container {
    10   background: url("../images/img-home.jpg") center center/cover no-repeat;
    1115  height: 100vh;
    1216  width: 100%;
     
    1519  justify-content: center;
    1620  align-items: center;
    17   box-shadow: inset 0 0 0 1000px rgba(0, 0, 0, 0.4);
     21
    1822  object-fit: contain;
     23
     24
     25
    1926}
    2027
     
    2330  font-size: 100px;
    2431  margin-top: -100px;
     32  font-family: exo, sans-serif;
     33  text-transform: uppercase;
     34  text-shadow: 1px 1px 0px #ef404e,
     35  1px 2px 0px #ef404e,
     36  1px 3px 0px #ef404e,
     37  1px 4px 0px #ef404e,
     38  1px 5px 0px #ef404e,
     39  1px 6px 0px #ef404e,
     40  1px 10px 5px rgba(16, 16, 16, 0.5),
     41  1px 15px 10px rgba(16, 16, 16, 0.4),
     42  1px 20px 30px rgba(16, 16, 16, 0.3),
     43  1px 25px 50px rgba(16, 16, 16, 0.2);
    2544}
    2645
  • imaps-frontend/src/pages/IMaps/components/HeroSection.jsx

    rd565449 r0c6b92a  
    77function HeroSection() {
    88  return (
    9     <div className="hero-container">
    10       <h1>Map Your World</h1>
    11       <p>Create and explore detailed indoor maps.</p>
    12       <div className="hero-btns">
    13         <Link to="/Maps/FinkiMaps/Draw">
    14           <Button className="btns" buttonStyle="btn--outline" buttonSize="btn--large">
    15             Create maps
    16           </Button>
    17         </Link>
    18         <Link to="/Maps">
    19           <Button
    20             className="btns"
    21             buttonStyle="btn--primary"
    22             buttonSize="btn--large"
    23             onClick={console.log("hey")}
    24           >
    25             Browse Maps <i className="far fa-play-circle" />
    26           </Button>
    27         </Link>
     9      <div className="hero-container">
     10          <h1>Map Your World</h1>
     11          <p>Create and explore detailed indoor maps.</p>
     12          <div className="hero-btns">
     13              <Link to="/myMaps">
     14                  <Button className="btns" buttonStyle="btn--outline" buttonSize="btn--large">
     15                      Create maps
     16                  </Button>
     17              </Link>
     18              <Link to="/Maps">
     19                  <Button
     20                      className="btns"
     21                      buttonStyle="btn--primary"
     22                      buttonSize="btn--large"
     23                  >
     24                      Browse Maps <i className="far fa-play-circle"/>
     25                  </Button>
     26              </Link>
     27          </div>
    2828      </div>
    29     </div>
    3029  );
    3130}
  • imaps-frontend/src/pages/IMaps/components/Navbar.css

    rd565449 r0c6b92a  
    1 .navbar {
    2   background: linear-gradient(90deg, rgb(28, 27, 27) 0%, rgb(26, 23, 23) 100%);
    3   height: 80px;
     1.modern-navbar {
     2  /*background-color: #ffffff;*/
     3  /*background: linear-gradient(*/
     4  /*        90deg,*/
     5  /*        #fafafa 0%,*/
     6  /*        #c07e7e 25%,*/
     7  /*        #af2525 50%,*/
     8  /*        #443a3a 75%,*/
     9  /*        #8d1010 100%*/
     10  /*);*/
     11  /*background: linear-gradient(to right, #ffffff, #c12c2c);*/
     12  /*background: linear-gradient(90deg, #3b3131, #ffffff);*/
     13  background: linear-gradient(90deg, #9b1818, #efefef);
     14  color: #ffffff;
     15  /*color: #333333;*/
    416  display: flex;
    517  justify-content: center;
    618  align-items: center;
    7   font-size: 1.2rem;
     19  padding: 0.8rem 1.5rem;
     20  box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.1);
    821  position: sticky;
    922  top: 0;
    10   z-index: 999;
    11 }
    12 
    13 .pad-bot {
    14   /* padding-bottom: 1.5rem; */
     23  z-index: 1000;
     24  border-radius: 8px;
     25  margin: 5px;
    1526}
    1627
    1728.navbar-container {
    1829  display: flex;
    19   justify-content: center;
     30  justify-content: space-between;
    2031  align-items: center;
    2132  width: 100%;
     33  max-width: 1200px;
    2234}
    2335
    24 .navbar-logo {
    25   color: #fff;
    26   justify-self: start;
    27   margin-left: 20px;
    28   cursor: pointer;
    29   text-decoration: none;
    30   font-size: 2rem;
     36.navbar-left {
    3137  display: flex;
    3238  align-items: center;
     39  gap: 1rem;
    3340}
    3441
    35 .fa-typo3 {
    36   margin-left: 0.5rem;
    37   font-size: 1.8rem;
     42.navbar-title {
     43  font-size: 1.6rem;
     44  font-weight: 700;
     45  color: #ffffff;
     46  margin: 0;
     47  font-family: "exo", sans-serif;
    3848}
    3949
    40 .nav-menu {
    41   display: grid;
    42   grid-template-columns: repeat(4, auto);
    43   grid-gap: 10px;
    44   list-style: none;
    45   text-align: center;
    46   width: 70vw;
    47   justify-content: end;
    48   margin-right: 2rem;
     50.navbar-right {
     51  display: flex;
     52  align-items: center;
     53  gap: 1rem;
    4954}
    5055
    51 .nav-item {
    52   height: 80px;
     56.navbar-btn {
     57  padding: 0.4rem 1.5rem;
     58  font-size: 0.9rem;
     59  border: 2px solid transparent;
     60  border-radius: 20px;
     61  text-decoration: none;
     62  color: #ffffff;
     63  font-weight: 500;
     64  transition: all 0.3s ease-in-out;
     65  font-family: "exo", sans-serif;
     66  cursor: pointer;
     67  margin-left: 4em;
     68  margin-right: 1em;
    5369}
    5470
    55 .nav-links {
    56   color: #fff;
    57   display: flex;
    58   align-items: center;
    59   text-decoration: none;
    60   padding: 0.5rem 1rem;
    61   height: 100%;
     71.navbar-login {
     72  background-color: #252627;
     73  border: 2px solid #3f3232;
    6274}
    6375
    64 .nav-links:hover {
    65   border-bottom: 4px solid #fff;
    66   transition: all 0.2s ease-out;
     76.navbar-login:hover {
     77  background-color: #ffffff;
     78  color: #212121;
     79  border: 1px solid rgba(19, 18, 18, 0.82);
    6780}
    6881
    69 .fa-bars {
    70   color: #fff;
     82.navbar-signup {
     83  background-color: #252627;
     84  color: #ffffff;
     85  border: 2px solid #343a40;
    7186}
    7287
    73 .nav-links-mobile {
    74   display: none;
     88.navbar-signup:hover {
     89  background-color: #ffffff;
     90  color: #343a40;
     91  border: 2px solid #343a40;
    7592}
    76 
    77 .menu-icon {
    78   display: none;
    79 }
    80 
    81 @media screen and (max-width: 960px) {
    82   .NavbarItems {
    83     position: relative;
    84   }
    85 
    86   .nav-menu {
    87     display: flex;
    88     flex-direction: column;
    89     width: 100%;
    90     height: 90vh;
    91     position: absolute;
    92     top: 80px;
    93     left: -100%;
    94     opacity: 1;
    95     transition: all 0.5s ease;
    96   }
    97 
    98   .nav-menu.active {
    99     background: #242222;
    100     left: 0;
    101     opacity: 1;
    102     transition: all 0.5s ease;
    103     z-index: 1;
    104   }
    105 
    106   .nav-links {
    107     text-align: center;
    108     padding: 2rem;
    109     width: 100%;
    110     display: table;
    111   }
    112 
    113   .nav-links:hover {
    114     background-color: #fff;
    115     color: #242424;
    116     border-radius: 0;
    117   }
    118 
    119   .navbar-logo {
    120     position: absolute;
    121     top: 0;
    122     left: 0;
    123     transform: translate(25%, 50%);
    124   }
    125 
    126   .menu-icon {
    127     display: block;
    128     position: absolute;
    129     top: 0;
    130     right: 0;
    131     transform: translate(-100%, 60%);
    132     font-size: 1.8rem;
    133     cursor: pointer;
    134   }
    135 
    136   .fa-times {
    137     color: #fff;
    138     font-size: 2rem;
    139   }
    140 
    141   .nav-links-mobile {
    142     display: block;
    143     text-align: center;
    144     margin: 2rem auto;
    145     border-radius: 4px;
    146     width: 80%;
    147     text-decoration: none;
    148     font-size: 1.5rem;
    149     background-color: transparent;
    150     color: #fff;
    151     padding: 14px 20px;
    152     border: 1px solid #fff;
    153     transition: all 0.3s ease-out;
    154   }
    155 
    156   .nav-links-mobile:hover {
    157     background: #fff;
    158     color: #242424;
    159     transition: 250ms;
    160   }
    161 }
  • imaps-frontend/src/pages/IMaps/components/Navbar.jsx

    rd565449 r0c6b92a  
    1 import React, { useState, useEffect } from "react";
    2 import { Button } from "./Button";
     1import React, {useContext, useState} from "react";
     2import { Link } from "react-router-dom";
     3import logo_icon from "../../../assets/logo_icon.png";
     4//import { AuthContext } from "../../../components/AuthContext/AuthContext";
     5import Logo from "../../../components/Logo/Logo.jsx";
     6import Profile from "../../../components/Profile/Profile.jsx";
     7import {useAppContext} from "../../../components/AppContext/AppContext.jsx";
    38import "./Navbar.css";
    4 import { Link } from "react-router-dom";
    5 import logo from "../../../assets/logo_icon.png";
    69
    710function Navbar() {
     
    1215  const closeMobileMenu = () => setClick(false);
    1316
    14   const showButton = () => {
    15     if (window.innerWidth <= 960) {
    16       setButton(false);
    17     } else {
    18       setButton(true);
    19     }
    20   };
     17  const { isAuthenticated } = useAppContext();
    2118
    22   useEffect(() => {
    23     showButton();
    24   }, []);
     19    return (
     20        <nav className="modern-navbar">
     21            <div className="navbar-container">
     22                {/* Left Section - Logo and Title */}
     23                <div className="navbar-left">
     24                    <Logo position="relative"/>
     25                    <h1 className="navbar-title">iMaps</h1>
     26                </div>
    2527
    26   window.addEventListener("resize", showButton);
    27 
    28   return (
    29     <>
    30       <nav className="navbar">
    31         <div className="navbar-container">
    32           <a href="#" className="navbar-logo pad-bot" onClick={closeMobileMenu}>
    33             iMaps
    34           </a>
    35           <div className="menu-icon" onClick={handleClick}>
    36             <i className={click ? "fas fa-times" : "fas fa-bars"} />
    37           </div>
    38           <ul className={click ? "nav-menu active" : "nav-menu"}>
    39             <Link to="/Signup">
    40               <li className="nav-item">
    41                 <a href="#" className="nav-links" onClick={closeMobileMenu}>
    42                   SignUp
    43                 </a>
    44               </li>
    45             </Link>
    46           </ul>
    47           <div className="pad-bot">
    48             <Link to="/Login">{button && <Button buttonStyle="btn--outline">LOG IN</Button>}</Link>
    49           </div>
    50         </div>
    51       </nav>
    52     </>
    53   );
     28                {/* Right Section - Login/Signup or Profile */}
     29                <div className="navbar-right">
     30                    {isAuthenticated ? (
     31                        <Profile position="relative"/>
     32                    ) : (
     33                        <>
     34                            <Link to="/Login" className="navbar-btn navbar-login">
     35                                Log In
     36                            </Link>
     37                            <Link to="/Signup" className="navbar-btn navbar-signup">
     38                                Sign Up
     39                            </Link>
     40                        </>
     41                    )}
     42                </div>
     43            </div>
     44        </nav>
     45    );
    5446}
    5547
  • imaps-frontend/src/pages/IMaps/components/pages/Home.jsx

    rd565449 r0c6b92a  
    11import React from "react";
    2 import "./Home.css";
    3 import Cards from "../Cards";
    4 import HeroSection from "../HeroSection";
    5 import Footer from "../Footer";
     2import "./Home.scss";
     3import { Link } from "react-router-dom";
     4import { Button } from "../Button.jsx";
     5import Cards from "../Cards.jsx";
     6import Footer from "../Footer.jsx";
     7import sl from "../../../../assets/bg-home-light-gray.png"
    68
    79function Home() {
    810  return (
    9     <>
    10       <div className="home">
    11         <HeroSection />
    12         {/* <Cards /> */}
    13         <Footer />
     11    <div className="home">
     12      <div className="hero-container">
     13        <h1>Map Your World</h1>
     14        <h2 className="description">Create and explore detailed indoor maps.</h2>
     15        <div className="hero-btns">
     16          <Link to="/myMaps">
     17            <Button className="btns" buttonSize="btn--large">
     18              Create Maps
     19            </Button>
     20          </Link>
     21          <Link to="/Maps">
     22            <Button className="btns" buttonSize="btn--large">
     23              Browse Maps <i className="far fa-play-circle" />
     24            </Button>
     25          </Link>
     26        </div>
    1427      </div>
    15     </>
     28      <Cards />
     29      <Footer></Footer>
     30    </div>
    1631  );
    1732}
  • imaps-frontend/src/pages/Login/Login.jsx

    rd565449 r0c6b92a  
    1 import React, { useState } from "react";
    2 import { Link, useNavigate } from "react-router-dom";
     1import React, {useContext, useState} from "react";
     2import {Link, useLocation, useNavigate} from "react-router-dom";
    33import styles from "./Login.module.css";
    44import illustration from "../../assets/illustration_img.png";
     5import Logo from "../../components/Logo/Logo.jsx";
     6import HttpService from "../../scripts/net/HttpService.js";
     7import {useAppContext} from "../../components/AppContext/AppContext.jsx";
     8import config from "../../scripts/net/netconfig.js";
    59
    6 const LoginPage = ({onLogin}) => {
    7   const [username, setUsername] = useState("");
    8   const [password, setPassword] = useState("");
    9   const [error, setError] = useState(null);
    10   const navigate = useNavigate();
     10const LoginPage = () => {
     11    const [formUsername, setFormUsername] = useState("");
     12    const [password, setPassword] = useState("");
     13    const [error, setError] = useState(null);
     14    const navigate = useNavigate();
     15    const location = useLocation();
    1116
    12   const payload = {
    13     username: username,
    14     password: password
    15   };
     17    const {setUsername, setIsAuthenticated} = useAppContext();
    1618
    17   const handleLogin = (e) => {
    18     e.preventDefault();
     19    const {targetPath} = location.state || {targetPath: {pathname: "/"}};
    1920
    20     fetch("http://localhost:8080/api/auth/login", {
    21       method: "POST",
    22       headers: {
    23         "Content-Type": "application/json",
    24       },
    25       body: JSON.stringify(payload),
    26     })
    27       .then((response) => {
    28         if (!response.ok) {
    29           throw new Error("Login failed: resp = " + response.statusText);
    30         }
    31         return response.json();
    32       })
    33       .then((data) => {
    34         if (data.token) {
    35           navigate("/Maps/FinkiMaps/Draw");
    36           onLogin(data.token)
    37         } else {
    38           setError("Invalid username or password.");
    39         }
    40       })
    41       .catch((error) => {
    42         console.error("Login failed", error);
    43         setError("Login failed. Please try again.");
    44       });
    45    
    46   };
     21    const payload = {
     22        username: formUsername,
     23        password: password,
     24    };
    4725
    48   return (
    49     <div className={styles.wrapper}>
    50       <div className={styles.illustration}>
    51         <img src={illustration} alt="illustration" />
    52       </div>
    53       <div className={styles.form}>
    54         <div className={styles.heading}>LOGIN</div>
    55         <form onSubmit={handleLogin}>
    56           <div>
    57             <label htmlFor="username">Username</label>
    58             <input
    59               type="text"
    60               id="name"
    61               placeholder="Enter your username"
    62               onChange={(e) => setUsername(e.target.value)}
    63               value={username}
    64               required
    65             />
    66           </div>
    67           <div>
    68             <label htmlFor="password">Password</label>
    69             <input
    70               type="password"
    71               id="password"
    72               placeholder="Enter your password"
    73               onChange={(e) => setPassword(e.target.value)}
    74               value={password}
    75               required
    76             />
    77           </div>
    78           {error && <p className={styles.error}>{error}</p>}
    79           <button type="submit">Submit</button>
    80         </form>
    81         <p>
    82           Don't have an account? <Link to="/Signup"> Sign Up </Link>
    83         </p>
    84       </div>
    85     </div>
    86   );
     26    const handleLogin = async () => {
     27        const httpService = new HttpService();
     28        return httpService.post(config.auth.login, payload)
     29
     30    };
     31
     32
     33    const login = async (e) => {
     34        e.preventDefault();
     35
     36        handleLogin()
     37            .then(resp => {
     38                if (resp.token) {
     39                    navigate(targetPath)
     40                    localStorage.setItem("token", resp.token);
     41                    setUsername(resp.username);
     42                    setIsAuthenticated(true);
     43                    console.log("ROLES",resp.roles)
     44                } else {
     45                    setError("Invalid username or password.");
     46                }
     47            }).catch(reason => {
     48            console.error("Login failed", reason);
     49            setError("Login failed. Please try again.")
     50        })
     51
     52        // fetch("http://localhost:8080/api/auth/login", {
     53        //   method: "POST",
     54        //   headers: {
     55        //     "Content-Type": "application/json",
     56        //   },
     57        //   body: JSON.stringify(payload),
     58        // })
     59        //   .then((response) => {
     60        //     if (!response.ok) {
     61        //       throw new Error("Login failed: resp = " + response.statusText);
     62        //     }
     63        //     return response.json();
     64        //   })
     65        //   .then((data) => {
     66        //     if (data.token) {
     67        //       navigate(targetPath);
     68        //       handleLogin(data);
     69        //     } else {
     70        //       setError("Invalid username or password.");
     71        //     }
     72        //   })
     73        //   .catch((error) => {
     74        //     console.error("Login failed", error);
     75        //     setError("Login failed. Please try again.");
     76        //   });
     77    };
     78
     79    return (
     80        <div className={styles.wrapper}>
     81            <Logo></Logo>
     82            <div className={styles.illustration}>
     83                <img src={illustration} alt="illustration"/>
     84            </div>
     85            <div className={styles.form}>
     86                <div className={styles.heading}>LOGIN</div>
     87                <form onSubmit={login}>
     88                    <div>
     89                        <label htmlFor="username">Username</label>
     90                        <input
     91                            type="text"
     92                            id="name"
     93                            placeholder="Enter your username"
     94                            onChange={(e) => setFormUsername(e.target.value)}
     95                            value={formUsername}
     96                            required
     97                        />
     98                    </div>
     99                    <div>
     100                        <label htmlFor="password">Password</label>
     101                        <input
     102                            type="password"
     103                            id="password"
     104                            placeholder="Enter your password"
     105                            onChange={(e) => setPassword(e.target.value)}
     106                            value={password}
     107                            required
     108                        />
     109                    </div>
     110                    {error && <p className={styles.error}>{error}</p>}
     111                    <button type="submit">Submit</button>
     112                </form>
     113                <p>
     114                    Don't have an account? <Link to="/Signup"> Sign Up </Link>
     115                </p>
     116            </div>
     117        </div>
     118    );
    87119};
    88120
  • imaps-frontend/src/pages/Signup/Signup.jsx

    rd565449 r0c6b92a  
    33import illustration from "../../assets/illustration_img.png";
    44import styles from "./Signup.module.css";
     5import Logo from "../../components/Logo/Logo";
    56
    67export default function Signup() {
     
    5455  return (
    5556    <div className={styles.wrapper}>
     57      <Logo></Logo>
    5658      <div className={styles.illustration}>
    5759        <img src={illustration} alt="illustration" />
Note: See TracChangeset for help on using the changeset viewer.