@bash-app/bash-common 30.142.0 → 30.146.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.
@@ -2,7 +2,7 @@
2
2
  * Tests for payment utility functions
3
3
  * Testing business logic without database dependencies
4
4
  */
5
- import { calculateDiscountFromPromoCode, convertCentsToDollars, convertDollarsToCents, calculateBashAppFee, calculateBashAppFeeWithMembershipDiscount, } from "../paymentUtils";
5
+ import { calculateDiscountFromPromoCode, convertCentsToDollars, convertDollarsToCents, calculateBashAppFee, calculateBashAppFeeWithMembershipDiscount, calculateTotalPriceWithoutTax, calculateTotalBashPoints, calculateStripeDonationFee, calculateServiceFeeWithMembershipDiscount, } from "../paymentUtils";
6
6
  describe("PaymentUtils - Core Functions", () => {
7
7
  describe("Currency Conversion", () => {
8
8
  test("convertCentsToDollars", () => {
@@ -73,5 +73,74 @@ describe("PaymentUtils - Core Functions", () => {
73
73
  expect(fee).toBe(1000); // cap at $10
74
74
  });
75
75
  });
76
+ describe("Ticket total price (USD)", () => {
77
+ test("calculateTotalPriceWithoutTax sums USD tiers only", () => {
78
+ const tiers = [
79
+ { id: "t1", price: 1000, pricingType: "USD" },
80
+ { id: "t2", price: 500, pricingType: "USD" },
81
+ ];
82
+ const ticketList = new Map([
83
+ ["t1", [{ numberOfTickets: 2, ticketDateTime: new Date() }]],
84
+ ["t2", [{ numberOfTickets: 1, ticketDateTime: new Date() }]],
85
+ ]);
86
+ expect(calculateTotalPriceWithoutTax(tiers, ticketList)).toBe(2500); // 2*1000 + 1*500
87
+ });
88
+ test("calculateTotalPriceWithoutTax excludes BASHPOINTS tiers", () => {
89
+ const tiers = [
90
+ { id: "t1", price: 1000, pricingType: "USD" },
91
+ { id: "t2", price: 200, pricingType: "BASHPOINTS", priceBashPoints: 50 },
92
+ ];
93
+ const ticketList = new Map([
94
+ ["t1", [{ numberOfTickets: 1, ticketDateTime: new Date() }]],
95
+ ["t2", [{ numberOfTickets: 3, ticketDateTime: new Date() }]],
96
+ ]);
97
+ expect(calculateTotalPriceWithoutTax(tiers, ticketList)).toBe(1000);
98
+ });
99
+ test("calculateTotalPriceWithoutTax returns 0 for empty list", () => {
100
+ expect(calculateTotalPriceWithoutTax([], new Map())).toBe(0);
101
+ });
102
+ });
103
+ describe("Ticket total BashPoints", () => {
104
+ test("calculateTotalBashPoints sums BASHPOINTS tiers only", () => {
105
+ const tiers = [
106
+ { id: "t1", price: 1000, pricingType: "USD" },
107
+ { id: "t2", price: 0, pricingType: "BASHPOINTS", priceBashPoints: 100 },
108
+ ];
109
+ const ticketList = new Map([
110
+ ["t1", [{ numberOfTickets: 1, ticketDateTime: new Date() }]],
111
+ ["t2", [{ numberOfTickets: 2, ticketDateTime: new Date() }]],
112
+ ]);
113
+ expect(calculateTotalBashPoints(tiers, ticketList)).toBe(200);
114
+ });
115
+ test("calculateTotalBashPoints returns 0 when no BASHPOINTS tiers", () => {
116
+ const tiers = [{ id: "t1", price: 1000, pricingType: "USD" }];
117
+ const ticketList = new Map([["t1", [{ numberOfTickets: 1, ticketDateTime: new Date() }]]]);
118
+ expect(calculateTotalBashPoints(tiers, ticketList)).toBe(0);
119
+ });
120
+ });
121
+ describe("Stripe donation fee", () => {
122
+ test("calculateStripeDonationFee applies 2.9% + 30 cents", () => {
123
+ // 10000 cents = $100 -> 2.9% = 290, + 30 = 320
124
+ expect(calculateStripeDonationFee(10000)).toBe(320);
125
+ });
126
+ test("calculateStripeDonationFee for small amount", () => {
127
+ expect(calculateStripeDonationFee(100)).toBeGreaterThanOrEqual(30);
128
+ });
129
+ });
130
+ describe("Service fee with membership discount", () => {
131
+ test("calculateServiceFeeWithMembershipDiscount Basic tier", () => {
132
+ const fee = calculateServiceFeeWithMembershipDiscount(10000, "Basic");
133
+ expect(fee).toBeGreaterThan(0);
134
+ expect(typeof fee).toBe("number");
135
+ });
136
+ test("calculateServiceFeeWithMembershipDiscount Premium tier", () => {
137
+ const fee = calculateServiceFeeWithMembershipDiscount(10000, "Premium");
138
+ expect(fee).toBeGreaterThanOrEqual(0);
139
+ });
140
+ test("calculateServiceFeeWithMembershipDiscount defaults to Basic when null", () => {
141
+ const fee = calculateServiceFeeWithMembershipDiscount(10000, null);
142
+ expect(typeof fee).toBe("number");
143
+ });
144
+ });
76
145
  });
77
146
  //# sourceMappingURL=paymentUtils.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"paymentUtils.test.js","sourceRoot":"","sources":["../../../src/utils/__tests__/paymentUtils.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"paymentUtils.test.js","sourceRoot":"","sources":["../../../src/utils/__tests__/paymentUtils.test.ts"],"names":[],"mappings":"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"}
@@ -10,7 +10,7 @@ export function getUserName(contactOrUser) {
10
10
  }
11
11
  const user = contactOrUser;
12
12
  const combinedName = user.givenName && user.familyName ? `${user.givenName} ${user.familyName}` : null;
13
- return combinedName ?? user.email;
13
+ return combinedName ?? user.email ?? '';
14
14
  }
15
15
  export function getUserImage(contactOrUser) {
16
16
  if (!contactOrUser) {
@@ -1 +1 @@
1
- {"version":3,"file":"apiUtils.js","sourceRoot":"","sources":["../../src/utils/apiUtils.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"apiUtils.js","sourceRoot":"","sources":["../../src/utils/apiUtils.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"blogDbUtils.d.ts","sourceRoot":"","sources":["../../../src/utils/blog/blogDbUtils.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"blogDbUtils.d.ts","sourceRoot":"","sources":["../../../src/utils/blog/blogDbUtils.ts"],"names":[],"mappings":"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"}
@@ -96,6 +96,10 @@ export async function searchBlogPosts(prisma, params) {
96
96
  const where = {
97
97
  status,
98
98
  };
99
+ // When listing Published posts, only include posts with a set publishedAt so the list is consistent (null dates sort last and can hide new posts)
100
+ if (status === BlogStatus.Published) {
101
+ where.publishedAt = { not: null };
102
+ }
99
103
  if (query) {
100
104
  where.OR = [
101
105
  { title: { contains: query, mode: 'insensitive' } },
@@ -1 +1 @@
1
- {"version":3,"file":"blogDbUtils.js","sourceRoot":"","sources":["../../../src/utils/blog/blogDbUtils.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"blogDbUtils.js","sourceRoot":"","sources":["../../../src/utils/blog/blogDbUtils.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bash-app/bash-common",
3
- "version": "30.142.0",
3
+ "version": "30.146.0",
4
4
  "description": "Common data and scripts to use on the frontend and backend",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -10,6 +10,7 @@
10
10
  "generate": "prisma generate",
11
11
  "db": "prisma generate && prisma db push",
12
12
  "tsc": "tsc",
13
+ "block-malicious": "../scripts/block-malicious-patterns.sh .",
13
14
  "prepublishOnly": "npm run build"
14
15
  },
15
16
  "repository": {
@@ -19,14 +20,13 @@
19
20
  "author": "Frank Nielson and Steve Goodrick",
20
21
  "license": "ISC",
21
22
  "dependencies": {
22
- "@aws-sdk/client-s3": "^3.529.0",
23
- "@aws-sdk/client-textract": "^3.529.0",
24
- "@aws-sdk/s3-request-presigner": "^3.529.0",
25
- "@testing-library/jest-dom": "^6.6.3",
23
+ "@aws-sdk/client-s3": "^3.1004.0",
24
+ "@aws-sdk/client-textract": "^3.1004.0",
25
+ "@aws-sdk/s3-request-presigner": "^3.1004.0",
26
26
  "@types/qrcode": "^1.5.5",
27
27
  "lodash-es": "^4.17.21",
28
- "mixpanel-browser": "^2.65.0",
29
- "npm": "^11.7.0",
28
+ "mixpanel-browser": "^2.75.0",
29
+ "npm": "^11.11.0",
30
30
  "qrcode": "^1.5.3",
31
31
  "slugify": "^1.6.6"
32
32
  },
@@ -39,6 +39,7 @@
39
39
  },
40
40
  "devDependencies": {
41
41
  "@playwright/test": "^1.54.2",
42
+ "@testing-library/jest-dom": "^6.9.1",
42
43
  "@types/jest": "^29.5.5",
43
44
  "@types/luxon": "^3.4.2",
44
45
  "@types/mixpanel-browser": "^2.60.0",
@@ -50,7 +50,7 @@ model BashComment {
50
50
  creator User @relation(fields: [creatorId], references: [id], onDelete: Cascade)
51
51
  parentComment BashComment? @relation("CommentReplies", fields: [parentCommentId], references: [id], onDelete: Cascade)
52
52
  replies BashComment[] @relation("CommentReplies")
53
- review Review? @relation(fields: [reviewId], references: [id])
53
+ review Review? @relation(fields: [reviewId], references: [id], onDelete: SetNull)
54
54
  }
55
55
 
56
56
  // BashFeed Models - Event-Centric Social Discovery Feed
@@ -555,6 +555,7 @@ model Invitation {
555
555
  model BashEvent {
556
556
  id String @id @default(cuid())
557
557
  source BashEventSource @default(Bash)
558
+ sourcePartnerId String? // When source=Partner, e.g. 'jamwith', 'mixlog'
558
559
  title String
559
560
  slug String? @unique
560
561
  creatorId String
@@ -826,8 +827,7 @@ model BashCreditTransaction {
826
827
  status CreditTransactionStatus @default(Pending)
827
828
 
828
829
  // Source Tracking (Legacy fields - keeping for backwards compatibility)
829
- transactionType CreditTransactionType // Duplicate of 'type' for legacy compatibility
830
- source String // Legacy source field`
830
+ source String // Legacy source field
831
831
  referralCode String?
832
832
  referredUserId String?
833
833
  referredUser User? @relation("ReferredUser", fields: [referredUserId], references: [id])
@@ -862,7 +862,6 @@ model BashCreditTransaction {
862
862
  @@index([userId, taxYear])
863
863
  @@index([userId])
864
864
  @@index([referralCode])
865
- @@index([transactionType])
866
865
  @@index([createdAt])
867
866
  @@index([sourceType])
868
867
  @@index([type])
@@ -1161,6 +1160,7 @@ model BashEventTemplate {
1161
1160
  @@index([isActive, isFeatured])
1162
1161
  }
1163
1162
 
1163
+ // Used by BashEvent (amountOfGuests) and by Services (crowdSizeId/crowdSize); same model, different relation names.
1164
1164
  model AmountOfGuests {
1165
1165
  id String @id @default(cuid())
1166
1166
  minimum Int? @default(10)
@@ -1374,6 +1374,7 @@ model User {
1374
1374
  isSuperUser Boolean @default(false)
1375
1375
  isSuspended Boolean @default(false)
1376
1376
  intent UserIntent?
1377
+ signupSource String? // e.g. 'jamwith', 'mixlog', 'organic' for attribution
1377
1378
  googleCalendarAccess String?
1378
1379
 
1379
1380
  // Google OAuth tokens for API access (Contacts, Calendar, etc.)
@@ -1391,6 +1392,15 @@ model User {
1391
1392
  uploadedImage String?
1392
1393
  uploadedImageUpdatedAt DateTime? // When manually uploaded image was last updated
1393
1394
  dob DateTime?
1395
+ showBirthdayOnProfile Boolean @default(false) // If true, show month/day on public profile
1396
+ // Part B: Birthday Rewards full product
1397
+ birthdayRewardsOptIn Boolean @default(false)
1398
+ birthdayRewardsOptInAt DateTime?
1399
+ birthdayLocationId String? // FK UserLocation (birthday home base)
1400
+ birthdayMaxDistanceMiles Int @default(25)
1401
+ birthdayNoPurchaseOnly Boolean @default(false)
1402
+ birthdayCategories String[] @default([]) // e.g. restaurant, coffee, dessert
1403
+ idDocumentUrl String? // Optional: secure ID upload for verification
1394
1404
  gender Gender?
1395
1405
  sex Sex?
1396
1406
  organization String?
@@ -1478,6 +1488,17 @@ model User {
1478
1488
  auditLogs AuditLog[] @relation("UserAuditLogs")
1479
1489
  auditLogsPerformed AuditLog[] @relation("PerformedByUser")
1480
1490
  consents UserConsent[]
1491
+ birthdayOfferOptIns UserBirthdayOfferOptIn[]
1492
+ birthdayOfferDeliveries BirthdayOfferDelivery[]
1493
+ birthdayBoostGrants BirthdayBoostGrant[]
1494
+ birthdayRewardRedemptions BirthdayRewardRedemption[]
1495
+ birthdayDealSuggestions BirthdayDealSuggestion[]
1496
+ rewardReports RewardReport[]
1497
+ rewardReportsReviewed RewardReport[] @relation("RewardReportReviewedBy")
1498
+ userLocations UserLocation[]
1499
+ birthdayLocation UserLocation? @relation("UserBirthdayLocation", fields: [birthdayLocationId], references: [id], onDelete: SetNull)
1500
+ offerClaims OfferClaim[]
1501
+ birthdayPlans BirthdayPlan[]
1481
1502
 
1482
1503
  associatedBashes AssociatedBash[]
1483
1504
  associatedServices AssociatedService[]
@@ -2610,6 +2631,7 @@ model EventRSVP {
2610
2631
  @@index([userId])
2611
2632
  }
2612
2633
 
2634
+ // Event-scoped budgets (bashEventId) are created/edited in the bash creation wizard "Budget" step.
2613
2635
  model Budget {
2614
2636
  id String @id @default(cuid())
2615
2637
  name String
@@ -3610,6 +3632,8 @@ enum BashEventSource {
3610
3632
  LinkedIn
3611
3633
  Meetup
3612
3634
  Facebook
3635
+ JamWith
3636
+ Partner // Generic: use sourcePartnerId for partner key (e.g. 'mixlog', custom integrations)
3613
3637
  }
3614
3638
 
3615
3639
  enum TicketStatus {
@@ -5516,6 +5540,7 @@ enum CreditSourceType {
5516
5540
  FirstFavoriteBash // First bash added to favorites
5517
5541
  FirstShareBash // First time sharing a bash event
5518
5542
  FirstInviteToBash // First invite to someone else's bash
5543
+ BirthdayReward // Annual BashPoints boost on user's birthday
5519
5544
  }
5520
5545
 
5521
5546
  enum PendingGiftStatus {
@@ -5577,6 +5602,378 @@ enum ConsentType {
5577
5602
  Analytics // Optional: Google Analytics, Mixpanel, etc.
5578
5603
  Marketing // Optional: Promotional emails
5579
5604
  ThirdPartySharing // Optional: Share data with partners
5605
+ BirthdayOffers // Optional: Receive birthday offers from partner companies
5606
+ }
5607
+
5608
+ // Birthday offers from partner companies: users opt in once, we send minimal PII to partner APIs
5609
+ model BirthdayOfferPartner {
5610
+ id String @id @default(cuid())
5611
+ name String
5612
+ slug String @unique
5613
+ description String? @db.Text
5614
+ apiEndpoint String // Partner API URL; API keys live in env (BIRTHDAY_PARTNER_<SLUG>_API_KEY)
5615
+ config Json? // Partner-specific: e.g. sendFullDob (bool), extra fields
5616
+ requiresPhone Boolean @default(false) // Part B: when true, share User.phone with partner
5617
+ isActive Boolean @default(true)
5618
+ createdAt DateTime @default(now())
5619
+ updatedAt DateTime @updatedAt
5620
+ optIns UserBirthdayOfferOptIn[]
5621
+ deliveries BirthdayOfferDelivery[]
5622
+ catalogEntries BirthdayFreebieCatalog[]
5623
+
5624
+ @@index([isActive])
5625
+ }
5626
+
5627
+ model UserBirthdayOfferOptIn {
5628
+ id String @id @default(cuid())
5629
+ userId String
5630
+ partnerId String
5631
+ optedInAt DateTime @default(now())
5632
+ lastSentAt DateTime? // Last time we sent this user to this partner (for idempotency)
5633
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
5634
+ partner BirthdayOfferPartner @relation(fields: [partnerId], references: [id], onDelete: Cascade)
5635
+
5636
+ @@unique([userId, partnerId])
5637
+ @@index([partnerId])
5638
+ @@index([userId])
5639
+ }
5640
+
5641
+ model BirthdayOfferDelivery {
5642
+ id String @id @default(cuid())
5643
+ userId String
5644
+ partnerId String
5645
+ birthdayYear Int // Year when the send counted (for idempotency: one send per user/partner/year)
5646
+ sentAt DateTime @default(now())
5647
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
5648
+ partner BirthdayOfferPartner @relation(fields: [partnerId], references: [id], onDelete: Cascade)
5649
+
5650
+ @@unique([userId, partnerId, birthdayYear])
5651
+ @@index([partnerId])
5652
+ @@index([userId])
5653
+ }
5654
+
5655
+ // Birthday Rewards focused scope (v1): annual BashPoints boost idempotency
5656
+ model BirthdayBoostGrant {
5657
+ id String @id @default(cuid())
5658
+ userId String
5659
+ birthdayYear Int // Year for which boost was granted
5660
+ grantedAt DateTime @default(now())
5661
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
5662
+
5663
+ @@unique([userId, birthdayYear])
5664
+ @@index([userId])
5665
+ @@index([birthdayYear])
5666
+ }
5667
+
5668
+ // User-recorded places where they picked up a birthday reward (with optional rating)
5669
+ model BirthdayRewardRedemption {
5670
+ id String @id @default(cuid())
5671
+ userId String
5672
+ placeName String // e.g. "Freddy's", "Starbucks"
5673
+ redeemedAt DateTime @default(now())
5674
+ birthdayYear Int
5675
+ notes String? @db.Text
5676
+ difficultyScore Int? // 1-10
5677
+ qualityScore Int? // 1-10
5678
+ ratingComment String? @db.Text
5679
+ ratedAt DateTime?
5680
+ offerId String? // Part B: optional FK to structured BirthdayOffer
5681
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
5682
+ offer BirthdayOffer? @relation(fields: [offerId], references: [id], onDelete: SetNull)
5683
+
5684
+ @@index([userId])
5685
+ @@index([userId, birthdayYear])
5686
+ @@index([offerId])
5687
+ }
5688
+
5689
+ enum BirthdayDealSuggestionStatus {
5690
+ Pending
5691
+ Approved
5692
+ Rejected
5693
+ }
5694
+
5695
+ // User-suggested birthday deals (admin can approve and add to catalog later)
5696
+ model BirthdayDealSuggestion {
5697
+ id String @id @default(cuid())
5698
+ userId String
5699
+ brandOrPlaceName String
5700
+ dealDescription String @db.Text
5701
+ sourceWhereHeard String? @db.Text
5702
+ linkUrl String? @db.Text
5703
+ status BirthdayDealSuggestionStatus @default(Pending)
5704
+ createdAt DateTime @default(now())
5705
+ reviewedAt DateTime?
5706
+ reviewedById String?
5707
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
5708
+ catalogEntry BirthdayFreebieCatalog?
5709
+
5710
+ @@index([userId])
5711
+ @@index([status])
5712
+ }
5713
+
5714
+ // Public SEO catalog for birthday freebie pages (programmatic by city/state)
5715
+ enum BirthdayFreebieCategory {
5716
+ NoPurchaseRequired
5717
+ PurchaseRequired
5718
+ }
5719
+
5720
+ enum BirthdayFreebieExpirationType {
5721
+ DayOf
5722
+ Valid30Days
5723
+ }
5724
+
5725
+ enum BirthdayFreebieSource {
5726
+ Partner
5727
+ Suggestion
5728
+ Manual
5729
+ }
5730
+
5731
+ enum BirthdayFreebieSector {
5732
+ CoffeeAndBeverages
5733
+ FoodAndRestaurants
5734
+ DessertsAndIceCream
5735
+ BeautyAndRetail
5736
+ Entertainment
5737
+ Other
5738
+ }
5739
+
5740
+ model BirthdayFreebieCatalog {
5741
+ id String @id @default(cuid())
5742
+ brandOrPlaceName String
5743
+ description String? @db.Text
5744
+ logoUrl String? @db.Text
5745
+ sector BirthdayFreebieSector @default(Other)
5746
+ category BirthdayFreebieCategory
5747
+ expirationType BirthdayFreebieExpirationType
5748
+ lastVerifiedAt DateTime
5749
+ requiresAdvanceSignup Boolean? @default(false)
5750
+ source BirthdayFreebieSource
5751
+ partnerId String?
5752
+ suggestionId String? @unique // one-to-one: at most one catalog entry per suggestion
5753
+ stateSlug String
5754
+ citySlug String?
5755
+ isActive Boolean @default(true)
5756
+ signupUrl String? @db.Text // Official "how to redeem" / terms link
5757
+ sourceUrl String? @db.Text // Optional: reference source (e.g. NerdWallet, Krazy Coupon Lady)
5758
+ appRequired Boolean @default(false)
5759
+ priority Int @default(0) // Tie-break sort
5760
+ address String? @db.Text // For Maps and display
5761
+ redemptionNotes String? @db.Text // Conditions, limitations
5762
+ createdAt DateTime @default(now())
5763
+ updatedAt DateTime @updatedAt
5764
+
5765
+ partner BirthdayOfferPartner? @relation(fields: [partnerId], references: [id], onDelete: SetNull)
5766
+ suggestion BirthdayDealSuggestion? @relation(fields: [suggestionId], references: [id], onDelete: SetNull)
5767
+ rewardReports RewardReport[]
5768
+
5769
+ @@index([stateSlug, citySlug])
5770
+ @@index([isActive])
5771
+ @@index([sector])
5772
+ }
5773
+
5774
+ // Per-city "free things to do" links (tourism calendar, Eventbrite, Meetup, alt-weekly)
5775
+ enum BirthdayCityResourceType {
5776
+ TourismCalendar
5777
+ EventAggregator
5778
+ LocalCalendar
5779
+ }
5780
+
5781
+ model BirthdayCityResource {
5782
+ id String @id @default(cuid())
5783
+ stateSlug String
5784
+ citySlug String? // null = state-level resource
5785
+ type BirthdayCityResourceType
5786
+ label String // e.g. "Visit Salt Lake events"
5787
+ url String @db.Text
5788
+ sortOrder Int @default(0)
5789
+ createdAt DateTime @default(now())
5790
+ updatedAt DateTime @updatedAt
5791
+
5792
+ @@index([stateSlug, citySlug])
5793
+ }
5794
+
5795
+ enum RewardReportStatus {
5796
+ Pending
5797
+ Approved
5798
+ Rejected
5799
+ }
5800
+
5801
+ model RewardReport {
5802
+ id String @id @default(cuid())
5803
+ catalogId String
5804
+ userId String
5805
+ reportedAt DateTime @default(now())
5806
+ reason String @db.Text
5807
+ suggestedChanges String? @db.Text
5808
+ status RewardReportStatus @default(Pending)
5809
+ reviewedAt DateTime?
5810
+ reviewedById String?
5811
+ catalog BirthdayFreebieCatalog @relation(fields: [catalogId], references: [id], onDelete: Cascade)
5812
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
5813
+ reviewedBy User? @relation("RewardReportReviewedBy", fields: [reviewedById], references: [id], onDelete: SetNull)
5814
+
5815
+ @@index([catalogId])
5816
+ @@index([userId])
5817
+ @@index([status])
5818
+ }
5819
+
5820
+ // Part B: User saved locations (birthday home base, etc.)
5821
+ model UserLocation {
5822
+ id String @id @default(cuid())
5823
+ userId String
5824
+ label String? // e.g. "Home", "Work"
5825
+ address1 String
5826
+ address2 String?
5827
+ city String
5828
+ state String
5829
+ zip String
5830
+ country String? @default("US")
5831
+ lat Float?
5832
+ lng Float?
5833
+ isDefault Boolean? @default(false)
5834
+ createdAt DateTime @default(now())
5835
+ updatedAt DateTime @updatedAt
5836
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
5837
+ usersWithBirthdayLocation User[] @relation("UserBirthdayLocation")
5838
+
5839
+ @@index([userId])
5840
+ }
5841
+
5842
+ // Part B: Structured birthday offers (catalog)
5843
+ enum RedemptionMethod {
5844
+ APP
5845
+ EMAIL
5846
+ IN_STORE
5847
+ ONLINE
5848
+ }
5849
+
5850
+ enum BirthdayOfferExpirationType {
5851
+ DAY_OF // End of birthday day
5852
+ DAYS_FROM_BDAY
5853
+ END_OF_MONTH
5854
+ VARIABLE
5855
+ }
5856
+
5857
+ enum BirthdayOfferSourceType {
5858
+ BRAND_SITE
5859
+ USER_REPORTED
5860
+ PARTNER
5861
+ }
5862
+
5863
+ enum OfferClaimStatus {
5864
+ CLICKED
5865
+ SAVED
5866
+ CLAIMED
5867
+ REDEEMED
5868
+ EXPIRED
5869
+ }
5870
+
5871
+ model Brand {
5872
+ id String @id @default(cuid())
5873
+ name String
5874
+ websiteUrl String? @db.Text
5875
+ logoUrl String? @db.Text
5876
+ categoryDefault String? // restaurant, coffee, dessert, retail, entertainment
5877
+ isNational Boolean @default(true)
5878
+ createdAt DateTime @default(now())
5879
+ updatedAt DateTime @updatedAt
5880
+ offers BirthdayOffer[]
5881
+ locations BrandLocation[]
5882
+
5883
+ @@index([isNational])
5884
+ }
5885
+
5886
+ model BirthdayOffer {
5887
+ id String @id @default(cuid())
5888
+ brandId String
5889
+ title String // e.g. "Free burger reward"
5890
+ descriptionShort String? @db.Text
5891
+ purchaseRequired Boolean @default(false)
5892
+ signupRequired Boolean @default(false)
5893
+ appRequired Boolean @default(false)
5894
+ requiresPhone Boolean @default(false)
5895
+ redemptionMethod RedemptionMethod
5896
+ expirationType BirthdayOfferExpirationType
5897
+ expirationDays Int? // when expirationType = DAYS_FROM_BDAY
5898
+ windowStartOffsetDays Int @default(0)
5899
+ termsUrl String? @db.Text
5900
+ termsNotes String? @db.Text
5901
+ sourceType BirthdayOfferSourceType
5902
+ lastVerifiedAt DateTime?
5903
+ isActive Boolean @default(true)
5904
+ priorityScore Int @default(0)
5905
+ featuredUntil DateTime?
5906
+ createdAt DateTime @default(now())
5907
+ updatedAt DateTime @updatedAt
5908
+ brand Brand @relation(fields: [brandId], references: [id], onDelete: Cascade)
5909
+ claims OfferClaim[]
5910
+ redemptions BirthdayRewardRedemption[]
5911
+
5912
+ @@index([brandId])
5913
+ @@index([isActive])
5914
+ @@index([sourceType])
5915
+ }
5916
+
5917
+ model BrandLocation {
5918
+ id String @id @default(cuid())
5919
+ brandId String
5920
+ address1 String
5921
+ address2 String?
5922
+ city String
5923
+ state String
5924
+ zip String
5925
+ lat Float
5926
+ lng Float
5927
+ isActive Boolean @default(true)
5928
+ createdAt DateTime @default(now())
5929
+ updatedAt DateTime @updatedAt
5930
+ brand Brand @relation(fields: [brandId], references: [id], onDelete: Cascade)
5931
+
5932
+ @@index([brandId])
5933
+ @@index([isActive])
5934
+ }
5935
+
5936
+ model OfferClaim {
5937
+ id String @id @default(cuid())
5938
+ userId String
5939
+ birthdayOfferId String
5940
+ claimedAt DateTime @default(now())
5941
+ birthdayYear Int
5942
+ status OfferClaimStatus
5943
+ meta Json?
5944
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
5945
+ birthdayOffer BirthdayOffer @relation(fields: [birthdayOfferId], references: [id], onDelete: Cascade)
5946
+
5947
+ @@index([userId])
5948
+ @@index([birthdayOfferId])
5949
+ @@index([userId, birthdayYear])
5950
+ }
5951
+
5952
+ model BirthdayPlan {
5953
+ id String @id @default(cuid())
5954
+ userId String
5955
+ birthdayYear Int
5956
+ generatedAt DateTime @default(now())
5957
+ preferencesSnapshot Json // distance, filters, optimizeFor
5958
+ items Json // ordered stops: plannedDate, brandId, offerId, locationId?, distanceFromHome, deadline, purchaseRequired
5959
+ validFrom DateTime
5960
+ validTo DateTime
5961
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
5962
+
5963
+ @@index([userId])
5964
+ @@index([userId, birthdayYear])
5965
+ }
5966
+
5967
+ // Part B: Geocoding cache to avoid repeated API calls (birthday rewards, UserLocation, etc.)
5968
+ model GeocodeCache {
5969
+ id String @id @default(cuid())
5970
+ addressQuery String @unique // Normalized query string (trimmed, collapsed whitespace)
5971
+ lat Float
5972
+ lng Float
5973
+ normalizedAddress String @db.Text // formatted_address from provider
5974
+ createdAt DateTime @default(now())
5975
+
5976
+ @@index([addressQuery])
5580
5977
  }
5581
5978
 
5582
5979
  model AuditLog {
@@ -1373,3 +1373,4 @@ export const POPULAR_BLOG_TAGS = [
1373
1373
  ] as const;
1374
1374
 
1375
1375
  export const SITE_NAME = "Bash" as const;
1376
+
@@ -1186,4 +1186,3 @@ export interface BlogTagFormData {
1186
1186
  slug?: string;
1187
1187
  color?: string;
1188
1188
  }
1189
-
@@ -928,4 +928,3 @@ export interface MembershipPaymentIntentResult {
928
928
  amount: number;
929
929
  currency: string;
930
930
  }
931
-
@@ -1250,4 +1250,3 @@ export function getTemplateCategoryCounts(): Record<EventTemplateCategory, numbe
1250
1250
 
1251
1251
  // Export total count
1252
1252
  export const TOTAL_TEMPLATE_COUNT = allEventTemplates.length;
1253
-
@@ -9,6 +9,10 @@ import {
9
9
  convertDollarsToCents,
10
10
  calculateBashAppFee,
11
11
  calculateBashAppFeeWithMembershipDiscount,
12
+ calculateTotalPriceWithoutTax,
13
+ calculateTotalBashPoints,
14
+ calculateStripeDonationFee,
15
+ calculateServiceFeeWithMembershipDiscount,
12
16
  } from "../paymentUtils";
13
17
 
14
18
  describe("PaymentUtils - Core Functions", () => {
@@ -92,4 +96,83 @@ describe("PaymentUtils - Core Functions", () => {
92
96
  expect(fee).toBe(1000); // cap at $10
93
97
  });
94
98
  });
99
+
100
+ describe("Ticket total price (USD)", () => {
101
+ test("calculateTotalPriceWithoutTax sums USD tiers only", () => {
102
+ const tiers = [
103
+ { id: "t1", price: 1000, pricingType: "USD" },
104
+ { id: "t2", price: 500, pricingType: "USD" },
105
+ ] as any;
106
+ const ticketList = new Map([
107
+ ["t1", [{ numberOfTickets: 2, ticketDateTime: new Date() }]],
108
+ ["t2", [{ numberOfTickets: 1, ticketDateTime: new Date() }]],
109
+ ]);
110
+ expect(calculateTotalPriceWithoutTax(tiers, ticketList)).toBe(2500); // 2*1000 + 1*500
111
+ });
112
+
113
+ test("calculateTotalPriceWithoutTax excludes BASHPOINTS tiers", () => {
114
+ const tiers = [
115
+ { id: "t1", price: 1000, pricingType: "USD" },
116
+ { id: "t2", price: 200, pricingType: "BASHPOINTS", priceBashPoints: 50 },
117
+ ] as any;
118
+ const ticketList = new Map([
119
+ ["t1", [{ numberOfTickets: 1, ticketDateTime: new Date() }]],
120
+ ["t2", [{ numberOfTickets: 3, ticketDateTime: new Date() }]],
121
+ ]);
122
+ expect(calculateTotalPriceWithoutTax(tiers, ticketList)).toBe(1000);
123
+ });
124
+
125
+ test("calculateTotalPriceWithoutTax returns 0 for empty list", () => {
126
+ expect(calculateTotalPriceWithoutTax([], new Map())).toBe(0);
127
+ });
128
+ });
129
+
130
+ describe("Ticket total BashPoints", () => {
131
+ test("calculateTotalBashPoints sums BASHPOINTS tiers only", () => {
132
+ const tiers = [
133
+ { id: "t1", price: 1000, pricingType: "USD" },
134
+ { id: "t2", price: 0, pricingType: "BASHPOINTS", priceBashPoints: 100 },
135
+ ] as any;
136
+ const ticketList = new Map([
137
+ ["t1", [{ numberOfTickets: 1, ticketDateTime: new Date() }]],
138
+ ["t2", [{ numberOfTickets: 2, ticketDateTime: new Date() }]],
139
+ ]);
140
+ expect(calculateTotalBashPoints(tiers, ticketList)).toBe(200);
141
+ });
142
+
143
+ test("calculateTotalBashPoints returns 0 when no BASHPOINTS tiers", () => {
144
+ const tiers = [{ id: "t1", price: 1000, pricingType: "USD" }] as any;
145
+ const ticketList = new Map([["t1", [{ numberOfTickets: 1, ticketDateTime: new Date() }]]]);
146
+ expect(calculateTotalBashPoints(tiers, ticketList)).toBe(0);
147
+ });
148
+ });
149
+
150
+ describe("Stripe donation fee", () => {
151
+ test("calculateStripeDonationFee applies 2.9% + 30 cents", () => {
152
+ // 10000 cents = $100 -> 2.9% = 290, + 30 = 320
153
+ expect(calculateStripeDonationFee(10000)).toBe(320);
154
+ });
155
+
156
+ test("calculateStripeDonationFee for small amount", () => {
157
+ expect(calculateStripeDonationFee(100)).toBeGreaterThanOrEqual(30);
158
+ });
159
+ });
160
+
161
+ describe("Service fee with membership discount", () => {
162
+ test("calculateServiceFeeWithMembershipDiscount Basic tier", () => {
163
+ const fee = calculateServiceFeeWithMembershipDiscount(10000, "Basic" as any);
164
+ expect(fee).toBeGreaterThan(0);
165
+ expect(typeof fee).toBe("number");
166
+ });
167
+
168
+ test("calculateServiceFeeWithMembershipDiscount Premium tier", () => {
169
+ const fee = calculateServiceFeeWithMembershipDiscount(10000, "Premium" as any);
170
+ expect(fee).toBeGreaterThanOrEqual(0);
171
+ });
172
+
173
+ test("calculateServiceFeeWithMembershipDiscount defaults to Basic when null", () => {
174
+ const fee = calculateServiceFeeWithMembershipDiscount(10000, null);
175
+ expect(typeof fee).toBe("number");
176
+ });
177
+ });
95
178
  });
@@ -18,7 +18,7 @@ export function getUserName(contactOrUser: Partial<CombinedUserOrContact> | unde
18
18
  }
19
19
  const user = contactOrUser as CombinedUser;
20
20
  const combinedName = user.givenName && user.familyName ? `${user.givenName} ${user.familyName}` : null;
21
- return combinedName ?? user.email;
21
+ return combinedName ?? user.email ?? '';
22
22
  }
23
23
 
24
24
  export function getUserImage(contactOrUser: CombinedUserOrContact | undefined): string {
@@ -104,3 +104,4 @@ export function isProduction(): boolean {
104
104
  return process.env.NODE_ENV === 'production' &&
105
105
  (environment === 'production' || bashEnv === 'production');
106
106
  }
107
+
@@ -104,4 +104,3 @@ export function validateBashPointsPayment(
104
104
  errorMessage: "BashPoints can only be used for BashPoints-priced tickets, not service bookings. Please pay with a credit card.",
105
105
  };
106
106
  }
107
-
@@ -184,6 +184,11 @@ export async function searchBlogPosts(
184
184
  status,
185
185
  };
186
186
 
187
+ // When listing Published posts, only include posts with a set publishedAt so the list is consistent (null dates sort last and can hide new posts)
188
+ if (status === BlogStatus.Published) {
189
+ where.publishedAt = { not: null };
190
+ }
191
+
187
192
  if (query) {
188
193
  where.OR = [
189
194
  { title: { contains: query, mode: 'insensitive' } },
@@ -340,4 +345,4 @@ export async function getRecentBlogPosts(
340
345
  });
341
346
 
342
347
  return posts as BlogPostExt[];
343
- }
348
+ }
@@ -131,4 +131,4 @@ export function formatPublishDate(date: Date | string): string {
131
131
  month: 'long',
132
132
  day: 'numeric'
133
133
  });
134
- }
134
+ }
@@ -311,12 +311,3 @@ export function shouldWarnUser(violations: ContentViolation[], userTier: string)
311
311
  message: 'Please avoid mentioning external payment methods. Use the platform\'s payment system instead.'
312
312
  };
313
313
  }
314
-
315
-
316
-
317
-
318
-
319
-
320
-
321
-
322
-
@@ -209,4 +209,3 @@ export const calculateEffectiveRate = (result: BestPriceResult): number => {
209
209
  if (result.originalTotal === 0) return 0;
210
210
  return Math.floor((result.totalSavings / result.originalTotal) * 100);
211
211
  };
212
-
@@ -253,4 +253,3 @@ export const getTimeRemaining = (offer: SpecialOffer, currentDate: Date): {
253
253
 
254
254
  return { expired: false, days, hours, minutes, seconds };
255
255
  };
256
-
@@ -57,4 +57,4 @@ export function parseBashUrlParams(param: string): { id: string; slug: string |
57
57
  export function validateSlug(slug: string): boolean {
58
58
  // Check if slug only contains lowercase letters, numbers, and hyphens
59
59
  return /^[a-z0-9-]+$/.test(slug);
60
- }
60
+ }
@@ -26,5 +26,3 @@ export function formatVenueTypes(venueTypes: string[], maxDisplay: number = 2):
26
26
 
27
27
  return formatted.join(', ');
28
28
  }
29
-
30
-