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.
Files changed (108) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/stylesheets/iceholidays/frontend/actiontext.scss +119 -0
  3. data/app/assets/stylesheets/iceholidays/frontend/application.sass.scss +2194 -0
  4. data/app/assets/stylesheets/iceholidays/frontend/common.scss +317 -0
  5. data/app/assets/stylesheets/iceholidays/frontend/layout.scss +281 -0
  6. data/app/assets/stylesheets/iceholidays/frontend/utils/_antd_overrides.scss +122 -0
  7. data/app/assets/stylesheets/iceholidays/frontend/utils/_variables.scss +4 -0
  8. data/app/assets/stylesheets/iceholidays/frontend/widgets/filter_pills.scss +52 -0
  9. data/app/assets/stylesheets/iceholidays/frontend/widgets/search_bar.scss +116 -0
  10. data/app/controllers/iceholidays/frontend/posts_controller.rb +14 -0
  11. data/app/controllers/iceholidays/frontend/site_controller.rb +32 -0
  12. data/app/javascript/api-services/agents-api.service.ts +33 -0
  13. data/app/javascript/api-services/banners-api.service.ts +28 -0
  14. data/app/javascript/api-services/locations-api.service.ts +71 -0
  15. data/app/javascript/api-services/search-api.service.ts +16 -0
  16. data/app/javascript/api-services/series-api.service.ts +64 -0
  17. data/app/javascript/api-services/testimonials-api.service.ts +27 -0
  18. data/app/javascript/interfaces/agent.interface.ts +11 -0
  19. data/app/javascript/interfaces/banner.interface.ts +10 -0
  20. data/app/javascript/interfaces/country.interface.ts +19 -0
  21. data/app/javascript/interfaces/itinerary.interface.ts +111 -0
  22. data/app/javascript/interfaces/testimonial.interface.ts +6 -0
  23. data/app/javascript/react/App.tsx +32 -0
  24. data/app/javascript/react/components/Destinations.tsx +84 -143
  25. data/app/javascript/react/components/PriceDetails.tsx +146 -0
  26. data/app/javascript/react/components/Testimonials.tsx +68 -61
  27. data/app/javascript/react/components/shared/ContactAgentsForm.tsx +44 -0
  28. data/app/javascript/react/components/shared/Headline.tsx +30 -0
  29. data/app/javascript/react/components/shared/LocationDropdown.tsx +34 -0
  30. data/app/javascript/react/components/shared/LocationPostcards.tsx +52 -0
  31. data/app/javascript/react/components/shared/RibbonSection.tsx +21 -0
  32. data/app/javascript/react/index.js +3 -5
  33. data/app/javascript/react/layouts/MainFooter.tsx +97 -0
  34. data/app/javascript/react/layouts/MainHeader.tsx +83 -0
  35. data/app/javascript/react/layouts/MainLayout.tsx +21 -0
  36. data/app/javascript/react/pages/AboutUsPage.tsx +95 -0
  37. data/app/javascript/react/pages/BlogPage.tsx +81 -0
  38. data/app/javascript/react/pages/BlogShowPage.tsx +43 -0
  39. data/app/javascript/react/pages/ContactAgentsPage.tsx +185 -0
  40. data/app/javascript/react/pages/ContactUsPage.tsx +122 -0
  41. data/app/javascript/react/pages/CountriesPage.tsx +57 -0
  42. data/app/javascript/react/pages/Homepage.tsx +100 -0
  43. data/app/javascript/react/pages/ListingPage.tsx +292 -0
  44. data/app/javascript/react/pages/ShowPage.tsx +402 -0
  45. data/app/javascript/react/widgets/FilterPills.tsx +111 -0
  46. data/app/javascript/react/widgets/SearchBarWidget.tsx +58 -0
  47. data/app/views/iceholidays/frontend/posts/index.html.erb +9 -0
  48. data/app/views/iceholidays/frontend/posts/show.html.erb +2 -0
  49. data/app/views/iceholidays/frontend/site/index.html.erb +1 -24
  50. data/app/views/layouts/iceholidays/frontend/application.html.erb +2 -6
  51. data/config/routes.rb +10 -0
  52. data/lib/iceholidays/frontend/version.rb +1 -1
  53. data/public/iceholidays-assets/application.css +2638 -0
  54. data/public/iceholidays-assets/application.js +212 -651
  55. data/public/iceholidays-assets/application.js.map +4 -4
  56. data/public/iceholidays-assets/images/about-us_logo_mobile.png +0 -0
  57. data/public/iceholidays-assets/images/about_us.png +0 -0
  58. data/public/iceholidays-assets/images/about_us2.png +0 -0
  59. data/public/iceholidays-assets/images/blog.png +0 -0
  60. data/public/iceholidays-assets/images/blog1.png +0 -0
  61. data/public/iceholidays-assets/images/certificate1.png +0 -0
  62. data/public/iceholidays-assets/images/certificate2.png +0 -0
  63. data/public/iceholidays-assets/images/china_southern_airlines.png +0 -0
  64. data/public/iceholidays-assets/images/china_southern_airlines_icon.png +0 -0
  65. data/public/iceholidays-assets/images/competitiveness.png +0 -0
  66. data/public/iceholidays-assets/images/contact_agents.png +0 -0
  67. data/public/iceholidays-assets/images/contact_us.png +0 -0
  68. data/public/iceholidays-assets/images/contact_us_form.png +0 -0
  69. data/public/iceholidays-assets/images/destinations_logo.png +0 -0
  70. data/public/iceholidays-assets/images/ethical.png +0 -0
  71. data/public/iceholidays-assets/images/footer-bg_mobile.png +0 -0
  72. data/public/iceholidays-assets/images/hw_logo.png +0 -0
  73. data/public/iceholidays-assets/images/innovative.png +0 -0
  74. data/public/iceholidays-assets/images/logo_mobile.png +0 -0
  75. data/public/iceholidays-assets/images/plane.png +0 -0
  76. data/public/iceholidays-assets/images/social/ico_fb.png +0 -0
  77. data/public/iceholidays-assets/images/social/ico_ig.png +0 -0
  78. data/public/iceholidays-assets/images/social/ico_twitter.png +0 -0
  79. data/public/iceholidays-assets/images/social/ico_yt.png +0 -0
  80. data/public/iceholidays-assets/images/social.png +0 -0
  81. metadata +74 -71
  82. data/app/assets/stylesheets/iceholidays/frontend/application.scss +0 -904
  83. data/app/javascript/react/components/Homepage.tsx +0 -15
  84. data/app/javascript/react/components/HomepageBanner.tsx +0 -62
  85. data/app/views/layouts/iceholidays/frontend/shared/_footer.html.erb +0 -42
  86. data/app/views/layouts/iceholidays/frontend/shared/_header.html.erb +0 -20
  87. data/public/iceholidays-assets/images/Frame71.png +0 -0
  88. data/public/iceholidays-assets/images/africa.png +0 -0
  89. data/public/iceholidays-assets/images/banner1.png +0 -0
  90. data/public/iceholidays-assets/images/banner2.png +0 -0
  91. data/public/iceholidays-assets/images/china.png +0 -0
  92. data/public/iceholidays-assets/images/china2.png +0 -0
  93. data/public/iceholidays-assets/images/guangzhou.png +0 -0
  94. data/public/iceholidays-assets/images/guilin.png +0 -0
  95. data/public/iceholidays-assets/images/harbin.png +0 -0
  96. data/public/iceholidays-assets/images/hongkong.png +0 -0
  97. data/public/iceholidays-assets/images/inner_mongolia.png +0 -0
  98. data/public/iceholidays-assets/images/jiangxi.png +0 -0
  99. data/public/iceholidays-assets/images/kenya.png +0 -0
  100. data/public/iceholidays-assets/images/kenya2.png +0 -0
  101. data/public/iceholidays-assets/images/kunming.png +0 -0
  102. data/public/iceholidays-assets/images/slikroad.png +0 -0
  103. data/public/iceholidays-assets/images/southafrica.png +0 -0
  104. data/public/iceholidays-assets/images/tanzania.png +0 -0
  105. data/public/iceholidays-assets/images/uganda.png +0 -0
  106. /data/public/iceholidays-assets/images/{Group_71.png → about-us_logo.png} +0 -0
  107. /data/public/iceholidays-assets/images/{chongqing.png → china_listings_cover.png} +0 -0
  108. /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
+ }
@@ -0,0 +1,14 @@
1
+ module Iceholidays
2
+ module Frontend
3
+ class PostsController < ApplicationController
4
+
5
+ def index
6
+ @posts = current_brand.posts
7
+ end
8
+
9
+ def show
10
+ @post = current_brand.posts.find(params[:id])
11
+ end
12
+ end
13
+ end
14
+ end
@@ -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,11 @@
1
+ export interface Agent {
2
+ id:number;
3
+ email:string;
4
+ name:string;
5
+ image?:string;
6
+ phone?:string;
7
+ whatsapp?:string;
8
+ address:string;
9
+ city?:string;
10
+ state:string;
11
+ }
@@ -0,0 +1,10 @@
1
+ export interface Banner {
2
+ id?:number;
3
+ title:string;
4
+ url?:string;
5
+ target?:string;
6
+ sortOrder?:number;
7
+ isActive?:boolean;
8
+ desktopImage?:string;
9
+ mobileImage?:string;
10
+ }
@@ -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,6 @@
1
+ export interface Testimonial {
2
+ id:number;
3
+ tour:string;
4
+ comment:string;
5
+ author:string;
6
+ }
@@ -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
+ }