@bash-app/bash-common 30.335.0 → 30.337.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 (134) hide show
  1. package/dist/__tests__/seatMap.test.d.ts +2 -0
  2. package/dist/__tests__/seatMap.test.d.ts.map +1 -0
  3. package/dist/__tests__/seatMap.test.js +42 -0
  4. package/dist/__tests__/seatMap.test.js.map +1 -0
  5. package/dist/__tests__/seatMapBestAvailable.test.d.ts +2 -0
  6. package/dist/__tests__/seatMapBestAvailable.test.d.ts.map +1 -0
  7. package/dist/__tests__/seatMapBestAvailable.test.js +101 -0
  8. package/dist/__tests__/seatMapBestAvailable.test.js.map +1 -0
  9. package/dist/accessScreening.js +0 -1
  10. package/dist/aiApproval.js +0 -1
  11. package/dist/aiEventPlan.js +0 -1
  12. package/dist/bashFeedTypes.js +0 -1
  13. package/dist/bookingIntent.js +0 -1
  14. package/dist/causeTags.js +0 -1
  15. package/dist/definitions.d.ts +10 -0
  16. package/dist/definitions.d.ts.map +1 -1
  17. package/dist/definitions.js.map +1 -1
  18. package/dist/entertainmentNotableVenues.js +0 -1
  19. package/dist/extendedSchemas.d.ts +1 -1
  20. package/dist/groupTicketUtils.js +0 -1
  21. package/dist/guestPartySize.js +0 -1
  22. package/dist/hostCrmAutomation.js +0 -1
  23. package/dist/hostCrmConstants.js +0 -1
  24. package/dist/hostCrmInsights.js +0 -1
  25. package/dist/hostCrmSegments.js +0 -1
  26. package/dist/hostPromoter.js +0 -1
  27. package/dist/icebreakerPrompts.js +0 -1
  28. package/dist/index.d.ts +2 -0
  29. package/dist/index.d.ts.map +1 -1
  30. package/dist/index.js +2 -0
  31. package/dist/index.js.map +1 -1
  32. package/dist/influencerAudience.js +0 -1
  33. package/dist/legalTemplates.js +0 -1
  34. package/dist/membershipDefinitions.js +0 -1
  35. package/dist/mirroredPrismaEnums.js +0 -1
  36. package/dist/onSaleCapabilityRecommendations.js +0 -1
  37. package/dist/partnerStoreTypes.js +0 -1
  38. package/dist/productLaunch.js +0 -1
  39. package/dist/relationshipHealth.js +0 -1
  40. package/dist/requestAuthUser.js +0 -1
  41. package/dist/seatMap.d.ts +80 -0
  42. package/dist/seatMap.d.ts.map +1 -0
  43. package/dist/seatMap.js +250 -0
  44. package/dist/seatMap.js.map +1 -0
  45. package/dist/seatMapBestAvailable.d.ts +24 -0
  46. package/dist/seatMapBestAvailable.d.ts.map +1 -0
  47. package/dist/seatMapBestAvailable.js +143 -0
  48. package/dist/seatMapBestAvailable.js.map +1 -0
  49. package/dist/serviceTypeLabels.js +0 -1
  50. package/dist/sideQuestIdeas.js +0 -1
  51. package/dist/sms/smsTemplates.js +0 -1
  52. package/dist/storePrintArtworkUtils.js +0 -1
  53. package/dist/storeTypes.js +0 -1
  54. package/dist/stripeListingSubscriptionMessages.js +0 -1
  55. package/dist/targetAudienceLabels.js +0 -1
  56. package/dist/templates/eventTemplates.js +0 -1
  57. package/dist/ticketBnplPaymentMethods.js +0 -1
  58. package/dist/userReportTypes.js +0 -1
  59. package/dist/utils/__tests__/paymentUtils.test.js +1 -1
  60. package/dist/utils/__tests__/paymentUtils.test.js.map +1 -1
  61. package/dist/utils/__tests__/ticketListUtils.test.js +41 -0
  62. package/dist/utils/__tests__/ticketListUtils.test.js.map +1 -1
  63. package/dist/utils/agencyBookingCheckoutCopy.js +0 -1
  64. package/dist/utils/arrayUtils.js +0 -1
  65. package/dist/utils/awsS3Utils.js +0 -1
  66. package/dist/utils/bashPointsPaymentUtils.js +0 -1
  67. package/dist/utils/birthdayExperienceQuality.js +0 -1
  68. package/dist/utils/contentFilterUtils.js +0 -1
  69. package/dist/utils/discountEngine/bestPriceResolver.js +0 -1
  70. package/dist/utils/discountEngine/eligibilityValidator.js +0 -1
  71. package/dist/utils/displayDateUtils.js +0 -1
  72. package/dist/utils/entertainmentDrawFit.js +0 -1
  73. package/dist/utils/entityUtils.js +0 -1
  74. package/dist/utils/eventCitySlug.js +0 -1
  75. package/dist/utils/eventTimezoneIana.js +0 -1
  76. package/dist/utils/featuredDiscoveryGeo.js +0 -1
  77. package/dist/utils/flyerUtils.js +0 -1
  78. package/dist/utils/generalDateTimeUtils.js +0 -1
  79. package/dist/utils/guestSurface.js +6 -6
  80. package/dist/utils/lobFlyerUtils.js +0 -1
  81. package/dist/utils/localPartnerHours.js +0 -1
  82. package/dist/utils/locationVisibility.js +0 -1
  83. package/dist/utils/luxonUtils.js +0 -1
  84. package/dist/utils/mathUtils.js +0 -1
  85. package/dist/utils/mediaClientDefaults.js +0 -1
  86. package/dist/utils/nonprofitUtils.js +0 -1
  87. package/dist/utils/objUtils.js +0 -1
  88. package/dist/utils/orgPromotionalPackageUtils.js +0 -1
  89. package/dist/utils/organizationEntitlements.js +0 -1
  90. package/dist/utils/paymentUtils.d.ts +1 -1
  91. package/dist/utils/paymentUtils.js +1 -1
  92. package/dist/utils/promotionBlastUtils.js +0 -1
  93. package/dist/utils/reputationUtils.js +0 -1
  94. package/dist/utils/reviewDimensionUtils.js +0 -1
  95. package/dist/utils/service/attendeeOptionUtils.js +0 -1
  96. package/dist/utils/service/billingCapUtils.js +0 -1
  97. package/dist/utils/service/eventPromoterUtils.js +0 -1
  98. package/dist/utils/service/offerAllowListUtils.js +0 -1
  99. package/dist/utils/service/offerComparisonUtils.js +0 -1
  100. package/dist/utils/service/regexUtils.js +0 -1
  101. package/dist/utils/service/serviceBookingExposureUtils.js +0 -1
  102. package/dist/utils/service/serviceFeaturedSortUtils.js +0 -1
  103. package/dist/utils/service/unifiedPricingResolver.js +0 -1
  104. package/dist/utils/service/venueSettlementUtils.js +0 -1
  105. package/dist/utils/service/volunteerCompensationUtils.js +0 -1
  106. package/dist/utils/serviceAvailabilityDisplay.js +0 -1
  107. package/dist/utils/sortUtils.js +0 -1
  108. package/dist/utils/stringUtils.js +0 -1
  109. package/dist/utils/ticketCheckInDisplay.js +0 -1
  110. package/dist/utils/ticketListUtils.d.ts.map +1 -1
  111. package/dist/utils/ticketListUtils.js +17 -0
  112. package/dist/utils/ticketListUtils.js.map +1 -1
  113. package/dist/utils/trustScoreUtils.js +0 -1
  114. package/dist/utils/typeUtils.js +0 -1
  115. package/dist/utils/userPromoCodeUtils.js +0 -1
  116. package/dist/utils/userUtils.js +0 -1
  117. package/dist/utils/venueLoyalty/redemptionCodeUtils.js +0 -1
  118. package/dist/utils/venueTypeFormatter.js +0 -1
  119. package/dist/utmAttribution.js +0 -1
  120. package/dist/venueMatch.js +0 -1
  121. package/package.json +1 -1
  122. package/prisma/schema.prisma +151 -0
  123. package/src/__tests__/seatMap.test.ts +59 -0
  124. package/src/__tests__/seatMapBestAvailable.test.ts +111 -0
  125. package/src/definitions.ts +10 -0
  126. package/src/extendedSchemas.ts +1 -1
  127. package/src/index.ts +2 -0
  128. package/src/seatMap.ts +337 -0
  129. package/src/seatMapBestAvailable.ts +174 -0
  130. package/src/utils/__tests__/paymentUtils.test.ts +1 -1
  131. package/src/utils/__tests__/ticketListUtils.test.ts +44 -0
  132. package/src/utils/guestSurface.ts +6 -6
  133. package/src/utils/paymentUtils.ts +1 -1
  134. package/src/utils/ticketListUtils.ts +26 -0
