@bash-app/bash-common 30.403.0 → 30.408.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__/definitionsHelpers.test.js +34 -1
- package/dist/__tests__/definitionsHelpers.test.js.map +1 -1
- package/dist/definitions.d.ts +59 -4
- package/dist/definitions.d.ts.map +1 -1
- package/dist/definitions.js +238 -152
- package/dist/definitions.js.map +1 -1
- package/dist/extendedSchemas.d.ts +39 -5
- package/dist/extendedSchemas.d.ts.map +1 -1
- package/dist/extendedSchemas.js +4 -0
- package/dist/extendedSchemas.js.map +1 -1
- package/dist/sideQuestTypes.d.ts +1 -1
- package/dist/sideQuestTypes.d.ts.map +1 -1
- package/package.json +1 -1
- package/prisma/schema.prisma +61 -4
- package/src/__tests__/definitionsHelpers.test.ts +50 -0
- package/src/definitions.ts +276 -153
- package/src/extendedSchemas.ts +38 -5
- package/src/sideQuestTypes.ts +1 -1
|
@@ -15,6 +15,16 @@ import {
|
|
|
15
15
|
COMPLEMENTARY_SERVICE_TYPE,
|
|
16
16
|
complementaryServiceTypeFor,
|
|
17
17
|
ServiceTypes,
|
|
18
|
+
isIntroIntentId,
|
|
19
|
+
INTRO_INTENT_OPTIONS,
|
|
20
|
+
isLocusOfControlId,
|
|
21
|
+
LOCUS_OF_CONTROL_OPTIONS,
|
|
22
|
+
hasSensingIntuitionOverlap,
|
|
23
|
+
personalityOverlapHint,
|
|
24
|
+
normalizePersonalityType,
|
|
25
|
+
isInterestExpressionMode,
|
|
26
|
+
sharedIntroIntentHint,
|
|
27
|
+
locusOfControlShortLabel,
|
|
18
28
|
} from "../definitions.js";
|
|
19
29
|
|
|
20
30
|
describe("definitions helpers", () => {
|
|
@@ -183,4 +193,44 @@ describe("definitions helpers", () => {
|
|
|
183
193
|
).toBeUndefined();
|
|
184
194
|
});
|
|
185
195
|
});
|
|
196
|
+
|
|
197
|
+
describe("Intros intents", () => {
|
|
198
|
+
test("accepts the three platonic/professional intent ids", () => {
|
|
199
|
+
expect(INTRO_INTENT_OPTIONS.map((option) => option.id)).toEqual([
|
|
200
|
+
"friends",
|
|
201
|
+
"professional",
|
|
202
|
+
"mentorship",
|
|
203
|
+
]);
|
|
204
|
+
expect(isIntroIntentId("friends")).toBe(true);
|
|
205
|
+
expect(isIntroIntentId("dating")).toBe(false);
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
test("normalizes personality type and detects S/N overlap", () => {
|
|
209
|
+
expect(normalizePersonalityType("enfp!")).toBe("ENFP");
|
|
210
|
+
expect(normalizePersonalityType(" ")).toBeNull();
|
|
211
|
+
expect(hasSensingIntuitionOverlap("ENFP", "INTJ")).toBe(true);
|
|
212
|
+
expect(hasSensingIntuitionOverlap("ESFP", "INTJ")).toBe(false);
|
|
213
|
+
expect(personalityOverlapHint("ENFP", "INTJ")).toBe(
|
|
214
|
+
"You both picked N — good icebreaker."
|
|
215
|
+
);
|
|
216
|
+
expect(isLocusOfControlId("internal")).toBe(true);
|
|
217
|
+
expect(isLocusOfControlId("random")).toBe(false);
|
|
218
|
+
expect(LOCUS_OF_CONTROL_OPTIONS.map((option) => option.id)).toEqual([
|
|
219
|
+
"internal",
|
|
220
|
+
"external",
|
|
221
|
+
"mixed",
|
|
222
|
+
]);
|
|
223
|
+
expect(isInterestExpressionMode("named")).toBe(true);
|
|
224
|
+
expect(isInterestExpressionMode("crush")).toBe(false);
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
test("shared intro intent and locus labels stay conversational", () => {
|
|
228
|
+
expect(
|
|
229
|
+
sharedIntroIntentHint(["friends", "mentorship"], ["professional", "friends"])
|
|
230
|
+
).toBe("You're both here for making friends.");
|
|
231
|
+
expect(sharedIntroIntentHint(["friends"], ["professional"])).toBeNull();
|
|
232
|
+
expect(locusOfControlShortLabel("internal")).toBe("Internal");
|
|
233
|
+
expect(locusOfControlShortLabel("nope")).toBeNull();
|
|
234
|
+
});
|
|
235
|
+
});
|
|
186
236
|
});
|
package/src/definitions.ts
CHANGED
|
@@ -4,7 +4,6 @@ import {
|
|
|
4
4
|
Contact,
|
|
5
5
|
DietaryOption,
|
|
6
6
|
EntertainmentServiceType,
|
|
7
|
-
IncomeRange,
|
|
8
7
|
JudgingType,
|
|
9
8
|
MembershipTier,
|
|
10
9
|
MusicGenreType,
|
|
@@ -17,6 +16,7 @@ import {
|
|
|
17
16
|
} from "@prisma/client";
|
|
18
17
|
import type {
|
|
19
18
|
AgePolicy as AgePolicyEnum,
|
|
19
|
+
IncomeRange,
|
|
20
20
|
BashPassTier,
|
|
21
21
|
BashEventDressTags,
|
|
22
22
|
BashEventVibeTags,
|
|
@@ -134,6 +134,109 @@ export const AgePolicy = {
|
|
|
134
134
|
|
|
135
135
|
export type AgePolicy = AgePolicyEnum;
|
|
136
136
|
|
|
137
|
+
export const INTRO_INTENT_OPTIONS = [
|
|
138
|
+
{ id: "friends", label: "Making friends" },
|
|
139
|
+
{ id: "professional", label: "Professional networking" },
|
|
140
|
+
{ id: "mentorship", label: "Finding a mentor or mentee" },
|
|
141
|
+
] as const;
|
|
142
|
+
|
|
143
|
+
export type IntroIntentId = (typeof INTRO_INTENT_OPTIONS)[number]["id"];
|
|
144
|
+
|
|
145
|
+
export const INTRO_INTENT_IDS: readonly IntroIntentId[] =
|
|
146
|
+
INTRO_INTENT_OPTIONS.map((option) => option.id);
|
|
147
|
+
|
|
148
|
+
export function isIntroIntentId(value: string): value is IntroIntentId {
|
|
149
|
+
return (INTRO_INTENT_IDS as readonly string[]).includes(value);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export const LOCUS_OF_CONTROL_OPTIONS = [
|
|
153
|
+
{ id: "internal", label: "Internal — I shape my own outcomes" },
|
|
154
|
+
{ id: "external", label: "External — circumstances shape outcomes" },
|
|
155
|
+
{ id: "mixed", label: "Mixed — bit of both" },
|
|
156
|
+
] as const;
|
|
157
|
+
|
|
158
|
+
export type LocusOfControlId = (typeof LOCUS_OF_CONTROL_OPTIONS)[number]["id"];
|
|
159
|
+
|
|
160
|
+
export const LOCUS_OF_CONTROL_IDS: readonly LocusOfControlId[] =
|
|
161
|
+
LOCUS_OF_CONTROL_OPTIONS.map((option) => option.id);
|
|
162
|
+
|
|
163
|
+
export function isLocusOfControlId(value: string): value is LocusOfControlId {
|
|
164
|
+
return (LOCUS_OF_CONTROL_IDS as readonly string[]).includes(value);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export const PERSONALITY_TYPE_MAX_LENGTH = 4;
|
|
168
|
+
|
|
169
|
+
export function normalizePersonalityType(
|
|
170
|
+
value: string | null | undefined
|
|
171
|
+
): string | null {
|
|
172
|
+
if (!value) return null;
|
|
173
|
+
const normalized = value
|
|
174
|
+
.toUpperCase()
|
|
175
|
+
.replace(/[^A-Z]/g, "")
|
|
176
|
+
.slice(0, PERSONALITY_TYPE_MAX_LENGTH);
|
|
177
|
+
return normalized.length > 0 ? normalized : null;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/** True if two MBTI codes share the same second letter (S/N axis). */
|
|
181
|
+
export function hasSensingIntuitionOverlap(a: string, b: string): boolean {
|
|
182
|
+
return (
|
|
183
|
+
a.length >= 2 &&
|
|
184
|
+
b.length >= 2 &&
|
|
185
|
+
a[1].toUpperCase() === b[1].toUpperCase()
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
export function personalityOverlapHint(
|
|
190
|
+
a: string | null | undefined,
|
|
191
|
+
b: string | null | undefined
|
|
192
|
+
): string | null {
|
|
193
|
+
if (!a || !b || !hasSensingIntuitionOverlap(a, b)) return null;
|
|
194
|
+
return `You both picked ${a[1].toUpperCase()} — good icebreaker.`;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
export function sharedIntroIntentHint(
|
|
198
|
+
viewerIntents: readonly string[] | null | undefined,
|
|
199
|
+
guestIntents: readonly string[] | null | undefined
|
|
200
|
+
): string | null {
|
|
201
|
+
if (!viewerIntents?.length || !guestIntents?.length) return null;
|
|
202
|
+
const guest = new Set(guestIntents);
|
|
203
|
+
const match = viewerIntents.find((id) => guest.has(id));
|
|
204
|
+
if (!match || !isIntroIntentId(match)) return null;
|
|
205
|
+
const label = INTRO_INTENT_OPTIONS.find((option) => option.id === match)?.label;
|
|
206
|
+
return label ? `You're both here for ${label.toLowerCase()}.` : null;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
export function locusOfControlShortLabel(
|
|
210
|
+
id: string | null | undefined
|
|
211
|
+
): string | null {
|
|
212
|
+
if (!id || !isLocusOfControlId(id)) return null;
|
|
213
|
+
if (id === "internal") return "Internal";
|
|
214
|
+
if (id === "external") return "External";
|
|
215
|
+
return "Mixed";
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
export const INTEREST_EXPRESSION_MODES = ["named", "anonymous"] as const;
|
|
219
|
+
|
|
220
|
+
export type InterestExpressionMode = (typeof INTEREST_EXPRESSION_MODES)[number];
|
|
221
|
+
|
|
222
|
+
export function isInterestExpressionMode(
|
|
223
|
+
value: string
|
|
224
|
+
): value is InterestExpressionMode {
|
|
225
|
+
return (INTEREST_EXPRESSION_MODES as readonly string[]).includes(value);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
export const INTROS_DISCLAIMER =
|
|
229
|
+
"Intros connects you only with people who have also explicitly opted in. Bash does not conduct background checks, verify identities beyond basic account registration, or screen users for any purpose. This feature supports platonic and professional connections only — romantic or sexual contact is a violation of our Community Guidelines. Always meet at the event, in public. Use the Report button if anyone makes you uncomfortable. By turning on Intros, you agree that Bash is not responsible for interactions between users.";
|
|
230
|
+
|
|
231
|
+
export const INTROS_DISCLAIMER_SHORT =
|
|
232
|
+
"Bash does not background-check users. Meet at the event, in public. Romantic or sexual contact is prohibited. Bash is not responsible for interactions between users.";
|
|
233
|
+
|
|
234
|
+
/** @deprecated Use INTROS_DISCLAIMER */
|
|
235
|
+
export const SCENE_INTROS_DISCLAIMER = INTROS_DISCLAIMER;
|
|
236
|
+
|
|
237
|
+
/** @deprecated Use INTROS_DISCLAIMER_SHORT */
|
|
238
|
+
export const SCENE_INTROS_DISCLAIMER_SHORT = INTROS_DISCLAIMER_SHORT;
|
|
239
|
+
|
|
137
240
|
export const PASSWORD_MIN_LENGTH = 8 as const;
|
|
138
241
|
export const PASSWORD_REQUIREMENTS_REGEX = new RegExp(
|
|
139
242
|
String.raw`^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&^#])[A-Za-z\d@$!%*?&^#]{${PASSWORD_MIN_LENGTH},}$`
|
|
@@ -602,8 +705,8 @@ export const BASH_EVENT_WIZARD_WHAT_SUBSTEP = {
|
|
|
602
705
|
} as const;
|
|
603
706
|
|
|
604
707
|
export const BASH_EVENT_WIZARD_WHERE_SUBSTEP = {
|
|
605
|
-
|
|
606
|
-
|
|
708
|
+
UPLOAD_MEDIA: 0,
|
|
709
|
+
LOCATION: 1,
|
|
607
710
|
} as const;
|
|
608
711
|
|
|
609
712
|
export const BASH_EVENT_WIZARD_WHEN_SUBSTEP = {
|
|
@@ -1366,6 +1469,8 @@ export interface StripeConfirmPaymentResult {
|
|
|
1366
1469
|
ticketsSubtotalCents?: number;
|
|
1367
1470
|
/** Actual amount charged to the guest (cents), including pass-through fees when applicable */
|
|
1368
1471
|
totalPaidCents?: number;
|
|
1472
|
+
/** True when this is the buyer's first ticket purchase on Bash ever. */
|
|
1473
|
+
isFirstTicketPurchase?: boolean;
|
|
1369
1474
|
}
|
|
1370
1475
|
|
|
1371
1476
|
export interface IMediaUploadArgs {
|
|
@@ -1649,96 +1754,101 @@ export type BashEventTypeToStringType = {
|
|
|
1649
1754
|
[key in BashEventType]: string;
|
|
1650
1755
|
};
|
|
1651
1756
|
export { BashEventType };
|
|
1757
|
+
/**
|
|
1758
|
+
* Keys are string literals (not `BashEventType.*`) so this module can load
|
|
1759
|
+
* when Jest's `@prisma/client` cache is briefly incomplete after resetModules
|
|
1760
|
+
* (see api/jest.setup.afterEnv.cjs). Same pattern as SERVICE_TYPE_LABELS.
|
|
1761
|
+
*/
|
|
1652
1762
|
export const BashEventTypeToString: BashEventTypeToStringType = {
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1763
|
+
AfterParty: "After-Party",
|
|
1764
|
+
AnniversaryCelebration: "Anniversary Celebration",
|
|
1765
|
+
ArtAndCraftNight: "Art and Craft Night",
|
|
1766
|
+
ArtExhibitOpening: "Art Exhibit Opening",
|
|
1767
|
+
BBQCookout: "BBQ Cookout",
|
|
1768
|
+
BabyShower: "Baby Shower",
|
|
1769
|
+
BachelorParty: "Bachelor Party",
|
|
1770
|
+
BacheloretteParty: "Bachelorette Party",
|
|
1771
|
+
BeachParty: "Beach Party",
|
|
1772
|
+
Birthday: "Birthday",
|
|
1773
|
+
BoatParty: "Boat Party",
|
|
1774
|
+
Bonfire: "Bonfire",
|
|
1775
|
+
BridalShower: "Bridal Shower",
|
|
1776
|
+
BrunchGathering: "Brunch Gathering",
|
|
1777
|
+
CarShow: "Car Show",
|
|
1778
|
+
Carnival: "Carnival",
|
|
1779
|
+
CasinoNight: "Casino Night",
|
|
1780
|
+
CasualMixer: "Casual Mixer",
|
|
1781
|
+
CharityGala: "Charity Gala",
|
|
1782
|
+
ChristmasParty: "Christmas Party",
|
|
1783
|
+
ChurchEvent: "Church Event",
|
|
1784
|
+
CitySponsored: "City-Sponsored Event",
|
|
1785
|
+
CocktailParty: "Cocktail Party",
|
|
1786
|
+
CollegeParty: "College Party",
|
|
1787
|
+
ComedyShow: "Comedy Show",
|
|
1788
|
+
Concert: "Concert",
|
|
1789
|
+
Conference: "Conference",
|
|
1790
|
+
Convention: "Convention",
|
|
1791
|
+
CorporateEvent: "Corporate Event",
|
|
1792
|
+
Cruise: "Cruise",
|
|
1793
|
+
DanceParty: "Dance Party",
|
|
1794
|
+
DiscoNight: "Disco Night",
|
|
1795
|
+
EasterGathering: "Easter Gathering",
|
|
1796
|
+
EngagementParty: "Engagement Party",
|
|
1797
|
+
Fair: "Fair",
|
|
1798
|
+
FarewellParty: "Farewell Party",
|
|
1799
|
+
FashionShow: "Fashion Show",
|
|
1800
|
+
Festival: "Festival",
|
|
1801
|
+
FestivalFilm: "Film Festival",
|
|
1802
|
+
FestivalFood: "Food Festival",
|
|
1803
|
+
Fundraiser: "Fundraiser",
|
|
1804
|
+
GameNight: "Game Night",
|
|
1805
|
+
GamingEvent: "Gaming Event",
|
|
1806
|
+
GardenParty: "Garden Party",
|
|
1807
|
+
GraduationParty: "Graduation Party",
|
|
1808
|
+
HalloweenParty: "Halloween Party",
|
|
1809
|
+
HanukkahParty: "Hanukkah Party",
|
|
1810
|
+
HolidayParty: "Holiday Party",
|
|
1811
|
+
HouseParty: "House Party",
|
|
1812
|
+
HousewarmingParty: "Housewarming Party",
|
|
1813
|
+
KaraokeNight: "Karaoke Night",
|
|
1814
|
+
LaunchParty: "Launch Party",
|
|
1815
|
+
LuxuryRetreat: "Luxury Retreat",
|
|
1816
|
+
MansionParty: "Mansion Party",
|
|
1817
|
+
MardiGras: "Mardi Gras",
|
|
1818
|
+
Memorial: "Memorial",
|
|
1819
|
+
MovieNight: "Movie Night",
|
|
1820
|
+
MoviePremiere: "Movie Premiere",
|
|
1821
|
+
MusicFestival: "Music Festival",
|
|
1822
|
+
NewYearsEveCelebration: "New Year's Eve Celebration",
|
|
1823
|
+
OfficeParty: "Office Party",
|
|
1824
|
+
OpenMicNight: "Open Mic Night",
|
|
1825
|
+
OutdoorActivity: "Outdoor Activity",
|
|
1826
|
+
Parade: "Parade",
|
|
1827
|
+
Party: "Party",
|
|
1828
|
+
PoolParty: "Pool Party",
|
|
1829
|
+
Potluck: "Potluck",
|
|
1830
|
+
PreParty: "Pre-Party",
|
|
1831
|
+
ProfessionalNetworkingEvent: "Professional Networking Event",
|
|
1832
|
+
PubCrawl: "Pub Crawl",
|
|
1833
|
+
Rave: "Rave",
|
|
1834
|
+
RetirementCelebration: "Retirement Celebration",
|
|
1835
|
+
Reunion: "Reunion",
|
|
1836
|
+
SchoolEvent: "School Event",
|
|
1837
|
+
SocialClubEvent: "Social Club Event",
|
|
1838
|
+
SportsWatchParty: "Sports Watch Party",
|
|
1839
|
+
ThanksgivingDinner: "Thanksgiving Dinner",
|
|
1840
|
+
ThemedDinnerParty: "Themed Dinner Party",
|
|
1841
|
+
ThemedParty: "Themed Party",
|
|
1842
|
+
ThemedPubCrawl: "Themed Pub Crawl",
|
|
1843
|
+
Tournament: "Tournament",
|
|
1844
|
+
TradeShow: "Trade Show",
|
|
1845
|
+
TriviaNight: "Trivia Night",
|
|
1846
|
+
ValentinesDayParty: "Valentine's Day Party",
|
|
1847
|
+
WeddingReception: "Wedding Reception",
|
|
1848
|
+
WelcomeHomeParty: "Welcome Home Party",
|
|
1849
|
+
WineTastingEvent: "Wine Tasting Event",
|
|
1850
|
+
Workshop: "Workshop",
|
|
1851
|
+
Other: "Other",
|
|
1742
1852
|
};
|
|
1743
1853
|
|
|
1744
1854
|
/**
|
|
@@ -1751,47 +1861,61 @@ export type DietaryOptionToStringType = {
|
|
|
1751
1861
|
[key in DietaryOption]: string;
|
|
1752
1862
|
};
|
|
1753
1863
|
export const DietaryOptionToString: DietaryOptionToStringType = {
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1864
|
+
GlutenFreeOptions: "Gluten-Free Options Available",
|
|
1865
|
+
VeganOptions: "Vegan Options Available",
|
|
1866
|
+
VegetarianOptions: "Vegetarian Options Available",
|
|
1867
|
+
DairyFreeOptions: "Dairy-Free Options Available",
|
|
1868
|
+
NutFreeOptions: "Nut-Free Options Available",
|
|
1869
|
+
HalalOptions: "Halal Options Available",
|
|
1870
|
+
KosherOptions: "Kosher Options Available",
|
|
1871
|
+
SugarFreeOptions: "Low-Sugar / Sugar-Free Options Available",
|
|
1872
|
+
KetoOptions: "Keto-Friendly Options Available",
|
|
1873
|
+
PaleoOptions: "Paleo-Friendly Options Available",
|
|
1874
|
+
AlcoholFreeOptions: "Non-Alcoholic Options Available",
|
|
1765
1875
|
};
|
|
1766
1876
|
|
|
1767
1877
|
/** Short chip labels used in tight UI spots (filter modal, card pills). */
|
|
1768
1878
|
export const DietaryOptionShortLabel: DietaryOptionToStringType = {
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1879
|
+
GlutenFreeOptions: "Gluten-Free",
|
|
1880
|
+
VeganOptions: "Vegan",
|
|
1881
|
+
VegetarianOptions: "Vegetarian",
|
|
1882
|
+
DairyFreeOptions: "Dairy-Free",
|
|
1883
|
+
NutFreeOptions: "Nut-Free",
|
|
1884
|
+
HalalOptions: "Halal",
|
|
1885
|
+
KosherOptions: "Kosher",
|
|
1886
|
+
SugarFreeOptions: "Sugar-Free",
|
|
1887
|
+
KetoOptions: "Keto",
|
|
1888
|
+
PaleoOptions: "Paleo",
|
|
1889
|
+
AlcoholFreeOptions: "Non-Alcoholic",
|
|
1780
1890
|
};
|
|
1781
1891
|
|
|
1782
1892
|
/** All `DietaryOption` enum values in display order (for rendering checkboxes/tags). */
|
|
1783
1893
|
export const DIETARY_OPTION_VALUES: ReadonlyArray<DietaryOption> = [
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1894
|
+
"GlutenFreeOptions",
|
|
1895
|
+
"VeganOptions",
|
|
1896
|
+
"VegetarianOptions",
|
|
1897
|
+
"DairyFreeOptions",
|
|
1898
|
+
"NutFreeOptions",
|
|
1899
|
+
"HalalOptions",
|
|
1900
|
+
"KosherOptions",
|
|
1901
|
+
"SugarFreeOptions",
|
|
1902
|
+
"KetoOptions",
|
|
1903
|
+
"PaleoOptions",
|
|
1904
|
+
"AlcoholFreeOptions",
|
|
1905
|
+
];
|
|
1906
|
+
|
|
1907
|
+
/**
|
|
1908
|
+
* Guest-facing filter chips — everyday accommodations only.
|
|
1909
|
+
* Religious, drink, and diet-trend tags stay on the host form / enum
|
|
1910
|
+
* so existing events keep their data, but they do not crowd the filter menu.
|
|
1911
|
+
*/
|
|
1912
|
+
export const DIETARY_OPTION_FILTER_VALUES: ReadonlyArray<DietaryOption> = [
|
|
1913
|
+
"VegetarianOptions",
|
|
1914
|
+
"VeganOptions",
|
|
1915
|
+
"GlutenFreeOptions",
|
|
1916
|
+
"DairyFreeOptions",
|
|
1917
|
+
"NutFreeOptions",
|
|
1918
|
+
"SugarFreeOptions",
|
|
1795
1919
|
];
|
|
1796
1920
|
|
|
1797
1921
|
/** Display labels for `IncomeRange` (wizard primary/secondary chips). */
|
|
@@ -1799,29 +1923,28 @@ export type IncomeRangeToStringType = {
|
|
|
1799
1923
|
[key in IncomeRange]: string;
|
|
1800
1924
|
};
|
|
1801
1925
|
export const IncomeRangeLabel: IncomeRangeToStringType = {
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
[IncomeRange.PreferNotToSay]: "Prefer not to say",
|
|
1926
|
+
NoPreference: "Anyone",
|
|
1927
|
+
Under40k: "Under $40k",
|
|
1928
|
+
From40to80k: "$40k – $80k",
|
|
1929
|
+
From80to150k: "$80k – $150k",
|
|
1930
|
+
From150to200k: "$150k – $200k",
|
|
1931
|
+
From200to500k: "$200k – $500k (common accredited-income band)",
|
|
1932
|
+
From500kTo1M: "$500k – $1M",
|
|
1933
|
+
Over1M: "$1M+",
|
|
1934
|
+
PreferNotToSay: "Prefer not to say",
|
|
1812
1935
|
};
|
|
1813
1936
|
|
|
1814
1937
|
/** Short labels for filter modal / tight chips. */
|
|
1815
1938
|
export const IncomeRangeShortLabel: IncomeRangeToStringType = {
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1939
|
+
NoPreference: "Any income",
|
|
1940
|
+
Under40k: "<$40k",
|
|
1941
|
+
From40to80k: "$40–80k",
|
|
1942
|
+
From80to150k: "$80–150k",
|
|
1943
|
+
From150to200k: "$150–200k",
|
|
1944
|
+
From200to500k: "$200–500k",
|
|
1945
|
+
From500kTo1M: "$500k–$1M",
|
|
1946
|
+
Over1M: "$1M+",
|
|
1947
|
+
PreferNotToSay: "No answer",
|
|
1825
1948
|
};
|
|
1826
1949
|
|
|
1827
1950
|
/**
|
|
@@ -1829,15 +1952,15 @@ export const IncomeRangeShortLabel: IncomeRangeToStringType = {
|
|
|
1829
1952
|
* Audience-targeting only — never use to gate ticket purchase or entry.
|
|
1830
1953
|
*/
|
|
1831
1954
|
export const INCOME_RANGE_VALUES: ReadonlyArray<IncomeRange> = [
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1955
|
+
"Under40k",
|
|
1956
|
+
"From40to80k",
|
|
1957
|
+
"From80to150k",
|
|
1958
|
+
"From150to200k",
|
|
1959
|
+
"From200to500k",
|
|
1960
|
+
"From500kTo1M",
|
|
1961
|
+
"Over1M",
|
|
1962
|
+
"PreferNotToSay",
|
|
1963
|
+
"NoPreference",
|
|
1841
1964
|
];
|
|
1842
1965
|
|
|
1843
1966
|
/** Homepage / discovery section labels for synthetic rows (not `BashEventType` enum values). */
|
package/src/extendedSchemas.ts
CHANGED
|
@@ -257,7 +257,22 @@ export const PUBLIC_TEASER_USER_DATA_TO_SELECT = {
|
|
|
257
257
|
|
|
258
258
|
export type PublicTeaserUser = Prisma.UserGetPayload<{
|
|
259
259
|
select: typeof PUBLIC_TEASER_USER_DATA_TO_SELECT;
|
|
260
|
-
}
|
|
260
|
+
}> & {
|
|
261
|
+
/** Only populated by Intros endpoints for eligible viewers. */
|
|
262
|
+
openToIntros?: boolean;
|
|
263
|
+
/** Only populated by Intros endpoints for eligible viewers. */
|
|
264
|
+
personalityType?: string | null;
|
|
265
|
+
/** Only populated by Intros endpoints for eligible viewers. */
|
|
266
|
+
locusOfControl?: string | null;
|
|
267
|
+
/** True when the viewer already sent an interest expression to this person. */
|
|
268
|
+
alreadyExpressedInterest?: boolean;
|
|
269
|
+
/** True when this person already sent an interest expression to the viewer. */
|
|
270
|
+
interestFromThem?: boolean;
|
|
271
|
+
/** True when both people have sent a signal. */
|
|
272
|
+
mutualInterest?: boolean;
|
|
273
|
+
/** Only populated by Intros endpoints for eligible viewers. */
|
|
274
|
+
introIntents?: string[];
|
|
275
|
+
};
|
|
261
276
|
|
|
262
277
|
export const PRIVATE_USER_ACCOUNT_TO_SELECT = {
|
|
263
278
|
...FRONT_END_USER_DATA_TO_SELECT,
|
|
@@ -652,6 +667,9 @@ type BashEventExtBase = Override<
|
|
|
652
667
|
dateOptions?: IdeaDateOption[];
|
|
653
668
|
/** Public aggregate when poll enabled (no PII) */
|
|
654
669
|
datePollPublicSummary?: IdeaDatePollPublicSummary;
|
|
670
|
+
hideCancellationPolicy?: boolean;
|
|
671
|
+
hideGroupUp?: boolean;
|
|
672
|
+
hideServicesOpenTo?: boolean;
|
|
655
673
|
/** GET /event/:id — tickets sold (non-cancelled), for social proof */
|
|
656
674
|
goingCount?: number;
|
|
657
675
|
/** GET /event/:id — true when at least one Budget line has `showOnBashDetailPage` set. Drives the "View budget" reveal on the public bash page; never carries dollar amounts. */
|
|
@@ -729,6 +747,10 @@ type BashEventExtBase = Override<
|
|
|
729
747
|
* When true (default), signed-in visitors can message the host from the bash detail page.
|
|
730
748
|
*/
|
|
731
749
|
allowViewerContact: boolean;
|
|
750
|
+
/**
|
|
751
|
+
* Host opt-in: guests must have a profile photo to RSVP or buy tickets.
|
|
752
|
+
*/
|
|
753
|
+
requireProfilePhoto: boolean;
|
|
732
754
|
};
|
|
733
755
|
|
|
734
756
|
export type BashEventExt = Omit<
|
|
@@ -1310,6 +1332,10 @@ export const SERVICE_BOOKING_PUBLIC_DATA_TO_INCLUDE = {
|
|
|
1310
1332
|
title: true,
|
|
1311
1333
|
slug: true,
|
|
1312
1334
|
status: true,
|
|
1335
|
+
coverPhoto: true,
|
|
1336
|
+
startDateTime: true,
|
|
1337
|
+
endDateTime: true,
|
|
1338
|
+
timezone: true,
|
|
1313
1339
|
},
|
|
1314
1340
|
},
|
|
1315
1341
|
representedByOrganization: {
|
|
@@ -1344,7 +1370,14 @@ export const SERVICE_BOOKING_PRIVATE_DATA_TO_INCLUDE = {
|
|
|
1344
1370
|
// so call sites can cast prisma.upsert/findUnique results without needing `as unknown`.
|
|
1345
1371
|
export type ServiceBookingBashEventRef = Pick<
|
|
1346
1372
|
BashEvent,
|
|
1347
|
-
|
|
1373
|
+
| "id"
|
|
1374
|
+
| "title"
|
|
1375
|
+
| "slug"
|
|
1376
|
+
| "status"
|
|
1377
|
+
| "coverPhoto"
|
|
1378
|
+
| "startDateTime"
|
|
1379
|
+
| "endDateTime"
|
|
1380
|
+
| "timezone"
|
|
1348
1381
|
>;
|
|
1349
1382
|
|
|
1350
1383
|
export type ServiceBookingCheckoutRef = Pick<
|
|
@@ -1981,10 +2014,10 @@ export interface UserExt extends User {
|
|
|
1981
2014
|
socialEventCadenceDisplay?: string;
|
|
1982
2015
|
|
|
1983
2016
|
/**
|
|
1984
|
-
* Computed trust badges. Server
|
|
1985
|
-
* `showVerifiedBadgesOnProfile` and strips the underlying raw fields
|
|
2017
|
+
* Computed trust badges. Server strips the underlying raw fields
|
|
1986
2018
|
* (`paymentVerified`, `stripeAccountId`, `studentIdImageS3Key`, `schoolName`)
|
|
1987
|
-
* from the public response.
|
|
2019
|
+
* from the public response. `paymentVerified` stays public once true;
|
|
2020
|
+
* ID / host / student badges still require `showVerifiedBadgesOnProfile`.
|
|
1988
2021
|
*/
|
|
1989
2022
|
badges?: {
|
|
1990
2023
|
idVerified: boolean;
|
package/src/sideQuestTypes.ts
CHANGED