-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
26 changed files
with
850 additions
and
22 deletions.
There are no files selected for viewing
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import * as React from 'react'; | ||
|
||
import Container from '../../reusable/Container'; | ||
import Filters from './RealEstate/Filters'; | ||
import PropertyTable from './RealEstate/PropertyTable'; | ||
|
||
export interface IFilters { | ||
city?: string; | ||
country?: string; | ||
} | ||
|
||
const Marketplace = () => { | ||
const [filters, setFilters] = React.useState<IFilters>({}); | ||
|
||
return ( | ||
<Container.Container> | ||
<Container.FlexResponsiveRow className="flex-1 gap-8"> | ||
<Filters filters={filters} setFilters={setFilters} /> | ||
<Container.Container className="flex-1 py-4"> | ||
<PropertyTable filters={filters} /> | ||
</Container.Container> | ||
</Container.FlexResponsiveRow> | ||
</Container.Container> | ||
); | ||
}; | ||
|
||
export default Marketplace; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
import * as React from 'react'; | ||
import * as Icon from 'react-icons/fi'; | ||
|
||
import Container from '../../../reusable/Container'; | ||
import { Map, MapLink } from './Filters/Map'; | ||
import FiltersTab from './Filters/FiltersTab'; | ||
import Button from '../../../reusable/Button'; | ||
import Link from '../../../reusable/Link'; | ||
import { IFilters } from '../RealEstate'; | ||
|
||
interface Props { | ||
filters: IFilters; | ||
setFilters: React.Dispatch<React.SetStateAction<IFilters>>; | ||
} | ||
|
||
const Filters = (props: Props) => ( | ||
<> | ||
<Container.Container className="block sm:hidden w-2/6 xl:w-3/12"> | ||
<PostsSidebarDesktop {...props} /> | ||
</Container.Container> | ||
<Container.Container className="w-full hidden sm:block"> | ||
<PostsSidebarMobile {...props} /> | ||
</Container.Container> | ||
</> | ||
); | ||
|
||
const PostsSidebarDesktop = (props: Props) => ( | ||
<Container.FlexCols className="w-full"> | ||
<Map /> | ||
<Container.Card className="bg-white w-full block"> | ||
<FiltersTab {...props} /> | ||
</Container.Card> | ||
</Container.FlexCols> | ||
); | ||
|
||
const PostsSidebarMobile = (props: Props) => ( | ||
<Container.FlexRow className="justify-around py-2"> | ||
<MapLink /> | ||
<FiltersOnMobile tab={<FiltersTab {...props} />} /> | ||
</Container.FlexRow> | ||
); | ||
|
||
const FiltersOnMobile = ({ tab }: { tab: React.ReactNode }) => { | ||
const [showFilters, setShowFilters] = React.useState<boolean>(false); | ||
|
||
const onOpenFilters = () => { | ||
setShowFilters(true); | ||
}; | ||
|
||
return ( | ||
<> | ||
{showFilters && ( | ||
<Container.Container className="bg-white fixed z-50 top-0 left-0 w-screen min-h-screen overflow-y-scroll"> | ||
<Container.FlexCols className="shadow-md p-1"> | ||
<Icon.FiX | ||
className="text-brandAlt hover:cursor-pointer" | ||
size={24} | ||
onClick={() => setShowFilters(false)} | ||
/> | ||
</Container.FlexCols> | ||
<Container.Container className="p-4">{tab}</Container.Container> | ||
<Container.Container className="p-4"> | ||
<Button.Primary onClick={() => setShowFilters(false)}> | ||
Apply filters | ||
</Button.Primary> | ||
</Container.Container> | ||
</Container.Container> | ||
)} | ||
<Link.Default className="!text-brand" onClick={onOpenFilters}> | ||
<Icon.FiFilter className="text-brand inline mr-2" size={24} /> | ||
Filters | ||
</Link.Default> | ||
</> | ||
); | ||
}; | ||
|
||
export default Filters; |
107 changes: 107 additions & 0 deletions
107
src/js/components/App/pages/RealEstate/Filters/FiltersTab.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
import * as React from 'react'; | ||
import * as Icon from 'react-icons/md'; | ||
|
||
import Container from '../../../../reusable/Container'; | ||
import Input from '../../../../reusable/Input'; | ||
import { IFilters } from '../../RealEstate'; | ||
|
||
interface Props { | ||
filters: IFilters; | ||
setFilters: React.Dispatch<React.SetStateAction<IFilters>>; | ||
} | ||
|
||
const FiltersTab = ({ filters, setFilters }: Props) => { | ||
const [debouncedCity, setDebouncedCity] = React.useState<string>( | ||
filters.city ?? '', | ||
); | ||
const [cityDebouncer, setCityDebouncer] = React.useState<NodeJS.Timeout>(); | ||
const [debouncedCountry, setDebouncedCountry] = React.useState<string>( | ||
filters.country ?? '', | ||
); | ||
const [countryDebouncer, setCountryDebouncer] = | ||
React.useState<NodeJS.Timeout>(); | ||
|
||
const onCityChanged = (e: React.ChangeEvent<HTMLInputElement>) => { | ||
setDebouncedCity(e.target.value); | ||
}; | ||
|
||
const onCountryChanged = (e: React.ChangeEvent<HTMLInputElement>) => { | ||
setDebouncedCountry(e.target.value); | ||
}; | ||
|
||
const resetFilters = () => { | ||
setFilters({}); | ||
setDebouncedCity(''); | ||
setDebouncedCountry(''); | ||
}; | ||
|
||
React.useEffect(() => { | ||
if (cityDebouncer) { | ||
clearTimeout(cityDebouncer); | ||
} | ||
setCityDebouncer( | ||
setTimeout(() => { | ||
setFilters((prevFilters) => ({ | ||
...prevFilters, | ||
city: debouncedCity.length > 0 ? debouncedCity : undefined, | ||
})); | ||
}, 1000), | ||
); | ||
}, [debouncedCity]); | ||
|
||
React.useEffect(() => { | ||
if (countryDebouncer) { | ||
clearTimeout(countryDebouncer); | ||
} | ||
setCountryDebouncer( | ||
setTimeout(() => { | ||
setFilters((prevFilters) => ({ | ||
...prevFilters, | ||
country: debouncedCountry.length > 0 ? debouncedCountry : undefined, | ||
})); | ||
}, 1000), | ||
); | ||
}, [debouncedCountry]); | ||
|
||
return ( | ||
<Container.FlexCols className="gap-4"> | ||
<Container.FlexRow className="justify-between"> | ||
<Container.Container> | ||
<span className="text-lg font-bold pb-4">Filters</span> | ||
</Container.Container> | ||
<Container.Container> | ||
<span | ||
className="text-brand hover:underline hover:cursor-pointer" | ||
onClick={resetFilters} | ||
> | ||
<Icon.MdClear className="inline mr-2" size={24} /> Reset Filters | ||
</span> | ||
</Container.Container> | ||
</Container.FlexRow> | ||
<Container.FlexCols className="gap-2"> | ||
<span className="block text-brand text-lg">City</span> | ||
<Input.IconInput | ||
id="filters--city" | ||
containerClassName="!mb-0" | ||
placeholder="London" | ||
icon={<Icon.MdLocationCity className="text-brand" size={20} />} | ||
value={debouncedCity} | ||
onChange={onCityChanged} | ||
/> | ||
</Container.FlexCols> | ||
<Container.FlexCols className="gap-2"> | ||
<span className="block text-brand text-lg">Country</span> | ||
<Input.IconInput | ||
id="filters--country" | ||
containerClassName="!mb-0" | ||
placeholder="United Kingdom" | ||
icon={<Icon.MdLocationPin className="text-brand" size={20} />} | ||
value={debouncedCountry} | ||
onChange={onCountryChanged} | ||
/> | ||
</Container.FlexCols> | ||
</Container.FlexCols> | ||
); | ||
}; | ||
|
||
export default FiltersTab; |
Oops, something went wrong.