iceholidays-frontend 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/assets/stylesheets/iceholidays/frontend/actiontext.scss +119 -0
- data/app/assets/stylesheets/iceholidays/frontend/application.sass.scss +961 -355
- data/app/assets/stylesheets/iceholidays/frontend/common.scss +156 -72
- data/app/assets/stylesheets/iceholidays/frontend/layout.scss +218 -125
- data/app/assets/stylesheets/iceholidays/frontend/utils/_antd_overrides.scss +22 -7
- data/app/assets/stylesheets/iceholidays/frontend/utils/_variables.scss +2 -1
- data/app/assets/stylesheets/iceholidays/frontend/widgets/filter_pills.scss +19 -12
- data/app/assets/stylesheets/iceholidays/frontend/widgets/search_bar.scss +4 -0
- data/app/controllers/iceholidays/frontend/posts_controller.rb +14 -0
- data/app/javascript/api-services/agents-api.service.ts +33 -0
- data/app/javascript/api-services/locations-api.service.ts +23 -1
- data/app/javascript/api-services/series-api.service.ts +48 -28
- data/app/javascript/interfaces/agent.interface.ts +11 -0
- data/app/javascript/interfaces/country.interface.ts +4 -3
- data/app/javascript/interfaces/itinerary.interface.ts +101 -8
- data/app/javascript/react/App.tsx +1 -1
- data/app/javascript/react/components/Destinations.tsx +30 -20
- data/app/javascript/react/components/PriceDetails.tsx +146 -0
- data/app/javascript/react/components/shared/ContactAgentsForm.tsx +44 -0
- data/app/javascript/react/components/shared/Headline.tsx +2 -1
- data/app/javascript/react/components/shared/LocationDropdown.tsx +34 -0
- data/app/javascript/react/components/shared/{Postcard.tsx → LocationPostcards.tsx} +22 -1
- data/app/javascript/react/layouts/MainFooter.tsx +64 -39
- data/app/javascript/react/layouts/MainHeader.tsx +68 -30
- data/app/javascript/react/pages/AboutUsPage.tsx +6 -6
- data/app/javascript/react/pages/BlogPage.tsx +6 -4
- data/app/javascript/react/pages/ContactAgentsPage.tsx +174 -5
- data/app/javascript/react/pages/ContactUsPage.tsx +5 -5
- data/app/javascript/react/pages/CountriesPage.tsx +3 -8
- data/app/javascript/react/pages/Homepage.tsx +23 -13
- data/app/javascript/react/pages/ListingPage.tsx +192 -146
- data/app/javascript/react/pages/ShowPage.tsx +269 -264
- data/app/javascript/react/widgets/FilterPills.tsx +83 -49
- data/app/javascript/react/widgets/SearchBarWidget.tsx +24 -8
- data/app/views/iceholidays/frontend/posts/index.html.erb +9 -0
- data/app/views/iceholidays/frontend/posts/show.html.erb +2 -0
- data/config/routes.rb +2 -1
- data/lib/iceholidays/frontend/version.rb +1 -1
- data/public/iceholidays-assets/application.css +1190 -425
- data/public/iceholidays-assets/application.js +91 -104
- data/public/iceholidays-assets/application.js.map +4 -4
- data/public/iceholidays-assets/images/about-us_logo_mobile.png +0 -0
- data/public/iceholidays-assets/images/destinations_logo.png +0 -0
- data/public/iceholidays-assets/images/footer-bg_mobile.png +0 -0
- data/public/iceholidays-assets/images/logo_mobile.png +0 -0
- metadata +18 -27
- data/public/iceholidays-assets/images/8D7N.png +0 -0
- data/public/iceholidays-assets/images/Frame71.png +0 -0
- data/public/iceholidays-assets/images/africa.png +0 -0
- data/public/iceholidays-assets/images/banner1.png +0 -0
- data/public/iceholidays-assets/images/banner2.png +0 -0
- data/public/iceholidays-assets/images/china.png +0 -0
- data/public/iceholidays-assets/images/china2.png +0 -0
- data/public/iceholidays-assets/images/chongqing.png +0 -0
- data/public/iceholidays-assets/images/guangzhou.png +0 -0
- data/public/iceholidays-assets/images/guilin.png +0 -0
- data/public/iceholidays-assets/images/harbin.png +0 -0
- data/public/iceholidays-assets/images/hongkong.png +0 -0
- data/public/iceholidays-assets/images/inner_mongolia.png +0 -0
- data/public/iceholidays-assets/images/jiangxi.png +0 -0
- data/public/iceholidays-assets/images/kenya.png +0 -0
- data/public/iceholidays-assets/images/kenya2.png +0 -0
- data/public/iceholidays-assets/images/kunming.png +0 -0
- data/public/iceholidays-assets/images/slikroad.png +0 -0
- data/public/iceholidays-assets/images/southafrica.png +0 -0
- data/public/iceholidays-assets/images/tanzania.png +0 -0
- data/public/iceholidays-assets/images/tour1.png +0 -0
- data/public/iceholidays-assets/images/uganda.png +0 -0
- /data/public/iceholidays-assets/images/{Group_71.png → about-us_logo.png} +0 -0
- /data/public/iceholidays-assets/images/{logo_container.png → logo.png} +0 -0
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { Form, Select, Button, Flex } from "antd";
|
|
2
|
+
import React from "react";
|
|
3
|
+
|
|
4
|
+
export default function ContactAgentsForm(
|
|
5
|
+
props: {
|
|
6
|
+
states: any[];
|
|
7
|
+
cities: any[];
|
|
8
|
+
findAgents;
|
|
9
|
+
filterCities;
|
|
10
|
+
filterStates;
|
|
11
|
+
}
|
|
12
|
+
) {
|
|
13
|
+
const {states, cities, findAgents, filterCities, filterStates} = props;
|
|
14
|
+
|
|
15
|
+
return (
|
|
16
|
+
<Form layout="vertical" onFinish={findAgents}>
|
|
17
|
+
<Form.Item wrapperCol={{ span: 24 }} label="Select State" name="state">
|
|
18
|
+
<Select
|
|
19
|
+
allowClear={true}
|
|
20
|
+
showSearch
|
|
21
|
+
filterOption={(input, option) =>
|
|
22
|
+
(option?.label ?? '').toString().toLowerCase().includes(input.toLowerCase())
|
|
23
|
+
}
|
|
24
|
+
placeholder="Please select"
|
|
25
|
+
options={states.map((s:any) => {return {label: s, value: s}})}
|
|
26
|
+
onChange={filterCities}/>
|
|
27
|
+
</Form.Item>
|
|
28
|
+
<Form.Item wrapperCol={{ span: 24 }} label="City" name="city">
|
|
29
|
+
<Select
|
|
30
|
+
allowClear={true}
|
|
31
|
+
showSearch
|
|
32
|
+
filterOption={(input, option) =>
|
|
33
|
+
(option?.label ?? '').toString().toLowerCase().includes(input.toLowerCase())
|
|
34
|
+
}
|
|
35
|
+
placeholder="Please select"
|
|
36
|
+
options={cities.map((s:any) => {return {label: s, value: s}})}
|
|
37
|
+
onChange={filterStates}/>
|
|
38
|
+
</Form.Item>
|
|
39
|
+
<Flex align="flex-end" justify="center">
|
|
40
|
+
<Button type="primary" className="find-button" htmlType="submit">Find Agent</Button>
|
|
41
|
+
</Flex>
|
|
42
|
+
</Form>
|
|
43
|
+
)
|
|
44
|
+
}
|
|
@@ -6,6 +6,7 @@ import SearchBarWidget from "../../widgets/SearchBarWidget";
|
|
|
6
6
|
const Headline = (
|
|
7
7
|
props: {
|
|
8
8
|
bannerImage: string;
|
|
9
|
+
showSearch?: boolean;
|
|
9
10
|
title?: string;
|
|
10
11
|
children?: JSX.Element;
|
|
11
12
|
breadcrumbs: any[];
|
|
@@ -14,7 +15,7 @@ const Headline = (
|
|
|
14
15
|
const { bannerImage, title, children, breadcrumbs } = props;
|
|
15
16
|
return (
|
|
16
17
|
<>
|
|
17
|
-
<SearchBarWidget/>
|
|
18
|
+
{(props.showSearch == undefined || props.showSearch && props.showSearch == true) && <SearchBarWidget/>}
|
|
18
19
|
<div id="headline">
|
|
19
20
|
<div id="headline_banner" style={{backgroundImage: `url(${bannerImage})`}}></div>
|
|
20
21
|
<div id="headline_header">
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import Icon from "@mdi/react";
|
|
3
|
+
import { Location } from "../../../interfaces/country.interface";
|
|
4
|
+
import { Select } from "antd";
|
|
5
|
+
import { mdiFilterVariant } from "@mdi/js";
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
const LocationDropdown = (
|
|
9
|
+
props: {
|
|
10
|
+
locations:Location[];
|
|
11
|
+
selectLocation;
|
|
12
|
+
}
|
|
13
|
+
) => {
|
|
14
|
+
const { locations } = props;
|
|
15
|
+
|
|
16
|
+
return (
|
|
17
|
+
<div className="location-dropdown">
|
|
18
|
+
<Select
|
|
19
|
+
className="location-filter"
|
|
20
|
+
suffixIcon={<Icon path={mdiFilterVariant} size="18px" />}
|
|
21
|
+
variant="borderless"
|
|
22
|
+
defaultValue="china"
|
|
23
|
+
options={locations.map((location) => ({label: location.name, value: location.id}))}
|
|
24
|
+
dropdownStyle={{padding: "15px 20px", borderRadius: "20px", boxShadow: "0px 3.08px 16.47px 0px #00000040"}}
|
|
25
|
+
optionRender={(option) => (
|
|
26
|
+
<div className="location-filter_option"> {option.label} </div>
|
|
27
|
+
)}
|
|
28
|
+
onChange={props.selectLocation}
|
|
29
|
+
/>
|
|
30
|
+
</div>
|
|
31
|
+
)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export default LocationDropdown;
|
|
@@ -2,6 +2,7 @@ import React from "react";
|
|
|
2
2
|
import { Link } from "react-router-dom";
|
|
3
3
|
import { mdiMenuRight } from "@mdi/js";
|
|
4
4
|
import Icon from "@mdi/react";
|
|
5
|
+
import { Location } from "../../../interfaces/country.interface";
|
|
5
6
|
|
|
6
7
|
|
|
7
8
|
const Postcard = (
|
|
@@ -28,4 +29,24 @@ const Postcard = (
|
|
|
28
29
|
)
|
|
29
30
|
}
|
|
30
31
|
|
|
31
|
-
|
|
32
|
+
const LocationPostcards = (
|
|
33
|
+
props: {
|
|
34
|
+
locations:Location[];
|
|
35
|
+
}
|
|
36
|
+
) => {
|
|
37
|
+
const { locations } = props;
|
|
38
|
+
|
|
39
|
+
const listingLink = (locationId: number) => {
|
|
40
|
+
return `/app/listing?location_id=${locationId}`;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return (
|
|
44
|
+
<div className="postcards">
|
|
45
|
+
{
|
|
46
|
+
locations.map((city, index)=><Postcard key={index} link={listingLink(city.id)} image={city.cover} name={city.name} tourCount={city.tourCount}/>)
|
|
47
|
+
}
|
|
48
|
+
</div>
|
|
49
|
+
)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export default LocationPostcards;
|
|
@@ -1,10 +1,37 @@
|
|
|
1
|
-
import { notification, Space } from "antd";
|
|
1
|
+
import { Col, Flex, notification, Row, Space } from "antd";
|
|
2
2
|
import React from "react";
|
|
3
3
|
import { Link } from "react-router-dom";
|
|
4
4
|
import LocationsApi from "../../api-services/locations-api.service";
|
|
5
5
|
import { Country } from "../../interfaces/country.interface";
|
|
6
6
|
|
|
7
7
|
|
|
8
|
+
const menus = [
|
|
9
|
+
{
|
|
10
|
+
label: "Home",
|
|
11
|
+
link: "/app"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
label: "pdpa",
|
|
15
|
+
link: "/app"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
label: "about us",
|
|
19
|
+
link: "/app/about-us"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
label: "privacy policy",
|
|
23
|
+
link: "/app"
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
label: "contact us",
|
|
27
|
+
link: "/app/contact-us"
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
label: "terms & conditions",
|
|
31
|
+
link: "/app"
|
|
32
|
+
},
|
|
33
|
+
]
|
|
34
|
+
|
|
8
35
|
export default class MainFooter extends React.Component {
|
|
9
36
|
api = new LocationsApi;
|
|
10
37
|
|
|
@@ -25,44 +52,42 @@ export default class MainFooter extends React.Component {
|
|
|
25
52
|
render(){
|
|
26
53
|
return (
|
|
27
54
|
<div id="main-footer">
|
|
28
|
-
<
|
|
29
|
-
<
|
|
30
|
-
<
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
<
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
</
|
|
47
|
-
</
|
|
48
|
-
<
|
|
49
|
-
<
|
|
50
|
-
<
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
<hr/>
|
|
65
|
-
</div>
|
|
55
|
+
<Row id="main-footer_links" gutter={[12, 12]}>
|
|
56
|
+
<Col flex="1 0 25%" className="column">
|
|
57
|
+
<Space direction="vertical">
|
|
58
|
+
<div className="link-group-title">Countries</div>
|
|
59
|
+
<div className="link-group-items">
|
|
60
|
+
{
|
|
61
|
+
this.state.countries.map((country: Country)=> <Link key={country.id} to={`/app/listing?keyword=${country.name}`}>{country.name}</Link> )
|
|
62
|
+
}
|
|
63
|
+
</div>
|
|
64
|
+
</Space>
|
|
65
|
+
</Col>
|
|
66
|
+
<Col flex="1 0 30%" className="column footer-menu">
|
|
67
|
+
<Space direction="vertical">
|
|
68
|
+
<div className="link-group-items">
|
|
69
|
+
{
|
|
70
|
+
menus.map(menu => <Link to={menu.link}>{menu.label}</Link>)
|
|
71
|
+
}
|
|
72
|
+
</div>
|
|
73
|
+
</Space>
|
|
74
|
+
</Col>
|
|
75
|
+
<Col flex="1 0 20%" className="column contact-info">
|
|
76
|
+
<Space direction="vertical" align="center">
|
|
77
|
+
<Flex vertical gap="20px" align="center">
|
|
78
|
+
<div className="link-group-title">Contact Us</div>
|
|
79
|
+
<div><Link to="/app/contact-agents">contact agents</Link></div>
|
|
80
|
+
<div className="link-group-title">Follow us on</div>
|
|
81
|
+
<Flex gap={20} justify="space-between">
|
|
82
|
+
<img src="/iceholidays-assets/images/social/ico_fb.png"/>
|
|
83
|
+
<img src="/iceholidays-assets/images/social/ico_twitter.png"/>
|
|
84
|
+
<img src="/iceholidays-assets/images/social/ico_yt.png"/>
|
|
85
|
+
<img src="/iceholidays-assets/images/social/ico_ig.png"/>
|
|
86
|
+
</Flex>
|
|
87
|
+
</Flex>
|
|
88
|
+
</Space>
|
|
89
|
+
</Col>
|
|
90
|
+
</Row>
|
|
66
91
|
<div id="copyright">
|
|
67
92
|
<span>Copyright © 2024 Golden Destinations</span>
|
|
68
93
|
</div>
|
|
@@ -1,43 +1,81 @@
|
|
|
1
|
-
import { mdiFileDownload } from "@mdi/js";
|
|
1
|
+
import { mdiFileDownload, mdiMenu } from "@mdi/js";
|
|
2
2
|
import Icon from "@mdi/react";
|
|
3
|
-
import { Button } from "antd";
|
|
4
|
-
import React from "react";
|
|
5
|
-
import {
|
|
3
|
+
import { Button, Drawer, Menu } from "antd";
|
|
4
|
+
import React, { useState } from "react";
|
|
5
|
+
import type { MenuProps } from 'antd';
|
|
6
|
+
import { Link, useLocation, useMatch } from "react-router-dom";
|
|
6
7
|
|
|
8
|
+
type MenuItem = Required<MenuProps>['items'][number];
|
|
7
9
|
|
|
8
|
-
const routes = [
|
|
9
|
-
{label: "Home", path: "/app"},
|
|
10
|
-
{label: "About Us", path: "/app/about-us"},
|
|
11
|
-
{label: "Countries", path: "/app/countries"},
|
|
12
|
-
{label: "Blog", path: "/app/blog"}
|
|
13
|
-
]
|
|
14
10
|
|
|
15
|
-
const
|
|
16
|
-
{
|
|
17
|
-
|
|
11
|
+
const items: MenuItem[] = [
|
|
12
|
+
{
|
|
13
|
+
key: 'app',
|
|
14
|
+
label: <Link to="/app"> Home </Link>
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
key: 'about-us',
|
|
18
|
+
label: <Link to="/app/about-us"> About Us </Link>
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
key: 'countries',
|
|
22
|
+
label: <Link to="/app/countries"> Countries </Link>
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
key: 'blog',
|
|
26
|
+
label: <Link to="/app/blog"> Blog </Link>
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
key: 'logo',
|
|
30
|
+
label: <img src="/iceholidays-assets/images/logo.png" className="logo logo_desktop"/>,
|
|
31
|
+
disabled: true
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
key: 'contact-agents',
|
|
35
|
+
label: <Link to="/app/contact-agents"> Contact Agents </Link>
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
key: 'contact-us',
|
|
39
|
+
label: <Link to="/app/contact-us"> Contact Us </Link>
|
|
40
|
+
},
|
|
18
41
|
]
|
|
19
42
|
|
|
20
43
|
const MainHeader = () => {
|
|
44
|
+
const [open, setOpen] = useState(false);
|
|
45
|
+
const location = useLocation();
|
|
46
|
+
const activeUrlKey = location.pathname.split("/").pop() || "app";
|
|
47
|
+
const [current, setCurrent] = useState(activeUrlKey);
|
|
48
|
+
|
|
49
|
+
const onClick: MenuProps['onClick'] = (e) => {
|
|
50
|
+
setCurrent(e.key);
|
|
51
|
+
setOpen(false);
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const showDrawer = () => {
|
|
55
|
+
setOpen(true);
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const onClose = () => {
|
|
59
|
+
setOpen(false);
|
|
60
|
+
};
|
|
61
|
+
|
|
21
62
|
return (
|
|
22
63
|
<div id="main-header">
|
|
23
|
-
<
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
</
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
{
|
|
34
|
-
routes2.map((route, index)=> <NavLink key={index} to={route.path} end className={({ isActive }) => (isActive ? 'active' : '')}> {route.label} </NavLink>)
|
|
35
|
-
}
|
|
36
|
-
</div>
|
|
64
|
+
<Menu mode="horizontal" items={items} onClick={onClick} selectedKeys={[current]} className="nav-menu"/>
|
|
65
|
+
|
|
66
|
+
<a href="/app"><img src="/iceholidays-assets/images/logo_mobile.png" className="logo logo_mobile"/></a>
|
|
67
|
+
|
|
68
|
+
<div id="nav-buttons">
|
|
69
|
+
<Button id="get-brochure" type="primary"><Icon path={mdiFileDownload} size="18px" /> get brochure</Button>
|
|
70
|
+
|
|
71
|
+
<Button id="toggle-menu" type="primary" onClick={showDrawer}>
|
|
72
|
+
<Icon path={mdiMenu} size="25px" />
|
|
73
|
+
</Button>
|
|
37
74
|
</div>
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
75
|
+
|
|
76
|
+
<Drawer title={null} onClose={onClose} open={open} id="nav-drawer">
|
|
77
|
+
<Menu items={items} onClick={onClick} selectedKeys={[current]} className="nav-menu_mobile"/>
|
|
78
|
+
</Drawer>
|
|
41
79
|
</div>
|
|
42
80
|
)
|
|
43
81
|
}
|
|
@@ -50,21 +50,21 @@ const AboutUsPage = React.FC = () => (
|
|
|
50
50
|
<p>ICE Holidays is committed to striving towards our customer satisfaction in areas of more quality value for money of our products & services. The management and all employees are committed to the company quality policy through effort in:</p>
|
|
51
51
|
</div>
|
|
52
52
|
</Col>
|
|
53
|
-
<Col
|
|
53
|
+
<Col xs={24} sm={24} lg={8}>
|
|
54
54
|
<div className="items">
|
|
55
55
|
<img src="/iceholidays-assets/images/innovative.png"/>
|
|
56
56
|
<label>Innovative</label>
|
|
57
57
|
<p>Talent team develops great products and services; Agile, innovative, and a quality conscious team of resourceful people dedicated to the best.</p>
|
|
58
58
|
</div>
|
|
59
59
|
</Col>
|
|
60
|
-
<Col
|
|
60
|
+
<Col xs={24} sm={24} lg={8}>
|
|
61
61
|
<div className="items">
|
|
62
62
|
<img src="/iceholidays-assets/images/competitiveness.png"/>
|
|
63
63
|
<label>Competitiveness</label>
|
|
64
64
|
<p>Provide competitive pricing to achieve customer satisfaction.</p>
|
|
65
65
|
</div>
|
|
66
66
|
</Col>
|
|
67
|
-
<Col
|
|
67
|
+
<Col xs={24} sm={24} lg={8}>
|
|
68
68
|
<div className="items">
|
|
69
69
|
<img src="/iceholidays-assets/images/ethical.png"/>
|
|
70
70
|
<label>Ethical</label>
|
|
@@ -73,17 +73,17 @@ const AboutUsPage = React.FC = () => (
|
|
|
73
73
|
</Col>
|
|
74
74
|
</Row>
|
|
75
75
|
|
|
76
|
-
<Row id="certificates" gutter={24}>
|
|
76
|
+
<Row id="certificates" align="middle" justify="center" gutter={[24, 24]}>
|
|
77
77
|
<Col span={24}>
|
|
78
78
|
<div className="section-header">
|
|
79
79
|
<h2>Our Certificates</h2>
|
|
80
80
|
<p>We have acquired recognition and certificates such as:</p>
|
|
81
81
|
</div>
|
|
82
82
|
</Col>
|
|
83
|
-
<Col
|
|
83
|
+
<Col xs={24} sm={24} lg={8}>
|
|
84
84
|
<img src="/iceholidays-assets/images/certificate1.png"/>
|
|
85
85
|
</Col>
|
|
86
|
-
<Col
|
|
86
|
+
<Col xs={24} sm={24} lg={8}>
|
|
87
87
|
<img src="/iceholidays-assets/images/certificate2.png"/>
|
|
88
88
|
</Col>
|
|
89
89
|
</Row>
|
|
@@ -36,6 +36,10 @@ const blogs = [
|
|
|
36
36
|
},
|
|
37
37
|
]
|
|
38
38
|
|
|
39
|
+
const setFilter = (selectedFilter) => {
|
|
40
|
+
console.log("set filter", selectedFilter)
|
|
41
|
+
}
|
|
42
|
+
|
|
39
43
|
|
|
40
44
|
const BlogPage = React.FC = () => (
|
|
41
45
|
<div id="blog-page">
|
|
@@ -43,16 +47,14 @@ const BlogPage = React.FC = () => (
|
|
|
43
47
|
|
|
44
48
|
<div id="blog-page_body">
|
|
45
49
|
<Space size={12} direction="vertical">
|
|
46
|
-
<FilterPills items={types} allOption={true}></FilterPills>
|
|
47
|
-
<FilterPills items="years" title="Year" allOption={true}></FilterPills>
|
|
48
|
-
<FilterPills items="months" title="Month" allOption={true}></FilterPills>
|
|
50
|
+
<FilterPills items={types} allOption={true} initialValue={{keyword: "", year: "", month: ""}} selectFilter={(selected)=>setFilter(selected)}></FilterPills>
|
|
49
51
|
</Space>
|
|
50
52
|
|
|
51
53
|
<div id="blogs">
|
|
52
54
|
<Row wrap gutter={20}>
|
|
53
55
|
{
|
|
54
56
|
blogs.map(blog => (
|
|
55
|
-
<Col span={8}>
|
|
57
|
+
<Col key={blog.id} span={8}>
|
|
56
58
|
<Link to={`/app/blog/${blog.id}`}>
|
|
57
59
|
<Card
|
|
58
60
|
hoverable
|
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import Headline from "../components/shared/Headline";
|
|
3
|
+
import ContactAgentsForm from "../components/shared/ContactAgentsForm";
|
|
4
|
+
import AgentsApi from "../../api-services/agents-api.service";
|
|
5
|
+
import { Button, Card, Col, Modal, notification, Row } from "antd";
|
|
6
|
+
import { Agent } from "../../interfaces/agent.interface";
|
|
7
|
+
import { mdiMapMarker, mdiPhoneInTalkOutline, mdiWhatsapp, mdiEmailOutline } from "@mdi/js";
|
|
8
|
+
import Icon from "@mdi/react";
|
|
9
|
+
|
|
10
|
+
const { Meta } = Card;
|
|
3
11
|
|
|
4
12
|
const bannerPath = '/iceholidays-assets/images/contact_agents.png';
|
|
5
13
|
const breadcrumbs = [
|
|
@@ -7,10 +15,171 @@ const breadcrumbs = [
|
|
|
7
15
|
{ title: 'Contact Agents' }
|
|
8
16
|
]
|
|
9
17
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
18
|
+
class ContactAgentsPage extends React.Component {
|
|
19
|
+
agentsApi = new AgentsApi;
|
|
20
|
+
|
|
21
|
+
state = {
|
|
22
|
+
loading: true,
|
|
23
|
+
allAgents: [],
|
|
24
|
+
agents: [],
|
|
25
|
+
states: [],
|
|
26
|
+
cities: [],
|
|
27
|
+
setIsModalOpen: false,
|
|
28
|
+
agentData: { name: "", image: "", address: "", phone: "", whatsapp: "", email: "", city: "", state: "" },
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
componentDidMount() {
|
|
33
|
+
this.agentsApi.getAgents()
|
|
34
|
+
.then((agentsData:Agent[]) => {
|
|
35
|
+
const states = agentsData.filter(a => a.state != null).map(a => a.state);
|
|
36
|
+
const cities = agentsData.filter(a => a.city != null).map(a => a.city);
|
|
37
|
+
this.setState({agents: agentsData, allAgents: agentsData, loadingAgents:false, states, cities});
|
|
38
|
+
})
|
|
39
|
+
.finally(()=>this.setState({loading: false}))
|
|
40
|
+
.catch(error => {
|
|
41
|
+
notification.error({ message: 'An error occured while loading agents.'});
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
showModal(agentData){
|
|
46
|
+
this.setState({setIsModalOpen: true, agentData: agentData});
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
closeModal(){
|
|
50
|
+
this.setState({setIsModalOpen: false});
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
filterCities = (searchStr) => {
|
|
55
|
+
const allAgents:Agent[] = this.state.allAgents;
|
|
56
|
+
|
|
57
|
+
if(searchStr == undefined){
|
|
58
|
+
this.resetAgents();
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
const agents:Agent[] = allAgents.filter(a => a.state == searchStr);
|
|
62
|
+
const results = agents.map(a => a.city);
|
|
63
|
+
this.setState({cities: results});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
filterStates= (searchStr) => {
|
|
68
|
+
const allAgents:Agent[] = this.state.allAgents;
|
|
69
|
+
|
|
70
|
+
if(searchStr == undefined){
|
|
71
|
+
this.resetAgents();
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const agents:Agent[] = allAgents.filter(a => a.city == searchStr);
|
|
76
|
+
const results = agents.map(a => a.state);
|
|
77
|
+
this.setState({states: results});
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
resetAgents(){
|
|
81
|
+
const allAgents:Agent[] = this.state.allAgents;
|
|
82
|
+
const states = allAgents.filter(a => a.state != null).map(a => a.state);
|
|
83
|
+
const cities = allAgents.filter(a => a.city != null).map(a => a.city);
|
|
84
|
+
this.setState({states, cities});
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
findAgents = (formValues) => {
|
|
88
|
+
const allAgents:Agent[] = this.state.allAgents;
|
|
89
|
+
const agents = allAgents.filter(a =>
|
|
90
|
+
(formValues.state == undefined || a.state === formValues.state) &&
|
|
91
|
+
(formValues.city == undefined || a.city === formValues.city));
|
|
92
|
+
this.setState({agents, showAgentsResults: true})
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
render(){
|
|
97
|
+
const {agents, states, cities, agentData} = this.state;
|
|
98
|
+
return (
|
|
99
|
+
<div id="contact-agents-page">
|
|
100
|
+
<Headline bannerImage={bannerPath} breadcrumbs={breadcrumbs} title="CONTACT AGENTS"/>
|
|
101
|
+
|
|
102
|
+
<div id="contact-agents-page_body">
|
|
103
|
+
<div id="find-agents">
|
|
104
|
+
<div id="find-agents_header"><span>Get Your City</span></div>
|
|
105
|
+
<div id="find-agents_form">
|
|
106
|
+
<ContactAgentsForm
|
|
107
|
+
states={states}
|
|
108
|
+
cities={cities}
|
|
109
|
+
findAgents={this.findAgents}
|
|
110
|
+
filterCities={this.filterCities}
|
|
111
|
+
filterStates={this.filterStates}/>
|
|
112
|
+
</div>
|
|
113
|
+
</div>
|
|
114
|
+
|
|
115
|
+
<div id="agents-list">
|
|
116
|
+
<Row gutter={[20, 20]}>
|
|
117
|
+
{
|
|
118
|
+
agents.map((agent:Agent) => (
|
|
119
|
+
<Col xs={24} sm={24} md={12} lg={6}>
|
|
120
|
+
<Card
|
|
121
|
+
hoverable
|
|
122
|
+
cover={<img alt={agent.name} src={agent.image} />}
|
|
123
|
+
>
|
|
124
|
+
<Meta title={agent.name} description={
|
|
125
|
+
<>
|
|
126
|
+
<div className="agent-details">
|
|
127
|
+
<Row gutter={[20, 20]} align="middle">
|
|
128
|
+
<Col span={24}>
|
|
129
|
+
<Icon path={mdiMapMarker} size="15px" />
|
|
130
|
+
<span>{agent.address}</span>
|
|
131
|
+
</Col>
|
|
132
|
+
<Col span={24}>
|
|
133
|
+
<Icon path={mdiPhoneInTalkOutline} size="15px" />
|
|
134
|
+
<span>{agent.phone}</span>
|
|
135
|
+
</Col>
|
|
136
|
+
<Col span={24}>
|
|
137
|
+
<Icon path={mdiWhatsapp} size="15px" />
|
|
138
|
+
<span>{agent.whatsapp}</span>
|
|
139
|
+
</Col>
|
|
140
|
+
<Col span={24}>
|
|
141
|
+
<Icon path={mdiEmailOutline} size="15px" />
|
|
142
|
+
<span>{agent.email}</span>
|
|
143
|
+
</Col>
|
|
144
|
+
</Row>
|
|
145
|
+
</div>
|
|
146
|
+
<Button color="primary" variant="outlined" className="more-info-button"
|
|
147
|
+
onClick={()=>this.showModal(agent)}>
|
|
148
|
+
More info
|
|
149
|
+
</Button>
|
|
150
|
+
</>
|
|
151
|
+
} />
|
|
152
|
+
</Card>
|
|
153
|
+
</Col>
|
|
154
|
+
))
|
|
155
|
+
}
|
|
156
|
+
</Row>
|
|
157
|
+
</div>
|
|
158
|
+
|
|
159
|
+
<Modal title={
|
|
160
|
+
<>
|
|
161
|
+
<img src={agentData?.image}/>
|
|
162
|
+
<span> {agentData.name} </span>
|
|
163
|
+
</>
|
|
164
|
+
} open={this.state.setIsModalOpen} onCancel={()=>this.closeModal()} footer={null} width={350} centered className="agent-full-details">
|
|
165
|
+
<Row gutter={[10,10]}>
|
|
166
|
+
<Col span={12}> <label>Agent Name</label> </Col>
|
|
167
|
+
<Col span={12}> <span> {agentData.name} </span></Col>
|
|
168
|
+
<Col span={12}> <label>State</label> </Col>
|
|
169
|
+
<Col span={12}> <span> {agentData.state} </span></Col>
|
|
170
|
+
<Col span={12}> <label>Address</label> </Col>
|
|
171
|
+
<Col span={12}> <span> {agentData.address} </span></Col>
|
|
172
|
+
<Col span={12}> <label>Tel</label> </Col>
|
|
173
|
+
<Col span={12}> <span> {agentData.phone} </span></Col>
|
|
174
|
+
<Col span={12}> <label>Email</label> </Col>
|
|
175
|
+
<Col span={12}> <span> {agentData.email} </span></Col>
|
|
176
|
+
</Row>
|
|
177
|
+
{/* google maps */}
|
|
178
|
+
</Modal>
|
|
179
|
+
</div>
|
|
180
|
+
</div>
|
|
181
|
+
)
|
|
182
|
+
}
|
|
183
|
+
}
|
|
15
184
|
|
|
16
185
|
export default ContactAgentsPage;
|
|
@@ -83,25 +83,25 @@ const ContactUsPage = React.FC = () => {
|
|
|
83
83
|
<TextArea rows={4} placeholder="Write Here"/>
|
|
84
84
|
</Form.Item>
|
|
85
85
|
|
|
86
|
-
<
|
|
86
|
+
<Flex align="center" justify="center">
|
|
87
87
|
<Button type="primary" htmlType="submit">
|
|
88
88
|
Submit
|
|
89
89
|
</Button>
|
|
90
|
-
</
|
|
90
|
+
</Flex>
|
|
91
91
|
|
|
92
92
|
</Form>
|
|
93
93
|
</div>
|
|
94
94
|
</div>
|
|
95
95
|
|
|
96
96
|
<div id="contact-us-page_footer">
|
|
97
|
-
<Row gutter={29}>
|
|
98
|
-
<Col
|
|
97
|
+
<Row gutter={[29, 20]} >
|
|
98
|
+
<Col xs={24} sm={24} lg={12}>
|
|
99
99
|
<div>
|
|
100
100
|
<label>Contact Us</label>
|
|
101
101
|
<span>feedback@gd.my</span>
|
|
102
102
|
</div>
|
|
103
103
|
</Col>
|
|
104
|
-
<Col
|
|
104
|
+
<Col xs={24} sm={24} lg={12}>
|
|
105
105
|
<div>
|
|
106
106
|
<label>Connect with Us</label>
|
|
107
107
|
<Space size={29}>
|