iceholidays-frontend 0.5.0 → 0.6.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 +8 -1
- data/app/assets/stylesheets/iceholidays/frontend/common.scss +3 -2
- data/app/javascript/react/components/PriceDetails.tsx +6 -6
- data/app/javascript/react/pages/AboutUsPage.tsx +4 -4
- data/app/javascript/react/pages/ListingPage.tsx +74 -68
- data/app/javascript/react/pages/ShowPage.tsx +41 -36
- data/lib/iceholidays/frontend/version.rb +1 -1
- data/public/iceholidays-assets/application.css +10 -3
- data/public/iceholidays-assets/application.js +41 -41
- data/public/iceholidays-assets/application.js.map +3 -3
- data/public/iceholidays-assets/images/TSTRibbon.png +0 -0
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 6247a8c09cfbda6553642ceb846d1a1661d98edbfa83a891f3ae54dc1cc8db14
|
|
4
|
+
data.tar.gz: 5551d3ff2200d552fe3449604ff5ee3159a5096a06c19436b630e721ce2f3632
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f69e3e14e999712b65290da68cfda945d889b63d23acbfa94aad05351d6df78e77ca02150830688860187af1a724a763cb2402b673397140fc415eba4d99cb23
|
|
7
|
+
data.tar.gz: ad72cf692918fac66f81acf70a12790a6eec52cc34127bc8acf82ad8d1892ca5242d98a629c132066ab0bcb289452bb30f92bdc2511804eb7ff325fa46f668bc
|
|
@@ -467,6 +467,13 @@ body{
|
|
|
467
467
|
}
|
|
468
468
|
}
|
|
469
469
|
}
|
|
470
|
+
|
|
471
|
+
#no-tours-found{
|
|
472
|
+
font-family: $font-default;
|
|
473
|
+
font-weight: 400;
|
|
474
|
+
text-align: center;
|
|
475
|
+
color: #00000c99;
|
|
476
|
+
}
|
|
470
477
|
}
|
|
471
478
|
|
|
472
479
|
.tour_details_description.ant-modal{
|
|
@@ -1233,7 +1240,7 @@ body{
|
|
|
1233
1240
|
font-size: 24px;
|
|
1234
1241
|
font-weight: 500;
|
|
1235
1242
|
line-height: 36px;
|
|
1236
|
-
text-align:
|
|
1243
|
+
text-align: center;
|
|
1237
1244
|
text-underline-position: from-font;
|
|
1238
1245
|
text-decoration-skip-ink: none;
|
|
1239
1246
|
}
|
|
@@ -199,10 +199,11 @@
|
|
|
199
199
|
margin-top: 100px;
|
|
200
200
|
|
|
201
201
|
&_header{
|
|
202
|
-
height:
|
|
202
|
+
height: 150px;
|
|
203
203
|
text-align: center;
|
|
204
204
|
position: relative;
|
|
205
|
-
background-image: url('/iceholidays-assets/images/
|
|
205
|
+
background-image: url('/iceholidays-assets/images/TSTRibbon.png');
|
|
206
|
+
background-repeat: no-repeat;
|
|
206
207
|
|
|
207
208
|
h1{
|
|
208
209
|
font-family: $font-default;
|
|
@@ -11,12 +11,12 @@ const pricingCategory = {
|
|
|
11
11
|
"child_with_bed": "Child with bed",
|
|
12
12
|
"infant": "Infant",
|
|
13
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",
|
|
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
20
|
};
|
|
21
21
|
|
|
22
22
|
const priceTypes = {
|
|
@@ -26,12 +26,12 @@ const AboutUsPage = React.FC = () => (
|
|
|
26
26
|
<Col span={24}>
|
|
27
27
|
<img src="/iceholidays-assets/images/about_us2.png"/>
|
|
28
28
|
</Col>
|
|
29
|
-
<Col
|
|
29
|
+
<Col xs={24} sm={24} lg={12}>
|
|
30
30
|
<p>The Signature Tours was born from a passion for redefining travel. We believe that journeys should be more than just trips—they should be transformative experiences, filled with moments that leave an indelible mark on the soul. Catering to discerning travelers who seek more than the ordinary, The Signature Tours crafts bespoke journeys that combine sophistication, cultural immersion, and unparalleled quality. </p>
|
|
31
31
|
<p>Our story begins with a vision: to create journeys that linger in the heart long after the traveler returns home. Each itinerary we design reflects our dedication to perfection. From the charm of boutique accommodations nestled in picturesque landscapes to handpicked cultural experiences that unveil the soul of a destination, every detail is thoughtfully considered to ensure your journey is as seamless as it is extraordinary.</p>
|
|
32
32
|
<p>At The Signature Tours, we embrace the philosophy of the S-Tours experience—where every moment is a masterpiece. Imagine strolling through the cobblestone streets of a quaint village, savoring the aroma of freshly baked bread as locals welcome you with warm smiles. </p>
|
|
33
33
|
</Col>
|
|
34
|
-
<Col
|
|
34
|
+
<Col xs={24} sm={24} lg={12}>
|
|
35
35
|
<p>Picture yourself standing atop a majestic mountain at sunrise,the golden hues of the horizon reflecting the sense of awe within you. These are the kinds of moments we strive to create—authentic, meaningful, and unforgettable.</p>
|
|
36
36
|
<p>But our commitment goes beyond premium and comfort. It’s about forging connections—with places, cultures, and people. It’s about stepping into a story, whether it’s exploring ancient ruins with a seasoned archaeologist, learning the art of wine making from a passionate vintner, or sharing laughter with a local family over a home-cooked meal.</p>
|
|
37
37
|
<p>At The Signature Tours, every journey is an invitation to step out of the ordinary and into a world of wonder. We’re not just about travel; we’re about creating memories that stay with you forever. This is our promise, and this is what we call the S-Tours philosophy where we deliver S-Class Journeys, Signature Memories. Because every journey should be as unique as your signature.</p>
|
|
@@ -80,10 +80,10 @@ const AboutUsPage = React.FC = () => (
|
|
|
80
80
|
<p>We have acquired recognition and certificates such as:</p>
|
|
81
81
|
</div>
|
|
82
82
|
</Col>
|
|
83
|
-
<Col xs={24} sm={24} lg={8}>
|
|
83
|
+
<Col xs={24} sm={24} md={12} lg={8}>
|
|
84
84
|
<img src="/iceholidays-assets/images/certificate1.png"/>
|
|
85
85
|
</Col>
|
|
86
|
-
<Col xs={24} sm={24} lg={8}>
|
|
86
|
+
<Col xs={24} sm={24} md={12} lg={8}>
|
|
87
87
|
<img src="/iceholidays-assets/images/certificate2.png"/>
|
|
88
88
|
</Col>
|
|
89
89
|
</Row>
|
|
@@ -180,77 +180,83 @@ class ListingPage extends React.Component <{searchParams}> {
|
|
|
180
180
|
<FilterPills items={selectedCountry.cities} bindLabel="name" bindValue="location_id" initialValue={searchParamsObj} selectFilter={(selected) => this.getItineraries(selected)}></FilterPills>
|
|
181
181
|
</Space>
|
|
182
182
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
<
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
<
|
|
210
|
-
<
|
|
211
|
-
<
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
<
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
183
|
+
{
|
|
184
|
+
itineraries.length > 0 ? (
|
|
185
|
+
<>
|
|
186
|
+
<div id="legends">
|
|
187
|
+
<Space size={17}>
|
|
188
|
+
{
|
|
189
|
+
legends.map(legend => <Badge key={legend.id} color={legend.color} text={legend.label} />)
|
|
190
|
+
}
|
|
191
|
+
</Space>
|
|
192
|
+
</div>
|
|
193
|
+
<div id="tours">
|
|
194
|
+
<Flex vertical gap={30}>
|
|
195
|
+
{
|
|
196
|
+
itineraries.map((itinerary:Itinerary) => {
|
|
197
|
+
const departureDates = itinerary.departureDate ? itinerary.departureDate.map(ddate => {
|
|
198
|
+
var type = (itinerary.guranteedDepartureDates && itinerary.guranteedDepartureDates.includes(ddate)) ? "guaranteed" :
|
|
199
|
+
(itinerary.almostGuaranteedDepartureDates && itinerary.almostGuaranteedDepartureDates.includes(ddate)) ? "almost-guaranteed" : "";
|
|
200
|
+
|
|
201
|
+
return { type, date: ddate }
|
|
202
|
+
}) : [];
|
|
203
|
+
|
|
204
|
+
return (
|
|
205
|
+
<Row key={itinerary.id} className="tour">
|
|
206
|
+
<Col flex="1 0 25%" className="column">
|
|
207
|
+
<div className="tour_image"> <img src={itinerary.images[0]}/> </div>
|
|
208
|
+
</Col>
|
|
209
|
+
<Col flex="1 0 55%" className="column">
|
|
210
|
+
<div className="tour_details">
|
|
211
|
+
<Space size={20} direction="vertical" style={{ display: 'flex' }}>
|
|
212
|
+
<Space size={10} direction="vertical">
|
|
213
|
+
<div className="tour_details_title"> {itinerary.caption} </div>
|
|
214
|
+
<div className="tour_details_info">
|
|
215
|
+
<span onClick={()=>this.showModal("descriptionModalOpen", "descriptionData", itinerary.description)}><Icon path={mdiInformationOutline} size={1}/></span>
|
|
216
|
+
</div>
|
|
217
|
+
<div>
|
|
218
|
+
<span className="tour_details_country"> <Icon path={mdiMapMarkerOutline} size="18px" /> {itinerary.country} </span>
|
|
219
|
+
<span className="tour_details_code" onClick={()=>this.showModal("itineraryModalOpen", "fileUrlData", itinerary.fileUrl)}> <Icon path={mdiFileDownload} size="18px" /> {itinerary.code} </span>
|
|
220
|
+
</div>
|
|
221
|
+
</Space>
|
|
222
|
+
<div className="tour_details_dates">
|
|
223
|
+
<Space size={6} direction="vertical" style={{ display: 'flex' }}>
|
|
224
|
+
<label>Departure Date(s)</label>
|
|
225
|
+
<div className="date-selector">
|
|
226
|
+
{
|
|
227
|
+
departureDates && departureDates.map((ddate, index) => <span key={index} style={{borderColor: getColorByType(ddate.type)}}> {ddate.date} </span>)
|
|
228
|
+
}
|
|
229
|
+
{
|
|
230
|
+
departureDates.length >= 9 && <div className="show-all-dates" onClick={()=>this.showModal("dateModalOpen", "departureDatesData", departureDates)}> <Icon path={mdiDotsHorizontalCircleOutline} size="15px" /> Show All </div>
|
|
231
|
+
}
|
|
232
|
+
</div>
|
|
233
|
+
</Space>
|
|
230
234
|
</div>
|
|
231
235
|
</Space>
|
|
232
236
|
</div>
|
|
233
|
-
</
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
</
|
|
246
|
-
</
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
237
|
+
</Col>
|
|
238
|
+
<Col flex="1 0 20%" className="column">
|
|
239
|
+
<div className="tour_pricing">
|
|
240
|
+
<Space size={20} direction="vertical" align="center">
|
|
241
|
+
<Flex className="tour_pricing_details">
|
|
242
|
+
<span>From</span>
|
|
243
|
+
<span className="price">{itinerary.priceCurrency} {itinerary.price}</span>
|
|
244
|
+
<span>All In</span>
|
|
245
|
+
</Flex>
|
|
246
|
+
<Link className="select-tour" to={`/app/itinerary/${itinerary.id}`}>Select</Link>
|
|
247
|
+
</Space>
|
|
248
|
+
</div>
|
|
249
|
+
</Col>
|
|
250
|
+
</Row>
|
|
251
|
+
)
|
|
252
|
+
})
|
|
253
|
+
}
|
|
254
|
+
</Flex>
|
|
255
|
+
</div>
|
|
256
|
+
</>
|
|
257
|
+
) : <h1 id="no-tours-found">Not tour package is found.</h1>
|
|
258
|
+
}
|
|
259
|
+
|
|
254
260
|
</div>
|
|
255
261
|
|
|
256
262
|
<Modal title="Description" open={this.state.descriptionModalOpen} onCancel={()=>this.closeModal("descriptionModalOpen")} footer={null} width={1000} centered className="tour_details_description">
|
|
@@ -86,11 +86,10 @@ class ShowPage extends React.Component <{params;}> {
|
|
|
86
86
|
getAgents(){
|
|
87
87
|
this.agentsApi.getAgents()
|
|
88
88
|
.then((agentsData:Agent[]) => {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
this.setState({agents: agentsData, allAgents: agentsData, loadingAgents:false, states, cities});
|
|
89
|
+
this.setState({agents: agentsData, allAgents: agentsData});
|
|
90
|
+
this.resetAgents(agentsData);
|
|
92
91
|
})
|
|
93
|
-
|
|
92
|
+
.finally(()=>this.setState({loading: false}))
|
|
94
93
|
.catch(error => {
|
|
95
94
|
notification.error({ message: 'An error occured while loading agents.'});
|
|
96
95
|
});
|
|
@@ -138,11 +137,13 @@ class ShowPage extends React.Component <{params;}> {
|
|
|
138
137
|
this.setState({states: results});
|
|
139
138
|
}
|
|
140
139
|
|
|
141
|
-
resetAgents(){
|
|
142
|
-
const allAgents:Agent[] = this.state.allAgents;
|
|
143
|
-
const states = allAgents.filter(a => a.state !=
|
|
144
|
-
const cities = allAgents.filter(a => a.city !=
|
|
145
|
-
|
|
140
|
+
resetAgents(agents?){
|
|
141
|
+
const allAgents:Agent[] = agents || this.state.allAgents;
|
|
142
|
+
const states = allAgents.filter(a => a.state?.replace(/\s/g, "") != '').map(a => a.state);
|
|
143
|
+
const cities = allAgents.filter(a => a.city?.replace(/\s/g, "") != '').map(a => a.city);
|
|
144
|
+
let uniqStates = [... new Set(states.map(x=>x))];
|
|
145
|
+
let uniqCities = [... new Set(cities.map(x=>x))];
|
|
146
|
+
this.setState({states: uniqStates, cities: uniqCities});
|
|
146
147
|
}
|
|
147
148
|
|
|
148
149
|
findAgents = (formValues) => {
|
|
@@ -190,7 +191,7 @@ class ShowPage extends React.Component <{params;}> {
|
|
|
190
191
|
</Headline>
|
|
191
192
|
|
|
192
193
|
<div id="date-selector">
|
|
193
|
-
<Carousel
|
|
194
|
+
<Carousel infinite={false} arrows dots={false} draggable={true} slidesToScroll= {1} slidesToShow={8}
|
|
194
195
|
prevArrow={
|
|
195
196
|
<SlickButtonFix>
|
|
196
197
|
<Icon path={mdiMenuLeft} size={2} />
|
|
@@ -272,41 +273,45 @@ class ShowPage extends React.Component <{params;}> {
|
|
|
272
273
|
<div className="details-container_header"> Schedule Flight(s) </div>
|
|
273
274
|
<div className="details-container_content">
|
|
274
275
|
<Flex gap={20} vertical>
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
<
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
<label> Kuala Lumpur (KUL) > Guangzhou (CAN) </label>
|
|
282
|
-
<div className="flight-details_airline">
|
|
283
|
-
<img src="/iceholidays-assets/images/china_southern_airlines_icon.png" />
|
|
284
|
-
<span>China Southern Airlines CZ366</span>
|
|
285
|
-
</div>
|
|
286
|
-
</div>
|
|
287
|
-
<div className="flight-time">
|
|
288
|
-
<Flex gap={13}>
|
|
289
|
-
<div className="from">
|
|
290
|
-
<label>08:55</label>
|
|
291
|
-
<span>Kuala Lumpur (KUL)</span>
|
|
276
|
+
{
|
|
277
|
+
selectedTour?.flights.map((flight:any) => (
|
|
278
|
+
<div className="schedule" key={flight.id}>
|
|
279
|
+
<div className="flight-date">
|
|
280
|
+
<Icon path={mdiAirplane} size="12px" />
|
|
281
|
+
<span>{flight.departure_date}</span>
|
|
292
282
|
</div>
|
|
293
|
-
<div className="flight-
|
|
294
|
-
<
|
|
283
|
+
<div className="flight-details">
|
|
284
|
+
<label> {flight.from_airport} > {flight.to_airport} </label>
|
|
285
|
+
<div className="flight-details_airline">
|
|
286
|
+
<img src={flight.airline_logo} />
|
|
287
|
+
<span>{flight.airline}</span>
|
|
288
|
+
</div>
|
|
295
289
|
</div>
|
|
296
|
-
<div className="
|
|
297
|
-
<
|
|
298
|
-
|
|
290
|
+
<div className="flight-time">
|
|
291
|
+
<Flex gap={13}>
|
|
292
|
+
<div className="from">
|
|
293
|
+
<label>{flight.departure_time}</label>
|
|
294
|
+
<span>{flight.from_airport}</span>
|
|
295
|
+
</div>
|
|
296
|
+
<div className="flight-time_icon">
|
|
297
|
+
<img src="/iceholidays-assets/images/plane.png" />
|
|
298
|
+
</div>
|
|
299
|
+
<div className="to">
|
|
300
|
+
<label>{flight.arrival_time}</label>
|
|
301
|
+
<span>{flight.to_airport}</span>
|
|
302
|
+
</div>
|
|
303
|
+
</Flex>
|
|
299
304
|
</div>
|
|
300
|
-
</
|
|
301
|
-
|
|
302
|
-
|
|
305
|
+
</div>
|
|
306
|
+
))
|
|
307
|
+
}
|
|
303
308
|
</Flex>
|
|
304
309
|
</div>
|
|
305
310
|
</div>
|
|
306
311
|
)
|
|
307
312
|
}
|
|
308
313
|
|
|
309
|
-
<PriceDetails priceCurrency={itinerary.priceCurrency} prices={selectedTour?.prices}/>
|
|
314
|
+
{selectedTour?.prices.length > 0 && <PriceDetails priceCurrency={itinerary.priceCurrency} prices={selectedTour?.prices}/>}
|
|
310
315
|
|
|
311
316
|
</Flex>
|
|
312
317
|
</div>
|
|
@@ -484,10 +484,11 @@ a {
|
|
|
484
484
|
margin-top: 100px;
|
|
485
485
|
}
|
|
486
486
|
#ribbon-section_header {
|
|
487
|
-
height:
|
|
487
|
+
height: 150px;
|
|
488
488
|
text-align: center;
|
|
489
489
|
position: relative;
|
|
490
|
-
background-image: url("/iceholidays-assets/images/
|
|
490
|
+
background-image: url("/iceholidays-assets/images/TSTRibbon.png");
|
|
491
|
+
background-repeat: no-repeat;
|
|
491
492
|
}
|
|
492
493
|
#ribbon-section_header h1 {
|
|
493
494
|
font-family: Poppins, san-serif;
|
|
@@ -1243,6 +1244,12 @@ body {
|
|
|
1243
1244
|
display: block;
|
|
1244
1245
|
width: 100%;
|
|
1245
1246
|
}
|
|
1247
|
+
#listing-page #no-tours-found {
|
|
1248
|
+
font-family: Poppins, san-serif;
|
|
1249
|
+
font-weight: 400;
|
|
1250
|
+
text-align: center;
|
|
1251
|
+
color: rgba(0, 0, 12, 0.6);
|
|
1252
|
+
}
|
|
1246
1253
|
|
|
1247
1254
|
.tour_details_description.ant-modal .ant-modal-title {
|
|
1248
1255
|
font-family: Poppins, san-serif;
|
|
@@ -1873,7 +1880,7 @@ body {
|
|
|
1873
1880
|
font-size: 24px;
|
|
1874
1881
|
font-weight: 500;
|
|
1875
1882
|
line-height: 36px;
|
|
1876
|
-
text-align:
|
|
1883
|
+
text-align: center;
|
|
1877
1884
|
text-underline-position: from-font;
|
|
1878
1885
|
text-decoration-skip-ink: none;
|
|
1879
1886
|
}
|