@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
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared quote logic for Food & Beverage event-service listings.
|
|
3
|
+
*
|
|
4
|
+
* Rules:
|
|
5
|
+
* - Priced per-guest (PER_ATTENDEE pricingModel).
|
|
6
|
+
* - Headcount floors at minimumQuantity if set.
|
|
7
|
+
* - Dollar total floors at minimumChargeCents if set.
|
|
8
|
+
* - Packages and add-ons still stack on top.
|
|
9
|
+
* - No check-in true-up (promoter settlement) — headcount is snapshotted
|
|
10
|
+
* at booking time only.
|
|
11
|
+
*
|
|
12
|
+
* Keep this module pure (no Prisma, no React). Import it in bash-app, api,
|
|
13
|
+
* and frontendServiceBookingUtils via the index.
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* All FoodAndBeverageSubType values (mirrors the Prisma enum).
|
|
17
|
+
* Also include legacy/alias strings the wizard uses (Caterer, PrivateChef, etc.)
|
|
18
|
+
* so detection works before the DB normalises them.
|
|
19
|
+
*/
|
|
20
|
+
export declare const FOOD_AND_BEVERAGE_SUBTYPES: Set<string>;
|
|
21
|
+
/**
|
|
22
|
+
* Custom-order celebration cakes — consultation, serving-size packages,
|
|
23
|
+
* pickup/delivery. Not a dessert station (DessertBar) and not per-guest catering.
|
|
24
|
+
*/
|
|
25
|
+
export declare function isCelebrationCakeEventService(opts: {
|
|
26
|
+
eventServiceSubType?: string | null;
|
|
27
|
+
}): boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Charcuterie boards and grazing tables — board/table packages, not per-guest catering.
|
|
30
|
+
*/
|
|
31
|
+
export declare function isGrazingTableEventService(opts: {
|
|
32
|
+
eventServiceSubType?: string | null;
|
|
33
|
+
}): boolean;
|
|
34
|
+
/**
|
|
35
|
+
* Wedding / ceremony officiant. Hosting Support — not F&B, not Entertainment Emcee.
|
|
36
|
+
*/
|
|
37
|
+
export declare function isOfficiantEventService(opts: {
|
|
38
|
+
eventServiceSubType?: string | null;
|
|
39
|
+
}): boolean;
|
|
40
|
+
/** Cake and grazing: CUSTOM starting price + ServicePackage tiers. Never per-guest. */
|
|
41
|
+
export declare const PACKAGE_PRICED_FOOD_SUBTYPES: Set<string>;
|
|
42
|
+
export declare function isPackagePricedFoodEventService(opts: {
|
|
43
|
+
eventServiceSubType?: string | null;
|
|
44
|
+
}): boolean;
|
|
45
|
+
/**
|
|
46
|
+
* Return true when a listing is an F&B EventService — either by top-level
|
|
47
|
+
* type or by subtype string (for legacy/alias safety).
|
|
48
|
+
*/
|
|
49
|
+
export declare function isFoodAndBeverageEventService(opts: {
|
|
50
|
+
eventServiceType?: string | null;
|
|
51
|
+
eventServiceSubType?: string | null;
|
|
52
|
+
}): boolean;
|
|
53
|
+
/**
|
|
54
|
+
* Per-guest F&B only. Cake and grazing use packages — never this path.
|
|
55
|
+
*/
|
|
56
|
+
export declare function isPerGuestFoodAndBeverageEventService(opts: {
|
|
57
|
+
eventServiceType?: string | null;
|
|
58
|
+
eventServiceSubType?: string | null;
|
|
59
|
+
}): boolean;
|
|
60
|
+
export declare const EVENT_SERVICE_FULFILLMENT_MODES: readonly ["Pickup", "Delivery", "FullService"];
|
|
61
|
+
export type FoodAndBeverageFulfillmentMode = (typeof EVENT_SERVICE_FULFILLMENT_MODES)[number];
|
|
62
|
+
export declare function isFulfillmentMode(mode: string): mode is FoodAndBeverageFulfillmentMode;
|
|
63
|
+
export declare function filterFulfillmentModes(modes?: readonly string[] | null): FoodAndBeverageFulfillmentMode[];
|
|
64
|
+
export declare const FULFILLMENT_MODE_LABEL: Record<FoodAndBeverageFulfillmentMode, string>;
|
|
65
|
+
/**
|
|
66
|
+
* Suggested menu category chips shown in the wizard and on the listing.
|
|
67
|
+
* Providers can add custom values; these are just pre-populated starting points.
|
|
68
|
+
* Not SKUs — no flavors, quantities, or prices here.
|
|
69
|
+
*/
|
|
70
|
+
export declare const FB_MENU_CATEGORY_SUGGESTIONS: Record<string, readonly string[]>;
|
|
71
|
+
/**
|
|
72
|
+
* Get suggested menu categories for a subtype.
|
|
73
|
+
* Falls back to a generic list if the subtype is not found.
|
|
74
|
+
*/
|
|
75
|
+
export declare function getFoodAndBeverageMenuCategories(subtype?: string | null): readonly string[];
|
|
76
|
+
export interface FoodAndBeverageQuoteParams {
|
|
77
|
+
/** Cents per guest (baseRateCents from EventService). */
|
|
78
|
+
baseRateCents: number;
|
|
79
|
+
/** Host-entered guest count for the booking. */
|
|
80
|
+
headcount: number;
|
|
81
|
+
/** Minimum bookable guests (minimumQuantity from EventService). 0 = no floor. */
|
|
82
|
+
minimumQuantity?: number | null;
|
|
83
|
+
/** Hard dollar floor regardless of headcount (minimumChargeCents). 0 = no floor. */
|
|
84
|
+
minimumChargeCents?: number | null;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* The effective guest count used for the quote.
|
|
88
|
+
* Floors at minimumQuantity so the provider is never charged less than their floor.
|
|
89
|
+
*/
|
|
90
|
+
export declare function quotedGuestCount(headcount: number, minimumQuantity?: number | null): number;
|
|
91
|
+
/**
|
|
92
|
+
* Total food & beverage quote in cents, before packages, add-ons, and fees.
|
|
93
|
+
*
|
|
94
|
+
* Calculation order (mirrors the brochure's structure):
|
|
95
|
+
* 1. Floor headcount at minimumQuantity → quotedGuests
|
|
96
|
+
* 2. Compute rate total: baseRateCents × quotedGuests
|
|
97
|
+
* 3. Floor at minimumChargeCents
|
|
98
|
+
*
|
|
99
|
+
* Packages and add-ons are NOT included here — they are added on top by
|
|
100
|
+
* frontendServiceBookingUtils (same as for all other service types).
|
|
101
|
+
*/
|
|
102
|
+
export declare function foodAndBeverageQuoteCents({ baseRateCents, headcount, minimumQuantity, minimumChargeCents, }: FoodAndBeverageQuoteParams): number;
|
|
103
|
+
/**
|
|
104
|
+
* Human-readable summary string, e.g. "$18 / guest · min 25 guests".
|
|
105
|
+
*/
|
|
106
|
+
export declare function foodAndBeverageRateSummary(baseRateCents: number, minimumQuantity?: number | null): string;
|
|
107
|
+
/**
|
|
108
|
+
* Return true if the entered headcount is below the listing's minimum.
|
|
109
|
+
* Use this to block checkout with a human-readable message.
|
|
110
|
+
*/
|
|
111
|
+
export declare function isBelowGuestMinimum(headcount: number, minimumQuantity?: number | null): boolean;
|
|
112
|
+
/**
|
|
113
|
+
* Human-readable lead time label, e.g. "Needs 7 days notice" or "Needs 2 weeks notice".
|
|
114
|
+
* Rounds partial weeks only when evenly divisible.
|
|
115
|
+
*/
|
|
116
|
+
export declare function foodAndBeverageLeadTimeLabel(leadTimeDays?: number | null): string | null;
|
|
117
|
+
export declare const CELEBRATION_CAKE_FULFILLMENT_MODES: readonly ["Pickup", "Delivery"];
|
|
118
|
+
export type CelebrationCakeFulfillmentMode = (typeof CELEBRATION_CAKE_FULFILLMENT_MODES)[number];
|
|
119
|
+
export declare function isCelebrationCakeFulfillmentMode(mode: string): mode is CelebrationCakeFulfillmentMode;
|
|
120
|
+
export declare function filterCelebrationCakeFulfillmentModes(modes?: readonly string[] | null): CelebrationCakeFulfillmentMode[];
|
|
121
|
+
export declare const CAKE_OPTION_KINDS: readonly ["flavor", "frosting", "filling", "dietary"];
|
|
122
|
+
export type CakeOptionKind = (typeof CAKE_OPTION_KINDS)[number];
|
|
123
|
+
export declare const CELEBRATION_CAKE_FLAVORS: readonly ["Vanilla", "Chocolate", "Red Velvet", "Marble", "Carrot", "Lemon", "Almond", "Funfetti", "Spice", "Coconut"];
|
|
124
|
+
export declare const CELEBRATION_CAKE_FROSTINGS: readonly ["Vanilla Buttercream", "Chocolate Buttercream", "Cream Cheese", "Whipped Cream", "Fondant", "Ganache", "Swiss Meringue"];
|
|
125
|
+
export declare const CELEBRATION_CAKE_FILLINGS: readonly ["Raspberry", "Lemon Custard", "Chocolate Mousse", "Strawberry", "Cream Cheese", "Cannoli", "Vanilla Buttercream"];
|
|
126
|
+
export declare const CELEBRATION_CAKE_DIETARY: readonly ["Gluten-Free", "Vegan", "Nut-Free", "Sugar-Free", "Dairy-Free"];
|
|
127
|
+
export declare function encodeCakeOption(kind: CakeOptionKind, value: string): string;
|
|
128
|
+
export interface ParsedCakeOptions {
|
|
129
|
+
flavors: string[];
|
|
130
|
+
frostings: string[];
|
|
131
|
+
fillings: string[];
|
|
132
|
+
dietary: string[];
|
|
133
|
+
other: string[];
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Split prefixed cake chips back into grouped lists.
|
|
137
|
+
* Unprefixed leftovers land in `other` (caterer-style chips, if mixed).
|
|
138
|
+
*/
|
|
139
|
+
export declare function parseCakeOptions(goodsOrServices?: readonly string[] | null): ParsedCakeOptions;
|
|
140
|
+
export declare function serializeCakeOptions(opts: {
|
|
141
|
+
flavors?: readonly string[];
|
|
142
|
+
frostings?: readonly string[];
|
|
143
|
+
fillings?: readonly string[];
|
|
144
|
+
dietary?: readonly string[];
|
|
145
|
+
}): string[];
|
|
146
|
+
/**
|
|
147
|
+
* Listing line, e.g. "Cakes start at $350". Null when no starting price.
|
|
148
|
+
*/
|
|
149
|
+
export declare function celebrationCakeStartingPriceLabel(minimumChargeCents?: number | null): string | null;
|
|
150
|
+
export declare function grazingTableStartingPriceLabel(minimumChargeCents?: number | null): string | null;
|
|
151
|
+
export declare function packagePricedFoodStartingPriceLabel(eventServiceSubType?: string | null, minimumChargeCents?: number | null): string | null;
|
|
152
|
+
export declare const GRAZING_TABLE_FULFILLMENT_MODES: readonly ["Pickup", "Delivery", "FullService"];
|
|
153
|
+
export declare const GRAZING_OPTION_KINDS: readonly ["style", "protein", "dietary"];
|
|
154
|
+
export type GrazingOptionKind = (typeof GRAZING_OPTION_KINDS)[number];
|
|
155
|
+
export declare const GRAZING_TABLE_STYLES: readonly ["Classic Charcuterie", "Modern Grazing", "Cheese Board", "Dessert Board", "Breakfast Board", "Seasonal"];
|
|
156
|
+
export declare const GRAZING_TABLE_PROTEINS: readonly ["Cured Meats", "Artisan Cheeses", "Smoked Fish", "Plant-Based", "Crudité"];
|
|
157
|
+
export declare const GRAZING_TABLE_DIETARY: readonly ["Gluten-Free", "Vegan", "Nut-Free", "Dairy-Free"];
|
|
158
|
+
export declare function encodeGrazingOption(kind: GrazingOptionKind, value: string): string;
|
|
159
|
+
export interface ParsedGrazingOptions {
|
|
160
|
+
styles: string[];
|
|
161
|
+
proteins: string[];
|
|
162
|
+
dietary: string[];
|
|
163
|
+
other: string[];
|
|
164
|
+
}
|
|
165
|
+
export declare function parseGrazingOptions(goodsOrServices?: readonly string[] | null): ParsedGrazingOptions;
|
|
166
|
+
export declare function serializeGrazingOptions(opts: {
|
|
167
|
+
styles?: readonly string[];
|
|
168
|
+
proteins?: readonly string[];
|
|
169
|
+
dietary?: readonly string[];
|
|
170
|
+
}): string[];
|
|
171
|
+
//# sourceMappingURL=foodAndBeverageQuote.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"foodAndBeverageQuote.d.ts","sourceRoot":"","sources":["../../../src/utils/service/foodAndBeverageQuote.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,467 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared quote logic for Food & Beverage event-service listings.
|
|
3
|
+
*
|
|
4
|
+
* Rules:
|
|
5
|
+
* - Priced per-guest (PER_ATTENDEE pricingModel).
|
|
6
|
+
* - Headcount floors at minimumQuantity if set.
|
|
7
|
+
* - Dollar total floors at minimumChargeCents if set.
|
|
8
|
+
* - Packages and add-ons still stack on top.
|
|
9
|
+
* - No check-in true-up (promoter settlement) — headcount is snapshotted
|
|
10
|
+
* at booking time only.
|
|
11
|
+
*
|
|
12
|
+
* Keep this module pure (no Prisma, no React). Import it in bash-app, api,
|
|
13
|
+
* and frontendServiceBookingUtils via the index.
|
|
14
|
+
*/
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
// Subtype detection
|
|
17
|
+
// ---------------------------------------------------------------------------
|
|
18
|
+
/**
|
|
19
|
+
* All FoodAndBeverageSubType values (mirrors the Prisma enum).
|
|
20
|
+
* Also include legacy/alias strings the wizard uses (Caterer, PrivateChef, etc.)
|
|
21
|
+
* so detection works before the DB normalises them.
|
|
22
|
+
*/
|
|
23
|
+
export const FOOD_AND_BEVERAGE_SUBTYPES = new Set([
|
|
24
|
+
// Canonical FoodAndBeverageSubType values
|
|
25
|
+
"Caterer",
|
|
26
|
+
"FoodTruck",
|
|
27
|
+
"FoodCartStand",
|
|
28
|
+
"PrivateChefs",
|
|
29
|
+
"Bartenders",
|
|
30
|
+
"Baristas",
|
|
31
|
+
"Mixologist",
|
|
32
|
+
"Sommelier",
|
|
33
|
+
"DessertBar",
|
|
34
|
+
"BeverageCart",
|
|
35
|
+
"ConcessionStand",
|
|
36
|
+
"CelebrationCake",
|
|
37
|
+
"GrazingTable",
|
|
38
|
+
"FoodAndBeverageOther",
|
|
39
|
+
// Wizard aliases / legacy keys
|
|
40
|
+
"PrivateChef",
|
|
41
|
+
"Bartender",
|
|
42
|
+
"Barista",
|
|
43
|
+
]);
|
|
44
|
+
/**
|
|
45
|
+
* Custom-order celebration cakes — consultation, serving-size packages,
|
|
46
|
+
* pickup/delivery. Not a dessert station (DessertBar) and not per-guest catering.
|
|
47
|
+
*/
|
|
48
|
+
export function isCelebrationCakeEventService(opts) {
|
|
49
|
+
return opts.eventServiceSubType === "CelebrationCake";
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Charcuterie boards and grazing tables — board/table packages, not per-guest catering.
|
|
53
|
+
*/
|
|
54
|
+
export function isGrazingTableEventService(opts) {
|
|
55
|
+
return opts.eventServiceSubType === "GrazingTable";
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Wedding / ceremony officiant. Hosting Support — not F&B, not Entertainment Emcee.
|
|
59
|
+
*/
|
|
60
|
+
export function isOfficiantEventService(opts) {
|
|
61
|
+
return opts.eventServiceSubType === "Officiant";
|
|
62
|
+
}
|
|
63
|
+
/** Cake and grazing: CUSTOM starting price + ServicePackage tiers. Never per-guest. */
|
|
64
|
+
export const PACKAGE_PRICED_FOOD_SUBTYPES = new Set([
|
|
65
|
+
"CelebrationCake",
|
|
66
|
+
"GrazingTable",
|
|
67
|
+
]);
|
|
68
|
+
export function isPackagePricedFoodEventService(opts) {
|
|
69
|
+
return (!!opts.eventServiceSubType &&
|
|
70
|
+
PACKAGE_PRICED_FOOD_SUBTYPES.has(opts.eventServiceSubType));
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Return true when a listing is an F&B EventService — either by top-level
|
|
74
|
+
* type or by subtype string (for legacy/alias safety).
|
|
75
|
+
*/
|
|
76
|
+
export function isFoodAndBeverageEventService(opts) {
|
|
77
|
+
if (opts.eventServiceType === "FoodAndBeverage")
|
|
78
|
+
return true;
|
|
79
|
+
if (opts.eventServiceSubType && FOOD_AND_BEVERAGE_SUBTYPES.has(opts.eventServiceSubType))
|
|
80
|
+
return true;
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Per-guest F&B only. Cake and grazing use packages — never this path.
|
|
85
|
+
*/
|
|
86
|
+
export function isPerGuestFoodAndBeverageEventService(opts) {
|
|
87
|
+
return (isFoodAndBeverageEventService(opts) && !isPackagePricedFoodEventService(opts));
|
|
88
|
+
}
|
|
89
|
+
// ---------------------------------------------------------------------------
|
|
90
|
+
// Fulfillment modes
|
|
91
|
+
// ---------------------------------------------------------------------------
|
|
92
|
+
export const EVENT_SERVICE_FULFILLMENT_MODES = [
|
|
93
|
+
"Pickup",
|
|
94
|
+
"Delivery",
|
|
95
|
+
"FullService",
|
|
96
|
+
];
|
|
97
|
+
const FULFILLMENT_MODE_SET = new Set(EVENT_SERVICE_FULFILLMENT_MODES);
|
|
98
|
+
export function isFulfillmentMode(mode) {
|
|
99
|
+
return FULFILLMENT_MODE_SET.has(mode);
|
|
100
|
+
}
|
|
101
|
+
export function filterFulfillmentModes(modes) {
|
|
102
|
+
return (modes ?? []).filter(isFulfillmentMode);
|
|
103
|
+
}
|
|
104
|
+
export const FULFILLMENT_MODE_LABEL = {
|
|
105
|
+
Pickup: "Pickup",
|
|
106
|
+
Delivery: "Delivery",
|
|
107
|
+
FullService: "Full Service",
|
|
108
|
+
};
|
|
109
|
+
// ---------------------------------------------------------------------------
|
|
110
|
+
// Menu category chips per subtype
|
|
111
|
+
// ---------------------------------------------------------------------------
|
|
112
|
+
/**
|
|
113
|
+
* Suggested menu category chips shown in the wizard and on the listing.
|
|
114
|
+
* Providers can add custom values; these are just pre-populated starting points.
|
|
115
|
+
* Not SKUs — no flavors, quantities, or prices here.
|
|
116
|
+
*/
|
|
117
|
+
export const FB_MENU_CATEGORY_SUGGESTIONS = {
|
|
118
|
+
Caterer: [
|
|
119
|
+
"Appetizers",
|
|
120
|
+
"Salads",
|
|
121
|
+
"Sandwiches",
|
|
122
|
+
"Mains",
|
|
123
|
+
"Sides",
|
|
124
|
+
"Desserts",
|
|
125
|
+
"Beverages",
|
|
126
|
+
"Vegetarian",
|
|
127
|
+
"Vegan",
|
|
128
|
+
"Gluten-Free",
|
|
129
|
+
],
|
|
130
|
+
DessertBar: [
|
|
131
|
+
"Cakes",
|
|
132
|
+
"Cupcakes",
|
|
133
|
+
"Cookies",
|
|
134
|
+
"Dessert Table",
|
|
135
|
+
"Chocolate Fountain",
|
|
136
|
+
"Ice Cream",
|
|
137
|
+
"Candy Buffet",
|
|
138
|
+
"Gluten-Free",
|
|
139
|
+
"Vegan",
|
|
140
|
+
"Custom Orders",
|
|
141
|
+
],
|
|
142
|
+
FoodTruck: [
|
|
143
|
+
"Street Food",
|
|
144
|
+
"Burgers",
|
|
145
|
+
"Tacos",
|
|
146
|
+
"Pizza",
|
|
147
|
+
"BBQ",
|
|
148
|
+
"Ethnic Cuisine",
|
|
149
|
+
"Desserts",
|
|
150
|
+
"Vegan",
|
|
151
|
+
"Gluten-Free",
|
|
152
|
+
],
|
|
153
|
+
PrivateChef: [
|
|
154
|
+
"Appetizers",
|
|
155
|
+
"Multi-Course Dinner",
|
|
156
|
+
"Wine Pairing",
|
|
157
|
+
"Dietary Specialist",
|
|
158
|
+
"Tasting Menu",
|
|
159
|
+
"Family-Style",
|
|
160
|
+
],
|
|
161
|
+
PrivateChefs: [
|
|
162
|
+
"Appetizers",
|
|
163
|
+
"Multi-Course Dinner",
|
|
164
|
+
"Wine Pairing",
|
|
165
|
+
"Dietary Specialist",
|
|
166
|
+
"Tasting Menu",
|
|
167
|
+
"Family-Style",
|
|
168
|
+
],
|
|
169
|
+
Bartenders: [
|
|
170
|
+
"Cocktails",
|
|
171
|
+
"Beer & Wine",
|
|
172
|
+
"Open Bar",
|
|
173
|
+
"Mocktails",
|
|
174
|
+
"Craft Beer",
|
|
175
|
+
"Specialty Drinks",
|
|
176
|
+
],
|
|
177
|
+
Bartender: [
|
|
178
|
+
"Cocktails",
|
|
179
|
+
"Beer & Wine",
|
|
180
|
+
"Open Bar",
|
|
181
|
+
"Mocktails",
|
|
182
|
+
"Craft Beer",
|
|
183
|
+
"Specialty Drinks",
|
|
184
|
+
],
|
|
185
|
+
Baristas: ["Espresso", "Cold Brew", "Lattes", "Tea", "Specialty Beverages"],
|
|
186
|
+
Barista: ["Espresso", "Cold Brew", "Lattes", "Tea", "Specialty Beverages"],
|
|
187
|
+
FoodCartStand: [
|
|
188
|
+
"Street Food",
|
|
189
|
+
"Snacks",
|
|
190
|
+
"Desserts",
|
|
191
|
+
"Coffee",
|
|
192
|
+
"Specialty Station",
|
|
193
|
+
],
|
|
194
|
+
BeverageCart: ["Coffee", "Tea", "Juice", "Smoothies", "Mocktails", "Water"],
|
|
195
|
+
};
|
|
196
|
+
/**
|
|
197
|
+
* Get suggested menu categories for a subtype.
|
|
198
|
+
* Falls back to a generic list if the subtype is not found.
|
|
199
|
+
*/
|
|
200
|
+
export function getFoodAndBeverageMenuCategories(subtype) {
|
|
201
|
+
if (subtype && FB_MENU_CATEGORY_SUGGESTIONS[subtype]) {
|
|
202
|
+
return FB_MENU_CATEGORY_SUGGESTIONS[subtype];
|
|
203
|
+
}
|
|
204
|
+
return ["Mains", "Sides", "Desserts", "Beverages", "Dietary Options"];
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* The effective guest count used for the quote.
|
|
208
|
+
* Floors at minimumQuantity so the provider is never charged less than their floor.
|
|
209
|
+
*/
|
|
210
|
+
export function quotedGuestCount(headcount, minimumQuantity) {
|
|
211
|
+
if (!minimumQuantity || minimumQuantity <= 0)
|
|
212
|
+
return Math.max(0, headcount);
|
|
213
|
+
return Math.max(headcount, minimumQuantity);
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Total food & beverage quote in cents, before packages, add-ons, and fees.
|
|
217
|
+
*
|
|
218
|
+
* Calculation order (mirrors the brochure's structure):
|
|
219
|
+
* 1. Floor headcount at minimumQuantity → quotedGuests
|
|
220
|
+
* 2. Compute rate total: baseRateCents × quotedGuests
|
|
221
|
+
* 3. Floor at minimumChargeCents
|
|
222
|
+
*
|
|
223
|
+
* Packages and add-ons are NOT included here — they are added on top by
|
|
224
|
+
* frontendServiceBookingUtils (same as for all other service types).
|
|
225
|
+
*/
|
|
226
|
+
export function foodAndBeverageQuoteCents({ baseRateCents, headcount, minimumQuantity, minimumChargeCents, }) {
|
|
227
|
+
if (baseRateCents <= 0 || headcount < 0)
|
|
228
|
+
return 0;
|
|
229
|
+
const guests = quotedGuestCount(headcount, minimumQuantity);
|
|
230
|
+
const rateTotalCents = baseRateCents * guests;
|
|
231
|
+
const floorCents = minimumChargeCents ?? 0;
|
|
232
|
+
return Math.max(rateTotalCents, floorCents);
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Human-readable summary string, e.g. "$18 / guest · min 25 guests".
|
|
236
|
+
*/
|
|
237
|
+
export function foodAndBeverageRateSummary(baseRateCents, minimumQuantity) {
|
|
238
|
+
const formatted = new Intl.NumberFormat("en-US", {
|
|
239
|
+
style: "currency",
|
|
240
|
+
currency: "USD",
|
|
241
|
+
minimumFractionDigits: 0,
|
|
242
|
+
maximumFractionDigits: 2,
|
|
243
|
+
}).format(baseRateCents / 100);
|
|
244
|
+
const perGuest = `${formatted} / guest`;
|
|
245
|
+
if (minimumQuantity && minimumQuantity > 0) {
|
|
246
|
+
return `${perGuest} · min ${minimumQuantity} guests`;
|
|
247
|
+
}
|
|
248
|
+
return perGuest;
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Return true if the entered headcount is below the listing's minimum.
|
|
252
|
+
* Use this to block checkout with a human-readable message.
|
|
253
|
+
*/
|
|
254
|
+
export function isBelowGuestMinimum(headcount, minimumQuantity) {
|
|
255
|
+
if (!minimumQuantity || minimumQuantity <= 0)
|
|
256
|
+
return false;
|
|
257
|
+
return headcount < minimumQuantity;
|
|
258
|
+
}
|
|
259
|
+
// ---------------------------------------------------------------------------
|
|
260
|
+
// Lead time
|
|
261
|
+
// ---------------------------------------------------------------------------
|
|
262
|
+
/**
|
|
263
|
+
* Human-readable lead time label, e.g. "Needs 7 days notice" or "Needs 2 weeks notice".
|
|
264
|
+
* Rounds partial weeks only when evenly divisible.
|
|
265
|
+
*/
|
|
266
|
+
export function foodAndBeverageLeadTimeLabel(leadTimeDays) {
|
|
267
|
+
if (!leadTimeDays || leadTimeDays <= 0)
|
|
268
|
+
return null;
|
|
269
|
+
if (leadTimeDays % 7 === 0) {
|
|
270
|
+
const weeks = leadTimeDays / 7;
|
|
271
|
+
return `Needs ${weeks} ${weeks === 1 ? "week" : "weeks"} notice`;
|
|
272
|
+
}
|
|
273
|
+
return `Needs ${leadTimeDays} ${leadTimeDays === 1 ? "day" : "days"} notice`;
|
|
274
|
+
}
|
|
275
|
+
// ---------------------------------------------------------------------------
|
|
276
|
+
// Celebration cake chips (stored on goodsOrServices with lowercase prefixes)
|
|
277
|
+
// ---------------------------------------------------------------------------
|
|
278
|
+
export const CELEBRATION_CAKE_FULFILLMENT_MODES = ["Pickup", "Delivery"];
|
|
279
|
+
const CAKE_FULFILLMENT_MODE_SET = new Set(CELEBRATION_CAKE_FULFILLMENT_MODES);
|
|
280
|
+
export function isCelebrationCakeFulfillmentMode(mode) {
|
|
281
|
+
return CAKE_FULFILLMENT_MODE_SET.has(mode);
|
|
282
|
+
}
|
|
283
|
+
export function filterCelebrationCakeFulfillmentModes(modes) {
|
|
284
|
+
return (modes ?? []).filter(isCelebrationCakeFulfillmentMode);
|
|
285
|
+
}
|
|
286
|
+
export const CAKE_OPTION_KINDS = [
|
|
287
|
+
"flavor",
|
|
288
|
+
"frosting",
|
|
289
|
+
"filling",
|
|
290
|
+
"dietary",
|
|
291
|
+
];
|
|
292
|
+
export const CELEBRATION_CAKE_FLAVORS = [
|
|
293
|
+
"Vanilla",
|
|
294
|
+
"Chocolate",
|
|
295
|
+
"Red Velvet",
|
|
296
|
+
"Marble",
|
|
297
|
+
"Carrot",
|
|
298
|
+
"Lemon",
|
|
299
|
+
"Almond",
|
|
300
|
+
"Funfetti",
|
|
301
|
+
"Spice",
|
|
302
|
+
"Coconut",
|
|
303
|
+
];
|
|
304
|
+
export const CELEBRATION_CAKE_FROSTINGS = [
|
|
305
|
+
"Vanilla Buttercream",
|
|
306
|
+
"Chocolate Buttercream",
|
|
307
|
+
"Cream Cheese",
|
|
308
|
+
"Whipped Cream",
|
|
309
|
+
"Fondant",
|
|
310
|
+
"Ganache",
|
|
311
|
+
"Swiss Meringue",
|
|
312
|
+
];
|
|
313
|
+
export const CELEBRATION_CAKE_FILLINGS = [
|
|
314
|
+
"Raspberry",
|
|
315
|
+
"Lemon Custard",
|
|
316
|
+
"Chocolate Mousse",
|
|
317
|
+
"Strawberry",
|
|
318
|
+
"Cream Cheese",
|
|
319
|
+
"Cannoli",
|
|
320
|
+
"Vanilla Buttercream",
|
|
321
|
+
];
|
|
322
|
+
export const CELEBRATION_CAKE_DIETARY = [
|
|
323
|
+
"Gluten-Free",
|
|
324
|
+
"Vegan",
|
|
325
|
+
"Nut-Free",
|
|
326
|
+
"Sugar-Free",
|
|
327
|
+
"Dairy-Free",
|
|
328
|
+
];
|
|
329
|
+
export function encodeCakeOption(kind, value) {
|
|
330
|
+
return `${kind}:${value}`;
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Split prefixed cake chips back into grouped lists.
|
|
334
|
+
* Unprefixed leftovers land in `other` (caterer-style chips, if mixed).
|
|
335
|
+
*/
|
|
336
|
+
export function parseCakeOptions(goodsOrServices) {
|
|
337
|
+
const result = {
|
|
338
|
+
flavors: [],
|
|
339
|
+
frostings: [],
|
|
340
|
+
fillings: [],
|
|
341
|
+
dietary: [],
|
|
342
|
+
other: [],
|
|
343
|
+
};
|
|
344
|
+
if (!goodsOrServices)
|
|
345
|
+
return result;
|
|
346
|
+
for (const raw of goodsOrServices) {
|
|
347
|
+
if (raw.startsWith("flavor:")) {
|
|
348
|
+
result.flavors.push(raw.slice("flavor:".length));
|
|
349
|
+
}
|
|
350
|
+
else if (raw.startsWith("frosting:")) {
|
|
351
|
+
result.frostings.push(raw.slice("frosting:".length));
|
|
352
|
+
}
|
|
353
|
+
else if (raw.startsWith("filling:")) {
|
|
354
|
+
result.fillings.push(raw.slice("filling:".length));
|
|
355
|
+
}
|
|
356
|
+
else if (raw.startsWith("dietary:")) {
|
|
357
|
+
result.dietary.push(raw.slice("dietary:".length));
|
|
358
|
+
}
|
|
359
|
+
else if (raw.length > 0) {
|
|
360
|
+
result.other.push(raw);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
return result;
|
|
364
|
+
}
|
|
365
|
+
export function serializeCakeOptions(opts) {
|
|
366
|
+
return [
|
|
367
|
+
...(opts.flavors ?? []).map((v) => encodeCakeOption("flavor", v)),
|
|
368
|
+
...(opts.frostings ?? []).map((v) => encodeCakeOption("frosting", v)),
|
|
369
|
+
...(opts.fillings ?? []).map((v) => encodeCakeOption("filling", v)),
|
|
370
|
+
...(opts.dietary ?? []).map((v) => encodeCakeOption("dietary", v)),
|
|
371
|
+
];
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* Listing line, e.g. "Cakes start at $350". Null when no starting price.
|
|
375
|
+
*/
|
|
376
|
+
export function celebrationCakeStartingPriceLabel(minimumChargeCents) {
|
|
377
|
+
return startingPriceLabel("Cakes start at", minimumChargeCents);
|
|
378
|
+
}
|
|
379
|
+
function startingPriceLabel(prefix, minimumChargeCents) {
|
|
380
|
+
if (!minimumChargeCents || minimumChargeCents <= 0)
|
|
381
|
+
return null;
|
|
382
|
+
const formatted = new Intl.NumberFormat("en-US", {
|
|
383
|
+
style: "currency",
|
|
384
|
+
currency: "USD",
|
|
385
|
+
minimumFractionDigits: 0,
|
|
386
|
+
maximumFractionDigits: 2,
|
|
387
|
+
}).format(minimumChargeCents / 100);
|
|
388
|
+
return `${prefix} ${formatted}`;
|
|
389
|
+
}
|
|
390
|
+
export function grazingTableStartingPriceLabel(minimumChargeCents) {
|
|
391
|
+
return startingPriceLabel("Boards start at", minimumChargeCents);
|
|
392
|
+
}
|
|
393
|
+
export function packagePricedFoodStartingPriceLabel(eventServiceSubType, minimumChargeCents) {
|
|
394
|
+
if (eventServiceSubType === "GrazingTable") {
|
|
395
|
+
return grazingTableStartingPriceLabel(minimumChargeCents);
|
|
396
|
+
}
|
|
397
|
+
if (eventServiceSubType === "CelebrationCake") {
|
|
398
|
+
return celebrationCakeStartingPriceLabel(minimumChargeCents);
|
|
399
|
+
}
|
|
400
|
+
return null;
|
|
401
|
+
}
|
|
402
|
+
// ---------------------------------------------------------------------------
|
|
403
|
+
// Grazing / charcuterie chips (goodsOrServices with lowercase prefixes)
|
|
404
|
+
// ---------------------------------------------------------------------------
|
|
405
|
+
export const GRAZING_TABLE_FULFILLMENT_MODES = [
|
|
406
|
+
"Pickup",
|
|
407
|
+
"Delivery",
|
|
408
|
+
"FullService",
|
|
409
|
+
];
|
|
410
|
+
export const GRAZING_OPTION_KINDS = ["style", "protein", "dietary"];
|
|
411
|
+
export const GRAZING_TABLE_STYLES = [
|
|
412
|
+
"Classic Charcuterie",
|
|
413
|
+
"Modern Grazing",
|
|
414
|
+
"Cheese Board",
|
|
415
|
+
"Dessert Board",
|
|
416
|
+
"Breakfast Board",
|
|
417
|
+
"Seasonal",
|
|
418
|
+
];
|
|
419
|
+
export const GRAZING_TABLE_PROTEINS = [
|
|
420
|
+
"Cured Meats",
|
|
421
|
+
"Artisan Cheeses",
|
|
422
|
+
"Smoked Fish",
|
|
423
|
+
"Plant-Based",
|
|
424
|
+
"Crudité",
|
|
425
|
+
];
|
|
426
|
+
export const GRAZING_TABLE_DIETARY = [
|
|
427
|
+
"Gluten-Free",
|
|
428
|
+
"Vegan",
|
|
429
|
+
"Nut-Free",
|
|
430
|
+
"Dairy-Free",
|
|
431
|
+
];
|
|
432
|
+
export function encodeGrazingOption(kind, value) {
|
|
433
|
+
return `${kind}:${value}`;
|
|
434
|
+
}
|
|
435
|
+
export function parseGrazingOptions(goodsOrServices) {
|
|
436
|
+
const result = {
|
|
437
|
+
styles: [],
|
|
438
|
+
proteins: [],
|
|
439
|
+
dietary: [],
|
|
440
|
+
other: [],
|
|
441
|
+
};
|
|
442
|
+
if (!goodsOrServices)
|
|
443
|
+
return result;
|
|
444
|
+
for (const raw of goodsOrServices) {
|
|
445
|
+
if (raw.startsWith("style:")) {
|
|
446
|
+
result.styles.push(raw.slice("style:".length));
|
|
447
|
+
}
|
|
448
|
+
else if (raw.startsWith("protein:")) {
|
|
449
|
+
result.proteins.push(raw.slice("protein:".length));
|
|
450
|
+
}
|
|
451
|
+
else if (raw.startsWith("dietary:")) {
|
|
452
|
+
result.dietary.push(raw.slice("dietary:".length));
|
|
453
|
+
}
|
|
454
|
+
else if (raw.length > 0) {
|
|
455
|
+
result.other.push(raw);
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
return result;
|
|
459
|
+
}
|
|
460
|
+
export function serializeGrazingOptions(opts) {
|
|
461
|
+
return [
|
|
462
|
+
...(opts.styles ?? []).map((v) => encodeGrazingOption("style", v)),
|
|
463
|
+
...(opts.proteins ?? []).map((v) => encodeGrazingOption("protein", v)),
|
|
464
|
+
...(opts.dietary ?? []).map((v) => encodeGrazingOption("dietary", v)),
|
|
465
|
+
];
|
|
466
|
+
}
|
|
467
|
+
//# sourceMappingURL=foodAndBeverageQuote.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"foodAndBeverageQuote.js","sourceRoot":"","sources":["../../../src/utils/service/foodAndBeverageQuote.ts"],"names":[],"mappings":"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"}
|