@bash-app/bash-common 30.56.0 → 30.58.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 (43) hide show
  1. package/dist/extendedSchemas.d.ts +44 -0
  2. package/dist/extendedSchemas.d.ts.map +1 -1
  3. package/dist/extendedSchemas.js +6 -0
  4. package/dist/extendedSchemas.js.map +1 -1
  5. package/dist/utils/dateTimeUtils.d.ts +1 -17
  6. package/dist/utils/dateTimeUtils.d.ts.map +1 -1
  7. package/dist/utils/dateTimeUtils.js +1 -114
  8. package/dist/utils/dateTimeUtils.js.map +1 -1
  9. package/dist/utils/luxonUtils.d.ts +17 -6
  10. package/dist/utils/luxonUtils.d.ts.map +1 -1
  11. package/dist/utils/luxonUtils.js +31 -3
  12. package/dist/utils/luxonUtils.js.map +1 -1
  13. package/dist/utils/recurrenceUtils.d.ts +1 -1
  14. package/dist/utils/recurrenceUtils.d.ts.map +1 -1
  15. package/dist/utils/recurrenceUtils.js +24 -49
  16. package/dist/utils/recurrenceUtils.js.map +1 -1
  17. package/dist/utils/service/apiServiceBookingApiUtils.d.ts +14 -2
  18. package/dist/utils/service/apiServiceBookingApiUtils.d.ts.map +1 -1
  19. package/dist/utils/service/apiServiceBookingApiUtils.js +36 -2
  20. package/dist/utils/service/apiServiceBookingApiUtils.js.map +1 -1
  21. package/dist/utils/service/frontendServiceBookingUtils.d.ts +10 -3
  22. package/dist/utils/service/frontendServiceBookingUtils.d.ts.map +1 -1
  23. package/dist/utils/service/frontendServiceBookingUtils.js +86 -40
  24. package/dist/utils/service/frontendServiceBookingUtils.js.map +1 -1
  25. package/dist/utils/service/serviceBookingTypes.d.ts +4 -2
  26. package/dist/utils/service/serviceBookingTypes.d.ts.map +1 -1
  27. package/dist/utils/ticketListUtils.d.ts.map +1 -1
  28. package/dist/utils/ticketListUtils.js +10 -13
  29. package/dist/utils/ticketListUtils.js.map +1 -1
  30. package/dist/utils/typeUtils.d.ts +5 -0
  31. package/dist/utils/typeUtils.d.ts.map +1 -1
  32. package/dist/utils/typeUtils.js.map +1 -1
  33. package/package.json +1 -1
  34. package/prisma/schema.prisma +31 -41
  35. package/src/extendedSchemas.ts +9 -0
  36. package/src/utils/dateTimeUtils.ts +7 -190
  37. package/src/utils/luxonUtils.ts +56 -10
  38. package/src/utils/recurrenceUtils.ts +97 -77
  39. package/src/utils/service/apiServiceBookingApiUtils.ts +64 -7
  40. package/src/utils/service/frontendServiceBookingUtils.ts +120 -49
  41. package/src/utils/service/serviceBookingTypes.ts +30 -2
  42. package/src/utils/ticketListUtils.ts +40 -27
  43. package/src/utils/typeUtils.ts +15 -8
@@ -1,9 +1,10 @@
1
+ import { ServiceBookingStatus, ServiceBookingType } from "@prisma/client";
1
2
  import {
2
3
  ApiBookingParamsLuxon,
3
- ApiServiceBookingParams,
4
- ApiServiceBookedDayParamsLuxon,
5
4
  ApiServiceAddonParams,
6
5
  ApiServiceBookedDayParams,
6
+ ApiServiceBookedDayParamsLuxon,
7
+ ApiServiceBookingParams,
7
8
  ApiServicePriceToBookResult,
8
9
  } from "../../definitions";
