@swift-food-services/catering-widget 0.2.0-beta.8 → 0.2.0-beta.9
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/index.cjs +137 -94
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +137 -94
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -7536,12 +7536,15 @@ function createChatEndpoints(client) {
|
|
|
7536
7536
|
const res = await client.request(`/catering-chat/${sid}`);
|
|
7537
7537
|
return handleChatResponse(res);
|
|
7538
7538
|
},
|
|
7539
|
-
sendMessage: (sid, message, address, selectedMealSessionIndex) => {
|
|
7539
|
+
sendMessage: (sid, message, address, selectedMealSessionIndex, selectedIntentId) => {
|
|
7540
7540
|
const body = { message };
|
|
7541
7541
|
if (address) body.address = address;
|
|
7542
7542
|
if (typeof selectedMealSessionIndex === "number") {
|
|
7543
7543
|
body.selectedMealSessionIndex = selectedMealSessionIndex;
|
|
7544
7544
|
}
|
|
7545
|
+
if (typeof selectedIntentId === "string" && selectedIntentId.length > 0) {
|
|
7546
|
+
body.selectedIntentId = selectedIntentId;
|
|
7547
|
+
}
|
|
7545
7548
|
return post(`/catering-chat/${sid}/message`, body);
|
|
7546
7549
|
},
|
|
7547
7550
|
editField: (sid, field, value, mealSessionIndex) => {
|
|
@@ -12555,21 +12558,10 @@ function ActiveSessionPanel({
|
|
|
12555
12558
|
}
|
|
12556
12559
|
|
|
12557
12560
|
// src/components/ai/edit/translateEditField.ts
|
|
12558
|
-
function translateEditField(field, value
|
|
12559
|
-
if (field === "guestCount") {
|
|
12560
|
-
|
|
12561
|
-
}
|
|
12562
|
-
const idx = mealSessionIndex ?? 0;
|
|
12563
|
-
const meal = meals.find((m) => m.mealSessionIndex === idx) ?? meals[0] ?? null;
|
|
12564
|
-
const meta = meal ? aiMealSessions[meal.mealSessionIndex] : void 0;
|
|
12565
|
-
if (field === "sessionDate") {
|
|
12566
|
-
const time = meta?.eventTime || "12:00";
|
|
12567
|
-
return { field: "event_datetime", value: `${value}T${time}` };
|
|
12568
|
-
}
|
|
12569
|
-
if (field === "eventTime") {
|
|
12570
|
-
const date = meta?.sessionDate || (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
12571
|
-
return { field: "event_datetime", value: `${date}T${value}` };
|
|
12572
|
-
}
|
|
12561
|
+
function translateEditField(field, value) {
|
|
12562
|
+
if (field === "guestCount") return { field: "headcount", value };
|
|
12563
|
+
if (field === "sessionDate") return { field: "event_date", value };
|
|
12564
|
+
if (field === "eventTime") return { field: "event_time", value };
|
|
12573
12565
|
return { field, value };
|
|
12574
12566
|
}
|
|
12575
12567
|
|
|
@@ -12577,6 +12569,16 @@ function translateEditField(field, value, meals, aiMealSessions, mealSessionInde
|
|
|
12577
12569
|
var STORAGE_KEY2 = "swift-food-chat-session";
|
|
12578
12570
|
var messagesKey = (sid) => `swift-food-chat-messages-${sid}`;
|
|
12579
12571
|
var errorKey = (sid) => `swift-food-chat-error-${sid}`;
|
|
12572
|
+
function clearChatSessionStorage() {
|
|
12573
|
+
if (typeof window === "undefined") return null;
|
|
12574
|
+
const sid = window.localStorage.getItem(STORAGE_KEY2);
|
|
12575
|
+
window.localStorage.removeItem(STORAGE_KEY2);
|
|
12576
|
+
if (sid) {
|
|
12577
|
+
window.localStorage.removeItem(messagesKey(sid));
|
|
12578
|
+
window.localStorage.removeItem(errorKey(sid));
|
|
12579
|
+
}
|
|
12580
|
+
return sid;
|
|
12581
|
+
}
|
|
12580
12582
|
function readCachedError(sid) {
|
|
12581
12583
|
if (typeof window === "undefined") return null;
|
|
12582
12584
|
const raw = window.localStorage.getItem(errorKey(sid));
|
|
@@ -12653,10 +12655,14 @@ function useChatSession(options = {}) {
|
|
|
12653
12655
|
const sessionIdRef = react.useRef(null);
|
|
12654
12656
|
const lastTaxonomyRef = react.useRef({});
|
|
12655
12657
|
const selectedMealSessionIndexRef = react.useRef(null);
|
|
12658
|
+
const selectedIntentIdRef = react.useRef(null);
|
|
12656
12659
|
const applySideState = react.useCallback((data) => {
|
|
12657
12660
|
setStatus(data.status ?? null);
|
|
12658
|
-
|
|
12659
|
-
|
|
12661
|
+
const meals = data.mealSessions ?? [];
|
|
12662
|
+
setLatestMealSessions(meals);
|
|
12663
|
+
setLatestActiveMealSessionIndex(
|
|
12664
|
+
(prev) => meals.length === 0 ? 0 : Math.max(0, Math.min(prev, meals.length - 1))
|
|
12665
|
+
);
|
|
12660
12666
|
if (data.summary) {
|
|
12661
12667
|
setLatestSummary(data.summary);
|
|
12662
12668
|
lastTaxonomyRef.current = data.summary.taxonomy;
|
|
@@ -12928,11 +12934,13 @@ function useChatSession(options = {}) {
|
|
|
12928
12934
|
setRetryParams(null);
|
|
12929
12935
|
try {
|
|
12930
12936
|
const selectedIdx = selectedMealSessionIndexRef.current;
|
|
12937
|
+
const selectedIntentId = selectedIntentIdRef.current;
|
|
12931
12938
|
const data = await api.chat.sendMessage(
|
|
12932
12939
|
sid,
|
|
12933
12940
|
text,
|
|
12934
12941
|
address,
|
|
12935
|
-
selectedIdx
|
|
12942
|
+
selectedIdx,
|
|
12943
|
+
selectedIntentId
|
|
12936
12944
|
);
|
|
12937
12945
|
applyResponse(data);
|
|
12938
12946
|
} catch (e) {
|
|
@@ -12965,19 +12973,11 @@ function useChatSession(options = {}) {
|
|
|
12965
12973
|
if (!params || !sid) return;
|
|
12966
12974
|
await dispatchSend(sid, params.text, params.address);
|
|
12967
12975
|
}, [retryParams, dispatchSend]);
|
|
12968
|
-
const latestMealSessionPartsRef = react.useRef([]);
|
|
12969
|
-
const latestMealSessionsRef = react.useRef([]);
|
|
12970
12976
|
const applyEditField = react.useCallback(
|
|
12971
12977
|
async (field, value, mealSessionIndex) => {
|
|
12972
12978
|
const sid = sessionIdRef.current;
|
|
12973
12979
|
if (!sid) return;
|
|
12974
|
-
const translated = translateEditField(
|
|
12975
|
-
field,
|
|
12976
|
-
value,
|
|
12977
|
-
latestMealSessionPartsRef.current,
|
|
12978
|
-
latestMealSessionsRef.current,
|
|
12979
|
-
mealSessionIndex
|
|
12980
|
-
);
|
|
12980
|
+
const translated = translateEditField(field, value);
|
|
12981
12981
|
await callApiAndApply(
|
|
12982
12982
|
() => api.chat.editField(
|
|
12983
12983
|
sid,
|
|
@@ -13034,17 +13034,22 @@ function useChatSession(options = {}) {
|
|
|
13034
13034
|
[api, callApiAndApply]
|
|
13035
13035
|
);
|
|
13036
13036
|
const pickMealSession = react.useCallback(
|
|
13037
|
+
// Local-only navigation — no network round-trip. The old
|
|
13038
|
+
// pick_meal_session call blocked the UI on a server response just to
|
|
13039
|
+
// move the active tab, which made switching meals feel like it hung.
|
|
13040
|
+
// We update the viewed index immediately and stash it as the
|
|
13041
|
+
// "currently viewing" signal so the next /message carries it
|
|
13042
|
+
// (selectedMealSessionIndex) for BE disambiguation. The viewed intent
|
|
13043
|
+
// is cleared here and repopulated by IntentStepper's focus effect once
|
|
13044
|
+
// the new meal renders. Kept async (returns a resolved promise) so the
|
|
13045
|
+
// hook's contract and existing `void pickMealSession(idx)` callers are
|
|
13046
|
+
// unchanged.
|
|
13037
13047
|
async (mealSessionIndex) => {
|
|
13038
|
-
|
|
13039
|
-
|
|
13040
|
-
|
|
13041
|
-
() => api.chat.menuAction(sid, {
|
|
13042
|
-
action: "pick_meal_session",
|
|
13043
|
-
mealSessionIndex
|
|
13044
|
-
})
|
|
13045
|
-
);
|
|
13048
|
+
setLatestActiveMealSessionIndex(mealSessionIndex);
|
|
13049
|
+
selectedMealSessionIndexRef.current = mealSessionIndex;
|
|
13050
|
+
selectedIntentIdRef.current = null;
|
|
13046
13051
|
},
|
|
13047
|
-
[
|
|
13052
|
+
[]
|
|
13048
13053
|
);
|
|
13049
13054
|
const confirmInheritance = react.useCallback(
|
|
13050
13055
|
async (mealSessionIndex, accept) => {
|
|
@@ -13146,8 +13151,6 @@ function useChatSession(options = {}) {
|
|
|
13146
13151
|
if (latestMealSessions.length === 0) return parts;
|
|
13147
13152
|
return parts.filter((p) => p.mealSessionIndex < latestMealSessions.length);
|
|
13148
13153
|
}, [messages, latestMealSessions]);
|
|
13149
|
-
latestMealSessionPartsRef.current = latestMealSessionParts;
|
|
13150
|
-
latestMealSessionsRef.current = latestMealSessions;
|
|
13151
13154
|
return {
|
|
13152
13155
|
messages,
|
|
13153
13156
|
sending,
|
|
@@ -13181,6 +13184,10 @@ function useChatSession(options = {}) {
|
|
|
13181
13184
|
getTaxonomyValueFor,
|
|
13182
13185
|
setSelectedMealSessionIndex: (idx) => {
|
|
13183
13186
|
selectedMealSessionIndexRef.current = idx;
|
|
13187
|
+
selectedIntentIdRef.current = null;
|
|
13188
|
+
},
|
|
13189
|
+
setSelectedIntentId: (id) => {
|
|
13190
|
+
selectedIntentIdRef.current = id;
|
|
13184
13191
|
},
|
|
13185
13192
|
submitFeedback
|
|
13186
13193
|
};
|
|
@@ -13200,7 +13207,6 @@ function mergeAdaptedMealParts(data) {
|
|
|
13200
13207
|
mealSessionIndex: i,
|
|
13201
13208
|
intentBlocks: blocks.map((b) => ({
|
|
13202
13209
|
type: "intent_block",
|
|
13203
|
-
intentId: b.intentId,
|
|
13204
13210
|
mealSessionIndex: i,
|
|
13205
13211
|
intent: b.intent,
|
|
13206
13212
|
restaurantPicks: b.restaurantPicks
|
|
@@ -13268,7 +13274,11 @@ function findLatestMealSessionParts(messages) {
|
|
|
13268
13274
|
(a, b) => a.mealSessionIndex - b.mealSessionIndex
|
|
13269
13275
|
);
|
|
13270
13276
|
}
|
|
13271
|
-
var STORAGE_KEY_PREFIX = "swift-food-cart-
|
|
13277
|
+
var STORAGE_KEY_PREFIX = "swift-food-cart-v4-";
|
|
13278
|
+
function clearCartStorage(sessionId) {
|
|
13279
|
+
if (!sessionId || typeof window === "undefined") return;
|
|
13280
|
+
window.localStorage.removeItem(STORAGE_KEY_PREFIX + sessionId);
|
|
13281
|
+
}
|
|
13272
13282
|
var emptyIntent = () => ({
|
|
13273
13283
|
selectedRestaurantId: null,
|
|
13274
13284
|
qtyOverrides: {},
|
|
@@ -13487,12 +13497,13 @@ function ChatSessionProvider({
|
|
|
13487
13497
|
const [suggestionsOverlayDismissed, setSuggestionsOverlayDismissed] = react.useState(false);
|
|
13488
13498
|
const [feedbackTarget, setFeedbackTarget] = react.useState(null);
|
|
13489
13499
|
const [feedbackRating, setFeedbackRating] = react.useState(0);
|
|
13500
|
+
const [feedbackState, setFeedbackState] = react.useState("idle");
|
|
13490
13501
|
react.useEffect(() => {
|
|
13491
13502
|
if (!chat.sessionId) setActiveViewedPreview(null);
|
|
13492
13503
|
}, [chat.sessionId]);
|
|
13493
13504
|
const hasResults = react.useMemo(
|
|
13494
|
-
() => chat.
|
|
13495
|
-
[chat.
|
|
13505
|
+
() => chat.latestMealSessions.length > 0,
|
|
13506
|
+
[chat.latestMealSessions]
|
|
13496
13507
|
);
|
|
13497
13508
|
const prevPartsRef = react.useRef(chat.latestMealSessionParts);
|
|
13498
13509
|
const onViewResultsRef = react.useRef(onViewResults);
|
|
@@ -13528,17 +13539,22 @@ function ChatSessionProvider({
|
|
|
13528
13539
|
feedbackTarget,
|
|
13529
13540
|
feedbackRating,
|
|
13530
13541
|
setFeedbackRating,
|
|
13542
|
+
feedbackState,
|
|
13543
|
+
setFeedbackState,
|
|
13531
13544
|
startFeedback: (messageId, up, eventId) => {
|
|
13532
13545
|
setFeedbackTarget({ messageId, up, eventId });
|
|
13533
13546
|
setFeedbackRating(0);
|
|
13547
|
+
setFeedbackState("idle");
|
|
13534
13548
|
},
|
|
13535
13549
|
startGeneralFeedback: () => {
|
|
13536
13550
|
setFeedbackTarget({ messageId: "__general__", up: false });
|
|
13537
13551
|
setFeedbackRating(0);
|
|
13552
|
+
setFeedbackState("idle");
|
|
13538
13553
|
},
|
|
13539
13554
|
cancelFeedback: () => {
|
|
13540
13555
|
setFeedbackTarget(null);
|
|
13541
13556
|
setFeedbackRating(0);
|
|
13557
|
+
setFeedbackState("idle");
|
|
13542
13558
|
},
|
|
13543
13559
|
hasResults,
|
|
13544
13560
|
suggestionsOverlayDismissed,
|
|
@@ -15066,7 +15082,7 @@ function IntentBlockCard({
|
|
|
15066
15082
|
items: selected.items,
|
|
15067
15083
|
onAddItem
|
|
15068
15084
|
},
|
|
15069
|
-
`${part.
|
|
15085
|
+
`${part.intent.id}-${selected.restaurant.id}-${section.title ?? "_null"}`
|
|
15070
15086
|
)) }),
|
|
15071
15087
|
alts.length >= 3 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
15072
15088
|
AltRestaurantChips,
|
|
@@ -15251,10 +15267,10 @@ function resolveSelections(blocks, explicit) {
|
|
|
15251
15267
|
const resolved = /* @__PURE__ */ new Map();
|
|
15252
15268
|
const priorIds = /* @__PURE__ */ new Set();
|
|
15253
15269
|
for (const block of blocks) {
|
|
15254
|
-
const explicitId = explicit.get(block.
|
|
15270
|
+
const explicitId = explicit.get(block.intent.id);
|
|
15255
15271
|
const chosenId = explicitId ?? block.restaurantPicks[pickDefaultIndex(block.restaurantPicks, priorIds)]?.restaurant.id;
|
|
15256
15272
|
if (chosenId !== void 0) {
|
|
15257
|
-
resolved.set(block.
|
|
15273
|
+
resolved.set(block.intent.id, chosenId);
|
|
15258
15274
|
priorIds.add(chosenId);
|
|
15259
15275
|
}
|
|
15260
15276
|
}
|
|
@@ -15340,11 +15356,11 @@ function MealSessionStepper({
|
|
|
15340
15356
|
IntentBlockCard,
|
|
15341
15357
|
{
|
|
15342
15358
|
part: block,
|
|
15343
|
-
selectedRestaurantId: resolved.get(block.
|
|
15344
|
-
onSelectRestaurant: handleSelect(block.
|
|
15359
|
+
selectedRestaurantId: resolved.get(block.intent.id) ?? block.restaurantPicks[0]?.restaurant.id ?? "",
|
|
15360
|
+
onSelectRestaurant: handleSelect(block.intent.id),
|
|
15345
15361
|
onAddItem
|
|
15346
15362
|
},
|
|
15347
|
-
block.
|
|
15363
|
+
block.intent.id
|
|
15348
15364
|
))
|
|
15349
15365
|
},
|
|
15350
15366
|
stepMode ? `step-${safeStepIdx}` : "all"
|
|
@@ -17113,14 +17129,14 @@ function AIChatBody() {
|
|
|
17113
17129
|
const el = textareaRef.current;
|
|
17114
17130
|
if (!el) return;
|
|
17115
17131
|
el.style.height = "auto";
|
|
17116
|
-
const gateMinHeight = gateActive ? 72 : 0;
|
|
17132
|
+
const gateMinHeight = gateActive && feedbackTarget === null ? 72 : 0;
|
|
17117
17133
|
const fullHeight = Math.max(el.scrollHeight, gateMinHeight);
|
|
17118
17134
|
el.style.height = `${Math.min(fullHeight, MAX_INPUT_HEIGHT)}px`;
|
|
17119
17135
|
el.style.overflowY = fullHeight > MAX_INPUT_HEIGHT ? "auto" : "hidden";
|
|
17120
17136
|
};
|
|
17121
17137
|
react.useEffect(() => {
|
|
17122
17138
|
handleInput();
|
|
17123
|
-
}, [input, feedbackNote, gateActive]);
|
|
17139
|
+
}, [input, feedbackNote, gateActive, feedbackTarget]);
|
|
17124
17140
|
react.useEffect(() => {
|
|
17125
17141
|
if (!pendingInputFocus) return;
|
|
17126
17142
|
if (gateActive || pillEditing) return;
|
|
@@ -17255,8 +17271,8 @@ function AIChatBody() {
|
|
|
17255
17271
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-shrink-0 px-3 py-2.5 flex items-center gap-3 border-b border-base-200", children: [
|
|
17256
17272
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-9 h-9 rounded-full bg-primary flex items-center justify-center flex-shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Sparkles, { className: "w-4 h-4 text-white" }) }),
|
|
17257
17273
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 min-w-0", children: [
|
|
17258
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-semibold text-gray-800", children: "
|
|
17259
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-gray-500", children: "
|
|
17274
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-semibold text-gray-800", children: "Nibbles" }),
|
|
17275
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-gray-500", children: "Our AI Assistant" })
|
|
17260
17276
|
] }),
|
|
17261
17277
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
17262
17278
|
"button",
|
|
@@ -17486,7 +17502,7 @@ function AIChatBody() {
|
|
|
17486
17502
|
animate: { opacity: 1, y: 0 },
|
|
17487
17503
|
exit: { opacity: 0, y: -8 },
|
|
17488
17504
|
transition: { duration: 0.18, ease: "easeOut" },
|
|
17489
|
-
children: gateActive ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
17505
|
+
children: gateActive && !inFeedbackMode ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
17490
17506
|
react$1.motion.form,
|
|
17491
17507
|
{
|
|
17492
17508
|
onSubmit: handleSubmit,
|
|
@@ -18049,13 +18065,13 @@ function buildCategoryView(category, mealSession, cart, resolveSelectedRestauran
|
|
|
18049
18065
|
const view = [];
|
|
18050
18066
|
for (const block of mealSession.intentBlocks) {
|
|
18051
18067
|
if (block.intent.category !== category) continue;
|
|
18052
|
-
const selectedRestaurantId = resolveSelectedRestaurantId(block.
|
|
18068
|
+
const selectedRestaurantId = resolveSelectedRestaurantId(block.intent.id) ?? block.restaurantPicks[0]?.restaurant.id ?? null;
|
|
18053
18069
|
if (!selectedRestaurantId) continue;
|
|
18054
18070
|
const pick = block.restaurantPicks.find(
|
|
18055
18071
|
(rp) => rp.restaurant.id === selectedRestaurantId
|
|
18056
18072
|
);
|
|
18057
18073
|
if (!pick) continue;
|
|
18058
|
-
const cartIntent = cart[block.
|
|
18074
|
+
const cartIntent = cart[block.intent.id];
|
|
18059
18075
|
const removedSet = new Set(cartIntent?.removedItemIds ?? []);
|
|
18060
18076
|
const pickedSet = new Set(cartIntent?.pickedItemIds ?? []);
|
|
18061
18077
|
const swappedInItems = cartIntent ? Object.values(cartIntent.swappedIn) : [];
|
|
@@ -18070,7 +18086,7 @@ function buildCategoryView(category, mealSession, cart, resolveSelectedRestauran
|
|
|
18070
18086
|
for (const item of liveItems) {
|
|
18071
18087
|
view.push({
|
|
18072
18088
|
item,
|
|
18073
|
-
intent: { intentId: block.
|
|
18089
|
+
intent: { intentId: block.intent.id, quantity: block.intent.quantity },
|
|
18074
18090
|
itemsInPick,
|
|
18075
18091
|
overrideQty: cartIntent?.qtyOverrides[item.id],
|
|
18076
18092
|
intentQuantityPacks: packsByItemId?.get(item.id) ?? null
|
|
@@ -18226,7 +18242,7 @@ function checkMinOrders(mealSessionParts, aiMealSessions, cart) {
|
|
|
18226
18242
|
return out;
|
|
18227
18243
|
}
|
|
18228
18244
|
function findRestaurantForEntry(intentId, ms, cart) {
|
|
18229
|
-
const block = ms.intentBlocks.find((b) => b.
|
|
18245
|
+
const block = ms.intentBlocks.find((b) => b.intent.id === intentId);
|
|
18230
18246
|
if (!block) return null;
|
|
18231
18247
|
const selectedId = cart.getSelectedRestaurantId(intentId) ?? block.restaurantPicks[0]?.restaurant.id ?? null;
|
|
18232
18248
|
if (!selectedId) return null;
|
|
@@ -18305,13 +18321,13 @@ function aiPlanToPricingInput(mealSessionParts, aiMealSessions, cart) {
|
|
|
18305
18321
|
}
|
|
18306
18322
|
}
|
|
18307
18323
|
for (const block of ms.intentBlocks) {
|
|
18308
|
-
const selectedRestaurantId = cart.getSelectedRestaurantId(block.
|
|
18324
|
+
const selectedRestaurantId = cart.getSelectedRestaurantId(block.intent.id) ?? block.restaurantPicks[0]?.restaurant.id ?? null;
|
|
18309
18325
|
if (!selectedRestaurantId) continue;
|
|
18310
18326
|
const pick = block.restaurantPicks.find(
|
|
18311
18327
|
(rp) => rp.restaurant.id === selectedRestaurantId
|
|
18312
18328
|
);
|
|
18313
18329
|
if (!pick) continue;
|
|
18314
|
-
const cartIntent = cart.cart[block.
|
|
18330
|
+
const cartIntent = cart.cart[block.intent.id];
|
|
18315
18331
|
const removedSet = new Set(cartIntent?.removedItemIds ?? []);
|
|
18316
18332
|
const pickedSet = new Set(cartIntent?.pickedItemIds ?? []);
|
|
18317
18333
|
const liveItems = [
|
|
@@ -18323,7 +18339,7 @@ function aiPlanToPricingInput(mealSessionParts, aiMealSessions, cart) {
|
|
|
18323
18339
|
)
|
|
18324
18340
|
];
|
|
18325
18341
|
for (const it of liveItems) {
|
|
18326
|
-
const qty = qtyByItemKey.get(`${block.
|
|
18342
|
+
const qty = qtyByItemKey.get(`${block.intent.id}::${it.id}`) ?? 0;
|
|
18327
18343
|
if (qty <= 0) continue;
|
|
18328
18344
|
orderItems.push({
|
|
18329
18345
|
item: toPricingItem(it, selectedRestaurantId),
|
|
@@ -18733,7 +18749,13 @@ function IntentStepper({
|
|
|
18733
18749
|
const safeIntentIdx = Math.min(intentIndex, blocks.length);
|
|
18734
18750
|
const isReview = blocks.length > 0 && safeIntentIdx === blocks.length;
|
|
18735
18751
|
const block = isReview || blocks.length === 0 ? null : blocks[safeIntentIdx] ?? null;
|
|
18736
|
-
const
|
|
18752
|
+
const focusedIntentId = block?.intent.id ?? null;
|
|
18753
|
+
const { chat: chatForFocus } = useChatSessionContext();
|
|
18754
|
+
react.useEffect(() => {
|
|
18755
|
+
chatForFocus.setSelectedMealSessionIndex(activeMealSessionIndex);
|
|
18756
|
+
chatForFocus.setSelectedIntentId(focusedIntentId);
|
|
18757
|
+
}, [activeMealSessionIndex, focusedIntentId]);
|
|
18758
|
+
const selectedRestaurantId = block ? cart.getSelectedRestaurantId(block.intent.id) ?? block.restaurantPicks[0]?.restaurant.id ?? null : null;
|
|
18737
18759
|
const pickIdx = block ? Math.max(
|
|
18738
18760
|
0,
|
|
18739
18761
|
block.restaurantPicks.findIndex(
|
|
@@ -18741,7 +18763,7 @@ function IntentStepper({
|
|
|
18741
18763
|
)
|
|
18742
18764
|
) : 0;
|
|
18743
18765
|
const selected = block ? block.restaurantPicks[pickIdx] : void 0;
|
|
18744
|
-
const cartIntent = block ? cart.cart[block.
|
|
18766
|
+
const cartIntent = block ? cart.cart[block.intent.id] : void 0;
|
|
18745
18767
|
const removedSet = new Set(cartIntent?.removedItemIds ?? []);
|
|
18746
18768
|
const intentLiveSlots = react.useMemo(() => {
|
|
18747
18769
|
if (!block || !selected) return [];
|
|
@@ -18757,13 +18779,13 @@ function IntentStepper({
|
|
|
18757
18779
|
const headcount = activeMealMeta?.guestCount ?? 1;
|
|
18758
18780
|
const result = [];
|
|
18759
18781
|
for (const b of blocks) {
|
|
18760
|
-
const selRestId = cart.getSelectedRestaurantId(b.
|
|
18782
|
+
const selRestId = cart.getSelectedRestaurantId(b.intent.id) ?? b.restaurantPicks[0]?.restaurant.id ?? null;
|
|
18761
18783
|
if (!selRestId) continue;
|
|
18762
18784
|
const pick = b.restaurantPicks.find(
|
|
18763
18785
|
(rp) => rp.restaurant.id === selRestId
|
|
18764
18786
|
);
|
|
18765
18787
|
if (!pick) continue;
|
|
18766
|
-
const ci = cart.cart[b.
|
|
18788
|
+
const ci = cart.cart[b.intent.id];
|
|
18767
18789
|
const rem = new Set(ci?.removedItemIds ?? []);
|
|
18768
18790
|
const picked = new Set(ci?.pickedItemIds ?? []);
|
|
18769
18791
|
const swappedIn = ci?.swappedIn ?? {};
|
|
@@ -18785,7 +18807,7 @@ function IntentStepper({
|
|
|
18785
18807
|
const items = liveSlots.map(({ item: it, slotId }) => {
|
|
18786
18808
|
const qty = effectiveQty({
|
|
18787
18809
|
targetItem: it,
|
|
18788
|
-
targetIntent: { intentId: b.
|
|
18810
|
+
targetIntent: { intentId: b.intent.id, quantity: b.intent.quantity },
|
|
18789
18811
|
itemsInTargetPick: liveItems.length,
|
|
18790
18812
|
categoryView,
|
|
18791
18813
|
headcount
|
|
@@ -18900,7 +18922,7 @@ function IntentStepper({
|
|
|
18900
18922
|
const nextLabel = isReview ? !isLastMeal ? aiMealSessions[orderedMeals[myPos + 1].mealSessionIndex]?.sessionName ?? null : null : !isLastIntent ? capitalize(blocks[safeIntentIdx + 1].intent.phrase) : "Review";
|
|
18901
18923
|
const handlePickAlt = (restaurantId) => {
|
|
18902
18924
|
if (!block) return;
|
|
18903
|
-
cart.setRestaurant(block.
|
|
18925
|
+
cart.setRestaurant(block.intent.id, restaurantId);
|
|
18904
18926
|
};
|
|
18905
18927
|
function computeAddonChip(intentId, item, restaurantId, restaurantName) {
|
|
18906
18928
|
const groups = item.addons ?? [];
|
|
@@ -19094,27 +19116,27 @@ function IntentStepper({
|
|
|
19094
19116
|
intentPhrase: b.intent.phrase,
|
|
19095
19117
|
restaurantName,
|
|
19096
19118
|
items,
|
|
19097
|
-
intentId: b.
|
|
19119
|
+
intentId: b.intent.id,
|
|
19098
19120
|
restaurantId,
|
|
19099
19121
|
intentExcludes: b.intent.excludes,
|
|
19100
19122
|
onSwap,
|
|
19101
|
-
onRemove: (itemId) => cart.removeItem(b.
|
|
19102
|
-
onTogglePicked: (itemId) => cart.togglePicked(b.
|
|
19103
|
-
onQtyChange: (itemId, q) => cart.setQty(b.
|
|
19123
|
+
onRemove: (itemId) => cart.removeItem(b.intent.id, itemId),
|
|
19124
|
+
onTogglePicked: (itemId) => cart.togglePicked(b.intent.id, itemId),
|
|
19125
|
+
onQtyChange: (itemId, q) => cart.setQty(b.intent.id, itemId, q),
|
|
19104
19126
|
onViewItem: (item) => setViewItem({
|
|
19105
19127
|
item,
|
|
19106
|
-
intentId: b.
|
|
19128
|
+
intentId: b.intent.id,
|
|
19107
19129
|
restaurantId,
|
|
19108
19130
|
restaurantName
|
|
19109
19131
|
}),
|
|
19110
19132
|
getAddonChip: (item) => computeAddonChip(
|
|
19111
|
-
b.
|
|
19133
|
+
b.intent.id,
|
|
19112
19134
|
item,
|
|
19113
19135
|
restaurantId,
|
|
19114
19136
|
restaurantName
|
|
19115
19137
|
)
|
|
19116
19138
|
},
|
|
19117
|
-
b.
|
|
19139
|
+
b.intent.id
|
|
19118
19140
|
)) }) : /* @__PURE__ */ jsxRuntime.jsx(EmptyIntentState, { message: "No items picked yet \u2014 head back and check the items you want." })
|
|
19119
19141
|
},
|
|
19120
19142
|
`${activeMealSessionIndex}-review`
|
|
@@ -19140,9 +19162,9 @@ function IntentStepper({
|
|
|
19140
19162
|
}
|
|
19141
19163
|
),
|
|
19142
19164
|
intentLiveSlots.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("ul", { style: { margin: "0", padding: 0, listStyle: "none" }, children: intentLiveSlots.map(({ item, slotId }) => {
|
|
19143
|
-
const checked = cart.isPicked(block.
|
|
19165
|
+
const checked = cart.isPicked(block.intent.id, item.id);
|
|
19144
19166
|
const chip = computeAddonChip(
|
|
19145
|
-
block.
|
|
19167
|
+
block.intent.id,
|
|
19146
19168
|
item,
|
|
19147
19169
|
selected.restaurant.id,
|
|
19148
19170
|
selected.restaurant.name
|
|
@@ -19166,7 +19188,7 @@ function IntentStepper({
|
|
|
19166
19188
|
addonState: chip.state,
|
|
19167
19189
|
addonSummary: chip.summary,
|
|
19168
19190
|
onSwap: () => onSwap({
|
|
19169
|
-
intentId: block.
|
|
19191
|
+
intentId: block.intent.id,
|
|
19170
19192
|
slotId,
|
|
19171
19193
|
itemId: item.id,
|
|
19172
19194
|
itemName: item.name,
|
|
@@ -19176,10 +19198,10 @@ function IntentStepper({
|
|
|
19176
19198
|
intentExcludes: block.intent.excludes,
|
|
19177
19199
|
visibleItemIds: intentLiveSlots.map((s) => s.item.id)
|
|
19178
19200
|
}),
|
|
19179
|
-
onRemove: () => cart.removeItem(block.
|
|
19201
|
+
onRemove: () => cart.removeItem(block.intent.id, item.id),
|
|
19180
19202
|
onView: () => setViewItem({
|
|
19181
19203
|
item,
|
|
19182
|
-
intentId: block.
|
|
19204
|
+
intentId: block.intent.id,
|
|
19183
19205
|
restaurantId: selected.restaurant.id,
|
|
19184
19206
|
restaurantName: selected.restaurant.name
|
|
19185
19207
|
})
|
|
@@ -19189,7 +19211,7 @@ function IntentStepper({
|
|
|
19189
19211
|
}) }) : /* @__PURE__ */ jsxRuntime.jsx(EmptyIntentState, { message: "No items in this intent yet \u2014 keep chatting on the right." })
|
|
19190
19212
|
]
|
|
19191
19213
|
},
|
|
19192
|
-
`${activeMealSessionIndex}-${block.
|
|
19214
|
+
`${activeMealSessionIndex}-${block.intent.id}-${pickedId}`
|
|
19193
19215
|
) }),
|
|
19194
19216
|
atFinal && minOrderShortfalls.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
19195
19217
|
"div",
|
|
@@ -19742,7 +19764,7 @@ function TimelineList({
|
|
|
19742
19764
|
children: [
|
|
19743
19765
|
...meal.intentBlocks.map((b, i) => ({
|
|
19744
19766
|
kind: "intent",
|
|
19745
|
-
key: b.
|
|
19767
|
+
key: b.intent.id,
|
|
19746
19768
|
phrase: b.intent.phrase,
|
|
19747
19769
|
idx: i
|
|
19748
19770
|
})),
|
|
@@ -20812,13 +20834,13 @@ function resolveDraftItems(mealSessionParts, aiMealSessions, activeMealSessionIn
|
|
|
20812
20834
|
}
|
|
20813
20835
|
const out = [];
|
|
20814
20836
|
for (const block of ms.intentBlocks) {
|
|
20815
|
-
const selectedRestaurantId = cart.getSelectedRestaurantId(block.
|
|
20837
|
+
const selectedRestaurantId = cart.getSelectedRestaurantId(block.intent.id) ?? block.restaurantPicks[0]?.restaurant.id;
|
|
20816
20838
|
if (!selectedRestaurantId) continue;
|
|
20817
20839
|
const pick = block.restaurantPicks.find(
|
|
20818
20840
|
(rp) => rp.restaurant.id === selectedRestaurantId
|
|
20819
20841
|
);
|
|
20820
20842
|
if (!pick) continue;
|
|
20821
|
-
const cartIntent = cart.cart[block.
|
|
20843
|
+
const cartIntent = cart.cart[block.intent.id];
|
|
20822
20844
|
const removedSet = new Set(cartIntent?.removedItemIds ?? []);
|
|
20823
20845
|
const pickedSet = new Set(cartIntent?.pickedItemIds ?? []);
|
|
20824
20846
|
const liveItems = [
|
|
@@ -20830,7 +20852,7 @@ function resolveDraftItems(mealSessionParts, aiMealSessions, activeMealSessionIn
|
|
|
20830
20852
|
)
|
|
20831
20853
|
];
|
|
20832
20854
|
for (const it of liveItems) {
|
|
20833
|
-
const qty = qtyByItemKey.get(`${block.
|
|
20855
|
+
const qty = qtyByItemKey.get(`${block.intent.id}::${it.id}`) ?? 0;
|
|
20834
20856
|
if (qty <= 0) continue;
|
|
20835
20857
|
out.push({
|
|
20836
20858
|
id: it.id,
|
|
@@ -20850,7 +20872,7 @@ function resolveDraftItems(mealSessionParts, aiMealSessions, activeMealSessionIn
|
|
|
20850
20872
|
reason: it.reason ?? "",
|
|
20851
20873
|
restaurantId: selectedRestaurantId,
|
|
20852
20874
|
intentPhrase: block.intent.phrase,
|
|
20853
|
-
addonSelections: cart.getAddonSelections(block.
|
|
20875
|
+
addonSelections: cart.getAddonSelections(block.intent.id, it.id)
|
|
20854
20876
|
});
|
|
20855
20877
|
}
|
|
20856
20878
|
}
|
|
@@ -25703,6 +25725,8 @@ function CheckoutScreen() {
|
|
|
25703
25725
|
markOrderAsSubmitted();
|
|
25704
25726
|
setShowPaymentModal(false);
|
|
25705
25727
|
setSubmittedOrder(createCateringOrderResponse);
|
|
25728
|
+
const clearedSid = clearChatSessionStorage();
|
|
25729
|
+
clearCartStorage(clearedSid);
|
|
25706
25730
|
const orderId = createCateringOrderResponse?.id ?? "";
|
|
25707
25731
|
const accessToken = createCateringOrderResponse?.sharedAccessUsers?.[0]?.accessToken ?? "";
|
|
25708
25732
|
setPendingOrderResult({
|
|
@@ -26373,7 +26397,7 @@ function CheckoutScreen() {
|
|
|
26373
26397
|
deliveryFeeAmt.toFixed(2)
|
|
26374
26398
|
] })
|
|
26375
26399
|
] }),
|
|
26376
|
-
promoDiscountAmt >
|
|
26400
|
+
promoDiscountAmt > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-between text-sm text-success font-medium", children: [
|
|
26377
26401
|
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Promo Discount" }),
|
|
26378
26402
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
26379
26403
|
"-\xA3",
|
|
@@ -29061,7 +29085,17 @@ function CateringOrderBuilder() {
|
|
|
29061
29085
|
)
|
|
29062
29086
|
}
|
|
29063
29087
|
),
|
|
29064
|
-
mobileChatView === "chat" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
29088
|
+
mobileChatView === "chat" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
29089
|
+
MobileChatFloatingChips,
|
|
29090
|
+
{
|
|
29091
|
+
bottomOffset: mobileAIInputHeight + 28,
|
|
29092
|
+
inputRef: mobileAIInputRef,
|
|
29093
|
+
onCancelFeedback: () => {
|
|
29094
|
+
setMobileAIInput("");
|
|
29095
|
+
resetMobileAIInputHeight();
|
|
29096
|
+
}
|
|
29097
|
+
}
|
|
29098
|
+
)
|
|
29065
29099
|
]
|
|
29066
29100
|
},
|
|
29067
29101
|
"chat-surface"
|
|
@@ -29630,15 +29664,24 @@ function MobileChatThread({
|
|
|
29630
29664
|
const paddingTop = hasAddressTopPill ? 68 : 56;
|
|
29631
29665
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-4", style: { paddingTop, paddingBottom }, children: /* @__PURE__ */ jsxRuntime.jsx(ChatMessagesView, {}) });
|
|
29632
29666
|
}
|
|
29633
|
-
function MobileChatFloatingChips({
|
|
29667
|
+
function MobileChatFloatingChips({
|
|
29668
|
+
bottomOffset,
|
|
29669
|
+
inputRef,
|
|
29670
|
+
onCancelFeedback
|
|
29671
|
+
}) {
|
|
29634
29672
|
const {
|
|
29635
29673
|
hasResults,
|
|
29636
29674
|
onViewResults,
|
|
29637
29675
|
feedbackTarget,
|
|
29638
29676
|
feedbackRating,
|
|
29639
29677
|
setFeedbackRating,
|
|
29678
|
+
feedbackState,
|
|
29640
29679
|
cancelFeedback
|
|
29641
29680
|
} = useChatSessionContext();
|
|
29681
|
+
const handleCancel = () => {
|
|
29682
|
+
cancelFeedback();
|
|
29683
|
+
onCancelFeedback?.();
|
|
29684
|
+
};
|
|
29642
29685
|
const [feedbackHover, setFeedbackHover] = react.useState(0);
|
|
29643
29686
|
const inFeedbackMode = feedbackTarget !== null;
|
|
29644
29687
|
react.useEffect(() => {
|
|
@@ -29665,7 +29708,7 @@ function MobileChatFloatingChips({ bottomOffset, inputRef }) {
|
|
|
29665
29708
|
"button",
|
|
29666
29709
|
{
|
|
29667
29710
|
type: "button",
|
|
29668
|
-
onClick:
|
|
29711
|
+
onClick: handleCancel,
|
|
29669
29712
|
className: "p-0.5 rounded text-white/60 hover:text-white transition-colors",
|
|
29670
29713
|
"aria-label": "Cancel feedback",
|
|
29671
29714
|
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "w-3.5 h-3.5" })
|
|
@@ -29693,7 +29736,9 @@ function MobileChatFloatingChips({ bottomOffset, inputRef }) {
|
|
|
29693
29736
|
},
|
|
29694
29737
|
n
|
|
29695
29738
|
)) }),
|
|
29696
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-white/80 min-w-[3.5rem]", children: activeStar > 0 ? RATING_LABELS[activeStar - 1] : "" })
|
|
29739
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-white/80 min-w-[3.5rem]", children: feedbackState === "done" ? "" : activeStar > 0 ? RATING_LABELS[activeStar - 1] : "" }),
|
|
29740
|
+
feedbackState === "error" && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-red-300", children: "Failed" }),
|
|
29741
|
+
feedbackState === "done" && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-green-300 font-medium", children: "Thanks!" })
|
|
29697
29742
|
]
|
|
29698
29743
|
},
|
|
29699
29744
|
"feedback-pill"
|
|
@@ -29731,13 +29776,11 @@ function MobileAIInput({
|
|
|
29731
29776
|
chat: { sending, bootstrapping, sessionId, sendText, submitFeedback },
|
|
29732
29777
|
feedbackTarget,
|
|
29733
29778
|
feedbackRating,
|
|
29779
|
+
feedbackState,
|
|
29780
|
+
setFeedbackState,
|
|
29734
29781
|
cancelFeedback
|
|
29735
29782
|
} = useChatSessionContext();
|
|
29736
29783
|
const inFeedbackMode = feedbackTarget !== null;
|
|
29737
|
-
const [feedbackState, setFeedbackState] = react.useState("idle");
|
|
29738
|
-
react.useEffect(() => {
|
|
29739
|
-
if (!feedbackTarget) setFeedbackState("idle");
|
|
29740
|
-
}, [feedbackTarget]);
|
|
29741
29784
|
const chatDisabled = sending || bootstrapping || !sessionId;
|
|
29742
29785
|
const inputDisabled = inFeedbackMode ? feedbackState === "sending" : bootstrapping || !sessionId;
|
|
29743
29786
|
const sendDisabled = inFeedbackMode ? feedbackState === "sending" : submitBlocked || (chatDisabled || !value.trim());
|