bukazu-portal-react 2.1.21 → 3.0.2

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 (191) hide show
  1. package/.github/workflows/dependabot.yml +11 -0
  2. package/.github/workflows/node.js.yml +31 -0
  3. package/.prettierrc +3 -6
  4. package/CHANGELOG.MD +5 -0
  5. package/babel.config.json +1 -1
  6. package/build/index.css +1 -2312
  7. package/build/portal.es.js +35483 -0
  8. package/build/portal.umd.js +596 -0
  9. package/{build/calendar.html → calendar.html} +2 -4
  10. package/coverage/clover.xml +28 -0
  11. package/coverage/coverage-final.json +2 -0
  12. package/coverage/lcov-report/base.css +224 -0
  13. package/coverage/lcov-report/block-navigation.js +87 -0
  14. package/coverage/lcov-report/favicon.png +0 -0
  15. package/coverage/lcov-report/helper.ts.html +142 -0
  16. package/coverage/lcov-report/index.html +116 -0
  17. package/coverage/lcov-report/prettify.css +1 -0
  18. package/coverage/lcov-report/prettify.js +2 -0
  19. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  20. package/coverage/lcov-report/sorter.js +196 -0
  21. package/coverage/lcov.info +36 -0
  22. package/cypress/{integration → e2e}/.examples/actions.spec.js +0 -0
  23. package/cypress/{integration → e2e}/.examples/aliasing.spec.js +0 -0
  24. package/cypress/{integration → e2e}/.examples/assertions.spec.js +0 -0
  25. package/cypress/{integration → e2e}/.examples/connectors.spec.js +0 -0
  26. package/cypress/{integration → e2e}/.examples/cookies.spec.js +0 -0
  27. package/cypress/{integration → e2e}/.examples/cypress_api.spec.js +0 -0
  28. package/cypress/{integration → e2e}/.examples/files.spec.js +0 -0
  29. package/cypress/{integration → e2e}/.examples/local_storage.spec.js +0 -0
  30. package/cypress/{integration → e2e}/.examples/location.spec.js +0 -0
  31. package/cypress/{integration → e2e}/.examples/misc.spec.js +0 -0
  32. package/cypress/{integration → e2e}/.examples/navigation.spec.js +0 -0
  33. package/cypress/{integration → e2e}/.examples/network_requests.spec.js +0 -0
  34. package/cypress/{integration → e2e}/.examples/querying.spec.js +0 -0
  35. package/cypress/{integration → e2e}/.examples/spies_stubs_clocks.spec.js +0 -0
  36. package/cypress/{integration → e2e}/.examples/traversal.spec.js +0 -0
  37. package/cypress/{integration → e2e}/.examples/utilities.spec.js +0 -0
  38. package/cypress/{integration → e2e}/.examples/viewport.spec.js +0 -0
  39. package/cypress/{integration → e2e}/.examples/waiting.spec.js +0 -0
  40. package/cypress/{integration → e2e}/.examples/window.spec.js +0 -0
  41. package/cypress/{integration → e2e}/booking.spec.js +0 -0
  42. package/cypress/{integration → e2e}/calendar.spec.js +0 -0
  43. package/cypress/{integration → e2e}/search.spec.js +0 -0
  44. package/cypress/support/commands.ts +37 -0
  45. package/cypress/support/component-index.html +12 -0
  46. package/cypress/support/component.ts +39 -0
  47. package/cypress/support/{index.js → e2e.js} +0 -0
  48. package/cypress.config.ts +15 -0
  49. package/{dev.js → dev.tsx} +1 -1
  50. package/index.html +15 -0
  51. package/{build/invalid-calendar.html → invalid-calendar.html} +0 -0
  52. package/jest.config.js +195 -0
  53. package/package.json +35 -40
  54. package/reviews.html +16 -0
  55. package/src/_lib/{SearchQueries.js → SearchQueries.ts} +8 -2
  56. package/src/_lib/{countries.js → countries.ts} +0 -0
  57. package/src/_lib/date_helper.ts +27 -0
  58. package/src/_lib/{queries.js → queries.ts} +24 -5
  59. package/src/components/App.tsx +132 -0
  60. package/src/components/AppContext.ts +14 -0
  61. package/src/components/CalendarPage/BookingForm.tsx +42 -0
  62. package/src/components/CalendarPage/Calendar.tsx +50 -0
  63. package/src/components/CalendarPage/CalendarPage.tsx +43 -0
  64. package/src/components/CalendarPage/CalendarParts/CalendarContext.tsx +89 -0
  65. package/src/components/CalendarPage/CalendarParts/CalendarHeader.tsx +72 -0
  66. package/src/components/CalendarPage/CalendarParts/DayClasses.ts +111 -0
  67. package/src/components/CalendarPage/CalendarParts/GenerateCalendar.tsx +64 -0
  68. package/src/components/CalendarPage/CalendarParts/Legend.tsx +33 -0
  69. package/src/components/CalendarPage/CalendarParts/MonthHeader.tsx +15 -0
  70. package/src/components/CalendarPage/CalendarParts/Months.tsx +37 -0
  71. package/src/components/CalendarPage/CalendarParts/RenderCells.tsx +94 -0
  72. package/src/components/CalendarPage/CalendarParts/SingleMonth.tsx +72 -0
  73. package/src/components/CalendarPage/CalendarParts/StartBooking.tsx +17 -0
  74. package/src/components/CalendarPage/CalendarParts/WeekDays.tsx +27 -0
  75. package/src/components/CalendarPage/FormCreator.tsx +213 -0
  76. package/src/components/CalendarPage/FormItems/{Date.js → Date.tsx} +10 -2
  77. package/src/components/CalendarPage/FormItems/{NumberSelect.js → NumberSelect.tsx} +1 -1
  78. package/src/components/CalendarPage/FormItems/{Select.js → Select.tsx} +0 -0
  79. package/src/components/CalendarPage/FormItems/{index.js → index.ts} +0 -0
  80. package/src/components/CalendarPage/PriceField/Price.tsx +58 -0
  81. package/src/components/CalendarPage/PriceField/Queries.ts +23 -0
  82. package/src/components/CalendarPage/PriceField/index.tsx +127 -0
  83. package/src/components/CalendarPage/Summary/{CostRow.js → CostRow.tsx} +19 -3
  84. package/src/components/CalendarPage/Summary/{CostSection.js → CostSection.tsx} +5 -1
  85. package/src/components/CalendarPage/Summary/{CostSummary.js → CostSummary.tsx} +19 -10
  86. package/src/components/CalendarPage/Summary/Description.tsx +27 -0
  87. package/src/components/CalendarPage/Summary/{InsurancesAndRequired.js → InsurancesAndRequired.tsx} +21 -2
  88. package/src/components/CalendarPage/Summary/Object.tsx +59 -0
  89. package/src/components/CalendarPage/Summary/{OnSite.js → OnSite.tsx} +9 -9
  90. package/src/components/CalendarPage/Summary/{OptionalNotOnSite.js → OptionalNotOnSite.tsx} +19 -18
  91. package/src/components/CalendarPage/Summary/{OptionalOnSite.js → OptionalOnSite.tsx} +6 -1
  92. package/src/components/CalendarPage/Summary/{Queries.js → Queries.ts} +3 -3
  93. package/src/components/CalendarPage/Summary/RentAndDiscount.tsx +30 -0
  94. package/src/components/CalendarPage/Summary/{Totals.js → Totals.tsx} +8 -3
  95. package/src/components/CalendarPage/Summary/cost_types.d.ts +31 -0
  96. package/src/components/CalendarPage/Summary/index.tsx +24 -0
  97. package/src/components/CalendarPage/calender_types.d.ts +16 -0
  98. package/src/components/CalendarPage/formParts/AssistanceMessage.tsx +60 -0
  99. package/src/components/CalendarPage/formParts/{BookingHelpers.js → BookingHelpers.tsx} +3 -3
  100. package/src/components/CalendarPage/formParts/{BookingOrOption.js → BookingOrOption.tsx} +6 -1
  101. package/src/components/CalendarPage/formParts/CancelInsuranceText.tsx +105 -0
  102. package/src/components/CalendarPage/formParts/{DefaultBookingFields.js → DefaultBookingFields.ts} +3 -1
  103. package/src/components/CalendarPage/formParts/DiscountCode.tsx +62 -0
  104. package/src/components/CalendarPage/formParts/{Guests.js → Guests.tsx} +10 -4
  105. package/src/components/CalendarPage/formParts/{OptionalBookingFields.js → OptionalBookingFields.tsx} +0 -0
  106. package/src/components/CalendarPage/formParts/{OptionalCosts.js → OptionalCosts.tsx} +1 -2
  107. package/src/components/CalendarPage/formParts/{SuccessMessage.js → SuccessMessage.tsx} +0 -0
  108. package/src/components/CalendarPage/formParts/Validations.tsx +78 -0
  109. package/src/components/CalendarPage/formParts/{discount.js → discount.tsx} +11 -2
  110. package/src/components/CalendarPage/formParts/form_types.d.ts +38 -0
  111. package/src/components/CalendarPage/formParts/{insurances.js → insurances.tsx} +14 -10
  112. package/src/components/CalendarPage/formParts/{radioButtons.js → radioButtons.tsx} +0 -0
  113. package/src/components/Error/{ApiError.js → ApiError.tsx} +6 -4
  114. package/src/components/Error/{IntegrationError.js → IntegrationError.tsx} +17 -11
  115. package/src/components/Error/{index.js → index.ts} +0 -0
  116. package/src/components/{ErrorBoundary.js → ErrorBoundary.tsx} +13 -5
  117. package/src/components/Modal/index.tsx +46 -0
  118. package/src/components/ReviewsPage/Queries.ts +26 -0
  119. package/src/components/ReviewsPage/ReviewsPage.tsx +43 -0
  120. package/src/components/ReviewsPage/Score.tsx +25 -0
  121. package/src/components/ReviewsPage/SingleReview.tsx +38 -0
  122. package/src/components/SafeBooking.tsx +97 -0
  123. package/src/components/SearchPage/Field.tsx +75 -0
  124. package/src/components/SearchPage/Filters.tsx +91 -0
  125. package/src/components/SearchPage/Paginator.tsx +63 -0
  126. package/src/components/SearchPage/Results.tsx +129 -0
  127. package/src/components/SearchPage/{SearchPage.js → SearchPage.tsx} +42 -31
  128. package/src/components/SearchPage/{SingleResult.js → SingleResult.tsx} +15 -8
  129. package/src/components/SearchPage/filters/Categories.tsx +57 -0
  130. package/src/components/SearchPage/filters/DateFilter.tsx +34 -0
  131. package/src/components/SearchPage/filters/List.tsx +80 -0
  132. package/src/components/SearchPage/filters/NumberFilter.tsx +37 -0
  133. package/src/components/SearchPage/filters/Radio.tsx +46 -0
  134. package/src/components/SearchPage/filters/Select.tsx +85 -0
  135. package/src/components/SearchPage/filters/__tests__/helper.spec.js +15 -0
  136. package/src/components/SearchPage/filters/filter_types.d.ts +25 -0
  137. package/src/components/SearchPage/filters/helper.ts +19 -0
  138. package/src/components/icons/ArrowLeft.svg.tsx +20 -0
  139. package/src/components/icons/{ArrowRight.svg.js → ArrowRight.svg.tsx} +0 -0
  140. package/src/components/icons/{Reload.svg.js → Reload.svg.tsx} +0 -0
  141. package/src/components/icons/{info.svg.js → info.svg.tsx} +0 -0
  142. package/src/components/icons/{loading.svg.js → loading.svg.tsx} +1 -1
  143. package/src/custom.d.ts +10 -0
  144. package/src/index.tsx +93 -0
  145. package/src/locales/de.json +4 -3
  146. package/src/locales/en.json +4 -3
  147. package/src/locales/es.json +4 -3
  148. package/src/locales/fr.json +4 -3
  149. package/src/locales/it.json +4 -3
  150. package/src/locales/nl.json +4 -3
  151. package/src/styles/main.css +2 -1
  152. package/src/styles/modal.css +1 -1
  153. package/src/styles/pagination.css +25 -23
  154. package/src/styles/result.css +33 -2
  155. package/src/styles/reviews.css +76 -0
  156. package/src/types.d.ts +85 -0
  157. package/tsconfig.json +17 -0
  158. package/vite.config.ts +31 -0
  159. package/build/index.html +0 -16
  160. package/build/index.js +0 -48528
  161. package/cypress.json +0 -9
  162. package/rollup.config.js +0 -30
  163. package/src/_lib/format.js +0 -16
  164. package/src/components/App.js +0 -164
  165. package/src/components/CalendarPage/BookingForm.js +0 -57
  166. package/src/components/CalendarPage/Calendar.js +0 -373
  167. package/src/components/CalendarPage/CalendarHeader.js +0 -58
  168. package/src/components/CalendarPage/CalendarPage.js +0 -158
  169. package/src/components/CalendarPage/FormCreator.js +0 -278
  170. package/src/components/CalendarPage/FormItems/Wrapper.js +0 -0
  171. package/src/components/CalendarPage/PriceField.js +0 -203
  172. package/src/components/CalendarPage/Summary/Description.js +0 -22
  173. package/src/components/CalendarPage/Summary/Object.js +0 -46
  174. package/src/components/CalendarPage/Summary/RentAndDiscount.js +0 -21
  175. package/src/components/CalendarPage/Summary/index.js +0 -19
  176. package/src/components/CalendarPage/formParts/AssistanceMessage.js +0 -47
  177. package/src/components/CalendarPage/formParts/CancelInsuranceText.js +0 -91
  178. package/src/components/CalendarPage/formParts/DiscountCode.js +0 -62
  179. package/src/components/CalendarPage/formParts/summary.js +0 -43
  180. package/src/components/Modal/index.js +0 -58
  181. package/src/components/ReviewsPage/ReviewsPage.js +0 -15
  182. package/src/components/SafeBooking.js +0 -69
  183. package/src/components/SearchPage/Field.js +0 -241
  184. package/src/components/SearchPage/Filters.js +0 -108
  185. package/src/components/SearchPage/Paginator.js +0 -59
  186. package/src/components/SearchPage/Results.js +0 -130
  187. package/src/components/SearchPage/filters/List.js +0 -63
  188. package/src/components/icons/ArrowLeft.svg.js +0 -18
  189. package/src/index.js +0 -74
  190. package/webpack.config.dev.js +0 -53
  191. package/webpack.config.js +0 -67
