iceholidays-frontend 0.3.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 +2194 -0
- data/app/assets/stylesheets/iceholidays/frontend/common.scss +317 -0
- data/app/assets/stylesheets/iceholidays/frontend/layout.scss +281 -0
- data/app/assets/stylesheets/iceholidays/frontend/utils/_antd_overrides.scss +122 -0
- data/app/assets/stylesheets/iceholidays/frontend/utils/_variables.scss +4 -0
- data/app/assets/stylesheets/iceholidays/frontend/widgets/filter_pills.scss +52 -0
- data/app/assets/stylesheets/iceholidays/frontend/widgets/search_bar.scss +116 -0
- data/app/controllers/iceholidays/frontend/posts_controller.rb +14 -0
- data/app/controllers/iceholidays/frontend/site_controller.rb +32 -0
- data/app/javascript/api-services/agents-api.service.ts +33 -0
- data/app/javascript/api-services/banners-api.service.ts +28 -0
- data/app/javascript/api-services/locations-api.service.ts +71 -0
- data/app/javascript/api-services/search-api.service.ts +16 -0
- data/app/javascript/api-services/series-api.service.ts +64 -0
- data/app/javascript/api-services/testimonials-api.service.ts +27 -0
- data/app/javascript/interfaces/agent.interface.ts +11 -0
- data/app/javascript/interfaces/banner.interface.ts +10 -0
- data/app/javascript/interfaces/country.interface.ts +19 -0
- data/app/javascript/interfaces/itinerary.interface.ts +111 -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 +84 -143
- data/app/javascript/react/components/PriceDetails.tsx +146 -0
- data/app/javascript/react/components/Testimonials.tsx +68 -61
- data/app/javascript/react/components/shared/ContactAgentsForm.tsx +44 -0
- data/app/javascript/react/components/shared/Headline.tsx +30 -0
- data/app/javascript/react/components/shared/LocationDropdown.tsx +34 -0
- data/app/javascript/react/components/shared/LocationPostcards.tsx +52 -0
- data/app/javascript/react/components/shared/RibbonSection.tsx +21 -0
- data/app/javascript/react/index.js +3 -5
- data/app/javascript/react/layouts/MainFooter.tsx +97 -0
- data/app/javascript/react/layouts/MainHeader.tsx +83 -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 +81 -0
- data/app/javascript/react/pages/BlogShowPage.tsx +43 -0
- data/app/javascript/react/pages/ContactAgentsPage.tsx +185 -0
- data/app/javascript/react/pages/ContactUsPage.tsx +122 -0
- data/app/javascript/react/pages/CountriesPage.tsx +57 -0
- data/app/javascript/react/pages/Homepage.tsx +100 -0
- data/app/javascript/react/pages/ListingPage.tsx +292 -0
- data/app/javascript/react/pages/ShowPage.tsx +402 -0
- data/app/javascript/react/widgets/FilterPills.tsx +111 -0
- data/app/javascript/react/widgets/SearchBarWidget.tsx +58 -0
- data/app/views/iceholidays/frontend/posts/index.html.erb +9 -0
- data/app/views/iceholidays/frontend/posts/show.html.erb +2 -0
- data/app/views/iceholidays/frontend/site/index.html.erb +1 -24
- data/app/views/layouts/iceholidays/frontend/application.html.erb +2 -6
- data/config/routes.rb +10 -0
- data/lib/iceholidays/frontend/version.rb +1 -1
- data/public/iceholidays-assets/application.css +2638 -0
- data/public/iceholidays-assets/application.js +212 -651
- 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/about_us.png +0 -0
- data/public/iceholidays-assets/images/about_us2.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/destinations_logo.png +0 -0
- data/public/iceholidays-assets/images/ethical.png +0 -0
- data/public/iceholidays-assets/images/footer-bg_mobile.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/logo_mobile.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
- metadata +74 -71
- data/app/assets/stylesheets/iceholidays/frontend/application.scss +0 -904
- data/app/javascript/react/components/Homepage.tsx +0 -15
- data/app/javascript/react/components/HomepageBanner.tsx +0 -62
- 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/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/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/uganda.png +0 -0
- /data/public/iceholidays-assets/images/{Group_71.png → about-us_logo.png} +0 -0
- /data/public/iceholidays-assets/images/{chongqing.png → china_listings_cover.png} +0 -0
- /data/public/iceholidays-assets/images/{logo_container.png → logo.png} +0 -0
|
@@ -1,138 +1,75 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
|
3
|
-
import { Tabs, TabsProps } from "antd";
|
|
1
|
+
import { notification, Select, Tabs, TabsProps } from "antd";
|
|
4
2
|
import React from "react";
|
|
3
|
+
import LocationsApi from "../../api-services/locations-api.service";
|
|
4
|
+
import { Country } from "../../interfaces/country.interface";
|
|
5
|
+
import { mdiFilterVariant, mdiMenuRight } from "@mdi/js";
|
|
6
|
+
import Icon from "@mdi/react";
|
|
7
|
+
import { Link } from "react-router-dom";
|
|
8
|
+
import LocationPostcards from "./shared/LocationPostcards";
|
|
9
|
+
import LocationDropdown from "./shared/LocationDropdown";
|
|
5
10
|
|
|
6
|
-
const countries = [
|
|
7
|
-
{
|
|
8
|
-
name: "Africa",
|
|
9
|
-
image: "iceholidays-assets/images/africa.png",
|
|
10
|
-
topCities: [{
|
|
11
|
-
name: "Kenya",
|
|
12
|
-
image: "iceholidays-assets/images/kenya.png",
|
|
13
|
-
},
|
|
14
|
-
{
|
|
15
|
-
name: "South Africa",
|
|
16
|
-
image: "iceholidays-assets/images/southafrica.png",
|
|
17
|
-
},
|
|
18
|
-
{
|
|
19
|
-
name: "Tanzania",
|
|
20
|
-
image: "iceholidays-assets/images/tanzania.png",
|
|
21
|
-
},
|
|
22
|
-
{
|
|
23
|
-
name: "Uaganda",
|
|
24
|
-
image: "iceholidays-assets/images/uganda.png",
|
|
25
|
-
}]
|
|
26
|
-
},
|
|
27
|
-
{
|
|
28
|
-
name: "China",
|
|
29
|
-
image: "iceholidays-assets/images/china.png",
|
|
30
|
-
topCities: [{
|
|
31
|
-
name: "Chong Qing",
|
|
32
|
-
image: "iceholidays-assets/images/china.png",
|
|
33
|
-
},
|
|
34
|
-
{
|
|
35
|
-
name: "Guangzhou",
|
|
36
|
-
image: "iceholidays-assets/images/guangzhou.png",
|
|
37
|
-
},
|
|
38
|
-
{
|
|
39
|
-
name: "Guilin",
|
|
40
|
-
image: "iceholidays-assets/images/guilin.png",
|
|
41
|
-
},
|
|
42
|
-
{
|
|
43
|
-
name: "Hongkong",
|
|
44
|
-
image: "iceholidays-assets/images/hongkong.png",
|
|
45
|
-
}],
|
|
46
|
-
moreCities: [
|
|
47
|
-
"Leizhou", "Ningxia", "Qinghai", "Shanghai", "Tibet", "Xiamen", "Yunnan"
|
|
48
|
-
],
|
|
49
|
-
tours: [
|
|
50
|
-
{
|
|
51
|
-
name: "Harbin",
|
|
52
|
-
image: "iceholidays-assets/images/harbin.png",
|
|
53
|
-
},
|
|
54
|
-
{
|
|
55
|
-
name: "Inner Mongolia",
|
|
56
|
-
image: "iceholidays-assets/images/inner_mongolia.png",
|
|
57
|
-
},
|
|
58
|
-
{
|
|
59
|
-
name: "Jiangxi",
|
|
60
|
-
image: "iceholidays-assets/images/jiangxi.png",
|
|
61
|
-
},
|
|
62
|
-
{
|
|
63
|
-
name: "Kun Ming",
|
|
64
|
-
image: "iceholidays-assets/images/kunming.png",
|
|
65
|
-
},
|
|
66
|
-
{
|
|
67
|
-
name: "Silk Road",
|
|
68
|
-
image: "iceholidays-assets/images/slikroad.png",
|
|
69
|
-
}
|
|
70
|
-
]
|
|
71
|
-
},
|
|
72
|
-
{
|
|
73
|
-
name: "Europe"
|
|
74
|
-
},
|
|
75
|
-
{
|
|
76
|
-
name: "Exotic"
|
|
77
|
-
},
|
|
78
|
-
{
|
|
79
|
-
name: "japan"
|
|
80
|
-
},
|
|
81
|
-
{
|
|
82
|
-
name: "korea"
|
|
83
|
-
},
|
|
84
|
-
{
|
|
85
|
-
name: "maldives"
|
|
86
|
-
},
|
|
87
|
-
{
|
|
88
|
-
name: "taiwan"
|
|
89
|
-
},
|
|
90
|
-
]
|
|
91
11
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
12
|
+
export default class Destinations extends React.Component {
|
|
13
|
+
api = new LocationsApi;
|
|
14
|
+
|
|
15
|
+
state = {
|
|
16
|
+
countries: [],
|
|
17
|
+
activeTab: "1"
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
componentDidMount() {
|
|
21
|
+
this.api.getCountries()
|
|
22
|
+
.then(locationsData => {
|
|
23
|
+
this.setState({countries: locationsData})
|
|
24
|
+
})
|
|
25
|
+
.catch(error => {
|
|
26
|
+
notification.error({ message: 'An error occured while loading countries.'});
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
render(){
|
|
31
|
+
const pluralize = (count: number, noun: string, suffix = 's') =>
|
|
32
|
+
`${count} ${noun}${count > 1 ? suffix : ''}`;
|
|
33
|
+
|
|
34
|
+
const listingLink = (locationId: number) => {
|
|
35
|
+
return `/app/listing?location_id=${locationId}`;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const changeTab = (selectedKey:string) => {
|
|
39
|
+
this.setState({activeTab:selectedKey.toString()})
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
var items:TabsProps["items"] = this.state.countries.map((country:Country, index)=>{
|
|
44
|
+
return {
|
|
45
|
+
key: country.id.toString(),
|
|
46
|
+
label: <>
|
|
47
|
+
{country.name}
|
|
48
|
+
</>,
|
|
49
|
+
children: (
|
|
99
50
|
<div>
|
|
100
|
-
<
|
|
101
|
-
<img className="country-image"
|
|
102
|
-
src={`${country.image}`} />
|
|
51
|
+
<Link to={listingLink(country.id)} className="country">
|
|
52
|
+
<img className="country-image" src={`${country.cover}`} />
|
|
103
53
|
<h1 className="country-name"> {country.name} </h1>
|
|
104
|
-
<
|
|
105
|
-
|
|
54
|
+
<picture className="bottom-logo">
|
|
55
|
+
<img src="/iceholidays-assets/images/destinations_logo.png"></img>
|
|
56
|
+
</picture>
|
|
57
|
+
</Link>
|
|
106
58
|
{
|
|
107
|
-
country.topCities?.length &&
|
|
59
|
+
country.topCities?.length > 0 &&
|
|
108
60
|
<div className="top-cities">
|
|
109
61
|
<h2>Top Cities</h2>
|
|
110
|
-
<
|
|
111
|
-
{
|
|
112
|
-
country.topCities?.map((city, index)=>{
|
|
113
|
-
return (
|
|
114
|
-
<div key={index} className="city-cover">
|
|
115
|
-
<img src={`${city.image}`}/>
|
|
116
|
-
<div className="city-details">
|
|
117
|
-
<span className="city-name">{city.name}</span>
|
|
118
|
-
<span className="tour-count">1 Tour <FontAwesomeIcon icon={faCaretRight}/> </span>
|
|
119
|
-
</div>
|
|
120
|
-
</div>
|
|
121
|
-
)
|
|
122
|
-
})
|
|
123
|
-
}
|
|
124
|
-
</div>
|
|
62
|
+
<LocationPostcards locations={country.topCities}/>
|
|
125
63
|
</div>
|
|
126
64
|
}
|
|
127
|
-
|
|
128
65
|
{
|
|
129
|
-
country.
|
|
66
|
+
country.tags?.length > 0 &&
|
|
130
67
|
<div className="more-cities">
|
|
131
68
|
<h2>Browse more {country.name} destination</h2>
|
|
132
69
|
<div className="other-destinations">
|
|
133
70
|
{
|
|
134
|
-
country.
|
|
135
|
-
return <
|
|
71
|
+
country.tags?.map((city, index)=>{
|
|
72
|
+
return <Link key={index} to={listingLink(city.id)}> {city.name} </Link>
|
|
136
73
|
})
|
|
137
74
|
}
|
|
138
75
|
</div>
|
|
@@ -140,37 +77,41 @@ function Destinations(){
|
|
|
140
77
|
}
|
|
141
78
|
|
|
142
79
|
{
|
|
143
|
-
country.
|
|
144
|
-
<div className="
|
|
80
|
+
country.highlights?.length > 0 &&
|
|
81
|
+
<div className="highlights">
|
|
145
82
|
{
|
|
146
|
-
country.
|
|
147
|
-
return <
|
|
148
|
-
<div className="tour-
|
|
149
|
-
<
|
|
150
|
-
|
|
83
|
+
country.highlights?.map((city, index)=>{
|
|
84
|
+
return <Link key={index} to={listingLink(city.id)}>
|
|
85
|
+
<div className="tour" style={{backgroundImage:`linear-gradient(180deg, rgba(0, 0, 0, 0) 50%, rgba(0, 0, 0, 0.8) 100%), url("${city.cover}")`}}>
|
|
86
|
+
<div className="details">
|
|
87
|
+
<span className="city-name"> {city.name} </span>
|
|
88
|
+
<span className="tour-count"> {pluralize(city.tourCount || 0, "tour")} <Icon path={mdiMenuRight} size={1} /> </span>
|
|
89
|
+
</div>
|
|
151
90
|
</div>
|
|
152
|
-
</
|
|
91
|
+
</Link>
|
|
153
92
|
})
|
|
154
93
|
}
|
|
155
94
|
</div>
|
|
156
95
|
}
|
|
157
96
|
</div>
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
}
|
|
161
|
-
})
|
|
97
|
+
)
|
|
98
|
+
}
|
|
99
|
+
})
|
|
162
100
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
101
|
+
return (
|
|
102
|
+
<div id="popular-destinations">
|
|
103
|
+
<h1>Explore Popular Destination</h1>
|
|
166
104
|
|
|
167
|
-
|
|
168
|
-
defaultActiveKey="1"
|
|
169
|
-
items={items}
|
|
170
|
-
type="card"/>
|
|
105
|
+
<LocationDropdown locations={this.state.countries} selectLocation={changeTab}/>
|
|
171
106
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
}
|
|
107
|
+
<Tabs
|
|
108
|
+
defaultActiveKey="1"
|
|
109
|
+
activeKey={this.state.activeTab}
|
|
110
|
+
items={items}
|
|
111
|
+
type="card"
|
|
112
|
+
onChange={changeTab}/>
|
|
175
113
|
|
|
176
|
-
|
|
114
|
+
</div>
|
|
115
|
+
)
|
|
116
|
+
}
|
|
117
|
+
}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
|
|
2
|
+
import { List, Card, Space } from "antd";
|
|
3
|
+
import React from "react";
|
|
4
|
+
import { data } from "react-router-dom";
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
const pricingCategory = {
|
|
8
|
+
"adult": "Adult",
|
|
9
|
+
"child_no_bed": "Child no bed",
|
|
10
|
+
"child_twin": "Child twin",
|
|
11
|
+
"child_with_bed": "Child with bed",
|
|
12
|
+
"infant": "Infant",
|
|
13
|
+
"single_supplement": "Single Supplement",
|
|
14
|
+
"dta_adult": "DTA Adult",
|
|
15
|
+
"dta_child_no_bed": "DTA Child no bed",
|
|
16
|
+
"dta_child_twin": "DTA Child twin",
|
|
17
|
+
"dta_child_with_bed": "DTA Child with bed",
|
|
18
|
+
"dta_infant": "DTA Infant",
|
|
19
|
+
"dta_single_supplement": "DTA Single Supplement",
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const priceTypes = {
|
|
23
|
+
"normal": "normal",
|
|
24
|
+
"normal1": "normal 1",
|
|
25
|
+
"normal2": "normal 2",
|
|
26
|
+
"normal3": "normal 3",
|
|
27
|
+
"normal4": "normal 4",
|
|
28
|
+
"normal5": "normal 5",
|
|
29
|
+
"normal6": "normal 6",
|
|
30
|
+
"normal7": "normal 7",
|
|
31
|
+
"normal8": "normal 8",
|
|
32
|
+
"normal9": "normal 9",
|
|
33
|
+
"early_bird": "early bird",
|
|
34
|
+
"specialoffer": "special offer",
|
|
35
|
+
"specialdeal": "special deal",
|
|
36
|
+
"superpromo": "super promo",
|
|
37
|
+
"promo": "promo",
|
|
38
|
+
"promo1": "promo 1",
|
|
39
|
+
"promo2": "promo 2",
|
|
40
|
+
"promo3": "promo 3",
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
const PriceDetails = (
|
|
45
|
+
props: {
|
|
46
|
+
priceCurrency:string,
|
|
47
|
+
prices: any[]
|
|
48
|
+
}
|
|
49
|
+
) => {
|
|
50
|
+
const { priceCurrency, prices } = props;
|
|
51
|
+
|
|
52
|
+
var pricingTypes:any[] = [], priceTable:any = {}, priceList:any[] = [];
|
|
53
|
+
if(prices.length>0){
|
|
54
|
+
pricingTypes = prices.map((price:any) => price.type);
|
|
55
|
+
prices.forEach((price:any) => {
|
|
56
|
+
const pricingObj = {
|
|
57
|
+
label: price.display_price,
|
|
58
|
+
adult: price.adult,
|
|
59
|
+
child_no_bed: price.child_no_bed,
|
|
60
|
+
child_twin: price.child_twin,
|
|
61
|
+
child_with_bed: price.child_with_bed,
|
|
62
|
+
dta_adult: price.dta_adult,
|
|
63
|
+
dta_child_no_bed: price.dta_child_no_bed,
|
|
64
|
+
dta_child_twin: price.dta_child_twin,
|
|
65
|
+
dta_child_with_bed: price.dta_child_with_bed,
|
|
66
|
+
dta_infant: price.dta_infant,
|
|
67
|
+
dta_single_supplement: price.dta_single_supplement,
|
|
68
|
+
infant: price.infant,
|
|
69
|
+
single_supplement: price.single_supplement,
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
priceTable[price.type] = pricingObj;
|
|
73
|
+
|
|
74
|
+
priceList.push({
|
|
75
|
+
title: `${price.display_price} ${priceTypes[price.type]}`,
|
|
76
|
+
type: price.type,
|
|
77
|
+
...pricingObj
|
|
78
|
+
})
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return (
|
|
83
|
+
<div id="price-details" className="details-container">
|
|
84
|
+
<div className="details-container_header"> Price Details </div>
|
|
85
|
+
<div className="details-container_content">
|
|
86
|
+
<table id="pricing-table">
|
|
87
|
+
<thead>
|
|
88
|
+
<tr>
|
|
89
|
+
<th></th>
|
|
90
|
+
{
|
|
91
|
+
pricingTypes.map((type:any) => <th className={type}>
|
|
92
|
+
<div>{priceTable[type].label}</div>
|
|
93
|
+
<div className="price-type">{priceTypes[type]}</div>
|
|
94
|
+
</th>)
|
|
95
|
+
}
|
|
96
|
+
</tr>
|
|
97
|
+
</thead>
|
|
98
|
+
<tbody>
|
|
99
|
+
{
|
|
100
|
+
Object.entries(pricingCategory).map(category => (
|
|
101
|
+
<tr>
|
|
102
|
+
<td> {category[1]} </td>
|
|
103
|
+
{
|
|
104
|
+
pricingTypes.map((type:any) => <td className={type}> {priceCurrency} {priceTable[type][category[0]]}</td>)
|
|
105
|
+
}
|
|
106
|
+
</tr>
|
|
107
|
+
))
|
|
108
|
+
}
|
|
109
|
+
</tbody>
|
|
110
|
+
</table>
|
|
111
|
+
|
|
112
|
+
{
|
|
113
|
+
priceList.length > 0 && (
|
|
114
|
+
<List
|
|
115
|
+
id="pricing-list"
|
|
116
|
+
itemLayout="vertical"
|
|
117
|
+
dataSource={priceList}
|
|
118
|
+
renderItem={(item) => (
|
|
119
|
+
<List.Item>
|
|
120
|
+
<Card className={item.type}>
|
|
121
|
+
<div className="pricing-header"> {item.title} </div>
|
|
122
|
+
<div className="pricing-body">
|
|
123
|
+
<Space size={15} direction="vertical" style={{display: 'flex'}}>
|
|
124
|
+
{
|
|
125
|
+
Object.entries(pricingCategory).map(category => (
|
|
126
|
+
<div className="pricing">
|
|
127
|
+
<div className="category"> {category[1]} </div>
|
|
128
|
+
<div className="price">{priceCurrency} {item[category[0]]} </div>
|
|
129
|
+
</div>
|
|
130
|
+
))
|
|
131
|
+
}
|
|
132
|
+
</Space>
|
|
133
|
+
</div>
|
|
134
|
+
</Card>
|
|
135
|
+
</List.Item>
|
|
136
|
+
)}
|
|
137
|
+
/>
|
|
138
|
+
)
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
</div>
|
|
142
|
+
</div>
|
|
143
|
+
)
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export default PriceDetails;
|
|
@@ -1,19 +1,75 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
|
3
|
-
import { Carousel } from "antd";
|
|
1
|
+
import { Carousel, notification } from "antd";
|
|
4
2
|
import React from "react";
|
|
5
3
|
import SlickButtonFix from "./shared/SlickButtonFix";
|
|
6
|
-
import {
|
|
7
|
-
import
|
|
4
|
+
import { mdiFountainPenTip, mdiMenuLeft, mdiMenuRight } from "@mdi/js";
|
|
5
|
+
import Icon from "@mdi/react";
|
|
6
|
+
import RibbonSection from "./shared/RibbonSection";
|
|
7
|
+
import TestimonialsApi from "../../api-services/testimonials-api.service";
|
|
8
|
+
import { Testimonial } from "../../interfaces/testimonial.interface";
|
|
9
|
+
import createDOMPurify from 'dompurify'
|
|
8
10
|
|
|
11
|
+
const DOMPurify = createDOMPurify(window)
|
|
9
12
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
export default class Testimonials extends React.Component {
|
|
14
|
+
api = new TestimonialsApi;
|
|
15
|
+
|
|
16
|
+
state = {
|
|
17
|
+
reviews: []
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
componentDidMount() {
|
|
21
|
+
this.api.getTestimonials()
|
|
22
|
+
.then(testimonialsData => {
|
|
23
|
+
this.setState({reviews: testimonialsData})
|
|
24
|
+
})
|
|
25
|
+
.catch(error => {
|
|
26
|
+
notification.error({ message: 'An error occured while loading testimonials.'});
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
render(){
|
|
31
|
+
return (
|
|
32
|
+
<RibbonSection title="Testimonial">
|
|
33
|
+
<div id="testimonials">
|
|
34
|
+
<Carousel autoplay arrows dots={false} draggable slidesToScroll= {1} slidesToShow={this.state.reviews.length > 3 ? 3 : this.state.reviews.length}
|
|
35
|
+
prevArrow={
|
|
36
|
+
<SlickButtonFix>
|
|
37
|
+
<Icon path={mdiMenuLeft} size={4} />
|
|
38
|
+
</SlickButtonFix>
|
|
39
|
+
}
|
|
40
|
+
nextArrow={
|
|
41
|
+
<SlickButtonFix>
|
|
42
|
+
<Icon path={mdiMenuRight} size={4} />
|
|
43
|
+
</SlickButtonFix>
|
|
44
|
+
}>
|
|
45
|
+
{
|
|
46
|
+
this.state.reviews.map((review:Testimonial)=>{
|
|
47
|
+
return (
|
|
48
|
+
<div key={review.id} className="testimonial">
|
|
49
|
+
<img src="/iceholidays-assets/images/5star.png" className="stars-icon"/>
|
|
50
|
+
<div className="tour">
|
|
51
|
+
<img src="/iceholidays-assets/images/logomark.png" className="st-logo"/>
|
|
52
|
+
<div>
|
|
53
|
+
<span> {review.tour} </span>
|
|
54
|
+
</div>
|
|
55
|
+
</div>
|
|
56
|
+
<div className="comment">
|
|
57
|
+
<span dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(review.comment) }} />
|
|
58
|
+
</div>
|
|
59
|
+
<div className="author">
|
|
60
|
+
<Icon path={mdiFountainPenTip} size={1} className="author-icon" />
|
|
61
|
+
<span>{review.author}</span>
|
|
62
|
+
</div>
|
|
63
|
+
</div>
|
|
64
|
+
)
|
|
65
|
+
})
|
|
66
|
+
}
|
|
67
|
+
</Carousel>
|
|
68
|
+
</div>
|
|
69
|
+
</RibbonSection>
|
|
70
|
+
)
|
|
71
|
+
}
|
|
72
|
+
}
|
|
17
73
|
|
|
18
74
|
const reviews = [
|
|
19
75
|
{
|
|
@@ -37,52 +93,3 @@ const reviews = [
|
|
|
37
93
|
},
|
|
38
94
|
]
|
|
39
95
|
|
|
40
|
-
function Testimonials(){
|
|
41
|
-
return (
|
|
42
|
-
<div id="testimonial">
|
|
43
|
-
<div id="testimonial-header" style={{backgroundImage: "url('iceholidays-assets/images/Layer_1.png')"}}>
|
|
44
|
-
<span>Testimonial</span>
|
|
45
|
-
</div>
|
|
46
|
-
|
|
47
|
-
<div id="testimonials">
|
|
48
|
-
<Carousel autoplay arrows dots={false} draggable slidesToScroll= {1} slidesToShow={3}
|
|
49
|
-
prevArrow={
|
|
50
|
-
<SlickButtonFix>
|
|
51
|
-
<FontAwesomeIcon icon={faCaretLeft} size="4x"/>
|
|
52
|
-
</SlickButtonFix>
|
|
53
|
-
}
|
|
54
|
-
nextArrow={
|
|
55
|
-
<SlickButtonFix>
|
|
56
|
-
<FontAwesomeIcon icon={faCaretRight} size="4x"/>
|
|
57
|
-
</SlickButtonFix>
|
|
58
|
-
}>
|
|
59
|
-
{
|
|
60
|
-
reviews?.map((review)=>{
|
|
61
|
-
return (
|
|
62
|
-
<div key={review.key} className="testimonial">
|
|
63
|
-
<img src="iceholidays-assets/images/5star.png" className="stars-icon"/>
|
|
64
|
-
<div className="itinerary-summary">
|
|
65
|
-
<img src="iceholidays-assets/images/logomark.png" className="st-logo"/>
|
|
66
|
-
<div>
|
|
67
|
-
<span> {review.itinerarySummaryTitle} </span>
|
|
68
|
-
<span> {review.itinerarySummaryDesc} </span>
|
|
69
|
-
</div>
|
|
70
|
-
</div>
|
|
71
|
-
<div className="comment">
|
|
72
|
-
<span>{review.comment}</span>
|
|
73
|
-
</div>
|
|
74
|
-
<div className="customer-name">
|
|
75
|
-
<FontAwesomeIcon icon={faPenNib} className="author-icon" />
|
|
76
|
-
<span>{review.customerName}</span>
|
|
77
|
-
</div>
|
|
78
|
-
</div>
|
|
79
|
-
)
|
|
80
|
-
})
|
|
81
|
-
}
|
|
82
|
-
</Carousel>
|
|
83
|
-
</div>
|
|
84
|
-
</div>
|
|
85
|
-
)
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
export default Testimonials;
|
|
@@ -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
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Breadcrumb } from "antd";
|
|
2
|
+
import React, { JSX } from "react";
|
|
3
|
+
import SearchBarWidget from "../../widgets/SearchBarWidget";
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
const Headline = (
|
|
7
|
+
props: {
|
|
8
|
+
bannerImage: string;
|
|
9
|
+
showSearch?: boolean;
|
|
10
|
+
title?: string;
|
|
11
|
+
children?: JSX.Element;
|
|
12
|
+
breadcrumbs: any[];
|
|
13
|
+
}
|
|
14
|
+
) => {
|
|
15
|
+
const { bannerImage, title, children, breadcrumbs } = props;
|
|
16
|
+
return (
|
|
17
|
+
<>
|
|
18
|
+
{(props.showSearch == undefined || props.showSearch && props.showSearch == true) && <SearchBarWidget/>}
|
|
19
|
+
<div id="headline">
|
|
20
|
+
<div id="headline_banner" style={{backgroundImage: `url(${bannerImage})`}}></div>
|
|
21
|
+
<div id="headline_header">
|
|
22
|
+
{ title ? <h1> {title} </h1> : children}
|
|
23
|
+
</div>
|
|
24
|
+
<Breadcrumb items={breadcrumbs} separator=">"/>
|
|
25
|
+
</div>
|
|
26
|
+
</>
|
|
27
|
+
)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export default Headline;
|
|
@@ -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;
|