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
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
|
|
2
|
+
.filter-title{
|
|
3
|
+
font-family: $font-default;
|
|
4
|
+
font-size: 12px;
|
|
5
|
+
font-weight: 400;
|
|
6
|
+
line-height: 18px;
|
|
7
|
+
letter-spacing: 0.05em;
|
|
8
|
+
text-align: left;
|
|
9
|
+
text-underline-position: from-font;
|
|
10
|
+
text-decoration-skip-ink: none;
|
|
11
|
+
color: #545047;
|
|
12
|
+
}
|
|
13
|
+
.filter-pill{
|
|
14
|
+
padding: 6px 13px 6px 13px;
|
|
15
|
+
border-radius: 10px;
|
|
16
|
+
background: linear-gradient(360deg, $primary-color 5.04%, #F9E298 99.13%);
|
|
17
|
+
color: #836848;
|
|
18
|
+
cursor: pointer;
|
|
19
|
+
text-align: center;
|
|
20
|
+
|
|
21
|
+
&.default-filter{
|
|
22
|
+
background: #F9E298;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
span{
|
|
26
|
+
font-family: $font-default;
|
|
27
|
+
font-weight: 500;
|
|
28
|
+
font-size: 14px;
|
|
29
|
+
line-height: 21px;
|
|
30
|
+
letter-spacing: 2%;
|
|
31
|
+
text-align: left;
|
|
32
|
+
text-underline-position: from-font;
|
|
33
|
+
text-decoration-skip-ink: none;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
&.selected{
|
|
37
|
+
background: #836848;
|
|
38
|
+
color: #FFFFFF;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@media only screen and (min-width: 769px) {
|
|
44
|
+
.filter-pill{
|
|
45
|
+
span{
|
|
46
|
+
font-size: 18px;
|
|
47
|
+
font-weight: 400;
|
|
48
|
+
line-height: 27px;
|
|
49
|
+
letter-spacing: 0.05em;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
|
|
2
|
+
.ant-input{
|
|
3
|
+
field-sizing: content;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
#search-bar{
|
|
8
|
+
width: 100%;
|
|
9
|
+
height: auto;
|
|
10
|
+
filter: drop-shadow(0 3px 3px #00000026) drop-shadow(0 1px 1px #DFB16399);
|
|
11
|
+
|
|
12
|
+
img{
|
|
13
|
+
display: none;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
#search-bar-widget{
|
|
17
|
+
width: 100%;
|
|
18
|
+
padding: 25px;
|
|
19
|
+
gap: 7px;
|
|
20
|
+
opacity: 0px;
|
|
21
|
+
background: #F7F4EB;
|
|
22
|
+
position: relative;
|
|
23
|
+
|
|
24
|
+
.ant-picker{
|
|
25
|
+
width: 100%;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.ant-form-item{
|
|
29
|
+
margin-bottom: 10px;
|
|
30
|
+
|
|
31
|
+
.ant-form-item-label{
|
|
32
|
+
padding-bottom: 3px;
|
|
33
|
+
|
|
34
|
+
label{
|
|
35
|
+
font-family: $font-default;
|
|
36
|
+
font-size: 12px;
|
|
37
|
+
font-weight: 400;
|
|
38
|
+
line-height: 16.5px;
|
|
39
|
+
letter-spacing: 0.05em;
|
|
40
|
+
text-align: left;
|
|
41
|
+
text-underline-position: from-font;
|
|
42
|
+
text-decoration-skip-ink: none;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.search-button{
|
|
48
|
+
width: 172px;
|
|
49
|
+
margin-top: 20px;
|
|
50
|
+
|
|
51
|
+
span{
|
|
52
|
+
font-family: $font-default;
|
|
53
|
+
font-size: 12px;
|
|
54
|
+
font-weight: 600;
|
|
55
|
+
line-height: 18px;
|
|
56
|
+
text-align: center;
|
|
57
|
+
text-underline-position: from-font;
|
|
58
|
+
text-decoration-skip-ink: none;
|
|
59
|
+
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.ant-picker .ant-picker-input span.ant-picker-suffix {
|
|
64
|
+
margin-left: 1px;
|
|
65
|
+
margin-right: 10px;
|
|
66
|
+
order: -1;
|
|
67
|
+
color: #AA853E;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
@media only screen and (min-width: 769px) {
|
|
74
|
+
#search-bar{
|
|
75
|
+
top: 0;
|
|
76
|
+
left: 0;
|
|
77
|
+
position: absolute;
|
|
78
|
+
display: flex;
|
|
79
|
+
justify-content: center;
|
|
80
|
+
z-index: 1;
|
|
81
|
+
|
|
82
|
+
img{
|
|
83
|
+
display: block;
|
|
84
|
+
margin: 0 -1px; //to hide visible shadow line in between
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
#search-bar-widget{
|
|
88
|
+
width: auto;
|
|
89
|
+
padding: 15px;
|
|
90
|
+
|
|
91
|
+
.ant-space{
|
|
92
|
+
flex-direction: unset;
|
|
93
|
+
align-items: flex-end;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.ant-form{
|
|
97
|
+
display: inline-flex;
|
|
98
|
+
gap: 7px;
|
|
99
|
+
height: 100%;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.ant-form-item{
|
|
103
|
+
margin-bottom: 0;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.ant-input{
|
|
107
|
+
min-width: 272px;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.search-button{
|
|
111
|
+
width: auto;
|
|
112
|
+
margin-bottom: 3px;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
@@ -3,6 +3,38 @@ module Iceholidays
|
|
|
3
3
|
class SiteController < ApplicationController
|
|
4
4
|
def index
|
|
5
5
|
end
|
|
6
|
+
|
|
7
|
+
def listing
|
|
8
|
+
render :index
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def show
|
|
12
|
+
render :index
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def about_us
|
|
16
|
+
render :index
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def countries
|
|
20
|
+
render :index
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def blog
|
|
24
|
+
render :index
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def show_blog
|
|
28
|
+
render :index
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def contact_agents
|
|
32
|
+
render :index
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def contact_us
|
|
36
|
+
render :index
|
|
37
|
+
end
|
|
6
38
|
end
|
|
7
39
|
end
|
|
8
40
|
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import axios from "axios";
|
|
2
|
+
import { Agent } from "../interfaces/agent.interface";
|
|
3
|
+
|
|
4
|
+
class AgentsApi
|
|
5
|
+
{
|
|
6
|
+
|
|
7
|
+
getAgents(): Promise<Agent[]> {
|
|
8
|
+
const apiUrl = "/api/v1/users/agents";
|
|
9
|
+
|
|
10
|
+
return axios.get(apiUrl)
|
|
11
|
+
.then(response => {
|
|
12
|
+
const agents = response.data.agents.map(agentData => {
|
|
13
|
+
const agent:Agent = {
|
|
14
|
+
id: agentData.id,
|
|
15
|
+
name: agentData.full_name,
|
|
16
|
+
email: agentData.email,
|
|
17
|
+
image: agentData.image,
|
|
18
|
+
phone: agentData.phone,
|
|
19
|
+
whatsapp: agentData.whatsapp_no,
|
|
20
|
+
address: agentData.address,
|
|
21
|
+
city: agentData.city,
|
|
22
|
+
state: agentData.state,
|
|
23
|
+
}
|
|
24
|
+
return agent;
|
|
25
|
+
})
|
|
26
|
+
return Promise.resolve(agents);
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export default AgentsApi
|
|
33
|
+
;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import axios from "axios";
|
|
2
|
+
import { Banner } from "../interfaces/banner.interface";
|
|
3
|
+
|
|
4
|
+
class BannersApi {
|
|
5
|
+
|
|
6
|
+
getBanners(): Promise<Banner[]> {
|
|
7
|
+
const apiUrl = "/api/v1/banner";
|
|
8
|
+
|
|
9
|
+
return axios.get(apiUrl)
|
|
10
|
+
.then(response => {
|
|
11
|
+
const banners = response.data.data.attributes.slides.map(slide => {
|
|
12
|
+
const banner:Banner = {
|
|
13
|
+
title: slide.title,
|
|
14
|
+
url: slide.url,
|
|
15
|
+
target: slide.target,
|
|
16
|
+
sortOrder: slide.sort_order,
|
|
17
|
+
desktopImage: slide.image.desktop,
|
|
18
|
+
mobileImage: slide.image.mobile
|
|
19
|
+
}
|
|
20
|
+
return banner;
|
|
21
|
+
})
|
|
22
|
+
return Promise.resolve(banners);
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export default BannersApi;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import axios from "axios";
|
|
2
|
+
import { City, Country, Location } from "../interfaces/country.interface";
|
|
3
|
+
|
|
4
|
+
class LocationsApi {
|
|
5
|
+
|
|
6
|
+
getCountries(): Promise<Country[]> {
|
|
7
|
+
const apiUrl = "/api/v1/locations";
|
|
8
|
+
|
|
9
|
+
return axios.get(apiUrl)
|
|
10
|
+
.then(response => {
|
|
11
|
+
const countries = response.data.map(locationData => {
|
|
12
|
+
const countryData = locationData.data.attributes;
|
|
13
|
+
const citiesData = countryData.children.map(childrenData => this.mapCity(childrenData.data.attributes));
|
|
14
|
+
|
|
15
|
+
const allCities = [...citiesData];
|
|
16
|
+
const citiesWithImages = allCities.filter(x => x.cover != null);
|
|
17
|
+
const topCities = citiesWithImages.splice(0,4);
|
|
18
|
+
const highlights = citiesWithImages.splice(0,5);
|
|
19
|
+
|
|
20
|
+
const country:Country = {
|
|
21
|
+
id: countryData.id,
|
|
22
|
+
name: countryData.name,
|
|
23
|
+
cover: countryData.cover,
|
|
24
|
+
tourCount: countryData.itineraries,
|
|
25
|
+
cities: allCities,
|
|
26
|
+
topCities: topCities,
|
|
27
|
+
highlights: highlights,
|
|
28
|
+
tags: allCities.filter(city => !topCities.includes(city) && !highlights.includes(city)),
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return country;
|
|
32
|
+
})
|
|
33
|
+
return Promise.resolve(countries);
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
getLocation(locationId:number): Promise<Location> {
|
|
38
|
+
const apiUrl = `/api/v1/locations/${locationId}`;
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
return axios.get(apiUrl)
|
|
42
|
+
.then(response => {
|
|
43
|
+
const locationData = response.data.data.attributes;
|
|
44
|
+
const location: Location = {
|
|
45
|
+
id: locationData.id,
|
|
46
|
+
cover: locationData.cover,
|
|
47
|
+
name: locationData.name,
|
|
48
|
+
ancestry: locationData.ancestors.map(a => {
|
|
49
|
+
return {
|
|
50
|
+
id: a.id,
|
|
51
|
+
name: a.name
|
|
52
|
+
}
|
|
53
|
+
})
|
|
54
|
+
}
|
|
55
|
+
return Promise.resolve(location);
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
private mapCity(cityData): City{
|
|
60
|
+
const city:City = {
|
|
61
|
+
id: cityData.id,
|
|
62
|
+
name: cityData.name,
|
|
63
|
+
cover: cityData.cover,
|
|
64
|
+
tourCount: cityData.itineraries
|
|
65
|
+
};
|
|
66
|
+
return city;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export default LocationsApi;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import axios from "axios";
|
|
2
|
+
|
|
3
|
+
class SearchApi {
|
|
4
|
+
|
|
5
|
+
search(keyword:string, month?:number): Promise<any[]> {
|
|
6
|
+
const apiUrl = `/api/v1/series?keyword=${keyword}${month && `&month=${month}`}&type=series`;
|
|
7
|
+
|
|
8
|
+
return axios.get(apiUrl)
|
|
9
|
+
.then(response => {
|
|
10
|
+
return Promise.resolve(response.data);
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export default SearchApi;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import axios from "axios";
|
|
2
|
+
import { Itinerary } from "../interfaces/itinerary.interface";
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class SeriesApi {
|
|
6
|
+
|
|
7
|
+
getItineraries(searchParamsObj): Promise<Itinerary[]> {
|
|
8
|
+
const searchParamsQuery = new URLSearchParams(searchParamsObj).toString()
|
|
9
|
+
const apiUrl = `/api/v1/series?${searchParamsQuery}&type=series`;
|
|
10
|
+
|
|
11
|
+
return axios.get(apiUrl)
|
|
12
|
+
.then(response => {
|
|
13
|
+
const itineraries:Itinerary[] = response.data.itineraries.map(itineraryData => this.mapItinerary(itineraryData));
|
|
14
|
+
return Promise.resolve(itineraries);
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
getItinerary(id): Promise<Itinerary>{
|
|
20
|
+
const apiUrl = `/api/v1/series/${id}`;
|
|
21
|
+
|
|
22
|
+
return axios.get(apiUrl)
|
|
23
|
+
.then(response => {
|
|
24
|
+
const itinerary = this.mapItinerary(response.data);
|
|
25
|
+
return Promise.resolve(itinerary);
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
private mapItinerary(itineraryData):Itinerary {
|
|
31
|
+
const itinerary:Itinerary = {
|
|
32
|
+
id: itineraryData.id,
|
|
33
|
+
description: itineraryData.description,
|
|
34
|
+
caption: itineraryData.caption,
|
|
35
|
+
otherCaption: itineraryData.otherCaption,
|
|
36
|
+
code: itineraryData.code,
|
|
37
|
+
category: itineraryData.category,
|
|
38
|
+
country: itineraryData.country,
|
|
39
|
+
price: itineraryData.price,
|
|
40
|
+
images: itineraryData.images,
|
|
41
|
+
coverImage: itineraryData.images[0],
|
|
42
|
+
priceCurrency: itineraryData.price_currency,
|
|
43
|
+
departureDate: itineraryData.departure_date,
|
|
44
|
+
guranteedDepartureDates: itineraryData.guranteed_departure_dates,
|
|
45
|
+
almostGuaranteedDepartureDates: itineraryData.almost_guaranteed_departure_dates,
|
|
46
|
+
departureLocations: itineraryData.departure_locations,
|
|
47
|
+
totalItineraries: itineraryData.total_itineraries,
|
|
48
|
+
fileUrl: itineraryData.file_url,
|
|
49
|
+
|
|
50
|
+
autoCancel: itineraryData.auto_cancel,
|
|
51
|
+
ccRate: itineraryData.cc_rate,
|
|
52
|
+
includings: itineraryData.includings,
|
|
53
|
+
maxBookingSeats: itineraryData.max_booking_seats,
|
|
54
|
+
remark: itineraryData.remark,
|
|
55
|
+
tourType: itineraryData.tour_type,
|
|
56
|
+
tours: itineraryData.tours,
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return itinerary;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export default SeriesApi;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import axios from "axios";
|
|
2
|
+
import { Testimonial } from "../interfaces/testimonial.interface";
|
|
3
|
+
|
|
4
|
+
class TestimonialsApi {
|
|
5
|
+
|
|
6
|
+
getTestimonials(): Promise<Testimonial[]> {
|
|
7
|
+
const apiUrl = "/api/v1/testimonials";
|
|
8
|
+
|
|
9
|
+
return axios.get(apiUrl)
|
|
10
|
+
.then(response => {
|
|
11
|
+
const testimonials = response.data.data.map(responseData => {
|
|
12
|
+
const testimonialData = responseData.attributes;
|
|
13
|
+
const testimonial:Testimonial = {
|
|
14
|
+
id: testimonialData.id,
|
|
15
|
+
tour: testimonialData.tour,
|
|
16
|
+
author: testimonialData.author,
|
|
17
|
+
comment: testimonialData.body,
|
|
18
|
+
}
|
|
19
|
+
return testimonial;
|
|
20
|
+
})
|
|
21
|
+
return Promise.resolve(testimonials);
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export default TestimonialsApi;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export interface Country extends Location {
|
|
2
|
+
cities:City[];
|
|
3
|
+
topCities:City[];
|
|
4
|
+
highlights:City[];
|
|
5
|
+
tags:City[];
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface City extends Location {
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
export interface Location {
|
|
13
|
+
id:number;
|
|
14
|
+
cover?:string;
|
|
15
|
+
name:string;
|
|
16
|
+
tourCount?:number;
|
|
17
|
+
ancestry?: Location[];
|
|
18
|
+
|
|
19
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
export interface Itinerary {
|
|
2
|
+
id: number;
|
|
3
|
+
description: string;
|
|
4
|
+
code: string;
|
|
5
|
+
category: string;
|
|
6
|
+
caption: string;
|
|
7
|
+
otherCaption: string;
|
|
8
|
+
country: string;
|
|
9
|
+
fileUrl?: string;
|
|
10
|
+
price?: string;
|
|
11
|
+
departureDate?: string[];
|
|
12
|
+
guranteedDepartureDates?: string[];
|
|
13
|
+
almostGuaranteedDepartureDates?: string[];
|
|
14
|
+
departureLocations?: string[];
|
|
15
|
+
coverImage?:string[];
|
|
16
|
+
images: string[];
|
|
17
|
+
priceCurrency?: string;
|
|
18
|
+
totalItineraries?: number;
|
|
19
|
+
|
|
20
|
+
autoCancel?:boolean;
|
|
21
|
+
ccRate?: number;
|
|
22
|
+
includings?: ItineraryIncludings;
|
|
23
|
+
maxBookingSeats?: number;
|
|
24
|
+
remark?: string;
|
|
25
|
+
tourType?: string;
|
|
26
|
+
tours?: Tour[];
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
interface ItineraryIncludings {
|
|
30
|
+
acf: boolean;
|
|
31
|
+
airport_taxes: boolean;
|
|
32
|
+
gratuities: boolean;
|
|
33
|
+
group_departure: boolean;
|
|
34
|
+
hotel: boolean;
|
|
35
|
+
luggage: boolean;
|
|
36
|
+
meal_onboard: boolean;
|
|
37
|
+
tour_leader: boolean;
|
|
38
|
+
wifi: boolean;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface Tour {
|
|
42
|
+
id:number;
|
|
43
|
+
addon_others:number;
|
|
44
|
+
allow_customer_pay: boolean;
|
|
45
|
+
arrival_date: string;
|
|
46
|
+
caption: string;
|
|
47
|
+
code: string;
|
|
48
|
+
compulsory_additional_fee: number;
|
|
49
|
+
credit_available: number;
|
|
50
|
+
customer_deposit: number;
|
|
51
|
+
day_before_departure: number;
|
|
52
|
+
departure_date: string;
|
|
53
|
+
departure_location: string;
|
|
54
|
+
deposit: number;
|
|
55
|
+
deposit_date: string;
|
|
56
|
+
dobw_available: any;
|
|
57
|
+
dobw_cor_available: any;
|
|
58
|
+
dobw_ret_available: any;
|
|
59
|
+
extra_deposit: number;
|
|
60
|
+
fare_type: string;
|
|
61
|
+
final_payment_date: string;
|
|
62
|
+
flights: any[];
|
|
63
|
+
fpxb2b_available:any;
|
|
64
|
+
fpxb2c_available:any;
|
|
65
|
+
guaranteed_departure: boolean;
|
|
66
|
+
guaranteed_indicator: string;
|
|
67
|
+
highlight: string;
|
|
68
|
+
insurance: string;
|
|
69
|
+
insurance_rebate: number;
|
|
70
|
+
latest_tour_confirmation: LatestTourConfirmation;
|
|
71
|
+
max_booking_seats: number;
|
|
72
|
+
min_dta: number;
|
|
73
|
+
pay_later: string;
|
|
74
|
+
pbb2_available: string;
|
|
75
|
+
pre_commisions: any[];
|
|
76
|
+
price: number;
|
|
77
|
+
prices: Price[];
|
|
78
|
+
red_luggage_protection: boolean;
|
|
79
|
+
single_supplement_price: string;
|
|
80
|
+
subtract_others: number;
|
|
81
|
+
visa_fee: number;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
interface LatestTourConfirmation {
|
|
85
|
+
assembly_time: string;
|
|
86
|
+
confirmation_emergency_contact: string;
|
|
87
|
+
hand_carry_weight: string;
|
|
88
|
+
luggage_quantity: string;
|
|
89
|
+
luggage_weight: string;
|
|
90
|
+
meet_up_point: string;
|
|
91
|
+
tour_guide_chinese_name: string;
|
|
92
|
+
tour_guide_name: string;
|
|
93
|
+
tour_guide_phone: string;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
interface Price {
|
|
97
|
+
display_price: string;
|
|
98
|
+
adult: number;
|
|
99
|
+
child_no_bed: number;
|
|
100
|
+
child_twin: number;
|
|
101
|
+
child_with_bed: number;
|
|
102
|
+
dta_adult: number;
|
|
103
|
+
dta_child_no_bed: number;
|
|
104
|
+
dta_child_twin: number;
|
|
105
|
+
dta_child_with_bed: number;
|
|
106
|
+
dta_infant: number;
|
|
107
|
+
dta_single_supplement: number;
|
|
108
|
+
infant: number;
|
|
109
|
+
single_supplement: number;
|
|
110
|
+
type: string;
|
|
111
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { BrowserRouter, Routes, Route } from "react-router-dom";
|
|
3
|
+
import Homepage from "./pages/Homepage";
|
|
4
|
+
import ListingPage from "./pages/ListingPage";
|
|
5
|
+
import ShowPage from "./pages/ShowPage";
|
|
6
|
+
import MainLayout from "./layouts/MainLayout";
|
|
7
|
+
import AboutUsPage from "./pages/AboutUsPage";
|
|
8
|
+
import CountriesPage from "./pages/CountriesPage";
|
|
9
|
+
import BlogPage from "./pages/BlogPage";
|
|
10
|
+
import ContactAgentsPage from "./pages/ContactAgentsPage";
|
|
11
|
+
import ContactUsPage from "./pages/ContactUsPage";
|
|
12
|
+
import BlogShowPage from "./pages/BlogShowPage";
|
|
13
|
+
|
|
14
|
+
export default function App() {
|
|
15
|
+
return (
|
|
16
|
+
<BrowserRouter>
|
|
17
|
+
<Routes>
|
|
18
|
+
<Route path="/app" element={<MainLayout />}>
|
|
19
|
+
<Route index element={<Homepage />} />
|
|
20
|
+
<Route path="/app/listing" element={<ListingPage />} />
|
|
21
|
+
<Route path="/app/itinerary/:id" element={<ShowPage />} />
|
|
22
|
+
<Route path="/app/about-us" element={<AboutUsPage />} />
|
|
23
|
+
<Route path="/app/countries" element={<CountriesPage />} />
|
|
24
|
+
<Route path="/app/blog" element={<BlogPage />} />
|
|
25
|
+
<Route path="/app/blog/1" element={<BlogShowPage />} />
|
|
26
|
+
<Route path="/app/contact-agents" element={<ContactAgentsPage />} />
|
|
27
|
+
<Route path="/app/contact-us" element={<ContactUsPage />} />
|
|
28
|
+
</Route>
|
|
29
|
+
</Routes>
|
|
30
|
+
</BrowserRouter>
|
|
31
|
+
);
|
|
32
|
+
}
|