@@ -65,9 +65,16 @@ export function ticketListToString(ticketList) {
65
65
  dateTimeStr = dateTime.toISO() || dateTimeStr;
66
66
  }
67
67
  }
68
+ const needsSeatHold = !!ticketNumAndDates.seatHoldId && ticketNumAndDates.seatIds?.length;
68
69
  ticketArgs.push(`${ticketNumAndDates.numberOfTickets}${URL_PARAMS_TICKETS_DATE_DELIM}${dateTimeStr}${ticketNumAndDates.unitPriceCents != null &&
69
70
  ticketNumAndDates.unitPriceCents > 0
70
71
  ? `${URL_PARAMS_TICKETS_DATE_DELIM}${ticketNumAndDates.unitPriceCents}`
72
+ : ticketNumAndDates.seatIds?.length
73
+ ? `${URL_PARAMS_TICKETS_DATE_DELIM}`
74
+ : ""}${ticketNumAndDates.seatIds?.length
75
+ ? `${URL_PARAMS_TICKETS_DATE_DELIM}${ticketNumAndDates.seatIds.join("|")}`
76
+ : ""}${needsSeatHold
77
+ ? `${URL_PARAMS_TICKETS_DATE_DELIM}${ticketNumAndDates.seatHoldId}`
71
78
  : ""}`);