@@ -0,0 +1,50 @@
1
+ import React, { useState } from 'react';
2
+ import { addMonths, subMonths } from 'date-fns';
3
+ import CalendarHeader from './CalendarParts/CalendarHeader';
4
+ import AssistanceMessage from './formParts/AssistanceMessage';
5
+ import Legend from './CalendarParts/Legend';
6
+ import Months from './CalendarParts/Months';
7
+ import StartBooking from './CalendarParts/StartBooking';
8
+ import { HouseType } from '../../types';
9
+
10
+ interface Props {
11
+ numberOfMonths: number;
12
+ numberOfMonthsInARow: number;
13
+ house: HouseType;
14
+ }
15
+
16
+ function Calendar({
17
+ numberOfMonths,
18
+ house,
19
+ numberOfMonthsInARow
20
+ }: Props): JSX.Element {
21
+ const [currentMonth, setCurrentMonth] = useState(new Date());
22
+
23
+ return (
24
+ <div className="calendar-container ">
25
+ <StartBooking house={house} />
26
+ <div className="calendar-section">
27
+ <CalendarHeader
28
+ changeMonth={setCurrentMonth}
29
+ currentMonth={currentMonth}
30
+ numberOfMonths={numberOfMonths}
31
+ />
32
+ <Months
33
+ house={house}
34
+ numberOfMonths={numberOfMonths}
35
+ numberOfMonthsInARow={numberOfMonthsInARow}
36
+ currentMonth={currentMonth}
37
+ />
38
+ <Legend house={house} />
39
+ <AssistanceMessage house={house} />
40
+ </div>
41
+ </div>
42
+ );
43
+ }
44
+
45
+ Calendar.defaultProps = {
46
+ numberOfMonths: 4,
47
+ numberOfMonthsInARow: 2
48
+ };
49
+
50
+ export default Calendar;
@@ -0,0 +1,43 @@
1
+ import React, { useContext } from 'react';
2
+ import BookingForm from './BookingForm';
3
+ import GenerateCalendar from './CalendarParts/GenerateCalendar';
4
+ import { PortalSiteType } from '../../types';
5
+ import {
6
+ CalendarContext,
7
+ CalendarProvider
8
+ } from './CalendarParts/CalendarContext';
9
+
10
+ interface Props {
11
+ PortalSite: PortalSiteType;
12
+ }
13
+
14
+ function CalendarPage({ PortalSite }: Props): JSX.Element {
15
+ const { bookingStarted } = useContext(CalendarContext);
16
+
17
+ if (bookingStarted) {
18
+ return <BookingForm />;
19
+ } else {
20
+ return <GenerateCalendar PortalSite={PortalSite} />;
21
+ }
22
+ }
23
+
24
+ CalendarPage.DefaultProps = {
25
+ PortalSite: {
26
+ options: {
27
+ bookingForm: {
28
+ numberOfMonths: 4,
29
+ numberOfMonthsInARow: 2
30
+ }
31
+ }
32
+ }
33
+ };
34
+
35
+ function CalendarWrapper({ PortalSite }: Props): JSX.Element {
36
+ return (
37
+ <CalendarProvider>
38
+ <CalendarPage PortalSite={PortalSite} />
39
+ </CalendarProvider>
40
+ );
41
+ }
42
+
43
+ export default CalendarWrapper;
@@ -0,0 +1,89 @@
1
+ import { differenceInCalendarDays, isAfter } from 'date-fns';
2
+ import React, { createContext, useReducer } from 'react';
3
+ import { BuDate, HouseType } from '../../../types';
4
+ import { Parse_EN_US } from '../../../_lib/date_helper';
5
+ import { BookingType } from '../calender_types';
6
+
7
+ const initialBooking: BookingType = {
8
+ selectedDate: null,
9
+ arrivalDate: null,
10
+ departureDate: null,
11
+ bookingStarted: false,
12
+ persons: 2
13
+ };
14
+
15
+ export const CalendarContext = createContext<BookingType>(initialBooking);
16
+ export const CalendarContextDispatch = createContext<Function>(calendarReducer);
17
+
18
+ export function CalendarProvider({
19
+ children
20
+ }: {
21
+ children: React.ReactNode;
22
+ }): React.ReactNode {
23
+ const [booking_state, dispatch] = useReducer(calendarReducer, initialBooking);
24
+ return (
25
+ <CalendarContext.Provider value={booking_state}>
26
+ <CalendarContextDispatch.Provider value={dispatch}>
27
+ {children}
28
+ </CalendarContextDispatch.Provider>
29
+ </CalendarContext.Provider>
30
+ );
31
+ }
32
+
33
+ function calendarReducer(
34
+ bookingState: BookingType,
35
+ action: { type: string; house: HouseType; day: BuDate; persons: number }
36
+ ): BookingType {
37
+ console.log({ action });
38
+ switch (action.type) {
39
+ case 'clicked': {
40
+ const { day, house } = action;
41
+ const { selectedDate, arrivalDate } = bookingState;
42
+ const date = Parse_EN_US(day.date);
43
+
44
+ if (
45
+ day.departure &&
46
+ selectedDate &&
47
+ arrivalDate &&
48
+ isAfter(date, selectedDate) &&
49
+ differenceInCalendarDays(date, selectedDate) <= house.max_nights &&
50
+ differenceInCalendarDays(date, selectedDate) >=
51
+ arrivalDate.min_nights &&
52
+ differenceInCalendarDays(date, selectedDate) <= arrivalDate.max_nights
53
+ ) {
54
+ return {
55
+ ...bookingState,
56
+ departureDate: day
57
+ };
58
+ } else if (day.arrival) {
59
+ return {
60
+ bookingStarted: false,
61
+ selectedDate: date,
62
+ arrivalDate: day,
63
+ departureDate: null,
64
+ persons: 2
65
+ };
66
+ }
67
+ return bookingState;
68
+ }
69
+ case 'reset': {
70
+ return initialBooking;
71
+ }
72
+ case 'start': {
73
+ return {
74
+ ...bookingState,
75
+ bookingStarted: true,
76
+ persons: action.persons
77
+ };
78
+ }
79
+ case 'return': {
80
+ return {
81
+ ...bookingState,
82
+ bookingStarted: false
83
+ };
84
+ }
85
+ default: {
86
+ throw Error('Unknown action: ' + action.type);
87
+ }
88
+ }
89
+ }
@@ -0,0 +1,72 @@
1
+ import React, { useContext } from 'react';
2
+ import ArrowRight from '../../icons/ArrowRight.svg';
3
+ import ArrowLeft from '../../icons/ArrowLeft.svg';
4
+ import Reload from '../../icons/Reload.svg';
5
+ import { CalendarContextDispatch } from './CalendarContext';
6
+ import { addMonths, subMonths } from 'date-fns';
7
+
8
+ interface Props {
9
+ changeMonth: Function;
10
+ currentMonth: Date;
11
+ numberOfMonths: number;
12
+ }
13
+
14
+ function CalendarHeader({
15
+ changeMonth,
16
+ currentMonth,
17
+ numberOfMonths
18
+ }: Props): JSX.Element {
19
+ const dispatch = useContext(CalendarContextDispatch);
20
+
21
+ function next() {
22
+ changeMonth(addMonths(currentMonth, numberOfMonths));
23
+ }
24
+ function prev() {
25
+ changeMonth(subMonths(currentMonth, numberOfMonths));
26
+ }
27
+
28
+ return (
29
+ <div className="calendars-header">
30
+ <div
31
+ className="col bu-prev"
32
+ style={{ textAlign: 'center' }}
33
+ onClick={prev}
34
+ tabIndex={0}
35
+ role="button"
36
+ >
37
+ <div className="icon">
38
+ {' '}
39
+ <ArrowLeft />
40
+ </div>
41
+ </div>
42
+ <div
43
+ className="col bu-reset"
44
+ onClick={() => {
45
+ dispatch({
46
+ type: 'reset'
47
+ });
48
+ }}
49
+ style={{ textAlign: 'center' }}
50
+ tabIndex={0}
51
+ role="button"
52
+ >
53
+ <div className="icon">
54
+ <Reload />
55
+ </div>
56
+ </div>
57
+ <div
58
+ className="col bu-next"
59
+ onClick={next}
60
+ style={{ textAlign: 'center' }}
61
+ tabIndex={0}
62
+ role="button"
63
+ >
64
+ <div className="icon">
65
+ <ArrowRight />
66
+ </div>
67
+ </div>
68
+ </div>
69
+ );
70
+ }
71
+
72
+ export default CalendarHeader;
@@ -0,0 +1,111 @@
1
+ import {
2
+ addDays,
3
+ differenceInCalendarDays,
4
+ isAfter,
5
+ isBefore,
6
+ isSameDay,
7
+ isSameMonth,
8
+ subDays
9
+ } from 'date-fns';
10
+ import { BuDate } from '../../../types';
11
+ import { Parse_EN_US } from '../../../_lib/date_helper';
12
+
13
+ interface Props {
14
+ day: Date;
15
+ monthStart: Date;
16
+ prevBooked: BuDate;
17
+ buDate: BuDate;
18
+ dates: {
19
+ selectedDate: Date;
20
+ departureDate: BuDate;
21
+ arrivalDate: BuDate;
22
+ };
23
+ house: {
24
+ max_nights: Number;
25
+ };
26
+ discounts: [];
27
+ }
28
+
29
+ function DayClasses({
30
+ day,
31
+ monthStart,
32
+ buDate,
33
+ prevBooked,
34
+ dates,
35
+ house,
36
+ discounts
37
+ }: Props): string {
38
+ const { selectedDate, departureDate, arrivalDate } = dates;
39
+ let classes = ['col', 'cell'];
40
+
41
+ if (!isSameMonth(day, monthStart)) {
42
+ classes.push('disabled');
43
+ return classes.join(' ');
44
+ }
45
+ if (buDate) {
46
+ if (buDate.arrival && isAfter(day, new Date()) && buDate.max_nights !== 0) {
47
+ if (prevBooked.max_nights === 0) {
48
+ classes.push('departure-arrival');
49
+ } else {
50
+ classes.push('arrival');
51
+ classes.push('arrival');
52
+ }
53
+ } else if (buDate.max_nights === 0) {
54
+ if (prevBooked.max_nights !== 0) {
55
+ classes.push('booked-departure');
56
+ } else {
57
+ classes.push('booked');
58
+ }
59
+ }
60
+ }
61
+
62
+ if (selectedDate) {
63
+ if (isSameDay(day, selectedDate)) {
64
+ classes.push('selected');
65
+ }
66
+ const minimum =
67
+ differenceInCalendarDays(day, selectedDate) >= arrivalDate.min_nights;
68
+ const maximum =
69
+ differenceInCalendarDays(day, selectedDate) <= house.max_nights &&
70
+ differenceInCalendarDays(day, selectedDate) <= arrivalDate.max_nights;
71
+
72
+ if (
73
+ buDate.departure &&
74
+ isAfter(day, selectedDate) &&
75
+ minimum &&
76
+ maximum &&
77
+ prevBooked.max_nights !== 0
78
+ ) {
79
+ classes.push('departure');
80
+ }
81
+ }
82
+
83
+ if (departureDate) {
84
+ if (
85
+ isAfter(day, selectedDate) &&
86
+ isBefore(day, Parse_EN_US(departureDate.date))
87
+ ) {
88
+ classes.push('selected');
89
+ }
90
+ if (isSameDay(day, Parse_EN_US(departureDate.date))) {
91
+ classes.push('selected');
92
+ }
93
+ }
94
+
95
+ const daysFromToday = differenceInCalendarDays(day, new Date());
96
+ const last_minute =
97
+ daysFromToday <= house.last_minute_days && daysFromToday > 0;
98
+
99
+ const discount = discounts.find(
100
+ (x) =>
101
+ isBefore(subDays(Parse_EN_US(x.discount_starts_at), 1), day) &&
102
+ isAfter(addDays(Parse_EN_US(x.discount_ends_at), 1), day)
103
+ );
104
+ if (last_minute || discount || buDate.special_offer > 0) {
105
+ classes.push('discount');
106
+ }
107
+
108
+ return classes.join(' ');
109
+ }
110
+
111
+ export default DayClasses;
@@ -0,0 +1,64 @@
1
+ import { useQuery } from '@apollo/client';
2
+ import React, { useContext } from 'react';
3
+ import { FormattedMessage } from 'react-intl';
4
+ import { HouseType, PortalSiteType } from '../../../types';
5
+ import { SINGLE_HOUSE_QUERY } from '../../../_lib/queries';
6
+ import { AppContext } from '../../AppContext';
7
+ import { ApiError } from '../../Error';
8
+ import Loading from '../../icons/loading.svg';
9
+ import Calendar from '../Calendar';
10
+
11
+ interface Props {
12
+ PortalSite: PortalSiteType;
13
+ }
14
+
15
+ function GenerateCalendar({ PortalSite }: Props): JSX.Element {
16
+ const { portalCode, objectCode } = useContext(AppContext);
17
+ const { loading, error, data } = useQuery(SINGLE_HOUSE_QUERY, {
18
+ variables: { portalCode, objectCode }
19
+ });
20
+
21
+ if (loading)
22
+ return (
23
+ <div>
24
+ <Loading />
25
+ </div>
26
+ );
27
+ if (error) {
28
+ return (
29
+ <div>
30
+ <ApiError errors={error} />
31
+ </div>
32
+ );
33
+ }
34
+
35
+ const Results = data.PortalSite.houses;
36
+ const numberOfMonths = PortalSite.options.bookingForm
37
+ ? PortalSite.options.bookingForm.numberOfMonths
38
+ : 4;
39
+ const numberOfMonthsInARow = PortalSite.options.bookingForm
40
+ ? PortalSite.options.bookingForm.numberOfMonthsInARow
41
+ : 4;
42
+
43
+ return (
44
+ <div id="calendar-container">
45
+ {Results.length === 0 && (
46
+ <div>
47
+ <FormattedMessage id="no_house_found" />
48
+ </div>
49
+ )}
50
+ {Results.map((result: HouseType) => (
51
+ <div key={result.id}>
52
+ <div className="house-name">{result.name}</div>
53
+ <Calendar
54
+ numberOfMonths={numberOfMonths}
55
+ numberOfMonthsInARow={numberOfMonthsInARow}
56
+ house={result}
57
+ />
58
+ </div>
59
+ ))}
60
+ </div>
61
+ );
62
+ }
63
+
64
+ export default GenerateCalendar;
@@ -0,0 +1,33 @@
1
+ import React from 'react';
2
+ import { FormattedMessage } from 'react-intl';
3
+
4
+ interface Props {
5
+ house: {
6
+ house_type: string;
7
+ };
8
+ }
9
+
10
+ function Legend({ house }: Props): JSX.Element {
11
+ return (
12
+ <div className="legend">
13
+ <div>
14
+ <span className="legend-field arrival" />
15
+ <FormattedMessage id={`${house.house_type}.arrival_date`} />
16
+ </div>
17
+ <div>
18
+ <span className="legend-field booked" />
19
+ <FormattedMessage id="booked" />
20
+ </div>
21
+ <div>
22
+ <span className="legend-field departure" />
23
+ <FormattedMessage id={`${house.house_type}.departure_date`} />
24
+ </div>
25
+ <div>
26
+ <span className="legend-field last_minute_discount" />
27
+ <FormattedMessage id="discount" />
28
+ </div>
29
+ </div>
30
+ );
31
+ }
32
+
33
+ export default Legend;
@@ -0,0 +1,15 @@
1
+ import React from "react";
2
+ import { MONTH_FORMAT, FormatIntl } from '../../../_lib/date_helper';
3
+
4
+ interface Props { month: Date; }
5
+
6
+ const MonthHeader = ({ month }:Props): JSX.Element => (
7
+ <div className="header row flex-middle">
8
+ <div className="col col-center" style={{ textAlign: 'center' }}>
9
+ <span>{FormatIntl(month, MONTH_FORMAT)}</span>
10
+ </div>
11
+ </div>
12
+ );
13
+
14
+
15
+ export default MonthHeader
@@ -0,0 +1,37 @@
1
+ import { addMonths, format } from 'date-fns';
2
+ import React from 'react';
3
+ import { HouseType } from '../../../types';
4
+ import SingleMonth from './SingleMonth';
5
+
6
+ interface Props {
7
+ house: HouseType;
8
+ numberOfMonths: number;
9
+ numberOfMonthsInARow: number;
10
+ currentMonth: Date;
11
+ }
12
+
13
+ function Months({
14
+ numberOfMonthsInARow,
15
+ currentMonth,
16
+ numberOfMonths,
17
+
18
+ house
19
+ }: Props): JSX.Element {
20
+ let template: JSX.Element[] = [];
21
+
22
+ for (let i = 0; i < numberOfMonths; i++) {
23
+ template.push(
24
+ <SingleMonth
25
+ key={format(addMonths(currentMonth, i), 'MM-yyyy')}
26
+ house={house}
27
+ numberOfMonthsInARow={numberOfMonthsInARow}
28
+ currentMonth={currentMonth}
29
+ count={i}
30
+ />
31
+ );
32
+ }
33
+
34
+ return <div className="calendars-row">{template}</div>;
35
+ }
36
+
37
+ export default Months;
@@ -0,0 +1,94 @@
1
+ import React, { useContext } from 'react';
2
+ import {
3
+ addDays,
4
+ endOfMonth,
5
+ endOfWeek,
6
+ startOfMonth,
7
+ startOfWeek,
8
+ subDays,
9
+ isBefore,
10
+ isAfter,
11
+ differenceInCalendarDays,
12
+ addMonths,
13
+ isSameMonth,
14
+ parse,
15
+ isSameDay
16
+ } from 'date-fns';
17
+ import { FormatIntl, Parse_EN_US } from '../../../_lib/date_helper';
18
+ import DayClasses from './DayClasses';
19
+ import { HouseType } from '../../../types';
20
+ import { CalendarContext, CalendarContextDispatch } from './CalendarContext';
21
+
22
+ interface CellProps {
23
+ availabilities: [];
24
+ month: Date;
25
+ discounts: [];
26
+ house: HouseType;
27
+ }
28
+
29
+ function RenderCells({
30
+ availabilities,
31
+ month,
32
+ discounts,
33
+ house
34
+ }: CellProps): JSX.Element {
35
+ const dispatch = useContext(CalendarContextDispatch);
36
+ const dates = useContext(CalendarContext);
37
+
38
+ const monthStart = startOfMonth(month);
39
+ const monthEnd = endOfMonth(monthStart);
40
+ const startDate = startOfWeek(monthStart);
41
+ const endDate = endOfWeek(monthEnd);
42
+ const rows: JSX.Element[] = [];
43
+
44
+ let days: JSX.Element[] = [];
45
+ let day: Date = startDate;
46
+
47
+ while (day <= endDate) {
48
+ // for (let daz of dayz) {
49
+ for (let i = 0; i < 7; i++) {
50
+ let date = FormatIntl(day, 'yyyy-MM-dd');
51
+ let yesterday = FormatIntl(subDays(day, 1), 'yyyy-MM-dd');
52
+ let daz = availabilities.find((x) => x.date === date);
53
+
54
+ const prevBooked = availabilities.find((x) => x.date === yesterday);
55
+ const cloneDay = daz;
56
+
57
+ days.push(
58
+ <div
59
+ className={DayClasses({
60
+ day,
61
+ monthStart,
62
+ discounts,
63
+ buDate: daz,
64
+ prevBooked,
65
+ house,
66
+ dates
67
+ })}
68
+ key={daz.date}
69
+ role="button"
70
+ tabIndex={0}
71
+ onClick={() => {
72
+ dispatch({
73
+ type: 'clicked',
74
+ day: cloneDay,
75
+ house
76
+ });
77
+ }}
78
+ >
79
+ <span>{FormatIntl(day, 'd')}</span>
80
+ </div>
81
+ );
82
+ day = addDays(day, 1);
83
+ }
84
+ rows.push(
85
+ <div className="row" key={day}>
86
+ {days}
87
+ </div>
88
+ );
89
+ days = [];
90
+ }
91
+ return <div className="body">{rows}</div>;
92
+ }
93
+
94
+ export default RenderCells;
@@ -0,0 +1,72 @@
1
+ import { useQuery } from '@apollo/client';
2
+ import {
3
+ addMonths,
4
+ endOfMonth,
5
+ endOfWeek,
6
+ startOfMonth,
7
+ startOfWeek
8
+ } from 'date-fns';
9
+ import React, { useContext } from 'react';
10
+ import { HouseType } from '../../../types';
11
+ import { CALENDAR_QUERY } from '../../../_lib/queries';
12
+ import { AppContext } from '../../AppContext';
13
+ import Loading from '../../icons/loading.svg';
14
+ import MonthHeader from './MonthHeader';
15
+ import RenderCells from './RenderCells';
16
+ import WeekDays from './WeekDays';
17
+
18
+ interface Props {
19
+ count: number;
20
+ currentMonth: Date;
21
+ house: HouseType;
22
+ numberOfMonthsInARow: Number;
23
+ }
24
+
25
+ function SingleMonth({
26
+ count,
27
+ currentMonth,
28
+ house,
29
+ numberOfMonthsInARow
30
+ }: Props): JSX.Element {
31
+ const { portalCode, objectCode } = useContext(AppContext);
32
+
33
+ let month = addMonths(currentMonth, count);
34
+ let monthStart = startOfMonth(month);
35
+ let monthEnd = endOfMonth(month);
36
+ const variables = {
37
+ id: portalCode,
38
+ house_id: objectCode,
39
+ starts_at: startOfWeek(monthStart),
40
+ ends_at: endOfWeek(monthEnd)
41
+ };
42
+
43
+ const { loading, error, data } = useQuery(CALENDAR_QUERY, { variables });
44
+
45
+ if (loading)
46
+ return (
47
+ <div>
48
+ <Loading />
49
+ </div>
50
+ );
51
+ if (error) {
52
+ return <div>Error</div>;
53
+ }
54
+
55
+ const results = data.PortalSite.houses[0].availabilities;
56
+ const discounts = data.Discounts;
57
+
58
+ return (
59
+ <div className={`calendar calendar-${numberOfMonthsInARow}`} key={month}>
60
+ <MonthHeader month={month} />
61
+ <WeekDays month={month} />
62
+ <RenderCells
63
+ availabilities={results}
64
+ discounts={discounts}
65
+ month={month}
66
+ house={house}
67
+ />
68
+ </div>
69
+ );
70
+ }
71
+
72
+ export default SingleMonth;
@@ -0,0 +1,17 @@
1
+ import React from 'react';
2
+ import { HouseType } from '../../../types';
3
+ import PriceField from '../PriceField';
4
+
5
+ interface Props {
6
+ house: HouseType;
7
+ }
8
+
9
+ function StartBooking({ house }: Props): JSX.Element {
10
+ return (
11
+ <div className="price-overview">
12
+ <PriceField house={house} />
13
+ </div>
14
+ );
15
+ }
16
+
17
+ export default StartBooking;