@bash-app/bash-common 30.309.0 → 30.310.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__/competitionValidation.test.d.ts +2 -0
- package/dist/__tests__/competitionValidation.test.d.ts.map +1 -0
- package/dist/__tests__/competitionValidation.test.js +28 -0
- package/dist/__tests__/competitionValidation.test.js.map +1 -0
- package/dist/__tests__/definitionsHelpers.test.js +8 -1
- package/dist/__tests__/definitionsHelpers.test.js.map +1 -1
- package/dist/__tests__/membershipDefinitions.test.js +5 -0
- package/dist/__tests__/membershipDefinitions.test.js.map +1 -1
- package/dist/__tests__/sideQuestIdeas.test.js +5 -1
- package/dist/__tests__/sideQuestIdeas.test.js.map +1 -1
- package/dist/__tests__/statusEnums.test.js +7 -0
- package/dist/__tests__/statusEnums.test.js.map +1 -1
- package/dist/competitionValidation.d.ts +11 -2
- package/dist/competitionValidation.d.ts.map +1 -1
- package/dist/competitionValidation.js +40 -2
- package/dist/competitionValidation.js.map +1 -1
- package/dist/definitions.d.ts +7 -0
- package/dist/definitions.d.ts.map +1 -1
- package/dist/definitions.js +10 -0
- package/dist/definitions.js.map +1 -1
- package/dist/extendedSchemas.d.ts +51 -11
- package/dist/extendedSchemas.d.ts.map +1 -1
- package/dist/extendedSchemas.js +5 -0
- package/dist/extendedSchemas.js.map +1 -1
- package/dist/membershipDefinitions.d.ts +2 -0
- package/dist/membershipDefinitions.d.ts.map +1 -1
- package/dist/membershipDefinitions.js +3 -0
- package/dist/membershipDefinitions.js.map +1 -1
- package/dist/mirroredPrismaEnums.d.ts +4 -0
- package/dist/mirroredPrismaEnums.d.ts.map +1 -1
- package/dist/mirroredPrismaEnums.js +4 -0
- package/dist/mirroredPrismaEnums.js.map +1 -1
- package/dist/sideQuestIdeas.d.ts.map +1 -1
- package/dist/sideQuestIdeas.js +2 -2
- package/dist/sideQuestIdeas.js.map +1 -1
- package/dist/sideQuestTypes.d.ts +1 -0
- package/dist/sideQuestTypes.d.ts.map +1 -1
- package/dist/sideQuestTypes.js.map +1 -1
- package/package.json +1 -1
- package/prisma/schema.prisma +109 -0
- package/src/__tests__/competitionValidation.test.ts +43 -0
- package/src/__tests__/definitionsHelpers.test.ts +16 -0
- package/src/__tests__/membershipDefinitions.test.ts +18 -0
- package/src/__tests__/sideQuestIdeas.test.ts +11 -1
- package/src/__tests__/statusEnums.test.ts +7 -0
- package/src/competitionValidation.ts +56 -2
- package/src/definitions.ts +13 -0
- package/src/extendedSchemas.ts +23 -11
- package/src/membershipDefinitions.ts +3 -0
- package/src/mirroredPrismaEnums.ts +4 -0
- package/src/sideQuestIdeas.ts +2 -2
- package/src/sideQuestTypes.ts +1 -0
|
@@ -139,6 +139,13 @@ describe("status enum value sets", () => {
|
|
|
139
139
|
"ReferralCodeUsed",
|
|
140
140
|
"VenueLoyaltyRedemption",
|
|
141
141
|
"PartnerPromoRedemption",
|
|
142
|
+
"SideQuestCompletion",
|
|
143
|
+
"SideQuestMilestone",
|
|
144
|
+
"CommunityQuestUnlock",
|
|
145
|
+
"CompetitionVote",
|
|
146
|
+
"CompetitionParticipation",
|
|
147
|
+
"CompetitionFinalist",
|
|
148
|
+
"CompetitionWin",
|
|
142
149
|
].sort(),
|
|
143
150
|
);
|
|
144
151
|
});
|
|
@@ -17,14 +17,20 @@ export function parseJudgingType(
|
|
|
17
17
|
return value as JudgingType;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
/**
|
|
20
|
+
/**
|
|
21
|
+
* Judging modes disallowed for new competitions: lottery / auction-adjacent
|
|
22
|
+
* (RANDOM_DRAW, HIGHEST_BID), plus METRICS and FIRST_COME which have no
|
|
23
|
+
* winner-resolution implementation yet (dead ends for hosts).
|
|
24
|
+
*/
|
|
21
25
|
export const DISALLOWED_JUDGING_TYPES_FOR_NEW: ReadonlySet<JudgingType> = new Set([
|
|
22
26
|
JudgingType.RANDOM_DRAW,
|
|
23
27
|
JudgingType.HIGHEST_BID,
|
|
28
|
+
JudgingType.METRICS,
|
|
29
|
+
JudgingType.FIRST_COME,
|
|
24
30
|
]);
|
|
25
31
|
|
|
26
32
|
export const DISALLOWED_JUDGING_TYPE_MESSAGE =
|
|
27
|
-
"Random draw
|
|
33
|
+
"Random draw, highest-bid, metrics, and first-come judging are not supported on Bash yet. Use host choice, skill judging, audience vote, or tournament bracket.";
|
|
28
34
|
|
|
29
35
|
export function isDisallowedJudgingTypeForNew(
|
|
30
36
|
judgingType: JudgingType | null | undefined
|
|
@@ -45,6 +51,54 @@ export function assertAllowedJudgingTypeForNew(
|
|
|
45
51
|
export const DEFAULT_COMPETITION_JUDGING_TYPE: JudgingType =
|
|
46
52
|
JudgingType.HOST_CHOOSES;
|
|
47
53
|
|
|
54
|
+
/** Single source of truth for judging-type copy — shared by the host wizard and guest-facing display. */
|
|
55
|
+
export const JUDGING_TYPE_LABELS: Record<JudgingType, string> = {
|
|
56
|
+
[JudgingType.RANDOM_DRAW]: "Drawing (legacy)",
|
|
57
|
+
[JudgingType.HIGHEST_BID]: "Highest Bid (legacy)",
|
|
58
|
+
[JudgingType.HOST_CHOOSES]: "Host Selection",
|
|
59
|
+
[JudgingType.JUDGES]: "Panel of Judges",
|
|
60
|
+
[JudgingType.AUDIENCE_VOTE]: "Audience Vote",
|
|
61
|
+
[JudgingType.METRICS]: "Performance Metrics",
|
|
62
|
+
[JudgingType.FIRST_COME]: "First Come First Serve",
|
|
63
|
+
[JudgingType.BRACKET_TOURNAMENT]: "Bracket Tournament",
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
export const JUDGING_TYPE_DESCRIPTIONS: Record<JudgingType, string> = {
|
|
67
|
+
[JudgingType.RANDOM_DRAW]:
|
|
68
|
+
"This competition uses a legacy random drawing configuration. New competitions on Bash use host choice, skill judging, audience vote, or tournament formats.",
|
|
69
|
+
[JudgingType.HIGHEST_BID]:
|
|
70
|
+
"Legacy auction-style configuration. New competitions on Bash do not support highest-bid judging.",
|
|
71
|
+
[JudgingType.HOST_CHOOSES]:
|
|
72
|
+
"The event host will personally select the winner(s) based on their criteria.",
|
|
73
|
+
[JudgingType.JUDGES]:
|
|
74
|
+
"A panel of judges will evaluate participants based on specific criteria and select the winner(s).",
|
|
75
|
+
[JudgingType.AUDIENCE_VOTE]:
|
|
76
|
+
"Attendees will vote to determine the winner(s). The participant(s) with the most votes win!",
|
|
77
|
+
[JudgingType.METRICS]:
|
|
78
|
+
"Winners are determined by measurable performance metrics and objective criteria.",
|
|
79
|
+
[JudgingType.FIRST_COME]:
|
|
80
|
+
"Winners are determined by order of participation - first to sign up or complete wins!",
|
|
81
|
+
[JudgingType.BRACKET_TOURNAMENT]:
|
|
82
|
+
"Participants compete head-to-head in a tournament bracket. Winners advance through rounds until a champion is determined.",
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
export function getJudgingTypeLabel(
|
|
86
|
+
judgingType: JudgingType | null | undefined
|
|
87
|
+
): string {
|
|
88
|
+
if (!judgingType) return "TBD";
|
|
89
|
+
return JUDGING_TYPE_LABELS[judgingType] ?? "TBD";
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export function getJudgingTypeDescription(
|
|
93
|
+
judgingType: JudgingType | null | undefined
|
|
94
|
+
): string {
|
|
95
|
+
if (!judgingType) return "The judging method has not been determined yet.";
|
|
96
|
+
return (
|
|
97
|
+
JUDGING_TYPE_DESCRIPTIONS[judgingType] ??
|
|
98
|
+
"The judging method has not been determined yet."
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
|
|
48
102
|
export function normalizeJudgingTypeForSave(
|
|
49
103
|
judgingType: JudgingType | null | undefined,
|
|
50
104
|
isExistingLegacy: boolean
|
package/src/definitions.ts
CHANGED
|
@@ -44,6 +44,19 @@ import type { UtmFields } from "./utmAttribution.js";
|
|
|
44
44
|
* values — importing them from `@prisma/client` yields `undefined` and crashes on first
|
|
45
45
|
* property access. These mirrors match the Prisma schema / full client enum strings.
|
|
46
46
|
*/
|
|
47
|
+
/**
|
|
48
|
+
* "Also list as [complementary type]" — a one-time identity-field prefill copy
|
|
49
|
+
* (see Service.complementaryOfServiceId), not an ongoing synced link. Scoped to
|
|
50
|
+
* the Vendors <-> EventServices pairing only (e.g. a food truck that vends
|
|
51
|
+
* publicly at festivals and is also paid a flat fee at private weddings).
|
|
52
|
+
*/
|
|
53
|
+
export const COMPLEMENTARY_SERVICE_TYPE: Partial<
|
|
54
|
+
Record<ServiceTypes, ServiceTypes>
|
|
55
|
+
> = {
|
|
56
|
+
[ServiceTypes.Vendors]: ServiceTypes.EventServices,
|
|
57
|
+
[ServiceTypes.EventServices]: ServiceTypes.Vendors,
|
|
58
|
+
};
|
|
59
|
+
|
|
47
60
|
export const ServiceBookingOfferDirection = {
|
|
48
61
|
HostToProvider: "HostToProvider",
|
|
49
62
|
ProviderToHost: "ProviderToHost",
|
package/src/extendedSchemas.ts
CHANGED
|
@@ -270,14 +270,17 @@ export const PRIVATE_USER_ACCOUNT_TO_SELECT = {
|
|
|
270
270
|
|
|
271
271
|
export interface SponsoredEventExt extends SponsoredEvent {}
|
|
272
272
|
|
|
273
|
+
/** Minimal service identity used wherever a competition prize/offer just needs to point at a listing. */
|
|
274
|
+
export interface ServiceRefLite {
|
|
275
|
+
id: string;
|
|
276
|
+
serviceName: string | null;
|
|
277
|
+
coverPhoto: string | null;
|
|
278
|
+
}
|
|
279
|
+
|
|
273
280
|
export interface PrizeExt extends Prize {
|
|
274
281
|
winner?: PublicUser | null;
|
|
275
282
|
contributor?: PublicUser | null;
|
|
276
|
-
sourceService?:
|
|
277
|
-
id: string;
|
|
278
|
-
serviceName: string | null;
|
|
279
|
-
coverPhoto: string | null;
|
|
280
|
-
} | null;
|
|
283
|
+
sourceService?: ServiceRefLite | null;
|
|
281
284
|
}
|
|
282
285
|
|
|
283
286
|
export interface CompetitionPrizeOfferExt {
|
|
@@ -296,11 +299,7 @@ export interface CompetitionPrizeOfferExt {
|
|
|
296
299
|
createdAt: Date | string;
|
|
297
300
|
respondedAt?: Date | string | null;
|
|
298
301
|
offeredBy?: PublicUser;
|
|
299
|
-
sourceService?:
|
|
300
|
-
id: string;
|
|
301
|
-
serviceName: string | null;
|
|
302
|
-
coverPhoto: string | null;
|
|
303
|
-
} | null;
|
|
302
|
+
sourceService?: ServiceRefLite | null;
|
|
304
303
|
targetPrize?: {
|
|
305
304
|
id: string;
|
|
306
305
|
name: string;
|
|
@@ -309,6 +308,11 @@ export interface CompetitionPrizeOfferExt {
|
|
|
309
308
|
} | null;
|
|
310
309
|
}
|
|
311
310
|
|
|
311
|
+
/** One competition participant row + resolved user; shared by CompetitionExt.participants and the host roster endpoint. */
|
|
312
|
+
export interface CompetitionParticipantExt extends CompetitionParticipant {
|
|
313
|
+
user?: Pick<PublicUser, "uploadedImage" | "image"> | null;
|
|
314
|
+
}
|
|
315
|
+
|
|
312
316
|
/** Competition row + relations; Override keeps new columns visible before consumers refresh Prisma. */
|
|
313
317
|
export type CompetitionExt = Override<
|
|
314
318
|
Competition,
|
|
@@ -320,7 +324,7 @@ export type CompetitionExt = Override<
|
|
|
320
324
|
prizes: PrizeExt[];
|
|
321
325
|
}
|
|
322
326
|
> & {
|
|
323
|
-
participants?:
|
|
327
|
+
participants?: CompetitionParticipantExt[];
|
|
324
328
|
votes?: CompetitionVote[];
|
|
325
329
|
entryTicketTier?: TicketTier | null;
|
|
326
330
|
sponsor?: CompetitionSponsor[];
|
|
@@ -848,6 +852,11 @@ export const SERVICE_DATA_TO_INCLUDE = {
|
|
|
848
852
|
sportsProfile: true,
|
|
849
853
|
}
|
|
850
854
|
}, // Include organization data with member counts
|
|
855
|
+
// Lightweight — just enough for the UI to know a complementary Vendor <-> EventServices
|
|
856
|
+
// profile already exists (see Part B "also list as" flow) without a second fetch.
|
|
857
|
+
complementaryProfiles: {
|
|
858
|
+
select: { id: true, serviceType: true },
|
|
859
|
+
},
|
|
851
860
|
// bookings: {
|
|
852
861
|
// include: SERVICE_BOOKING_PRIVATE_DATA_TO_INCLUDE, //make sure only to include owned bookedDays
|
|
853
862
|
// },
|
|
@@ -1101,6 +1110,9 @@ export interface ServiceExt extends Service {
|
|
|
1101
1110
|
associatedBashesReferencingMe?: AssociatedBashExt[];
|
|
1102
1111
|
associatedServicesReferencingMe?: AssociatedServiceExt[];
|
|
1103
1112
|
|
|
1113
|
+
/** Reverse side of `complementaryOfServiceId` — the "also list as" profile(s) this service already spawned. */
|
|
1114
|
+
complementaryProfiles?: Pick<Service, "id" | "serviceType">[];
|
|
1115
|
+
|
|
1104
1116
|
// googleReviews: GoogleReview[];
|
|
1105
1117
|
|
|
1106
1118
|
// For availability filtering - matches Prisma relation name "bookings"
|
|
@@ -813,6 +813,8 @@ export const MEMBERSHIP_FEATURES = {
|
|
|
813
813
|
SEARCH_PRIORITY: 'search_priority',
|
|
814
814
|
BASIC_ANALYTICS: 'basic_analytics',
|
|
815
815
|
VENDOR_DIRECTORY: 'vendor_directory',
|
|
816
|
+
/** Host-side perk: offer a vendor exclusive-category status for an event when sending a booking request. */
|
|
817
|
+
VENDOR_CATEGORY_EXCLUSIVITY: 'vendor_category_exclusivity',
|
|
816
818
|
TIER_BADGE: 'tier_badge',
|
|
817
819
|
|
|
818
820
|
// Elite features
|
|
@@ -854,6 +856,7 @@ export function hasFeatureAccess(userTier: MembershipTier, feature: string): boo
|
|
|
854
856
|
case MEMBERSHIP_FEATURES.SEARCH_PRIORITY:
|
|
855
857
|
case MEMBERSHIP_FEATURES.BASIC_ANALYTICS:
|
|
856
858
|
case MEMBERSHIP_FEATURES.VENDOR_DIRECTORY:
|
|
859
|
+
case MEMBERSHIP_FEATURES.VENDOR_CATEGORY_EXCLUSIVITY:
|
|
857
860
|
case MEMBERSHIP_FEATURES.TIER_BADGE:
|
|
858
861
|
return tierIndex >= 2; // Pro+
|
|
859
862
|
|
|
@@ -180,6 +180,10 @@ export const CreditSourceType = {
|
|
|
180
180
|
SideQuestCompletion: "SideQuestCompletion",
|
|
181
181
|
SideQuestMilestone: "SideQuestMilestone",
|
|
182
182
|
CommunityQuestUnlock: "CommunityQuestUnlock",
|
|
183
|
+
CompetitionVote: "CompetitionVote",
|
|
184
|
+
CompetitionParticipation: "CompetitionParticipation",
|
|
185
|
+
CompetitionFinalist: "CompetitionFinalist",
|
|
186
|
+
CompetitionWin: "CompetitionWin",
|
|
183
187
|
} as const satisfies Record<CreditSourceTypeEnum, CreditSourceTypeEnum>;
|
|
184
188
|
|
|
185
189
|
export type CreditSourceType = CreditSourceTypeEnum;
|
package/src/sideQuestIdeas.ts
CHANGED
|
@@ -40,7 +40,7 @@ export const SIDE_QUEST_CATEGORY_META: Record<
|
|
|
40
40
|
};
|
|
41
41
|
|
|
42
42
|
/** Phase 1 host-selectable quest types */
|
|
43
|
-
export const SIDE_QUEST_PHASE1_TYPES: SideQuestTypeId[] = ["Qr", "Code"];
|
|
43
|
+
export const SIDE_QUEST_PHASE1_TYPES: SideQuestTypeId[] = ["Qr", "Code", "Vote"];
|
|
44
44
|
|
|
45
45
|
export const SIDE_QUEST_TYPE_META: Record<
|
|
46
46
|
SideQuestTypeId,
|
|
@@ -79,7 +79,7 @@ export const SIDE_QUEST_TYPE_META: Record<
|
|
|
79
79
|
Vote: {
|
|
80
80
|
label: "Vote Quest",
|
|
81
81
|
description: "Completes after voting in a competition.",
|
|
82
|
-
phase1:
|
|
82
|
+
phase1: true,
|
|
83
83
|
},
|
|
84
84
|
Sponsor: {
|
|
85
85
|
label: "Sponsor Quest",
|
package/src/sideQuestTypes.ts
CHANGED