@bash-app/bash-common 30.118.1 → 30.120.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 (39) hide show
  1. package/dist/definitions.d.ts +3 -0
  2. package/dist/definitions.d.ts.map +1 -1
  3. package/dist/definitions.js.map +1 -1
  4. package/dist/index.d.ts +1 -1
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +1 -1
  7. package/dist/index.js.map +1 -1
  8. package/dist/membershipDefinitions.d.ts +9 -5
  9. package/dist/membershipDefinitions.d.ts.map +1 -1
  10. package/dist/membershipDefinitions.js +28 -24
  11. package/dist/membershipDefinitions.js.map +1 -1
  12. package/dist/utils/bashPointsPaymentUtils.d.ts +55 -0
  13. package/dist/utils/bashPointsPaymentUtils.d.ts.map +1 -0
  14. package/dist/utils/bashPointsPaymentUtils.js +79 -0
  15. package/dist/utils/bashPointsPaymentUtils.js.map +1 -0
  16. package/dist/utils/index.d.ts +1 -1
  17. package/dist/utils/index.d.ts.map +1 -1
  18. package/dist/utils/index.js +1 -1
  19. package/dist/utils/index.js.map +1 -1
  20. package/dist/utils/ticketListUtils.d.ts +2 -1
  21. package/dist/utils/ticketListUtils.d.ts.map +1 -1
  22. package/dist/utils/ticketListUtils.js +61 -11
  23. package/dist/utils/ticketListUtils.js.map +1 -1
  24. package/package.json +1 -1
  25. package/prisma/migrations/add_bashcash_pricing_to_ticket_tier.sql +15 -0
  26. package/prisma/migrations/add_bashpoints_purchase_tracking.sql +33 -0
  27. package/prisma/migrations/add_pricing_type_enum.sql +88 -0
  28. package/prisma/migrations/diagnostic_bashcash_columns.sql +157 -0
  29. package/prisma/migrations/fix_bashcash_referral_code_schema_mismatch.sql +81 -0
  30. package/prisma/migrations/rename_bashcash_to_bashpoints.sql +183 -0
  31. package/prisma/migrations/rename_bashcredits_to_bashpoints.sql +96 -0
  32. package/prisma/schema.prisma +64 -48
  33. package/src/definitions.ts +3 -0
  34. package/src/index.ts +1 -1
  35. package/src/membershipDefinitions.ts +29 -25
  36. package/src/utils/bashPointsPaymentUtils.ts +107 -0
  37. package/src/utils/index.ts +1 -1
  38. package/src/utils/ticketListUtils.ts +64 -10
  39. package/src/utils/bashCashPaymentUtils.ts +0 -146
