@bash-app/bash-common 30.118.0 → 30.119.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 +432 -317
  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
@@ -354,6 +354,7 @@ export type FilterFields = {
354
354
  specialOffers: string[];
355
355
  eventFormat: string[];
356
356
  hasOpenTasks: boolean; // Boolean filter for events with open volunteer tasks
357
+ acceptsBashPoints: boolean; // Boolean filter for events with BashPoints-priced tickets
357
358
  };
358
359
 
359
360
  export type ApiEntityApproval = {
@@ -362,6 +363,8 @@ export type ApiEntityApproval = {
362
363
 
363
364
  export type TicketTierWherePriceIsAString = Omit<TicketTier, "price"> & {
364
365
  price: string;
366
+ pricingType?: string; // 'USD' or 'BASHCASH'
367
+ priceBashPoints?: string; // Price in BashPoints credits (string for form input)
365
368
  } & { cannotDelete: boolean };
366
369
 
367
370
  export type ApiServiceAddonParams = {
package/src/index.ts CHANGED
@@ -9,7 +9,7 @@ export * from "./utils/addressUtils";
9
9
  export * from "./utils/apiUtils";
10
10
  export * from "./utils/arrayUtils";
11
11
  export * from "./utils/awsS3Utils";
12
- export * from "./utils/bashCashPaymentUtils";
12
+ export * from "./utils/bashPointsPaymentUtils";
13
13
  export * from "./utils/contentFilterUtils";
14
14
  export * from "./utils/dateTimeUtils";
15
15
  export * from "./utils/discountEngine/bestPriceResolver";
@@ -90,7 +90,7 @@ export const MEMBERSHIP_PRICING = {
90
90
  Legend: { monthly: 99900, yearly: 1000000 }, // $999/month, $10,000/year
91
91
  };
92
92
 
93
- // Helper: Get monthly price in cents for a tier (for BashCash calculations)
93
+ // Helper: Get monthly price in cents for a tier (for BashPoints calculations)
94
94
  export const MEMBERSHIP_MONTHLY_PRICE_CENTS: Record<MembershipTier, number> = {
95
95
  Basic: MEMBERSHIP_PRICING.Basic.monthly,
96
96
  Creator: MEMBERSHIP_PRICING.Creator.monthly,
@@ -104,59 +104,63 @@ export const MEMBERSHIP_TIER_HIERARCHY: MembershipTier[] = [
104
104
  ];
105
105
 
106
106
  // ============================================================================
107
- // BASHCASH REWARDS SYSTEM
107
+ // BASHPOINTS REWARDS SYSTEM
108
108
  // ============================================================================
109
109
 
110
110
  /**
111
- * BashCash rewards per membership tier
112
- * All amounts in CENTS (1 credit = 1 cent = $0.01)
111
+ * BashPoints rewards per membership tier
112
+ * Points are loyalty rewards with floating market value (like airline miles)
113
113
  */
114
- export const BASHCASH_REWARDS: Record<MembershipTier, {
115
- monthlyCredits: number; // Credits earned per month
114
+ export const BASHPOINTS_REWARDS: Record<MembershipTier, {
115
+ monthlyCredits: number; // Points earned per month
116
116
  ticketCashbackRate: number; // Cashback % on ticket purchases
117
117
  serviceCashbackRate: number; // Cashback % on service bookings
118
118
  }> = {
119
119
  Basic: {
120
120
  monthlyCredits: 0,
121
- ticketCashbackRate: 0,
122
- serviceCashbackRate: 0,
121
+ ticketCashbackRate: 0.01, // 1% cashback
122
+ serviceCashbackRate: 0.01, // 1% cashback
123
123
  },
124
124
  Creator: {
125
- monthlyCredits: 10000, // 10,000 credits = $100/month
126
- ticketCashbackRate: 0.05, // 5% cashback
127
- serviceCashbackRate: 0.03, // 3% cashback
125
+ monthlyCredits: 10000, // 10,000 BashPoints/month
126
+ ticketCashbackRate: 0.03, // 3% cashback
127
+ serviceCashbackRate: 0.02, // 2% cashback
128
128
  },
129
129
  Pro: {
130
- monthlyCredits: 40000, // 40,000 credits = $400/month
130
+ monthlyCredits: 40000, // 40,000 BashPoints/month
131
131
  ticketCashbackRate: 0.05, // 5% cashback
132
132
  serviceCashbackRate: 0.03, // 3% cashback
133
133
  },
134
134
  Elite: {
135
- monthlyCredits: 120000, // 120,000 credits = $1,200/month
136
- ticketCashbackRate: 0.05, // 5% cashback
137
- serviceCashbackRate: 0.03, // 3% cashback
135
+ monthlyCredits: 120000, // 120,000 BashPoints/month
136
+ ticketCashbackRate: 0.07, // 7% cashback
137
+ serviceCashbackRate: 0.04, // 4% cashback
138
138
  },
139
139
  Legend: {
140
- monthlyCredits: 250000, // 250,000 credits = $2,500/month
141
- ticketCashbackRate: 0.05, // 5% cashback
142
- serviceCashbackRate: 0.03, // 3% cashback
140
+ monthlyCredits: 250000, // 250,000 BashPoints/month
141
+ ticketCashbackRate: 0.10, // 10% cashback
142
+ serviceCashbackRate: 0.05, // 5% cashback
143
143
  },
144
144
  } as const;
145
145
 
146
146
  /**
147
- * BashCash system rules and limits
147
+ * BashPoints system rules and limits
148
+ *
149
+ * IMPORTANT: BashPoints is a LOYALTY POINTS SYSTEM with floating market value.
150
+ * Credits do NOT have a fixed dollar conversion rate.
151
+ * Hosts/providers set their own BashPoints prices for tickets and services.
148
152
  */
149
- export const BASHCASH_CONFIG = {
153
+ export const BASHPOINTS_CONFIG = {
150
154
  // Referral bonuses
151
- referralBonusRate: 0.10, // 10% of referee's first purchase
152
- maxReferralCredits: 10000, // $100 cap on referral bonuses
155
+ referralBonusRate: 0.10, // 10% of referee's first USD purchase (in credits)
156
+ maxReferralCredits: 10000, // 10,000 credit cap on referral bonuses
153
157
 
154
158
  // Credit lifecycle
155
159
  creditExpirationMonths: 12, // Credits expire after 12 months
156
160
 
157
- // Redemption rules
158
- minimumRedemption: 100, // $1 minimum redemption (100 credits)
159
- membershipRedemptionCap: 0.50, // 50% max BashCash for membership fees
161
+ // Redemption rules (deprecated for floating value system)
162
+ minimumRedemption: 100, // Legacy: was used for fixed-value redemptions
163
+ membershipRedemptionCap: 0.50, // NOT USED: Can't pay memberships with BashPoints (no fixed value)
160
164
  } as const;
161
165
 
162
166
  // ============================================================================
@@ -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
-