@bash-app/bash-common 30.386.0 → 30.393.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.
- package/dist/__tests__/bashSectionTitleForBashType.test.js +5 -0
- package/dist/__tests__/bashSectionTitleForBashType.test.js.map +1 -1
- package/dist/__tests__/budgetApproval.test.d.ts +2 -0
- package/dist/__tests__/budgetApproval.test.d.ts.map +1 -0
- package/dist/__tests__/budgetApproval.test.js +109 -0
- package/dist/__tests__/budgetApproval.test.js.map +1 -0
- package/dist/__tests__/crewSocialCopy.test.d.ts +2 -0
- package/dist/__tests__/crewSocialCopy.test.d.ts.map +1 -0
- package/dist/__tests__/crewSocialCopy.test.js +21 -0
- package/dist/__tests__/crewSocialCopy.test.js.map +1 -0
- package/dist/__tests__/discoveryScope.test.d.ts +2 -0
- package/dist/__tests__/discoveryScope.test.d.ts.map +1 -0
- package/dist/__tests__/discoveryScope.test.js +40 -0
- package/dist/__tests__/discoveryScope.test.js.map +1 -0
- package/dist/__tests__/scenePulse.test.d.ts +2 -0
- package/dist/__tests__/scenePulse.test.d.ts.map +1 -0
- package/dist/__tests__/scenePulse.test.js +52 -0
- package/dist/__tests__/scenePulse.test.js.map +1 -0
- package/dist/__tests__/suggestedNight.test.d.ts +2 -0
- package/dist/__tests__/suggestedNight.test.d.ts.map +1 -0
- package/dist/__tests__/suggestedNight.test.js +10 -0
- package/dist/__tests__/suggestedNight.test.js.map +1 -0
- package/dist/__tests__/suggestionScore.test.d.ts +2 -0
- package/dist/__tests__/suggestionScore.test.d.ts.map +1 -0
- package/dist/__tests__/suggestionScore.test.js +68 -0
- package/dist/__tests__/suggestionScore.test.js.map +1 -0
- package/dist/__tests__/userTaste.test.d.ts +2 -0
- package/dist/__tests__/userTaste.test.d.ts.map +1 -0
- package/dist/__tests__/userTaste.test.js +21 -0
- package/dist/__tests__/userTaste.test.js.map +1 -0
- package/dist/budgetApproval.d.ts +126 -0
- package/dist/budgetApproval.d.ts.map +1 -0
- package/dist/budgetApproval.js +161 -0
- package/dist/budgetApproval.js.map +1 -0
- package/dist/crewSocialCopy.d.ts +16 -0
- package/dist/crewSocialCopy.d.ts.map +1 -0
- package/dist/crewSocialCopy.js +23 -0
- package/dist/crewSocialCopy.js.map +1 -0
- package/dist/definitions.d.ts +6 -0
- package/dist/definitions.d.ts.map +1 -1
- package/dist/definitions.js +6 -0
- package/dist/definitions.js.map +1 -1
- package/dist/discoveryScope.d.ts +48 -0
- package/dist/discoveryScope.d.ts.map +1 -0
- package/dist/discoveryScope.js +114 -0
- package/dist/discoveryScope.js.map +1 -0
- package/dist/extendedSchemas.d.ts +7 -0
- package/dist/extendedSchemas.d.ts.map +1 -1
- package/dist/extendedSchemas.js +8 -0
- package/dist/extendedSchemas.js.map +1 -1
- package/dist/home.d.ts +6 -1
- package/dist/home.d.ts.map +1 -1
- package/dist/home.js +5 -1
- package/dist/home.js.map +1 -1
- package/dist/hostCrmCrowdPulse.d.ts +2 -0
- package/dist/hostCrmCrowdPulse.d.ts.map +1 -1
- package/dist/hostCrmCrowdPulse.js.map +1 -1
- package/dist/hostCrmSegments.d.ts +6 -0
- package/dist/hostCrmSegments.d.ts.map +1 -1
- package/dist/hostCrmSegments.js.map +1 -1
- package/dist/index.d.ts +9 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +15 -2
- package/dist/index.js.map +1 -1
- package/dist/scenePulse.d.ts +66 -0
- package/dist/scenePulse.d.ts.map +1 -0
- package/dist/scenePulse.js +54 -0
- package/dist/scenePulse.js.map +1 -0
- package/dist/sms/smsTemplates.d.ts +6 -1
- package/dist/sms/smsTemplates.d.ts.map +1 -1
- package/dist/sms/smsTemplates.js +1 -0
- package/dist/sms/smsTemplates.js.map +1 -1
- package/dist/suggestedNight.d.ts +12 -0
- package/dist/suggestedNight.d.ts.map +1 -0
- package/dist/suggestedNight.js +12 -0
- package/dist/suggestedNight.js.map +1 -0
- package/dist/suggestionScore.d.ts +42 -0
- package/dist/suggestionScore.d.ts.map +1 -0
- package/dist/suggestionScore.js +100 -0
- package/dist/suggestionScore.js.map +1 -0
- package/dist/userTaste.d.ts +40 -0
- package/dist/userTaste.d.ts.map +1 -0
- package/dist/userTaste.js +103 -0
- package/dist/userTaste.js.map +1 -0
- package/dist/utils/__tests__/featuredDiscoveryGeo.test.js +9 -1
- package/dist/utils/__tests__/featuredDiscoveryGeo.test.js.map +1 -1
- package/dist/utils/featuredDiscoveryGeo.d.ts +7 -0
- package/dist/utils/featuredDiscoveryGeo.d.ts.map +1 -1
- package/dist/utils/featuredDiscoveryGeo.js +11 -0
- package/dist/utils/featuredDiscoveryGeo.js.map +1 -1
- package/dist/utils/service/__tests__/foodAndBeverageQuote.test.d.ts +2 -0
- package/dist/utils/service/__tests__/foodAndBeverageQuote.test.d.ts.map +1 -0
- package/dist/utils/service/__tests__/foodAndBeverageQuote.test.js +353 -0
- package/dist/utils/service/__tests__/foodAndBeverageQuote.test.js.map +1 -0
- package/dist/utils/service/foodAndBeverageQuote.d.ts +171 -0
- package/dist/utils/service/foodAndBeverageQuote.d.ts.map +1 -0
- package/dist/utils/service/foodAndBeverageQuote.js +467 -0
- package/dist/utils/service/foodAndBeverageQuote.js.map +1 -0
- package/package.json +1 -1
- package/prisma/schema.prisma +185 -53
- package/src/__tests__/bashSectionTitleForBashType.test.ts +10 -0
- package/src/__tests__/budgetApproval.test.ts +153 -0
- package/src/__tests__/crewSocialCopy.test.ts +25 -0
- package/src/__tests__/discoveryScope.test.ts +65 -0
- package/src/__tests__/scenePulse.test.ts +69 -0
- package/src/__tests__/suggestedNight.test.ts +11 -0
- package/src/__tests__/suggestionScore.test.ts +81 -0
- package/src/__tests__/userTaste.test.ts +33 -0
- package/src/budgetApproval.ts +303 -0
- package/src/crewSocialCopy.ts +37 -0
- package/src/definitions.ts +11 -0
- package/src/discoveryScope.ts +170 -0
- package/src/extendedSchemas.ts +8 -0
- package/src/home.ts +15 -0
- package/src/hostCrmCrowdPulse.ts +2 -0
- package/src/hostCrmSegments.ts +6 -0
- package/src/index.ts +18 -3
- package/src/scenePulse.ts +113 -0
- package/src/sms/smsTemplates.ts +6 -0
- package/src/suggestedNight.ts +20 -0
- package/src/suggestionScore.ts +140 -0
- package/src/userTaste.ts +152 -0
- package/src/utils/__tests__/featuredDiscoveryGeo.test.ts +13 -0
- package/src/utils/featuredDiscoveryGeo.ts +15 -0
- package/src/utils/service/__tests__/foodAndBeverageQuote.test.ts +502 -0
- package/src/utils/service/foodAndBeverageQuote.ts +613 -0
package/prisma/schema.prisma
CHANGED
|
@@ -9,38 +9,6 @@ datasource db {
|
|
|
9
9
|
directUrl = env("POSTGRES_URL_NON_POOLING")
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
model Club {
|
|
13
|
-
id String @id @default(cuid())
|
|
14
|
-
name String
|
|
15
|
-
street String
|
|
16
|
-
userId String
|
|
17
|
-
price Int?
|
|
18
|
-
events BashEvent[]
|
|
19
|
-
admin ClubAdmin[]
|
|
20
|
-
members ClubMember[]
|
|
21
|
-
budgets Budget[] @relation("ClubBudgets")
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
model ClubAdmin {
|
|
25
|
-
id String @id @default(cuid())
|
|
26
|
-
userId String
|
|
27
|
-
clubId String
|
|
28
|
-
role ClubAdminRole
|
|
29
|
-
club Club @relation(fields: [clubId], references: [id], onDelete: Cascade)
|
|
30
|
-
admin User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
model ClubMember {
|
|
34
|
-
id String @id @default(cuid())
|
|
35
|
-
userId String
|
|
36
|
-
clubId String
|
|
37
|
-
status ClubMemberStatus
|
|
38
|
-
statusHistory Json
|
|
39
|
-
price Int?
|
|
40
|
-
club Club @relation(fields: [clubId], references: [id], onDelete: Cascade)
|
|
41
|
-
member User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
42
|
-
}
|
|
43
|
-
|
|
44
12
|
model BashComment {
|
|
45
13
|
id String @id @default(cuid())
|
|
46
14
|
creatorId String
|
|
@@ -937,6 +905,9 @@ model BashEvent {
|
|
|
937
905
|
/// Curated cause IDs from `CAUSE_TAGS` (bash-common) for discovery/search later.
|
|
938
906
|
causeTags String[] @default([])
|
|
939
907
|
eventType String @default("Other")
|
|
908
|
+
/// How far the draw goes — orthogonal to eventType. Hosts may set Local/State only.
|
|
909
|
+
discoveryScope DiscoveryScope @default(Unspecified)
|
|
910
|
+
discoveryScopeLabel String?
|
|
940
911
|
timezone String?
|
|
941
912
|
startDateTime DateTime?
|
|
942
913
|
endDateTime DateTime?
|
|
@@ -994,7 +965,6 @@ model BashEvent {
|
|
|
994
965
|
status BashStatus @default(Draft)
|
|
995
966
|
tags String[]
|
|
996
967
|
coverPhoto String?
|
|
997
|
-
clubId String?
|
|
998
968
|
dateTimePublished DateTime?
|
|
999
969
|
includedItems String[]
|
|
1000
970
|
videoLink String?
|
|
@@ -1276,7 +1246,6 @@ model BashEvent {
|
|
|
1276
1246
|
associatedBashesReferencingMe AssociatedBash[]
|
|
1277
1247
|
comments BashComment[]
|
|
1278
1248
|
amountOfGuests AmountOfGuests? @relation(fields: [amountOfGuestsId], references: [id], onDelete: Cascade)
|
|
1279
|
-
club Club? @relation(fields: [clubId], references: [id])
|
|
1280
1249
|
creator User @relation("CreatedEvent", fields: [creatorId], references: [id], onDelete: Cascade)
|
|
1281
1250
|
targetAudience TargetAudience? @relation(fields: [targetAudienceId], references: [id], onDelete: Cascade)
|
|
1282
1251
|
transferredFrom User? @relation("TransferredFrom", fields: [transferredFromId], references: [id])
|
|
@@ -1390,6 +1359,7 @@ model BashEvent {
|
|
|
1390
1359
|
|
|
1391
1360
|
// Organization Relations
|
|
1392
1361
|
budgets Budget[] @relation("EventBudgets")
|
|
1362
|
+
budgetApprovalRequests BudgetApprovalRequest[]
|
|
1393
1363
|
rsvps EventRSVP[] @relation("EventRSVPs")
|
|
1394
1364
|
|
|
1395
1365
|
// Groups & page views (Phases 0–4)
|
|
@@ -1435,6 +1405,7 @@ model BashEvent {
|
|
|
1435
1405
|
locationShareSessions LocationShareSession[]
|
|
1436
1406
|
/// Private Memories vault captures for this bash
|
|
1437
1407
|
memoryCaptures BashMemoryCapture[]
|
|
1408
|
+
suggestedNights SuggestedNight[]
|
|
1438
1409
|
|
|
1439
1410
|
@@index([templateId])
|
|
1440
1411
|
@@index([parentEventId])
|
|
@@ -1442,6 +1413,7 @@ model BashEvent {
|
|
|
1442
1413
|
@@index([hostedByServiceId])
|
|
1443
1414
|
@@index([eventSeriesId])
|
|
1444
1415
|
@@index([status, aiApprovalVerdict])
|
|
1416
|
+
@@index([discoveryScope, startDateTime])
|
|
1445
1417
|
}
|
|
1446
1418
|
|
|
1447
1419
|
/// Lineup / attribution roster for an event (optional act list for checkout tagging).
|
|
@@ -4634,8 +4606,6 @@ model User {
|
|
|
4634
4606
|
blogPosts BlogPost[] @relation("BlogAuthor")
|
|
4635
4607
|
checkouts Checkout[]
|
|
4636
4608
|
waiverAcceptances WaiverAcceptance[]
|
|
4637
|
-
clubAdmins ClubAdmin[]
|
|
4638
|
-
clubMembers ClubMember[]
|
|
4639
4609
|
competitions Competition[]
|
|
4640
4610
|
competitionSponsorships CompetitionSponsor[]
|
|
4641
4611
|
competitionPrizeOffersSubmitted CompetitionPrizeOffer[] @relation("CompetitionPrizeOffersSubmitted")
|
|
@@ -4855,6 +4825,8 @@ model User {
|
|
|
4855
4825
|
approvedBudgets Budget[] @relation("BudgetApprover")
|
|
4856
4826
|
submittedBudgets Budget[] @relation("BudgetSubmitter")
|
|
4857
4827
|
ownedBudgets Budget[] @relation("UserBudgets")
|
|
4828
|
+
budgetApprovalsRequested BudgetApprovalRequest[] @relation("BudgetApprovalRequester")
|
|
4829
|
+
budgetApprovalsAsApprover BudgetApprovalRequest[] @relation("BudgetApprovalApprover")
|
|
4858
4830
|
departmentsHeaded Department[] @relation("DepartmentHead")
|
|
4859
4831
|
/// Enterprise platform (Phase 0-4): internal team members assigned as a named
|
|
4860
4832
|
/// account manager, and org members who submit/approve procurement requests
|
|
@@ -4895,6 +4867,8 @@ model User {
|
|
|
4895
4867
|
// Activity Intent / Experience Discovery
|
|
4896
4868
|
userDiscoveryPreferences UserDiscoveryPreferences?
|
|
4897
4869
|
activityIntents ActivityIntent[]
|
|
4870
|
+
tastePreferences UserTastePreference[]
|
|
4871
|
+
suggestedNights SuggestedNight[]
|
|
4898
4872
|
experienceInvitations ExperienceInvitation[]
|
|
4899
4873
|
experienceOpportunitiesCreated ExperienceOpportunity[] @relation("ExperienceOpportunityCreatedBy")
|
|
4900
4874
|
|
|
@@ -4944,6 +4918,12 @@ model UserPreferences {
|
|
|
4944
4918
|
organizerUpdatesNotify Boolean @default(true)
|
|
4945
4919
|
eventSuggestions Boolean @default(true)
|
|
4946
4920
|
eventReminderNotify Boolean @default(true)
|
|
4921
|
+
/// Opt-in: engine may propose nights (Build my nights strip).
|
|
4922
|
+
suggestedNightsEnabled Boolean @default(false)
|
|
4923
|
+
/// Favorite-nudge email/push. Migrated to match eventReminderNotify.
|
|
4924
|
+
suggestedNightReminderNotify Boolean @default(true)
|
|
4925
|
+
/// Hosts in the guest's CRM may filter blasts by taste chips.
|
|
4926
|
+
hostsMayTargetTaste Boolean @default(true)
|
|
4947
4927
|
newMessageNotify Boolean @default(true)
|
|
4948
4928
|
invitationNotify Boolean @default(true)
|
|
4949
4929
|
commentNotify Boolean @default(true)
|
|
@@ -5053,6 +5033,38 @@ model UserPreferences {
|
|
|
5053
5033
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
5054
5034
|
}
|
|
5055
5035
|
|
|
5036
|
+
model UserTastePreference {
|
|
5037
|
+
id String @id @default(cuid())
|
|
5038
|
+
userId String
|
|
5039
|
+
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
5040
|
+
kind UserTasteKind
|
|
5041
|
+
value String
|
|
5042
|
+
weight Int @default(1)
|
|
5043
|
+
source UserTasteSource @default(Explicit)
|
|
5044
|
+
updatedAt DateTime @updatedAt
|
|
5045
|
+
|
|
5046
|
+
@@unique([userId, kind, value])
|
|
5047
|
+
@@index([userId, kind])
|
|
5048
|
+
}
|
|
5049
|
+
|
|
5050
|
+
model SuggestedNight {
|
|
5051
|
+
id String @id @default(cuid())
|
|
5052
|
+
userId String
|
|
5053
|
+
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
5054
|
+
bashEventId String
|
|
5055
|
+
bashEvent BashEvent @relation(fields: [bashEventId], references: [id], onDelete: Cascade)
|
|
5056
|
+
status SuggestedNightStatus @default(Proposed)
|
|
5057
|
+
reason String[] @default([])
|
|
5058
|
+
proposedAt DateTime @default(now())
|
|
5059
|
+
acceptedAt DateTime?
|
|
5060
|
+
dismissedAt DateTime?
|
|
5061
|
+
remindedAt DateTime?
|
|
5062
|
+
|
|
5063
|
+
@@unique([userId, bashEventId])
|
|
5064
|
+
@@index([userId, status])
|
|
5065
|
+
@@index([bashEventId, status])
|
|
5066
|
+
}
|
|
5067
|
+
|
|
5056
5068
|
model UserFollowing {
|
|
5057
5069
|
id String @id @default(cuid())
|
|
5058
5070
|
userId String
|
|
@@ -5736,6 +5748,10 @@ model EventService {
|
|
|
5736
5748
|
rateUnit String?
|
|
5737
5749
|
minimumChargeCents Int?
|
|
5738
5750
|
minimumQuantity Int?
|
|
5751
|
+
/// Delivery logistics for F&B listings: Pickup | Delivery | FullService.
|
|
5752
|
+
fulfillmentModes String[] @default([])
|
|
5753
|
+
/// Minimum advance-notice days required for F&B bookings (e.g. 7 = one week).
|
|
5754
|
+
leadTimeDays Int?
|
|
5739
5755
|
crowdSize AmountOfGuests? @relation(fields: [crowdSizeId], references: [id], onDelete: Cascade)
|
|
5740
5756
|
serviceRange ServiceRange? @relation(fields: [serviceRangeId], references: [id])
|
|
5741
5757
|
service Service?
|
|
@@ -7259,7 +7275,6 @@ model Budget {
|
|
|
7259
7275
|
// Flexible ownership - at least ONE should be set
|
|
7260
7276
|
organizationId String?
|
|
7261
7277
|
bashEventId String?
|
|
7262
|
-
clubId String?
|
|
7263
7278
|
departmentId String?
|
|
7264
7279
|
userId String? // For personal event budgets
|
|
7265
7280
|
/// Optional: budgets tied to a service profile (vendor/exhibitor/sponsor owner costs).
|
|
@@ -7297,7 +7312,6 @@ model Budget {
|
|
|
7297
7312
|
// Relations
|
|
7298
7313
|
organization Organization? @relation("OrganizationBudgets", fields: [organizationId], references: [id], onDelete: Cascade)
|
|
7299
7314
|
bashEvent BashEvent? @relation("EventBudgets", fields: [bashEventId], references: [id], onDelete: Cascade)
|
|
7300
|
-
club Club? @relation("ClubBudgets", fields: [clubId], references: [id], onDelete: Cascade)
|
|
7301
7315
|
department Department? @relation("DepartmentBudgets", fields: [departmentId], references: [id], onDelete: Cascade)
|
|
7302
7316
|
user User? @relation("UserBudgets", fields: [userId], references: [id], onDelete: Cascade)
|
|
7303
7317
|
service Service? @relation("ServiceBudgets", fields: [serviceId], references: [id], onDelete: Cascade)
|
|
@@ -7308,7 +7322,6 @@ model Budget {
|
|
|
7308
7322
|
|
|
7309
7323
|
@@index([organizationId])
|
|
7310
7324
|
@@index([bashEventId])
|
|
7311
|
-
@@index([clubId])
|
|
7312
7325
|
@@index([departmentId])
|
|
7313
7326
|
@@index([userId])
|
|
7314
7327
|
@@index([serviceId])
|
|
@@ -7316,6 +7329,66 @@ model Budget {
|
|
|
7316
7329
|
@@index([fiscalYear])
|
|
7317
7330
|
}
|
|
7318
7331
|
|
|
7332
|
+
enum BudgetApprovalKind {
|
|
7333
|
+
CapAsk
|
|
7334
|
+
PlanSignOff
|
|
7335
|
+
}
|
|
7336
|
+
|
|
7337
|
+
enum BudgetApprovalStatus {
|
|
7338
|
+
Pending
|
|
7339
|
+
Approved
|
|
7340
|
+
ChangesRequested
|
|
7341
|
+
Declined
|
|
7342
|
+
Cancelled
|
|
7343
|
+
Superseded
|
|
7344
|
+
}
|
|
7345
|
+
|
|
7346
|
+
/// Event-level budget sign-off or pre-plan cap ask. Not per-line Budget.status.
|
|
7347
|
+
model BudgetApprovalRequest {
|
|
7348
|
+
id String @id @default(cuid())
|
|
7349
|
+
bashEventId String
|
|
7350
|
+
kind BudgetApprovalKind
|
|
7351
|
+
status BudgetApprovalStatus @default(Pending)
|
|
7352
|
+
requesterUserId String
|
|
7353
|
+
hostNote String?
|
|
7354
|
+
approverEmail String
|
|
7355
|
+
approverName String?
|
|
7356
|
+
approverUserId String?
|
|
7357
|
+
token String @unique @default(cuid())
|
|
7358
|
+
expiresAt DateTime
|
|
7359
|
+
snapshotJson Json
|
|
7360
|
+
snapshotTotalCents Int
|
|
7361
|
+
authorizedCents Int?
|
|
7362
|
+
decisionNote String?
|
|
7363
|
+
decidedAt DateTime?
|
|
7364
|
+
staleAt DateTime?
|
|
7365
|
+
createdAt DateTime @default(now())
|
|
7366
|
+
updatedAt DateTime @updatedAt
|
|
7367
|
+
|
|
7368
|
+
bashEvent BashEvent @relation(fields: [bashEventId], references: [id], onDelete: Cascade)
|
|
7369
|
+
requester User @relation("BudgetApprovalRequester", fields: [requesterUserId], references: [id], onDelete: Cascade)
|
|
7370
|
+
approverUser User? @relation("BudgetApprovalApprover", fields: [approverUserId], references: [id], onDelete: SetNull)
|
|
7371
|
+
lineNotes BudgetApprovalLineNote[]
|
|
7372
|
+
|
|
7373
|
+
@@index([bashEventId, status])
|
|
7374
|
+
@@index([approverEmail])
|
|
7375
|
+
}
|
|
7376
|
+
|
|
7377
|
+
model BudgetApprovalLineNote {
|
|
7378
|
+
id String @id @default(cuid())
|
|
7379
|
+
requestId String
|
|
7380
|
+
budgetId String?
|
|
7381
|
+
nameSnapshot String
|
|
7382
|
+
categorySnapshot String?
|
|
7383
|
+
allocatedCentsSnapshot Int
|
|
7384
|
+
note String
|
|
7385
|
+
createdAt DateTime @default(now())
|
|
7386
|
+
|
|
7387
|
+
request BudgetApprovalRequest @relation(fields: [requestId], references: [id], onDelete: Cascade)
|
|
7388
|
+
|
|
7389
|
+
@@index([requestId])
|
|
7390
|
+
}
|
|
7391
|
+
|
|
7319
7392
|
enum BudgetContributionKind {
|
|
7320
7393
|
Cash
|
|
7321
7394
|
InKind
|
|
@@ -8506,20 +8579,6 @@ model BashEventMessageRead {
|
|
|
8506
8579
|
@@index([userId])
|
|
8507
8580
|
}
|
|
8508
8581
|
|
|
8509
|
-
enum ClubAdminRole {
|
|
8510
|
-
Owner
|
|
8511
|
-
Admin
|
|
8512
|
-
Staff
|
|
8513
|
-
}
|
|
8514
|
-
|
|
8515
|
-
enum ClubMemberStatus {
|
|
8516
|
-
Active
|
|
8517
|
-
Inactive
|
|
8518
|
-
Canceled
|
|
8519
|
-
Paused
|
|
8520
|
-
Removed
|
|
8521
|
-
}
|
|
8522
|
-
|
|
8523
8582
|
enum TaskStatus {
|
|
8524
8583
|
Open
|
|
8525
8584
|
Accepted
|
|
@@ -8620,6 +8679,10 @@ enum NotificationType {
|
|
|
8620
8679
|
SideQuestWindowOpened // Attendee: a timed Side Quest just went live
|
|
8621
8680
|
/// Attendee/ticket holder: host changed significant bash details (time, place, title, …)
|
|
8622
8681
|
EventDetailsUpdated
|
|
8682
|
+
/// Approver already on Bash: host sent a budget sign-off or cap ask
|
|
8683
|
+
BudgetApprovalRequested
|
|
8684
|
+
/// Host: approver approved, requested changes, or declined a budget request
|
|
8685
|
+
BudgetApprovalDecided
|
|
8623
8686
|
}
|
|
8624
8687
|
|
|
8625
8688
|
/// Opt-in reminder for a scheduled tier release (v1.5).
|
|
@@ -8670,6 +8733,34 @@ enum BashEventSource {
|
|
|
8670
8733
|
Partner // Generic: use sourcePartnerId for partner key (e.g. 'mixlog', custom integrations)
|
|
8671
8734
|
}
|
|
8672
8735
|
|
|
8736
|
+
/// How far an event's draw goes. Orthogonal to BashEventType.
|
|
8737
|
+
enum DiscoveryScope {
|
|
8738
|
+
Local
|
|
8739
|
+
State
|
|
8740
|
+
National
|
|
8741
|
+
International
|
|
8742
|
+
Unspecified
|
|
8743
|
+
}
|
|
8744
|
+
|
|
8745
|
+
enum UserTasteKind {
|
|
8746
|
+
EventType
|
|
8747
|
+
CauseTag
|
|
8748
|
+
MusicGenre
|
|
8749
|
+
DiscoveryScope
|
|
8750
|
+
}
|
|
8751
|
+
|
|
8752
|
+
enum UserTasteSource {
|
|
8753
|
+
Explicit
|
|
8754
|
+
Inferred
|
|
8755
|
+
}
|
|
8756
|
+
|
|
8757
|
+
enum SuggestedNightStatus {
|
|
8758
|
+
Proposed
|
|
8759
|
+
Accepted
|
|
8760
|
+
Dismissed
|
|
8761
|
+
Expired
|
|
8762
|
+
}
|
|
8763
|
+
|
|
8673
8764
|
/// Channel used to create a BashEvent. See BashEvent.creationChannel doc comment.
|
|
8674
8765
|
enum CreationChannel {
|
|
8675
8766
|
Web
|
|
@@ -9490,6 +9581,8 @@ enum FoodAndBeverageSubType {
|
|
|
9490
9581
|
DessertBar
|
|
9491
9582
|
BeverageCart
|
|
9492
9583
|
ConcessionStand
|
|
9584
|
+
CelebrationCake
|
|
9585
|
+
GrazingTable
|
|
9493
9586
|
FoodAndBeverageOther
|
|
9494
9587
|
}
|
|
9495
9588
|
|
|
@@ -9530,6 +9623,7 @@ enum RentalEquipmentSubType {
|
|
|
9530
9623
|
BounceHouse
|
|
9531
9624
|
WaterSlide
|
|
9532
9625
|
CarnivalGames
|
|
9626
|
+
RestroomTrailer
|
|
9533
9627
|
RentalEquipmentOther
|
|
9534
9628
|
}
|
|
9535
9629
|
|
|
@@ -9617,6 +9711,7 @@ enum WellnessSubType {
|
|
|
9617
9711
|
}
|
|
9618
9712
|
|
|
9619
9713
|
enum HostingSupportSubType {
|
|
9714
|
+
Officiant
|
|
9620
9715
|
HostingSupportOther
|
|
9621
9716
|
}
|
|
9622
9717
|
|
|
@@ -9868,6 +9963,24 @@ enum DessertBarFormat {
|
|
|
9868
9963
|
MultiStationDessert
|
|
9869
9964
|
}
|
|
9870
9965
|
|
|
9966
|
+
enum CelebrationCakeFormat {
|
|
9967
|
+
WeddingCake
|
|
9968
|
+
BirthdayCake
|
|
9969
|
+
AnniversaryCake
|
|
9970
|
+
CorporateCake
|
|
9971
|
+
CustomOrder
|
|
9972
|
+
}
|
|
9973
|
+
|
|
9974
|
+
enum GrazingTableFormat {
|
|
9975
|
+
CharcuterieBoard
|
|
9976
|
+
CheeseBoard
|
|
9977
|
+
DessertBoard
|
|
9978
|
+
BreakfastBoard
|
|
9979
|
+
GrazingTableSetup
|
|
9980
|
+
CorporateSpread
|
|
9981
|
+
CustomOrder
|
|
9982
|
+
}
|
|
9983
|
+
|
|
9871
9984
|
enum BeverageCartFormat {
|
|
9872
9985
|
FullBarCart
|
|
9873
9986
|
PremiumBarCart
|
|
@@ -10151,6 +10264,25 @@ enum TablesFormat {
|
|
|
10151
10264
|
CustomTables
|
|
10152
10265
|
}
|
|
10153
10266
|
|
|
10267
|
+
enum RestroomTrailerFormat {
|
|
10268
|
+
LuxuryTrailer
|
|
10269
|
+
StandardPortable
|
|
10270
|
+
ADAAccessible
|
|
10271
|
+
MultiStall
|
|
10272
|
+
HandwashStation
|
|
10273
|
+
}
|
|
10274
|
+
|
|
10275
|
+
enum OfficiantFormat {
|
|
10276
|
+
WeddingCeremony
|
|
10277
|
+
Elopement
|
|
10278
|
+
VowRenewal
|
|
10279
|
+
CommitmentCeremony
|
|
10280
|
+
Interfaith
|
|
10281
|
+
Nondenominational
|
|
10282
|
+
Civil
|
|
10283
|
+
CustomCeremony
|
|
10284
|
+
}
|
|
10285
|
+
|
|
10154
10286
|
enum TentsFormat {
|
|
10155
10287
|
ClearSpanTents
|
|
10156
10288
|
FrameTents
|
|
@@ -52,6 +52,16 @@ describe("bashSectionTitleForBashType", () => {
|
|
|
52
52
|
it("'Ideas' → 'Ideas'", () => {
|
|
53
53
|
expect(bashSectionTitleForBashType("Ideas")).toBe("Ideas");
|
|
54
54
|
});
|
|
55
|
+
|
|
56
|
+
it("scope rows use destination copy", () => {
|
|
57
|
+
expect(bashSectionTitleForBashType("National")).toBe(
|
|
58
|
+
"Across the country"
|
|
59
|
+
);
|
|
60
|
+
expect(bashSectionTitleForBashType("International")).toBe(
|
|
61
|
+
"Worth the flight"
|
|
62
|
+
);
|
|
63
|
+
expect(bashSectionTitleForBashType("CrewGoing")).toBe("The crew's going");
|
|
64
|
+
});
|
|
55
65
|
});
|
|
56
66
|
|
|
57
67
|
describe("BashEventType enum values get pluralized", () => {
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import {
|
|
2
|
+
buildBudgetApprovalSnapshot,
|
|
3
|
+
budgetApprovalSnapshotsMatch,
|
|
4
|
+
eventBudgetApprovalWizardPath,
|
|
5
|
+
formatBudgetCents,
|
|
6
|
+
isBudgetApprovalExpired,
|
|
7
|
+
isValidApproverEmail,
|
|
8
|
+
normalizeApproverEmail,
|
|
9
|
+
parseBudgetApprovalSnapshot,
|
|
10
|
+
resolveApproverDisplayName,
|
|
11
|
+
validateBudgetApprovalDecide,
|
|
12
|
+
} from "../budgetApproval.js";
|
|
13
|
+
|
|
14
|
+
describe("budgetApproval helpers", () => {
|
|
15
|
+
it("normalizes and validates approver emails", () => {
|
|
16
|
+
expect(normalizeApproverEmail(" Pat@Acme.com ")).toBe("pat@acme.com");
|
|
17
|
+
expect(isValidApproverEmail("pat@acme.com")).toBe(true);
|
|
18
|
+
expect(isValidApproverEmail("not-an-email")).toBe(false);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it("hashes snapshots in a stable, order-independent way", () => {
|
|
22
|
+
const a = buildBudgetApprovalSnapshot([
|
|
23
|
+
{ id: "b", name: "DJ", category: null, totalAllocatedCents: 20000 },
|
|
24
|
+
{ id: "a", name: "Venue", category: "Rentals", totalAllocatedCents: 10000 },
|
|
25
|
+
]);
|
|
26
|
+
const b = buildBudgetApprovalSnapshot([
|
|
27
|
+
{ id: "a", name: "Venue", category: "Rentals", totalAllocatedCents: 10000 },
|
|
28
|
+
{ id: "b", name: "DJ", category: null, totalAllocatedCents: 20000 },
|
|
29
|
+
]);
|
|
30
|
+
expect(a.totalCents).toBe(30000);
|
|
31
|
+
expect(a.hash).toBe(b.hash);
|
|
32
|
+
expect(
|
|
33
|
+
budgetApprovalSnapshotsMatch(a.lines, parseBudgetApprovalSnapshot(b.lines))
|
|
34
|
+
).toBe(true);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it("detects drift when an amount changes", () => {
|
|
38
|
+
const original = buildBudgetApprovalSnapshot([
|
|
39
|
+
{ id: "a", name: "Venue", category: null, totalAllocatedCents: 10000 },
|
|
40
|
+
]);
|
|
41
|
+
const changed = buildBudgetApprovalSnapshot([
|
|
42
|
+
{ id: "a", name: "Venue", category: null, totalAllocatedCents: 12000 },
|
|
43
|
+
]);
|
|
44
|
+
expect(budgetApprovalSnapshotsMatch(original.lines, changed.lines)).toBe(
|
|
45
|
+
false
|
|
46
|
+
);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it("requires cents on cap-ask approve and a note on request-changes", () => {
|
|
50
|
+
expect(
|
|
51
|
+
validateBudgetApprovalDecide({
|
|
52
|
+
action: "approve",
|
|
53
|
+
kind: "CapAsk",
|
|
54
|
+
authorizedCents: 0,
|
|
55
|
+
})
|
|
56
|
+
).toEqual({
|
|
57
|
+
ok: false,
|
|
58
|
+
error: "Enter an authorized amount greater than zero.",
|
|
59
|
+
});
|
|
60
|
+
expect(
|
|
61
|
+
validateBudgetApprovalDecide({
|
|
62
|
+
action: "approve",
|
|
63
|
+
kind: "CapAsk",
|
|
64
|
+
authorizedCents: 50000,
|
|
65
|
+
}).ok
|
|
66
|
+
).toBe(true);
|
|
67
|
+
expect(
|
|
68
|
+
validateBudgetApprovalDecide({
|
|
69
|
+
action: "changes",
|
|
70
|
+
kind: "PlanSignOff",
|
|
71
|
+
})
|
|
72
|
+
).toEqual({
|
|
73
|
+
ok: false,
|
|
74
|
+
error: "Add an overall note or a note on at least one line.",
|
|
75
|
+
});
|
|
76
|
+
expect(
|
|
77
|
+
validateBudgetApprovalDecide({
|
|
78
|
+
action: "changes",
|
|
79
|
+
kind: "PlanSignOff",
|
|
80
|
+
lineNotes: [
|
|
81
|
+
{
|
|
82
|
+
nameSnapshot: "Venue",
|
|
83
|
+
allocatedCentsSnapshot: 10000,
|
|
84
|
+
note: "Too high",
|
|
85
|
+
},
|
|
86
|
+
],
|
|
87
|
+
}).ok
|
|
88
|
+
).toBe(true);
|
|
89
|
+
expect(
|
|
90
|
+
validateBudgetApprovalDecide({
|
|
91
|
+
action: "changes",
|
|
92
|
+
kind: "CapAsk",
|
|
93
|
+
lineNotes: [
|
|
94
|
+
{
|
|
95
|
+
nameSnapshot: "Venue",
|
|
96
|
+
allocatedCentsSnapshot: 10000,
|
|
97
|
+
note: "n/a",
|
|
98
|
+
},
|
|
99
|
+
],
|
|
100
|
+
})
|
|
101
|
+
).toEqual({
|
|
102
|
+
ok: false,
|
|
103
|
+
error: "A cap ask has no budget lines to annotate.",
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it("resolves display name decided > hint > email", () => {
|
|
108
|
+
expect(
|
|
109
|
+
resolveApproverDisplayName({
|
|
110
|
+
decidedName: "Pat Chen",
|
|
111
|
+
hostHintName: "Boss",
|
|
112
|
+
email: "pat@acme.com",
|
|
113
|
+
})
|
|
114
|
+
).toBe("Pat Chen");
|
|
115
|
+
expect(
|
|
116
|
+
resolveApproverDisplayName({
|
|
117
|
+
decidedName: " ",
|
|
118
|
+
hostHintName: "Boss",
|
|
119
|
+
email: "pat@acme.com",
|
|
120
|
+
})
|
|
121
|
+
).toBe("Boss");
|
|
122
|
+
expect(
|
|
123
|
+
resolveApproverDisplayName({
|
|
124
|
+
decidedName: null,
|
|
125
|
+
hostHintName: null,
|
|
126
|
+
email: "pat@acme.com",
|
|
127
|
+
})
|
|
128
|
+
).toBe("pat@acme.com");
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it("computes expiry from expiresAt", () => {
|
|
132
|
+
expect(
|
|
133
|
+
isBudgetApprovalExpired("2020-01-01T00:00:00.000Z", new Date("2026-01-01"))
|
|
134
|
+
).toBe(true);
|
|
135
|
+
expect(
|
|
136
|
+
isBudgetApprovalExpired("2030-01-01T00:00:00.000Z", new Date("2026-01-01"))
|
|
137
|
+
).toBe(false);
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it("formats money and the wizard deep link", () => {
|
|
141
|
+
expect(formatBudgetCents(420000)).toBe("$4,200");
|
|
142
|
+
expect(eventBudgetApprovalWizardPath("evt-1")).toContain(
|
|
143
|
+
"/bash-event-wizard/evt-1/"
|
|
144
|
+
);
|
|
145
|
+
expect(eventBudgetApprovalWizardPath("evt-1")).toContain("budgetTab=lines");
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
it("parses invalid snapshot json as empty", () => {
|
|
149
|
+
expect(parseBudgetApprovalSnapshot(null)).toEqual([]);
|
|
150
|
+
expect(parseBudgetApprovalSnapshot("nope")).toEqual([]);
|
|
151
|
+
expect(parseBudgetApprovalSnapshot([{ id: 1 }])).toEqual([]);
|
|
152
|
+
});
|
|
153
|
+
});
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { crewSocialProofCopy } from "../crewSocialCopy.js";
|
|
2
|
+
|
|
3
|
+
describe("crewSocialProofCopy", () => {
|
|
4
|
+
it("names visible crew", () => {
|
|
5
|
+
expect(
|
|
6
|
+
crewSocialProofCopy([
|
|
7
|
+
{ displayName: "Nico", attendanceVisible: true },
|
|
8
|
+
{ displayName: "Petra", attendanceVisible: true },
|
|
9
|
+
]).line
|
|
10
|
+
).toBe("Nico and Petra are going");
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it("does not use a count when names are hidden", () => {
|
|
14
|
+
const copy = crewSocialProofCopy([
|
|
15
|
+
{ displayName: "Sam", attendanceVisible: false },
|
|
16
|
+
{ displayName: "Alex", attendanceVisible: false },
|
|
17
|
+
]);
|
|
18
|
+
expect(copy.line).toBe("Your crew's on this one");
|
|
19
|
+
expect(copy.named).toBe(false);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it("omits the line when nobody is going", () => {
|
|
23
|
+
expect(crewSocialProofCopy([]).line).toBeNull();
|
|
24
|
+
});
|
|
25
|
+
});
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DiscoveryScope,
|
|
3
|
+
inferDiscoveryScopeFromText,
|
|
4
|
+
isHostSettableDiscoveryScope,
|
|
5
|
+
resolveDiscoveryScopeForWrite,
|
|
6
|
+
} from "../discoveryScope.js";
|
|
7
|
+
|
|
8
|
+
describe("discoveryScope", () => {
|
|
9
|
+
it("lets hosts set Local and State only", () => {
|
|
10
|
+
expect(isHostSettableDiscoveryScope(DiscoveryScope.Local)).toBe(true);
|
|
11
|
+
expect(isHostSettableDiscoveryScope(DiscoveryScope.State)).toBe(true);
|
|
12
|
+
expect(isHostSettableDiscoveryScope(DiscoveryScope.National)).toBe(false);
|
|
13
|
+
expect(isHostSettableDiscoveryScope(DiscoveryScope.International)).toBe(
|
|
14
|
+
false
|
|
15
|
+
);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it("infers State from state fair copy", () => {
|
|
19
|
+
expect(inferDiscoveryScopeFromText("Utah State Fair")).toBe(
|
|
20
|
+
DiscoveryScope.State
|
|
21
|
+
);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it("infers National from destination brands", () => {
|
|
25
|
+
expect(inferDiscoveryScopeFromText("EDC Las Vegas")).toBe(
|
|
26
|
+
DiscoveryScope.National
|
|
27
|
+
);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it("infers International from world-tour language", () => {
|
|
31
|
+
expect(inferDiscoveryScopeFromText("Tomorrowland world tour")).toBe(
|
|
32
|
+
DiscoveryScope.International
|
|
33
|
+
);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it("clamps host National without a hard signal", () => {
|
|
37
|
+
expect(
|
|
38
|
+
resolveDiscoveryScopeForWrite({
|
|
39
|
+
requested: DiscoveryScope.National,
|
|
40
|
+
role: "host",
|
|
41
|
+
title: "House party in Sugar House",
|
|
42
|
+
})
|
|
43
|
+
).toBe(DiscoveryScope.Unspecified);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it("allows host National when inference already matches", () => {
|
|
47
|
+
expect(
|
|
48
|
+
resolveDiscoveryScopeForWrite({
|
|
49
|
+
requested: DiscoveryScope.National,
|
|
50
|
+
role: "host",
|
|
51
|
+
title: "Coachella Weekend 1",
|
|
52
|
+
})
|
|
53
|
+
).toBe(DiscoveryScope.National);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it("lets scrapers set National", () => {
|
|
57
|
+
expect(
|
|
58
|
+
resolveDiscoveryScopeForWrite({
|
|
59
|
+
requested: DiscoveryScope.National,
|
|
60
|
+
role: "scraper",
|
|
61
|
+
title: "Random fest",
|
|
62
|
+
})
|
|
63
|
+
).toBe(DiscoveryScope.National);
|
|
64
|
+
});
|
|
65
|
+
});
|