72
79
  }
73
80
  }
@@ -122,6 +129,8 @@ export function ticketListStrToTicketList(ticketListStr) {
122
129
  const numberOfTickets = segments[0];
123
130
  const ticketDateTimeStr = segments[1];
124
131
  const unitPriceCentsRaw = segments[2];
132
+ const seatIdsRaw = segments[3];
133
+ const seatHoldIdRaw = segments[4];
125
134
  const ticketDateTime = DateTime.fromISO(ticketDateTimeStr);
126
135
  let ticketDateTimeFormattedStr = undefined;
127
136
  if (ticketDateTime.isValid) {
@@ -130,12 +139,20 @@ export function ticketListStrToTicketList(ticketListStr) {
130
139
  const unitPriceCents = unitPriceCentsRaw != null && unitPriceCentsRaw !== ""
131
140
  ? parseInt(unitPriceCentsRaw, 10)
132
141
  : undefined;
142
+ const seatIds = seatIdsRaw != null && seatIdsRaw !== ""
143
+ ? seatIdsRaw.split("|").map((id) => id.trim()).filter(Boolean)
144
+ : undefined;
145
+ const seatHoldId = seatHoldIdRaw != null && seatHoldIdRaw.trim() !== ""
146
+ ? seatHoldIdRaw.trim()
147
+ : undefined;
133
148
  ticketNumAndDatesArr.push({
134
149
  numberOfTickets: parseInt(numberOfTickets),
135
150
  ticketDateTime: ticketDateTimeFormattedStr,
136
151
  ...(unitPriceCents != null && !Number.isNaN(unitPriceCents)
137
152
  ? { unitPriceCents }
138
153
  : {}),
154
+ ...(seatIds?.length ? { seatIds } : {}),
155
+ ...(seatHoldId ? { seatHoldId } : {}),
139
156
  });
140
157
  }
141
158
  ticketList.set(ticketTierId, ticketNumAndDatesArr);
@@ -1 +1 @@
1
- {"version":3,"file":"ticketListUtils.js","sourceRoot":"","sources":["../../src/utils/ticketListUtils.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ticketListUtils.js","sourceRoot":"","sources":["../../src/utils/ticketListUtils.ts"],"names":[],"mappings":"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"}
@@ -96,4 +96,3 @@ export function trustScoreFromReviewAverage(actorType, averageRating, totalRatin
96
96
  });
97
97
  return result.score;
98
98
  }
99
- //# sourceMappingURL=trustScoreUtils.js.map
@@ -5,4 +5,3 @@ export function createAllTrueObject(keys) {
5
5
  return acc;
6
6
  }, {});
7
7
  }
8
- //# sourceMappingURL=typeUtils.js.map
@@ -10,4 +10,3 @@ export const USER_PROMO_CODES = {
10
10
  },
11
11
  };
