Compare commits
12 Commits
d05052b5e3
...
dev
| Author | SHA1 | Date | |
|---|---|---|---|
| afed3aed53 | |||
| ead8f23379 | |||
| 4d31f9f71a | |||
| 880df2c2ac | |||
| c40302aa93 | |||
| b424376656 | |||
| 788ca3519f | |||
| 3a0f43d491 | |||
| 6ecb29eb5e | |||
| 96a838eb8e | |||
| 8795de6c7d | |||
| 5bc0e9220a |
@@ -6,8 +6,9 @@ import Error404Page from '../main/404/Error404Page';
|
|||||||
import navigationPagesConfigs from '../main/navigationPages/navigationPagesConfig';
|
import navigationPagesConfigs from '../main/navigationPages/navigationPagesConfig';
|
||||||
import authPagesConfigs from '../main/authPages/authPagesConfigs';
|
import authPagesConfigs from '../main/authPages/authPagesConfigs';
|
||||||
import HomeConfig from '../main/home/HomeConfig';
|
import HomeConfig from '../main/home/HomeConfig';
|
||||||
|
import RentAndBuyConfig from '../main/rentAndBuy/RentAndBuyConfig';
|
||||||
|
|
||||||
const routeConfigs = [...navigationPagesConfigs, ...authPagesConfigs, HomeConfig];
|
const routeConfigs = [...navigationPagesConfigs, ...authPagesConfigs, HomeConfig, RentAndBuyConfig];
|
||||||
|
|
||||||
const routes = [
|
const routes = [
|
||||||
...FuseUtils.generateRoutesFromConfigs(routeConfigs, settingsConfig.defaultAuth),
|
...FuseUtils.generateRoutesFromConfigs(routeConfigs, settingsConfig.defaultAuth),
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import i18next from 'i18next';
|
import i18next from 'i18next';
|
||||||
|
|
||||||
import ForgotPasswordPage from './ForgotPasswordPage';
|
import ForgotPasswordPage from './ForgotPasswordPage';
|
||||||
import authRoles from '../../../configs/consts';
|
import { authRoles } from '../../../configs/consts';
|
||||||
import en from './i18n/en';
|
import en from './i18n/en';
|
||||||
|
|
||||||
i18next.addResourceBundle('en', 'forgotPasswordPage', en);
|
i18next.addResourceBundle('en', 'forgotPasswordPage', en);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import i18next from 'i18next';
|
import i18next from 'i18next';
|
||||||
|
|
||||||
import SignInPage from './SignInPage';
|
import SignInPage from './SignInPage';
|
||||||
import authRoles from '../../../configs/consts';
|
import { authRoles } from '../../../configs/consts';
|
||||||
import en from './i18n/en';
|
import en from './i18n/en';
|
||||||
|
|
||||||
i18next.addResourceBundle('en', 'signInPage', en);
|
i18next.addResourceBundle('en', 'signInPage', en);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import i18next from 'i18next';
|
import i18next from 'i18next';
|
||||||
|
|
||||||
import SignUpPage from './SignUpPage';
|
import SignUpPage from './SignUpPage';
|
||||||
import authRoles from '../../../configs/consts';
|
import { authRoles } from '../../../configs/consts';
|
||||||
import en from './i18n/en';
|
import en from './i18n/en';
|
||||||
|
|
||||||
i18next.addResourceBundle('en', 'signUpPage', en);
|
i18next.addResourceBundle('en', 'signUpPage', en);
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ function AboutUs({ t }) {
|
|||||||
</div>
|
</div>
|
||||||
<Link
|
<Link
|
||||||
className="w-[220px] py-[17px] text-center text-base text-primary-light font-semibold tracking-widest uppercase rounded-2xl bg-secondary-light shadow hover:shadow-hover hover:shadow-secondary-light ease-in-out duration-300"
|
className="w-[220px] py-[17px] text-center text-base text-primary-light font-semibold tracking-widest uppercase rounded-2xl bg-secondary-light shadow hover:shadow-hover hover:shadow-secondary-light ease-in-out duration-300"
|
||||||
to="/rent-and-buy"
|
to="/rent-and-buy/search"
|
||||||
>
|
>
|
||||||
{t('research_btn')}
|
{t('research_btn')}
|
||||||
</Link>
|
</Link>
|
||||||
|
|||||||
@@ -1,19 +1,25 @@
|
|||||||
import { memo, useState } from 'react';
|
import { memo, useState } from 'react';
|
||||||
import { withTranslation } from 'react-i18next';
|
import { withTranslation } from 'react-i18next';
|
||||||
|
import { useNavigate } from 'react-router-dom';
|
||||||
import SearchInput from '../../shared-components/SearchInput';
|
import SearchInput from '../../shared-components/SearchInput';
|
||||||
|
|
||||||
function Welcome({ t }) {
|
function Welcome({ t }) {
|
||||||
const [query, setQuery] = useState('');
|
const [query, setQuery] = useState('');
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
const onInputType = (event) => {
|
const onInputType = (event) => {
|
||||||
const { target } = event;
|
const { target } = event;
|
||||||
const value = target?.value ?? '';
|
const value = target?.value ?? '';
|
||||||
console.log(value);
|
|
||||||
setQuery(value);
|
setQuery(value);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onSearch = () => {
|
const onSearch = () => {
|
||||||
// query
|
const trimmedQuery = query.trim();
|
||||||
|
if (!trimmedQuery) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
navigate(`/rent-and-buy/search?query=${trimmedQuery}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -26,6 +32,7 @@ function Welcome({ t }) {
|
|||||||
{t('subtitle')}
|
{t('subtitle')}
|
||||||
</p>
|
</p>
|
||||||
<SearchInput
|
<SearchInput
|
||||||
|
className="max-w-[780px]"
|
||||||
mode="simple"
|
mode="simple"
|
||||||
placeholder={t('main_input_placeholder')}
|
placeholder={t('main_input_placeholder')}
|
||||||
btnText={t('main_input_btn')}
|
btnText={t('main_input_btn')}
|
||||||
|
|||||||
@@ -1,7 +1,43 @@
|
|||||||
import { styled } from '@mui/material/styles';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
import FusePageSimple from '@fuse/core/FusePageSimple';
|
import FusePageSimple from '@fuse/core/FusePageSimple';
|
||||||
import DemoContent from '@fuse/core/DemoContent';
|
import Paper from '@mui/material/Paper';
|
||||||
|
import { styled } from '@mui/material/styles';
|
||||||
|
import { useState } from 'react';
|
||||||
|
import { withTranslation } from 'react-i18next';
|
||||||
|
import SearchInput from '../../shared-components/SearchInput';
|
||||||
|
import DashboardCategory from '../shared-components/DashboardCategory';
|
||||||
|
|
||||||
|
const categoriesMock = [
|
||||||
|
{
|
||||||
|
title: 'All Properties',
|
||||||
|
value: 34,
|
||||||
|
valueColor: 'secondary-main',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'New',
|
||||||
|
value: 12,
|
||||||
|
valueColor: 'common-highlight2',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'In Research',
|
||||||
|
value: 3,
|
||||||
|
valueColor: 'secondary-main',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Interested',
|
||||||
|
value: 25,
|
||||||
|
valueColor: 'common-highlight1',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Purchased',
|
||||||
|
value: 8,
|
||||||
|
valueColor: 'accept-main',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Not Interested',
|
||||||
|
value: 11,
|
||||||
|
valueColor: 'error-main',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
const Root = styled(FusePageSimple)(({ theme }) => ({
|
const Root = styled(FusePageSimple)(({ theme }) => ({
|
||||||
'& .FusePageSimple-header': {
|
'& .FusePageSimple-header': {
|
||||||
@@ -16,21 +52,39 @@ const Root = styled(FusePageSimple)(({ theme }) => ({
|
|||||||
'& .FusePageSimple-sidebarContent': {},
|
'& .FusePageSimple-sidebarContent': {},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
function DashboardPage(props) {
|
function DashboardPage({ t }) {
|
||||||
const { t } = useTranslation('dashboardPage');
|
const [query, setQuery] = useState('');
|
||||||
|
|
||||||
|
const onInputType = (event) => {
|
||||||
|
const { target } = event;
|
||||||
|
const value = target?.value ?? '';
|
||||||
|
setQuery(value);
|
||||||
|
};
|
||||||
|
|
||||||
|
const onSearch = () => {
|
||||||
|
// query
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Root
|
<Root
|
||||||
// header={
|
|
||||||
// <div className="p-24">
|
|
||||||
// <h4>{t('TITLE')}</h4>
|
|
||||||
// </div>
|
|
||||||
// }
|
|
||||||
content={
|
content={
|
||||||
<div className="p-24">
|
<div className="w-full p-60">
|
||||||
<h4>Content</h4>
|
<div className="flex flex-wrap justify-center items-center gap-20 mb-52">
|
||||||
<br />
|
{categoriesMock.map(({ title, value, valueColor }) => (
|
||||||
<DemoContent />
|
<DashboardCategory title={title} value={value} valueColor={valueColor} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<SearchInput
|
||||||
|
className="mb-28"
|
||||||
|
mode="manual"
|
||||||
|
btnText={t('search_input_btn')}
|
||||||
|
query={query}
|
||||||
|
onType={onInputType}
|
||||||
|
onSearch={onSearch}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Paper className="w-full h-640 mb-[30px] rounded-20 shadow-light" />
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
scroll="content"
|
scroll="content"
|
||||||
@@ -38,4 +92,4 @@ function DashboardPage(props) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default DashboardPage;
|
export default withTranslation('dashboardPage')(DashboardPage);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import i18next from 'i18next';
|
import i18next from 'i18next';
|
||||||
|
|
||||||
import authRoles from '../../../configs/consts';
|
import { authRoles } from '../../../configs/consts';
|
||||||
import Dashboard from './Dashboard';
|
import Dashboard from './Dashboard';
|
||||||
import en from './i18n/en';
|
import en from './i18n/en';
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
const locale = {};
|
const locale = {
|
||||||
|
search_input_btn: 'calculate',
|
||||||
|
};
|
||||||
|
|
||||||
export default locale;
|
export default locale;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import FusePageSimple from '@fuse/core/FusePageSimple';
|
import FusePageSimple from '@fuse/core/FusePageSimple';
|
||||||
import { Paper } from '@mui/material';
|
import Paper from '@mui/material/Paper';
|
||||||
import { styled } from '@mui/material/styles';
|
import { styled } from '@mui/material/styles';
|
||||||
import { PROPERTIES_LAYOUTS } from 'app/configs/consts';
|
import { PROPERTIES_LAYOUTS } from 'app/configs/consts';
|
||||||
import { selectUserFavorites, updateUserFavorites } from 'app/store/userSlice';
|
import { selectUserFavorites, updateUserFavorites } from 'app/store/userSlice';
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { lazy } from 'react';
|
import { lazy } from 'react';
|
||||||
import i18next from 'i18next';
|
import i18next from 'i18next';
|
||||||
|
|
||||||
import authRoles from '../../../configs/consts';
|
import { authRoles } from '../../../configs/consts';
|
||||||
import en from './i18n/en';
|
import en from './i18n/en';
|
||||||
|
|
||||||
i18next.addResourceBundle('en', 'favoritesPage', en);
|
i18next.addResourceBundle('en', 'favoritesPage', en);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import FusePageSimple from '@fuse/core/FusePageSimple';
|
import FusePageSimple from '@fuse/core/FusePageSimple';
|
||||||
import { Paper } from '@mui/material';
|
import Paper from '@mui/material/Paper';
|
||||||
import { styled } from '@mui/material/styles';
|
import { styled } from '@mui/material/styles';
|
||||||
import { PROPERTIES_LAYOUTS } from 'app/configs/consts';
|
import { PROPERTIES_LAYOUTS } from 'app/configs/consts';
|
||||||
import { selectUserHistory, updateUserFavorites, updateUserHistory } from 'app/store/userSlice';
|
import { selectUserHistory, updateUserFavorites, updateUserHistory } from 'app/store/userSlice';
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { lazy } from 'react';
|
import { lazy } from 'react';
|
||||||
import i18next from 'i18next';
|
import i18next from 'i18next';
|
||||||
|
|
||||||
import authRoles from '../../../configs/consts';
|
import { authRoles } from '../../../configs/consts';
|
||||||
import en from './i18n/en';
|
import en from './i18n/en';
|
||||||
|
|
||||||
i18next.addResourceBundle('en', 'historyPage', en);
|
i18next.addResourceBundle('en', 'historyPage', en);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { lazy } from 'react';
|
import { lazy } from 'react';
|
||||||
import i18next from 'i18next';
|
import i18next from 'i18next';
|
||||||
|
|
||||||
import authRoles from '../../../configs/consts';
|
import { authRoles } from '../../../configs/consts';
|
||||||
import en from './i18n/en';
|
import en from './i18n/en';
|
||||||
|
|
||||||
i18next.addResourceBundle('en', 'profilePage', en);
|
i18next.addResourceBundle('en', 'profilePage', en);
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
import Typography from '@mui/material/Typography';
|
||||||
|
import clsx from 'clsx';
|
||||||
|
import { memo } from 'react';
|
||||||
|
|
||||||
|
function DashboardCategory({ className, title, value, valueColor }) {
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className={clsx(
|
||||||
|
'flex flex-col items-center justify-center gap-24 max-w-224 w-full h-160 p-24 bg-white shadow-light rounded-20',
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<Typography variant="body1" className="text-lg text-common-layout font-medium">
|
||||||
|
{title}
|
||||||
|
</Typography>
|
||||||
|
<Typography
|
||||||
|
variant="body2"
|
||||||
|
className={clsx('text-5xl font-bold', valueColor && `text-${valueColor}`)}
|
||||||
|
>
|
||||||
|
{value}
|
||||||
|
</Typography>
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default memo(DashboardCategory);
|
||||||
16
src/app/main/rentAndBuy/RentAndBuy.js
Normal file
16
src/app/main/rentAndBuy/RentAndBuy.js
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import Typography from '@mui/material/Typography';
|
||||||
|
import { withTranslation } from 'react-i18next';
|
||||||
|
import { Outlet } from 'react-router-dom';
|
||||||
|
|
||||||
|
function RentAndBuy({ t }) {
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col max-w-8xl w-full px-10 py-32 mx-auto">
|
||||||
|
<Typography variant="h1" className="mb-44 text-4xl text-common-layout font-medium">
|
||||||
|
{t('title')}
|
||||||
|
</Typography>
|
||||||
|
<Outlet />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default withTranslation('rentAndBuyPage')(RentAndBuy);
|
||||||
38
src/app/main/rentAndBuy/RentAndBuyConfig.js
Normal file
38
src/app/main/rentAndBuy/RentAndBuyConfig.js
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
import { lazy } from 'react';
|
||||||
|
import i18next from 'i18next';
|
||||||
|
|
||||||
|
import RentAndBuy from './RentAndBuy';
|
||||||
|
import en from './i18n/en';
|
||||||
|
|
||||||
|
i18next.addResourceBundle('en', 'rentAndBuyPage', en);
|
||||||
|
|
||||||
|
const SearchAddress = lazy(() => import('./components/SearchAddress/SearchAddress'));
|
||||||
|
const PropertyPreview = lazy(() => import('./components/PropertyPreview/PropertyPreview'));
|
||||||
|
|
||||||
|
const RentAndBuyConfig = {
|
||||||
|
settings: {
|
||||||
|
layout: {
|
||||||
|
config: {},
|
||||||
|
style: 'layout2',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
auth: null,
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
path: '/rent-and-buy',
|
||||||
|
element: <RentAndBuy />,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: 'search',
|
||||||
|
element: <SearchAddress />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'preview',
|
||||||
|
element: <PropertyPreview />,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
export default RentAndBuyConfig;
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
import Button from '@mui/material/Button';
|
||||||
|
import { useState } from 'react';
|
||||||
|
import { withTranslation } from 'react-i18next';
|
||||||
|
import RegistrationPopup from 'src/app/main/shared-components/popups/RegistrationPopup';
|
||||||
|
|
||||||
|
function PropertyPreview({ t }) {
|
||||||
|
const [isPopupOpen, setIsPopupOpen] = useState(false);
|
||||||
|
|
||||||
|
const openPopup = () => setIsPopupOpen(true);
|
||||||
|
const closePopup = () => setIsPopupOpen(false);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="flex flex-col items-center">
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
color="secondary"
|
||||||
|
className="w-384 p-20 text-2xl leading-none rounded-lg"
|
||||||
|
aria-label={t('see_more_btn')}
|
||||||
|
type="button"
|
||||||
|
size="large"
|
||||||
|
onClick={openPopup}
|
||||||
|
>
|
||||||
|
{t('see_more_btn')}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
<RegistrationPopup open={isPopupOpen} onClose={closePopup} />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default withTranslation('rentAndBuyPage')(PropertyPreview);
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
import { withTranslation } from 'react-i18next';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
|
||||||
|
function SearchAddress({ t }) {
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col items-center gap-68">
|
||||||
|
<span>How are you?</span>
|
||||||
|
<Link
|
||||||
|
to="/rent-and-buy/preview"
|
||||||
|
className="inline-block w-[182px] py-[17px] text-center text-base text-primary-light font-semibold tracking-widest uppercase rounded-lg bg-secondary-light shadow hover:shadow-hover hover:shadow-secondary-light ease-in-out duration-300"
|
||||||
|
>
|
||||||
|
{t('show_btn')}
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default withTranslation('rentAndBuyPage')(SearchAddress);
|
||||||
8
src/app/main/rentAndBuy/i18n/en.js
Normal file
8
src/app/main/rentAndBuy/i18n/en.js
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
const locale = {
|
||||||
|
title: 'Rent&Buy Analysis',
|
||||||
|
show_btn: 'show',
|
||||||
|
see_more_btn: 'See more',
|
||||||
|
view: 'View the Calculation',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
||||||
11
src/app/main/shared-components/PropertyAnalysisHeader.js
Normal file
11
src/app/main/shared-components/PropertyAnalysisHeader.js
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import Paper from '@mui/material/Paper';
|
||||||
|
|
||||||
|
function PropertyAnalysisHeader() {
|
||||||
|
return (
|
||||||
|
<Paper>
|
||||||
|
<div></div>
|
||||||
|
</Paper>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PropertyAnalysisHeader;
|
||||||
@@ -1,7 +1,14 @@
|
|||||||
import { forwardRef, memo, useCallback } from 'react';
|
|
||||||
import TextField from '@mui/material/TextField';
|
|
||||||
import Button from '@mui/material/Button';
|
|
||||||
import _ from '@lodash';
|
import _ from '@lodash';
|
||||||
|
import Button from '@mui/material/Button';
|
||||||
|
// import Select from '@mui/material/Select';
|
||||||
|
import TextField from '@mui/material/TextField';
|
||||||
|
import clsx from 'clsx';
|
||||||
|
import { forwardRef, memo, useCallback } from 'react';
|
||||||
|
|
||||||
|
const SEARCH_INPUT_MODES = {
|
||||||
|
simple: 'simple',
|
||||||
|
manual: 'manual',
|
||||||
|
};
|
||||||
|
|
||||||
const StyledTextField = forwardRef((props, ref) => (
|
const StyledTextField = forwardRef((props, ref) => (
|
||||||
<TextField
|
<TextField
|
||||||
@@ -19,28 +26,32 @@ const StyledTextField = forwardRef((props, ref) => (
|
|||||||
/>
|
/>
|
||||||
));
|
));
|
||||||
|
|
||||||
function SearchInput({ mode, placeholder, btnText, query, onType, onSearch }) {
|
function SearchInput({ className, mode, placeholder, btnText, query, onType, onSearch }) {
|
||||||
const isSimpleMode = mode === 'simple';
|
const isSimpleMode = mode === SEARCH_INPUT_MODES.simple;
|
||||||
|
const isManualMode = mode === SEARCH_INPUT_MODES.manual;
|
||||||
|
const hasBtn = isSimpleMode || isManualMode;
|
||||||
|
|
||||||
const debouncedOnType = useCallback(_.debounce(onType, 250), [onType]);
|
const debouncedOnType = useCallback(_.debounce(onType, 250), [onType]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form className="flex items-center gap-20">
|
<form className={clsx('flex items-center gap-20', className)}>
|
||||||
<StyledTextField
|
<StyledTextField
|
||||||
type="text"
|
type="text"
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
className="max-w-[620px] w-full bourder-0"
|
className="w-full bourder-0"
|
||||||
defaultValue={query}
|
defaultValue={query}
|
||||||
placeholder={placeholder}
|
placeholder={placeholder ?? ''}
|
||||||
onChange={debouncedOnType}
|
onChange={debouncedOnType}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{isSimpleMode && (
|
{/* {isManualMode && <Select />} */}
|
||||||
|
|
||||||
|
{hasBtn && (
|
||||||
<Button
|
<Button
|
||||||
variant="contained"
|
variant="contained"
|
||||||
color="inherit"
|
color="inherit"
|
||||||
className="text-center text-base text-primary-light font-semibold tracking-widest uppercase rounded-2xl bg-secondary-light shadow hover:shadow-hover hover:shadow-secondary-light ease-in-out duration-300"
|
className="text-center text-base text-primary-light font-semibold tracking-widest uppercase rounded-2xl bg-secondary-light shadow hover:shadow-hover hover:shadow-secondary-light ease-in-out duration-300"
|
||||||
aria-label={btnText}
|
aria-label={btnText ?? ''}
|
||||||
type="button"
|
type="button"
|
||||||
size="large"
|
size="large"
|
||||||
onClick={onSearch}
|
onClick={onSearch}
|
||||||
|
|||||||
44
src/app/main/shared-components/popups/BasicPopup.js
Normal file
44
src/app/main/shared-components/popups/BasicPopup.js
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
import Backdrop from '@mui/material/Backdrop';
|
||||||
|
import Box from '@mui/material/Box';
|
||||||
|
import Fade from '@mui/material/Fade';
|
||||||
|
import Modal from '@mui/material/Modal';
|
||||||
|
import { memo } from 'react';
|
||||||
|
|
||||||
|
const style = {
|
||||||
|
position: 'absolute',
|
||||||
|
top: '50%',
|
||||||
|
left: '50%',
|
||||||
|
transform: 'translate(-50%, -50%)',
|
||||||
|
width: 400,
|
||||||
|
bgcolor: 'inherit',
|
||||||
|
boxShadow: 24,
|
||||||
|
overflow: 'hidden',
|
||||||
|
};
|
||||||
|
|
||||||
|
function BasicPopup({ children, className, open, onClose }) {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Modal
|
||||||
|
aria-labelledby="transition-modal-title"
|
||||||
|
aria-describedby="transition-modal-description"
|
||||||
|
open={open}
|
||||||
|
onClose={onClose}
|
||||||
|
closeAfterTransition
|
||||||
|
slots={{ backdrop: Backdrop }}
|
||||||
|
slotProps={{
|
||||||
|
backdrop: {
|
||||||
|
timeout: 500,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Fade in={open}>
|
||||||
|
<Box sx={style} className={className}>
|
||||||
|
{children}
|
||||||
|
</Box>
|
||||||
|
</Fade>
|
||||||
|
</Modal>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default memo(BasicPopup);
|
||||||
72
src/app/main/shared-components/popups/RegistrationPopup.js
Normal file
72
src/app/main/shared-components/popups/RegistrationPopup.js
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
import Box from '@mui/material/Box';
|
||||||
|
import Typography from '@mui/material/Typography';
|
||||||
|
import { memo } from 'react';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
import BasicPopup from './BasicPopup';
|
||||||
|
|
||||||
|
const bullets = [
|
||||||
|
'Lorem ipsum rci egestas. Tortor nulla ac est nulla nisl ut.',
|
||||||
|
'Lorem ipsum dolor sit amet consectetur.',
|
||||||
|
'Lorem ipsum rci egestas. Tortor nulla ac est nulla nisl ut.',
|
||||||
|
'Lorem ipsum dolor sit amet consectetur.',
|
||||||
|
'Lorem ipsum dolor sit amet consectetur.',
|
||||||
|
'Lorem ipsum dt amet consectetur. Duis massa vel estas. Tortor nulla ac est nulla nisl ut.',
|
||||||
|
'Lorem ipsum dolor sit amet consectetur.',
|
||||||
|
];
|
||||||
|
|
||||||
|
function RegistrationPopup({ open, onClose }) {
|
||||||
|
return (
|
||||||
|
<BasicPopup
|
||||||
|
className="flex max-w-[76vw] w-full h-[66vh] min-h-[600px] rounded-20"
|
||||||
|
open={open}
|
||||||
|
onClose={onClose}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
className="relative hidden md:flex flex-auto items-center justify-center h-full p-64 lg:px-112 overflow-hidden max-w-[45vw] w-full"
|
||||||
|
sx={{ backgroundColor: 'common.layout' }}
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
className="absolute inset-0 pointer-events-none"
|
||||||
|
viewBox="0 0 960 540"
|
||||||
|
width="100%"
|
||||||
|
height="100%"
|
||||||
|
preserveAspectRatio="xMidYMax slice"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
component="g"
|
||||||
|
sx={{ color: 'primary.light' }}
|
||||||
|
className="opacity-20"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
strokeWidth="100"
|
||||||
|
>
|
||||||
|
<circle r="234" cx="266" cy="23" />
|
||||||
|
<circle r="234" cx="790" cy="551" />
|
||||||
|
</Box>
|
||||||
|
</svg>
|
||||||
|
</Box>
|
||||||
|
<Box
|
||||||
|
className="flex flex-col items-center px-60 pt-56"
|
||||||
|
sx={{ backgroundColor: 'background.paper' }}
|
||||||
|
>
|
||||||
|
<Typography variant="h4" className="mb-52 text-4xl font-semibold">
|
||||||
|
Lorem ipsum dolor sit amet consetur
|
||||||
|
</Typography>
|
||||||
|
<ul className="flex flex-col gap-10 mb-68">
|
||||||
|
{bullets.map((bullet) => (
|
||||||
|
<li className="bullet">{bullet}</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
<Link
|
||||||
|
className="w-full py-20 text-center text-xl text-primary-light font-semibold tracking-widest rounded-2xl bg-secondary-main shadow hover:shadow-hover hover:shadow-secondary-main ease-in-out duration-300"
|
||||||
|
to="/sign-up"
|
||||||
|
>
|
||||||
|
Try for free
|
||||||
|
</Link>
|
||||||
|
</Box>
|
||||||
|
</BasicPopup>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default memo(RegistrationPopup);
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
import AuthService from './authService';
|
import AuthService from './authService';
|
||||||
import FirebaseService from './firebaseService';
|
import FirebaseService from './firebaseService';
|
||||||
|
import PropertyService from './propertyService';
|
||||||
|
|
||||||
// TODO: change to firebase secrets or to use firebase functions
|
// TODO: change to firebase secrets or to use firebase functions
|
||||||
const firebaseConfig = {
|
const firebaseConfig = {
|
||||||
apiKey: 'AIzaSyBqMGmOF0-DkYDpnsmZwpf5S8w5cL3fBb8',
|
apiKey: 'AIzaSyBqMGmOF0-DkYDpnsmZwpf5S8w5cL3fBb8',
|
||||||
@@ -12,7 +14,15 @@ const firebaseConfig = {
|
|||||||
measurementId: 'G-JW7J8ZQ9FJ',
|
measurementId: 'G-JW7J8ZQ9FJ',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// TopHap
|
||||||
|
const propertyConfig = {
|
||||||
|
dataBaseURL: process.env.REACT_APP_PROPERTY_DATA_BASE_URL,
|
||||||
|
widgetBaseURL: process.env.REACT_APP_PROPERTY_WIDGET_BASE_URL,
|
||||||
|
apiKey: process.env.REACT_APP_PROPERTY_API_KEY,
|
||||||
|
};
|
||||||
|
|
||||||
const firebase = new FirebaseService(firebaseConfig);
|
const firebase = new FirebaseService(firebaseConfig);
|
||||||
const authService = new AuthService();
|
const authService = new AuthService();
|
||||||
|
const propertyService = new PropertyService(propertyConfig);
|
||||||
|
|
||||||
export { authService, firebase };
|
export { authService, firebase, propertyService };
|
||||||
|
|||||||
57
src/app/services/propertyService.js
Normal file
57
src/app/services/propertyService.js
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
|
const widgets = {
|
||||||
|
absorptionRate: 'absorption-rate',
|
||||||
|
crime: 'crime',
|
||||||
|
hazards: 'hazards',
|
||||||
|
mapPreview: 'map-preview',
|
||||||
|
marketTrends: 'market-trends',
|
||||||
|
noise: 'noise',
|
||||||
|
population: 'population',
|
||||||
|
propertyTypes: 'property-types',
|
||||||
|
rentEstimate: 'rent-estimate',
|
||||||
|
thEstimate: 'th-estimate',
|
||||||
|
turnover: 'turnover',
|
||||||
|
walkability: 'walkability',
|
||||||
|
zipCodeMap: 'zip-code-map',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default class PropertyService {
|
||||||
|
#dataApi;
|
||||||
|
|
||||||
|
#widgetApi;
|
||||||
|
|
||||||
|
constructor(config) {
|
||||||
|
const { dataBaseURL, widgetBaseURL, apiKey } = config;
|
||||||
|
this.#dataApi = axios.create({
|
||||||
|
baseURL: dataBaseURL,
|
||||||
|
headers: { 'X-API-Key': apiKey },
|
||||||
|
});
|
||||||
|
this.#widgetApi = axios.create({
|
||||||
|
baseURL: widgetBaseURL,
|
||||||
|
params: {
|
||||||
|
sid: apiKey,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchProperty(params) {
|
||||||
|
return this.#dataApi.get('/property', { params });
|
||||||
|
}
|
||||||
|
|
||||||
|
search(body) {
|
||||||
|
return this.#dataApi.post('/search', body);
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchComparables(params) {
|
||||||
|
return this.#dataApi.get('/comparables', { params });
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchWidgetByPropertyId(widget, propertyId, params) {
|
||||||
|
return this.#widgetApi.get(`${widget}/${propertyId}`, { params });
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchWidgetByAddress(widget, params) {
|
||||||
|
return this.#widgetApi.get(`${widget}/address`, { params });
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,7 +7,7 @@ function FooterLayout2() {
|
|||||||
const { t } = useTranslation('layout2');
|
const { t } = useTranslation('layout2');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<footer className="flex items-center justify-center w-full bg-common-layout">
|
<footer className="z-[10000] flex items-center justify-center w-full bg-common-layout">
|
||||||
<div className="flex gap-96 w-full max-w-screen-xl px-10 py-52">
|
<div className="flex gap-96 w-full max-w-screen-xl px-10 py-52">
|
||||||
<ul className="flex flex-col gap-16 mr-96">
|
<ul className="flex flex-col gap-16 mr-96">
|
||||||
<li>
|
<li>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ function HeaderLayout2(props) {
|
|||||||
const { t } = useTranslation('layout2');
|
const { t } = useTranslation('layout2');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<header className="fixed z-50 flex items-center justify-center w-full h-72 px-10 bg-primary-light">
|
<header className="fixed z-[10000] flex items-center justify-center w-full h-72 px-10 bg-primary-light">
|
||||||
<div className="flex justify-between max-w-screen-xl w-full">
|
<div className="flex justify-between max-w-screen-xl w-full">
|
||||||
<Link to="/">
|
<Link to="/">
|
||||||
<img
|
<img
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ function NavLinks({ className }) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Link className={className} to="/rent-and-buy">
|
<Link className={className} to="/rent-and-buy/search">
|
||||||
{t('rent_and_buy')}
|
{t('rent_and_buy')}
|
||||||
</Link>
|
</Link>
|
||||||
<Link className={className} to={{ hash: 'about-us' }}>
|
<Link className={className} to={{ hash: 'about-us' }}>
|
||||||
|
|||||||
Reference in New Issue
Block a user