@@ -0,0 +1,107 @@
1
+ /**
2
+ * BashPoints Utilities
3
+ *
4
+ * BashPoints is a loyalty rewards program where:
5
+ * 1. Users EARN BashPoints as cashback on USD purchases (tickets & services)
6
+ * 2. Users SPEND BashPoints ONLY on BashPoints-priced tickets (floating market value set by hosts)
7
+ *
8
+ * BashPoints have NO fixed dollar value - hosts set prices freely (e.g., "500 points for entry")
9
+ * This is a peer-to-peer points exchange system, NOT a stored value currency.
10
+ */
11
+
12
+ /**
13
+ * Format BashPoints for display
14
+ * @param points BashPoints amount
15
+ * @returns Formatted string (e.g., "28,750 points")
16
+ */
17
+ export function formatBashPoints(points: number): string {
18
+ return `${points.toLocaleString('en-US')} point${points === 1 ? '' : 's'}`;
19
+ }
20
+
21
+ /**
22
+ * Calculate BashPoints cashback earned on a USD purchase
23
+ * Uses tiered rates based on membership level (handled by membership tier definitions)
24
+ *
25
+ * @param amountCents Amount paid in USD cents
26
+ * @param cashbackRate Cashback rate (e.g., 0.05 for 5%)
27
+ * @returns BashPoints earned (1 cent = 1 point for earning calculation)
28
+ */
29
+ export function calculateBashPointsCashback(
30
+ amountCents: number,
31
+ cashbackRate: number
32
+ ): number {
33
+ // Award 1 point per cent spent, multiplied by cashback rate
34
+ // Example: $10.00 (1000 cents) at 5% = 50 points
35
+ return Math.floor(amountCents * cashbackRate);
36
+ }
37
+
38
+ // =====================================================================
39
+ // DEPRECATED FUNCTIONS - Service Booking Payments Removed
40
+ // BashPoints can ONLY be spent on BashPoints-priced tickets, not service bookings
41
+ // =====================================================================
42
+
43
+ /**
44
+ * @deprecated BashPoints cannot be used for service bookings
45
+ * Only for BashPoints-priced tickets with floating market value
46
+ */
47
+ export function centsToBashPoints(cents: number): number {
48
+ console.warn('DEPRECATED: centsToBashPoints - BashPoints have no fixed dollar value');
49
+ return cents; // Keep for backward compatibility but log warning
50
+ }
51
+
52
+ /**
53
+ * @deprecated BashPoints cannot be used for service bookings
54
+ * Only for BashPoints-priced tickets with floating market value
55
+ */
56
+ export function bashPointsToCents(credits: number): number {
57
+ console.warn('DEPRECATED: bashPointsToCents - BashPoints have no fixed dollar value');
58
+ return credits; // Keep for backward compatibility but log warning
59
+ }
60
+
61
+ /**
62
+ * @deprecated BashPoints cannot be used for service bookings
63
+ */
64
+ export function calculateMaxBashPointsForBooking(
65
+ totalCents: number,
66
+ userBalance: number
67
+ ): number {
68
+ console.warn('DEPRECATED: calculateMaxBashPointsForBooking - BashPoints not supported for service bookings');
69
+ return 0;
70
+ }
71
+
72
+ /**
73
+ * @deprecated BashPoints cannot be used for service bookings
74
+ */
75
+ export function calculateSplitPayment(
76
+ totalCents: number,
77
+ bashPointsToUse: number
78
+ ): {
79
+ bashPointsCents: number;
80
+ stripeCents: number;
81
+ bashPointsCredits: number;
82
+ } {
83
+ console.warn('DEPRECATED: calculateSplitPayment - BashPoints not supported for service bookings');
84
+ return {
85
+ bashPointsCents: 0,
86
+ stripeCents: totalCents,
87
+ bashPointsCredits: 0,
88
+ };
89
+ }
90
+
91
+ /**
92
+ * @deprecated BashPoints cannot be used for service bookings
93
+ */
94
+ export function validateBashPointsPayment(
95
+ bashPointsToUse: number,
96
+ userBalance: number,
97
+ totalCents: number
98
+ ): {
99
+ valid: boolean;
100
+ errorMessage?: string;
101
+ } {
102
+ return {
103
+ valid: false,
104
+ errorMessage: "BashPoints can only be used for BashPoints-priced tickets, not service bookings. Please pay with a credit card.",
105
+ };
106
+ }
107
+
@@ -3,7 +3,7 @@ export * from './apiUtils';
3
3
  export * from './arrayUtils';
4
4
  export * from './awsS3Utils';
5
5
  export * from './badgeUtils';
6
- export * from './bashCashPaymentUtils';
6
+ export * from './bashPointsPaymentUtils';
7
7
  export * from './blog/blogDbUtils';
8
8
  export * from './blogUtils';
9
9
  export * from './contentFilterUtils';
@@ -13,8 +13,50 @@ import {
13
13
  LUXON_DATETIME_FORMAT_ISO_LIKE,
14
14
  } from "./luxonUtils";
15
15
 