12
12
  Object.entries(USER_PROMO_CODES).forEach((promoCode) => (promoCode[1].code = promoCode[0]));
13
- //# sourceMappingURL=userPromoCodeUtils.js.map
@@ -57,4 +57,3 @@ export function getSocialEventCadenceDisplay(cadence) {
57
57
  return null;
58
58
  return SOCIAL_EVENT_CADENCE_PROFILE_LABELS[cadence] ?? cadence;
59
59
  }
60
- //# sourceMappingURL=userUtils.js.map
@@ -71,4 +71,3 @@ function defaultRandomBytes(length) {
71
71
  export const __testInternals = {
72
72
  REDEMPTION_CODE_ALPHABET,
73
73
  };
74
- //# sourceMappingURL=redemptionCodeUtils.js.map
@@ -22,4 +22,3 @@ export function formatVenueTypes(venueTypes, maxDisplay = 2) {
22
22
  }
23
23
  return formatted.join(', ');
24
24
  }
25
- //# sourceMappingURL=venueTypeFormatter.js.map
@@ -121,4 +121,3 @@ export function getStoredUtmFields() {
121
121
  }
122
122
  return out;
123
123
  }
124
- //# sourceMappingURL=utmAttribution.js.map
@@ -65,4 +65,3 @@ export const VENUE_MATCH_MODES = [
65
65
  "marketplace_only",
66
66
  "marketplace_and_google",
67
67
  ];
