iceholidays-frontend 0.2.0 → 0.4.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/application.sass.scss +1588 -0
- data/app/assets/stylesheets/iceholidays/frontend/common.scss +233 -0
- data/app/assets/stylesheets/iceholidays/frontend/layout.scss +188 -0
- data/app/assets/stylesheets/iceholidays/frontend/utils/_antd_overrides.scss +107 -0
- data/app/assets/stylesheets/iceholidays/frontend/utils/_variables.scss +3 -0
- data/app/assets/stylesheets/iceholidays/frontend/widgets/filter_pills.scss +45 -0
- data/app/assets/stylesheets/iceholidays/frontend/widgets/search_bar.scss +112 -0
- data/app/controllers/iceholidays/frontend/application_controller.rb +1 -0
- data/app/controllers/iceholidays/frontend/site_controller.rb +32 -0
- data/app/javascript/api-services/banners-api.service.ts +28 -0
- data/app/javascript/api-services/locations-api.service.ts +49 -0
- data/app/javascript/api-services/search-api.service.ts +16 -0
- data/app/javascript/api-services/series-api.service.ts +44 -0
- data/app/javascript/api-services/testimonials-api.service.ts +27 -0
- data/app/javascript/interfaces/banner.interface.ts +10 -0
- data/app/javascript/interfaces/country.interface.ts +18 -0
- data/app/javascript/interfaces/itinerary.interface.ts +18 -0
- data/app/javascript/interfaces/testimonial.interface.ts +6 -0
- data/app/javascript/react/App.tsx +32 -0
- data/app/javascript/react/components/Destinations.tsx +67 -165
- data/app/javascript/react/components/Testimonials.tsx +75 -48
- data/app/javascript/react/components/shared/Headline.tsx +29 -0
- data/app/javascript/react/components/shared/Postcard.tsx +31 -0
- data/app/javascript/react/components/shared/RibbonSection.tsx +21 -0
- data/app/javascript/react/components/shared/SlickButtonFix.tsx +19 -0
- data/app/javascript/react/index.js +3 -5
- data/app/javascript/react/layouts/MainFooter.tsx +72 -0
- data/app/javascript/react/layouts/MainHeader.tsx +45 -0
- data/app/javascript/react/layouts/MainLayout.tsx +21 -0
- data/app/javascript/react/pages/AboutUsPage.tsx +95 -0
- data/app/javascript/react/pages/BlogPage.tsx +79 -0
- data/app/javascript/react/pages/BlogShowPage.tsx +43 -0
- data/app/javascript/react/pages/ContactAgentsPage.tsx +16 -0
- data/app/javascript/react/pages/ContactUsPage.tsx +122 -0
- data/app/javascript/react/pages/CountriesPage.tsx +62 -0
- data/app/javascript/react/pages/Homepage.tsx +90 -0
- data/app/javascript/react/pages/ListingPage.tsx +246 -0
- data/app/javascript/react/pages/ShowPage.tsx +397 -0
- data/app/javascript/react/widgets/FilterPills.tsx +77 -0
- data/app/javascript/react/widgets/SearchBarWidget.tsx +42 -0
- data/app/views/iceholidays/frontend/site/index.html.erb +1 -24
- data/app/views/layouts/iceholidays/frontend/application.html.erb +3 -7
- data/config/routes.rb +9 -0
- data/lib/iceholidays/frontend/engine.rb +11 -4
- data/lib/iceholidays/frontend/version.rb +1 -1
- data/public/iceholidays-assets/application.css +1873 -0
- data/public/iceholidays-assets/application.js +430 -0
- data/public/iceholidays-assets/application.js.map +7 -0
- data/public/iceholidays-assets/images/8D7N.png +0 -0
- data/public/iceholidays-assets/images/about_us.png +0 -0
- data/public/iceholidays-assets/images/about_us2.png +0 -0
- data/public/iceholidays-assets/images/banner_arrow.png +0 -0
- data/public/iceholidays-assets/images/banner_right_arrow.png +0 -0
- data/public/iceholidays-assets/images/blog.png +0 -0
- data/public/iceholidays-assets/images/blog1.png +0 -0
- data/public/iceholidays-assets/images/certificate1.png +0 -0
- data/public/iceholidays-assets/images/certificate2.png +0 -0
- data/public/iceholidays-assets/images/china_southern_airlines.png +0 -0
- data/public/iceholidays-assets/images/china_southern_airlines_icon.png +0 -0
- data/public/iceholidays-assets/images/competitiveness.png +0 -0
- data/public/iceholidays-assets/images/contact_agents.png +0 -0
- data/public/iceholidays-assets/images/contact_us.png +0 -0
- data/public/iceholidays-assets/images/contact_us_form.png +0 -0
- data/public/iceholidays-assets/images/ethical.png +0 -0
- data/public/iceholidays-assets/images/hw_logo.png +0 -0
- data/public/iceholidays-assets/images/innovative.png +0 -0
- data/public/iceholidays-assets/images/plane.png +0 -0
- data/public/iceholidays-assets/images/social/ico_fb.png +0 -0
- data/public/iceholidays-assets/images/social/ico_ig.png +0 -0
- data/public/iceholidays-assets/images/social/ico_twitter.png +0 -0
- data/public/iceholidays-assets/images/social/ico_yt.png +0 -0
- data/public/iceholidays-assets/images/social.png +0 -0
- data/public/iceholidays-assets/images/tour1.png +0 -0
- metadata +96 -104
- data/app/assets/builds/iceholidays/frontend/5star-GEMYV5WA.digested.png +0 -0
- data/app/assets/builds/iceholidays/frontend/Frame71-U6FKYUGB.digested.png +0 -0
- data/app/assets/builds/iceholidays/frontend/Layer_1-24HTXUKI.digested.png +0 -0
- data/app/assets/builds/iceholidays/frontend/Rectangle49-SVQRLXW6.digested.png +0 -0
- data/app/assets/builds/iceholidays/frontend/africa-HBPEOBHM.digested.png +0 -0
- data/app/assets/builds/iceholidays/frontend/application.js +0 -293
- data/app/assets/builds/iceholidays/frontend/application.js.map +0 -7
- data/app/assets/builds/iceholidays/frontend/banner1-OM6SQ5GW.digested.png +0 -0
- data/app/assets/builds/iceholidays/frontend/banner2-BWOLYVUE.digested.png +0 -0
- data/app/assets/builds/iceholidays/frontend/china-DX6D6FE2.digested.png +0 -0
- data/app/assets/builds/iceholidays/frontend/china2-FESATHUH.digested.png +0 -0
- data/app/assets/builds/iceholidays/frontend/guangzhou-JGSVPIYY.digested.png +0 -0
- data/app/assets/builds/iceholidays/frontend/guilin-AXXU7K32.digested.png +0 -0
- data/app/assets/builds/iceholidays/frontend/harbin-2YJL7HHH.digested.png +0 -0
- data/app/assets/builds/iceholidays/frontend/hongkong-IPUEZ35P.digested.png +0 -0
- data/app/assets/builds/iceholidays/frontend/inner_mongolia-EURVGQVT.digested.png +0 -0
- data/app/assets/builds/iceholidays/frontend/jiangxi-DTEOQGIY.digested.png +0 -0
- data/app/assets/builds/iceholidays/frontend/kenya-F5ZJOIBS.digested.png +0 -0
- data/app/assets/builds/iceholidays/frontend/kenya2-CCJWJDUN.digested.png +0 -0
- data/app/assets/builds/iceholidays/frontend/kunming-OCHNG2UW.digested.png +0 -0
- data/app/assets/builds/iceholidays/frontend/slikroad-CVUSDDRO.digested.png +0 -0
- data/app/assets/builds/iceholidays/frontend/southafrica-HBPEOBHM.digested.png +0 -0
- data/app/assets/builds/iceholidays/frontend/tanzania-VJSRMTCY.digested.png +0 -0
- data/app/assets/builds/iceholidays/frontend/uganda-H4JWFN3A.digested.png +0 -0
- data/app/assets/stylesheets/iceholidays/frontend/application.scss +0 -850
- data/app/javascript/react/components/Homepage.tsx +0 -16
- data/app/javascript/react/components/HomepageBanner.tsx +0 -54
- data/app/views/layouts/iceholidays/frontend/shared/_footer.html.erb +0 -42
- data/app/views/layouts/iceholidays/frontend/shared/_header.html.erb +0 -20
- /data/{app/assets/images/iceholidays/frontend → public/iceholidays-assets/images}/5star.png +0 -0
- /data/{app/assets/images/iceholidays/frontend → public/iceholidays-assets/images}/Frame71.png +0 -0
- /data/{app/assets/images/iceholidays/frontend → public/iceholidays-assets/images}/Group_71.png +0 -0
- /data/{app/assets/images/iceholidays/frontend → public/iceholidays-assets/images}/Layer_1.png +0 -0
- /data/{app/assets/images/iceholidays/frontend → public/iceholidays-assets/images}/Rectangle49.png +0 -0
- /data/{app/assets/images/iceholidays/frontend → public/iceholidays-assets/images}/TS_Logo.png +0 -0
- /data/{app/assets/images/iceholidays/frontend → public/iceholidays-assets/images}/about_st_bg.png +0 -0
- /data/{app/assets/images/iceholidays/frontend → public/iceholidays-assets/images}/africa.png +0 -0
- /data/{app/assets/images/iceholidays/frontend → public/iceholidays-assets/images}/banner1.png +0 -0
- /data/{app/assets/images/iceholidays/frontend → public/iceholidays-assets/images}/banner2.png +0 -0
- /data/{app/assets/images/iceholidays/frontend → public/iceholidays-assets/images}/china.png +0 -0
- /data/{app/assets/images/iceholidays/frontend → public/iceholidays-assets/images}/china2.png +0 -0
- /data/{app/assets/builds/iceholidays/frontend/chongqing-CCJWJDUN.digested.png → public/iceholidays-assets/images/china_listings_cover.png} +0 -0
- /data/{app/assets/images/iceholidays/frontend → public/iceholidays-assets/images}/chongqing.png +0 -0
- /data/{app/assets/images/iceholidays/frontend/cover_img.jpeg → public/iceholidays-assets/images/cover_img.jpg} +0 -0
- /data/{app/assets/images/iceholidays/frontend/feature.jpeg → public/iceholidays-assets/images/feature.jpg} +0 -0
- /data/{app/assets/images/iceholidays/frontend → public/iceholidays-assets/images}/guangzhou.png +0 -0
- /data/{app/assets/images/iceholidays/frontend → public/iceholidays-assets/images}/guilin.png +0 -0
- /data/{app/assets/images/iceholidays/frontend → public/iceholidays-assets/images}/harbin.png +0 -0
- /data/{app/assets/images/iceholidays/frontend → public/iceholidays-assets/images}/hongkong.png +0 -0
- /data/{app/assets/images/iceholidays/frontend → public/iceholidays-assets/images}/inner_mongolia.png +0 -0
- /data/{app/assets/images/iceholidays/frontend → public/iceholidays-assets/images}/jiangxi.png +0 -0
- /data/{app/assets/images/iceholidays/frontend → public/iceholidays-assets/images}/kenya.png +0 -0
- /data/{app/assets/images/iceholidays/frontend → public/iceholidays-assets/images}/kenya2.png +0 -0
- /data/{app/assets/images/iceholidays/frontend → public/iceholidays-assets/images}/kunming.png +0 -0
- /data/{app/assets/images/iceholidays/frontend → public/iceholidays-assets/images}/logo_container.png +0 -0
- /data/{app/assets/images/iceholidays/frontend → public/iceholidays-assets/images}/logomark.png +0 -0
- /data/{app/assets/images/iceholidays/frontend → public/iceholidays-assets/images}/slikroad.png +0 -0
- /data/{app/assets/images/iceholidays/frontend → public/iceholidays-assets/images}/southafrica.png +0 -0
- /data/{app/assets/images/iceholidays/frontend → public/iceholidays-assets/images}/tanzania.png +0 -0
- /data/{app/assets/images/iceholidays/frontend → public/iceholidays-assets/images}/uganda.png +0 -0
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import Headline from "../components/shared/Headline";
|
|
3
|
+
import { Button, Col, Flex, Form, Input, Row, Select, Space } from "antd";
|
|
4
|
+
import { mdiFacebook, mdiInstagram, mdiTwitter, mdiYoutube } from "@mdi/js";
|
|
5
|
+
import Icon from "@mdi/react";
|
|
6
|
+
const { TextArea } = Input;
|
|
7
|
+
|
|
8
|
+
const bannerPath = '/iceholidays-assets/images/contact_us.png';
|
|
9
|
+
const breadcrumbs = [
|
|
10
|
+
{ title: 'Home' },
|
|
11
|
+
{ title: 'Contact Us' }
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
const ContactUsPage = React.FC = () => {
|
|
15
|
+
const [form] = Form.useForm();
|
|
16
|
+
|
|
17
|
+
return (
|
|
18
|
+
<div id="contact-us-page">
|
|
19
|
+
<Headline bannerImage={bannerPath} breadcrumbs={breadcrumbs} title="contact us"/>
|
|
20
|
+
|
|
21
|
+
<div id="contact-us-page_body">
|
|
22
|
+
<img src="/iceholidays-assets/images/contact_us_form.png"/>
|
|
23
|
+
|
|
24
|
+
<div id="contact-us-form">
|
|
25
|
+
<div id="contact-us-form_header">
|
|
26
|
+
<h2>Get in touch</h2>
|
|
27
|
+
<span>Send us your enquiry</span>
|
|
28
|
+
</div>
|
|
29
|
+
<Form
|
|
30
|
+
form={form}
|
|
31
|
+
autoComplete="off"
|
|
32
|
+
layout="vertical"
|
|
33
|
+
variant="filled"
|
|
34
|
+
>
|
|
35
|
+
<Form.Item label="Enter Name" name="name">
|
|
36
|
+
<Input placeholder="Enter Here" />
|
|
37
|
+
</Form.Item>
|
|
38
|
+
|
|
39
|
+
<Row gutter={20}>
|
|
40
|
+
<Col span={12}>
|
|
41
|
+
<Form.Item label="Enter Email" name="email">
|
|
42
|
+
<Input placeholder="Enter Here" />
|
|
43
|
+
</Form.Item>
|
|
44
|
+
</Col>
|
|
45
|
+
<Col span={12}>
|
|
46
|
+
<Form.Item label="Enter Phone Number" name="phoneNumber">
|
|
47
|
+
<Input placeholder="Enter Here" />
|
|
48
|
+
</Form.Item>
|
|
49
|
+
</Col>
|
|
50
|
+
</Row>
|
|
51
|
+
|
|
52
|
+
<Form.Item label="Select State" name="state">
|
|
53
|
+
<Select
|
|
54
|
+
placeholder="Please Select"
|
|
55
|
+
defaultValue="lucy"
|
|
56
|
+
options={[
|
|
57
|
+
{ value: 'jack', label: 'Jack' },
|
|
58
|
+
]}
|
|
59
|
+
/>
|
|
60
|
+
</Form.Item>
|
|
61
|
+
|
|
62
|
+
<Form.Item label="Select Area" name="area">
|
|
63
|
+
<Select
|
|
64
|
+
placeholder="Please Select"
|
|
65
|
+
defaultValue="lucy"
|
|
66
|
+
options={[
|
|
67
|
+
{ value: 'jack', label: 'Jack' },
|
|
68
|
+
]}
|
|
69
|
+
/>
|
|
70
|
+
</Form.Item>
|
|
71
|
+
|
|
72
|
+
<Form.Item label="Select Subject" name="subject">
|
|
73
|
+
<Select
|
|
74
|
+
placeholder="Please Select"
|
|
75
|
+
defaultValue="lucy"
|
|
76
|
+
options={[
|
|
77
|
+
{ value: 'jack', label: 'Jack' },
|
|
78
|
+
]}
|
|
79
|
+
/>
|
|
80
|
+
</Form.Item>
|
|
81
|
+
|
|
82
|
+
<Form.Item label="Write your message" name="message">
|
|
83
|
+
<TextArea rows={4} placeholder="Write Here"/>
|
|
84
|
+
</Form.Item>
|
|
85
|
+
|
|
86
|
+
<Form.Item wrapperCol={{ offset: 10, span: 14 }}>
|
|
87
|
+
<Button type="primary" htmlType="submit">
|
|
88
|
+
Submit
|
|
89
|
+
</Button>
|
|
90
|
+
</Form.Item>
|
|
91
|
+
|
|
92
|
+
</Form>
|
|
93
|
+
</div>
|
|
94
|
+
</div>
|
|
95
|
+
|
|
96
|
+
<div id="contact-us-page_footer">
|
|
97
|
+
<Row gutter={29}>
|
|
98
|
+
<Col span={12}>
|
|
99
|
+
<div>
|
|
100
|
+
<label>Contact Us</label>
|
|
101
|
+
<span>feedback@gd.my</span>
|
|
102
|
+
</div>
|
|
103
|
+
</Col>
|
|
104
|
+
<Col span={12}>
|
|
105
|
+
<div>
|
|
106
|
+
<label>Connect with Us</label>
|
|
107
|
+
<Space size={29}>
|
|
108
|
+
<Icon path={mdiFacebook} size={1} />
|
|
109
|
+
<Icon path={mdiInstagram} size={1} />
|
|
110
|
+
<Icon path={mdiTwitter} size={1} />
|
|
111
|
+
<Icon path={mdiYoutube} size={1} />
|
|
112
|
+
<img src="/iceholidays-assets/images/social.png" className="social-icon"/>
|
|
113
|
+
</Space>
|
|
114
|
+
</div>
|
|
115
|
+
</Col>
|
|
116
|
+
</Row>
|
|
117
|
+
</div>
|
|
118
|
+
</div>
|
|
119
|
+
);
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
export default ContactUsPage;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import Headline from "../components/shared/Headline";
|
|
3
|
+
import LocationsApi from "../../api-services/locations-api.service";
|
|
4
|
+
import { Col, Flex, notification, Row } from "antd";
|
|
5
|
+
import { Country } from "../../interfaces/country.interface";
|
|
6
|
+
import Postcard from "../components/shared/Postcard";
|
|
7
|
+
|
|
8
|
+
const bannerPath = '/iceholidays-assets/images/about_us.png';
|
|
9
|
+
const breadcrumbs = [
|
|
10
|
+
{ title: 'Home' },
|
|
11
|
+
{ title: 'Countries' }
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
export default class CountriesPage extends React.Component {
|
|
16
|
+
locationsApi = new LocationsApi;
|
|
17
|
+
|
|
18
|
+
state = {
|
|
19
|
+
countries: []
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
componentDidMount() {
|
|
23
|
+
this.locationsApi.getCountries()
|
|
24
|
+
.then(locationsData => {
|
|
25
|
+
this.setState({countries: locationsData})
|
|
26
|
+
})
|
|
27
|
+
.catch(error => {
|
|
28
|
+
notification.error({ message: 'An error occured while loading countries.'});
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
render(){
|
|
34
|
+
return (
|
|
35
|
+
<div id="countries-page">
|
|
36
|
+
<Headline bannerImage={bannerPath} breadcrumbs={breadcrumbs} title="Countries"/>
|
|
37
|
+
|
|
38
|
+
<div id="countries-page_body">
|
|
39
|
+
<div id="introduction">
|
|
40
|
+
<Flex vertical gap={24}>
|
|
41
|
+
<div id="introduction_header"> <img src="/iceholidays-assets/images/logomark.png"/> <span> The Signature Tours </span> </div>
|
|
42
|
+
<div id="introduction_body">
|
|
43
|
+
<p>Immerse yourself in the art of travel with The Signature Tour. Every experience is meticulously designed to create memories that last a lifetime.
|
|
44
|
+
Our journeys go beyond the ordinary, offering experiences that are as unique as you are.</p>
|
|
45
|
+
|
|
46
|
+
<p>From charming accommodations to curated cultural encounters, every aspect is thoughtfully crafted to elevate your travel experience. At The Signature Tour, we believe in the S-Tour’s philosophy —where every moment is a signature memory.</p>
|
|
47
|
+
</div>
|
|
48
|
+
</Flex>
|
|
49
|
+
</div>
|
|
50
|
+
|
|
51
|
+
<h2> Countries </h2>
|
|
52
|
+
<div className="postcards">
|
|
53
|
+
{
|
|
54
|
+
this.state.countries.map((country:Country, index) => <Postcard key={index} link={`/app/listing?keyword=${country.name}`} image={country.cover} name={country.name} tourCount={country.tourCount}/>)
|
|
55
|
+
}
|
|
56
|
+
</div>
|
|
57
|
+
</div>
|
|
58
|
+
|
|
59
|
+
</div>
|
|
60
|
+
)
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import Testimonials from "../components/Testimonials";
|
|
3
|
+
import Destinations from "../components/Destinations";
|
|
4
|
+
import SearchBarWidget from "../widgets/SearchBarWidget";
|
|
5
|
+
import { Carousel, notification } from "antd";
|
|
6
|
+
import SlickButtonFix from "../components/shared/SlickButtonFix";
|
|
7
|
+
import BannersApi from "../../api-services/banners-api.service";
|
|
8
|
+
import { Banner } from "../../interfaces/banner.interface";
|
|
9
|
+
|
|
10
|
+
export default class Homepage extends React.Component {
|
|
11
|
+
api = new BannersApi;
|
|
12
|
+
|
|
13
|
+
state = {
|
|
14
|
+
banners: []
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
componentDidMount() {
|
|
19
|
+
this.api.getBanners()
|
|
20
|
+
.then(bannersData => {
|
|
21
|
+
this.setState({banners: bannersData})
|
|
22
|
+
})
|
|
23
|
+
.catch(error => {
|
|
24
|
+
notification.error({ message: 'An error occured while loading banners.'});
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
render(){
|
|
29
|
+
const { banners } = this.state;
|
|
30
|
+
|
|
31
|
+
return (
|
|
32
|
+
<div id="homepage">
|
|
33
|
+
|
|
34
|
+
<SearchBarWidget/>
|
|
35
|
+
|
|
36
|
+
<div id="homepage_banner">
|
|
37
|
+
<Carousel autoplay arrows infinite={banners.length>1}
|
|
38
|
+
prevArrow={
|
|
39
|
+
<SlickButtonFix>
|
|
40
|
+
<img src="/iceholidays-assets/images/banner_arrow.png"/>
|
|
41
|
+
</SlickButtonFix>
|
|
42
|
+
}
|
|
43
|
+
nextArrow={
|
|
44
|
+
<SlickButtonFix>
|
|
45
|
+
<img src="/iceholidays-assets/images/banner_arrow.png" className="flip"/>
|
|
46
|
+
</SlickButtonFix>
|
|
47
|
+
}
|
|
48
|
+
>
|
|
49
|
+
{
|
|
50
|
+
banners.map((banner:Banner, index)=>{
|
|
51
|
+
return <a key={index} href={banner.url} target={banner.target} rel="nofollow">
|
|
52
|
+
<picture>
|
|
53
|
+
<source media="(min-width: 600px)" srcSet={banner.desktopImage} />
|
|
54
|
+
<source media="(max-width: 599px)" srcSet={banner.mobileImage} />
|
|
55
|
+
<img src={banner.desktopImage} alt={banner.title} />
|
|
56
|
+
</picture>
|
|
57
|
+
</a>
|
|
58
|
+
})
|
|
59
|
+
}
|
|
60
|
+
</Carousel>
|
|
61
|
+
</div>
|
|
62
|
+
|
|
63
|
+
<Destinations/>
|
|
64
|
+
<Testimonials/>
|
|
65
|
+
|
|
66
|
+
<div id="about-signature-tours" style={{background: "url('/iceholidays-assets/images/about_st_bg.png') no-repeat 70% 7%, linear-gradient(65.77deg, rgba(170, 133, 62, 0.5) 33.44%, rgba(249, 225, 151, 0.5) 67.37%)"}}>
|
|
67
|
+
<div>
|
|
68
|
+
<h1>ABOUT SIGNATURE TOURS</h1>
|
|
69
|
+
<p>
|
|
70
|
+
From charming accommodations to curated cultural encounters, every aspect is thoughtfully crafted to elevate your travel experience. At The Signature Tours, we believe in the S-Tour’s philosophy —where every moment is a signature memory.
|
|
71
|
+
</p>
|
|
72
|
+
<img src="/iceholidays-assets/images/Group_71.png"/>
|
|
73
|
+
<div id="about-st-feature">
|
|
74
|
+
<div style={{maxWidth: "449px"}}>
|
|
75
|
+
<p>Every experience is meticulously designed to create memories that last a lifetime. Our journeys go beyond the ordinary, offering experiences that are as unique as you are.</p>
|
|
76
|
+
</div>
|
|
77
|
+
<div id="feature">
|
|
78
|
+
<img src="/iceholidays-assets/images/feature.jpg"/>
|
|
79
|
+
<div id="st-brand">
|
|
80
|
+
<span>Signature Tours</span>
|
|
81
|
+
<img src="/iceholidays-assets/images/logomark.png" id="st-logo"/>
|
|
82
|
+
</div>
|
|
83
|
+
</div>
|
|
84
|
+
</div>
|
|
85
|
+
</div>
|
|
86
|
+
</div>
|
|
87
|
+
</div>
|
|
88
|
+
)
|
|
89
|
+
}
|
|
90
|
+
}
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
import React, { Component } from "react";
|
|
2
|
+
import { Badge, Breadcrumb, Button, Flex, Modal, Space, Select, Row, Col, notification } from "antd";
|
|
3
|
+
import FilterPills from "../widgets/FilterPills";
|
|
4
|
+
import { Link, useSearchParams } from "react-router-dom";
|
|
5
|
+
import { mdiDotsHorizontalCircleOutline, mdiFileDownload, mdiFilterVariant, mdiInformationOutline, mdiMapMarkerOutline } from "@mdi/js";
|
|
6
|
+
import Icon from "@mdi/react";
|
|
7
|
+
import Headline from "../components/shared/Headline";
|
|
8
|
+
import LocationsApi from "../../api-services/locations-api.service";
|
|
9
|
+
import { Country } from "../../interfaces/country.interface";
|
|
10
|
+
import SeriesApi from "../../api-services/series-api.service";
|
|
11
|
+
import { Itinerary } from "../../interfaces/itinerary.interface";
|
|
12
|
+
|
|
13
|
+
import createDOMPurify from 'dompurify'
|
|
14
|
+
|
|
15
|
+
const DOMPurify = createDOMPurify(window)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
const bannerPath = '/iceholidays-assets/images/china_listings_cover.png';
|
|
19
|
+
const breadcrumbs = [
|
|
20
|
+
{ title: 'Home' },
|
|
21
|
+
{ title: 'China' },
|
|
22
|
+
{ title: 'Chongqing' }
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
const legends = [
|
|
26
|
+
{ id: "guaranteed", label: "Guaranteed", color: "#DCB062" },
|
|
27
|
+
{ id: "selling-fast", label: "Selling Fast", color: "#23D1C0" }
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
const getColorByType = (type:string) => {
|
|
31
|
+
var legend = legends.find(l => l.id == type);
|
|
32
|
+
return legend ? legend.color : "#000000";
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function withSearchParams(Component) {
|
|
36
|
+
return props => <Component {...props} searchParams={useSearchParams()} />;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
class ListingPage extends React.Component <{searchParams}> {
|
|
40
|
+
locationsApi = new LocationsApi;
|
|
41
|
+
seriesApi = new SeriesApi;
|
|
42
|
+
|
|
43
|
+
state = {
|
|
44
|
+
countries: [],
|
|
45
|
+
selectedCountry: {cities: []},
|
|
46
|
+
keyword: "",
|
|
47
|
+
itineraries: [],
|
|
48
|
+
setIsModalOpen: false,
|
|
49
|
+
setIsDateModalOpen: false,
|
|
50
|
+
descriptionData: "",
|
|
51
|
+
departureDatesData: []
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
constructor(props:any){
|
|
55
|
+
super(props);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
componentDidMount() {
|
|
59
|
+
this.locationsApi.getCountries()
|
|
60
|
+
.then(locationsData => {
|
|
61
|
+
this.setState({countries: locationsData, selectedCountry: locationsData[0]})
|
|
62
|
+
})
|
|
63
|
+
.catch(error => {
|
|
64
|
+
notification.error({ message: 'An error occured while loading countries.'});
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
const [searchParams] = this.props.searchParams;
|
|
68
|
+
const keyword = searchParams.get('keyword');
|
|
69
|
+
this.setState({keyword: keyword})
|
|
70
|
+
|
|
71
|
+
this.getItineraries({keyword});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
getItineraries(searchParams){
|
|
75
|
+
this.seriesApi.getItineraries(searchParams)
|
|
76
|
+
.then(itinerariesData => {
|
|
77
|
+
this.setState({itineraries: itinerariesData})
|
|
78
|
+
})
|
|
79
|
+
.catch(error => {
|
|
80
|
+
notification.error({ message: 'An error occured while loading itineraries.'});
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
showModal(description){
|
|
85
|
+
this.setState({setIsModalOpen:true, descriptionData: description});
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
closeModal() {
|
|
89
|
+
this.setState({setIsModalOpen:false});
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
showDatesModal(dates) {
|
|
93
|
+
this.setState({setIsDateModalOpen:true, departureDatesData: dates});
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
closeDatesModalatesModal(){
|
|
97
|
+
this.setState({setIsDateModalOpen:false});
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
selectCountry(country){
|
|
101
|
+
const selectedCountry = this.state.countries.find((c:Country) => c.id == country);
|
|
102
|
+
if(selectedCountry){
|
|
103
|
+
this.setState({selectedCountry})
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
render(){
|
|
109
|
+
const {countries, selectedCountry, keyword, itineraries, descriptionData, departureDatesData } = this.state;
|
|
110
|
+
|
|
111
|
+
return <div id="listing-page">
|
|
112
|
+
|
|
113
|
+
<Headline bannerImage={bannerPath} breadcrumbs={breadcrumbs}>
|
|
114
|
+
<div id="listing-page_header">
|
|
115
|
+
<Flex justify="space-between" align="center">
|
|
116
|
+
<h1>{keyword}</h1>
|
|
117
|
+
<Select
|
|
118
|
+
className="country-filter"
|
|
119
|
+
suffixIcon={<Icon path={mdiFilterVariant} size={1} />}
|
|
120
|
+
defaultValue="china"
|
|
121
|
+
value={selectedCountry["name"]}
|
|
122
|
+
options={countries}
|
|
123
|
+
fieldNames={{label: 'name', value: 'id'}}
|
|
124
|
+
dropdownStyle={{padding: "15px 10px 15px 20px", borderRadius: "20px"}}
|
|
125
|
+
optionRender={(option) => (
|
|
126
|
+
<div className="country-filter_option"> {option.label} </div>
|
|
127
|
+
)}
|
|
128
|
+
onChange={(country)=>this.selectCountry(country)}
|
|
129
|
+
/>
|
|
130
|
+
</Flex>
|
|
131
|
+
</div>
|
|
132
|
+
</Headline>
|
|
133
|
+
|
|
134
|
+
<div id="listing-page_body">
|
|
135
|
+
<Space size={12} direction="vertical">
|
|
136
|
+
<FilterPills items={selectedCountry.cities} label="name" initialValue={{keyword}} selectFilter={(selected) => this.getItineraries(selected)}></FilterPills>
|
|
137
|
+
</Space>
|
|
138
|
+
|
|
139
|
+
<div id="legends">
|
|
140
|
+
<Space size={17}>
|
|
141
|
+
{
|
|
142
|
+
legends.map(legend => <Badge key={legend.id} color={legend.color} text={legend.label} />)
|
|
143
|
+
}
|
|
144
|
+
</Space>
|
|
145
|
+
</div>
|
|
146
|
+
|
|
147
|
+
<div id="tours">
|
|
148
|
+
<Flex vertical gap={30}>
|
|
149
|
+
{
|
|
150
|
+
itineraries.map((itinerary:Itinerary) => {
|
|
151
|
+
const departureDates = itinerary.departureDate.map(ddate => {
|
|
152
|
+
return {
|
|
153
|
+
type: itinerary.guranteedDepartureDates.includes(ddate) ? "guaranteed" : "",
|
|
154
|
+
date: ddate
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
return (
|
|
159
|
+
<Row className="tour" wrap={false}>
|
|
160
|
+
<Col flex="300px">
|
|
161
|
+
<div className="tour_image"> <img src={itinerary.images[0]}/> </div>
|
|
162
|
+
</Col>
|
|
163
|
+
<Col flex="auto">
|
|
164
|
+
<div className="tour_details">
|
|
165
|
+
<Space size={20} direction="vertical" style={{ display: 'flex' }}>
|
|
166
|
+
<Space size={10} direction="vertical">
|
|
167
|
+
<div className="tour_details_title"> {itinerary.caption} </div>
|
|
168
|
+
<div className="tour_details_subtitle"> {itinerary.otherCaption} </div>
|
|
169
|
+
<div className="tour_details_info">
|
|
170
|
+
<span onClick={()=>this.showModal(itinerary.description)}><Icon path={mdiInformationOutline} size={1}/></span>
|
|
171
|
+
</div>
|
|
172
|
+
<div>
|
|
173
|
+
<span className="tour_details_country"> <Icon path={mdiMapMarkerOutline} size="18px" /> {itinerary.country} </span>
|
|
174
|
+
<span className="tour_details_code"> <Icon path={mdiFileDownload} size="18px" /> {itinerary.code} </span>
|
|
175
|
+
</div>
|
|
176
|
+
</Space>
|
|
177
|
+
<div className="tour_details_dates">
|
|
178
|
+
<Space size={6} direction="vertical" style={{ display: 'flex' }}>
|
|
179
|
+
<label>Departure Date(s)</label>
|
|
180
|
+
<div className="date-selector">
|
|
181
|
+
{
|
|
182
|
+
departureDates && departureDates.map(ddate => <span style={{borderColor: getColorByType(ddate.type)}}> {ddate.date} </span>)
|
|
183
|
+
}
|
|
184
|
+
{
|
|
185
|
+
departureDates.length >= 9 && <div className="show-all-dates" onClick={()=>this.showDatesModal(departureDates)}> <Icon path={mdiDotsHorizontalCircleOutline} size="15px" /> Show All </div>
|
|
186
|
+
}
|
|
187
|
+
</div>
|
|
188
|
+
</Space>
|
|
189
|
+
</div>
|
|
190
|
+
</Space>
|
|
191
|
+
</div>
|
|
192
|
+
</Col>
|
|
193
|
+
<Col flex="210px">
|
|
194
|
+
<div className="tour_pricing">
|
|
195
|
+
<Space size={20} direction="vertical" align="center">
|
|
196
|
+
<Flex vertical>
|
|
197
|
+
<span>From</span>
|
|
198
|
+
<span className="price">{itinerary.priceCurrency} {itinerary.price}</span>
|
|
199
|
+
<span>All In</span>
|
|
200
|
+
</Flex>
|
|
201
|
+
<Link className="select-tour" to="/app/show">Select</Link>
|
|
202
|
+
</Space>
|
|
203
|
+
</div>
|
|
204
|
+
</Col>
|
|
205
|
+
</Row>
|
|
206
|
+
)
|
|
207
|
+
})
|
|
208
|
+
}
|
|
209
|
+
</Flex>
|
|
210
|
+
</div>
|
|
211
|
+
</div>
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
<Modal title="Description" open={this.state.setIsModalOpen} onCancel={()=>this.closeModal()} footer={null} width={1000} centered className="tour_details_description">
|
|
215
|
+
<div className="pre-wrap">{ <span dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(descriptionData) }} /> }</div>
|
|
216
|
+
</Modal>
|
|
217
|
+
|
|
218
|
+
<Modal title={
|
|
219
|
+
<Flex justify="space-between" align="center">
|
|
220
|
+
<div className="custom-modal-header-title"> Departure Date(s) </div>
|
|
221
|
+
<div className="custom-modal-header-legends">
|
|
222
|
+
<Space size={17}>
|
|
223
|
+
{
|
|
224
|
+
legends.map(legend => <Badge key={legend.id} color={legend.color} text={legend.label} />)
|
|
225
|
+
}
|
|
226
|
+
</Space>
|
|
227
|
+
</div>
|
|
228
|
+
</Flex>
|
|
229
|
+
} footer={
|
|
230
|
+
<Button>Confirm</Button>
|
|
231
|
+
}
|
|
232
|
+
open={this.state.setIsDateModalOpen} onCancel={()=>this.closeDatesModalatesModal()} width={940} centered className="tour_details_all_dates">
|
|
233
|
+
<div className="date-selector">
|
|
234
|
+
<Space size={8} wrap>
|
|
235
|
+
{
|
|
236
|
+
departureDatesData && departureDatesData.map((ddate:any) => <span style={{borderColor: getColorByType(ddate.type)}}> {ddate.date} </span>)
|
|
237
|
+
}
|
|
238
|
+
</Space>
|
|
239
|
+
</div>
|
|
240
|
+
</Modal>
|
|
241
|
+
</div>
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
export default withSearchParams(ListingPage);
|