diff --git a/src/App.css b/src/App.css index 2bb08714..8ac7e2cf 100644 --- a/src/App.css +++ b/src/App.css @@ -36,3 +36,13 @@ .host { color: grey; } + +.overlay { + position: fixed; + top: 0; + left: 0; + width: 100vw; + height: 100vh; + background-color: rgba(0, 0, 0, 0.6); + z-index: 1100; +} \ No newline at end of file diff --git a/src/App.jsx b/src/App.jsx index a34aa345..d9235a46 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -5,32 +5,18 @@ import "./App.css"; import CategoryTabs from "./components/CategoryTabs/CategoryTabs"; import ProductCard from "./components/ProductCard/ProductCard"; import CalendarToggle from "./components/calendarToggle/CalendarToggle"; -import PriceRangeFilter from "./components/priceRange/PriceRangeFilter"; import { BASE_URL } from "./constants/constants"; +import PriceRangeModal from "./components/PriceRangeModal/PriceRangeModal"; function App() { const [places, setPlaces] = useState([]); const [selectPlaceId, setSelectPlaceId] = useState(null); const [searchParams] = useSearchParams(); + const [isModalOpen, setModalOpen] = useState(false); + const [histogramData, setHistogramData] = useState([]); - const histogramData = [ - { from: 16, to: 23, count: 2 }, - { from: 37, to: 44, count: 13 }, - { from: 55, to: 63, count: 30 }, - { from: 76, to: 84, count: 50 }, - { from: 95, to: 103, count: 90 }, - { from: 116, to: 123, count: 60 }, - { from: 135, to: 143, count: 20 }, - { from: 156, to: 156, count: 12 }, - { from: 174, to: 182, count: 15 }, - { from: 194, to: 202, count: 8 }, - { from: 216, to: 224, count: 5 }, - { from: 233, to: 242, count: 10 }, - { from: 254, to: 261, count: 25 }, - { from: 273, to: 281, count: 40 }, - { from: 292, to: 304, count: 22 }, - ]; + const toggleModal = () => setModalOpen((prev) => !prev); useEffect(() => { axios @@ -59,9 +45,7 @@ function App() { - - - +
{places.map((place) => { @@ -82,6 +66,14 @@ function App() { ); })}
+ {isModalOpen && ( + + )} ); } diff --git a/src/components/CategoryTabs/CategoryTabs.jsx b/src/components/CategoryTabs/CategoryTabs.jsx index 8d1c5d26..71e68e7b 100644 --- a/src/components/CategoryTabs/CategoryTabs.jsx +++ b/src/components/CategoryTabs/CategoryTabs.jsx @@ -28,7 +28,7 @@ const categories = [ { label: "Riverside Cabins", tag: constants.RIVERSIDE_CABINS, icon: }, ]; -const CategoryTabs = () => { +const CategoryTabs = ({toggleModal, setHistogramData}) => { const [activeTab, setActiveTab] = useState(null); const [showLeftArrow, setShowLeftArrow] = useState(false); const [showRightArrow, setShowRightArrow] = useState(false); @@ -124,7 +124,7 @@ const CategoryTabs = () => { })}
- +
{showRightArrow && ( diff --git a/src/components/CategoryTabs/CategoryTabs.module.css b/src/components/CategoryTabs/CategoryTabs.module.css index e7ac990b..244c82a7 100644 --- a/src/components/CategoryTabs/CategoryTabs.module.css +++ b/src/components/CategoryTabs/CategoryTabs.module.css @@ -10,12 +10,13 @@ left: 0; right: 0; background-color: white; - z-index: 998; + z-index: 499; padding-top: 15px; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); } .categoryMenu { + z-index: 1; width: 95vw; display: flex; flex-direction: row; @@ -29,7 +30,8 @@ display: flex; justify-content: center; overflow: hidden; - position: relative; + /* position: relative; */ + z-index: 1; } .filterButtonWrapper { diff --git a/src/components/FilterButton/FilterButton.jsx b/src/components/FilterButton/FilterButton.jsx index 35aba5d9..2d263d25 100644 --- a/src/components/FilterButton/FilterButton.jsx +++ b/src/components/FilterButton/FilterButton.jsx @@ -1,19 +1,48 @@ -import React from 'react' -import styles from "./FilterButton.module.css" +import { useEffect } from "react"; +import styles from "./FilterButton.module.css"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faSliders } from "@fortawesome/free-solid-svg-icons"; -const FilterButton = () => { - return ( +const FilterButton = ({toggleModal, setHistogramData = () => {}}) => { + // Simulating dynamic data fetching or processing + useEffect(() => { + if (!setHistogramData) { + console.warn("setHistogramData is not provided to FilterButton"); + return; + } + // Replace this logic with actual data processing from the provided file or API + const generateHistogramData = () => { + const minPrice = 9; + const maxPrice = 310; + const bins = 6; // Number of bins for histogram -
-
- -
Filters
-
-
+ const binSize = Math.ceil((maxPrice - minPrice) / bins); + const mockData = Array.from({ length: bins }, (_, index) => { + const from = minPrice + index * binSize; + const to = Math.min(from + binSize - 1, maxPrice); + const count = Math.floor(Math.random() * 20) + 1; // Random count for demo - ) -} + return { from, to, count }; + }); -export default FilterButton \ No newline at end of file + return mockData; + }; + + const data = generateHistogramData(); + setHistogramData(data); + }, [setHistogramData]); + + return ( + <> + {/* Filter button */} +
+
+ +
Filters
+
+
+ + ); +}; + +export default FilterButton; diff --git a/src/components/HeaderUserMenu/HeaderUserMenu.module.css b/src/components/HeaderUserMenu/HeaderUserMenu.module.css index 0368cb50..a4a62120 100644 --- a/src/components/HeaderUserMenu/HeaderUserMenu.module.css +++ b/src/components/HeaderUserMenu/HeaderUserMenu.module.css @@ -1,4 +1,5 @@ .headerContainer { + z-index:; position: relative; display: inline-block; } diff --git a/src/components/PriceRangeModal/PriceRangeModal.jsx b/src/components/PriceRangeModal/PriceRangeModal.jsx new file mode 100644 index 00000000..15887941 --- /dev/null +++ b/src/components/PriceRangeModal/PriceRangeModal.jsx @@ -0,0 +1,91 @@ +import React, { useState } from "react"; +import styles from "./PriceRangeModal.module.css"; +import PriceRangeFilter from "../priceRange/PriceRangeFilter"; +import { CloseIcon } from "../../icons/CloseIcon"; + +const PriceRangeModal = ({ isOpen, onClose, histogramData, className }) => { + const [bedrooms, setBedrooms] = useState(0); // State for Bedrooms + const [beds, setBeds] = useState(0); // State for Beds + const [bathrooms, setBathrooms] = useState(0); // State for Bathrooms + + // Increment and Decrement Handlers + const increment = (setter, value) => setter(value + 1); + const decrement = (setter, value) => { + if (value > 0) setter(value - 1); + }; + + if (!isOpen) return null; + + return ( +
+
+ {/* Header Section */} +
+
+ +
+

Filters

+
+ +
+ +
+ + {/* Rooms and Beds Section */} +
+

Rooms and Beds

+ + {/* Bedrooms Section */} +
+
+

Bedrooms

+
+
+ +

{bedrooms || "Any"}

+ +
+
+ + {/* Beds Section */} +
+
+

Beds

+
+
+ +

{beds || "Any"}

+ +
+
+ + {/* Bathrooms Section */} +
+
+

Bathrooms

+
+
+ +

{bathrooms || "Any"}

+ +
+
+
+ + {/* Submit Section */} +
+ + +
+
+
+ ); +}; + +export default PriceRangeModal; diff --git a/src/components/PriceRangeModal/PriceRangeModal.module.css b/src/components/PriceRangeModal/PriceRangeModal.module.css new file mode 100644 index 00000000..10eb4cff --- /dev/null +++ b/src/components/PriceRangeModal/PriceRangeModal.module.css @@ -0,0 +1,208 @@ +.overlay { + position: fixed; + top: 0; + left: 0; + width: 100vw; + height: 100vh; + background-color: rgba(0, 0, 0, 0.6); +} + +.submitSection { + padding-left: 0px; + padding-right: 10px; + padding-top: 20px; + display: flex; + flex-direction: row; + justify-content: space-between; +} + +.section { + justify-content: space-between; + display: flex; + flex-direction: row; +} + +.increment { + display: flex; + gap: 20px; + align-items: center; + justify-content: center; + flex-direction: row; +} + +.sub { + font-weight: 400; + width: 2.5rem; + text-align: center; +} + +.label { + display: flex; + flex-direction: row; +} + +.buttonContainer { + display: flex; + flex-direction: row; + flex: 1; + align-items: center; +} + +button.button { + border-radius: 100%; + background-color: white; + color: black; + border: 1px solid rgb(176, 176, 176); + width: 1.2rem; + height: 1.2rem; + padding: .938rem; + text-align: center; + display: inline-flex; + font-size: 1rem; + flex-direction: column; + justify-content: center; + align-items: center; + text-decoration: none; +} + +button.button:hover { + cursor: pointer; + border-color: var(--primary); +} + +button.buttonDisable { + border-radius: 100%; + background-color: white; + color: rgb(235, 235, 235); + border: 1px solid rgb(235, 235, 235); + width: 1.2rem; + height: 1.2rem; + padding: .938rem; + text-align: center; + display: inline-flex; + font-size: 16px; + flex-direction: column; + justify-content: center; + align-items: center; + text-decoration: none; +} + +button.buttonDisable:hover { + cursor: not-allowed; +} + +.button { + border-radius: 100%; + background-color: white; + color: black; + border: 1px solid rgb(176, 176, 176); + width: 1.2rem; + height: 1.2rem; + padding: .938rem; + text-align: center; + display: inline-flex; + font-size: 1rem; + flex-direction: column; + justify-content: center; + align-items: center; + text-decoration: none; +} + +.subtitle { + margin-bottom: 10px; + font-weight: 400; + font-size: medium; +} + +.title { + margin: 0; + font-size: 18px; + font-weight: 500; + margin-top: 20px; + +} + +.priceModal { + position: fixed; + width: 30vw; + flex-direction: column; + position: fixed; + display: flex; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + padding: 30px; + padding-top: 10px; + background-color: #fff; + border-radius: 8px; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); + z-index: 2000; +} + +.priceModal .header { + padding-top: 0; + display: flex; + align-items: center; + justify-content: center; + position: relative; + /* Position to allow absolute positioning of CloseIcon */ + padding: 10px; + /* Add vertical padding */ + border-bottom: 1px solid #ccc; + /* Optional border for header separation */ +} + +.priceModal .header h4 { + font-size: 18px; + font-weight: bold; + margin: 0; + /* Remove default margin */ + text-align: center; +} + +.customCloseWrapper { + position: absolute; + left: 10px; + top: 50%; + transform: translateY(-50%); + cursor: pointer; + font-size: 20px; + display: flex; + align-items: center; + /* If the icon is not centered vertically */ + justify-content: center; +} + +.roomsSection { + border-bottom: 1px solid #e7e7e7; + /* Optional border for header separation */ + padding: 10px; +} + +.range { + border-bottom: 1px solid #e7e7e7; +} + +.buttonModal { + color: aliceblue; + max-height: 50px; + background-color: rgb(0, 0, 0); +} + +.clearAll:hover { + border: none; + background-color: rgb(236, 236, 236); +} + +h4 { + text-align: left; +} + +@media (max-width: 768px) { + .priceModal { + position: fixed; + width: 100vw; + + } + +} \ No newline at end of file diff --git a/src/components/priceRange/PriceRangeFilter.css b/src/components/priceRange/PriceRangeFilter.css index e349266f..c2578b28 100644 --- a/src/components/priceRange/PriceRangeFilter.css +++ b/src/components/priceRange/PriceRangeFilter.css @@ -1,12 +1,13 @@ .price-range-container { position: relative; - width: 30%; - padding: 20px; + padding: 10px; color: #fff; } h2 { margin-bottom: 10px; + font-size: larger; + font-weight: 500; text-align: left; color: black; } @@ -15,40 +16,50 @@ p { text-align: left; margin-bottom: 20px; color: black; + font-size: medium; + font-weight: 400; } /* slider */ .horizontal-slider { width: 100%; - height: 10px; + height: 80px; margin: 0; position: relative; z-index: 2; } .track { - height: 10px; + height: 2px; } -.thumb { - height: 20px; - width: 20px; - background-color: white; - border: 2px solid #ff5a5f; - border-radius: 50%; - cursor: grab; - position: absolute; - top: -5px; - z-index: 3; -} + .thumb { + top: -15px; + cursor: grab; + border-radius: 100%; + background-color: white; + color: black; + border: 1px solid lightgrey; + width: 2rem; + height: 2rem; + padding: .938rem; + text-align: center; + display: inline-flex; + flex-direction: column; + justify-content: center; + align-items: center; + text-decoration: none; + box-shadow: 1px 5px 22px rgba(0, 0, 0, 0.1); + } + /* Histogram styling */ .histogram { display: flex; justify-content: space-between; align-items: flex-end; - height: 150px; - margin: 0 15px; /* Pull histogram up to remove space with slider */ + height: 100px; + margin: 0 125px; /* Pull histogram up to remove space with slider */ position: relative; z-index: 1; } @@ -57,28 +68,24 @@ p { display: flex; flex-direction: column-reverse; text-align: center; - width: 100%; - height: 100%; - margin: o 1px; } .histogram-bar { - background-color: red; - width: 100%; - max-width: 20px; - margin: 0 auto; + background-color: rgb(196, 0, 91); + max-width: 6px; } .histogram-label { margin-top: 5px; - font-size: 12px; + font-size: 5px; } /* inputs */ .price-inputs-container { display: flex; justify-content: space-between; - margin-top: 10px; + margin-top: -30px; + margin-bottom: 40px; width: 100%; } @@ -98,16 +105,10 @@ p { color: black; width: 100px; outline: none; - box-shadow: 0 1px 5px rgba(0, 0, 0, 0.1); } .price-input label { margin-bottom: 5px; font-size: 14px; color: #666; -} - -.price-input input:focus { - border-color: #ff5a5f; - box-shadow: 0 2px 8px rgba(255, 90, 95, 0.3); -} +} \ No newline at end of file diff --git a/src/components/priceRange/PriceRangeFilter.jsx b/src/components/priceRange/PriceRangeFilter.jsx index c8975b57..e1504420 100644 --- a/src/components/priceRange/PriceRangeFilter.jsx +++ b/src/components/priceRange/PriceRangeFilter.jsx @@ -2,75 +2,86 @@ import React, { useState } from "react"; import ReactSlider from "react-slider"; import "./PriceRangeFilter.css"; -const PriceRangeFilter = ({ histogramData }) => { - const [minPrice, setMinPrice] = useState(9); - const [maxPrice, setMaxPrice] = useState(310); - const [sliderValues, setSliderValues] = useState([minPrice, maxPrice]); +const PriceRangeFilter = () => { + const [sliderValues, setSliderValues] = useState([134, 340]); + + // Mock histogram data + const histogramData = [ + { from: 50, to: 62.5, count: 2 }, + { from: 62.5, to: 75, count: 1 }, + { from: 75, to: 87.5, count: 2 }, + { from: 87.5, to: 100, count: 3 }, + { from: 100, to: 112.5, count: 3 }, + { from: 112.5, to: 125, count: 2 }, + { from: 125, to: 137.5, count: 3 }, + { from: 137.5, to: 150, count: 2 }, + { from: 150, to: 162.5, count: 5 }, + { from: 162.5, to: 175, count: 5 }, + { from: 175, to: 187.5, count: 5 }, + { from: 187.5, to: 200, count: 5 }, + { from: 200, to: 212.5, count: 4 }, + { from: 212.5, to: 225, count: 4 }, + { from: 225, to: 237.5, count: 3 }, + { from: 237.5, to: 250, count: 4 }, + { from: 250, to: 262.5, count: 3 }, + { from: 262.5, to: 275, count: 2 }, + { from: 275, to: 287.5, count: 2 }, + { from: 287.5, to: 300, count: 3 }, + { from: 300, to: 312.5, count: 2 }, + { from: 312.5, to: 325, count: 1 }, + ]; + const handleSliderChange = (values) => { setSliderValues(values); - setMinPrice(values[0]); - setMaxPrice(values[1]); - }; - - const handleMinPriceChange = (e) => { - const value = parseInt(e.target.value, 10); - if (value < maxPrice && value >= 9) { - setMinPrice(value); - setSliderValues([value, sliderValues[1]]); - } }; - const handleMaxPriceChange = (e) => { - const value = parseInt(e.target.value, 10); - if (value > minPrice && value <= 310) { - setMaxPrice(value); - setSliderValues([sliderValues[0], value]); - } - }; - - const [minValue, maxValue] = sliderValues; - return (
+ {/* Header */}

Price range

Nightly prices including fees and taxes

+ {/* Histogram */}
{histogramData.map((bin, index) => { - const isInRange = bin.from >= minValue && bin.to <= maxValue; - const barColor = isInRange ? "red" : "gray"; + const isInRange = bin.from >= sliderValues[0] && bin.to <= sliderValues[1]; + const barColor = isInRange ? "rgb(255, 19, 129)" : "lightgray"; - return( -
-
- {/*{`${bin.from}-${bin.to}`}*/} -
+ return ( +
+
+ {`${bin.from}-${bin.to}`} +
); })}
+ {/* Slider */} { - const [minValue, maxValue] = state.value; + const trackColor = + props.key === "track-0" + ? "lightgray" + : props.key === "track-1" + ? "rgb(255, 19, 129)" + : "lightgray"; - let trackColor = props.key === "track-0" ? "gray" : props.key === "track-1" ? "red" : "gray"; - return (
{ ); }} /> - - + {/* Inputs */}