client,server folders

This commit is contained in:
2024-06-14 13:54:55 +05:00
parent e67512bd6d
commit 158f081b5f
649 changed files with 228 additions and 162 deletions
@@ -0,0 +1,64 @@
import { useNavigate } from "react-router-dom";
import { ILayoutCard } from "../../types/layoutCard";
import { formatNumber } from "../../calc/formatNumber";
interface LayoutCardProps {
layoutCard: ILayoutCard;
}
const LayoutCard = ({ layoutCard }: LayoutCardProps) => {
const {
floorEnd,
floorStart,
apartmentType,
roveHome,
wing,
units,
square,
cost,
id,
} = layoutCard;
const navigate = useNavigate();
const handleOnClick = () => {
navigate(`${id}`);
};
return (
<div
className="bg-white flex flex-col p-4 rounded-2xl gap-4 cursor-pointer select-none"
onClick={handleOnClick}
>
<div className="flex gap-4 justify-between">
<div className="flex gap-1 flex-col">
<p className="text-[#00BED7] text-s leading-5">
Rove Home {roveHome}
</p>
<div className="text-[#73787C] flex gap-2 items-center w-fit">
<p className="text-caption-m font-semibold leading-4">{wing}</p>
<div className="w-1 h-1 bg-[#E2E2DC] rounded-full"></div>
<p className="text-caption-m font-semibold leading-4">
Floor {floorStart}-{floorEnd}
</p>
</div>
</div>
<div className="bg-[#00BED7] text-white text-caption-m font-semibold rounded-full py-[3px] px-2 self-start text-nowrap">
{units} units
</div>
</div>
<div className="w-full aspect-square rounded-lg">
<img src="/images/layout-1.png" alt="" className="h-full" />
</div>
<div className="flex flex-col">
<p className="text[#0D1922] text-s">
{apartmentType}, {square} Sqft
</p>
<p className="text-[#00BED7] text-m font-bold">
AED {formatNumber(cost, ",", 3, 1)}
</p>
</div>
</div>
);
};
export default LayoutCard;
@@ -0,0 +1,78 @@
import { useEffect, useState } from "react";
import LayoutCard from "./LayoutCard";
import SortButton from "./SortButton";
import useSearchFilters from "../../store/useSearchFilters";
import { initialSortList, layoutsCards } from "../../consts/initialSearchPage";
import SearchIcon from "../icons/SearchIcon";
import { sortCardBy } from "../../calc/sortCard";
import Button from "../Button";
import FilterIcon from "../icons/FilterIcon";
import useModal from "../../store/useModal";
import { MobileModalWrapper } from "../modals/mobile/MobileModalWrapper";
import SearchFiltersModal from "../modals/mobile/SearchFiltersModal";
const LayoutOptions = () => {
const [sortList, setSortList] = useState(initialSortList);
const [cards, setCards] = useState(layoutsCards);
const { setModal } = useModal();
const { roveHomeTypeCheckboxes, apartmentTypeCheckboxes, multirangeSliders } =
useSearchFilters();
const handleOnSortClick = (sortId: string) => {
const updatedSortList = sortList.map((sort) => {
const isSelected = sort.id === sortId;
return { ...sort, isSelected: isSelected };
});
setSortList(updatedSortList);
};
const handleOnFilterClick = () => {
setModal(
<MobileModalWrapper>
<SearchFiltersModal />
</MobileModalWrapper>
);
};
useEffect(() => {
const sortedCards = sortCardBy(sortList, layoutsCards);
setCards(sortedCards);
}, [
sortList,
roveHomeTypeCheckboxes,
apartmentTypeCheckboxes,
multirangeSliders,
]);
return (
<section className="w-full p-6 flex flex-col">
<div className="flex justify-between items-center border-b">
<div className="flex w-full justify-between pb-4 lg:flex-row lg:items-center flex-col">
<div className="flex gap-4 font-semibold text-subheadline-s leading-7 py-[6px]">
<h2 className="text-[#0D1922]">Units</h2>
<p className="text-[#73787C]">145</p>
</div>
<SortButton sortList={sortList} onClick={handleOnSortClick} />
</div>
<div className="lg:hidden block">
<Button
icon={<FilterIcon />}
text="Filters"
className="text-[#0D1922B2]"
onClick={handleOnFilterClick}
/>
</div>
</div>
<div className="grid 2xl:grid-cols-4 xl:grid-cols-3 grid-cols-2 gap-4 pt-6">
{cards.map((layoutsCard) => (
<LayoutCard layoutCard={layoutsCard} />
))}
</div>
<div className="bg-white rounded-lg mt-4 py-[10px] flex justify-center select-none cursor-pointer items-center gap-2">
<SearchIcon /> Show 12 more apartments
</div>
</section>
);
};
export default LayoutOptions;
@@ -0,0 +1,176 @@
import Button from "../Button";
import ResetIcon from "../icons/ResetIcon";
import Checkbox from "../Checkbox";
import Switch from "../Switch";
import MultiRangeSlider from "../MultiRangeSlider";
import {
initialApartmentTypeCheckboxes,
initialSliders,
initialSwitchers,
initialRoveHomeCheckboxes,
} from "../../consts/initialSearchFilters";
import useSearchFilters from "../../store/useSearchFilters";
import { initialViewCheckboxes } from "../../consts/initialMasterplanFilters";
import { useState } from "react";
import { ICheckbox } from "../../types/checkbox";
const SidebarFilters = () => {
const {
multirangeSliders,
setMultirangeSliders,
switchers,
setSwitchers,
apartmentTypeCheckboxes,
setApartmentTypeCheckboxes,
roveHomeTypeCheckboxes,
setRoveHomeTypeCheckboxes,
} = useSearchFilters();
const [viewCheckboxes, setViewCheckboxes] = useState<ICheckbox[]>(
initialViewCheckboxes
);
const handleOnCheckboxApartmentClick = (checkboxId: string) => {
const updatedCheckboxes = apartmentTypeCheckboxes.map((cbox) => {
if (checkboxId !== cbox.id) return cbox;
const isSelected = !cbox.selected;
return { ...cbox, selected: isSelected };
});
setApartmentTypeCheckboxes(updatedCheckboxes);
};
const handleOnCheckboxRoveHomeClick = (checkboxId: string) => {
const updatedCheckboxes = roveHomeTypeCheckboxes.map((cbox) => {
if (checkboxId !== cbox.id) return cbox;
const isSelected = !cbox.selected;
return { ...cbox, selected: isSelected };
});
setRoveHomeTypeCheckboxes(updatedCheckboxes);
};
const handleOnSliderValueChange = (
sliderId: string,
e: [a: number, b: number]
) => {
const updatedSliders = multirangeSliders.map((slider) => {
if (sliderId !== slider.id) return slider;
return { ...slider, startValue: e[0], endValue: e[1] };
});
setMultirangeSliders(updatedSliders);
};
const handleOnSwitcherClick = (switcherId: string) => {
const updatedSwitchers = switchers.map((switcher) => {
if (switcherId !== switcher.id) return switcher;
const { isSwitched } = switcher;
return { ...switcher, isSwitched: !isSwitched };
});
setSwitchers(updatedSwitchers);
};
const handleOnViewCheckboxClick = (checkboxId: string) => {
const updatedCheckboxes = viewCheckboxes.map((cbox) => {
if (checkboxId !== cbox.id) return cbox;
const isSelected = !cbox.selected;
return { ...cbox, selected: isSelected };
});
setViewCheckboxes(updatedCheckboxes);
};
const handleOnResetClick = () => {
setViewCheckboxes(initialViewCheckboxes);
setApartmentTypeCheckboxes(initialApartmentTypeCheckboxes);
setRoveHomeTypeCheckboxes(initialRoveHomeCheckboxes);
setMultirangeSliders(initialSliders);
setSwitchers(initialSwitchers);
};
return (
<div>
<div className="h-full w-[360px] bg-[#F3F3F2] flex-col items-center justify-between border-r lg:flex hidden">
<div className="w-full py-6 px-6 flex flex-col items-center">
<div className="flex justify-between border-b border-[#E2E2DC] w-full pb-4">
<h2 className="text-subheadline-m font-semibold">Filters</h2>
<Button
isCircleRounded
icon={<ResetIcon />}
buttonType="fab"
onClick={handleOnResetClick}
/>
</div>
<div className="flex flex-col pt-6 w-full">
<p className="text-[#0D1922] text-s pb-4">Rove Home</p>
<div className="flex flex-col gap-2">
{roveHomeTypeCheckboxes.map((checkbox) => (
<Checkbox
checkbox={checkbox}
key={checkbox.id}
onClick={handleOnCheckboxRoveHomeClick}
/>
))}
</div>
</div>
<div className="flex flex-col pt-6 w-full">
<p className="text-[#0D1922] text-s pb-4">Apartment type</p>
<div className="flex flex-col gap-2">
{apartmentTypeCheckboxes.map((checkbox) => (
<Checkbox
checkbox={checkbox}
key={checkbox.id}
onClick={handleOnCheckboxApartmentClick}
/>
))}
</div>
</div>
<div className="flex flex-col pt-6 w-full gap-8">
{multirangeSliders.map((slider) => (
<div className="flex flex-col gap-2">
<div className="flex justify-between items-center">
<p className="text-[#0D1922] text-s ">{slider.title}</p>
<p className="text-[#73787C] text-s">{slider.unit}</p>
</div>
<MultiRangeSlider
onChange={handleOnSliderValueChange}
multirangeSlider={slider}
/>
</div>
))}
<div className="flex flex-col gap-2">
{switchers.map((switcher) => (
<div key={switcher.id} className="flex justify-between w-full">
<p className="text-s text-[#73787C]">{switcher.title}</p>
<Switch switcher={switcher} onClick={handleOnSwitcherClick} />
</div>
))}
</div>
<div className="flex flex-col w-full">
<p className="text-[#0D1922] text-s pb-4">Views</p>
<div className="flex flex-col gap-2">
{viewCheckboxes.map((checkbox) => (
<Checkbox
checkbox={checkbox}
key={checkbox.id}
onClick={handleOnViewCheckboxClick}
/>
))}
</div>
</div>
</div>
</div>
</div>
</div>
);
};
export default SidebarFilters;
@@ -0,0 +1,60 @@
import { useState } from "react";
import { ISort } from "../../types/sortType";
import CheckIcon from "../icons/CheckIcon";
import ChevronDownIcon from "../icons/ChevronDownIcon";
interface SortButtonProps {
sortList: ISort[];
onClick: (id: string) => void;
}
const SortButton = ({ sortList, onClick }: SortButtonProps) => {
const [isSelected, setIsSelected] = useState(false);
const handleOnClick = () => {
setIsSelected((prev) => !prev);
};
return (
<div className="relative">
<button
className="text-[#00BED7] text-m leading-5 flex gap-2 items-center"
onClick={handleOnClick}
>
Sort by{" "}
<div>
{sortList.find((sort) => sort.isSelected)?.title.toLocaleLowerCase()}{" "}
</div>
<div
className={`transition-all duration-300 ease-in-out ${
isSelected ? "rotate-180" : "rotate-0"
}`}
>
<ChevronDownIcon />
</div>
</button>
<div
className={`absolute z-20 flex flex-col bg-white p-2 text-[#0D1922] rounded-lg w-full shadow-lg transition-opacity duration-300 ease-in-out ${
isSelected ? "opacity-100" : "opacity-0"
}`}
>
{sortList.map((sort) => (
<button
onClick={() => onClick(sort.id)}
key={sort.id}
className="hover:bg-[#F3F3F2] py-2 pl-3 rounded-lg transition-all duration-300 ease-in-out text-left flex items-center gap-2"
>
{sort.isSelected && (
<div className="text-[#00BED7]">
<CheckIcon />
</div>
)}
{sort.title}
</button>
))}
</div>
</div>
);
};
export default SortButton;