@bash-app/bash-common 30.75.2 → 30.78.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 (40) hide show
  1. package/dist/definitions.d.ts +116 -0
  2. package/dist/definitions.d.ts.map +1 -1
  3. package/dist/definitions.js +143 -1
  4. package/dist/definitions.js.map +1 -1
  5. package/dist/extendedSchemas.d.ts +12 -0
  6. package/dist/extendedSchemas.d.ts.map +1 -1
  7. package/dist/extendedSchemas.js.map +1 -1
  8. package/dist/index.d.ts +0 -1
  9. package/dist/index.d.ts.map +1 -1
  10. package/dist/index.js +1 -1
  11. package/dist/index.js.map +1 -1
  12. package/dist/membershipDefinitions.d.ts +1 -0
  13. package/dist/membershipDefinitions.d.ts.map +1 -1
  14. package/dist/membershipDefinitions.js.map +1 -1
  15. package/dist/utils/paymentUtils.d.ts +41 -1
  16. package/dist/utils/paymentUtils.d.ts.map +1 -1
  17. package/dist/utils/paymentUtils.js +146 -1
  18. package/dist/utils/paymentUtils.js.map +1 -1
  19. package/dist/utils/recurrenceUtils.d.ts.map +1 -1
  20. package/dist/utils/recurrenceUtils.js +136 -2
  21. package/dist/utils/recurrenceUtils.js.map +1 -1
  22. package/dist/utils/service/frontendServiceBookingUtils.d.ts.map +1 -1
  23. package/dist/utils/service/frontendServiceBookingUtils.js +5 -1
  24. package/dist/utils/service/frontendServiceBookingUtils.js.map +1 -1
  25. package/dist/utils/userSubscriptionUtils.d.ts +4 -12
  26. package/dist/utils/userSubscriptionUtils.d.ts.map +1 -1
  27. package/dist/utils/userSubscriptionUtils.js +13 -20
  28. package/dist/utils/userSubscriptionUtils.js.map +1 -1
  29. package/package.json +1 -1
  30. package/prisma/schema.prisma +193 -107
  31. package/src/definitions.ts +180 -1
  32. package/src/extendedSchemas.ts +21 -2
  33. package/src/index.ts +1 -1
  34. package/src/membershipDefinitions.ts +1 -0
  35. package/src/utils/contentFilterUtils.ts +2 -0
  36. package/src/utils/paymentUtils.ts +221 -1
  37. package/src/utils/recurrenceUtils.ts +180 -4
  38. package/src/utils/service/frontendServiceBookingUtils.ts +5 -1
  39. package/src/utils/userSubscriptionUtils.ts +20 -38
  40. package/src/utils/service/venueUtils.ts +0 -30
@@ -37,26 +37,58 @@ function getRecurringBashEventPossibleDatesTimesInternal(
37
37
  recurrence: Recurrence | undefined | null,
38
38
  toDate: boolean
39
39
  ): (DateTime | Date)[] {
40
+ console.log("🚨 getRecurringBashEventPossibleDatesTimesInternal called:", {
41
+ startDateTime,
42
+ recurrence,
43
+ toDate,
44
+ });
45
+
40
46
  if (
41
47
  !recurrence ||
42
48
  !recurrence.frequency ||
43
49
  recurrence.frequency === RecurringFrequency.Never
44
50
  ) {
51
+ console.log("🚨 Early return: No recurrence or frequency is Never");
45
52
  return [];
46
53
  }
47
54
 
48
55
  let recurrenceDates: DateTime[] = [];
49
- const beginningDate = findEarliestPossibleBashEventDate(
50
- startDateTime
51
- ) as DateTime; // Don't allow dates before the current date
56
+
57
+ // For Monthly and Yearly, start from the event's actual date, not "today"
58
+ // This ensures we generate dates relative to the event's schedule
59
+ const shouldUseEventDate =
60
+ recurrence.frequency === RecurringFrequency.Monthly ||
61
+ recurrence.frequency === RecurringFrequency.Yearly;
62
+
63
+ const beginningDate = shouldUseEventDate
64
+ ? (startDateTime ? dateTimeFromDate(startDateTime) as DateTime : DateTime.local())
65
+ : findEarliestPossibleBashEventDate(startDateTime) as DateTime;
66
+
67
+ console.log("🚨 beginningDate:", beginningDate?.toISO(), "shouldUseEventDate:", shouldUseEventDate);
52
68
 
53
69
  switch (recurrence.frequency) {
70
+ case RecurringFrequency.Daily:
71
+ console.log("🚨 Calling getDailyRecurringDates");
72
+ recurrenceDates = getDailyRecurringDates(beginningDate, recurrence);
73
+ break;
54
74
  case RecurringFrequency.Weekly:
75
+ console.log("🚨 Calling getWeeklyRecurringDates");
55
76
  recurrenceDates = getWeeklyRecurringDates(beginningDate, recurrence);
56
77
  break;
78
+ case RecurringFrequency.Monthly:
79
+ console.log("🚨 Calling getMonthlyRecurringDates");
80
+ recurrenceDates = getMonthlyRecurringDates(beginningDate, recurrence);
81
+ break;
82
+ case RecurringFrequency.Yearly:
83
+ console.log("🚨 Calling getYearlyRecurringDates");
84
+ recurrenceDates = getYearlyRecurringDates(beginningDate, recurrence);
85
+ break;
57
86
  default:
58
- console.error(`Only weekly frequency is currently supported`);
87
+ console.error(`Unsupported frequency: ${recurrence.frequency}`);
59
88
  }
89
+
90
+ console.log("🚨 recurrenceDates before mapping:", recurrenceDates.length, recurrenceDates.map(d => d.toISO()));
91
+
60
92
  return recurrenceDates
61
93
  .map((date: DateTime): string =>
62
94
  date.toFormat(LUXON_DATETIME_FORMAT_ISO_LIKE)
@@ -75,6 +107,39 @@ function getRecurringBashEventPossibleDatesTimesInternal(
75
107
  });
76
108
  }