16
+ /**
17
+ * Encodes a string to Base64 URL-safe format
18
+ * Replaces + with -, / with _, and removes = padding
19
+ */
20
+ function encodeBase64UrlSafe(str: string): string {
21
+ if (typeof window !== "undefined") {
22
+ // Browser environment
23
+ return btoa(str)
24
+ .replace(/\+/g, "-")
25
+ .replace(/\//g, "_")
26
+ .replace(/=/g, "");
27
+ } else {
28
+ // Node environment
29
+ return Buffer.from(str)
30
+ .toString("base64")
31
+ .replace(/\+/g, "-")
32
+ .replace(/\//g, "_")
33
+ .replace(/=/g, "");
34
+ }
35
+ }
36
+
37
+ /**
38
+ * Decodes a Base64 URL-safe string
39
+ * Replaces - with +, _ with /, and adds back = padding
40
+ */
41
+ function decodeBase64UrlSafe(str: string): string {
42
+ // Add back padding
43
+ let base64 = str.replace(/-/g, "+").replace(/_/g, "/");
44
+ while (base64.length % 4) {
45
+ base64 += "=";
46
+ }
47
+
48
+ if (typeof window !== "undefined") {
49
+ // Browser environment
50
+ return atob(base64);
51
+ } else {
52
+ // Node environment
53
+ return Buffer.from(base64, "base64").toString();
54
+ }
55
+ }
56
+
16
57
  /**
17
58
  * Returns A string structured like: [ticketTierId]__[numberOfTickets];;[date]~~[numberOfTickets];;[date]~~,...
59
+ * The returned string is Base64 URL-safe encoded to prevent routing issues
18
60
  * @param ticketList A map where the key is the ticketTierId
19
61
  */
20
62
  export function ticketListToString(
@@ -23,51 +65,63 @@ export function ticketListToString(
23
65
  const ticketListArr: string[] = [];
24
66
 
25
67
  for (const [ticketTierId, ticketListArgs] of ticketList.entries()) {
26
- let ticketsExist = true;
27
68
  const ticketArgs: string[] = [
28
69
  `${ticketTierId}${URL_PARAMS_TICKET_TIER_ID_NUMBER_OF_TICKETS_DATE_DELIM}`,
29
70
  ];
71
+ let hasAnyTickets = false; // Track if we added ANY valid tickets for this tier
72
+
30
73
  for (const ticketNumAndDates of ticketListArgs) {
31
74
  if (ticketNumAndDates.numberOfTickets > 0) {
32
- ticketsExist = true;
75
+ hasAnyTickets = true;
33
76
 
34
- // Ensure ticketDateTime is in ISO format
77
+ // Ensure ticketDateTime is in ISO format (URL-safe)
35
78
  let dateTimeStr = ticketNumAndDates.ticketDateTime;
36
79
  if (dateTimeStr) {
37
80
  // If it's already a string, try to parse it as DateTime and convert to ISO
38
81
  const dateTime = dateTimeFromDate(dateTimeStr);
39
82
  if (dateTime.isValid) {
40
- dateTimeStr = dateTimeFormat(dateTime) || dateTimeStr;
83
+ dateTimeStr = dateTime.toISO() || dateTimeStr;
41
84
  }
42
85
  }
43
86
 
44
87
  ticketArgs.push(
45
88
  `${ticketNumAndDates.numberOfTickets}${URL_PARAMS_TICKETS_DATE_DELIM}${dateTimeStr}`
46
89
  );
47
- } else {
48
- ticketsExist = false;
49
90
  }
50
91
  }
51
- if (ticketsExist) {
92
+
93
+ // Only include this tier if we found at least one ticket > 0
94
+ if (hasAnyTickets) {
52
95
  ticketListArr.push(
53
96
  ticketArgs.join(URL_PARAMS_NUMBER_OF_TICKETS_TICKETS_DATE_DELIM)
54
97
  );
55
98
  }
56
99
  }
57
- return ticketListArr.join(URL_PARAMS_TICKET_LIST_DELIM);
100
+ const plainString = ticketListArr.join(URL_PARAMS_TICKET_LIST_DELIM);
101
+ return encodeBase64UrlSafe(plainString);
58
102
  }
59
103
 
60
104
  /**
61
105
  * Returns map where the key is the ticketTierId
62
- * @param ticketListStr A string structured like: [ticketTierId]__[numberOfTickets];;[date]~~[numberOfTickets];;[date]~~...,...
106
+ * @param ticketListStr A Base64 URL-safe encoded string that decodes to: [ticketTierId]__[numberOfTickets];;[date]~~[numberOfTickets];;[date]~~...,...
63
107
  */
64
108
  export function ticketListStrToTicketList(
65
109
  ticketListStr: string
66
110
  ): Map<string, NumberOfTicketsForDate[]> {
67
111
  const ticketList: Map<string, NumberOfTicketsForDate[]> = new Map();
68
112
 
113
+ // Decode the Base64 URL-safe string first
114
+ let decodedStr: string;
115
+ try {
116
+ decodedStr = decodeBase64UrlSafe(ticketListStr);
117
+ } catch (error) {
118
+ console.error("Failed to decode ticketListStr:", error);
119
+ // If decoding fails, try using the string as-is (for backward compatibility)
120
+ decodedStr = ticketListStr;
121
+ }
122
+
69
123
  // [ticketTierId]__~~[numberOfTickets];;[date]~~[numberOfTickets];;[date]~~...,...
70
- const ticketListArgs = ticketListStr.split(URL_PARAMS_TICKET_LIST_DELIM);
124
+ const ticketListArgs = decodedStr.split(URL_PARAMS_TICKET_LIST_DELIM);
71
125
 
72
126
  ticketListArgs.forEach((tierIdAndTicketNumbersAndDates: string): void => {
73
127
  const ticketNumAndDatesArr: NumberOfTicketsForDate[] = [];
@@ -1,146 +0,0 @@
1
- /**
2
- * BashCash Payment Utilities
3
- * Handles calculations and conversions for BashCash payment system
4
- */
5
-
6
- // 1 BashCash credit = 1 cent = $0.01
7
- export const BASHCASH_TO_CENTS_RATE = 1;
8
- export const CENTS_TO_BASHCASH_RATE = 1;
9
-
10
- /**
11
- * Convert USD cents to BashCash credits
12
- * @param cents Amount in cents (e.g., 28750 = $287.50)
13
- * @returns BashCash credits (e.g., 28750 credits)
14
- */
15
- export function centsToBashCash(cents: number): number {
16
- return Math.floor(cents * CENTS_TO_BASHCASH_RATE);
17
- }
18
-
19
- /**
20
- * Convert BashCash credits to USD cents
21
- * @param credits BashCash credits (e.g., 28750 credits)
22
- * @returns Amount in cents (e.g., 28750 = $287.50)
23
- */
24
- export function bashCashToCents(credits: number): number {
25
- return Math.floor(credits * BASHCASH_TO_CENTS_RATE);
26
- }
27
-
28
- /**
29
- * Format BashCash credits for display
30
- * @param credits BashCash credits
31
- * @returns Formatted string (e.g., "28,750 credits")
32
- */
33
- export function formatBashCash(credits: number): string {
34
- return `${credits.toLocaleString('en-US')} credit${credits === 1 ? '' : 's'}`;
35
- }
36
-
37
- /**
38
- * Format BashCash credits with USD equivalent
39
- * @param credits BashCash credits
40
- * @returns Formatted string (e.g., "28,750 credits ($287.50)")
41
- */
42
- export function formatBashCashWithUSD(credits: number): string {
43
- const cents = bashCashToCents(credits);
44
- const dollars = (cents / 100).toFixed(2);
45
- return `${formatBashCash(credits)} ($${dollars})`;
46
- }
47
-
48
- /**
49
- * Calculate maximum BashCash that can be used for a booking
50
- * @param totalCents Total booking cost in cents
51
- * @param userBalance User's BashCash balance in credits
52
- * @returns Maximum BashCash credits that can be applied
53
- */
54
- export function calculateMaxBashCashForBooking(
55
- totalCents: number,
56
- userBalance: number
57
- ): number {
58
- // No cap on BashCash usage for service bookings (can pay 100% if they have enough)
59
- const maxPossible = centsToBashCash(totalCents);
60
- return Math.min(maxPossible, userBalance);
61
- }
62
-
63
- /**
64
- * Calculate split payment amounts
65
- * @param totalCents Total booking cost in cents
66
- * @param bashCashToUse BashCash credits user wants to apply
67
- * @returns Object with bashCashCents and stripeCents
68
- */
69
- export function calculateSplitPayment(
70
- totalCents: number,
71
- bashCashToUse: number
72
- ): {
73
- bashCashCents: number;
74
- stripeCents: number;
75
- bashCashCredits: number;
76
- } {
77
- const bashCashCents = bashCashToCents(bashCashToUse);
78
- const stripeCents = Math.max(0, totalCents - bashCashCents);
79
-
80
- return {
81
- bashCashCents,
82
- stripeCents,
83
- bashCashCredits: bashCashToUse,
84
- };
85
- }
86
-
87
- /**
88
- * Validate BashCash payment
89
- * @param bashCashToUse BashCash credits to use
90
- * @param userBalance User's current balance
91
- * @param totalCents Total booking cost
92
- * @returns Validation result
93
- */
94
- export function validateBashCashPayment(
95
- bashCashToUse: number,
96
- userBalance: number,
97
- totalCents: number
98
- ): {
99
- valid: boolean;
100
- errorMessage?: string;
101
- } {
102
- if (bashCashToUse < 0) {
103
- return {
104
- valid: false,
105
- errorMessage: "BashCash amount cannot be negative",
106
- };
107
- }
108
-
109
- if (bashCashToUse > userBalance) {
110
- return {
111
- valid: false,
112
- errorMessage: `Insufficient BashCash balance. You have ${formatBashCash(userBalance)}, but tried to use ${formatBashCash(bashCashToUse)}.`,
113
- };
114
- }
115
-
116
- const bashCashCents = bashCashToCents(bashCashToUse);
117
- if (bashCashCents > totalCents) {
118
- return {
119
- valid: false,
120
- errorMessage: `BashCash amount ($${(bashCashCents / 100).toFixed(2)}) exceeds booking total ($${(totalCents / 100).toFixed(2)}).`,
121
- };
122
- }
123
-
124
- return { valid: true };
125
- }
126
-
127
- /**
128
- * Calculate BashCash cashback for a service booking (3%)
129
- * @param amountCents Amount paid in cents
130
- * @returns BashCash credits earned as cashback
131
- */
132
- export function calculateServiceBookingCashback(amountCents: number): number {
133
- const CASHBACK_RATE = 0.03; // 3% for service bookings
134
- return Math.floor((amountCents * CASHBACK_RATE));
135
- }
136
-
137
- /**
138
- * Calculate BashCash cashback for a ticket purchase (5%)
139
- * @param amountCents Amount paid in cents
140
- * @returns BashCash credits earned as cashback
141
- */
142
- export function calculateTicketCashback(amountCents: number): number {
143
- const CASHBACK_RATE = 0.05; // 5% for ticket purchases
144
- return Math.floor((amountCents * CASHBACK_RATE));
145
- }
146
-