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
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import Headline from "../components/shared/Headline";
|
|
3
3
|
import LocationsApi from "../../api-services/locations-api.service";
|
|
4
|
-
import {
|
|
5
|
-
import
|
|
6
|
-
import Postcard from "../components/shared/Postcard";
|
|
4
|
+
import { Flex, notification } from "antd";
|
|
5
|
+
import LocationPostcards from "../components/shared/LocationPostcards";
|
|
7
6
|
|
|
8
7
|
const bannerPath = '/iceholidays-assets/images/about_us.png';
|
|
9
8
|
const breadcrumbs = [
|
|
@@ -49,11 +48,7 @@ export default class CountriesPage extends React.Component {
|
|
|
49
48
|
</div>
|
|
50
49
|
|
|
51
50
|
<h2> Countries </h2>
|
|
52
|
-
<
|
|
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>
|
|
51
|
+
<LocationPostcards locations={this.state.countries}/>
|
|
57
52
|
</div>
|
|
58
53
|
|
|
59
54
|
</div>
|
|
@@ -2,7 +2,7 @@ import React from "react";
|
|
|
2
2
|
import Testimonials from "../components/Testimonials";
|
|
3
3
|
import Destinations from "../components/Destinations";
|
|
4
4
|
import SearchBarWidget from "../widgets/SearchBarWidget";
|
|
5
|
-
import { Carousel, notification } from "antd";
|
|
5
|
+
import { Carousel, Col, notification, Row } from "antd";
|
|
6
6
|
import SlickButtonFix from "../components/shared/SlickButtonFix";
|
|
7
7
|
import BannersApi from "../../api-services/banners-api.service";
|
|
8
8
|
import { Banner } from "../../interfaces/banner.interface";
|
|
@@ -61,7 +61,9 @@ export default class Homepage extends React.Component {
|
|
|
61
61
|
</div>
|
|
62
62
|
|
|
63
63
|
<Destinations/>
|
|
64
|
-
<
|
|
64
|
+
<div id="testimonials-section">
|
|
65
|
+
<Testimonials/>
|
|
66
|
+
</div>
|
|
65
67
|
|
|
66
68
|
<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
69
|
<div>
|
|
@@ -69,18 +71,26 @@ export default class Homepage extends React.Component {
|
|
|
69
71
|
<p>
|
|
70
72
|
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
73
|
</p>
|
|
72
|
-
<
|
|
74
|
+
<picture>
|
|
75
|
+
<source media="(min-width: 600px)" srcSet="/iceholidays-assets/images/about-us_logo.png" />
|
|
76
|
+
<source media="(max-width: 599px)" srcSet="/iceholidays-assets/images/about-us_logo_mobile.png" />
|
|
77
|
+
<img src="/iceholidays-assets/images/about-us_logo.png" alt="About Signature Tours Logo Line"/>
|
|
78
|
+
</picture>
|
|
73
79
|
<div id="about-st-feature">
|
|
74
|
-
<
|
|
75
|
-
<
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
<
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
80
|
+
<Row gutter={[20, 20]} align="middle">
|
|
81
|
+
<Col flex="1 0 50%" className="column">
|
|
82
|
+
<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>
|
|
83
|
+
</Col>
|
|
84
|
+
<Col flex="1 0 50%" className="column">
|
|
85
|
+
<div id="feature">
|
|
86
|
+
<img src="/iceholidays-assets/images/feature.jpg"/>
|
|
87
|
+
<div id="st-brand">
|
|
88
|
+
<span>Signature Tours</span>
|
|
89
|
+
<img src="/iceholidays-assets/images/logomark.png" id="st-logo"/>
|
|
90
|
+
</div>
|
|
91
|
+
</div>
|
|
92
|
+
</Col>
|
|
93
|
+
</Row>
|
|
84
94
|
</div>
|
|
85
95
|
</div>
|
|
86
96
|
</div>
|
|
@@ -11,25 +11,21 @@ import SeriesApi from "../../api-services/series-api.service";
|
|
|
11
11
|
import { Itinerary } from "../../interfaces/itinerary.interface";
|
|
12
12
|
|
|
13
13
|
import createDOMPurify from 'dompurify'
|
|
14
|
+
import LocationDropdown from "../components/shared/LocationDropdown";
|
|
14
15
|
|
|
15
16
|
const DOMPurify = createDOMPurify(window)
|
|
16
17
|
|
|
17
18
|
|
|
18
19
|
const bannerPath = '/iceholidays-assets/images/china_listings_cover.png';
|
|
19
|
-
const breadcrumbs = [
|
|
20
|
-
{ title: 'Home' },
|
|
21
|
-
{ title: 'China' },
|
|
22
|
-
{ title: 'Chongqing' }
|
|
23
|
-
]
|
|
24
20
|
|
|
25
21
|
const legends = [
|
|
26
22
|
{ id: "guaranteed", label: "Guaranteed", color: "#DCB062" },
|
|
27
|
-
{ id: "
|
|
23
|
+
{ id: "almost-guaranteed", label: "Selling Fast", color: "#23D1C0" }
|
|
28
24
|
]
|
|
29
25
|
|
|
30
26
|
const getColorByType = (type:string) => {
|
|
31
27
|
var legend = legends.find(l => l.id == type);
|
|
32
|
-
return legend ? legend.color : "#
|
|
28
|
+
return legend ? legend.color : "#999999";
|
|
33
29
|
}
|
|
34
30
|
|
|
35
31
|
function withSearchParams(Component) {
|
|
@@ -43,11 +39,15 @@ class ListingPage extends React.Component <{searchParams}> {
|
|
|
43
39
|
state = {
|
|
44
40
|
countries: [],
|
|
45
41
|
selectedCountry: {cities: []},
|
|
46
|
-
keyword: "",
|
|
42
|
+
searchParamsObj: {keyword: "", year: "", month: "", location_id: null},
|
|
47
43
|
itineraries: [],
|
|
48
|
-
|
|
49
|
-
|
|
44
|
+
location: {name: "", cover: ""},
|
|
45
|
+
breadcrumbs: [{ title: <a href="/app">Home</a> }],
|
|
46
|
+
descriptionModalOpen: false,
|
|
47
|
+
itineraryModalOpen: false,
|
|
48
|
+
dateModalOpen: false,
|
|
50
49
|
descriptionData: "",
|
|
50
|
+
fileUrlData: "",
|
|
51
51
|
departureDatesData: []
|
|
52
52
|
}
|
|
53
53
|
|
|
@@ -64,16 +64,55 @@ class ListingPage extends React.Component <{searchParams}> {
|
|
|
64
64
|
notification.error({ message: 'An error occured while loading countries.'});
|
|
65
65
|
});
|
|
66
66
|
|
|
67
|
-
|
|
68
|
-
const keyword = searchParams.get('keyword');
|
|
69
|
-
this.setState({keyword: keyword})
|
|
67
|
+
this.setSearchParamsObj();
|
|
70
68
|
|
|
71
|
-
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
private setSearchParamsObj(){
|
|
72
|
+
const [searchParams] = this.props.searchParams;
|
|
73
|
+
const {searchParamsObj} = this.state;
|
|
74
|
+
searchParams.keys().forEach(key => {
|
|
75
|
+
searchParamsObj[key] = searchParams.get(key);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
this.setState({searchParamsObj});
|
|
79
|
+
|
|
80
|
+
const locationId = searchParamsObj.location_id;
|
|
81
|
+
if(locationId) this.getLocation(locationId);
|
|
82
|
+
|
|
83
|
+
this.getItineraries(searchParamsObj);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
searchParamsToText() {
|
|
88
|
+
var {keyword, year, month} = this.state.searchParamsObj;
|
|
89
|
+
return <span>{ this.state.location?.name || keyword}{`${month && `, ${month}`} ${year}`} </span>
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
getLocation(locationId){
|
|
93
|
+
//resets the breadcrumbs
|
|
94
|
+
this.setState({breadcrumbs: [{ title: <a href="/app">Home</a> }]});
|
|
95
|
+
|
|
96
|
+
this.locationsApi.getLocation(locationId)
|
|
97
|
+
.then(locationData => {
|
|
98
|
+
var locationCrumbs = this.state.breadcrumbs;
|
|
99
|
+
if(locationData.ancestry?.length && locationData.ancestry?.length > 0){
|
|
100
|
+
locationData.ancestry.forEach(a => {
|
|
101
|
+
locationCrumbs.push({title: <span key={a.id}> {a.name} </span>})
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
locationCrumbs.push({title: <span>{locationData.name}</span>});
|
|
105
|
+
this.setState({location: locationData, breadcrumbs: locationCrumbs})
|
|
106
|
+
})
|
|
107
|
+
.catch(error => {
|
|
108
|
+
notification.error({ message: 'An error occured while loading location.'});
|
|
109
|
+
});
|
|
72
110
|
}
|
|
73
111
|
|
|
74
112
|
getItineraries(searchParams){
|
|
75
113
|
this.seriesApi.getItineraries(searchParams)
|
|
76
|
-
|
|
114
|
+
.then(itinerariesData => {
|
|
115
|
+
this.setBreadcrumbs();
|
|
77
116
|
this.setState({itineraries: itinerariesData})
|
|
78
117
|
})
|
|
79
118
|
.catch(error => {
|
|
@@ -81,163 +120,170 @@ class ListingPage extends React.Component <{searchParams}> {
|
|
|
81
120
|
});
|
|
82
121
|
}
|
|
83
122
|
|
|
84
|
-
|
|
85
|
-
this.
|
|
86
|
-
|
|
123
|
+
setBreadcrumbs(){
|
|
124
|
+
var breadcrumbs = this.state.breadcrumbs;
|
|
125
|
+
if(breadcrumbs.length > 1){
|
|
126
|
+
const {keyword, ...noKeyword} = this.state.searchParamsObj;
|
|
127
|
+
const allHasValues = Object.entries(noKeyword).every(o => o[1] != "");
|
|
128
|
+
if(allHasValues){
|
|
129
|
+
const searchResultsCrumb = {title: <span>Search results</span>};
|
|
130
|
+
if(breadcrumbs.length > 2){
|
|
131
|
+
breadcrumbs[breadcrumbs.length-2] = searchResultsCrumb;
|
|
132
|
+
}else{
|
|
133
|
+
breadcrumbs.splice(1, 0, searchResultsCrumb);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
87
136
|
|
|
88
|
-
|
|
89
|
-
|
|
137
|
+
breadcrumbs[breadcrumbs.length-1] = {title: this.searchParamsToText()};
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
this.setState({breadcrumbs});
|
|
90
141
|
}
|
|
91
142
|
|
|
92
|
-
|
|
93
|
-
this.setState({
|
|
143
|
+
showModal(modalName:string, propName: string, value: any){
|
|
144
|
+
this.setState({[modalName]: true, [propName]: value});
|
|
94
145
|
}
|
|
95
146
|
|
|
96
|
-
|
|
97
|
-
this.setState({
|
|
147
|
+
closeModal(modalName:string) {
|
|
148
|
+
this.setState({[modalName]:false});
|
|
98
149
|
}
|
|
99
150
|
|
|
100
|
-
selectCountry(country){
|
|
101
|
-
const selectedCountry = this.state.countries.find((c:Country) => c.id == country);
|
|
151
|
+
selectCountry = (country) => {
|
|
152
|
+
const selectedCountry:any = this.state.countries.find((c:Country) => c.id == country);
|
|
102
153
|
if(selectedCountry){
|
|
103
|
-
this.
|
|
154
|
+
const searchParamsObj = this.state.searchParamsObj;
|
|
155
|
+
searchParamsObj.location_id = selectedCountry.id;
|
|
156
|
+
this.getLocation(selectedCountry.id);
|
|
157
|
+
|
|
158
|
+
this.setState({selectedCountry, searchParamsObj});
|
|
159
|
+
this.getItineraries(searchParamsObj);
|
|
104
160
|
}
|
|
105
161
|
}
|
|
106
162
|
|
|
107
163
|
|
|
108
164
|
render(){
|
|
109
|
-
const {countries, selectedCountry,
|
|
165
|
+
const {countries, selectedCountry, searchParamsObj, itineraries, location, breadcrumbs, descriptionData, fileUrlData, departureDatesData } = this.state;
|
|
110
166
|
|
|
111
167
|
return <div id="listing-page">
|
|
112
168
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
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
|
-
}
|
|
169
|
+
<Headline bannerImage={location?.cover || bannerPath} breadcrumbs={breadcrumbs}>
|
|
170
|
+
<div id="listing-page_header">
|
|
171
|
+
<Flex vertical gap={10}>
|
|
172
|
+
<h1>{this.searchParamsToText()}</h1>
|
|
173
|
+
<LocationDropdown locations={countries} selectLocation={this.selectCountry}/>
|
|
174
|
+
</Flex>
|
|
175
|
+
</div>
|
|
176
|
+
</Headline>
|
|
177
|
+
|
|
178
|
+
<div id="listing-page_body">
|
|
179
|
+
<Space size={12} direction="vertical">
|
|
180
|
+
<FilterPills items={selectedCountry.cities} bindLabel="name" bindValue="location_id" initialValue={searchParamsObj} selectFilter={(selected) => this.getItineraries(selected)}></FilterPills>
|
|
144
181
|
</Space>
|
|
145
|
-
</div>
|
|
146
182
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
<
|
|
180
|
-
|
|
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
|
-
}
|
|
183
|
+
<div id="legends">
|
|
184
|
+
<Space size={17}>
|
|
185
|
+
{
|
|
186
|
+
legends.map(legend => <Badge key={legend.id} color={legend.color} text={legend.label} />)
|
|
187
|
+
}
|
|
188
|
+
</Space>
|
|
189
|
+
</div>
|
|
190
|
+
|
|
191
|
+
<div id="tours">
|
|
192
|
+
<Flex vertical gap={30}>
|
|
193
|
+
{
|
|
194
|
+
itineraries.map((itinerary:Itinerary) => {
|
|
195
|
+
const departureDates = itinerary.departureDate ? itinerary.departureDate.map(ddate => {
|
|
196
|
+
var type = (itinerary.guranteedDepartureDates && itinerary.guranteedDepartureDates.includes(ddate)) ? "guaranteed" :
|
|
197
|
+
(itinerary.almostGuaranteedDepartureDates && itinerary.almostGuaranteedDepartureDates.includes(ddate)) ? "almost-guaranteed" : "";
|
|
198
|
+
|
|
199
|
+
return { type, date: ddate }
|
|
200
|
+
}) : [];
|
|
201
|
+
|
|
202
|
+
return (
|
|
203
|
+
<Row key={itinerary.id} className="tour">
|
|
204
|
+
<Col flex="1 0 25%" className="column">
|
|
205
|
+
<div className="tour_image"> <img src={itinerary.images[0]}/> </div>
|
|
206
|
+
</Col>
|
|
207
|
+
<Col flex="1 0 55%" className="column">
|
|
208
|
+
<div className="tour_details">
|
|
209
|
+
<Space size={20} direction="vertical" style={{ display: 'flex' }}>
|
|
210
|
+
<Space size={10} direction="vertical">
|
|
211
|
+
<div className="tour_details_title"> {itinerary.caption} </div>
|
|
212
|
+
<div className="tour_details_info">
|
|
213
|
+
<span onClick={()=>this.showModal("descriptionModalOpen", "descriptionData", itinerary.description)}><Icon path={mdiInformationOutline} size={1}/></span>
|
|
214
|
+
</div>
|
|
215
|
+
<div>
|
|
216
|
+
<span className="tour_details_country"> <Icon path={mdiMapMarkerOutline} size="18px" /> {itinerary.country} </span>
|
|
217
|
+
<span className="tour_details_code" onClick={()=>this.showModal("itineraryModalOpen", "fileUrlData", itinerary.fileUrl)}> <Icon path={mdiFileDownload} size="18px" /> {itinerary.code} </span>
|
|
187
218
|
</div>
|
|
188
219
|
</Space>
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
220
|
+
<div className="tour_details_dates">
|
|
221
|
+
<Space size={6} direction="vertical" style={{ display: 'flex' }}>
|
|
222
|
+
<label>Departure Date(s)</label>
|
|
223
|
+
<div className="date-selector">
|
|
224
|
+
{
|
|
225
|
+
departureDates && departureDates.map((ddate, index) => <span key={index} style={{borderColor: getColorByType(ddate.type)}}> {ddate.date} </span>)
|
|
226
|
+
}
|
|
227
|
+
{
|
|
228
|
+
departureDates.length >= 9 && <div className="show-all-dates" onClick={()=>this.showModal("dateModalOpen", "departureDatesData", departureDates)}> <Icon path={mdiDotsHorizontalCircleOutline} size="15px" /> Show All </div>
|
|
229
|
+
}
|
|
230
|
+
</div>
|
|
231
|
+
</Space>
|
|
232
|
+
</div>
|
|
233
|
+
</Space>
|
|
234
|
+
</div>
|
|
235
|
+
</Col>
|
|
236
|
+
<Col flex="1 0 20%" className="column">
|
|
237
|
+
<div className="tour_pricing">
|
|
238
|
+
<Space size={20} direction="vertical" align="center">
|
|
239
|
+
<Flex className="tour_pricing_details">
|
|
240
|
+
<span>From</span>
|
|
241
|
+
<span className="price">{itinerary.priceCurrency} {itinerary.price}</span>
|
|
242
|
+
<span>All In</span>
|
|
243
|
+
</Flex>
|
|
244
|
+
<Link className="select-tour" to={`/app/itinerary/${itinerary.id}`}>Select</Link>
|
|
245
|
+
</Space>
|
|
246
|
+
</div>
|
|
247
|
+
</Col>
|
|
248
|
+
</Row>
|
|
249
|
+
)
|
|
250
|
+
})
|
|
251
|
+
}
|
|
252
|
+
</Flex>
|
|
253
|
+
</div>
|
|
210
254
|
</div>
|
|
211
|
-
</div>
|
|
212
255
|
|
|
256
|
+
<Modal title="Description" open={this.state.descriptionModalOpen} onCancel={()=>this.closeModal("descriptionModalOpen")} footer={null} width={1000} centered className="tour_details_description">
|
|
257
|
+
<div className="pre-wrap">{ <span dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(descriptionData) }} /> }</div>
|
|
258
|
+
</Modal>
|
|
213
259
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
260
|
+
<Modal title="Itinerary" open={this.state.itineraryModalOpen} onCancel={()=>this.closeModal("itineraryModalOpen")} footer={null} width={1000} centered className="tour_details_itinerary">
|
|
261
|
+
<div id="itinerary-file"><img src={fileUrlData}/></div>
|
|
262
|
+
</Modal>
|
|
217
263
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
264
|
+
<Modal title={
|
|
265
|
+
<Flex justify="space-between" align="center">
|
|
266
|
+
<div className="custom-modal-header-title"> Departure Date(s) </div>
|
|
267
|
+
<div className="custom-modal-header-legends">
|
|
268
|
+
<Space size={17}>
|
|
269
|
+
{
|
|
270
|
+
legends.map(legend => <Badge key={legend.id} color={legend.color} text={legend.label} />)
|
|
271
|
+
}
|
|
272
|
+
</Space>
|
|
273
|
+
</div>
|
|
274
|
+
</Flex>
|
|
275
|
+
} footer={
|
|
276
|
+
<Button>Confirm</Button>
|
|
277
|
+
}
|
|
278
|
+
open={this.state.dateModalOpen} onCancel={()=>this.closeModal("dateModalOpen")} width={940} centered className="tour_details_all_dates">
|
|
279
|
+
<div className="date-selector">
|
|
280
|
+
<Space size={8} wrap>
|
|
223
281
|
{
|
|
224
|
-
|
|
282
|
+
departureDatesData && departureDatesData.map((ddate:any) => <span style={{borderColor: getColorByType(ddate.type)}}> {ddate.date} </span>)
|
|
225
283
|
}
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
</
|
|
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>
|
|
284
|
+
</Space>
|
|
285
|
+
</div>
|
|
286
|
+
</Modal>
|
|
241
287
|
</div>
|
|
242
288
|
}
|
|
243
289
|
}
|