feat: add dist files and correct build errors
This commit is contained in:
@@ -6,7 +6,6 @@ import SearchIcon from "./icons/SearchIcon";
|
||||
import ReactTestUtils from "react-dom/test-utils";
|
||||
import { isNotInViewport, sleep } from "@/utils/utils";
|
||||
import { useForm } from "react-hook-form";
|
||||
import CustomLocationAutoCompleteV2 from "../CustomLocationAutoCompleteV2";
|
||||
import CustomComboBox from "../CustomComboBox";
|
||||
import { GlobalContext } from "@/globalContext";
|
||||
import { MagnifyingGlassIcon } from "@heroicons/react/24/solid";
|
||||
@@ -16,15 +15,17 @@ const StaticSearchBar = ({ className }) => {
|
||||
const navigate = useNavigate();
|
||||
const inSearchPage = useMatch("/search");
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
const [showStaticBar, setShowStaticBar] = useState(isNotInViewport("search-bar"));
|
||||
const [showStaticBar, setShowStaticBar] = useState(
|
||||
isNotInViewport("search-bar")
|
||||
);
|
||||
const { pathname } = useLocation();
|
||||
const { state: globalState, dispatch } = useContext(GlobalContext);
|
||||
|
||||
|
||||
|
||||
const categories = globalState.spaceCategories;
|
||||
|
||||
const { handleSubmit, control, setValue } = useForm({ defaultValues: { category: "", location: globalState.location } });
|
||||
const { handleSubmit, control, setValue } = useForm({
|
||||
defaultValues: { category: "", location: globalState.location },
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
const onScroll = () => {
|
||||
@@ -67,49 +68,53 @@ const StaticSearchBar = ({ className }) => {
|
||||
return (
|
||||
<div className={className}>
|
||||
<form
|
||||
className="my-shadow2 flex w-full max-w-xl items-center rounded-lg rounded-r-pill border bg-white pl-1 md:rounded-r-lg md:pl-4 xl:ml-16 xl:max-w-3xl"
|
||||
className='my-shadow2 flex w-full max-w-xl items-center rounded-lg rounded-r-pill border bg-white pl-1 md:rounded-r-lg md:pl-4 xl:ml-16 xl:max-w-3xl'
|
||||
onSubmit={handleSubmit(onSubmit)}
|
||||
autoComplete="off"
|
||||
id="top-header-search-bar"
|
||||
autoComplete='off'
|
||||
id='top-header-search-bar'
|
||||
>
|
||||
<CustomComboBox
|
||||
control={control}
|
||||
name="category"
|
||||
labelField="category"
|
||||
valueField="category"
|
||||
name='category'
|
||||
labelField='category'
|
||||
valueField='category'
|
||||
setValue={(val) => setValue("category", val)}
|
||||
items={categories}
|
||||
containerClassName="relative hidden h-[40px] items-center md:flex md:w-[500px]"
|
||||
className="w-full truncate border-0 text-black focus:outline-none"
|
||||
placeholder="Search by category"
|
||||
containerClassName='relative hidden h-[40px] items-center md:flex md:w-[500px]'
|
||||
className='w-full truncate border-0 text-black focus:outline-none'
|
||||
placeholder='Search by category'
|
||||
/>
|
||||
|
||||
<CustomStaticLocationAutoCompleteV2
|
||||
containerClassName={"flex h-[40px] w-full items-center gap-2 rounded-t-md bg-white px-2 pr-1 md:h-[unset] lg:max-w-[331px] lg:rounded-none lg:py-0"}
|
||||
placeholder="Search by city or zip code"
|
||||
className="border-0 focus:outline-none"
|
||||
containerClassName={
|
||||
"flex h-[40px] w-full items-center gap-2 rounded-t-md bg-white px-2 pr-1 md:h-[unset] lg:max-w-[331px] lg:rounded-none lg:py-0"
|
||||
}
|
||||
placeholder='Search by city or zip code'
|
||||
className='border-0 focus:outline-none'
|
||||
// control={control}
|
||||
// name="location"
|
||||
type="static"
|
||||
setValue={(val) => dispatch({
|
||||
type: "SETLOCATION",
|
||||
payload: {
|
||||
location:val
|
||||
},
|
||||
})}
|
||||
type='static'
|
||||
setValue={(val) =>
|
||||
dispatch({
|
||||
type: "SETLOCATION",
|
||||
payload: {
|
||||
location: val,
|
||||
},
|
||||
})
|
||||
}
|
||||
suggestionType={["(regions)"]}
|
||||
/>
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
className="login-btn-gradient hidden w-1/2 items-center justify-center gap-2 rounded-md rounded-tl-none rounded-bl-none py-3 tracking-wide text-white outline-none focus:outline-none md:flex md:w-[unset] md:px-4 lg:w-[unset]"
|
||||
type='submit'
|
||||
className='login-btn-gradient hidden w-1/2 items-center justify-center gap-2 rounded-md rounded-bl-none rounded-tl-none py-3 tracking-wide text-white outline-none focus:outline-none md:flex md:w-[unset] md:px-4 lg:w-[unset]'
|
||||
>
|
||||
<SearchIcon className="md:w-[50px]" />
|
||||
<span className="hidden md:inline">Search</span>
|
||||
<SearchIcon className='md:w-[50px]' />
|
||||
<span className='hidden md:inline'>Search</span>
|
||||
</button>
|
||||
<button className="login-btn-gradient flex h-10 w-11 items-center justify-center rounded-circle md:hidden">
|
||||
<button className='login-btn-gradient flex h-10 w-11 items-center justify-center rounded-circle md:hidden'>
|
||||
{" "}
|
||||
<MagnifyingGlassIcon className="h-5 w-5 font-semibold text-white" />
|
||||
<MagnifyingGlassIcon className='h-5 w-5 font-semibold text-white' />
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
+288
-167
@@ -1,5 +1,11 @@
|
||||
import React, { useContext, useEffect, useState } from "react";
|
||||
import { createSearchParams, Link, useLocation, useNavigate, useSearchParams } from "react-router-dom";
|
||||
import {
|
||||
createSearchParams,
|
||||
Link,
|
||||
useLocation,
|
||||
useNavigate,
|
||||
useSearchParams,
|
||||
} from "react-router-dom";
|
||||
|
||||
import PropertySpaceCard from "@/components/frontend/PropertySpaceCard";
|
||||
import { callCustomAPI } from "@/utils/callCustomAPI";
|
||||
@@ -16,26 +22,29 @@ import { AuthContext, tokenExpireError } from "@/authContext";
|
||||
import useUserCurrentLocation from "@/hooks/api/useUserCurrentLocation";
|
||||
import { DRAFT_STATUS } from "@/utils/constants";
|
||||
import { useForm } from "react-hook-form";
|
||||
import CustomLocationAutoCompleteV2 from "@/components/CustomLocationAutoCompleteV2";
|
||||
// import CustomLocationAutoCompleteV2 from "@/components/CustomLocationAutoCompleteV2";
|
||||
import DatePickerV3 from "@/components/DatePickerV3";
|
||||
import CustomSelectV2 from "@/components/CustomSelectV2";
|
||||
import MkdSDK from "@/utils/MkdSDK";
|
||||
import CustomStaticLocationAutoCompleteV2 from "@/components/CustomStaticLocationAutoCompleteV2 ";
|
||||
import CustomStaticLocationAutoCompleteV2 from "@/components/CustomStaticLocationAutoCompleteV2";
|
||||
|
||||
const sdk = new MkdSDK();
|
||||
const ctrl = new AbortController();
|
||||
|
||||
const HomePage = () => {
|
||||
const FETCH_PER_SCROLL = 12;
|
||||
const { dispatch: globalDispatch, state: globalState } = useContext(GlobalContext);
|
||||
const { dispatch: globalDispatch, state: globalState } =
|
||||
useContext(GlobalContext);
|
||||
const { state } = useContext(AuthContext);
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
const [activeTab, setActiveTab] = useState(searchParams.get("category") || "all");
|
||||
const [activeTab, setActiveTab] = useState(
|
||||
searchParams.get("category") || "all"
|
||||
);
|
||||
const [hosts, setHosts] = useState(Array(5).fill({}));
|
||||
const [popularSpaces, setPopularSpaces] = useState([]);
|
||||
const [newSpaces, setNewSpaces] = useState([]);
|
||||
const [forceRender, setForceRender] = useState("");
|
||||
const location = useLocation()
|
||||
const location = useLocation();
|
||||
const { state: authState, dispatch: authDispatch } = useContext(AuthContext);
|
||||
|
||||
const { dispatch } = useContext(AuthContext);
|
||||
@@ -43,17 +52,22 @@ const HomePage = () => {
|
||||
const [newTotal, setNewTotal] = useState(1000);
|
||||
const spaceCategories = globalState.spaceCategories;
|
||||
|
||||
const { handleSubmit, control, setValue, resetField, formState, register } = useForm({
|
||||
defaultValues: {
|
||||
booking_start_time: new Date(),
|
||||
location: globalState.location,
|
||||
size: "",
|
||||
},
|
||||
});
|
||||
const { handleSubmit, control, setValue, resetField, formState, register } =
|
||||
useForm({
|
||||
defaultValues: {
|
||||
booking_start_time: new Date(),
|
||||
location: globalState.location,
|
||||
size: "",
|
||||
},
|
||||
});
|
||||
|
||||
const { touchedFields } = formState;
|
||||
|
||||
const { city, country, done: currentLocationChecked } = useUserCurrentLocation();
|
||||
const {
|
||||
city,
|
||||
country,
|
||||
done: currentLocationChecked,
|
||||
} = useUserCurrentLocation();
|
||||
const [noCurrentLocationData, setNoCurrentLocationData] = useState(false);
|
||||
|
||||
const navigate = useNavigate();
|
||||
@@ -64,22 +78,47 @@ const HomePage = () => {
|
||||
// only add empty spaces if there's no empty card i.e we are not currently fetching
|
||||
if (popularSpaces.every((space) => Object.keys(space).length > 0)) {
|
||||
setPopularSpaces((prev) => {
|
||||
const amountToFetch = popularTotal - prev.length > FETCH_PER_SCROLL ? FETCH_PER_SCROLL : Math.abs(popularTotal - prev.length - FETCH_PER_SCROLL);
|
||||
const amountToFetch =
|
||||
popularTotal - prev.length > FETCH_PER_SCROLL
|
||||
? FETCH_PER_SCROLL
|
||||
: Math.abs(popularTotal - prev.length - FETCH_PER_SCROLL);
|
||||
return [...prev, ...Array(amountToFetch).fill({})];
|
||||
});
|
||||
}
|
||||
const user_id = localStorage.getItem("user");
|
||||
const where = [
|
||||
`${activeTab != "all" ? `ergo_spaces.category LIKE '%${activeTab}%'` : "1"} AND ergo_property_spaces.space_status = 1 AND ergo_property_spaces.draft_status = ${DRAFT_STATUS.COMPLETED
|
||||
} AND ergo_property_spaces_images.is_approved = 1 AND ergo_property_spaces.deleted_at IS NULL AND schedule_template_id IS NOT NULL AND (${city && !noCurrentLocationData ? `ergo_property.city LIKE '%${city}%'` : "1"} OR ${country && !noCurrentLocationData ? `ergo_property.country LIKE '%${country}%'` : "1"
|
||||
`${
|
||||
activeTab != "all" ? `ergo_spaces.category LIKE '%${activeTab}%'` : "1"
|
||||
} AND ergo_property_spaces.space_status = 1 AND ergo_property_spaces.draft_status = ${
|
||||
DRAFT_STATUS.COMPLETED
|
||||
} AND ergo_property_spaces_images.is_approved = 1 AND ergo_property_spaces.deleted_at IS NULL AND schedule_template_id IS NOT NULL AND (${
|
||||
city && !noCurrentLocationData
|
||||
? `ergo_property.city LIKE '%${city}%'`
|
||||
: "1"
|
||||
} OR ${
|
||||
country && !noCurrentLocationData
|
||||
? `ergo_property.country LIKE '%${country}%'`
|
||||
: "1"
|
||||
})`,
|
||||
];
|
||||
try {
|
||||
const result = await sdk.callRawAPI("/v2/api/custom/ergo/popular/PAGINATE", { page: page ?? 1, limit: FETCH_PER_SCROLL, user_id: Number(user_id), where }, "POST", ctrl.signal);
|
||||
const result = await sdk.callRawAPI(
|
||||
"/v2/api/custom/ergo/popular/PAGINATE",
|
||||
{
|
||||
page: page ?? 1,
|
||||
limit: FETCH_PER_SCROLL,
|
||||
user_id: Number(user_id),
|
||||
where,
|
||||
},
|
||||
"POST",
|
||||
ctrl.signal
|
||||
);
|
||||
if (Array.isArray(result.list)) {
|
||||
|
||||
setPopularSpaces((prev) => {
|
||||
return [...prev.filter((item) => Object.keys(item).length > 0), ...result.list].filter((v, i, a) => a.findIndex((v2) => v2.id === v.id) === i);
|
||||
return [
|
||||
...prev.filter((item) => Object.keys(item).length > 0),
|
||||
...result.list,
|
||||
].filter((v, i, a) => a.findIndex((v2) => v2.id === v.id) === i);
|
||||
});
|
||||
setPopularTotal(result.total);
|
||||
}
|
||||
@@ -99,27 +138,50 @@ const HomePage = () => {
|
||||
async function fetchNewSpaces(page) {
|
||||
if (newSpaces.every((space) => Object.keys(space).length > 0)) {
|
||||
setNewSpaces((prev) => {
|
||||
const amountToFetch = newTotal - prev.length > FETCH_PER_SCROLL ? FETCH_PER_SCROLL : Math.abs(newTotal - prev.length - FETCH_PER_SCROLL);
|
||||
const amountToFetch =
|
||||
newTotal - prev.length > FETCH_PER_SCROLL
|
||||
? FETCH_PER_SCROLL
|
||||
: Math.abs(newTotal - prev.length - FETCH_PER_SCROLL);
|
||||
return [...prev, ...Array(amountToFetch).fill({})];
|
||||
});
|
||||
}
|
||||
const user_id = localStorage.getItem("user");
|
||||
const where = [
|
||||
`${activeTab != "all" ? `ergo_spaces.category LIKE '%${activeTab}%'` : "1"} AND ergo_property_spaces.space_status = 1 AND ergo_property_spaces.draft_status = ${DRAFT_STATUS.COMPLETED
|
||||
} AND ergo_property_spaces_images.is_approved = 1 AND schedule_template_id IS NOT NULL AND ergo_property_spaces.deleted_at IS NULL AND (${city && !noCurrentLocationData ? `ergo_property.city LIKE '%${city}%'` : "1"} OR ${country && !noCurrentLocationData ? `ergo_property.country LIKE '%${country}%'` : "1"
|
||||
`${
|
||||
activeTab != "all" ? `ergo_spaces.category LIKE '%${activeTab}%'` : "1"
|
||||
} AND ergo_property_spaces.space_status = 1 AND ergo_property_spaces.draft_status = ${
|
||||
DRAFT_STATUS.COMPLETED
|
||||
} AND ergo_property_spaces_images.is_approved = 1 AND schedule_template_id IS NOT NULL AND ergo_property_spaces.deleted_at IS NULL AND (${
|
||||
city && !noCurrentLocationData
|
||||
? `ergo_property.city LIKE '%${city}%'`
|
||||
: "1"
|
||||
} OR ${
|
||||
country && !noCurrentLocationData
|
||||
? `ergo_property.country LIKE '%${country}%'`
|
||||
: "1"
|
||||
})`,
|
||||
];
|
||||
try {
|
||||
const result = await sdk.callRawAPI(
|
||||
"/v2/api/custom/ergo/popular/PAGINATE",
|
||||
{ page: page ?? 1, limit: 6, user_id: Number(user_id), where, sortId: "update_at", direction: "DESC" },
|
||||
{
|
||||
page: page ?? 1,
|
||||
limit: 6,
|
||||
user_id: Number(user_id),
|
||||
where,
|
||||
sortId: "update_at",
|
||||
direction: "DESC",
|
||||
},
|
||||
// { page: page ?? 1, limit: FETCH_PER_SCROLL, user_id: null, where, sortId: "update_at", direction: "DESC" },
|
||||
"POST",
|
||||
ctrl?.signal,
|
||||
ctrl?.signal
|
||||
);
|
||||
if (Array.isArray(result.list)) {
|
||||
setNewSpaces((prev) => {
|
||||
return [...prev.filter((item) => Object.keys(item).length > 0), ...result.list].filter((v, i, a) => a.findIndex((v2) => v2.id === v.id) === i);
|
||||
return [
|
||||
...prev.filter((item) => Object.keys(item).length > 0),
|
||||
...result.list,
|
||||
].filter((v, i, a) => a.findIndex((v2) => v2.id === v.id) === i);
|
||||
});
|
||||
setNewTotal(result.total);
|
||||
}
|
||||
@@ -146,12 +208,21 @@ const HomePage = () => {
|
||||
sortId: "avg_host_rating",
|
||||
direction: "DESC",
|
||||
where: [
|
||||
`${city && !noCurrentLocationData ? `ergo_profile.city LIKE '%${city}%'` : "1"} AND ${country && !noCurrentLocationData ? `ergo_profile.country LIKE '%${country}%'` : "1"}`,
|
||||
"ergo_user.deleted_at IS NULL", "ergo_property.id IS NOT NULL",
|
||||
`${
|
||||
city && !noCurrentLocationData
|
||||
? `ergo_profile.city LIKE '%${city}%'`
|
||||
: "1"
|
||||
} AND ${
|
||||
country && !noCurrentLocationData
|
||||
? `ergo_profile.country LIKE '%${country}%'`
|
||||
: "1"
|
||||
}`,
|
||||
"ergo_user.deleted_at IS NULL",
|
||||
"ergo_property.id IS NOT NULL",
|
||||
],
|
||||
},
|
||||
"POST",
|
||||
ctrl.signal,
|
||||
ctrl.signal
|
||||
);
|
||||
|
||||
setHosts(result.list);
|
||||
@@ -173,7 +244,9 @@ const HomePage = () => {
|
||||
pathname: "/search",
|
||||
search: createSearchParams({
|
||||
location: globalState.location ?? "",
|
||||
booking_start_time: touchedFields.booking_start_time ? data.booking_start_time.toISOString() : "",
|
||||
booking_start_time: touchedFields.booking_start_time
|
||||
? data.booking_start_time.toISOString()
|
||||
: "",
|
||||
max_capacity: data.max_capacity ?? "",
|
||||
capacity: data.capacity ?? "",
|
||||
size: data.size ?? "",
|
||||
@@ -182,25 +255,28 @@ const HomePage = () => {
|
||||
}
|
||||
|
||||
async function setDevice() {
|
||||
if (!localStorage.getItem("token") || localStorage.getItem("token") !== undefined) {
|
||||
if (
|
||||
!localStorage.getItem("token") ||
|
||||
localStorage.getItem("token") !== undefined
|
||||
) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await sdk.setUUId()
|
||||
await sdk.setUUId();
|
||||
} catch (error) {
|
||||
console.log(error.message)
|
||||
console.log(error.message);
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
let setter;
|
||||
if (!setter) {
|
||||
setDevice()
|
||||
setDevice();
|
||||
}
|
||||
return () => {
|
||||
setter = true
|
||||
}
|
||||
}, [])
|
||||
setter = true;
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (!currentLocationChecked) return;
|
||||
@@ -208,10 +284,14 @@ const HomePage = () => {
|
||||
globalDispatch({
|
||||
type: "SETLOCATION",
|
||||
payload: {
|
||||
location:(city ?? "") + (city && country ? ", " : "") + (country ?? "")
|
||||
location:
|
||||
(city ?? "") + (city && country ? ", " : "") + (country ?? ""),
|
||||
},
|
||||
})
|
||||
setValue("location", (city ?? "") + (city && country ? ", " : "") + (country ?? ""));
|
||||
});
|
||||
setValue(
|
||||
"location",
|
||||
(city ?? "") + (city && country ? ", " : "") + (country ?? "")
|
||||
);
|
||||
}
|
||||
fetchHosts();
|
||||
}, [currentLocationChecked, noCurrentLocationData]);
|
||||
@@ -243,7 +323,7 @@ const HomePage = () => {
|
||||
btn: "Ok got it",
|
||||
},
|
||||
});
|
||||
navigate("/signup")
|
||||
navigate("/signup");
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -251,15 +331,20 @@ const HomePage = () => {
|
||||
<section
|
||||
style={{
|
||||
height: 600,
|
||||
background: `url('${spaceCategories.find((cat) => activeTab == cat.category)?.image ?? "/jumbotron1.jpg"}'), linear-gradient(0deg, rgba(16, 24, 40, 0.79), rgba(16, 24, 40, 0.79))`,
|
||||
background: `url('${
|
||||
spaceCategories.find((cat) => activeTab == cat.category)?.image ??
|
||||
"/jumbotron1.jpg"
|
||||
}'), linear-gradient(0deg, rgba(16, 24, 40, 0.79), rgba(16, 24, 40, 0.79))`,
|
||||
}}
|
||||
className="my-background-image mb-6 pt-[70px] md:rounded-b-[3rem]"
|
||||
className='my-background-image mb-6 pt-[70px] md:rounded-b-[3rem]'
|
||||
>
|
||||
<nav className="mb-[60px] flex justify-center border-t border-b border-gray-500 text-sm text-gray-300 md:mb-[103px] md:text-base">
|
||||
<div className="horizontal-scroll-categories">
|
||||
<nav className='mb-[60px] flex justify-center border-b border-t border-gray-500 text-sm text-gray-300 md:mb-[103px] md:text-base'>
|
||||
<div className='horizontal-scroll-categories'>
|
||||
<button
|
||||
key={0}
|
||||
className={`${activeTab == "all" ? "active text-white" : ""} flex w-[105px] items-center justify-center whitespace-nowrap py-[12px]`}
|
||||
className={`${
|
||||
activeTab == "all" ? "active text-white" : ""
|
||||
} flex w-[105px] items-center justify-center whitespace-nowrap py-[12px]`}
|
||||
onClick={() => {
|
||||
setActiveTab("all");
|
||||
searchParams.set("category", "all");
|
||||
@@ -272,7 +357,9 @@ const HomePage = () => {
|
||||
return (
|
||||
<button
|
||||
key={tab.id}
|
||||
className={`${activeTab == tab.category ? "active text-white" : ""} flex w-[105px] items-center justify-center whitespace-nowrap py-[12px]`}
|
||||
className={`${
|
||||
activeTab == tab.category ? "active text-white" : ""
|
||||
} flex w-[105px] items-center justify-center whitespace-nowrap py-[12px]`}
|
||||
onClick={() => {
|
||||
setActiveTab(tab.category);
|
||||
searchParams.set("category", tab.category);
|
||||
@@ -285,52 +372,61 @@ const HomePage = () => {
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
<div className="mover"></div>
|
||||
<div className='mover'></div>
|
||||
</div>
|
||||
</nav>
|
||||
<h1 className="mb-[30px] px-4 text-center text-5xl font-bold text-white md:text-6xl lg:text-7xl">Spaces tailored to your needs</h1>
|
||||
<h1 className='mb-[30px] px-4 text-center text-5xl font-bold text-white md:text-6xl lg:text-7xl'>
|
||||
Spaces tailored to your needs
|
||||
</h1>
|
||||
<form
|
||||
className="fourteenth-step flex flex-wrap justify-center px-6 text-sm md:px-24 md:text-base lg:flex-nowrap"
|
||||
id="search-bar"
|
||||
className='fourteenth-step flex flex-wrap justify-center px-6 text-sm md:px-24 md:text-base lg:flex-nowrap'
|
||||
id='search-bar'
|
||||
onSubmit={handleSubmit(onSubmit)}
|
||||
autoComplete="off"
|
||||
autoComplete='off'
|
||||
>
|
||||
<CustomStaticLocationAutoCompleteV2
|
||||
setValue={(val) => globalDispatch({
|
||||
type: "SETLOCATION",
|
||||
payload: {
|
||||
location:val
|
||||
},
|
||||
})}
|
||||
type="static"
|
||||
containerClassName={"flex h-[40px] w-full items-center gap-2 rounded-t-md border-2 border-r-0 bg-white px-4 py-2 md:h-[unset] lg:max-w-[331px] lg:rounded-none lg:py-0"}
|
||||
className="border-0 focus:outline-none"
|
||||
placeholder="Search by city or zip code"
|
||||
setValue={(val) =>
|
||||
globalDispatch({
|
||||
type: "SETLOCATION",
|
||||
payload: {
|
||||
location: val,
|
||||
},
|
||||
})
|
||||
}
|
||||
type='static'
|
||||
containerClassName={
|
||||
"flex h-[40px] w-full items-center gap-2 rounded-t-md border-2 border-r-0 bg-white px-4 py-2 md:h-[unset] lg:max-w-[331px] lg:rounded-none lg:py-0"
|
||||
}
|
||||
className='border-0 focus:outline-none'
|
||||
placeholder='Search by city or zip code'
|
||||
onClear={() => setNoCurrentLocationData(true)}
|
||||
suggestionType={["(regions)"]}
|
||||
/>
|
||||
<div className="flex min-h-[40px] w-1/2 items-center gap-2 rounded-bl-md border-l-2 bg-white px-2 lg:min-w-[230px] lg:max-w-[230px] lg:rounded-none">
|
||||
<div className='flex min-h-[40px] w-1/2 items-center gap-2 rounded-bl-md border-l-2 bg-white px-2 lg:min-w-[230px] lg:max-w-[230px] lg:rounded-none'>
|
||||
<DatePickerV3
|
||||
reset={() => resetField("booking_start_time")}
|
||||
setValue={(val) => setValue("booking_start_time", val)}
|
||||
control={control}
|
||||
name="booking_start_time"
|
||||
labelClassName="justify-between flex-grow flex-row-reverse"
|
||||
placeholder="Select Date"
|
||||
name='booking_start_time'
|
||||
labelClassName='justify-between flex-grow flex-row-reverse'
|
||||
placeholder='Select Date'
|
||||
min={new Date()}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex w-1/2 items-center gap-2 rounded-br-md border-l bg-white px-2 lg:max-w-[174px] lg:rounded-none lg:border-2">
|
||||
<div className='flex w-1/2 items-center gap-2 rounded-br-md border-l bg-white px-2 lg:max-w-[174px] lg:rounded-none lg:border-2'>
|
||||
<PeopleIcon />
|
||||
<input
|
||||
type="number"
|
||||
placeholder={activeTab == "Parking" ? "Number of spaces" : "2 People"}
|
||||
className="remove-arrow w-full focus:outline-none"
|
||||
type='number'
|
||||
placeholder={
|
||||
activeTab == "Parking" ? "Number of spaces" : "2 People"
|
||||
}
|
||||
className='remove-arrow w-full focus:outline-none'
|
||||
{...register("max_capacity")}
|
||||
/>
|
||||
</div>
|
||||
{spaceCategories.find((cat) => activeTab == cat.category)?.has_sizes == 1 && (
|
||||
<div className="flex w-1/2 items-center gap-2 rounded-br-md !border-l-0 bg-white px-2 lg:max-w-[174px] lg:rounded-none lg:border-2">
|
||||
{spaceCategories.find((cat) => activeTab == cat.category)
|
||||
?.has_sizes == 1 && (
|
||||
<div className='flex w-1/2 items-center gap-2 rounded-br-md !border-l-0 bg-white px-2 lg:max-w-[174px] lg:rounded-none lg:border-2'>
|
||||
<CustomSelectV2
|
||||
items={[
|
||||
{ label: "All Sizes", value: "" },
|
||||
@@ -339,21 +435,23 @@ const HomePage = () => {
|
||||
{ label: "Large", value: 2 },
|
||||
{ label: "X-Large", value: 3 },
|
||||
]}
|
||||
labelField="label"
|
||||
valueField="value"
|
||||
containerClassName="h-full flex-grow"
|
||||
labelField='label'
|
||||
valueField='value'
|
||||
containerClassName='h-full flex-grow'
|
||||
placeholder={"All sizes"}
|
||||
control={control}
|
||||
name="size"
|
||||
optionsClassName={"mt-3 w-[150%] -left-1/3 -right-1/3 normal-case"}
|
||||
name='size'
|
||||
optionsClassName={
|
||||
"mt-3 w-[150%] -left-1/3 -right-1/3 normal-case"
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
className="login-btn-gradient login-btn-gradient mt-4 flex w-full items-center justify-center gap-2 rounded-tr rounded-br rounded-tl rounded-bl py-3 px-6 tracking-wide text-white outline-none focus:outline-none lg:mt-0 lg:w-[unset] lg:rounded-tl-none lg:rounded-bl-none"
|
||||
id="search-button"
|
||||
type='submit'
|
||||
className='login-btn-gradient login-btn-gradient mt-4 flex w-full items-center justify-center gap-2 rounded-bl rounded-br rounded-tl rounded-tr px-6 py-3 tracking-wide text-white outline-none focus:outline-none lg:mt-0 lg:w-[unset] lg:rounded-bl-none lg:rounded-tl-none'
|
||||
id='search-button'
|
||||
>
|
||||
<SearchIcon />
|
||||
<span>Search</span>
|
||||
@@ -361,44 +459,54 @@ const HomePage = () => {
|
||||
</form>
|
||||
</section>
|
||||
|
||||
<div className="mb-[48px] w-full">
|
||||
<h2 className="mb-[5px] px-4 text-center text-3xl font-bold normal-case md:text-4xl">Top-quality spaces and customer service</h2>
|
||||
<h5 className="mb-[8px] px-4 text-center text-md font-normal normal-case md:text-2xl">Your number one stop for renting and offering space(s) for work and leisure</h5>
|
||||
<div className="mt-10 flex justify-center mx-auto max-w-max">
|
||||
<div className="grid grid-cols-2 md:grid-cols-4 w-full items-center justify-even gap-[15px] text-xl text-gray-300 w-full">
|
||||
{spaceCategories.map((cat, idx) => (
|
||||
<div key={cat.id} className="w-full block">
|
||||
<span className="flex items-center gap-2 rounded-full py-1 text-black">
|
||||
<img src= {cat.icon} className="w-5 h-5 object-cover"/>
|
||||
{cat.category}
|
||||
</span>
|
||||
<div className='mb-[48px] w-full'>
|
||||
<h2 className='mb-[5px] px-4 text-center text-3xl font-bold normal-case md:text-4xl'>
|
||||
Top-quality spaces and customer service
|
||||
</h2>
|
||||
<h5 className='text-md mb-[8px] px-4 text-center font-normal normal-case md:text-2xl'>
|
||||
Your number one stop for renting and offering space(s) for work and
|
||||
leisure
|
||||
</h5>
|
||||
<div className='mx-auto mt-10 flex max-w-max justify-center'>
|
||||
<div className='justify-even grid w-full w-full grid-cols-2 items-center gap-[15px] text-xl text-gray-300 md:grid-cols-4'>
|
||||
{spaceCategories.map((cat, idx) => (
|
||||
<div key={cat.id} className='block w-full'>
|
||||
<span className='flex items-center gap-2 rounded-full py-1 text-black'>
|
||||
<img src={cat.icon} className='h-5 w-5 object-cover' />
|
||||
{cat.category}
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<section className="container mx-auto pt-[40px] 2xl:px-16 px-6">
|
||||
<div className="mb-[26px] flex items-center justify-between border-b border-gray-300 px-6 pb-[12px] md:px-0">
|
||||
<h3 className="text-3xl font-bold">Popular</h3>
|
||||
<section className='container mx-auto px-6 pt-[40px] 2xl:px-16'>
|
||||
<div className='mb-[26px] flex items-center justify-between border-b border-gray-300 px-6 pb-[12px] md:px-0'>
|
||||
<h3 className='text-3xl font-bold'>Popular</h3>
|
||||
<Link
|
||||
to={`/explore?section=popular`}
|
||||
className="my-text-gradient text-sm font-semibold tracking-wider"
|
||||
id="view-all-popular"
|
||||
className='my-text-gradient text-sm font-semibold tracking-wider'
|
||||
id='view-all-popular'
|
||||
>
|
||||
VIEW ALL POPULAR
|
||||
</Link>
|
||||
</div>
|
||||
{popularSpaces.length < 1 && (
|
||||
<p className="flex min-h-[400px] items-center justify-center text-center normal-case">
|
||||
<p className='flex min-h-[400px] items-center justify-center text-center normal-case'>
|
||||
<b>No Spaces found</b>
|
||||
</p>
|
||||
)}
|
||||
<InfiniteScroll
|
||||
dataLength={popularSpaces.length}
|
||||
next={() => {
|
||||
console.log("calling next", popularSpaces.length / FETCH_PER_SCROLL + 1);
|
||||
fetchPopularSpaces(Math.round(popularSpaces.length / FETCH_PER_SCROLL + 1));
|
||||
console.log(
|
||||
"calling next",
|
||||
popularSpaces.length / FETCH_PER_SCROLL + 1
|
||||
);
|
||||
fetchPopularSpaces(
|
||||
Math.round(popularSpaces.length / FETCH_PER_SCROLL + 1)
|
||||
);
|
||||
}}
|
||||
scrollThreshold={0.5}
|
||||
hasMore={popularSpaces.length < popularTotal}
|
||||
@@ -406,7 +514,7 @@ const HomePage = () => {
|
||||
endMessage={<></>}
|
||||
>
|
||||
{
|
||||
<div className="property-space-grid pb-[100px]">
|
||||
<div className='property-space-grid pb-[100px]'>
|
||||
{popularSpaces.slice(0, 6).map((property, idx) => (
|
||||
<PropertySpaceCard
|
||||
key={property.id ?? idx}
|
||||
@@ -416,51 +524,55 @@ const HomePage = () => {
|
||||
))}
|
||||
{popularSpaces.length < 4 ? (
|
||||
<>
|
||||
<div className="hidden 2xl:block"></div>
|
||||
<div className="hidden lg:block"></div>
|
||||
<div className="hidden md:block"></div>
|
||||
<div className='hidden 2xl:block'></div>
|
||||
<div className='hidden lg:block'></div>
|
||||
<div className='hidden md:block'></div>
|
||||
</>
|
||||
) : null}
|
||||
</div>
|
||||
}
|
||||
</InfiniteScroll>
|
||||
</section>
|
||||
<section className="container mx-auto pb-[80px] normal-case md:pt-[40px] md:pb-[140px] 2xl:px-16 px-6">
|
||||
<div className="mb-[26px] flex items-center justify-between border-b border-gray-300 px-6 pb-[12px] md:px-0">
|
||||
<h3 className="text-3xl font-bold">Browse By Category</h3>
|
||||
<section className='container mx-auto px-6 pb-[80px] normal-case md:pb-[140px] md:pt-[40px] 2xl:px-16'>
|
||||
<div className='mb-[26px] flex items-center justify-between border-b border-gray-300 px-6 pb-[12px] md:px-0'>
|
||||
<h3 className='text-3xl font-bold'>Browse By Category</h3>
|
||||
<Link
|
||||
to={`/explore?category=§ion=popular&price_range=&space_name=&location=&from=&to=`}
|
||||
className="my-text-gradient text-sm font-semibold tracking-wider"
|
||||
id="view-all-popular"
|
||||
className='my-text-gradient text-sm font-semibold tracking-wider'
|
||||
id='view-all-popular'
|
||||
>
|
||||
VIEW ALL CATEGORIES
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<div className="md:browse-grid flex flex-wrap justify-between w-full gap-4">
|
||||
{spaceCategories.slice(0,spaceCategories.length-4).map((tab, idx) => (
|
||||
<Link
|
||||
key={tab.id}
|
||||
to={`/explore?category=${tab.category}§ion=popular`}
|
||||
className="rounded-[6px] border w-full flex grow flex-cols w-full md:max-w- border-[#EAECF0] bg-[#F9FAFB]"
|
||||
>
|
||||
<img
|
||||
src={tab.image}
|
||||
alt={tab.category}
|
||||
className="h-24 w-full rounded-lg object-cover md:h-40"
|
||||
/>
|
||||
<p className="text-lg w-full py-3 px-5 text-right font-semibold">{tab.category}</p>
|
||||
</Link>
|
||||
))}
|
||||
<div className='md:browse-grid flex w-full flex-wrap justify-between gap-4'>
|
||||
{spaceCategories
|
||||
.slice(0, spaceCategories.length - 4)
|
||||
.map((tab, idx) => (
|
||||
<Link
|
||||
key={tab.id}
|
||||
to={`/explore?category=${tab.category}§ion=popular`}
|
||||
className='flex-cols md:max-w- flex w-full w-full grow rounded-[6px] border border-[#EAECF0] bg-[#F9FAFB]'
|
||||
>
|
||||
<img
|
||||
src={tab.image}
|
||||
alt={tab.category}
|
||||
className='h-24 w-full rounded-lg object-cover md:h-40'
|
||||
/>
|
||||
<p className='text-lg w-full px-5 py-3 text-right font-semibold'>
|
||||
{tab.category}
|
||||
</p>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
<section className="container mx-auto py-[64px] 2xl:px-16 px-6">
|
||||
<div className="mb-[26px] flex items-center justify-between border-b border-gray-300 px-6 pb-[12px] md:px-0">
|
||||
<h3 className="text-2xl font-bold md:text-3xl">Top rated hosts</h3>
|
||||
<section className='container mx-auto px-6 py-[64px] 2xl:px-16'>
|
||||
<div className='mb-[26px] flex items-center justify-between border-b border-gray-300 px-6 pb-[12px] md:px-0'>
|
||||
<h3 className='text-2xl font-bold md:text-3xl'>Top rated hosts</h3>
|
||||
<Link
|
||||
to={`/explore?section=hosts`}
|
||||
className="my-text-gradient text-sm font-semibold tracking-wider md:text-base"
|
||||
id="view-all-hosts"
|
||||
className='my-text-gradient text-sm font-semibold tracking-wider md:text-base'
|
||||
id='view-all-hosts'
|
||||
>
|
||||
VIEW ALL HOSTS
|
||||
</Link>
|
||||
@@ -468,19 +580,19 @@ const HomePage = () => {
|
||||
<HostCardSlider hosts={hosts} />
|
||||
</section>
|
||||
|
||||
<section className="container mx-auto pt-[40px] 2xl:px-16 px-6">
|
||||
<div className="mb-[26px] flex items-center justify-between border-b border-gray-300 px-6 pb-[12px] md:px-0">
|
||||
<h3 className="text-2xl font-bold md:text-3xl">New Spaces</h3>
|
||||
<section className='container mx-auto px-6 pt-[40px] 2xl:px-16'>
|
||||
<div className='mb-[26px] flex items-center justify-between border-b border-gray-300 px-6 pb-[12px] md:px-0'>
|
||||
<h3 className='text-2xl font-bold md:text-3xl'>New Spaces</h3>
|
||||
<Link
|
||||
to={`/explore?section=new-spaces`}
|
||||
className="my-text-gradient text-sm font-semibold tracking-wider md:text-base"
|
||||
id="view-all-new-spaces"
|
||||
className='my-text-gradient text-sm font-semibold tracking-wider md:text-base'
|
||||
id='view-all-new-spaces'
|
||||
>
|
||||
VIEW ALL NEW SPACES
|
||||
</Link>
|
||||
</div>
|
||||
{newSpaces.length == 0 && (
|
||||
<p className="flex min-h-[400px] items-center justify-center text-center normal-case">
|
||||
<p className='flex min-h-[400px] items-center justify-center text-center normal-case'>
|
||||
<b>No Spaces found</b>
|
||||
</p>
|
||||
)}
|
||||
@@ -494,13 +606,13 @@ const HomePage = () => {
|
||||
hasMore={newSpaces.length < newTotal}
|
||||
loader={<></>}
|
||||
endMessage={
|
||||
<p className="text-center normal-case">
|
||||
<p className='text-center normal-case'>
|
||||
<b></b>
|
||||
</p>
|
||||
}
|
||||
>
|
||||
{
|
||||
<div className="property-space-grid pb-[100px]">
|
||||
<div className='property-space-grid pb-[100px]'>
|
||||
{newSpaces.slice(0, 6).map((property, idx) => (
|
||||
<PropertySpaceCard
|
||||
key={property.id ?? idx}
|
||||
@@ -510,9 +622,9 @@ const HomePage = () => {
|
||||
))}
|
||||
{newSpaces.length < 4 ? (
|
||||
<>
|
||||
<div className="hidden 2xl:block"></div>
|
||||
<div className="hidden lg:block"></div>
|
||||
<div className="hidden md:block"></div>
|
||||
<div className='hidden 2xl:block'></div>
|
||||
<div className='hidden lg:block'></div>
|
||||
<div className='hidden md:block'></div>
|
||||
</>
|
||||
) : null}
|
||||
</div>
|
||||
@@ -521,50 +633,59 @@ const HomePage = () => {
|
||||
</section>
|
||||
|
||||
{(!isLoggedIn || userRole === "customer") && (
|
||||
<section className="container bg-gray-100 mx-auto py-20 rounded-xl mb-12 2xl:px-16 px-6 md:flex justify-between md:flex-nowrap items-center">
|
||||
<div className="w-full md:w-[25%] mt-8 md:mt-0">
|
||||
<h3 className="text-xl pb-3 leading-10 font-bold md:text-4xl">Host Your Space Today!</h3>
|
||||
<p className="text-base text-left my-4">
|
||||
Unlock new income opportunities by listing your space on our platform. Join a community of successful hosts, reach thousands of potential guests, and maximize your property's potential.
|
||||
<section className='container mx-auto mb-12 items-center justify-between rounded-xl bg-gray-100 px-6 py-20 md:flex md:flex-nowrap 2xl:px-16'>
|
||||
<div className='mt-8 w-full md:mt-0 md:w-[25%]'>
|
||||
<h3 className='pb-3 text-xl font-bold leading-10 md:text-4xl'>
|
||||
Host Your Space Today!
|
||||
</h3>
|
||||
<p className='my-4 text-left text-base'>
|
||||
Unlock new income opportunities by listing your space on our
|
||||
platform. Join a community of successful hosts, reach thousands of
|
||||
potential guests, and maximize your property's potential.
|
||||
</p>
|
||||
<button
|
||||
onClick={() => authState.originalRole === "customer" ? navigate("/become-a-host") : navigate("/signup")}
|
||||
className="login-btn-gradient mb-4 py-3 px-4 rounded-3xl text-sm text-white">
|
||||
Start Hosting Now
|
||||
</button>
|
||||
<button
|
||||
onClick={() =>
|
||||
authState.originalRole === "customer"
|
||||
? navigate("/become-a-host")
|
||||
: navigate("/signup")
|
||||
}
|
||||
className='login-btn-gradient mb-4 rounded-3xl px-4 py-3 text-sm text-white'
|
||||
>
|
||||
Start Hosting Now
|
||||
</button>
|
||||
</div>
|
||||
<div className="hidden md:flex justify-between w-full md:w-1/2">
|
||||
<div className='hidden w-full justify-between md:flex md:w-1/2'>
|
||||
<img
|
||||
src="https://freepngimg.com/thumb/building/154733-building-hotel-download-hq.png"
|
||||
alt="Descriptive Alt Text"
|
||||
className="w-full md:w-[70%] h-auto rounded-lg object-cover"
|
||||
src='https://freepngimg.com/thumb/building/154733-building-hotel-download-hq.png'
|
||||
alt='Descriptive Alt Text'
|
||||
className='h-auto w-full rounded-lg object-cover md:w-[70%]'
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
)}
|
||||
|
||||
<Tooltip
|
||||
anchorId="search-button"
|
||||
place="right"
|
||||
content="Search"
|
||||
anchorId='search-button'
|
||||
place='right'
|
||||
content='Search'
|
||||
noArrow
|
||||
/>
|
||||
<Tooltip
|
||||
anchorId="view-all-popular"
|
||||
place="bottom"
|
||||
content="All popular"
|
||||
anchorId='view-all-popular'
|
||||
place='bottom'
|
||||
content='All popular'
|
||||
noArrow
|
||||
/>
|
||||
<Tooltip
|
||||
anchorId="view-all-hosts"
|
||||
place="bottom"
|
||||
content="All hosts"
|
||||
anchorId='view-all-hosts'
|
||||
place='bottom'
|
||||
content='All hosts'
|
||||
noArrow
|
||||
/>
|
||||
<Tooltip
|
||||
anchorId="view-all-new-spaces"
|
||||
place="bottom"
|
||||
content="New spaces"
|
||||
anchorId='view-all-new-spaces'
|
||||
place='bottom'
|
||||
content='New spaces'
|
||||
noArrow
|
||||
/>
|
||||
</>
|
||||
|
||||
+180
-100
@@ -15,13 +15,13 @@ import NoteIcon from "@/components/frontend/icons/NoteIcon";
|
||||
import { formatDate } from "@/utils/date-time-utils";
|
||||
import { DRAFT_STATUS, SPACE_STATUS } from "@/utils/constants";
|
||||
import { useForm } from "react-hook-form";
|
||||
import CustomLocationAutoCompleteV2 from "@/components/CustomLocationAutoCompleteV2";
|
||||
// import CustomLocationAutoCompleteV2 from "@/components/CustomLocationAutoCompleteV2";
|
||||
import DatePickerV3 from "@/components/DatePickerV3";
|
||||
import { isValidDate, parseSearchParams } from "@/utils/utils";
|
||||
import FilterCheckBoxesV2 from "@/components/FilterCheckBoxesV2";
|
||||
import MkdSDK from "@/utils/MkdSDK";
|
||||
import useAmenityCategories from "@/hooks/api/useAmenityCategories";
|
||||
import CustomStaticLocationAutoCompleteV2 from "@/components/CustomStaticLocationAutoCompleteV2 ";
|
||||
import CustomStaticLocationAutoCompleteV2 from "@/components/CustomStaticLocationAutoCompleteV2";
|
||||
|
||||
const prices = [
|
||||
{ name: "$0 - $30", id: 0 },
|
||||
@@ -54,7 +54,8 @@ const ctrl = new AbortController();
|
||||
const SearchPage = () => {
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
|
||||
const { dispatch: globalDispatch, state: globalState } = useContext(GlobalContext);
|
||||
const { dispatch: globalDispatch, state: globalState } =
|
||||
useContext(GlobalContext);
|
||||
|
||||
const [filterPopup, setFilterPopup] = useState(false);
|
||||
|
||||
@@ -82,7 +83,7 @@ const SearchPage = () => {
|
||||
|
||||
async function fetchSpaces() {
|
||||
const params = parseSearchParams(searchParams);
|
||||
const location = (params.location?.split(","))
|
||||
const location = params.location?.split(",");
|
||||
const d = new Date(params.booking_start_time || undefined);
|
||||
|
||||
const filter = {
|
||||
@@ -97,12 +98,28 @@ const SearchPage = () => {
|
||||
globalDispatch({ type: "START_LOADING" });
|
||||
|
||||
// make sure only approved and non-draft spaces
|
||||
var where = [`ergo_property_spaces.space_status = ${SPACE_STATUS.APPROVED} AND schedule_template_id IS NOT NULL AND ergo_property_spaces_images.is_approved = 1 AND ergo_property_spaces.draft_status = ${DRAFT_STATUS.COMPLETED} AND ergo_property_spaces.deleted_at IS NULL`];
|
||||
var where = [
|
||||
`ergo_property_spaces.space_status = ${SPACE_STATUS.APPROVED} AND schedule_template_id IS NOT NULL AND ergo_property_spaces_images.is_approved = 1 AND ergo_property_spaces.draft_status = ${DRAFT_STATUS.COMPLETED} AND ergo_property_spaces.deleted_at IS NULL`,
|
||||
];
|
||||
|
||||
// use data.location to search address, city, country and zip
|
||||
if (filter.location) {
|
||||
where.push(
|
||||
`(ergo_property.address_line_1 LIKE '%${filter.location}%' OR ergo_property.address_line_2 LIKE '%${filter.location}%' OR ergo_property.city LIKE '%${location[0] && location[0]}%' OR ergo_property.country LIKE '%${location.length === 1 ? location[0] : location.length === 2 ? location[1] : location[2]}%' OR ergo_property.zip LIKE '%${filter.location}%' OR ergo_property.name LIKE '%${filter.location}%')`,
|
||||
`(ergo_property.address_line_1 LIKE '%${
|
||||
filter.location
|
||||
}%' OR ergo_property.address_line_2 LIKE '%${
|
||||
filter.location
|
||||
}%' OR ergo_property.city LIKE '%${
|
||||
location[0] && location[0]
|
||||
}%' OR ergo_property.country LIKE '%${
|
||||
location.length === 1
|
||||
? location[0]
|
||||
: location.length === 2
|
||||
? location[1]
|
||||
: location[2]
|
||||
}%' OR ergo_property.zip LIKE '%${
|
||||
filter.location
|
||||
}%' OR ergo_property.name LIKE '%${filter.location}%')`
|
||||
);
|
||||
}
|
||||
|
||||
@@ -111,31 +128,41 @@ const SearchPage = () => {
|
||||
}
|
||||
|
||||
if (filter.capacity.length > 0) {
|
||||
if (filter.capacity[filter.capacity.length-1] !== "Greater Than 30") {
|
||||
const str = filter.capacity[filter.capacity.length-1]; // Get the first (and only) element from the array
|
||||
const numbers = str.split('-').map(num => num.trim()); // Split the string and trim spaces
|
||||
if (filter.capacity[filter.capacity.length - 1] !== "Greater Than 30") {
|
||||
const str = filter.capacity[filter.capacity.length - 1]; // Get the first (and only) element from the array
|
||||
const numbers = str.split("-").map((num) => num.trim()); // Split the string and trim spaces
|
||||
const [num1, num2] = numbers; // Destructure the resulting array to get the numbers
|
||||
where.pop()
|
||||
where.pop();
|
||||
where.push(
|
||||
`ergo_property_spaces.max_capacity BETWEEN ${num1} AND ${num2}`,
|
||||
`ergo_property_spaces.max_capacity BETWEEN ${num1} AND ${num2}`
|
||||
);
|
||||
} else {
|
||||
where.push(
|
||||
`ergo_property_spaces.max_capacity > 30`,
|
||||
);
|
||||
where.push(`ergo_property_spaces.max_capacity > 30`);
|
||||
}
|
||||
}
|
||||
|
||||
if (filter.category.length > 0) {
|
||||
where.push(`(${filter.category.map((cg) => `ergo_spaces.category LIKE '%${cg}%'`).join(" OR ")})`);
|
||||
where.push(
|
||||
`(${filter.category
|
||||
.map((cg) => `ergo_spaces.category LIKE '%${cg}%'`)
|
||||
.join(" OR ")})`
|
||||
);
|
||||
}
|
||||
|
||||
if (filter.amenity.length > 0) {
|
||||
where.push(`(${filter.amenity.map((am) => `ergo_amenity.name LIKE '%${am}%'`).join(" OR ")})`);
|
||||
where.push(
|
||||
`(${filter.amenity
|
||||
.map((am) => `ergo_amenity.name LIKE '%${am}%'`)
|
||||
.join(" OR ")})`
|
||||
);
|
||||
}
|
||||
|
||||
if (filter.review.length > 0) {
|
||||
where.push(`(${filter.review.map((rv) => `ER.average_space_rating >= ${rv.replace("+", "")}`).join(" OR ")})`);
|
||||
where.push(
|
||||
`(${filter.review
|
||||
.map((rv) => `ER.average_space_rating >= ${rv.replace("+", "")}`)
|
||||
.join(" OR ")})`
|
||||
);
|
||||
}
|
||||
|
||||
if (filter.price.length > 0) {
|
||||
@@ -143,8 +170,13 @@ const SearchPage = () => {
|
||||
`(${filter.price
|
||||
.filter((pr) => pr.trim() != "")
|
||||
.map((pr) => pr.split("-"))
|
||||
.map(([from, to]) => `ergo_property_spaces.rate BETWEEN ${from.trim().slice(1)} AND ${to.trim().slice(1)} `)
|
||||
.join(" OR ")})`,
|
||||
.map(
|
||||
([from, to]) =>
|
||||
`ergo_property_spaces.rate BETWEEN ${from
|
||||
.trim()
|
||||
.slice(1)} AND ${to.trim().slice(1)} `
|
||||
)
|
||||
.join(" OR ")})`
|
||||
);
|
||||
}
|
||||
|
||||
@@ -152,9 +184,17 @@ const SearchPage = () => {
|
||||
const user_id = Number(localStorage.getItem("user"));
|
||||
const result = await sdk.callRawAPI(
|
||||
"/v2/api/custom/ergo/popular/PAGINATE",
|
||||
{ page: 1, limit: 10000, user_id: Number(user_id), where, booking_start_time: isValidDate(filter.booking_start_time || "") ? new Date(filter.booking_start_time).toISOString() : undefined },
|
||||
{
|
||||
page: 1,
|
||||
limit: 10000,
|
||||
user_id: Number(user_id),
|
||||
where,
|
||||
booking_start_time: isValidDate(filter.booking_start_time || "")
|
||||
? new Date(filter.booking_start_time).toISOString()
|
||||
: undefined,
|
||||
},
|
||||
"POST",
|
||||
ctrl.signal,
|
||||
ctrl.signal
|
||||
);
|
||||
setPropertySpaces(result.list);
|
||||
} catch (err) {
|
||||
@@ -172,7 +212,11 @@ const SearchPage = () => {
|
||||
|
||||
useEffect(() => {
|
||||
if (isValidDate(searchParams.get("booking_start_time"))) {
|
||||
setValue("booking_start_time", new Date(searchParams.get("booking_start_time")), { shouldDirty: true });
|
||||
setValue(
|
||||
"booking_start_time",
|
||||
new Date(searchParams.get("booking_start_time")),
|
||||
{ shouldDirty: true }
|
||||
);
|
||||
}
|
||||
}, []);
|
||||
|
||||
@@ -207,7 +251,12 @@ const SearchPage = () => {
|
||||
globalState.location = result;
|
||||
}
|
||||
searchParams.set("location", globalState.location);
|
||||
searchParams.set("booking_start_time", isValidDate(data.booking_start_time) ? data.booking_start_time.toISOString() : "");
|
||||
searchParams.set(
|
||||
"booking_start_time",
|
||||
isValidDate(data.booking_start_time)
|
||||
? data.booking_start_time.toISOString()
|
||||
: ""
|
||||
);
|
||||
searchParams.set("category", data.category.join(","));
|
||||
searchParams.set("price", data.price.join(","));
|
||||
searchParams.set("amenity", data.amenity.join(","));
|
||||
@@ -215,7 +264,7 @@ const SearchPage = () => {
|
||||
if (data.max_capacity !== "NaN") {
|
||||
searchParams.set("max_capacity", Number(data.max_capacity));
|
||||
}
|
||||
searchParams.set("capacity", data.capacity);
|
||||
searchParams.set("capacity", data.capacity);
|
||||
setSearchParams(searchParams);
|
||||
}
|
||||
|
||||
@@ -231,39 +280,43 @@ const SearchPage = () => {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-white">
|
||||
<section className="container mx-auto mb-[24px] bg-white px-6 pt-[120px] normal-case 2xl:px-32">
|
||||
<div className='min-h-screen bg-white'>
|
||||
<section className='container mx-auto mb-[24px] bg-white px-6 pt-[120px] normal-case 2xl:px-32'>
|
||||
<form
|
||||
className="flex w-full flex-wrap justify-center"
|
||||
className='flex w-full flex-wrap justify-center'
|
||||
onSubmit={handleSubmit(onSubmit)}
|
||||
id="search-bar"
|
||||
id='search-bar'
|
||||
>
|
||||
<CustomStaticLocationAutoCompleteV2
|
||||
// type={true}
|
||||
// control={control}
|
||||
// setValue={(val) => setValue("location", val)}
|
||||
// name="location"
|
||||
type="static"
|
||||
setValue={(val) => globalDispatch({
|
||||
type: "SETLOCATION",
|
||||
payload: {
|
||||
location:val
|
||||
},
|
||||
})}
|
||||
containerClassName={"mb-4 flex min-h-[45px] w-full max-w-full flex-grow items-center gap-2 border-2 px-4 lg:mb-0 lg:w-[unset] lg:border-r-0 lg:border-b-2"}
|
||||
className="border-0 focus:outline-none"
|
||||
placeholder="Search by city or zip code"
|
||||
type='static'
|
||||
setValue={(val) =>
|
||||
globalDispatch({
|
||||
type: "SETLOCATION",
|
||||
payload: {
|
||||
location: val,
|
||||
},
|
||||
})
|
||||
}
|
||||
containerClassName={
|
||||
"mb-4 flex min-h-[45px] w-full max-w-full flex-grow items-center gap-2 border-2 px-4 lg:mb-0 lg:w-[unset] lg:border-r-0 lg:border-b-2"
|
||||
}
|
||||
className='border-0 focus:outline-none'
|
||||
placeholder='Search by city or zip code'
|
||||
suggestionType={["(regions)"]}
|
||||
/>
|
||||
|
||||
<div className="relative mb-6 flex h-[45px] w-full lg:w-1/2 cursor-pointer items-center gap-2 border-2 lg:border-r-0 p-2 lg:mb-0 lg:w-[unset] lg:min-w-[230px]">
|
||||
<div className='relative mb-6 flex h-[45px] w-full cursor-pointer items-center gap-2 border-2 p-2 lg:mb-0 lg:w-1/2 lg:w-[unset] lg:min-w-[230px] lg:border-r-0'>
|
||||
<DatePickerV3
|
||||
reset={() => resetField("booking_start_time")}
|
||||
setValue={(val) => setValue("booking_start_time", val)}
|
||||
control={control}
|
||||
name="booking_start_time"
|
||||
labelClassName="justify-between flex-grow flex-row-reverse"
|
||||
placeholder="Select Date"
|
||||
name='booking_start_time'
|
||||
labelClassName='justify-between flex-grow flex-row-reverse'
|
||||
placeholder='Select Date'
|
||||
min={new Date()}
|
||||
/>
|
||||
</div>
|
||||
@@ -277,32 +330,32 @@ const SearchPage = () => {
|
||||
/>
|
||||
</div> */}
|
||||
<button
|
||||
className="login-btn-gradient mb-4 w-full whitespace-nowrap p-2 px-6 text-white disabled:text-[#98A2B3] lg:mb-0 lg:w-[unset]"
|
||||
type="submit"
|
||||
id="update-search"
|
||||
className='login-btn-gradient mb-4 w-full whitespace-nowrap p-2 px-6 text-white disabled:text-[#98A2B3] lg:mb-0 lg:w-[unset]'
|
||||
type='submit'
|
||||
id='update-search'
|
||||
>
|
||||
Update Search
|
||||
</button>
|
||||
</form>
|
||||
<div className="block lg:hidden">
|
||||
<div className='block lg:hidden'>
|
||||
<button
|
||||
type="button"
|
||||
className="mb-6 flex w-full items-center justify-center gap-2 border-2 py-2 text-center"
|
||||
type='button'
|
||||
className='mb-6 flex w-full items-center justify-center gap-2 border-2 py-2 text-center'
|
||||
onClick={() => setFilterPopup(true)}
|
||||
>
|
||||
<FilterIcon />
|
||||
Filters
|
||||
</button>
|
||||
<div className="snap-scroll flex gap-4">
|
||||
<div className='snap-scroll flex gap-4'>
|
||||
{Object.entries(parseSearchParams(searchParams)).map(([k, v]) => {
|
||||
if (!v) return null;
|
||||
if (k == "booking_start_time") {
|
||||
return (
|
||||
<span className="whitespace-nowrap rounded-[50px] bg-[#F2F4F7] py-[6px] px-[16px] text-[#475467]">
|
||||
<span className='whitespace-nowrap rounded-[50px] bg-[#F2F4F7] px-[16px] py-[6px] text-[#475467]'>
|
||||
{formatDate(v)}
|
||||
<button
|
||||
type="button"
|
||||
className="ml-3"
|
||||
type='button'
|
||||
className='ml-3'
|
||||
onClick={() => removeFilter(k)}
|
||||
>
|
||||
✕
|
||||
@@ -318,12 +371,12 @@ const SearchPage = () => {
|
||||
return vArr.map((filter, i) => (
|
||||
<span
|
||||
key={i}
|
||||
className="whitespace-nowrap rounded-[50px] bg-[#F2F4F7] py-[6px] px-[16px] text-[#475467]"
|
||||
className='whitespace-nowrap rounded-[50px] bg-[#F2F4F7] px-[16px] py-[6px] text-[#475467]'
|
||||
>
|
||||
{filter}
|
||||
<button
|
||||
type="button"
|
||||
className="ml-3"
|
||||
type='button'
|
||||
className='ml-3'
|
||||
onClick={() => removeFilter(k, filter)}
|
||||
>
|
||||
✕
|
||||
@@ -335,12 +388,12 @@ const SearchPage = () => {
|
||||
return (
|
||||
<span
|
||||
key={k}
|
||||
className="whitespace-nowrap rounded-[50px] bg-[#F2F4F7] py-[6px] px-[16px] text-[#475467]"
|
||||
className='whitespace-nowrap rounded-[50px] bg-[#F2F4F7] px-[16px] py-[6px] text-[#475467]'
|
||||
>
|
||||
{v}
|
||||
<button
|
||||
type="button"
|
||||
className="ml-3"
|
||||
type='button'
|
||||
className='ml-3'
|
||||
onClick={() => removeFilter(k)}
|
||||
>
|
||||
✕
|
||||
@@ -351,21 +404,25 @@ const SearchPage = () => {
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section className="search-page-container container mx-auto flex gap-[32px] bg-white px-6 normal-case 2xl:px-32">
|
||||
<section className='search-page-container container mx-auto flex gap-[32px] bg-white px-6 normal-case 2xl:px-32'>
|
||||
<aside
|
||||
className={`hidden xl:block xl:w-1/5 ${filterPopup ? "popup-tablet" : ""}`}
|
||||
className={`hidden xl:block xl:w-1/5 ${
|
||||
filterPopup ? "popup-tablet" : ""
|
||||
}`}
|
||||
onClick={() => setFilterPopup(false)}
|
||||
>
|
||||
<div
|
||||
className={`${filterPopup ? "w-[80%] max-w-[500px] rounded-xl p-5" : ""} flex flex-col bg-white `}
|
||||
className={`${
|
||||
filterPopup ? "w-[80%] max-w-[500px] rounded-xl p-5" : ""
|
||||
} flex flex-col bg-white `}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
{filterPopup ? (
|
||||
<div className="mb-[18px] flex items-center justify-between border-b pb-2">
|
||||
<h3 className="text-2xl font-semibold">Filters</h3>
|
||||
<div className='mb-[18px] flex items-center justify-between border-b pb-2'>
|
||||
<h3 className='text-2xl font-semibold'>Filters</h3>
|
||||
<button
|
||||
onClick={() => setFilterPopup(false)}
|
||||
className="rounded-full border p-1 px-3 text-2xl font-normal duration-300 hover:bg-gray-200"
|
||||
className='rounded-full border p-1 px-3 text-2xl font-normal duration-300 hover:bg-gray-200'
|
||||
>
|
||||
✕
|
||||
</button>
|
||||
@@ -375,61 +432,84 @@ const SearchPage = () => {
|
||||
<div className={`${filterPopup ? "snap-scroll h-[60vh]" : ""}`}>
|
||||
<FilterCheckBoxesV2
|
||||
control={control}
|
||||
name="category"
|
||||
title="Spaces"
|
||||
labelField="category"
|
||||
valueField="category"
|
||||
name='category'
|
||||
title='Spaces'
|
||||
labelField='category'
|
||||
valueField='category'
|
||||
options={spaceCategories}
|
||||
reset={() => { resetField("category"); searchParams.set("category", ""); setSearchParams(searchParams) }}
|
||||
reset={() => {
|
||||
resetField("category");
|
||||
searchParams.set("category", "");
|
||||
setSearchParams(searchParams);
|
||||
}}
|
||||
/>
|
||||
<FilterCheckBoxesV2
|
||||
control={control}
|
||||
name="price"
|
||||
title="Prices"
|
||||
labelField="name"
|
||||
valueField="name"
|
||||
name='price'
|
||||
title='Prices'
|
||||
labelField='name'
|
||||
valueField='name'
|
||||
options={prices}
|
||||
reset={() => { resetField("price"); searchParams.set("price", ""); setSearchParams(searchParams) }}
|
||||
reset={() => {
|
||||
resetField("price");
|
||||
searchParams.set("price", "");
|
||||
setSearchParams(searchParams);
|
||||
}}
|
||||
/>
|
||||
<FilterCheckBoxesV2
|
||||
control={control}
|
||||
name="capacity"
|
||||
title="Capacity"
|
||||
labelField="name"
|
||||
valueField="name"
|
||||
name='capacity'
|
||||
title='Capacity'
|
||||
labelField='name'
|
||||
valueField='name'
|
||||
options={capacity}
|
||||
reset={() => { resetField("capacity"); searchParams.set("capacity", ""); setSearchParams(searchParams) }}
|
||||
reset={() => {
|
||||
resetField("capacity");
|
||||
searchParams.set("capacity", "");
|
||||
setSearchParams(searchParams);
|
||||
}}
|
||||
/>
|
||||
<FilterCheckBoxesV2
|
||||
name="amenity"
|
||||
name='amenity'
|
||||
control={control}
|
||||
title="Amenities"
|
||||
title='Amenities'
|
||||
options={amenityCategories}
|
||||
labelField="name"
|
||||
valueField="name"
|
||||
reset={() => { resetField("amenity"); searchParams.set("amenity", ""); setSearchParams(searchParams) }}
|
||||
labelField='name'
|
||||
valueField='name'
|
||||
reset={() => {
|
||||
resetField("amenity");
|
||||
searchParams.set("amenity", "");
|
||||
setSearchParams(searchParams);
|
||||
}}
|
||||
/>
|
||||
<FilterCheckBoxesV2
|
||||
name="review"
|
||||
name='review'
|
||||
control={control}
|
||||
title="Reviews"
|
||||
title='Reviews'
|
||||
options={reviews}
|
||||
labelField="name"
|
||||
valueField="name"
|
||||
reset={() => { resetField("review"); searchParams.set("review", ""); setSearchParams(searchParams) }}
|
||||
labelField='name'
|
||||
valueField='name'
|
||||
reset={() => {
|
||||
resetField("review");
|
||||
searchParams.set("review", "");
|
||||
setSearchParams(searchParams);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
<div className="mb-16 max-w-full flex-grow xl:w-4/5">
|
||||
<div className="mb-[15px] flex items-center justify-between">
|
||||
<div className='mb-16 max-w-full flex-grow xl:w-4/5'>
|
||||
<div className='mb-[15px] flex items-center justify-between'>
|
||||
<h5 className={propertySpaces.length == 0 ? "md:invisible" : ""}>
|
||||
{propertySpaces.length == 0 ? (
|
||||
"No results Found"
|
||||
) : (
|
||||
<>
|
||||
{" "}
|
||||
Results Found <strong className="font-semibold">({propertySpaces.length})</strong>
|
||||
Results Found{" "}
|
||||
<strong className='font-semibold'>
|
||||
({propertySpaces.length})
|
||||
</strong>
|
||||
</>
|
||||
)}
|
||||
</h5>
|
||||
@@ -439,16 +519,16 @@ const SearchPage = () => {
|
||||
{ label: "Rating (Low to High)", value: 1 },
|
||||
]}
|
||||
onChange={setSortAsc}
|
||||
accessor="label"
|
||||
valueAccessor="value"
|
||||
className="min-w-[200px]"
|
||||
accessor='label'
|
||||
valueAccessor='value'
|
||||
className='min-w-[200px]'
|
||||
listOptionClassName={"pl-4"}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-wrap justify-center gap-6 lg:block">
|
||||
<div className='flex flex-wrap justify-center gap-6 lg:block'>
|
||||
{propertySpaces.length == 0 && (
|
||||
<div className="hidden min-h-[300px] items-center justify-center normal-case text-[#667085] md:flex">
|
||||
<h2 className="flex gap-3">
|
||||
<div className='hidden min-h-[300px] items-center justify-center normal-case text-[#667085] md:flex'>
|
||||
<h2 className='flex gap-3'>
|
||||
<NoteIcon /> No results found
|
||||
</h2>
|
||||
</div>
|
||||
@@ -464,8 +544,8 @@ const SearchPage = () => {
|
||||
</div>
|
||||
</section>
|
||||
<Tooltip
|
||||
anchorId="update-search"
|
||||
place="right"
|
||||
anchorId='update-search'
|
||||
place='right'
|
||||
content={"Search"}
|
||||
noArrow
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user