9
10
  import {
@@ -17,12 +18,15 @@ import {
17
18
  } from "../../extendedSchemas";
18
19
  import { dateTimeFromString, dateTimeRangeFromDates } from "../luxonUtils";
19
20
  import { serviceAttendeeOptions } from "./attendeeOptionUtils";
20
- import { ServiceBookingPriceBreakdownBaseT } from "./serviceBookingTypes";
21
21
  import {
22
- ServiceAddonInput,
23
- FrontendServiceGetPriceToBookResult,
24
22
  FrontendServiceBookingDayInfo,
23
+ FrontendServiceGetPriceToBookResult,
24
+ ServiceAddonInput,
25
25
  } from "./frontendServiceBookingUtils";
26
+ import {
27
+ ServiceBookingPriceBreakdownBaseT,
28
+ ServiceBookingRequiredData,
29
+ } from "./serviceBookingTypes";
26
30
 
27
31
  export type ApiServiceCantBookReason = {
28
32
  type: string;
@@ -30,6 +34,9 @@ export type ApiServiceCantBookReason = {
30
34
  };
31
35
 
32
36
  export const ApiServiceCantBookReasons = {
37
+ notPublished: {
38
+ msg: "The requested service must be published..",
39
+ } as ApiServiceCantBookReason,
33
40
  notInBusinessHours: {
34
41
  msg: "Time not within normal Business Hours",
35
42
  } as ApiServiceCantBookReason,
@@ -104,6 +111,7 @@ export function apiTransformBookedDays(
104
111
  packages: [],
105
112
  fees: day.fees as ServiceBookingFeeExt[],
106
113
  priceBreakdown: priceBreakdown,
114
+ subtotalBeforeTaxesCents: day.subtotalBeforeTaxesCents,
107
115
  totalBeforeTaxesCents: day.totalBeforeTaxesCents,
108
116
  } as Partial<ServiceBookingDayExt>;
109
117
  });
@@ -137,6 +145,7 @@ export function serviceGetPriceToBookFromBooking(
137
145
  addOns: day.addOns,
138
146
  priceBreakdown: priceBreakdown,
139
147
  fees: day.fees,
148
+ subtotalBeforeTaxesCents: day.subtotalBeforeTaxesCents,
140
149
  totalBeforeTaxesCents: day.totalBeforeTaxesCents,
141
150
  timezone: booking.timezone,
142
151
  } as FrontendServiceBookingDayInfo;
@@ -148,11 +157,15 @@ export function serviceGetPriceToBookFromBooking(
148
157
 
149
158
  return {
150
159
  serviceId: service.id,
151
- daysToBook: daysToBook,
160
+ timezone: booking.timezone,
152
161
  selectedAttendeeOption: serviceAttendeeOptions[0],
162
+ daysToBook: daysToBook,
163
+ rateOption: booking.rateOption,
164
+ flatRateCents: booking.flatRateCents,
153
165
  additionalFees: booking.additionalFees,
154
- timezone: booking.timezone,
166
+ addOns: booking.addOns,
155
167
  daysTotalBeforeTaxesCents: booking.daysTotalATBCents,
168
+ subtotalBeforeTaxesCents: booking.subtotalATBCents,
156
169
  totalBeforeTaxesCents: booking.totalATBCents,
157
170
  } as FrontendServiceGetPriceToBookResult;
158
171
  }
@@ -220,3 +233,47 @@ export function servicePriceToBookToApiDays(
220
233
 
221
234
  return bookedDays;
222
235
  }
236
+ export interface ServicePriceToBookToApiBookingBaseArgs {
237
+ bookingType: ServiceBookingType;
238
+ status: ServiceBookingStatus;
239
+ timezone: string;
240
+ priceToBook: FrontendServiceGetPriceToBookResult;
241
+ isFreeGuest?: boolean;
242
+ allowPromiseToPay?: boolean;
243
+ }
244
+
245
+ export function servicePriceToBookToApiBookingBase({
246
+ bookingType,
247
+ status,
248
+ timezone,
249
+ priceToBook,
250
+ allowPromiseToPay = false,
251
+ isFreeGuest = false,
252
+ }: ServicePriceToBookToApiBookingBaseArgs): ServiceBookingRequiredData {
253
+ const bookedDays = apiTransformBookedDays(priceToBook);
254
+ const addOns = priceToBook.addOns.map(
255
+ (addOn): Partial<ServiceBookingAddOnExt> => ({
256
+ addOnId: addOn.addOnId,
257
+ addOn: addOn.addOn,
258
+ chosenQuantity: addOn.chosenQuantity,
259
+ costPQCents: addOn.costPQCents,
260
+ })
261
+ );
262
+
263
+ return {
264
+ bookingType: bookingType,
265
+ status: status,
266
+ timezone: timezone,
267
+ rateOption: priceToBook.rateOption,
268
+ flatRateCents: priceToBook.flatRateCents ?? null,
269
+ bookedDays: bookedDays as ServiceBookingDayExt[],
270
+ additionalFees: priceToBook.additionalFees as ServiceBookingFeeExt[],
271
+ daysTotalATBCents: priceToBook.daysTotalBeforeTaxesCents,
272
+ subtotalATBCents: priceToBook.subtotalBeforeTaxesCents,
273
+ totalATBCents: priceToBook.totalBeforeTaxesCents,
274
+ addOns: addOns as ServiceBookingAddOnExt[],
275
+ packages: [],
276
+ allowPromiseToPay: allowPromiseToPay,
277
+ isFreeGuest: isFreeGuest,
278
+ };
279
+ }
@@ -2,6 +2,7 @@ import {
2
2
  ServiceAddon,
3
3
  ServiceBookingFee,
4
4
  ServiceBookingFeeType,
5
+ ServiceBookingRateOption,
5
6
  } from "@prisma/client";
6
7
  import {
7
8
  ServiceBookingAddOnExt,
@@ -54,6 +55,7 @@ export interface FrontendServiceBookingDayInfo {
54
55
  dateTimeRange: LuxonDateRange;
55
56
  timezone: string;
56
57
 
58
+ subtotalBeforeTaxesCents: number; //sum of all daysTotalBeforeTaxesCents, plus addOns/packages
57
59
  totalBeforeTaxesCents: number;
58
60
  }
59
61
 
@@ -63,13 +65,20 @@ export interface FrontendServiceGetPriceToBookResult {
63
65
  daysToBook: FrontendServiceBookingDayInfo[];
64
66
  additionalFees: ServiceBookingFeeBase[];
65
67
 
68
+ rateOption: ServiceBookingRateOption;
69
+ flatRateCents?: number; //only valid on flatRate
70
+
71
+ addOns: ServiceBookingAddOnBase[]; //for bookings that do not bill by the time. e.g. flat rate bookings. For time based bookings, addOns are part of the day
72
+
66
73
  daysTotalBeforeTaxesCents: number;
74
+ subtotalBeforeTaxesCents: number; //sum of all daysTotalBeforeTaxesCents, plus addOns/packages
67
75
  totalBeforeTaxesCents: number;
68
76
 
69
77
  minimumTimeBlockHours?: number; //only valid on generalRate
70
78
  }
71
79
 
72
80
  export interface FrontendServiceGetBookingDayInfoFrontParams {
81
+ rateOption: ServiceBookingRateOption; //if true, then no special rates, daily rates, or general rates are used
73
82
  filteredRates: ServiceRatesLuxon;
74
83
  // overlappingBusinessHours: LuxonDateRange[] | null;
75
84
 
@@ -78,6 +87,7 @@ export interface FrontendServiceGetBookingDayInfoFrontParams {
78
87
  }
79
88
 
80
89
  export function frontendServiceGetBookingDayInfo({
90
+ rateOption,
81
91
  filteredRates,
82
92
  daysToBookParams,
83
93
  // overlappingBusinessHours,
@@ -99,49 +109,55 @@ export function frontendServiceGetBookingDayInfo({
99
109
  let currentRange = { ...day.dateTimeRange };
100
110
  let baseCostDiscountedCents = 0;
101
111
 
102
- const rates = serviceRatesFilter(filteredRates, [day.dateTimeRange]);
103
- const { generalRate, specialRates, dailyRates } = rates;
104
- while (serviceRatesHasRates(rates) && hoursRemaining > 0) {
105
- const pricingInfo = getServiceRatePricingInfo(
106
- currentRange,
107
- generalRate,
108
- dailyRates,
109
- specialRates,
110
- // overlappingBusinessHours,
111
- timezone,
112
- hoursRemaining
113
- );
114
-
115
- if (pricingInfo.hours == 0 || pricingInfo.unitCount == 0) {
116
- throw new Error(`Invalid pricingInfo`);
117
- }
118
-
119
- priceBreakdown.push(pricingInfo);
120
-
121
- // currentRange.start = currentRange.start.plus({
122
- // hours: pricingInfo.hours,
123
- // });
124
- currentRange.start = pricingInfo.dateTimeRange.end;
125
- hoursRemaining -= pricingInfo.hours;
126
- baseCostDiscountedCents += pricingInfo.piTotalCents;
112
+ if (rateOption === ServiceBookingRateOption.FlatRate) {
113
+ } else if (rateOption === ServiceBookingRateOption.TimeBased) {
114
+ const rates = serviceRatesFilter(filteredRates, [day.dateTimeRange]);
115
+ const { generalRate, specialRates, dailyRates } = rates;
116
+ while (serviceRatesHasRates(rates) && hoursRemaining > 0) {
117
+ const pricingInfo = getServiceRatePricingInfo(
118
+ currentRange,
119
+ generalRate,
120
+ dailyRates,
121
+ specialRates,
122
+ // overlappingBusinessHours,
123
+ timezone,
124
+ hoursRemaining
125
+ );
126
+
127
+ if (pricingInfo.hours == 0 || pricingInfo.unitCount == 0) {
128
+ throw new Error(`Invalid pricingInfo`);
129
+ }
127
130
 
128
- if (pricingInfo.hours < SERVICE_DAILY_RATE_HOURS_MIN) {
129
- if (pricingInfo.rateType == "Special") {
130
- specialRates.pop();
131
- } else if (pricingInfo.rateType == "Weekday") {
132
- dailyRates.pop();
131
+ priceBreakdown.push(pricingInfo);
132
+
133
+ // currentRange.start = currentRange.start.plus({
134
+ // hours: pricingInfo.hours,
135
+ // });
136
+ currentRange.start = pricingInfo.dateTimeRange.end;
137
+ hoursRemaining -= pricingInfo.hours;
138
+ baseCostDiscountedCents += pricingInfo.piTotalCents;
139
+
140
+ if (pricingInfo.hours < SERVICE_DAILY_RATE_HOURS_MIN) {
141
+ if (pricingInfo.rateType == "Special") {
142
+ specialRates.pop();
143
+ } else if (pricingInfo.rateType == "Weekday") {
144
+ dailyRates.pop();
145
+ }
133
146
  }
134
147
  }
135
148
  }
136
149
 
137
- const addOns = day.addOns.map((addOn): ServiceBookingAddOnBase => {
138
- return {
139
- addOn: addOn,
140
- addOnId: addOn.id,
141
- chosenQuantity: addOn.chosenQuantity ?? 0,
142
- costPQCents: addOn.priceCents,
143
- };
144
- });
150
+ const addOns =
151
+ rateOption === "FlatRate"
152
+ ? []
153
+ : day.addOns.map((addOn): ServiceBookingAddOnBase => {
154
+ return {
155
+ addOn: addOn,
156
+ addOnId: addOn.id,
157
+ chosenQuantity: addOn.chosenQuantity ?? 0,
158
+ costPQCents: addOn.priceCents,
159
+ };
160
+ });
145
161
 
146
162
  const feesTotalCents = day.fees.reduce(
147
163
  (sofar, fee) => sofar + fee.costPQCents * fee.quantity,
@@ -153,15 +169,19 @@ export function frontendServiceGetBookingDayInfo({
153
169
  0
154
170
  );
155
171
 
156
- const totalBeforeTaxesCents =
157
- baseCostDiscountedCents + addOnsTotalCents + feesTotalCents;
172
+ const subtotalBeforeTaxesCents =
173
+ baseCostDiscountedCents + addOnsTotalCents;
174
+
175
+ const totalBeforeTaxesCents = subtotalBeforeTaxesCents + feesTotalCents;
158
176
 
159
177
  return {
160
178
  priceBreakdown: priceBreakdown,
161
179
  dateTimeRange: day.dateTimeRange,
180
+ rateOption: rateOption,
162
181
  timezone: day.dateTimeRange.start.zoneName,
163
182
  fees: day.fees,
164
183
  addOns: addOns,
184
+ subtotalBeforeTaxesCents: subtotalBeforeTaxesCents,
165
185
  totalBeforeTaxesCents: totalBeforeTaxesCents,
166
186
  } as FrontendServiceBookingDayInfo;
167
187
  });
@@ -174,6 +194,7 @@ export interface FrontendServiceGetPriceToBookFeesParams {
174
194
  selectedAttendeeOption: ServiceAttendeeOption;
175
195
 
176
196
  additionalFees: ServiceBookingFeeBase[];
197
+ addOns: ServiceAddonInput[]; //used for bookings that do not bill by the time. e.g. flat rate bookings
177
198
 
178
199
  // overlappingBusinessHours: LuxonDateRange[] | null;
179
200
  timezone: string | null | undefined;
@@ -184,6 +205,7 @@ export function frontendServiceGetPriceToBookFees(
184
205
  {
185
206
  daysToBookParams,
186
207
  selectedAttendeeOption,
208
+ addOns,
187
209
  additionalFees,
188
210
  // overlappingBusinessHours,
189
211
  timezone,
@@ -198,33 +220,76 @@ export function frontendServiceGetPriceToBookFees(
198
220
  timezone
199
221
  );
200
222
 
223
+ const isFlatRate = (filteredRates.generalRate?.flatRateCents ?? 0) > 0;
224
+ const rateOption = isFlatRate
225
+ ? ServiceBookingRateOption.FlatRate
226
+ : ServiceBookingRateOption.TimeBased;
227
+
228
+ //only add addOns if flat rate booking (addOns are part of the day for time based bookings)
229
+ const usedAddons =
230
+ rateOption === ServiceBookingRateOption.FlatRate
231
+ ? addOns.map((addOn): ServiceBookingAddOnBase => {
232
+ return {
233
+ addOn: addOn,
234
+ addOnId: addOn.id,
235
+ chosenQuantity: addOn.chosenQuantity ?? 0,
236
+ costPQCents: addOn.priceCents,
237
+ };
238
+ })
239
+ : [];
240
+
201
241
  const bookingDayResults: FrontendServiceBookingDayInfo[] =
202
242
  frontendServiceGetBookingDayInfo({
243
+ rateOption: rateOption,
203
244
  filteredRates: filteredRates,
204
245
  daysToBookParams: daysToBookParams,
205
246
  // overlappingBusinessHours: overlappingBusinessHours,
206
247
  timezone: timezone,
207
248
  });
208
249
 
209
- const daysTotalBeforeTaxesCents = bookingDayResults.reduce((sofar, curr) => {
210
- return sofar + curr.totalBeforeTaxesCents;
211
- }, 0);
250
+ const flatRateCents = filteredRates.generalRate?.flatRateCents ?? 0;
251
+
252
+ const daysTotalBeforeTaxesCents =
253
+ rateOption === ServiceBookingRateOption.FlatRate
254
+ ? flatRateCents
255
+ : bookingDayResults.reduce((sofar, curr) => {
256
+ return sofar + curr.totalBeforeTaxesCents;
257
+ }, 0);
212
258
 
213
259
  const minimumTimeBlockHours =
214
260
  serviceRatesAssociation?.serviceGeneralRates?.minimumTimeBlockHours;
215
261
 
216
262
  // const attendeeRate = selectedAttendeeOption.rate * durationHours;
217
263
 
218
- const processingFeeCents =
219
- SERVICE_BOOKING_PROCESSING_FEE_PERCENT * daysTotalBeforeTaxesCents;
264
+ let allAdditionalFees = [...additionalFees];
265
+
266
+ // if (rateOption === ServiceBookingRateOption.FlatRate) {
267
+ // allAdditionalFees.push({
268
+ // feeType: ServiceBookingFeeType.FlatRate,
269
+ // name: "Flat Rate",
270
+ // description: "Flat Rate",
271
+ // costPQCents: filteredRates.generalRate?.flatRateCents ?? 0,
272
+ // quantity: 1,
273
+ // });
274
+ // }
220
275
 
221
276
  const hasCustomProcessingFee = additionalFees.some(
222
277
  (fee) => fee.feeType == ServiceBookingFeeType.ProcessingFee
223
278
  );
224
279
 
225
- let allAdditionalFees = [...additionalFees];
280
+ allAdditionalFees = allAdditionalFees.filter((fee) => fee.costPQCents > 0);
281
+
282
+ const addOnsTotalCents = usedAddons.reduce(
283
+ (sofar, addOn) => sofar + addOn.costPQCents * addOn.chosenQuantity,
284
+ 0
285
+ );
286
+
287
+ const subtotalBeforeTaxesCents = daysTotalBeforeTaxesCents + addOnsTotalCents;
226
288
 
227
289
  if (!hasCustomProcessingFee) {
290
+ const processingFeeCents =
291
+ SERVICE_BOOKING_PROCESSING_FEE_PERCENT * subtotalBeforeTaxesCents;
292
+
228
293
  allAdditionalFees.push({
229
294
  feeType: ServiceBookingFeeType.ProcessingFee,
230
295
  name: "Processing Fee",
@@ -234,23 +299,28 @@ export function frontendServiceGetPriceToBookFees(
234
299
  });
235
300
  }
236
301
 
237
- allAdditionalFees = allAdditionalFees.filter((fee) => fee.costPQCents > 0);
238
-
239
302
  const allAdditionalFeesCents = allAdditionalFees.reduce(
240
303
  (sofar, fee) => sofar + fee.costPQCents * fee.quantity,
241
304
  0
242
305
  );
243
306
 
244
307
  const totalBeforeTaxesCents =
245
- daysTotalBeforeTaxesCents + allAdditionalFeesCents;
308
+ subtotalBeforeTaxesCents + allAdditionalFeesCents;
246
309
 
247
310
  return {
248
311
  serviceId: serviceRatesAssociation?.serviceId,
249
312
  daysToBook: bookingDayResults,
250
313
  daysTotalBeforeTaxesCents: daysTotalBeforeTaxesCents,
314
+ subtotalBeforeTaxesCents: subtotalBeforeTaxesCents,
251
315
  totalBeforeTaxesCents: totalBeforeTaxesCents,
252
316
  additionalFees: allAdditionalFees,
317
+ addOns: usedAddons,
253
318
  minimumTimeBlockHours: minimumTimeBlockHours,
319
+ rateOption: rateOption,
320
+ flatRateCents:
321
+ (filteredRates.generalRate?.flatRateCents ?? 0) > 0
322
+ ? filteredRates.generalRate?.flatRateCents
323
+ : undefined,
254
324
  } as FrontendServiceGetPriceToBookResult;
255
325
  }
256
326
 
@@ -305,6 +375,7 @@ export function frontendServiceGetPriceToBook(
305
375
  daysToBookParams: daysToBookParams,
306
376
  selectedAttendeeOption: selectedAttendeeOption,
307
377
  additionalFees: [],
378
+ addOns: addOns,
308
379
  timezone: timezone,
309
380
  });
310
381
  }
@@ -1,3 +1,4 @@
1
+ import { ServiceBookingType, ServiceBookingStatus } from "@prisma/client";
1
2
  import {
2
3
  ServiceBookingAddOnExt,
3
4
  ServiceBookingFeeExt,
@@ -8,14 +9,24 @@ import {
8
9
  ServiceBookingExt,
9
10
  } from "../../extendedSchemas";
10
11
  import { LuxonDateRange } from "../luxonUtils";
12
+ import { FrontendServiceGetPriceToBookResult } from "./frontendServiceBookingUtils";
13
+ import { MakeNullablePropsOptional, MakeOptional } from "../typeUtils";
11
14
 
12
15
  export type ServiceBookingAddOnBase = Omit<
13
16
  ServiceBookingAddOnExt,
14
- "id" | "serviceBookingDayId" | "serviceBookingDay"
17
+ | "id"
18
+ | "serviceBookingDayId"
19
+ | "serviceBookingDay"
20
+ | "serviceBookingId"
21
+ | "serviceBooking"
15
22
  >;
16
23
  export type ServiceBookingPackageBase = Omit<
17
24
  ServiceBookingAddOnExt,
18
- "id" | "serviceBookingDayId" | "serviceBookingDay"
25
+ | "id"
26
+ | "serviceBookingDayId"
27
+ | "serviceBookingDay"
28
+ | "serviceBookingId"
29
+ | "serviceBooking"
19
30
  >;
20
31
  export type ServiceBookingFeeBase = Omit<
21
32
  ServiceBookingFeeExt,
@@ -38,6 +49,23 @@ export type ServiceBookingBase = Pick<
38
49
  "bookedDays" | "timezone" | "additionalFees"
39
50
  >;
40
51
 
52
+ export type ServiceBookingRequiredData = MakeNullablePropsOptional<
53
+ MakeOptional<
54
+ ServiceBookingExt,
55
+ | "id"
56
+ | "isVendorBid"
57
+ | "bashEventId"
58
+ | "vendorEventDetails"
59
+ | "serviceId"
60
+ | "service"
61
+ | "forUserId"
62
+ | "forUser"
63
+ | "creatorId"
64
+ | "creator"
65
+ | "checkout"
66
+ >
67
+ >;
68
+
41
69
  export type ServiceBookingAddonBaseT = ServiceBookingAddOnBase; //T for Transformed/Processed aka used for logic
42
70
  export type ServiceBookingPackageBaseT = ServiceBookingPackageBase;
43
71
  export type ServiceBookingFeeBaseT = ServiceBookingFeeBase;
@@ -4,51 +4,54 @@ import {
4
4
  URL_PARAMS_NUMBER_OF_TICKETS_TICKETS_DATE_DELIM,
5
5
  URL_PARAMS_TICKET_LIST_DELIM,
6
6
  URL_PARAMS_TICKET_TIER_ID_NUMBER_OF_TICKETS_DATE_DELIM,
7
- URL_PARAMS_TICKETS_DATE_DELIM
7
+ URL_PARAMS_TICKETS_DATE_DELIM,
8
8
  } from "../definitions";
9
- import { DATETIME_FORMAT_ISO_LIKE } from "./dateTimeUtils";
10
-
9
+ import {
10
+ dateTimeFormat,
11
+ dateTimeFromDate,
12
+ dateTimeFromString,
13
+ LUXON_DATETIME_FORMAT_ISO_LIKE,
14
+ } from "./luxonUtils";
11
15
 
12
16
  /**
13
17
  * Returns A string structured like: [ticketTierId]__[numberOfTickets];;[date]~~[numberOfTickets];;[date]~~,...
14
18
  * @param ticketList A map where the key is the ticketTierId
15
19
  */
16
- export function ticketListToString(ticketList: Map<string, NumberOfTicketsForDate[]>): string {
20
+ export function ticketListToString(
21
+ ticketList: Map<string, NumberOfTicketsForDate[]>
22
+ ): string {
17
23
  const ticketListArr: string[] = [];
18
24
 
19
25
  for (const [ticketTierId, ticketListArgs] of ticketList.entries()) {
20
26
  let ticketsExist = true;
21
- const ticketArgs: string[] = [`${ticketTierId}${URL_PARAMS_TICKET_TIER_ID_NUMBER_OF_TICKETS_DATE_DELIM}`];
27
+ const ticketArgs: string[] = [
28
+ `${ticketTierId}${URL_PARAMS_TICKET_TIER_ID_NUMBER_OF_TICKETS_DATE_DELIM}`,
29
+ ];
22
30
  for (const ticketNumAndDates of ticketListArgs) {
23
31
  if (ticketNumAndDates.numberOfTickets > 0) {
24
32
  ticketsExist = true;
25
-
33
+
26
34
  // Ensure ticketDateTime is in ISO format
27
35
  let dateTimeStr = ticketNumAndDates.ticketDateTime;
28
36
  if (dateTimeStr) {
29
37
  // If it's already a string, try to parse it as DateTime and convert to ISO
30
- const dateTime = typeof dateTimeStr === 'string'
31
- ? DateTime.fromFormat(dateTimeStr, DATETIME_FORMAT_ISO_LIKE).isValid
32
- ? DateTime.fromFormat(dateTimeStr, DATETIME_FORMAT_ISO_LIKE)
33
- : DateTime.fromISO(dateTimeStr).isValid
34
- ? DateTime.fromISO(dateTimeStr)
35
- : DateTime.fromJSDate(new Date(dateTimeStr))
36
- : DateTime.fromJSDate(dateTimeStr as any);
37
-
38
+ const dateTime = dateTimeFromDate(dateTimeStr);
38
39
  if (dateTime.isValid) {
39
- dateTimeStr = dateTime.toISO() || dateTimeStr;
40
+ dateTimeStr = dateTimeFormat(dateTime) || dateTimeStr;
40
41
  }
41
42
  }
42
-
43
+
43
44
  ticketArgs.push(
44
- `${ticketNumAndDates.numberOfTickets}${URL_PARAMS_TICKETS_DATE_DELIM}${dateTimeStr}`);
45
- }
46
- else {
45
+ `${ticketNumAndDates.numberOfTickets}${URL_PARAMS_TICKETS_DATE_DELIM}${dateTimeStr}`
46
+ );
47
+ } else {
47
48
  ticketsExist = false;
48
49
  }
49
50
  }
50
51
  if (ticketsExist) {
51
- ticketListArr.push(ticketArgs.join(URL_PARAMS_NUMBER_OF_TICKETS_TICKETS_DATE_DELIM));
52
+ ticketListArr.push(
53
+ ticketArgs.join(URL_PARAMS_NUMBER_OF_TICKETS_TICKETS_DATE_DELIM)
54
+ );
52
55
  }
53
56
  }
54
57
  return ticketListArr.join(URL_PARAMS_TICKET_LIST_DELIM);
@@ -58,7 +61,9 @@ export function ticketListToString(ticketList: Map<string, NumberOfTicketsForDat
58
61
  * Returns map where the key is the ticketTierId
59
62
  * @param ticketListStr A string structured like: [ticketTierId]__[numberOfTickets];;[date]~~[numberOfTickets];;[date]~~...,...
60
63
  */
61
- export function ticketListStrToTicketList(ticketListStr: string): Map<string, NumberOfTicketsForDate[]> {
64
+ export function ticketListStrToTicketList(
65
+ ticketListStr: string
66
+ ): Map<string, NumberOfTicketsForDate[]> {
62
67
  const ticketList: Map<string, NumberOfTicketsForDate[]> = new Map();
63
68
 
64
69
  // [ticketTierId]__~~[numberOfTickets];;[date]~~[numberOfTickets];;[date]~~...,...
@@ -67,22 +72,30 @@ export function ticketListStrToTicketList(ticketListStr: string): Map<string, Nu
67
72
  ticketListArgs.forEach((tierIdAndTicketNumbersAndDates: string): void => {
68
73
  const ticketNumAndDatesArr: NumberOfTicketsForDate[] = [];
69
74
  // [ticketTierId]__~~[numberOfTickets];;[date]~~[numberOfTickets];;[date]~~...
70
- const [ticketTierId, ticketNumAndDatesStr] = tierIdAndTicketNumbersAndDates.split(URL_PARAMS_TICKET_TIER_ID_NUMBER_OF_TICKETS_DATE_DELIM);
75
+ const [ticketTierId, ticketNumAndDatesStr] =
76
+ tierIdAndTicketNumbersAndDates.split(
77
+ URL_PARAMS_TICKET_TIER_ID_NUMBER_OF_TICKETS_DATE_DELIM
78
+ );
71
79
  if (!ticketNumAndDatesArr) {
72
- throw new Error(`Could not parse ticketListStr. Maybe it is just an amount?`);
80
+ throw new Error(
81
+ `Could not parse ticketListStr. Maybe it is just an amount?`
82
+ );
73
83
  }
74
84
  // ~~[numberOfTickets];;[date]~~[numberOfTickets];;[date]~~...
75
- const ticketNumAndDates = ticketNumAndDatesStr.split(URL_PARAMS_NUMBER_OF_TICKETS_TICKETS_DATE_DELIM)
76
- .filter((ticketNumAndDateStr): boolean => !!ticketNumAndDateStr);
85
+ const ticketNumAndDates = ticketNumAndDatesStr
86
+ .split(URL_PARAMS_NUMBER_OF_TICKETS_TICKETS_DATE_DELIM)
87
+ .filter((ticketNumAndDateStr): boolean => !!ticketNumAndDateStr);
77
88
 
78
89
  for (const ticketNumAndDateStr of ticketNumAndDates) {
79
90
  // [numberOfTickets];;[date]
80
- const [numberOfTickets, ticketDateTimeStr] = ticketNumAndDateStr.split(URL_PARAMS_TICKETS_DATE_DELIM);
91
+ const [numberOfTickets, ticketDateTimeStr] = ticketNumAndDateStr.split(
92
+ URL_PARAMS_TICKETS_DATE_DELIM
93
+ );
81
94
  const ticketDateTime = DateTime.fromISO(ticketDateTimeStr);
82
95
  let ticketDateTimeFormattedStr: string | undefined = undefined;
83
96
 
84
97
  if (ticketDateTime.isValid) {
85
- ticketDateTimeFormattedStr = ticketDateTime.toFormat(DATETIME_FORMAT_ISO_LIKE);
98
+ ticketDateTimeFormattedStr = dateTimeFormat(ticketDateTime);
86
99
  }
87
100
 
88
101
  ticketNumAndDatesArr.push({
@@ -6,17 +6,24 @@ export type RemoveCommonProperties<T, U> = keyof (Omit<T, keyof U> &
6
6
  export type MakeOptional<T, K extends keyof T> = Omit<T, K> &
7
7
  Partial<Pick<T, K>>;
8
8
 
9
+ export type MakeNullablePropsOptional<T> = {
10
+ [K in keyof T as null extends T[K] ? K : never]?:
11
+ | Exclude<T[K], undefined>
12
+ | undefined;
13
+ } & {
14
+ [K in keyof T as null extends T[K] ? never : K]: T[K];
15
+ };
16
+
9
17
  export type MakeRequired<T, K extends keyof T> = Omit<T, K> &
10
18
  Required<Pick<T, K>>;
11
19
 
12
- export type DeepPartial<T> =
13
- | T extends Function
14
- ? T
15
- : T extends Array<infer U>
16
- ? Array<DeepPartial<U>>
17
- : T extends object
18
- ? { [P in keyof T]?: DeepPartial<T[P]> }
19
- : T;
20
+ export type DeepPartial<T> = T extends Function
21
+ ? T
22
+ : T extends Array<infer U>
23
+ ? Array<DeepPartial<U>>
24
+ : T extends object
25
+ ? { [P in keyof T]?: DeepPartial<T[P]> }
26
+ : T;
20
27
 
21
28
  export type Override<T, U> = Omit<T, keyof U> & U;
22
29