@qite/tide-booking-component 0.0.2-preview.8 → 1.0.0-preview
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.
- package/README.md +1 -0
- package/build/build-cjs/booking-wizard/components/icon.d.ts +7 -7
- package/build/build-cjs/booking-wizard/components/labeled-input.d.ts +18 -18
- package/build/build-cjs/booking-wizard/components/labeled-select.d.ts +21 -21
- package/build/build-cjs/booking-wizard/components/message.d.ts +9 -8
- package/build/build-cjs/booking-wizard/components/product-card.d.ts +8 -9
- package/build/build-cjs/booking-wizard/components/rating.d.ts +6 -6
- package/build/build-cjs/booking-wizard/components/step-indicator.d.ts +6 -6
- package/build/build-cjs/booking-wizard/components/step-route.d.ts +9 -9
- package/build/build-cjs/booking-wizard/features/booking/api.d.ts +21 -0
- package/build/build-cjs/booking-wizard/features/booking/booking-slice.d.ts +124 -18
- package/build/build-cjs/booking-wizard/features/booking/booking.d.ts +8 -9
- package/build/build-cjs/booking-wizard/features/booking/selectors.d.ts +208 -0
- package/build/build-cjs/booking-wizard/features/confirmation/confirmation.d.ts +4 -5
- package/build/build-cjs/booking-wizard/features/error/error.d.ts +4 -5
- package/build/build-cjs/booking-wizard/features/price-details/price-details-api.d.ts +12 -6
- package/build/build-cjs/booking-wizard/features/price-details/price-details-slice.d.ts +105 -10
- package/build/build-cjs/booking-wizard/features/price-details/util.d.ts +5 -0
- package/build/build-cjs/booking-wizard/features/product-options/no-options.d.ts +2 -0
- package/build/build-cjs/booking-wizard/features/product-options/none-option.d.ts +17 -0
- package/build/build-cjs/booking-wizard/features/product-options/option-booking-group.d.ts +18 -0
- package/build/build-cjs/booking-wizard/features/product-options/option-item.d.ts +11 -0
- package/build/build-cjs/booking-wizard/features/product-options/option-pax-card.d.ts +9 -0
- package/build/build-cjs/booking-wizard/features/product-options/option-pax-group.d.ts +20 -0
- package/build/build-cjs/booking-wizard/features/product-options/option-room.d.ts +16 -0
- package/build/build-cjs/booking-wizard/features/product-options/option-unit-group.d.ts +20 -0
- package/build/build-cjs/booking-wizard/features/product-options/option-units-card.d.ts +9 -0
- package/build/build-cjs/booking-wizard/features/product-options/options-form.d.ts +4 -5
- package/build/build-cjs/booking-wizard/features/product-options/validate-form.d.ts +2 -2
- package/build/build-cjs/booking-wizard/features/sidebar/index.d.ts +7 -3
- package/build/build-cjs/booking-wizard/features/sidebar/sidebar-flight.d.ts +8 -0
- package/build/build-cjs/booking-wizard/features/sidebar/sidebar-util.d.ts +28 -4
- package/build/build-cjs/booking-wizard/features/sidebar/sidebar.d.ts +29 -21
- package/build/build-cjs/booking-wizard/features/summary/summary-booking-option-pax.d.ts +7 -0
- package/build/build-cjs/booking-wizard/features/summary/summary-booking-option-unit.d.ts +7 -0
- package/build/build-cjs/booking-wizard/features/summary/summary-flight.d.ts +8 -0
- package/build/build-cjs/booking-wizard/features/summary/summary-per-booking-option-group.d.ts +10 -0
- package/build/build-cjs/booking-wizard/features/summary/summary-per-pax-option-group.d.ts +10 -0
- package/build/build-cjs/booking-wizard/features/summary/summary-per-unit-option-group.d.ts +10 -0
- package/build/build-cjs/booking-wizard/features/summary/summary-slice.d.ts +14 -17
- package/build/build-cjs/booking-wizard/features/summary/summary.d.ts +4 -5
- package/build/build-cjs/booking-wizard/features/travelers-form/travelers-form-slice.d.ts +95 -45
- package/build/build-cjs/booking-wizard/features/travelers-form/travelers-form.d.ts +4 -5
- package/build/build-cjs/booking-wizard/features/travelers-form/type-ahead-input.d.ts +16 -15
- package/build/build-cjs/booking-wizard/features/travelers-form/validate-form.d.ts +7 -4
- package/build/build-cjs/booking-wizard/index.d.ts +12 -11
- package/build/build-cjs/booking-wizard/settings-context.d.ts +5 -6
- package/build/build-cjs/booking-wizard/store.d.ts +41 -25
- package/build/build-cjs/booking-wizard/types.d.ts +111 -59
- package/build/build-cjs/booking-wizard/utils/class-util.d.ts +1 -1
- package/build/build-cjs/booking-wizard/utils/localization-util.d.ts +1 -1
- package/build/build-cjs/booking-wizard/utils/query-string-util.d.ts +21 -2
- package/build/build-cjs/booking-wizard/utils/tide-api-utils.d.ts +2 -2
- package/build/build-cjs/index.d.ts +2 -2
- package/build/build-cjs/index.js +13642 -1886
- package/build/build-esm/booking-wizard/components/icon.d.ts +7 -7
- package/build/build-esm/booking-wizard/components/labeled-input.d.ts +18 -18
- package/build/build-esm/booking-wizard/components/labeled-select.d.ts +21 -21
- package/build/build-esm/booking-wizard/components/message.d.ts +9 -8
- package/build/build-esm/booking-wizard/components/product-card.d.ts +8 -9
- package/build/build-esm/booking-wizard/components/rating.d.ts +6 -6
- package/build/build-esm/booking-wizard/components/step-indicator.d.ts +6 -6
- package/build/build-esm/booking-wizard/components/step-route.d.ts +9 -9
- package/build/build-esm/booking-wizard/features/booking/api.d.ts +21 -0
- package/build/build-esm/booking-wizard/features/booking/booking-slice.d.ts +124 -18
- package/build/build-esm/booking-wizard/features/booking/booking.d.ts +8 -9
- package/build/build-esm/booking-wizard/features/booking/selectors.d.ts +208 -0
- package/build/build-esm/booking-wizard/features/confirmation/confirmation.d.ts +4 -5
- package/build/build-esm/booking-wizard/features/error/error.d.ts +4 -5
- package/build/build-esm/booking-wizard/features/price-details/price-details-api.d.ts +12 -6
- package/build/build-esm/booking-wizard/features/price-details/price-details-slice.d.ts +105 -10
- package/build/build-esm/booking-wizard/features/price-details/util.d.ts +5 -0
- package/build/build-esm/booking-wizard/features/product-options/no-options.d.ts +2 -0
- package/build/build-esm/booking-wizard/features/product-options/none-option.d.ts +17 -0
- package/build/build-esm/booking-wizard/features/product-options/option-booking-group.d.ts +18 -0
- package/build/build-esm/booking-wizard/features/product-options/option-item.d.ts +11 -0
- package/build/build-esm/booking-wizard/features/product-options/option-pax-card.d.ts +9 -0
- package/build/build-esm/booking-wizard/features/product-options/option-pax-group.d.ts +20 -0
- package/build/build-esm/booking-wizard/features/product-options/option-room.d.ts +16 -0
- package/build/build-esm/booking-wizard/features/product-options/option-unit-group.d.ts +20 -0
- package/build/build-esm/booking-wizard/features/product-options/option-units-card.d.ts +9 -0
- package/build/build-esm/booking-wizard/features/product-options/options-form.d.ts +4 -5
- package/build/build-esm/booking-wizard/features/product-options/validate-form.d.ts +2 -2
- package/build/build-esm/booking-wizard/features/sidebar/index.d.ts +7 -3
- package/build/build-esm/booking-wizard/features/sidebar/sidebar-flight.d.ts +8 -0
- package/build/build-esm/booking-wizard/features/sidebar/sidebar-util.d.ts +28 -4
- package/build/build-esm/booking-wizard/features/sidebar/sidebar.d.ts +29 -21
- package/build/build-esm/booking-wizard/features/summary/summary-booking-option-pax.d.ts +7 -0
- package/build/build-esm/booking-wizard/features/summary/summary-booking-option-unit.d.ts +7 -0
- package/build/build-esm/booking-wizard/features/summary/summary-flight.d.ts +8 -0
- package/build/build-esm/booking-wizard/features/summary/summary-per-booking-option-group.d.ts +10 -0
- package/build/build-esm/booking-wizard/features/summary/summary-per-pax-option-group.d.ts +10 -0
- package/build/build-esm/booking-wizard/features/summary/summary-per-unit-option-group.d.ts +10 -0
- package/build/build-esm/booking-wizard/features/summary/summary-slice.d.ts +14 -17
- package/build/build-esm/booking-wizard/features/summary/summary.d.ts +4 -5
- package/build/build-esm/booking-wizard/features/travelers-form/travelers-form-slice.d.ts +95 -45
- package/build/build-esm/booking-wizard/features/travelers-form/travelers-form.d.ts +4 -5
- package/build/build-esm/booking-wizard/features/travelers-form/type-ahead-input.d.ts +16 -15
- package/build/build-esm/booking-wizard/features/travelers-form/validate-form.d.ts +7 -4
- package/build/build-esm/booking-wizard/index.d.ts +12 -11
- package/build/build-esm/booking-wizard/settings-context.d.ts +5 -6
- package/build/build-esm/booking-wizard/store.d.ts +41 -25
- package/build/build-esm/booking-wizard/types.d.ts +111 -59
- package/build/build-esm/booking-wizard/utils/class-util.d.ts +1 -1
- package/build/build-esm/booking-wizard/utils/localization-util.d.ts +1 -1
- package/build/build-esm/booking-wizard/utils/query-string-util.d.ts +21 -2
- package/build/build-esm/booking-wizard/utils/tide-api-utils.d.ts +2 -2
- package/build/build-esm/index.d.ts +2 -2
- package/build/build-esm/index.js +13478 -1875
- package/package.json +8 -4
- package/rollup.config.js +1 -6
- package/src/booking-wizard/components/message.tsx +14 -8
- package/src/booking-wizard/components/product-card.tsx +10 -39
- package/src/booking-wizard/components/step-indicator.tsx +1 -1
- package/src/booking-wizard/components/step-route.tsx +1 -1
- package/src/booking-wizard/features/booking/api.ts +44 -0
- package/src/booking-wizard/features/booking/booking-slice.ts +274 -40
- package/src/booking-wizard/features/booking/booking.tsx +193 -57
- package/src/booking-wizard/features/booking/selectors.ts +328 -0
- package/src/booking-wizard/features/confirmation/confirmation.tsx +22 -11
- package/src/booking-wizard/features/error/error.tsx +15 -2
- package/src/booking-wizard/features/price-details/price-details-api.ts +12 -6
- package/src/booking-wizard/features/price-details/price-details-slice.ts +80 -50
- package/src/booking-wizard/features/price-details/util.ts +135 -0
- package/src/booking-wizard/features/product-options/no-options.tsx +18 -0
- package/src/booking-wizard/features/product-options/none-option.tsx +118 -0
- package/src/booking-wizard/features/product-options/option-booking-group.tsx +210 -0
- package/src/booking-wizard/features/product-options/option-item.tsx +321 -0
- package/src/booking-wizard/features/product-options/option-pax-card.tsx +102 -0
- package/src/booking-wizard/features/product-options/option-pax-group.tsx +169 -0
- package/src/booking-wizard/features/product-options/option-room.tsx +300 -0
- package/src/booking-wizard/features/product-options/option-unit-group.tsx +192 -0
- package/src/booking-wizard/features/product-options/option-units-card.tsx +100 -0
- package/src/booking-wizard/features/product-options/options-form.tsx +226 -48
- package/src/booking-wizard/features/sidebar/index.tsx +43 -20
- package/src/booking-wizard/features/sidebar/sidebar-flight.tsx +66 -0
- package/src/booking-wizard/features/sidebar/sidebar-util.ts +81 -39
- package/src/booking-wizard/features/sidebar/sidebar.tsx +150 -100
- package/src/booking-wizard/features/summary/summary-booking-option-pax.tsx +25 -0
- package/src/booking-wizard/features/summary/summary-booking-option-unit.tsx +25 -0
- package/src/booking-wizard/features/summary/summary-flight.tsx +35 -0
- package/src/booking-wizard/features/summary/summary-per-booking-option-group.tsx +57 -0
- package/src/booking-wizard/features/summary/summary-per-pax-option-group.tsx +51 -0
- package/src/booking-wizard/features/summary/summary-per-unit-option-group.tsx +54 -0
- package/src/booking-wizard/features/summary/summary-slice.ts +1 -134
- package/src/booking-wizard/features/summary/summary.tsx +521 -134
- package/src/booking-wizard/features/travelers-form/travelers-form-slice.ts +55 -56
- package/src/booking-wizard/features/travelers-form/travelers-form.tsx +202 -94
- package/src/booking-wizard/features/travelers-form/type-ahead-input.tsx +23 -3
- package/src/booking-wizard/features/travelers-form/validate-form.ts +40 -3
- package/src/booking-wizard/index.tsx +5 -6
- package/src/booking-wizard/settings-context.ts +33 -5
- package/src/booking-wizard/store.ts +5 -4
- package/src/booking-wizard/translations/translations.json +95 -61
- package/src/booking-wizard/types.ts +67 -10
- package/src/booking-wizard/utils/query-string-util.ts +42 -0
- package/build/build-cjs/booking-wizard/features/product-options/checkbox.d.ts +0 -11
- package/build/build-cjs/booking-wizard/features/product-options/option-details.d.ts +0 -11
- package/build/build-cjs/booking-wizard/features/product-options/product-options-api.d.ts +0 -26
- package/build/build-cjs/booking-wizard/features/product-options/product-options-slice.d.ts +0 -37
- package/build/build-cjs/booking-wizard/features/product-options/radio-button.d.ts +0 -10
- package/build/build-cjs/booking-wizard/features/product-options/rooms-slice.d.ts +0 -12
- package/build/build-cjs/booking-wizard/features/product-options/tree-level.d.ts +0 -7
- package/build/build-esm/booking-wizard/features/product-options/checkbox.d.ts +0 -11
- package/build/build-esm/booking-wizard/features/product-options/option-details.d.ts +0 -11
- package/build/build-esm/booking-wizard/features/product-options/product-options-api.d.ts +0 -26
- package/build/build-esm/booking-wizard/features/product-options/product-options-slice.d.ts +0 -37
- package/build/build-esm/booking-wizard/features/product-options/radio-button.d.ts +0 -10
- package/build/build-esm/booking-wizard/features/product-options/rooms-slice.d.ts +0 -12
- package/build/build-esm/booking-wizard/features/product-options/tree-level.d.ts +0 -7
- package/src/booking-wizard/features/product-options/checkbox.tsx +0 -38
- package/src/booking-wizard/features/product-options/option-details.tsx +0 -65
- package/src/booking-wizard/features/product-options/product-options-api.ts +0 -148
- package/src/booking-wizard/features/product-options/product-options-slice.ts +0 -149
- package/src/booking-wizard/features/product-options/radio-button.tsx +0 -35
- package/src/booking-wizard/features/product-options/rooms-slice.ts +0 -28
- package/src/booking-wizard/features/product-options/tree-level.tsx +0 -118
|
@@ -1,28 +1,27 @@
|
|
|
1
1
|
import { PayloadAction, createSelector, createSlice } from "@reduxjs/toolkit";
|
|
2
|
-
import { differenceInYears
|
|
2
|
+
import { differenceInYears } from "date-fns";
|
|
3
3
|
|
|
4
4
|
import { RootState } from "../../store";
|
|
5
5
|
import { TravelersFormValues } from "../../types";
|
|
6
6
|
|
|
7
7
|
export interface TravelersFormState {
|
|
8
|
-
adultCount: number;
|
|
9
|
-
childCount: number;
|
|
10
8
|
formValues?: TravelersFormValues;
|
|
11
9
|
}
|
|
12
10
|
|
|
13
|
-
const
|
|
11
|
+
export const CHILD_MAX_AGE = 17;
|
|
12
|
+
const isDebug = false;
|
|
14
13
|
|
|
15
14
|
const debugFormValues = {
|
|
16
15
|
adults: [
|
|
17
16
|
{
|
|
18
|
-
id:
|
|
17
|
+
id: 1,
|
|
19
18
|
firstName: "Jan",
|
|
20
19
|
lastName: "Jansens",
|
|
21
20
|
birthDate: "1984-05-20",
|
|
22
21
|
gender: "m",
|
|
23
22
|
},
|
|
24
23
|
{
|
|
25
|
-
id:
|
|
24
|
+
id: 2,
|
|
26
25
|
firstName: "Leen",
|
|
27
26
|
lastName: "Leenders",
|
|
28
27
|
birthDate: "1986-08-09",
|
|
@@ -46,21 +45,21 @@ const debugFormValues = {
|
|
|
46
45
|
// },
|
|
47
46
|
// ],
|
|
48
47
|
children: [],
|
|
49
|
-
mainBookerId:
|
|
48
|
+
mainBookerId: 1,
|
|
50
49
|
street: "Nieuwstraat",
|
|
51
50
|
houseNumber: "20",
|
|
52
51
|
box: "A",
|
|
53
52
|
zipCode: "9000",
|
|
54
53
|
place: "Gent",
|
|
55
54
|
country: "be",
|
|
56
|
-
email: "
|
|
57
|
-
emailConfirmation: "
|
|
55
|
+
email: "staging@qite.be",
|
|
56
|
+
emailConfirmation: "staging@qite.be",
|
|
58
57
|
phone: "+32 471 12 34 56",
|
|
58
|
+
travelAgentId: 0,
|
|
59
|
+
travelAgentName: "",
|
|
59
60
|
};
|
|
60
61
|
|
|
61
62
|
const initialState: TravelersFormState = {
|
|
62
|
-
adultCount: 2,
|
|
63
|
-
childCount: 0,
|
|
64
63
|
formValues: isDebug ? debugFormValues : undefined,
|
|
65
64
|
};
|
|
66
65
|
|
|
@@ -68,25 +67,13 @@ const travelersFormSlice = createSlice({
|
|
|
68
67
|
name: "travelersForm",
|
|
69
68
|
initialState,
|
|
70
69
|
reducers: {
|
|
71
|
-
setAdultCount(state, action: PayloadAction<number>) {
|
|
72
|
-
state.adultCount = action.payload;
|
|
73
|
-
},
|
|
74
|
-
setChildCount(state, action: PayloadAction<number>) {
|
|
75
|
-
state.childCount = action.payload;
|
|
76
|
-
},
|
|
77
70
|
setFormValues(state, action: PayloadAction<TravelersFormValues>) {
|
|
78
71
|
state.formValues = action.payload;
|
|
79
72
|
},
|
|
80
73
|
},
|
|
81
74
|
});
|
|
82
75
|
|
|
83
|
-
export const {
|
|
84
|
-
travelersFormSlice.actions;
|
|
85
|
-
|
|
86
|
-
export const selectAdultCount = (state: RootState) =>
|
|
87
|
-
state.travelersForm.adultCount;
|
|
88
|
-
export const selectChildCount = (state: RootState) =>
|
|
89
|
-
state.travelersForm.childCount;
|
|
76
|
+
export const { setFormValues } = travelersFormSlice.actions;
|
|
90
77
|
|
|
91
78
|
export const selectTravelersFormValues = (state: RootState) =>
|
|
92
79
|
state.travelersForm.formValues;
|
|
@@ -101,40 +88,52 @@ export const selectChildren = createSelector(
|
|
|
101
88
|
(formValues) => formValues?.children ?? []
|
|
102
89
|
);
|
|
103
90
|
|
|
104
|
-
export const
|
|
105
|
-
selectAdultCount,
|
|
106
|
-
selectChildCount,
|
|
91
|
+
export const selectAgentId = createSelector(
|
|
107
92
|
selectTravelersFormValues,
|
|
108
|
-
(
|
|
109
|
-
if (!travelerFormValues) {
|
|
110
|
-
return [
|
|
111
|
-
...new Array(adultCount).fill(30),
|
|
112
|
-
...new Array(childCount).fill(6),
|
|
113
|
-
];
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
return [
|
|
117
|
-
...(travelerFormValues.adults ?? []).map((adult) => {
|
|
118
|
-
const diff = differenceInYears(
|
|
119
|
-
new Date(),
|
|
120
|
-
parse(adult.birthDate, "yyyy-MM-dd", new Date())
|
|
121
|
-
);
|
|
122
|
-
return isNaN(diff) ? 30 : diff;
|
|
123
|
-
}),
|
|
124
|
-
...(travelerFormValues.children ?? []).map((traveler) => {
|
|
125
|
-
const diff = differenceInYears(
|
|
126
|
-
new Date(),
|
|
127
|
-
parse(traveler.birthDate, "yyyy-MM-dd", new Date())
|
|
128
|
-
);
|
|
129
|
-
return isNaN(diff) ? 6 : diff;
|
|
130
|
-
}),
|
|
131
|
-
];
|
|
132
|
-
}
|
|
93
|
+
(formValues) => formValues?.travelAgentId
|
|
133
94
|
);
|
|
134
95
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
)
|
|
96
|
+
const selectRequestRooms = (state: RootState) =>
|
|
97
|
+
state.booking.package?.options.find((x) => x.isSelected)?.requestRooms;
|
|
98
|
+
|
|
99
|
+
export const selectAdultIds = createSelector(selectRequestRooms, (rooms) => {
|
|
100
|
+
const ids: number[] = [];
|
|
101
|
+
if (rooms) {
|
|
102
|
+
rooms.forEach((x) =>
|
|
103
|
+
x.pax.forEach((p) => {
|
|
104
|
+
if (p.age && p.age > CHILD_MAX_AGE) {
|
|
105
|
+
ids.push(p.id);
|
|
106
|
+
} else if (p.dateOfBirth) {
|
|
107
|
+
const diff = differenceInYears(new Date(), new Date(p.dateOfBirth));
|
|
108
|
+
|
|
109
|
+
if (diff > CHILD_MAX_AGE) {
|
|
110
|
+
ids.push(p.id);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
})
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
return ids;
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
export const selectChildIds = createSelector(selectRequestRooms, (rooms) => {
|
|
120
|
+
const ids: number[] = [];
|
|
121
|
+
if (rooms) {
|
|
122
|
+
rooms.forEach((x) =>
|
|
123
|
+
x.pax.forEach((p) => {
|
|
124
|
+
if (p.age && p.age <= CHILD_MAX_AGE) {
|
|
125
|
+
ids.push(p.id);
|
|
126
|
+
} else if (p.dateOfBirth) {
|
|
127
|
+
const diff = differenceInYears(new Date(), new Date(p.dateOfBirth));
|
|
128
|
+
|
|
129
|
+
if (diff <= CHILD_MAX_AGE) {
|
|
130
|
+
ids.push(p.id);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
})
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
return ids;
|
|
137
|
+
});
|
|
139
138
|
|
|
140
139
|
export default travelersFormSlice.reducer;
|
|
@@ -1,14 +1,12 @@
|
|
|
1
|
-
import React, { useContext } from "react";
|
|
2
|
-
import { compact, get,
|
|
1
|
+
import React, { useContext, useEffect, useState } from "react";
|
|
2
|
+
import { compact, get, sortBy } from "lodash";
|
|
3
3
|
import {
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
selectAdultIds,
|
|
5
|
+
selectChildIds,
|
|
6
6
|
selectTravelersFormValues,
|
|
7
|
-
setAdultCount,
|
|
8
|
-
setChildCount,
|
|
9
7
|
setFormValues,
|
|
10
8
|
} from "./travelers-form-slice";
|
|
11
|
-
import {
|
|
9
|
+
import { useSelector } from "react-redux";
|
|
12
10
|
|
|
13
11
|
import LabeledInput from "../../components/labeled-input";
|
|
14
12
|
import LabeledSelect from "../../components/labeled-select";
|
|
@@ -16,27 +14,40 @@ import SettingsContext from "../../settings-context";
|
|
|
16
14
|
import { TravelersFormValues } from "../../types";
|
|
17
15
|
import { buildClassName } from "../../utils/class-util";
|
|
18
16
|
import { fetchPriceDetails } from "../price-details/price-details-slice";
|
|
19
|
-
import { fetchProductOptions } from "../product-options/product-options-slice";
|
|
20
17
|
import flat from "flat";
|
|
21
18
|
import { navigate } from "@reach/router";
|
|
22
19
|
import produce from "immer";
|
|
23
|
-
import {
|
|
20
|
+
import {
|
|
21
|
+
selectAgentAdressId,
|
|
22
|
+
selectAgents,
|
|
23
|
+
selectBookingQueryString,
|
|
24
|
+
selectStartDate,
|
|
25
|
+
} from "../booking/selectors";
|
|
24
26
|
import translations from "../../translations/translations.json";
|
|
25
27
|
import { useFormik } from "formik";
|
|
26
|
-
import { v4 as uuid } from "uuid";
|
|
27
28
|
import validateForm from "./validate-form";
|
|
29
|
+
import { format, parse } from "date-fns";
|
|
30
|
+
import { useAppDispatch } from "../../store";
|
|
31
|
+
import TypeAheadInput from "./type-ahead-input";
|
|
32
|
+
import { setBookingType } from "../booking/booking-slice";
|
|
28
33
|
|
|
29
34
|
interface TravelersFormProps {}
|
|
30
35
|
|
|
31
|
-
function createTraveler() {
|
|
32
|
-
return { id
|
|
36
|
+
function createTraveler(id: number) {
|
|
37
|
+
return { id, firstName: "", lastName: "", birthDate: "", gender: "" };
|
|
33
38
|
}
|
|
34
39
|
|
|
35
|
-
function createInitialValues(
|
|
40
|
+
function createInitialValues(
|
|
41
|
+
adultIds: number[],
|
|
42
|
+
childIds: number[],
|
|
43
|
+
startDate?: string,
|
|
44
|
+
agentAdressId?: number
|
|
45
|
+
) {
|
|
36
46
|
const initialValues = {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
47
|
+
startDate: startDate,
|
|
48
|
+
adults: adultIds.map((id) => createTraveler(id)),
|
|
49
|
+
children: childIds.map((id) => createTraveler(id)),
|
|
50
|
+
mainBookerId: -1,
|
|
40
51
|
street: "",
|
|
41
52
|
houseNumber: "",
|
|
42
53
|
box: "",
|
|
@@ -46,52 +57,76 @@ function createInitialValues(adultCount = 2, childCount = 0) {
|
|
|
46
57
|
phone: "",
|
|
47
58
|
email: "",
|
|
48
59
|
emailConfirmation: "",
|
|
60
|
+
travelAgentId: agentAdressId ?? 0,
|
|
61
|
+
travelAgentName: "",
|
|
49
62
|
};
|
|
50
63
|
|
|
51
|
-
initialValues.
|
|
64
|
+
if (initialValues.adults && initialValues.adults.length) {
|
|
65
|
+
initialValues.mainBookerId = initialValues.adults[0].id;
|
|
66
|
+
}
|
|
52
67
|
|
|
53
68
|
return initialValues;
|
|
54
69
|
}
|
|
55
70
|
|
|
56
71
|
const TravelersForm: React.FC<TravelersFormProps> = () => {
|
|
57
|
-
const dispatch =
|
|
72
|
+
const dispatch = useAppDispatch();
|
|
58
73
|
|
|
59
74
|
const settings = useContext(SettingsContext);
|
|
60
75
|
const bookingQueryString = useSelector(selectBookingQueryString);
|
|
61
|
-
const
|
|
62
|
-
const
|
|
76
|
+
const startDate = useSelector(selectStartDate);
|
|
77
|
+
const adultIds = useSelector(selectAdultIds);
|
|
78
|
+
const childIds = useSelector(selectChildIds);
|
|
79
|
+
const agents = useSelector(selectAgents);
|
|
80
|
+
const agentAdressId = useSelector(selectAgentAdressId);
|
|
81
|
+
|
|
63
82
|
const initialValues =
|
|
64
83
|
useSelector(selectTravelersFormValues) ??
|
|
65
|
-
createInitialValues(
|
|
84
|
+
createInitialValues(adultIds, childIds, startDate, agentAdressId);
|
|
85
|
+
|
|
86
|
+
const [showAgents, setShowAgents] = useState<boolean>(
|
|
87
|
+
settings.agentRequired ?? false
|
|
88
|
+
);
|
|
89
|
+
const [showAgentSelection, setShowAgentSelection] = useState<boolean>(
|
|
90
|
+
!settings.agentAdressId && !settings.hideAgentSelection
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
const typeaheadAgents =
|
|
94
|
+
sortBy(
|
|
95
|
+
agents?.map((x) => ({
|
|
96
|
+
key: `${x.id}`,
|
|
97
|
+
value: `${x.name} (${x.postalCode} ${x.location})`,
|
|
98
|
+
text: `${x.name} (${x.postalCode} ${x.location})`,
|
|
99
|
+
})),
|
|
100
|
+
"value"
|
|
101
|
+
) ?? [];
|
|
102
|
+
|
|
103
|
+
const [filteredAgents, setFilteredAgents] =
|
|
104
|
+
useState<{ key: string; value: string; text: string }[]>(typeaheadAgents);
|
|
66
105
|
|
|
67
106
|
const formik = useFormik<TravelersFormValues>({
|
|
68
107
|
initialValues,
|
|
69
|
-
validate: validateForm,
|
|
108
|
+
validate: (values) => validateForm(values, settings.agentRequired),
|
|
70
109
|
onSubmit: (values) => {
|
|
71
110
|
dispatch(setFormValues(values));
|
|
72
111
|
dispatch(fetchPriceDetails());
|
|
73
112
|
|
|
74
113
|
navigate(
|
|
75
|
-
`${settings.basePath}${settings.
|
|
114
|
+
`${settings.basePath}${settings.options.pathSuffix}?${bookingQueryString}`
|
|
76
115
|
);
|
|
77
116
|
},
|
|
78
117
|
});
|
|
79
118
|
|
|
80
|
-
|
|
81
|
-
e
|
|
82
|
-
) => {
|
|
83
|
-
const count = parseInt(e.currentTarget.value);
|
|
84
|
-
dispatch(setAdultCount(count));
|
|
85
|
-
|
|
119
|
+
useEffect(() => {
|
|
86
120
|
const formValues = produce(formik.values, (values) => {
|
|
87
|
-
values.adults =
|
|
88
|
-
(
|
|
121
|
+
values.adults = adultIds.map(
|
|
122
|
+
(id) => values.adults[id] ?? createTraveler(id)
|
|
89
123
|
);
|
|
90
124
|
|
|
91
125
|
if (
|
|
92
126
|
values.adults.findIndex(
|
|
93
127
|
(traveler) => traveler.id === values.mainBookerId
|
|
94
|
-
) === -1
|
|
128
|
+
) === -1 &&
|
|
129
|
+
values.adults.length
|
|
95
130
|
) {
|
|
96
131
|
values.mainBookerId = values.adults[0].id;
|
|
97
132
|
}
|
|
@@ -99,31 +134,89 @@ const TravelersForm: React.FC<TravelersFormProps> = () => {
|
|
|
99
134
|
|
|
100
135
|
formik.setValues(formValues, false);
|
|
101
136
|
dispatch(setFormValues(formValues));
|
|
137
|
+
}, [adultIds]);
|
|
102
138
|
|
|
103
|
-
|
|
104
|
-
};
|
|
105
|
-
|
|
106
|
-
const handleChildCountChange: React.FormEventHandler<HTMLSelectElement> = (
|
|
107
|
-
e
|
|
108
|
-
) => {
|
|
109
|
-
const count = parseInt(e.currentTarget.value);
|
|
110
|
-
dispatch(setChildCount(count));
|
|
111
|
-
|
|
139
|
+
useEffect(() => {
|
|
112
140
|
const formValues = produce(formik.values, (values) => {
|
|
113
|
-
values.children =
|
|
114
|
-
(
|
|
141
|
+
values.children = childIds.map(
|
|
142
|
+
(id) => values.children[id] ?? createTraveler(id)
|
|
115
143
|
);
|
|
116
144
|
});
|
|
117
145
|
formik.setValues(formValues, false);
|
|
118
146
|
dispatch(setFormValues(formValues));
|
|
147
|
+
}, [childIds]);
|
|
119
148
|
|
|
120
|
-
|
|
149
|
+
useEffect(() => {
|
|
150
|
+
dispatch(fetchPriceDetails());
|
|
151
|
+
}, []);
|
|
152
|
+
|
|
153
|
+
useEffect(() => {
|
|
154
|
+
if (agents && settings.affiliateSlug) {
|
|
155
|
+
const agent = agents.find(
|
|
156
|
+
(x) => x.affiliateSlug && x.affiliateSlug === settings.affiliateSlug
|
|
157
|
+
);
|
|
158
|
+
if (!agent) return;
|
|
159
|
+
|
|
160
|
+
const formValues = produce(formik.values, (values) => {
|
|
161
|
+
(values.travelAgentId = Number(agent.id)),
|
|
162
|
+
(values.travelAgentName = agent.name);
|
|
163
|
+
});
|
|
164
|
+
formik.setValues(formValues, false);
|
|
165
|
+
dispatch(setFormValues(formValues));
|
|
166
|
+
setShowAgentSelection(false);
|
|
167
|
+
}
|
|
168
|
+
}, [agents, settings.affiliateSlug]);
|
|
169
|
+
|
|
170
|
+
const handleMainBookerChange: React.FormEventHandler<HTMLInputElement> = (
|
|
171
|
+
e
|
|
172
|
+
) => {
|
|
173
|
+
const id = parseInt(e.currentTarget.value);
|
|
174
|
+
|
|
175
|
+
formik.setFieldValue("mainBookerId", id);
|
|
121
176
|
};
|
|
122
177
|
|
|
123
178
|
const mainBooker = formik.values.adults.find(
|
|
124
179
|
(traveler) => traveler.id === formik.values.mainBookerId
|
|
125
180
|
);
|
|
126
181
|
|
|
182
|
+
const handleAgentChange = (value: string) => {
|
|
183
|
+
const filteredAgents = typeaheadAgents.filter(
|
|
184
|
+
(x) => x.value.toLocaleLowerCase().indexOf(value.toLocaleLowerCase()) > -1
|
|
185
|
+
);
|
|
186
|
+
|
|
187
|
+
setFilteredAgents(filteredAgents);
|
|
188
|
+
formik.setFieldValue("travelAgentName", value);
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
const handleAgentSelect = (key: string) => {
|
|
192
|
+
const agent = typeaheadAgents.find((x) => x.key === key);
|
|
193
|
+
|
|
194
|
+
formik.setFieldValue("travelAgentId", Number(agent?.key));
|
|
195
|
+
formik.setFieldValue("travelAgentName", agent?.value);
|
|
196
|
+
|
|
197
|
+
let bookingType = "b2b2c";
|
|
198
|
+
if (agentAdressId && agentAdressId != 0) {
|
|
199
|
+
bookingType = "b2b";
|
|
200
|
+
}
|
|
201
|
+
dispatch(setBookingType(bookingType));
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
const handleAgentClear = () => {
|
|
205
|
+
formik.setFieldValue("travelAgentId", 0);
|
|
206
|
+
formik.setFieldValue("travelAgentName", "");
|
|
207
|
+
|
|
208
|
+
dispatch(setBookingType("b2c"));
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
const toggleAgent = (value: boolean) => {
|
|
212
|
+
setShowAgents(value);
|
|
213
|
+
|
|
214
|
+
if (!value) {
|
|
215
|
+
handleAgentClear();
|
|
216
|
+
setFilteredAgents([]);
|
|
217
|
+
}
|
|
218
|
+
};
|
|
219
|
+
|
|
127
220
|
const flatErrors: Record<string, string> = flat(formik.errors);
|
|
128
221
|
const hasVisibleError = (key: string) =>
|
|
129
222
|
get(formik.errors, key) && get(formik.touched, key);
|
|
@@ -131,6 +224,8 @@ const TravelersForm: React.FC<TravelersFormProps> = () => {
|
|
|
131
224
|
return (
|
|
132
225
|
<form
|
|
133
226
|
className="form"
|
|
227
|
+
name="booking--step1"
|
|
228
|
+
id="booking--step1"
|
|
134
229
|
noValidate
|
|
135
230
|
onSubmit={formik.handleSubmit}
|
|
136
231
|
onReset={formik.handleReset}
|
|
@@ -140,44 +235,21 @@ const TravelersForm: React.FC<TravelersFormProps> = () => {
|
|
|
140
235
|
<h5 className="form__region-heading">
|
|
141
236
|
{translations.TRAVELERS_FORM.PERSONS}
|
|
142
237
|
</h5>
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
}`}</option>
|
|
159
|
-
))}
|
|
160
|
-
</select>
|
|
161
|
-
</div>
|
|
162
|
-
</label>
|
|
163
|
-
<label
|
|
164
|
-
className={buildClassName(["form__group", "form__group--sm-50"])}
|
|
165
|
-
>
|
|
166
|
-
<span className="form__label">
|
|
167
|
-
{translations.TRAVELERS_FORM.CHILDREN} *
|
|
168
|
-
</span>
|
|
169
|
-
<div className="dropdown">
|
|
170
|
-
<select onChange={handleChildCountChange} value={childCount}>
|
|
171
|
-
{range(0, 11).map((i) => (
|
|
172
|
-
<option key={i} value={i}>{`${i} ${
|
|
173
|
-
i === 1
|
|
174
|
-
? translations.TRAVELERS_FORM.CHILD
|
|
175
|
-
: translations.TRAVELERS_FORM.CHILDREN
|
|
176
|
-
}`}</option>
|
|
177
|
-
))}
|
|
178
|
-
</select>
|
|
179
|
-
</div>
|
|
180
|
-
</label>
|
|
238
|
+
<p className="form__region-label">
|
|
239
|
+
{compact([
|
|
240
|
+
adultIds.length,
|
|
241
|
+
adultIds.length === 1 && ` ${translations.TRAVELERS_FORM.ADULT}`,
|
|
242
|
+
adultIds.length > 1 && ` ${translations.TRAVELERS_FORM.ADULTS}`,
|
|
243
|
+
adultIds &&
|
|
244
|
+
adultIds.length &&
|
|
245
|
+
childIds &&
|
|
246
|
+
childIds.length &&
|
|
247
|
+
", ",
|
|
248
|
+
childIds.length,
|
|
249
|
+
childIds.length === 1 && ` ${translations.TRAVELERS_FORM.CHILD}`,
|
|
250
|
+
childIds.length > 1 && ` ${translations.TRAVELERS_FORM.CHILDREN}`,
|
|
251
|
+
]).join("")}
|
|
252
|
+
</p>
|
|
181
253
|
</div>
|
|
182
254
|
</div>
|
|
183
255
|
{formik.values.adults.map((travelerValues, index) => (
|
|
@@ -195,7 +267,7 @@ const TravelersForm: React.FC<TravelersFormProps> = () => {
|
|
|
195
267
|
<input
|
|
196
268
|
type="radio"
|
|
197
269
|
name="mainBookerId"
|
|
198
|
-
onChange={
|
|
270
|
+
onChange={handleMainBookerChange}
|
|
199
271
|
onBlur={formik.handleBlur}
|
|
200
272
|
value={travelerValues.id}
|
|
201
273
|
checked={formik.values.mainBookerId === travelerValues.id}
|
|
@@ -412,7 +484,11 @@ const TravelersForm: React.FC<TravelersFormProps> = () => {
|
|
|
412
484
|
<p className="form__region-label">
|
|
413
485
|
{compact([
|
|
414
486
|
compact([mainBooker?.firstName, mainBooker?.lastName]).join(" "),
|
|
415
|
-
mainBooker?.birthDate
|
|
487
|
+
mainBooker?.birthDate &&
|
|
488
|
+
format(
|
|
489
|
+
parse(mainBooker.birthDate, "yyyy-MM-dd", new Date()),
|
|
490
|
+
"dd-MM-yyyy"
|
|
491
|
+
),
|
|
416
492
|
]).join(", ")}
|
|
417
493
|
</p>
|
|
418
494
|
</div>
|
|
@@ -428,7 +504,7 @@ const TravelersForm: React.FC<TravelersFormProps> = () => {
|
|
|
428
504
|
name="street"
|
|
429
505
|
onChange={formik.handleChange}
|
|
430
506
|
onBlur={formik.handleBlur}
|
|
431
|
-
placeholder=
|
|
507
|
+
placeholder={translations.TRAVELERS_FORM.STREET_PLACEHOLDER}
|
|
432
508
|
value={formik.values.street}
|
|
433
509
|
/>
|
|
434
510
|
<LabeledInput
|
|
@@ -471,7 +547,7 @@ const TravelersForm: React.FC<TravelersFormProps> = () => {
|
|
|
471
547
|
label={translations.TRAVELERS_FORM.CITY}
|
|
472
548
|
required
|
|
473
549
|
name="place"
|
|
474
|
-
placeholder=
|
|
550
|
+
placeholder={translations.TRAVELERS_FORM.CITY_PLACEHOLDER}
|
|
475
551
|
onChange={formik.handleChange}
|
|
476
552
|
onBlur={formik.handleBlur}
|
|
477
553
|
value={formik.values.place}
|
|
@@ -546,16 +622,48 @@ const TravelersForm: React.FC<TravelersFormProps> = () => {
|
|
|
546
622
|
/>
|
|
547
623
|
</div>
|
|
548
624
|
</div>
|
|
549
|
-
{
|
|
550
|
-
<div className="form__region
|
|
551
|
-
<
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
<
|
|
625
|
+
{showAgentSelection && (
|
|
626
|
+
<div className="form__region">
|
|
627
|
+
<div className="form__region-header">
|
|
628
|
+
<h5 className="form__region-heading">
|
|
629
|
+
Ik wens te boeken bij mijn lokale reisagent
|
|
630
|
+
</h5>
|
|
631
|
+
<div className="checkbox" id="cbxChooseOffice">
|
|
632
|
+
<label className="checkbox__label">
|
|
633
|
+
<input
|
|
634
|
+
type="checkbox"
|
|
635
|
+
name="booking--mainbooker"
|
|
636
|
+
defaultChecked={showAgents}
|
|
637
|
+
onClick={() => toggleAgent(!showAgents)}
|
|
638
|
+
className="checkbox__input"
|
|
639
|
+
/>
|
|
640
|
+
Ik kies een kantoor
|
|
641
|
+
</label>
|
|
642
|
+
</div>
|
|
556
643
|
</div>
|
|
644
|
+
{showAgents && (
|
|
645
|
+
<div className="form__row form__row--choose-office">
|
|
646
|
+
<div
|
|
647
|
+
className={buildClassName([
|
|
648
|
+
"form__group",
|
|
649
|
+
"form__group--icon",
|
|
650
|
+
hasVisibleError("travelAgentId") && "form__group--error",
|
|
651
|
+
])}
|
|
652
|
+
>
|
|
653
|
+
<TypeAheadInput
|
|
654
|
+
value={formik.values.travelAgentName}
|
|
655
|
+
options={filteredAgents}
|
|
656
|
+
onChange={handleAgentChange}
|
|
657
|
+
onSelect={handleAgentSelect}
|
|
658
|
+
onClear={handleAgentClear}
|
|
659
|
+
name="travelAgentName"
|
|
660
|
+
placeholder="Kies uw reisagent"
|
|
661
|
+
/>
|
|
662
|
+
</div>
|
|
663
|
+
</div>
|
|
664
|
+
)}
|
|
557
665
|
</div>
|
|
558
|
-
|
|
666
|
+
)}
|
|
559
667
|
{Object.keys(flatErrors).length > 0 && (
|
|
560
668
|
<div className="form__region form__region--errors">
|
|
561
669
|
<div className="form__row">
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import Icon from "../../components/icon";
|
|
2
|
-
import React from "react";
|
|
2
|
+
import React, { useState } from "react";
|
|
3
3
|
|
|
4
4
|
interface TypeAheadInputProps {
|
|
5
5
|
name?: string;
|
|
@@ -7,6 +7,7 @@ interface TypeAheadInputProps {
|
|
|
7
7
|
placeholder?: string;
|
|
8
8
|
options?: { key: string; value: string | number; text: string }[];
|
|
9
9
|
onChange?: (value: string) => void;
|
|
10
|
+
onSelect?: (key: string) => void;
|
|
10
11
|
onClear?: () => void;
|
|
11
12
|
}
|
|
12
13
|
|
|
@@ -16,8 +17,11 @@ const TypeAheadInput: React.FC<TypeAheadInputProps> = ({
|
|
|
16
17
|
placeholder,
|
|
17
18
|
options,
|
|
18
19
|
onChange,
|
|
20
|
+
onSelect,
|
|
19
21
|
onClear,
|
|
20
22
|
}) => {
|
|
23
|
+
const [showItems, setShowItems] = useState<boolean>(false);
|
|
24
|
+
|
|
21
25
|
const handleChange: React.ChangeEventHandler<HTMLInputElement> = (e) => {
|
|
22
26
|
if (onChange) {
|
|
23
27
|
onChange(e.target.value);
|
|
@@ -28,6 +32,7 @@ const TypeAheadInput: React.FC<TypeAheadInputProps> = ({
|
|
|
28
32
|
if (onClear) {
|
|
29
33
|
onClear();
|
|
30
34
|
}
|
|
35
|
+
setShowItems(false);
|
|
31
36
|
};
|
|
32
37
|
|
|
33
38
|
return (
|
|
@@ -42,6 +47,14 @@ const TypeAheadInput: React.FC<TypeAheadInputProps> = ({
|
|
|
42
47
|
onChange={handleChange}
|
|
43
48
|
placeholder={placeholder}
|
|
44
49
|
required
|
|
50
|
+
autoComplete="off"
|
|
51
|
+
onKeyDown={(e) => {
|
|
52
|
+
if (e.key === "Tab" && options && onSelect) {
|
|
53
|
+
onSelect(options[0].key);
|
|
54
|
+
setShowItems(false);
|
|
55
|
+
}
|
|
56
|
+
}}
|
|
57
|
+
onFocus={() => setShowItems(true)}
|
|
45
58
|
/>
|
|
46
59
|
<button
|
|
47
60
|
type="button"
|
|
@@ -49,7 +62,7 @@ const TypeAheadInput: React.FC<TypeAheadInputProps> = ({
|
|
|
49
62
|
onClick={handleClearClick}
|
|
50
63
|
></button>
|
|
51
64
|
</div>
|
|
52
|
-
{options && options.length > 0 && (
|
|
65
|
+
{options && options.length > 0 && showItems && (
|
|
53
66
|
<div className="typeahead__options">
|
|
54
67
|
{(options ?? []).map((option) => {
|
|
55
68
|
const matchIndex =
|
|
@@ -61,7 +74,14 @@ const TypeAheadInput: React.FC<TypeAheadInputProps> = ({
|
|
|
61
74
|
return (
|
|
62
75
|
<div className="typeahead__option" key={option.key}>
|
|
63
76
|
<div className="typeahead__option-header">
|
|
64
|
-
<button
|
|
77
|
+
<button
|
|
78
|
+
onClick={() => {
|
|
79
|
+
if (onSelect) onSelect(option.key);
|
|
80
|
+
setShowItems(false);
|
|
81
|
+
}}
|
|
82
|
+
type="button"
|
|
83
|
+
className="button button--plain"
|
|
84
|
+
>
|
|
65
85
|
{prefix}
|
|
66
86
|
<span className="typeahead__option-highlight">
|
|
67
87
|
{highlight}
|