77
109
 
110
+ /**
111
+ * Get the daily recurring dates
112
+ * @param beginningDateTime The beginning DateTime of the event, adjusted to be no earlier than now.
113
+ * @param recurrence
114
+ */
115
+ function getDailyRecurringDates(
116
+ beginningDateTime: DateTime,
117
+ recurrence: Recurrence
118
+ ): DateTime[] {
119
+ if (recurrence.frequency !== RecurringFrequency.Daily) {
120
+ throw new Error(
121
+ `Cannot do a daily recurrence if the frequency isn't daily.`
122
+ );
123
+ }
124
+
125
+ const interval = recurrence.interval ?? 1;
126
+ const recurrenceEnds = dateTimeFromDate(recurrence.ends).endOf("day");
127
+ const numberOfDays = recurrenceEnds.diff(beginningDateTime, "days").days;
128
+ const numberOfOccurrences = Math.ceil(numberOfDays / interval);
129
+
130
+ const recurrenceDates: DateTime[] = [];
131
+ let currentDate = beginningDateTime;
132
+
133
+ for (let i = 0; i < numberOfOccurrences && currentDate <= recurrenceEnds; i++) {
134
+ if (currentDate >= beginningDateTime) {
135
+ recurrenceDates.push(currentDate);
136
+ }
137
+ currentDate = currentDate.plus({ days: interval });
138
+ }
139
+
140
+ return recurrenceDates;
141
+ }
142
+
78
143
  /**
79
144
  * Get the weekly recurring dates
80
145
  * @param beginningDateTime The beginning DateTime of the event, adjusted to be no earlier than now.
@@ -137,6 +202,117 @@ function getBeginningOfWeekInterval(
137
202
  return date.endOf("week").plus({ days: numberOfDaysToAdd });
138
203
  }
139
204
 
205
+ /**
206
+ * Get the monthly recurring dates
207
+ * @param beginningDateTime The beginning DateTime of the event, adjusted to be no earlier than now.
208
+ * @param recurrence
209
+ */
210
+ function getMonthlyRecurringDates(
211
+ beginningDateTime: DateTime,
212
+ recurrence: Recurrence
213
+ ): DateTime[] {
214
+ if (recurrence.frequency !== RecurringFrequency.Monthly) {
215
+ throw new Error(
216
+ `Cannot do a monthly recurrence if the frequency isn't monthly.`
217
+ );
218
+ }
219
+
220
+ const interval = recurrence.interval ?? 1;
221
+ const recurrenceEnds = dateTimeFromDate(recurrence.ends).endOf("day");
222
+ const dayOfMonth = recurrence.repeatOnDayOfMonth ?? beginningDateTime.day;
223
+
224
+ console.log("📅 Monthly recurrence debug:", {
225
+ beginningDateTime: beginningDateTime.toISO(),
226
+ recurrenceEnds: recurrenceEnds.toISO(),
227
+ dayOfMonth,
228
+ interval,
229
+ "beginningDateTime.day": beginningDateTime.day,
230
+ "beginningDateTime.daysInMonth": beginningDateTime.daysInMonth,
231
+ });
232
+
233
+ const recurrenceDates: DateTime[] = [];
234
+ let currentDate = beginningDateTime.set({ day: Math.min(dayOfMonth, beginningDateTime.daysInMonth || 31) });
235
+
236
+ console.log("📅 Initial currentDate:", currentDate.toISO());
237
+
238
+ // If the day of month is after the current day, start from the current month
239
+ if (currentDate < beginningDateTime) {
240
+ console.log("📅 currentDate < beginningDateTime, adding 1 month");
241
+ currentDate = currentDate.plus({ months: 1 });
242
+ currentDate = currentDate.set({ day: Math.min(dayOfMonth, currentDate.daysInMonth || 31) });
243
+ console.log("📅 New currentDate after adjustment:", currentDate.toISO());
244
+ }
245
+
246
+ let iterations = 0;
247
+ while (currentDate <= recurrenceEnds && iterations < 100) {
248
+ iterations++;
249
+ console.log(`📅 Iteration ${iterations}: currentDate=${currentDate.toISO()}, recurrenceEnds=${recurrenceEnds.toISO()}, currentDate <= recurrenceEnds: ${currentDate <= recurrenceEnds}`);
250
+
251
+ if (currentDate >= beginningDateTime) {
252
+ // Set the time to match the beginning time
253
+ const dateWithTime = dateTimeSetTime(currentDate, beginningDateTime);
254
+ console.log(`📅 Adding date: ${dateWithTime.toISO()}`);
255
+ recurrenceDates.push(dateWithTime);
256
+ }
257
+ currentDate = currentDate.plus({ months: interval });
258
+ // Handle months with fewer days (e.g., Feb 31 -> Feb 28/29)
259
+ currentDate = currentDate.set({ day: Math.min(dayOfMonth, currentDate.daysInMonth || 31) });
260
+ }
261
+
262
+ console.log("📅 Monthly recurrence complete:", {
263
+ totalDates: recurrenceDates.length,
264
+ dates: recurrenceDates.map(d => d.toISO()),
265
+ });
266
+
267
+ return recurrenceDates;
268
+ }
269
+
270
+ /**
271
+ * Get the yearly recurring dates
272
+ * @param beginningDateTime The beginning DateTime of the event, adjusted to be no earlier than now.
273
+ * @param recurrence
274
+ */
275
+ function getYearlyRecurringDates(
276
+ beginningDateTime: DateTime,
277
+ recurrence: Recurrence
278
+ ): DateTime[] {
279
+ if (recurrence.frequency !== RecurringFrequency.Yearly) {
280
+ throw new Error(
281
+ `Cannot do a yearly recurrence if the frequency isn't yearly.`
282
+ );
283
+ }
284
+
285
+ const interval = recurrence.interval ?? 1;
286
+ const recurrenceEnds = dateTimeFromDate(recurrence.ends).endOf("day");
287
+
288
+ // Use the repeatYearlyDate if provided, otherwise use the beginning date
289
+ const baseDate = recurrence.repeatYearlyDate
290
+ ? dateTimeFromDate(recurrence.repeatYearlyDate)
291
+ : beginningDateTime;
292
+
293
+ const recurrenceDates: DateTime[] = [];
294
+ let currentDate = baseDate.set({
295
+ year: beginningDateTime.year,
296
+ hour: beginningDateTime.hour,
297
+ minute: beginningDateTime.minute,
298
+ second: beginningDateTime.second
299
+ });
300
+
301
+ // If we've already passed this date this year, start from next year
302
+ if (currentDate < beginningDateTime) {
303
+ currentDate = currentDate.plus({ years: interval });
304
+ }
305
+
306
+ while (currentDate <= recurrenceEnds) {
307
+ if (currentDate >= beginningDateTime) {
308
+ recurrenceDates.push(currentDate);
309
+ }
310
+ currentDate = currentDate.plus({ years: interval });
311
+ }
312
+
313
+ return recurrenceDates;
314
+ }
315
+
140
316
  export function freqToGrammarString(
141
317
  freq: RecurringFrequency,
142
318
  interval: number | undefined,
@@ -33,8 +33,12 @@ import {
33
33
  ServiceBookingAddOnBase,
34
34
  } from "./serviceBookingTypes";
35
35
  import { convertDollarsToCents } from "../paymentUtils";
36
+ import { SERVICE_FEE_PERCENTAGE } from "../../definitions";
36
37
 
37
- export const SERVICE_BOOKING_PROCESSING_FEE_PERCENT = 0.15;
38
+ // Use centralized service fee percentage (15% base rate for Basic tier)
39
+ // Note: This is the DEFAULT processing fee. Actual fees may be lower based on membership tier.
40
+ // See definitions.ts for SERVICE_FEE_BASIC, SERVICE_FEE_PRO, etc.
41
+ export const SERVICE_BOOKING_PROCESSING_FEE_PERCENT = SERVICE_FEE_PERCENTAGE;
38
42
 
39
43
  export interface ServiceAddonInput extends ServiceAddon {
40
44
  chosenQuantity?: number;
@@ -1,22 +1,19 @@
1
1
  import { ServiceTypes, MembershipTier } from "@prisma/client";
2
2
 
3
+ // Re-export from definitions.ts for backwards compatibility
4
+ export {
5
+ SERVICE_SUBSCRIPTION_TIERS,
6
+ type UserSubscriptionServiceTierInfo,
7
+ type UserSubscriptionServiceTierInfoMap
8
+ } from "../definitions";
9
+
3
10
  export const ServiceSubscriptionTier = {
4
- Ally: "Ally",
11
+ Free: "Free",
12
+ Ally: "Ally",
5
13
  Partner: "Partner",
6
- Patreon: "Patron",
14
+ Patron: "Patron",
7
15
  } as const;
8
- export type ServiceSubscriptionTier = "Ally" | "Partner" | "Patron";
9
-
10
- export type UserSubscriptionServiceTierInfo = {
11
- name: string;
12
- type?: ServiceSubscriptionTier;
13
- description: string;
14
- price: number;
15
- };
16
-
17
- export type UserSubscriptionServiceTierInfoMap = {
18
- [key in ServiceSubscriptionTier]: UserSubscriptionServiceTierInfo;
19
- };
16
+ export type ServiceSubscriptionTier = "Free" | "Ally" | "Partner" | "Patron";
20
17
 
21
18
  export type UserSubscriptionInfo = {
22
19
  name: string;
@@ -40,6 +37,7 @@ export type UserServiceSubscriptionTierFromServiceTypes = {
40
37
  };
41
38
 
42
39
  export const SERVICE_TIER_TO_SERVICES_LIST = {
40
+ Free: ["EventServices", "EntertainmentServices"],
43
41
  Ally: ["EventServices", "EntertainmentServices"],
44
42
  Partner: ["Vendors", "Exhibitors", "Sponsors"],
45
43
  Patron: ["Venues", "Organizations"],
@@ -48,9 +46,13 @@ export const SERVICE_TIER_TO_SERVICES_LIST = {
48
46
  export const SERVICE_TIER_FROM_SERVICE_TYPE = Object.entries(
49
47
  SERVICE_TIER_TO_SERVICES_LIST
50
48
  ).reduce((sofar, [type, serviceTypes]) => {
51
- serviceTypes.forEach(
52
- (serviceType) => (sofar[serviceType] = type as ServiceSubscriptionTier)
53
- );
49
+ serviceTypes.forEach((serviceType) => {
50
+ // Default to Free tier for EventServices and EntertainmentServices
51
+ // Higher tiers can be chosen by the user
52
+ if (!sofar[serviceType] || type === "Free") {
53
+ sofar[serviceType] = type as ServiceSubscriptionTier;
54
+ }
55
+ });
54
56
  return sofar;
55
57
  }, {} as UserServiceSubscriptionTierFromServiceTypes);
56
58
 
@@ -77,27 +79,7 @@ export const USER_SUBSCRIPTION_TYPES = {
77
79
  // }
78
80
  } as UserSubscriptionServiceInfoMap;
79
81
 
80
- export const SERVICE_SUBSCRIPTION_TIERS = {
81
- Ally: {
82
- name: "Ally",
83
- description: "Ally",
84
- price: 14,
85
- },
86
- Partner: {
87
- name: "Partner",
88
- description: "Partner",
89
- price: 49.0,
90
- },
91
- Patron: {
92
- name: "Patron",
93
- description: "Patron",
94
- price: 99.0,
95
- },
96
- } as UserSubscriptionServiceTierInfoMap;
97
-
82
+ // Set the type field on each tier info object
98
83
  Object.entries(USER_SUBSCRIPTION_TYPES).forEach(
99
84
  ([type, info]) => (info.type = type as MembershipTier)
100
85
  );
101
- Object.entries(SERVICE_SUBSCRIPTION_TIERS).forEach(
102
- ([type, info]) => (info.type = type as ServiceSubscriptionTier)
103
- );
@@ -1,30 +0,0 @@
1
- import { VenuePricingPlan as VenuePricingPlanOption } from "@prisma/client";
2
-
3
- export type VenuePricingPlanData = {
4
- name: string;
5
- description: string;
6
- percentageFee: number;
7
- monthlyFee: number;
8
- flatFee: number;
9
- };
10
-
11
- export type VenuePricingPlanMap = {
12
- [key in VenuePricingPlanOption]: VenuePricingPlanData;
13
- };
14
-
15
- export const VENUE_PRICING_PLAN_DATA: VenuePricingPlanMap = {
16
- [VenuePricingPlanOption.Percentage]: {
17
- name: "Pay per booking",
18
- description: "15% of each booking goes to Bash.",
19
- percentageFee: 0.15,
20
- monthlyFee: 0.0,
21
- flatFee: 0.0,
22
- },
23
- [VenuePricingPlanOption.Subscription]: {
24
- name: "Monthly subscription",
25
- description: "Pay $100/month and keep 100% of each booking.",
26
- percentageFee: 0.0,
27
- monthlyFee: 100.0,
28
- flatFee: 0.0,
29
- },
30
- } as const;