@bash-app/bash-common 30.263.0 → 30.272.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__/requestAuthUser.test.d.ts +2 -0
- package/dist/__tests__/requestAuthUser.test.d.ts.map +1 -0
- package/dist/__tests__/requestAuthUser.test.js +84 -0
- package/dist/__tests__/requestAuthUser.test.js.map +1 -0
- package/dist/__tests__/statusEnums.test.js +1 -0
- package/dist/__tests__/statusEnums.test.js.map +1 -1
- package/dist/definitions.d.ts +1 -0
- package/dist/definitions.d.ts.map +1 -1
- package/dist/definitions.js +1 -0
- package/dist/definitions.js.map +1 -1
- package/dist/extendedSchemas.d.ts +3 -0
- package/dist/extendedSchemas.d.ts.map +1 -1
- package/dist/extendedSchemas.js.map +1 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/mirroredPrismaEnums.d.ts +1 -0
- package/dist/mirroredPrismaEnums.d.ts.map +1 -1
- package/dist/mirroredPrismaEnums.js +1 -0
- package/dist/mirroredPrismaEnums.js.map +1 -1
- package/dist/partnerStoreTypes.d.ts +93 -3
- package/dist/partnerStoreTypes.d.ts.map +1 -1
- package/dist/partnerStoreTypes.js +39 -1
- package/dist/partnerStoreTypes.js.map +1 -1
- package/dist/requestAuthUser.d.ts +36 -0
- package/dist/requestAuthUser.d.ts.map +1 -0
- package/dist/requestAuthUser.js +76 -0
- package/dist/requestAuthUser.js.map +1 -0
- package/dist/utils/__tests__/eventCitySlug.test.d.ts +2 -0
- package/dist/utils/__tests__/eventCitySlug.test.d.ts.map +1 -0
- package/dist/utils/__tests__/eventCitySlug.test.js +12 -0
- package/dist/utils/__tests__/eventCitySlug.test.js.map +1 -0
- package/dist/utils/__tests__/localPartnerHours.test.d.ts +2 -0
- package/dist/utils/__tests__/localPartnerHours.test.d.ts.map +1 -0
- package/dist/utils/__tests__/localPartnerHours.test.js +35 -0
- package/dist/utils/__tests__/localPartnerHours.test.js.map +1 -0
- package/dist/utils/__tests__/orgPromotionalPackageUtils.test.d.ts +2 -0
- package/dist/utils/__tests__/orgPromotionalPackageUtils.test.d.ts.map +1 -0
- package/dist/utils/__tests__/orgPromotionalPackageUtils.test.js +56 -0
- package/dist/utils/__tests__/orgPromotionalPackageUtils.test.js.map +1 -0
- package/dist/utils/eventCitySlug.d.ts +11 -0
- package/dist/utils/eventCitySlug.d.ts.map +1 -0
- package/dist/utils/eventCitySlug.js +20 -0
- package/dist/utils/eventCitySlug.js.map +1 -0
- package/dist/utils/localPartnerHours.d.ts +12 -0
- package/dist/utils/localPartnerHours.d.ts.map +1 -0
- package/dist/utils/localPartnerHours.js +92 -0
- package/dist/utils/localPartnerHours.js.map +1 -0
- package/dist/utils/orgPromotionalPackageUtils.d.ts +75 -0
- package/dist/utils/orgPromotionalPackageUtils.d.ts.map +1 -0
- package/dist/utils/orgPromotionalPackageUtils.js +151 -0
- package/dist/utils/orgPromotionalPackageUtils.js.map +1 -0
- package/package.json +1 -1
- package/prisma/schema.prisma +151 -17
- package/src/__tests__/requestAuthUser.test.ts +120 -0
- package/src/__tests__/statusEnums.test.ts +1 -0
- package/src/definitions.ts +2 -0
- package/src/extendedSchemas.ts +3 -0
- package/src/index.ts +6 -0
- package/src/mirroredPrismaEnums.ts +1 -0
- package/src/partnerStoreTypes.ts +134 -3
- package/src/requestAuthUser.ts +107 -0
- package/src/utils/__tests__/eventCitySlug.test.ts +17 -0
- package/src/utils/__tests__/localPartnerHours.test.ts +45 -0
- package/src/utils/__tests__/orgPromotionalPackageUtils.test.ts +73 -0
- package/src/utils/eventCitySlug.ts +23 -0
- package/src/utils/localPartnerHours.ts +98 -0
- package/src/utils/orgPromotionalPackageUtils.ts +212 -0
package/prisma/schema.prisma
CHANGED
|
@@ -78,6 +78,7 @@ model BashFeedPost {
|
|
|
78
78
|
repostOfPostId String?
|
|
79
79
|
repostOf BashFeedPost? @relation("BashFeedPostRepost", fields: [repostOfPostId], references: [id], onDelete: Cascade)
|
|
80
80
|
repostShells BashFeedPost[] @relation("BashFeedPostRepost")
|
|
81
|
+
visibility BashFeedPostVisibility @default(Public)
|
|
81
82
|
|
|
82
83
|
// Relationships
|
|
83
84
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
@@ -589,6 +590,7 @@ model Invitation {
|
|
|
589
590
|
inviteDate DateTime? @default(now())
|
|
590
591
|
acceptedDate DateTime?
|
|
591
592
|
rejectedDate DateTime?
|
|
593
|
+
revokedDate DateTime?
|
|
592
594
|
maybeDate DateTime?
|
|
593
595
|
isFreeGuest Boolean @default(false)
|
|
594
596
|
sentCount Int @default(1) // Number of times this invitation email has been sent (1 on initial send; incremented on each host-confirmed re-invite for the same email + bash)
|
|
@@ -928,6 +930,7 @@ model BashEvent {
|
|
|
928
930
|
bookingOffers ServiceBookingOffer[]
|
|
929
931
|
promotionBlastEntitlements PromotionBlastEntitlement[]
|
|
930
932
|
promotionBlasts PromotionBlast[]
|
|
933
|
+
orgPromotionalPackages OrgPromotionalPackage[]
|
|
931
934
|
|
|
932
935
|
@@index([templateId])
|
|
933
936
|
@@index([parentEventId])
|
|
@@ -1421,6 +1424,73 @@ model PromotionBlastPushDelivery {
|
|
|
1421
1424
|
@@index([bashEventId])
|
|
1422
1425
|
}
|
|
1423
1426
|
|
|
1427
|
+
// --- Org Promotional Packages (host pays org to endorse event to members) ---
|
|
1428
|
+
enum OrgPromotionalPackageStatus {
|
|
1429
|
+
PENDING_APPROVAL
|
|
1430
|
+
ACTIVE
|
|
1431
|
+
COMPLETED
|
|
1432
|
+
REJECTED
|
|
1433
|
+
EXPIRED
|
|
1434
|
+
REFUNDED
|
|
1435
|
+
}
|
|
1436
|
+
|
|
1437
|
+
model OrgPromotionalPackage {
|
|
1438
|
+
id String @id @default(cuid())
|
|
1439
|
+
createdAt DateTime @default(now())
|
|
1440
|
+
updatedAt DateTime @updatedAt
|
|
1441
|
+
|
|
1442
|
+
organizationId String
|
|
1443
|
+
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
|
1444
|
+
bashEventId String
|
|
1445
|
+
bashEvent BashEvent @relation(fields: [bashEventId], references: [id], onDelete: Cascade)
|
|
1446
|
+
hostUserId String
|
|
1447
|
+
hostUser User @relation("OrgPromoHost", fields: [hostUserId], references: [id], onDelete: Cascade)
|
|
1448
|
+
|
|
1449
|
+
tierId String
|
|
1450
|
+
maxReach Int
|
|
1451
|
+
orgFeeCents Int
|
|
1452
|
+
bashPlatformFeeCents Int
|
|
1453
|
+
totalCents Int
|
|
1454
|
+
|
|
1455
|
+
stripePaymentIntentId String @unique
|
|
1456
|
+
authorizedAt DateTime
|
|
1457
|
+
capturedAt DateTime?
|
|
1458
|
+
status OrgPromotionalPackageStatus @default(PENDING_APPROVAL)
|
|
1459
|
+
|
|
1460
|
+
hostNote String?
|
|
1461
|
+
orgResponseNote String?
|
|
1462
|
+
approvedByUserId String?
|
|
1463
|
+
approvedBy User? @relation("OrgPromoApprover", fields: [approvedByUserId], references: [id], onDelete: SetNull)
|
|
1464
|
+
activatedAt DateTime?
|
|
1465
|
+
|
|
1466
|
+
membersNotifiedAt DateTime?
|
|
1467
|
+
notifyError String?
|
|
1468
|
+
notifyAttemptCount Int @default(0)
|
|
1469
|
+
|
|
1470
|
+
deliveries OrgPromotionalDelivery[]
|
|
1471
|
+
|
|
1472
|
+
@@index([organizationId, status])
|
|
1473
|
+
@@index([bashEventId, status])
|
|
1474
|
+
@@index([hostUserId])
|
|
1475
|
+
@@index([status])
|
|
1476
|
+
}
|
|
1477
|
+
|
|
1478
|
+
model OrgPromotionalDelivery {
|
|
1479
|
+
id String @id @default(cuid())
|
|
1480
|
+
createdAt DateTime @default(now())
|
|
1481
|
+
|
|
1482
|
+
packageId String
|
|
1483
|
+
package OrgPromotionalPackage @relation(fields: [packageId], references: [id], onDelete: Cascade)
|
|
1484
|
+
userId String
|
|
1485
|
+
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
1486
|
+
|
|
1487
|
+
channel String
|
|
1488
|
+
|
|
1489
|
+
@@unique([packageId, userId, channel])
|
|
1490
|
+
@@index([packageId])
|
|
1491
|
+
@@index([userId])
|
|
1492
|
+
}
|
|
1493
|
+
|
|
1424
1494
|
/// USPS carrier-route catalog (Utah MVP; expand for national rollout).
|
|
1425
1495
|
model PostalCarrierRoute {
|
|
1426
1496
|
id String @id @default(cuid())
|
|
@@ -2013,6 +2083,7 @@ model Ticket {
|
|
|
2013
2083
|
allowPromiseToPay Boolean?
|
|
2014
2084
|
status TicketStatus @default(Pending)
|
|
2015
2085
|
isFreeGuest Boolean?
|
|
2086
|
+
isNamedGuest Boolean @default(false)
|
|
2016
2087
|
geoFenceCheckInUnnecessary Boolean?
|
|
2017
2088
|
checkedInAt DateTime?
|
|
2018
2089
|
checkedOutAt DateTime?
|
|
@@ -2791,6 +2862,9 @@ model User {
|
|
|
2791
2862
|
sentBookingOffers ServiceBookingOffer[] @relation("OfferSender")
|
|
2792
2863
|
receivedBookingOffers ServiceBookingOffer[] @relation("OfferRecipient")
|
|
2793
2864
|
promotionBlastEntitlements PromotionBlastEntitlement[] @relation("PromotionBlastPartner")
|
|
2865
|
+
orgPromotionalPackagesHosted OrgPromotionalPackage[] @relation("OrgPromoHost")
|
|
2866
|
+
orgPromotionalPackagesApproved OrgPromotionalPackage[] @relation("OrgPromoApprover")
|
|
2867
|
+
orgPromotionalDeliveries OrgPromotionalDelivery[]
|
|
2794
2868
|
promotionBlastsOwned PromotionBlast[] @relation("PromotionBlastOwner")
|
|
2795
2869
|
promotionBlastsPaused PromotionBlast[] @relation("PromotionBlastPausedBy")
|
|
2796
2870
|
promotionBlastRedemptions PromotionBlastRedemption[]
|
|
@@ -3229,6 +3303,13 @@ model Contact {
|
|
|
3229
3303
|
contactEmail String?
|
|
3230
3304
|
fullName String?
|
|
3231
3305
|
phone String?
|
|
3306
|
+
/// Mailing address line 1 (street number and name). Maps to Lob `address1`.
|
|
3307
|
+
street String?
|
|
3308
|
+
/// Mailing address line 2 (apt, suite, unit). Maps to Lob `address2`.
|
|
3309
|
+
addressLine2 String?
|
|
3310
|
+
city String?
|
|
3311
|
+
state String?
|
|
3312
|
+
zipCode String?
|
|
3232
3313
|
requestToConnectSent DateTime?
|
|
3233
3314
|
requestToConnectAccepted DateTime?
|
|
3234
3315
|
contactOwner User @relation(fields: [contactOwnerId], references: [id], onDelete: Cascade)
|
|
@@ -4172,6 +4253,10 @@ model Organization {
|
|
|
4172
4253
|
|
|
4173
4254
|
smsSendLogs SmsSendLog[]
|
|
4174
4255
|
|
|
4256
|
+
/// Per-tier promotional package rates for external hosts (community / spotlight / featured).
|
|
4257
|
+
promotionalPackageRates Json?
|
|
4258
|
+
orgPromotionalPackages OrgPromotionalPackage[]
|
|
4259
|
+
|
|
4175
4260
|
@@index([ownerId])
|
|
4176
4261
|
@@index([slug])
|
|
4177
4262
|
@@index([parentOrganizationId])
|
|
@@ -5889,6 +5974,15 @@ enum AiApprovalVerdict {
|
|
|
5889
5974
|
Reject
|
|
5890
5975
|
}
|
|
5891
5976
|
|
|
5977
|
+
/// Feed post audience (future: filter feed queries by visibility).
|
|
5978
|
+
enum BashFeedPostVisibility {
|
|
5979
|
+
Public
|
|
5980
|
+
FollowersOnly
|
|
5981
|
+
ContactsOnly
|
|
5982
|
+
ConnectionsOnly
|
|
5983
|
+
OnlyMe
|
|
5984
|
+
}
|
|
5985
|
+
|
|
5892
5986
|
/// How a user is associated with a bash (for BashFeedPost display: "Sarah attended...", "Mike is hosting...")
|
|
5893
5987
|
enum BashAssociationType {
|
|
5894
5988
|
Hosting
|
|
@@ -7561,14 +7655,8 @@ enum MusicGenreType {
|
|
|
7561
7655
|
|
|
7562
7656
|
enum UserRole {
|
|
7563
7657
|
User
|
|
7564
|
-
|
|
7565
|
-
|
|
7566
|
-
Investor
|
|
7567
|
-
LoanProvider
|
|
7568
|
-
VenueProvider
|
|
7569
|
-
ServiceProvider
|
|
7570
|
-
SuperAdmin
|
|
7571
|
-
Exhibitor
|
|
7658
|
+
Admin
|
|
7659
|
+
SuperUser
|
|
7572
7660
|
}
|
|
7573
7661
|
|
|
7574
7662
|
enum UserStatus {
|
|
@@ -7732,6 +7820,7 @@ enum CreditSourceType {
|
|
|
7732
7820
|
PostAfterEvent // First BashFeed post linked to event after it ends
|
|
7733
7821
|
ReferralCodeUsed // Flat bonus for referrer when code drives a ticket/signup
|
|
7734
7822
|
VenueLoyaltyRedemption // BashPoints moved through a VenueLoyaltyRedemption claim/redeem/refund
|
|
7823
|
+
PartnerPromoRedemption // BashPoints spent to unlock a local partner promo code
|
|
7735
7824
|
}
|
|
7736
7825
|
|
|
7737
7826
|
enum ReferralTier {
|
|
@@ -9137,21 +9226,61 @@ enum PartnerTier {
|
|
|
9137
9226
|
Featured
|
|
9138
9227
|
}
|
|
9139
9228
|
|
|
9229
|
+
enum PartnerListingType {
|
|
9230
|
+
Gear
|
|
9231
|
+
LocalService
|
|
9232
|
+
}
|
|
9233
|
+
|
|
9234
|
+
enum LocalServiceCategory {
|
|
9235
|
+
GetReady
|
|
9236
|
+
WearAndStyle
|
|
9237
|
+
EatAndDrink
|
|
9238
|
+
Move
|
|
9239
|
+
Recover
|
|
9240
|
+
Wellness
|
|
9241
|
+
HealthAndEssentials
|
|
9242
|
+
HomeAndLife
|
|
9243
|
+
ContentAndKeepsakes
|
|
9244
|
+
HostShortcuts
|
|
9245
|
+
PerksAndRetail
|
|
9246
|
+
Other
|
|
9247
|
+
}
|
|
9248
|
+
|
|
9140
9249
|
model PartnerBrand {
|
|
9141
|
-
id String
|
|
9250
|
+
id String @id @default(cuid())
|
|
9142
9251
|
name String
|
|
9143
9252
|
logoUrl String?
|
|
9144
9253
|
websiteUrl String?
|
|
9145
|
-
description String?
|
|
9146
|
-
tier PartnerTier
|
|
9147
|
-
isActive Boolean
|
|
9254
|
+
description String? @db.Text
|
|
9255
|
+
tier PartnerTier @default(Standard)
|
|
9256
|
+
isActive Boolean @default(true)
|
|
9148
9257
|
affiliateBaseUrl String?
|
|
9149
9258
|
listingFeeMonthly Int? // cents; null = affiliate-only
|
|
9150
|
-
|
|
9259
|
+
listingType PartnerListingType @default(Gear)
|
|
9260
|
+
address String? @db.Text
|
|
9261
|
+
phone String?
|
|
9262
|
+
citySlug String?
|
|
9263
|
+
stateSlug String?
|
|
9264
|
+
serviceTimings String[] @default([])
|
|
9265
|
+
serviceCategory LocalServiceCategory?
|
|
9266
|
+
promoHeadline String?
|
|
9267
|
+
promoCode String?
|
|
9268
|
+
bookingUrl String?
|
|
9269
|
+
/// Weekly hours: { hours: { Monday: [{ open, close }] }, openDays: { Monday: true } }
|
|
9270
|
+
businessHours Json?
|
|
9271
|
+
timezone String?
|
|
9272
|
+
latitude Float?
|
|
9273
|
+
longitude Float?
|
|
9274
|
+
bashPointsCost Int?
|
|
9275
|
+
clicks Int @default(0)
|
|
9276
|
+
createdAt DateTime @default(now())
|
|
9151
9277
|
products PartnerProduct[]
|
|
9152
9278
|
adSlots PartnerAdSlot[]
|
|
9279
|
+
sourceInquiry PartnerInquiry?
|
|
9153
9280
|
|
|
9154
9281
|
@@index([isActive, tier])
|
|
9282
|
+
@@index([listingType, citySlug])
|
|
9283
|
+
@@index([serviceCategory])
|
|
9155
9284
|
}
|
|
9156
9285
|
|
|
9157
9286
|
model PartnerProduct {
|
|
@@ -9209,12 +9338,17 @@ model PartnerInquiry {
|
|
|
9209
9338
|
website String?
|
|
9210
9339
|
description String @db.Text
|
|
9211
9340
|
categories String[]
|
|
9212
|
-
|
|
9213
|
-
|
|
9214
|
-
|
|
9215
|
-
|
|
9341
|
+
listingType PartnerListingType @default(Gear)
|
|
9342
|
+
city String?
|
|
9343
|
+
status PartnerInquiryStatus @default(Pending)
|
|
9344
|
+
adminNote String? @db.Text
|
|
9345
|
+
createdBrandId String? @unique
|
|
9346
|
+
createdBrand PartnerBrand? @relation(fields: [createdBrandId], references: [id], onDelete: SetNull)
|
|
9347
|
+
createdAt DateTime @default(now())
|
|
9348
|
+
updatedAt DateTime @updatedAt
|
|
9216
9349
|
|
|
9217
9350
|
@@index([status, createdAt])
|
|
9351
|
+
@@index([listingType])
|
|
9218
9352
|
}
|
|
9219
9353
|
|
|
9220
9354
|
// ============================================
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { UserRole } from "@prisma/client";
|
|
2
|
+
import {
|
|
3
|
+
parseRequestAuthFromJwtPayload,
|
|
4
|
+
parseUserRolesFromJwtClaim,
|
|
5
|
+
userHasSuperUserAccess,
|
|
6
|
+
userHasAdminAccess,
|
|
7
|
+
} from "../requestAuthUser.js";
|
|
8
|
+
|
|
9
|
+
describe("parseUserRolesFromJwtClaim", () => {
|
|
10
|
+
it("returns undefined when claim is absent", () => {
|
|
11
|
+
expect(parseUserRolesFromJwtClaim(undefined)).toBeUndefined();
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it("defaults empty array to User", () => {
|
|
15
|
+
expect(parseUserRolesFromJwtClaim([])).toEqual([UserRole.User]);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it("accepts valid enum values", () => {
|
|
19
|
+
expect(parseUserRolesFromJwtClaim([UserRole.User, UserRole.SuperUser])).toEqual([
|
|
20
|
+
UserRole.User,
|
|
21
|
+
UserRole.SuperUser,
|
|
22
|
+
]);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it("rejects non-array and unknown role strings", () => {
|
|
26
|
+
expect(parseUserRolesFromJwtClaim("User")).toBeNull();
|
|
27
|
+
expect(parseUserRolesFromJwtClaim(["NotARealRole"])).toBeNull();
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
describe("parseRequestAuthFromJwtPayload", () => {
|
|
32
|
+
it("parses session-style payload with roles", () => {
|
|
33
|
+
expect(
|
|
34
|
+
parseRequestAuthFromJwtPayload({
|
|
35
|
+
id: "u-1",
|
|
36
|
+
email: "a@test.com",
|
|
37
|
+
roles: [UserRole.SuperUser],
|
|
38
|
+
isSuperUser: false,
|
|
39
|
+
givenName: "Ada",
|
|
40
|
+
}),
|
|
41
|
+
).toEqual({
|
|
42
|
+
id: "u-1",
|
|
43
|
+
email: "a@test.com",
|
|
44
|
+
roles: [UserRole.SuperUser],
|
|
45
|
+
isSuperUser: undefined,
|
|
46
|
+
username: undefined,
|
|
47
|
+
givenName: "Ada",
|
|
48
|
+
familyName: undefined,
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it("returns null when roles claim is absent", () => {
|
|
53
|
+
expect(
|
|
54
|
+
parseRequestAuthFromJwtPayload({
|
|
55
|
+
id: "u-legacy",
|
|
56
|
+
email: "legacy@test.com",
|
|
57
|
+
}),
|
|
58
|
+
).toBeNull();
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it("returns null when identity claims are missing or roles are invalid", () => {
|
|
62
|
+
expect(parseRequestAuthFromJwtPayload(null)).toBeNull();
|
|
63
|
+
expect(parseRequestAuthFromJwtPayload({ email: "a@test.com" })).toBeNull();
|
|
64
|
+
expect(
|
|
65
|
+
parseRequestAuthFromJwtPayload({
|
|
66
|
+
id: "u-1",
|
|
67
|
+
email: "a@test.com",
|
|
68
|
+
roles: ["BadRole"],
|
|
69
|
+
}),
|
|
70
|
+
).toBeNull();
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
describe("userHasSuperUserAccess", () => {
|
|
75
|
+
it("allows SuperUser role or isSuperUser flag", () => {
|
|
76
|
+
expect(
|
|
77
|
+
userHasSuperUserAccess({
|
|
78
|
+
roles: [UserRole.User, UserRole.SuperUser],
|
|
79
|
+
}),
|
|
80
|
+
).toBe(true);
|
|
81
|
+
expect(
|
|
82
|
+
userHasSuperUserAccess({
|
|
83
|
+
roles: [UserRole.User],
|
|
84
|
+
isSuperUser: true,
|
|
85
|
+
}),
|
|
86
|
+
).toBe(true);
|
|
87
|
+
expect(
|
|
88
|
+
userHasSuperUserAccess({
|
|
89
|
+
roles: [UserRole.User],
|
|
90
|
+
isSuperUser: false,
|
|
91
|
+
}),
|
|
92
|
+
).toBe(false);
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
describe("userHasAdminAccess", () => {
|
|
97
|
+
it("allows Admin role", () => {
|
|
98
|
+
expect(
|
|
99
|
+
userHasAdminAccess({ roles: [UserRole.Admin] }),
|
|
100
|
+
).toBe(true);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it("allows SuperUser role", () => {
|
|
104
|
+
expect(
|
|
105
|
+
userHasAdminAccess({ roles: [UserRole.SuperUser] }),
|
|
106
|
+
).toBe(true);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it("allows isSuperUser flag regardless of role", () => {
|
|
110
|
+
expect(
|
|
111
|
+
userHasAdminAccess({ roles: [UserRole.User], isSuperUser: true }),
|
|
112
|
+
).toBe(true);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it("rejects plain User role", () => {
|
|
116
|
+
expect(
|
|
117
|
+
userHasAdminAccess({ roles: [UserRole.User], isSuperUser: false }),
|
|
118
|
+
).toBe(false);
|
|
119
|
+
});
|
|
120
|
+
});
|
package/src/definitions.ts
CHANGED
|
@@ -473,6 +473,8 @@ export const HTTP_CODE_FORBIDDEN = 403 as const;
|
|
|
473
473
|
export const HTTP_CODE_NOT_FOUND = 404 as const;
|
|
474
474
|
export const ERR_UNAUTHORIZED_REQUEST =
|
|
475
475
|
"Unauthorized to perform requested action. Have you logged in?" as const;
|
|
476
|
+
export const ERR_SESSION_EXPIRED =
|
|
477
|
+
"Your session has expired — please refresh or log in again." as const;
|
|
476
478
|
|
|
477
479
|
export const DEFAULT_PRISMA_TTL_SECONDS = 60 as const;
|
|
478
480
|
export const PRISMA_MEDIA_TTL_SECONDS = 60 * 5; // 5 hours
|
package/src/extendedSchemas.ts
CHANGED
|
@@ -1217,6 +1217,9 @@ export interface InvitationExtraData extends Invitation {
|
|
|
1217
1217
|
organizerTitle?: string;
|
|
1218
1218
|
isOwnershipTransfer?: boolean;
|
|
1219
1219
|
includeQRCode?: boolean; // Controls whether QR code should be included in the invitation email
|
|
1220
|
+
sendEmail?: boolean; // When false, skip email notification (default true)
|
|
1221
|
+
existingTicketId?: string; // Link invitation to an existing ticket instead of creating a new one
|
|
1222
|
+
revoke?: boolean; // Host action: set revokedDate
|
|
1220
1223
|
}
|
|
1221
1224
|
|
|
1222
1225
|
export interface AssociatedBashExt extends AssociatedBash {
|
package/src/index.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export * from "./definitions.js";
|
|
2
|
+
export * from "./requestAuthUser.js";
|
|
2
3
|
export * from "./sms/smsTemplates.js";
|
|
3
4
|
export * from "./legalTemplates.js";
|
|
4
5
|
export * from "./utmAttribution.js";
|
|
@@ -153,6 +154,8 @@ export {
|
|
|
153
154
|
PrizePaymentMethod,
|
|
154
155
|
PrizePaymentStatus,
|
|
155
156
|
PartnerTier,
|
|
157
|
+
PartnerListingType,
|
|
158
|
+
LocalServiceCategory,
|
|
156
159
|
PaymentProvider,
|
|
157
160
|
PrizeType,
|
|
158
161
|
ProjectorSetupFormat,
|
|
@@ -276,6 +279,8 @@ export type {
|
|
|
276
279
|
SuggestionUpvote,
|
|
277
280
|
} from "@prisma/client";
|
|
278
281
|
|
|
282
|
+
export * from "./utils/localPartnerHours.js";
|
|
283
|
+
export * from "./utils/eventCitySlug.js";
|
|
279
284
|
export * from "./utils/addressUtils.js";
|
|
280
285
|
export * from "./utils/apiUtils.js";
|
|
281
286
|
export * from "./utils/arrayUtils.js";
|
|
@@ -335,6 +340,7 @@ export * from "./utils/blogUtils.js";
|
|
|
335
340
|
export * from "./utils/entityUtils.js";
|
|
336
341
|
export * from "./utils/flyerUtils.js";
|
|
337
342
|
export * from "./utils/promotionBlastUtils.js";
|
|
343
|
+
export * from "./utils/orgPromotionalPackageUtils.js";
|
|
338
344
|
export * from "./utils/guestSurface.js";
|
|
339
345
|
export * from "./utils/ticketTierSchedule.js";
|
|
340
346
|
export * from "./utils/lobFlyerUtils.js";
|
|
@@ -176,6 +176,7 @@ export const CreditSourceType = {
|
|
|
176
176
|
PostAfterEvent: "PostAfterEvent",
|
|
177
177
|
ReferralCodeUsed: "ReferralCodeUsed",
|
|
178
178
|
VenueLoyaltyRedemption: "VenueLoyaltyRedemption",
|
|
179
|
+
PartnerPromoRedemption: "PartnerPromoRedemption",
|
|
179
180
|
} as const satisfies Record<CreditSourceTypeEnum, CreditSourceTypeEnum>;
|
|
180
181
|
|
|
181
182
|
export type CreditSourceType = CreditSourceTypeEnum;
|
package/src/partnerStoreTypes.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {
|
|
2
|
+
LocalServiceCategory,
|
|
3
|
+
PartnerListingType,
|
|
4
|
+
PartnerTier,
|
|
5
|
+
} from "@prisma/client";
|
|
2
6
|
|
|
3
7
|
/** Product row returned by BashStore / wizard suggestion APIs (no internal counters). */
|
|
4
8
|
export type PartnerProductPublic = {
|
|
@@ -28,9 +32,136 @@ export type PartnerStoreResponse = {
|
|
|
28
32
|
brands: (PartnerBrandSummary & { products: PartnerProductPublic[] })[];
|
|
29
33
|
};
|
|
30
34
|
|
|
31
|
-
|
|
32
|
-
|
|
35
|
+
export type LocalPartnerOfferPublic = {
|
|
36
|
+
id: string;
|
|
37
|
+
name: string;
|
|
38
|
+
description: string | null;
|
|
39
|
+
imageUrl: string | null;
|
|
40
|
+
affiliateUrl: string;
|
|
41
|
+
priceSummary: string | null;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export type LocalPartnerPublic = {
|
|
45
|
+
id: string;
|
|
46
|
+
name: string;
|
|
47
|
+
logoUrl: string | null;
|
|
48
|
+
websiteUrl: string | null;
|
|
49
|
+
description: string | null;
|
|
50
|
+
tier: PartnerTier;
|
|
51
|
+
address: string | null;
|
|
52
|
+
phone: string | null;
|
|
53
|
+
citySlug: string | null;
|
|
54
|
+
stateSlug: string | null;
|
|
55
|
+
serviceTimings: string[];
|
|
56
|
+
serviceCategory: LocalServiceCategory | null;
|
|
57
|
+
promoHeadline: string | null;
|
|
58
|
+
promoCode: string | null;
|
|
59
|
+
bookingUrl: string | null;
|
|
60
|
+
businessHours: unknown;
|
|
61
|
+
timezone: string | null;
|
|
62
|
+
latitude: number | null;
|
|
63
|
+
longitude: number | null;
|
|
64
|
+
bashPointsCost: number | null;
|
|
65
|
+
distanceMiles: number | null;
|
|
66
|
+
offers: LocalPartnerOfferPublic[];
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
/** Gear wizard ad slot suggestion */
|
|
70
|
+
export type PartnerGearSuggestion = {
|
|
71
|
+
kind: "gear";
|
|
33
72
|
slotId: string;
|
|
34
73
|
product: PartnerProductPublic;
|
|
35
74
|
brand: PartnerBrandSummary;
|
|
36
75
|
};
|
|
76
|
+
|
|
77
|
+
/** Local service partner surfaced in wizard or feed contexts */
|
|
78
|
+
export type PartnerLocalSuggestion = {
|
|
79
|
+
kind: "local";
|
|
80
|
+
partner: LocalPartnerPublic;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
/** GET /api/partner/suggestions — at most one suggestion */
|
|
84
|
+
export type PartnerSuggestionResponse = PartnerGearSuggestion | PartnerLocalSuggestion;
|
|
85
|
+
|
|
86
|
+
export type ClaimPartnerPromoResponse = {
|
|
87
|
+
promoCode: string;
|
|
88
|
+
bashPointsCost: number;
|
|
89
|
+
balanceAfter: number;
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
/** GET /api/partner/local-services */
|
|
93
|
+
export type LocalServiceListingResponse = {
|
|
94
|
+
featured: LocalPartnerPublic | null;
|
|
95
|
+
partners: LocalPartnerPublic[];
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
/** Display labels for LocalServiceCategory enum values. */
|
|
99
|
+
export const LOCAL_SERVICE_CATEGORY_LABELS: Record<LocalServiceCategory, string> = {
|
|
100
|
+
GetReady: "Get Ready",
|
|
101
|
+
WearAndStyle: "Wear & Style",
|
|
102
|
+
EatAndDrink: "Eat & Drink",
|
|
103
|
+
Move: "Move",
|
|
104
|
+
Recover: "Recover",
|
|
105
|
+
Wellness: "Wellness",
|
|
106
|
+
HealthAndEssentials: "Health & Essentials",
|
|
107
|
+
HomeAndLife: "Home & Life",
|
|
108
|
+
ContentAndKeepsakes: "Content & Keepsakes",
|
|
109
|
+
HostShortcuts: "Host Shortcuts",
|
|
110
|
+
PerksAndRetail: "Perks & Retail",
|
|
111
|
+
Other: "Other",
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
/** Ordered list for filter chips in BashStore Local Partners tab. */
|
|
115
|
+
export const LOCAL_SERVICE_CATEGORY_ORDER: LocalServiceCategory[] = [
|
|
116
|
+
"GetReady",
|
|
117
|
+
"WearAndStyle",
|
|
118
|
+
"EatAndDrink",
|
|
119
|
+
"Move",
|
|
120
|
+
"Recover",
|
|
121
|
+
"Wellness",
|
|
122
|
+
"HealthAndEssentials",
|
|
123
|
+
"HomeAndLife",
|
|
124
|
+
"ContentAndKeepsakes",
|
|
125
|
+
"HostShortcuts",
|
|
126
|
+
"PerksAndRetail",
|
|
127
|
+
"Other",
|
|
128
|
+
];
|
|
129
|
+
|
|
130
|
+
export const LOCAL_SERVICE_TIMING_OPTIONS = [
|
|
131
|
+
{ value: "pre_event", label: "Pre-event" },
|
|
132
|
+
{ value: "day_of", label: "Day-of" },
|
|
133
|
+
{ value: "post_event", label: "Post-event" },
|
|
134
|
+
] as const;
|
|
135
|
+
|
|
136
|
+
export type LocalServiceTiming = (typeof LOCAL_SERVICE_TIMING_OPTIONS)[number]["value"];
|
|
137
|
+
|
|
138
|
+
export const PARTNER_LISTING_TYPE_LABELS: Record<PartnerListingType, string> = {
|
|
139
|
+
Gear: "Gear",
|
|
140
|
+
LocalService: "Local Service",
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
/** Admin / inquiry payloads for BashStore partner listing requests. */
|
|
144
|
+
export type PartnerInquiryRecord = {
|
|
145
|
+
id: string;
|
|
146
|
+
contactName: string;
|
|
147
|
+
email: string;
|
|
148
|
+
brandName: string;
|
|
149
|
+
website: string | null;
|
|
150
|
+
description: string;
|
|
151
|
+
categories: string[];
|
|
152
|
+
listingType: PartnerListingType;
|
|
153
|
+
city: string | null;
|
|
154
|
+
status: "Pending" | "Reviewed" | "Approved" | "Rejected";
|
|
155
|
+
adminNote: string | null;
|
|
156
|
+
createdBrandId: string | null;
|
|
157
|
+
createdAt: string;
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
/** GET /api/partner/inquiry-status */
|
|
161
|
+
export type PartnerInquiryStatusResponse = {
|
|
162
|
+
brandName: string;
|
|
163
|
+
status: string;
|
|
164
|
+
listingLive: boolean;
|
|
165
|
+
storeUrl: string | null;
|
|
166
|
+
createdBrandId: string | null;
|
|
167
|
+
};
|