@bash-app/bash-common 30.408.0 → 30.410.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__/partnerDealflow.test.d.ts +2 -0
- package/dist/__tests__/partnerDealflow.test.d.ts.map +1 -0
- package/dist/__tests__/partnerDealflow.test.js +51 -0
- package/dist/__tests__/partnerDealflow.test.js.map +1 -0
- package/dist/__tests__/partnerRevenueShareOptIn.test.d.ts +2 -0
- package/dist/__tests__/partnerRevenueShareOptIn.test.d.ts.map +1 -0
- package/dist/__tests__/partnerRevenueShareOptIn.test.js +55 -0
- package/dist/__tests__/partnerRevenueShareOptIn.test.js.map +1 -0
- package/dist/__tests__/reservedCustomBashEventType.test.d.ts +2 -0
- package/dist/__tests__/reservedCustomBashEventType.test.d.ts.map +1 -0
- package/dist/__tests__/reservedCustomBashEventType.test.js +19 -0
- package/dist/__tests__/reservedCustomBashEventType.test.js.map +1 -0
- package/dist/__tests__/serviceListingDealPreferences.test.d.ts +2 -0
- package/dist/__tests__/serviceListingDealPreferences.test.d.ts.map +1 -0
- package/dist/__tests__/serviceListingDealPreferences.test.js +84 -0
- package/dist/__tests__/serviceListingDealPreferences.test.js.map +1 -0
- package/dist/definitions.d.ts +5 -0
- package/dist/definitions.d.ts.map +1 -1
- package/dist/definitions.js +42 -0
- package/dist/definitions.js.map +1 -1
- package/dist/extendedSchemas.d.ts +78 -0
- package/dist/extendedSchemas.d.ts.map +1 -1
- package/dist/extendedSchemas.js +31 -0
- package/dist/extendedSchemas.js.map +1 -1
- package/dist/homepageSyntheticRows.d.ts +9 -0
- package/dist/homepageSyntheticRows.d.ts.map +1 -0
- package/dist/homepageSyntheticRows.js +26 -0
- package/dist/homepageSyntheticRows.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/utils/service/partnerDealflow.d.ts +12 -0
- package/dist/utils/service/partnerDealflow.d.ts.map +1 -0
- package/dist/utils/service/partnerDealflow.js +33 -0
- package/dist/utils/service/partnerDealflow.js.map +1 -0
- package/dist/utils/service/partnerRevenueShareOptIn.d.ts +18 -0
- package/dist/utils/service/partnerRevenueShareOptIn.d.ts.map +1 -0
- package/dist/utils/service/partnerRevenueShareOptIn.js +46 -0
- package/dist/utils/service/partnerRevenueShareOptIn.js.map +1 -0
- package/dist/utils/service/serviceListingDealPreferences.d.ts +28 -0
- package/dist/utils/service/serviceListingDealPreferences.d.ts.map +1 -0
- package/dist/utils/service/serviceListingDealPreferences.js +126 -0
- package/dist/utils/service/serviceListingDealPreferences.js.map +1 -0
- package/package.json +5 -2
- package/prisma/schema.prisma +58 -0
- package/src/__tests__/partnerDealflow.test.ts +62 -0
- package/src/__tests__/partnerRevenueShareOptIn.test.ts +68 -0
- package/src/__tests__/reservedCustomBashEventType.test.ts +27 -0
- package/src/__tests__/serviceListingDealPreferences.test.ts +112 -0
- package/src/definitions.ts +51 -0
- package/src/extendedSchemas.ts +33 -0
- package/src/homepageSyntheticRows.ts +32 -0
- package/src/index.ts +4 -0
- package/src/utils/service/partnerDealflow.ts +47 -0
- package/src/utils/service/partnerRevenueShareOptIn.ts +70 -0
- package/src/utils/service/serviceListingDealPreferences.ts +184 -0
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import type { ServiceExt } from "../../extendedSchemas";
|
|
2
|
+
import {
|
|
3
|
+
readPartnerDealflowFields,
|
|
4
|
+
serviceListingOpenToInKindDeal,
|
|
5
|
+
} from "./partnerDealflow.js";
|
|
6
|
+
import {
|
|
7
|
+
readPartnerRevenueShareFields,
|
|
8
|
+
REVENUE_SHARE_WITH_HOST_BASIS_LABEL,
|
|
9
|
+
serviceListingOpenToRevenueShare,
|
|
10
|
+
type RevenueShareWithHostBasis,
|
|
11
|
+
} from "./partnerRevenueShareOptIn.js";
|
|
12
|
+
|
|
13
|
+
export type ServiceListingDealBadge = {
|
|
14
|
+
id: string;
|
|
15
|
+
label: string;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export type ServiceListingDealDetailRow = {
|
|
19
|
+
label: string;
|
|
20
|
+
value: string;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
function formatUsdFromCents(cents: number): string {
|
|
24
|
+
const dollars = cents / 100;
|
|
25
|
+
return dollars % 1 === 0 ? `$${dollars.toFixed(0)}` : `$${dollars.toFixed(2)}`;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function minimumCashLabel(deal: ReturnType<typeof readPartnerDealflowFields>): string | null {
|
|
29
|
+
if (deal?.dealRequiresMinimumCash !== true) return null;
|
|
30
|
+
if (typeof deal.dealMinimumCashCents !== "number" || deal.dealMinimumCashCents <= 0) {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
return `${formatUsdFromCents(deal.dealMinimumCashCents)} min cash`;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function truncateOffer(text: string, maxLen: number): string {
|
|
37
|
+
const t = text.trim();
|
|
38
|
+
if (t.length <= maxLen) return t;
|
|
39
|
+
return `${t.slice(0, maxLen - 1).trim()}…`;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** Compact chips for cards and list rows. */
|
|
43
|
+
export function getServiceListingDealBadges(
|
|
44
|
+
service: ServiceExt
|
|
45
|
+
): ServiceListingDealBadge[] {
|
|
46
|
+
const badges: ServiceListingDealBadge[] = [];
|
|
47
|
+
const deal = readPartnerDealflowFields(service);
|
|
48
|
+
|
|
49
|
+
if (serviceListingOpenToRevenueShare(service)) {
|
|
50
|
+
badges.push({ id: "rev-share", label: "Rev share" });
|
|
51
|
+
}
|
|
52
|
+
if (serviceListingOpenToInKindDeal(service)) {
|
|
53
|
+
badges.push({ id: "in-kind", label: "In-kind" });
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const minCash = minimumCashLabel(deal);
|
|
57
|
+
if (minCash) {
|
|
58
|
+
badges.push({ id: "min-cash", label: minCash });
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const hostBidOpen =
|
|
62
|
+
service.vendor?.preferences?.openToHostBids === true ||
|
|
63
|
+
service.exhibitor?.openToHostBids === true ||
|
|
64
|
+
service.sponsor?.openToHostBids === true;
|
|
65
|
+
if (hostBidOpen) {
|
|
66
|
+
badges.push({ id: "host-bids", label: "Host bids" });
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return badges;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** Longer copy for public detail pages. */
|
|
73
|
+
export function getServiceListingDealDetailRows(
|
|
74
|
+
service: ServiceExt
|
|
75
|
+
): ServiceListingDealDetailRow[] {
|
|
76
|
+
const rows: ServiceListingDealDetailRow[] = [];
|
|
77
|
+
const deal = readPartnerDealflowFields(service);
|
|
78
|
+
const rev = readPartnerRevenueShareFields(service);
|
|
79
|
+
const venue = service.venue;
|
|
80
|
+
|
|
81
|
+
if (venue?.revenueShareEnabled === true && venue.revenueShareHostPercentage != null) {
|
|
82
|
+
rows.push({
|
|
83
|
+
label: "Venue revenue share",
|
|
84
|
+
value: `Host keeps ${venue.revenueShareHostPercentage}% of agreed ticket or bar revenue.`,
|
|
85
|
+
});
|
|
86
|
+
} else if (rev?.openToRevenueShareWithHost === true) {
|
|
87
|
+
const pct = rev.revenueShareWithHostPercentage;
|
|
88
|
+
const basis = rev.revenueShareWithHostBasis as RevenueShareWithHostBasis | null;
|
|
89
|
+
const basisLabel =
|
|
90
|
+
basis && basis in REVENUE_SHARE_WITH_HOST_BASIS_LABEL
|
|
91
|
+
? REVENUE_SHARE_WITH_HOST_BASIS_LABEL[basis]
|
|
92
|
+
: null;
|
|
93
|
+
rows.push({
|
|
94
|
+
label: "Revenue share with host",
|
|
95
|
+
value:
|
|
96
|
+
typeof pct === "number"
|
|
97
|
+
? `Shares ${pct}% with the host${basisLabel ? ` (${basisLabel.toLowerCase()})` : ""}.`
|
|
98
|
+
: "Open to sharing revenue with the host (percentage not set).",
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (serviceListingOpenToInKindDeal(service) && deal?.inKindDealOfferText) {
|
|
103
|
+
const est =
|
|
104
|
+
typeof deal.inKindEstimatedValueCents === "number" &&
|
|
105
|
+
deal.inKindEstimatedValueCents > 0
|
|
106
|
+
? ` Approx. value ${formatUsdFromCents(deal.inKindEstimatedValueCents)}.`
|
|
107
|
+
: "";
|
|
108
|
+
rows.push({
|
|
109
|
+
label: "In-kind / trade offer",
|
|
110
|
+
value: `${deal.inKindDealOfferText.trim()}${est}`,
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const minCash = minimumCashLabel(deal);
|
|
115
|
+
if (minCash) {
|
|
116
|
+
rows.push({
|
|
117
|
+
label: "Minimum cash on hybrid deals",
|
|
118
|
+
value: `Requires ${minCash.replace(" min cash", "")} minimum cash alongside rev-share or in-kind terms so hosts know you're serious.`,
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return rows;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/** Card preview line for in-kind (truncated). */
|
|
126
|
+
export function getServiceListingInKindPreview(
|
|
127
|
+
service: ServiceExt,
|
|
128
|
+
maxLen = 80
|
|
129
|
+
): string | null {
|
|
130
|
+
const deal = readPartnerDealflowFields(service);
|
|
131
|
+
if (!serviceListingOpenToInKindDeal(service) || !deal?.inKindDealOfferText) {
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
return truncateOffer(deal.inKindDealOfferText, maxLen);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export type PartnerDealflowBookingSnapshot = {
|
|
138
|
+
openToRevenueShareWithHostSnapshot?: boolean;
|
|
139
|
+
revenueShareWithHostPercentageSnapshot?: number | null;
|
|
140
|
+
revenueShareWithHostBasisSnapshot?: string | null;
|
|
141
|
+
openToInKindDealsSnapshot?: boolean;
|
|
142
|
+
inKindDealOfferTextSnapshot?: string | null;
|
|
143
|
+
inKindEstimatedValueCentsSnapshot?: number | null;
|
|
144
|
+
dealRequiresMinimumCashSnapshot?: boolean;
|
|
145
|
+
dealMinimumCashCentsSnapshot?: number | null;
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
/** Copy live listing deal prefs onto a booking at confirmation time. */
|
|
149
|
+
export function buildPartnerDealflowBookingSnapshot(
|
|
150
|
+
service: ServiceExt
|
|
151
|
+
): PartnerDealflowBookingSnapshot {
|
|
152
|
+
const rev = readPartnerRevenueShareFields(service);
|
|
153
|
+
const deal = readPartnerDealflowFields(service);
|
|
154
|
+
const venue = service.venue;
|
|
155
|
+
|
|
156
|
+
const snap: PartnerDealflowBookingSnapshot = {};
|
|
157
|
+
|
|
158
|
+
if (venue?.revenueShareEnabled === true) {
|
|
159
|
+
snap.openToRevenueShareWithHostSnapshot = true;
|
|
160
|
+
snap.revenueShareWithHostPercentageSnapshot =
|
|
161
|
+
venue.revenueShareHostPercentage ?? null;
|
|
162
|
+
snap.revenueShareWithHostBasisSnapshot = venue.revenueShareBasis ?? null;
|
|
163
|
+
} else if (rev?.openToRevenueShareWithHost === true) {
|
|
164
|
+
snap.openToRevenueShareWithHostSnapshot = true;
|
|
165
|
+
snap.revenueShareWithHostPercentageSnapshot =
|
|
166
|
+
rev.revenueShareWithHostPercentage ?? null;
|
|
167
|
+
snap.revenueShareWithHostBasisSnapshot =
|
|
168
|
+
rev.revenueShareWithHostBasis ?? null;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (deal?.openToInKindDeals === true) {
|
|
172
|
+
snap.openToInKindDealsSnapshot = true;
|
|
173
|
+
snap.inKindDealOfferTextSnapshot = deal.inKindDealOfferText?.trim() ?? null;
|
|
174
|
+
snap.inKindEstimatedValueCentsSnapshot =
|
|
175
|
+
deal.inKindEstimatedValueCents ?? null;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (deal?.dealRequiresMinimumCash === true) {
|
|
179
|
+
snap.dealRequiresMinimumCashSnapshot = true;
|
|
180
|
+
snap.dealMinimumCashCentsSnapshot = deal.dealMinimumCashCents ?? null;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
return snap;
|
|
184
|
+
}
|