68
- //# sourceMappingURL=venueMatch.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bash-app/bash-common",
3
- "version": "30.335.0",
3
+ "version": "30.337.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",
@@ -855,6 +855,10 @@ model BashEvent {
855
855
  coatCheckOversizedSurchargeCents Int?
856
856
  /// When true, door/checkout may collect an optional tip for coat check staff.
857
857
  coatCheckTipsEnabled Boolean @default(false)
858
+ /// Host opt-in: venue seat map for this bash (builder + guest view).
859
+ seatMapEnabled Boolean @default(false)
860
+ /// Seat map document (ISeatMap-shaped JSON: id, name, stageText, seatMapData).
861
+ seatMap Json?
858
862
  /// Host uses a Stripe card reader (Terminal) at the door; door app can run card on reader.
859
863
  hasStripeTerminal Boolean @default(false)
860
864
  /// Host uses Tap to Pay on a supported device (no separate reader). Door flow when enabled.
@@ -989,6 +993,8 @@ model BashEvent {
989
993
  postEventMessageSentAt DateTime?
990
994
  broadcastCount Int @default(0)
991
995
  lastBroadcastAt DateTime?
996
+ /// Optional host note appended to ticket purchase confirmation emails.
997
+ confirmationEmailNote String? @db.Text
992
998
  /// When true, notify opted-in CRM audience on publish (optional tag in crmPublishNotifyTag).
993
999
  crmPublishNotifyEnabled Boolean @default(false)
994
1000
  crmPublishNotifyTag String?
@@ -1041,6 +1047,12 @@ model BashEvent {
1041
1047
  eventTasks EventTask[]
1042
1048
  potluckItems PotluckItem[]
1043
1049
  bashEventSuggestions BashEventSuggestion[]
1050
+ eventBroadcasts EventBroadcast[]
1051
+ eventBroadcastSchedules EventBroadcastSchedule[]
1052
+ eventSuggestionDismissals EventSuggestionDismissal[]
1053
+ eventSuggestionSchedules EventSuggestionSchedule[]
1054
+ eventSuggestionAutomations EventSuggestionAutomation[]
1055
+
1044
1056
  itemUpvotes ItemUpvote[]
1045
1057
  exhibitorBookingRequests ExhibitorBookingRequest[] @relation("ExhibitorBookingEvent")
1046
1058
  investments Investment[]
@@ -2828,6 +2840,123 @@ model HostCrmAutomation {
2828
2840
  }
2829
2841
 
2830
2842
  // Tracks referrals: attendee A referred person B who bought a ticket
2843
+
2844
+ /// Sent host blast history for an event (Luma-style Blasts tab).
2845
+ model EventBroadcast {
2846
+ id String @id @default(cuid())
2847
+ bashEventId String
2848
+ sentByUserId String
2849
+ subject String
2850
+ message String @db.Text
2851
+ recipientType String
2852
+ tierIds String[] @default([])
2853
+ sendEmail Boolean @default(true)
2854
+ sendPush Boolean @default(true)
2855
+ sendSms Boolean @default(false)
2856
+ sentCount Int @default(0)
2857
+ createdAt DateTime @default(now())
2858
+
2859
+ bashEvent BashEvent @relation(fields: [bashEventId], references: [id], onDelete: Cascade)
2860
+ sentBy User @relation("EventBroadcastsSent", fields: [sentByUserId], references: [id], onDelete: Cascade)
2861
+
2862
+ @@index([bashEventId])
2863
+ @@index([bashEventId, createdAt])
2864
+ }
2865
+
2866
+ /// Scheduled host blast (send later via cron).
2867
+ model EventBroadcastSchedule {
2868
+ id String @id @default(cuid())
2869
+ bashEventId String
2870
+ createdByUserId String
2871
+ runAt DateTime
2872
+ /// pending | ran | cancelled | failed
2873
+ status String @default("pending")
2874
+ subject String
2875
+ message String @db.Text
2876
+ recipientType String @default("going")
2877
+ tierIds String[] @default([])
2878
+ sendEmail Boolean @default(true)
2879
+ sendPush Boolean @default(true)
2880
+ sendSms Boolean @default(false)
2881
+ lastError String?
2882
+ createdAt DateTime @default(now())
2883
+ updatedAt DateTime @updatedAt
2884
+
2885
+ bashEvent BashEvent @relation(fields: [bashEventId], references: [id], onDelete: Cascade)
2886
+ createdBy User @relation("EventBroadcastSchedulesCreated", fields: [createdByUserId], references: [id], onDelete: Cascade)
2887
+
2888
+ @@index([status, runAt])
2889
+ @@index([bashEventId])
2890
+ }
2891
+
2892
+ /// Host dismissed or snoozed an AI sales suggestion for this event.
2893
+ model EventSuggestionDismissal {
2894
+ id String @id @default(cuid())
2895
+ bashEventId String
2896
+ userId String
2897
+ suggestionType String
2898
+ suggestionKey String
2899
+ snoozeUntil DateTime?
2900
+ dismissedAt DateTime @default(now())
2901
+
2902
+ bashEvent BashEvent @relation(fields: [bashEventId], references: [id], onDelete: Cascade)
2903
+ user User @relation("EventSuggestionDismissals", fields: [userId], references: [id], onDelete: Cascade)
2904
+
2905
+ @@unique([bashEventId, userId, suggestionKey])
2906
+ @@index([bashEventId])
2907
+ }
2908
+
2909
+ /// One-shot scheduled execution of an AI suggestion.
2910
+ model EventSuggestionSchedule {
2911
+ id String @id @default(cuid())
2912
+ bashEventId String
2913
+ createdByUserId String
2914
+ suggestionType String
2915
+ suggestionKey String
2916
+ payload Json @default("{}")
2917
+ runAt DateTime
2918
+ /// pending | ran | cancelled | failed
2919
+ status String @default("pending")
2920
+ lastError String?
2921
+ createdAt DateTime @default(now())
2922
+ updatedAt DateTime @updatedAt
2923
+
2924
+ bashEvent BashEvent @relation(fields: [bashEventId], references: [id], onDelete: Cascade)
2925
+ createdBy User @relation("EventSuggestionSchedulesCreated", fields: [createdByUserId], references: [id], onDelete: Cascade)
2926
+
2927
+ @@index([status, runAt])
2928
+ @@index([bashEventId])
2929
+ }
2930
+
2931
+ /// Recurring / auto-run AI suggestion rule for an event (host can pause).
2932
+ model EventSuggestionAutomation {
2933
+ id String @id @default(cuid())
2934
+ bashEventId String
2935
+ createdByUserId String
2936
+ suggestionType String
2937
+ suggestionKey String
2938
+ enabled Boolean @default(true)
2939
+ sendEmail Boolean @default(true)
2940
+ sendPush Boolean @default(true)
2941
+ sendSms Boolean @default(false)
2942
+ budgetCents Int?
2943
+ maxRuns Int @default(3)
2944
+ runCount Int @default(0)
2945
+ lastRunAt DateTime?
2946
+ /// active | paused | completed | failed
2947
+ status String @default("active")
2948
+ payload Json @default("{}")
2949
+ createdAt DateTime @default(now())
2950
+ updatedAt DateTime @updatedAt
2951
+
2952
+ bashEvent BashEvent @relation(fields: [bashEventId], references: [id], onDelete: Cascade)
2953
+ createdBy User @relation("EventSuggestionAutomationsCreated", fields: [createdByUserId], references: [id], onDelete: Cascade)
2954
+
2955
+ @@unique([bashEventId, suggestionKey])
2956
+ @@index([enabled, status])
2957
+ }
2958
+
2959
+
2831
2960
  model EventReferral {
2832
2961
  id String @id @default(cuid())
2833
2962
  bashEventId String
@@ -3156,6 +3285,10 @@ model TicketTier {
3156
3285
  isGroupTicket Boolean @default(false)
3157
3286
  /// Headcount included per package when isGroupTicket (e.g. 6). Required when isGroupTicket.
3158
3287
  groupTicketSeatCount Int?
3288
+ /// When true, this tier uses the event seat map (guest View Seat Map).
3289
+ usesSeatMap Boolean @default(false)
3290
+ /// Seat ids from BashEvent.seatMap.seatMapData that this tier sells.
3291
+ seatIds String[] @default([])
3159
3292
  ticketGiftGrants TicketGiftGrant[]
3160
3293
  tierReleaseReminders TierReleaseReminder[]
3161
3294
  entryCompetition Competition? @relation("CompetitionEntryTicketTier")
@@ -3246,6 +3379,18 @@ model Ticket {
3246
3379
  /// Actual unit price paid at checkout in cents (PWYC tiers; null = use tier.price for legacy rows).
3247
3380
  paidUnitPriceCents Int?
3248
3381
 
3382
+ /// Assigned seat on BashEvent.seatMap (null until seat-pick checkout / host assign).
3383
+ seatId String?
3384
+ /// Denormalized for ticket UI: map section / block name.
3385
+ seatSection String?
3386
+ /// Denormalized row key from the seat map (e.g. "A").
3387
+ seatRow String?
3388
+ /// Denormalized seat number/label within the row (e.g. "12").
3389
+ seatLabel String?
3390
+
3391
+ /// Soft index for lookups; partial unique active seats enforced in migration
3392
+ /// `Ticket_bashEventId_seatId_active_key` (seatId NOT NULL AND status <> Cancelled).
3393
+
3249
3394
  /// P2P Venmo/Zelle off-platform payment flow
3250
3395
  p2pPaymentMethod String?
3251
3396
  p2pTransactionId String?
@@ -3290,6 +3435,7 @@ model Ticket {
3290
3435
  coatCheckEntitlements CoatCheckEntitlement[]
3291
3436
 
3292
3437
  @@index([bashEventId])
3438
+ @@index([bashEventId, seatId])
3293
3439
  @@index([waitlistUserId])
3294
3440
  @@index([attributedArtistId])
3295
3441
  @@index([giftGrantId])
@@ -4111,6 +4257,11 @@ model User {
4111
4257
  eventTasks EventTask[]
4112
4258
  potluckItemsClaimed PotluckItem[] @relation("PotluckItemsClaimedBy")
4113
4259
  bashEventSuggestionsCreated BashEventSuggestion[] @relation("BashEventSuggestionsCreated")
4260
+ eventBroadcastsSent EventBroadcast[] @relation("EventBroadcastsSent")
4261
+ eventBroadcastSchedulesCreated EventBroadcastSchedule[] @relation("EventBroadcastSchedulesCreated")
4262
+ eventSuggestionDismissals EventSuggestionDismissal[] @relation("EventSuggestionDismissals")
4263
+ eventSuggestionSchedulesCreated EventSuggestionSchedule[] @relation("EventSuggestionSchedulesCreated")
4264
+ eventSuggestionAutomationsCreated EventSuggestionAutomation[] @relation("EventSuggestionAutomationsCreated")
4114
4265
  bashSuggestionUpvotes SuggestionUpvote[] @relation("BashSuggestionUpvotes")
4115
4266
  itemUpvotesGiven ItemUpvote[] @relation("ItemUpvotesGiven")
4116
4267
  taskCommentsAuthored TaskComment[] @relation("TaskCommentsAuthored")
@@ -0,0 +1,59 @@
1
+ import {
2
+ formatAssignedSeatLocation,
3
+ formatTierSeatingArea,
4
+ isSeatMapDocument,
5
+ resolveTicketSeatingDisplay,
6
+ } from "../seatMap.js";
7
+
8
+ describe("seat location display", () => {
9
+ const map = {
10
+ id: "m1",
11
+ name: "Main floor",
12
+ blockName: "Orchestra",
13
+ stageText: "STAGE",
14
+ seatMapData: [
15
+ { id: "s1", row: "A", type: "seat", label: "1" },
16
+ { id: "s2", row: "A", type: "seat", label: "2" },
17
+ { id: "s3", row: "B", type: "seat", label: "1" },
18
+ { id: "sp", row: "A", type: "space", label: "" },
19
+ ],
20
+ };
21
+
22
+ it("formats an assigned seat", () => {
23
+ const loc = formatAssignedSeatLocation({
24
+ section: "Orchestra",
25
+ row: "A",
26
+ seat: "12",
27
+ });
28
+ expect(loc?.line).toBe("Orchestra · Row A · Seat 12");
29
+ expect(loc?.shortLine).toBe("A12");
30
+ });
31
+
32
+ it("formats a tier seating area from seat ids", () => {
33
+ const loc = formatTierSeatingArea(map, ["s1", "s2", "s3"]);
34
+ expect(loc?.section).toBe("Orchestra");
35
+ expect(loc?.line).toMatch(/Orchestra/);
36
+ expect(loc?.line).toMatch(/Rows A–B/);
37
+ expect(isSeatMapDocument(map)).toBe(true);
38
+ });
39
+
40
+ it("prefers ticket assignment over tier area", () => {
41
+ const loc = resolveTicketSeatingDisplay(
42
+ { seatRow: "A", seatLabel: "1", seatSection: "Orchestra" },
43
+ { usesSeatMap: true, seatIds: ["s1", "s2", "s3"] },
44
+ map
45
+ );
46
+ expect(loc?.shortLine).toBe("A1");
47
+ expect(loc?.line).toContain("Seat 1");
48
+ });
49
+
50
+ it("falls back to tier area when ticket has no seat", () => {
51
+ const loc = resolveTicketSeatingDisplay(
52
+ {},
53
+ { usesSeatMap: true, seatIds: ["s1", "s2"] },
54
+ map
55
+ );
56
+ expect(loc?.line).toMatch(/Orchestra/);
57
+ expect(loc?.line).toMatch(/Row A/);
58
+ });
59
+ });
@@ -0,0 +1,111 @@
1
+ import {
2
+ findBestAvailableSeats,
3
+ sectionsFromSeatMap,
4
+ sectionNameForRow,
5
+ isSeatMapDocument,
6
+ } from "../index.js";
7
+
8
+ describe("sectionsFromSeatMap", () => {
9
+ it("uses persisted sections when present", () => {
10
+ const map = {
11
+ id: "m1",
12
+ name: "Hall",
13
+ stageText: "STAGE",
14
+ sections: [
15
+ { id: "s1", name: "Orchestra", rowKeys: ["Orchestra-A", "Orchestra-B"] },
16
+ { id: "s2", name: "Balcony", rowKeys: ["Balcony-A"] },
17
+ ],
18
+ seatMapData: [
19
+ { id: "1", row: "Orchestra-A", type: "seat", label: "1" },
20
+ { id: "2", row: "Balcony-A", type: "seat", label: "1" },
21
+ ],
22
+ };
23
+ expect(isSeatMapDocument(map)).toBe(true);
24
+ expect(sectionsFromSeatMap(map).map((s) => s.name)).toEqual([
25
+ "Orchestra",
26
+ "Balcony",
27
+ ]);
28
+ });
29
+
30
+ it("derives sections from row prefixes and hallways", () => {
31
+ const map = {
32
+ id: "m1",
33
+ name: "Hall",
34
+ stageText: "STAGE",
35
+ seatMapData: [
36
+ { id: "1", row: "Orchestra-A", type: "seat", label: "1" },
37
+ { id: "2", row: "Orchestra-B", type: "seat", label: "1" },
38
+ { id: "h", row: "empty-1", type: "space", label: "" },
39
+ { id: "3", row: "Balcony-A", type: "seat", label: "1" },
40
+ ],
41
+ };
42
+ const sections = sectionsFromSeatMap(map);
43
+ expect(sections.map((s) => s.name)).toEqual(["Orchestra", "Balcony"]);
44
+ expect(sectionNameForRow(map, "Balcony-A")).toBe("Balcony");
45
+ });
46
+ });
47
+
48
+ describe("findBestAvailableSeats", () => {
49
+ const map = {
50
+ id: "m1",
51
+ name: "Hall",
52
+ stageText: "STAGE",
53
+ seatMapData: [
54
+ { id: "a1", row: "A", type: "seat", label: "1" },
55
+ { id: "a2", row: "A", type: "seat", label: "2" },
56
+ { id: "a3", row: "A", type: "seat", label: "3" },
57
+ { id: "a4", row: "A", type: "seat", label: "4" },
58
+ { id: "b1", row: "B", type: "seat", label: "1" },
59
+ { id: "b2", row: "B", type: "seat", label: "2" },
60
+ ],
61
+ };
62
+
63
+ it("picks contiguous seats in the first row", () => {
64
+ const r = findBestAvailableSeats({
65
+ map,
66
+ allowedSeatIds: ["a1", "a2", "a3", "a4", "b1", "b2"],
67
+ blockedSeatIds: [],
68
+ qty: 2,
69
+ });
70
+ expect(r.ok).toBe(true);
71
+ if (r.ok) {
72
+ expect(r.contiguous).toBe(true);
73
+ expect(r.seatIds).toEqual(["a2", "a3"]);
74
+ }
75
+ });
76
+
77
+ it("skips blocked seats and still finds contiguous", () => {
78
+ const r = findBestAvailableSeats({
79
+ map,
80
+ allowedSeatIds: ["a1", "a2", "a3", "a4"],
81
+ blockedSeatIds: ["a2"],
82
+ qty: 2,
83
+ });
84
+ expect(r.ok).toBe(true);
85
+ if (r.ok) {
86
+ expect(r.seatIds).toEqual(["a3", "a4"]);
87
+ }
88
+ });
89
+
90
+ it("returns non-contiguous when only split fits", () => {
91
+ const sparse = {
92
+ ...map,
93
+ seatMapData: [
94
+ { id: "a1", row: "A", type: "seat", label: "1" },
95
+ { id: "a9", row: "A", type: "seat", label: "9" },
96
+ { id: "b1", row: "B", type: "seat", label: "1" },
97
+ ],
98
+ };
99
+ const r = findBestAvailableSeats({
100
+ map: sparse,
101
+ allowedSeatIds: ["a1", "a9", "b1"],
102
+ blockedSeatIds: [],
103
+ qty: 2,
104
+ });
105
+ expect(r.ok).toBe(true);
106
+ if (r.ok) {
107
+ expect(r.contiguous).toBe(false);
108
+ expect(r.seatIds.length).toBe(2);
109
+ }
110
+ });
111
+ });
@@ -872,6 +872,16 @@ export interface NumberOfTicketsForDate {
872
872
  ticketDateTime: DateTimeArgType;
873
873
  /** Pay-what-you-can tier: buyer-chosen unit price in cents (min = tier.price). */
874
874
  unitPriceCents?: number;
875
+ /**
876
+ * Exact seats for seated tiers (length should match numberOfTickets).
877
+ * Encoded in ticketListStr as a 4th segment (pipe-separated ids).
878
+ */
879
+ seatIds?: string[];
880
+ /**
881
+ * Soft seat hold acquired on "Lock in seats" (Valkey).
882
+ * Encoded in ticketListStr as a 5th segment when present.
883
+ */
884
+ seatHoldId?: string;
875
885
  }
876
886
 
877
887
  export interface TicketTierAvailability {
@@ -570,7 +570,7 @@ type BashEventExtBase = Override<
570
570
  isVerifiedNonprofitHost?: boolean;
571
571
  /**
572
572
  * Computed at request time: true when guests pay exactly the listed ticket price
573
- * (host absorbs processing, no external checkout). Drives "No fees for attendees" badge.
573
+ * (host absorbs processing, no external checkout). Drives "No Platform Fees. Free for Everyone." badge.
574
574
  */
575
575
  guestCheckoutHasNoAddedFees?: boolean;
576
576
  /**
package/src/index.ts CHANGED
@@ -41,6 +41,8 @@ export * from "./bashEventCancellationPolicy.js";
41
41
  export * from "./userReportTypes.js";
42
42
  export * from "./mirroredPrismaEnums.js";
43
43
  export * from "./locationShare.js";
44
+ export * from "./seatMap.js";
45
+ export * from "./seatMapBestAvailable.js";
44
46
  export * from "./utils/featuredDiscoveryGeo.js";
45
47
  export * from "./utils/organizationEntitlements.js";
46
48
  export * from "./serviceTypeLabels.js";