@swift-food-services/catering-widget 0.2.0-beta.12 → 0.2.0-beta.13

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 CHANGED
@@ -2765,6 +2765,55 @@ styleInject(`/*! tailwindcss v4.2.4 | MIT License | https://tailwindcss.com */
2765
2765
  translate: 0 -35%;
2766
2766
  rotate: 0deg;
2767
2767
  }
2768
+ .swift-catering-widget .\\!rating {
2769
+ vertical-align: middle !important;
2770
+ display: inline-flex !important;
2771
+ position: relative !important;
2772
+ }
2773
+ .swift-catering-widget .\\!rating input {
2774
+ appearance: none !important;
2775
+ border: none !important;
2776
+ }
2777
+ .swift-catering-widget .\\!rating :where(*) {
2778
+ background-color: var(--color-base-content) !important;
2779
+ opacity: .2 !important;
2780
+ border-radius: 0 !important;
2781
+ width: 1.5rem !important;
2782
+ height: 1.5rem !important;
2783
+ }
2784
+ @media (prefers-reduced-motion: no-preference) {
2785
+ .swift-catering-widget .\\!rating :where(*) {
2786
+ animation: .25s ease-out rating !important;
2787
+ }
2788
+ }
2789
+ .swift-catering-widget .\\!rating :where(*):is(input) {
2790
+ cursor: pointer !important;
2791
+ }
2792
+ .swift-catering-widget .\\!rating .rating-hidden {
2793
+ background-color: #0000 !important;
2794
+ width: .5rem !important;
2795
+ }
2796
+ .swift-catering-widget .\\!rating input[type=radio]:checked {
2797
+ background-image: none !important;
2798
+ }
2799
+ .swift-catering-widget .\\!rating :checked,
2800
+ .swift-catering-widget .\\!rating [aria-checked=true],
2801
+ .swift-catering-widget .\\!rating [aria-current=true],
2802
+ .swift-catering-widget .\\!rating :has(~ :checked, ~ [aria-checked=true], ~ [aria-current=true]) {
2803
+ opacity: 1 !important;
2804
+ }
2805
+ .swift-catering-widget .\\!rating :focus-visible {
2806
+ scale: 1.1 !important;
2807
+ }
2808
+ @media (prefers-reduced-motion: no-preference) {
2809
+ .swift-catering-widget .\\!rating :focus-visible {
2810
+ transition: scale .2s ease-out !important;
2811
+ }
2812
+ }
2813
+ .swift-catering-widget .\\!rating :active:focus {
2814
+ animation: none !important;
2815
+ scale: 1.1 !important;
2816
+ }
2768
2817
  .swift-catering-widget .rating {
2769
2818
  vertical-align: middle;
2770
2819
  display: inline-flex;
@@ -3422,6 +3471,26 @@ styleInject(`/*! tailwindcss v4.2.4 | MIT License | https://tailwindcss.com */
3422
3471
  cursor: not-allowed;
3423
3472
  opacity: .2;
3424
3473
  }
3474
+ .swift-catering-widget .\\!rating.rating-xs :where(:not(.rating-hidden)) {
3475
+ width: 1rem !important;
3476
+ height: 1rem !important;
3477
+ }
3478
+ .swift-catering-widget .\\!rating.rating-sm :where(:not(.rating-hidden)) {
3479
+ width: 1.25rem !important;
3480
+ height: 1.25rem !important;
3481
+ }
3482
+ .swift-catering-widget .\\!rating.rating-md :where(:not(.rating-hidden)) {
3483
+ width: 1.5rem !important;
3484
+ height: 1.5rem !important;
3485
+ }
3486
+ .swift-catering-widget .\\!rating.rating-lg :where(:not(.rating-hidden)) {
3487
+ width: 1.75rem !important;
3488
+ height: 1.75rem !important;
3489
+ }
3490
+ .swift-catering-widget .\\!rating.rating-xl :where(:not(.rating-hidden)) {
3491
+ width: 2rem !important;
3492
+ height: 2rem !important;
3493
+ }
3425
3494
  .swift-catering-widget .rating.rating-xs :where(:not(.rating-hidden)) {
3426
3495
  width: 1rem;
3427
3496
  height: 1rem;
@@ -6490,9 +6559,6 @@ styleInject(`/*! tailwindcss v4.2.4 | MIT License | https://tailwindcss.com */
6490
6559
  .swift-catering-widget .disabled\\:opacity-50:disabled {
6491
6560
  opacity: .5;
6492
6561
  }
6493
- .swift-catering-widget .disabled\\:opacity-60:disabled {
6494
- opacity: .6;
6495
- }
6496
6562
  .swift-catering-widget .disabled\\:shadow-none:disabled {
6497
6563
  --tw-shadow:0 0 #0000;
6498
6564
  box-shadow:
@@ -8425,9 +8491,194 @@ function applySelectedAddons(live, snapshotAddons) {
8425
8491
  return { ...live, selectedAddons, addonPrice };
8426
8492
  }
8427
8493
 
8494
+ // src/components/catering-order-helpers.ts
8495
+ var to12h = (totalMins) => {
8496
+ const h = Math.floor(totalMins / 60);
8497
+ const m = totalMins % 60;
8498
+ const period = h >= 12 ? "pm" : "am";
8499
+ const h12 = h % 12 || 12;
8500
+ return `${h12}:${String(m).padStart(2, "0")}${period}`;
8501
+ };
8502
+ var TIME_SLOT_OPTIONS = (() => {
8503
+ const slots = [];
8504
+ for (let startMins = 7 * 60; startMins <= 20 * 60; startMins += 30) {
8505
+ const endMins = startMins + 30;
8506
+ const sH = String(Math.floor(startMins / 60)).padStart(2, "0");
8507
+ const sM = String(startMins % 60).padStart(2, "0");
8508
+ slots.push({ label: `${to12h(startMins)} - ${to12h(endMins)}`, value: `${sH}:${sM}` });
8509
+ }
8510
+ return slots;
8511
+ })();
8512
+ function groupSessionsByDay(sessions, getSessionTotal) {
8513
+ const groups = /* @__PURE__ */ new Map();
8514
+ sessions.forEach((session, index) => {
8515
+ const date = session.sessionDate || "unscheduled";
8516
+ if (!groups.has(date)) {
8517
+ const dateObj = date !== "unscheduled" ? /* @__PURE__ */ new Date(date + "T00:00:00") : null;
8518
+ groups.set(date, {
8519
+ date,
8520
+ displayDate: dateObj?.toLocaleDateString("en-GB", {
8521
+ day: "numeric",
8522
+ month: "short"
8523
+ }) || "No Date",
8524
+ fullDate: dateObj?.toLocaleDateString("en-GB", {
8525
+ day: "numeric",
8526
+ month: "long",
8527
+ year: "numeric"
8528
+ }) || "Unscheduled",
8529
+ dayName: dateObj?.toLocaleDateString("en-GB", { weekday: "short" }) || "",
8530
+ sessions: [],
8531
+ total: 0
8532
+ });
8533
+ }
8534
+ const group = groups.get(date);
8535
+ group.sessions.push({ session, index });
8536
+ group.total += getSessionTotal(index);
8537
+ });
8538
+ groups.forEach((group) => {
8539
+ group.sessions.sort((a, b) => {
8540
+ if (!a.session.eventTime && !b.session.eventTime) return 0;
8541
+ if (!a.session.eventTime) return 1;
8542
+ if (!b.session.eventTime) return -1;
8543
+ return a.session.eventTime.localeCompare(b.session.eventTime);
8544
+ });
8545
+ });
8546
+ return Array.from(groups.values()).sort((a, b) => {
8547
+ if (a.date === "unscheduled") return 1;
8548
+ if (b.date === "unscheduled") return -1;
8549
+ return a.date.localeCompare(b.date);
8550
+ });
8551
+ }
8552
+ function formatTimeDisplay(eventTime) {
8553
+ if (!eventTime) return "Set time";
8554
+ const [hours, minutes] = eventTime.split(":");
8555
+ const hour = parseInt(hours);
8556
+ const minute = parseInt(minutes);
8557
+ const period = hour >= 12 ? "PM" : "AM";
8558
+ const hour12 = hour % 12 || 12;
8559
+ const start = `${hour12}:${String(minute).padStart(2, "0")} ${period}`;
8560
+ const totalEnd = hour * 60 + minute + 30;
8561
+ const endHour = Math.floor(totalEnd / 60) % 24;
8562
+ const endMinute = totalEnd % 60;
8563
+ const endPeriod = endHour >= 12 ? "PM" : "AM";
8564
+ const endHour12 = endHour % 12 || 12;
8565
+ return `${start} \u2013 ${endHour12}:${String(endMinute).padStart(2, "0")} ${endPeriod}`;
8566
+ }
8567
+ function getMinDate() {
8568
+ const date = /* @__PURE__ */ new Date();
8569
+ return date.toISOString().split("T")[0];
8570
+ }
8571
+ function getMaxDate() {
8572
+ const date = /* @__PURE__ */ new Date();
8573
+ date.setMonth(date.getMonth() + 3);
8574
+ return date.toISOString().split("T")[0];
8575
+ }
8576
+ function mapToMenuItem(item) {
8577
+ return {
8578
+ id: item.id,
8579
+ menuItemName: item.name,
8580
+ description: item.description,
8581
+ price: item.price?.toString() || "0",
8582
+ discountPrice: item.discountPrice?.toString(),
8583
+ allergens: item.allergens,
8584
+ isDiscount: item.isDiscount || false,
8585
+ images: item.images ?? (item.image ? [item.image] : []),
8586
+ averageRating: item.averageRating,
8587
+ restaurantId: item.restaurantId,
8588
+ restaurantName: item.restaurant?.restaurant_name,
8589
+ restaurant: item.restaurant ? {
8590
+ id: item.restaurant.id || item.restaurantId,
8591
+ name: item.restaurant.restaurant_name || item.restaurant.name,
8592
+ restaurantId: item.restaurantId,
8593
+ menuGroupSettings: item.restaurant.menuGroupSettings,
8594
+ images: item.restaurant.images || item.restaurant.image
8595
+ } : void 0,
8596
+ groupTitle: item.groupTitle,
8597
+ status: item.status,
8598
+ itemDisplayOrder: item.itemDisplayOrder || 0,
8599
+ cateringQuantityUnit: item.cateringQuantityUnit,
8600
+ feedsPerUnit: item.feedsPerUnit,
8601
+ minOrderQuantity: item.minOrderQuantity,
8602
+ dietaryFilters: item.dietaryFilters,
8603
+ categoryId: item.categories?.[0]?.id || item.categoryId,
8604
+ categoryName: item.categories?.[0]?.name || item.categoryName,
8605
+ // Include subcategory info from API response
8606
+ subcategoryId: item.subcategories?.[0]?.id,
8607
+ subcategoryName: item.subcategories?.[0]?.name,
8608
+ addons: (item.addons || []).map((group) => ({
8609
+ groupTitle: group.groupTitle || "",
8610
+ selectionType: group.selectionType === "multiple" ? "multiple_no_repeat" : group.selectionType || "multiple_no_repeat",
8611
+ isRequired: group.isRequired || false,
8612
+ minSelections: group.minSelections,
8613
+ maxSelections: group.maxSelections,
8614
+ items: (group.items || []).map((addon) => ({
8615
+ name: addon.name,
8616
+ price: addon.price?.toString() || "0",
8617
+ allergens: addon.allergens?.join?.(", ") || "",
8618
+ dietaryRestrictions: addon.dietaryRestrictions,
8619
+ isDefault: addon.isDefault,
8620
+ displayOrder: addon.displayOrder
8621
+ }))
8622
+ }))
8623
+ };
8624
+ }
8625
+ function formatTime(hour, minute) {
8626
+ const period = hour >= 12 ? "PM" : "AM";
8627
+ const hour12 = hour % 12 || 12;
8628
+ return `${hour12}:${minute.toString().padStart(2, "0")} ${period}`;
8629
+ }
8630
+
8631
+ // src/hooks/useImportCart.ts
8632
+ function useImportCart() {
8633
+ const { loadMealSessions } = useCateringState();
8634
+ const [status, setStatus] = react.useState("idle");
8635
+ const loadById = async (id) => {
8636
+ const { cart } = await cateringService.getSharedCart(id);
8637
+ const { mealSessions, missing } = await hydrateCartFromSnapshot(
8638
+ cart,
8639
+ // Map raw API items → widget MenuItem shape, same as every other
8640
+ // getMenuItemsByRestaurant caller (RestaurantMenuBrowser, BundleBrowser).
8641
+ // Without this the cart reads menuItemName/dietaryFilters off the raw
8642
+ // entity (name/dietaryFilters) → blank item names + dietary on load.
8643
+ (rid) => cateringService.getMenuItemsByRestaurant(rid).then((items) => items.map(mapToMenuItem))
8644
+ );
8645
+ const empty = mealSessions.every((s) => s.orderItems.length === 0);
8646
+ if (!empty) loadMealSessions(mealSessions);
8647
+ return { ok: !empty, empty, missing: missing.length };
8648
+ };
8649
+ const handleImport = async () => {
8650
+ if (status === "loading") return;
8651
+ const id = window.prompt("Enter a cart code to import:")?.trim();
8652
+ if (!id) return;
8653
+ setStatus("loading");
8654
+ try {
8655
+ const { empty, missing } = await loadById(id);
8656
+ if (empty) {
8657
+ window.alert("The items in this shared cart are no longer available.");
8658
+ setStatus("idle");
8659
+ return;
8660
+ }
8661
+ if (missing > 0) {
8662
+ window.alert(
8663
+ `${missing} item${missing === 1 ? "" : "s"} from this shared cart ${missing === 1 ? "is" : "are"} no longer available and ${missing === 1 ? "was" : "were"} removed.`
8664
+ );
8665
+ }
8666
+ setStatus("done");
8667
+ setTimeout(() => setStatus("idle"), 2500);
8668
+ } catch (err) {
8669
+ console.error("[catering] failed to import shared cart", err);
8670
+ window.alert("We couldn't load that cart \u2014 check the code and try again.");
8671
+ setStatus("error");
8672
+ setTimeout(() => setStatus("idle"), 2500);
8673
+ }
8674
+ };
8675
+ const label = status === "loading" ? "Importing\u2026" : status === "done" ? "Cart imported" : status === "error" ? "Try again" : "Import cart";
8676
+ return { status, handleImport, label, loadById };
8677
+ }
8678
+
8428
8679
  // src/components/SharedCartLoader.tsx
8429
8680
  function SharedCartLoader() {
8430
- const { loadMealSessions } = useCateringState();
8681
+ const { loadById } = useImportCart();
8431
8682
  react.useEffect(() => {
8432
8683
  if (typeof window === "undefined") return;
8433
8684
  const id = new URLSearchParams(window.location.search).get("sharedCart");
@@ -8435,24 +8686,16 @@ function SharedCartLoader() {
8435
8686
  let cancelled = false;
8436
8687
  void (async () => {
8437
8688
  try {
8438
- const { cart } = await cateringService.getSharedCart(id);
8439
- const { mealSessions, missing } = await hydrateCartFromSnapshot(
8440
- cart,
8441
- (rid) => cateringService.getMenuItemsByRestaurant(rid)
8442
- );
8689
+ const { empty, missing } = await loadById(id);
8443
8690
  if (cancelled) return;
8444
- if (mealSessions.every((s) => s.orderItems.length === 0)) {
8691
+ if (empty) {
8445
8692
  window.alert(
8446
8693
  "The items in this shared cart are no longer available."
8447
8694
  );
8448
- } else {
8449
- loadMealSessions(mealSessions);
8450
- if (missing.length > 0) {
8451
- const n = missing.length;
8452
- window.alert(
8453
- `${n} item${n === 1 ? "" : "s"} from this shared cart ${n === 1 ? "is" : "are"} no longer available and ${n === 1 ? "was" : "were"} removed.`
8454
- );
8455
- }
8695
+ } else if (missing > 0) {
8696
+ window.alert(
8697
+ `${missing} item${missing === 1 ? "" : "s"} from this shared cart ${missing === 1 ? "is" : "are"} no longer available and ${missing === 1 ? "was" : "were"} removed.`
8698
+ );
8456
8699
  }
8457
8700
  const url = new URL(window.location.href);
8458
8701
  url.searchParams.delete("sharedCart");
@@ -11170,149 +11413,12 @@ function validateSessionMinOrders(session, restaurants) {
11170
11413
  (restaurant) => validateRestaurantMinOrders(session, restaurant)
11171
11414
  );
11172
11415
  }
11173
-
11174
- // src/components/catering-order-helpers.ts
11175
- var to12h = (totalMins) => {
11176
- const h = Math.floor(totalMins / 60);
11177
- const m = totalMins % 60;
11178
- const period = h >= 12 ? "pm" : "am";
11179
- const h12 = h % 12 || 12;
11180
- return `${h12}:${String(m).padStart(2, "0")}${period}`;
11181
- };
11182
- var TIME_SLOT_OPTIONS = (() => {
11183
- const slots = [];
11184
- for (let startMins = 7 * 60; startMins <= 20 * 60; startMins += 30) {
11185
- const endMins = startMins + 30;
11186
- const sH = String(Math.floor(startMins / 60)).padStart(2, "0");
11187
- const sM = String(startMins % 60).padStart(2, "0");
11188
- slots.push({ label: `${to12h(startMins)} - ${to12h(endMins)}`, value: `${sH}:${sM}` });
11189
- }
11190
- return slots;
11191
- })();
11192
- function groupSessionsByDay(sessions, getSessionTotal) {
11193
- const groups = /* @__PURE__ */ new Map();
11194
- sessions.forEach((session, index) => {
11195
- const date = session.sessionDate || "unscheduled";
11196
- if (!groups.has(date)) {
11197
- const dateObj = date !== "unscheduled" ? /* @__PURE__ */ new Date(date + "T00:00:00") : null;
11198
- groups.set(date, {
11199
- date,
11200
- displayDate: dateObj?.toLocaleDateString("en-GB", {
11201
- day: "numeric",
11202
- month: "short"
11203
- }) || "No Date",
11204
- fullDate: dateObj?.toLocaleDateString("en-GB", {
11205
- day: "numeric",
11206
- month: "long",
11207
- year: "numeric"
11208
- }) || "Unscheduled",
11209
- dayName: dateObj?.toLocaleDateString("en-GB", { weekday: "short" }) || "",
11210
- sessions: [],
11211
- total: 0
11212
- });
11213
- }
11214
- const group = groups.get(date);
11215
- group.sessions.push({ session, index });
11216
- group.total += getSessionTotal(index);
11217
- });
11218
- groups.forEach((group) => {
11219
- group.sessions.sort((a, b) => {
11220
- if (!a.session.eventTime && !b.session.eventTime) return 0;
11221
- if (!a.session.eventTime) return 1;
11222
- if (!b.session.eventTime) return -1;
11223
- return a.session.eventTime.localeCompare(b.session.eventTime);
11224
- });
11225
- });
11226
- return Array.from(groups.values()).sort((a, b) => {
11227
- if (a.date === "unscheduled") return 1;
11228
- if (b.date === "unscheduled") return -1;
11229
- return a.date.localeCompare(b.date);
11230
- });
11231
- }
11232
- function formatTimeDisplay(eventTime) {
11233
- if (!eventTime) return "Set time";
11234
- const [hours, minutes] = eventTime.split(":");
11235
- const hour = parseInt(hours);
11236
- const minute = parseInt(minutes);
11237
- const period = hour >= 12 ? "PM" : "AM";
11238
- const hour12 = hour % 12 || 12;
11239
- const start = `${hour12}:${String(minute).padStart(2, "0")} ${period}`;
11240
- const totalEnd = hour * 60 + minute + 30;
11241
- const endHour = Math.floor(totalEnd / 60) % 24;
11242
- const endMinute = totalEnd % 60;
11243
- const endPeriod = endHour >= 12 ? "PM" : "AM";
11244
- const endHour12 = endHour % 12 || 12;
11245
- return `${start} \u2013 ${endHour12}:${String(endMinute).padStart(2, "0")} ${endPeriod}`;
11246
- }
11247
- function getMinDate() {
11248
- const date = /* @__PURE__ */ new Date();
11249
- return date.toISOString().split("T")[0];
11250
- }
11251
- function getMaxDate() {
11252
- const date = /* @__PURE__ */ new Date();
11253
- date.setMonth(date.getMonth() + 3);
11254
- return date.toISOString().split("T")[0];
11255
- }
11256
- function mapToMenuItem(item) {
11257
- return {
11258
- id: item.id,
11259
- menuItemName: item.name,
11260
- description: item.description,
11261
- price: item.price?.toString() || "0",
11262
- discountPrice: item.discountPrice?.toString(),
11263
- allergens: item.allergens,
11264
- isDiscount: item.isDiscount || false,
11265
- images: item.images ?? (item.image ? [item.image] : []),
11266
- averageRating: item.averageRating,
11267
- restaurantId: item.restaurantId,
11268
- restaurantName: item.restaurant?.restaurant_name,
11269
- restaurant: item.restaurant ? {
11270
- id: item.restaurant.id || item.restaurantId,
11271
- name: item.restaurant.restaurant_name || item.restaurant.name,
11272
- restaurantId: item.restaurantId,
11273
- menuGroupSettings: item.restaurant.menuGroupSettings,
11274
- images: item.restaurant.images || item.restaurant.image
11275
- } : void 0,
11276
- groupTitle: item.groupTitle,
11277
- status: item.status,
11278
- itemDisplayOrder: item.itemDisplayOrder || 0,
11279
- cateringQuantityUnit: item.cateringQuantityUnit,
11280
- feedsPerUnit: item.feedsPerUnit,
11281
- minOrderQuantity: item.minOrderQuantity,
11282
- dietaryFilters: item.dietaryFilters,
11283
- categoryId: item.categories?.[0]?.id || item.categoryId,
11284
- categoryName: item.categories?.[0]?.name || item.categoryName,
11285
- // Include subcategory info from API response
11286
- subcategoryId: item.subcategories?.[0]?.id,
11287
- subcategoryName: item.subcategories?.[0]?.name,
11288
- addons: (item.addons || []).map((group) => ({
11289
- groupTitle: group.groupTitle || "",
11290
- selectionType: group.selectionType === "multiple" ? "multiple_no_repeat" : group.selectionType || "multiple_no_repeat",
11291
- isRequired: group.isRequired || false,
11292
- minSelections: group.minSelections,
11293
- maxSelections: group.maxSelections,
11294
- items: (group.items || []).map((addon) => ({
11295
- name: addon.name,
11296
- price: addon.price?.toString() || "0",
11297
- allergens: addon.allergens?.join?.(", ") || "",
11298
- dietaryRestrictions: addon.dietaryRestrictions,
11299
- isDefault: addon.isDefault,
11300
- displayOrder: addon.displayOrder
11301
- }))
11302
- }))
11303
- };
11304
- }
11305
- function formatTime(hour, minute) {
11306
- const period = hour >= 12 ? "PM" : "AM";
11307
- const hour12 = hour % 12 || 12;
11308
- return `${hour12}:${minute.toString().padStart(2, "0")} ${period}`;
11309
- }
11310
- function readPrimaryColor(from) {
11311
- if (!from) return void 0;
11312
- const root = from.closest(".swift-catering-widget");
11313
- if (!root) return void 0;
11314
- const value = getComputedStyle(root).getPropertyValue("--swift-primary").trim();
11315
- return value || void 0;
11416
+ function readPrimaryColor(from) {
11417
+ if (!from) return void 0;
11418
+ const root = from.closest(".swift-catering-widget");
11419
+ if (!root) return void 0;
11420
+ const value = getComputedStyle(root).getPropertyValue("--swift-primary").trim();
11421
+ return value || void 0;
11316
11422
  }
11317
11423
  function TimeSlotDropdown({
11318
11424
  value,
@@ -21799,118 +21905,120 @@ function PricingSummary({
21799
21905
  if (calculatingPricing && !pricing) {
21800
21906
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: `text-center text-base-content/60 ${compact ? "py-2 text-xs" : "py-4 text-sm"}`, children: "Calculating pricing..." });
21801
21907
  }
21802
- if (pricing) {
21803
- const deliveryBreakdown = pricing.deliveryFeeBreakdown || pricing.mealSessions?.[0]?.deliveryFeeBreakdown;
21804
- const distanceInMiles = pricing.distanceInMiles || pricing.mealSessions?.[0]?.distanceInMiles;
21805
- const backendPromos = pricing.appliedPromotions?.filter((p) => p.discount > 0) ?? [];
21806
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `transition-opacity duration-200 ${calculatingPricing ? "opacity-50" : "opacity-100"} ${compact ? "space-y-1.5" : "border-t border-base-300 space-y-2 pt-4"}`, children: [
21807
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `flex justify-between text-base-content/70 ${compact ? "text-xs" : "text-sm"}`, children: [
21808
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Subtotal" }),
21809
- /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
21810
- "\xA3",
21811
- pricing.subtotal.toFixed(2)
21812
- ] })
21908
+ if (!pricing && estimatedTotal !== void 0) {
21909
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-between pt-4 border-t border-base-300", children: [
21910
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-semibold text-base-content", children: "Estimated Total:" }),
21911
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-bold text-xl text-base-content", children: [
21912
+ "\xA3",
21913
+ estimatedTotal.toFixed(2)
21914
+ ] })
21915
+ ] });
21916
+ }
21917
+ const quote = pricing ?? {
21918
+ subtotal: 0,
21919
+ deliveryFee: 0,
21920
+ total: 0
21921
+ };
21922
+ const deliveryBreakdown = quote.deliveryFeeBreakdown || quote.mealSessions?.[0]?.deliveryFeeBreakdown;
21923
+ const distanceInMiles = quote.distanceInMiles || quote.mealSessions?.[0]?.distanceInMiles;
21924
+ const backendPromos = quote.appliedPromotions?.filter((p) => p.discount > 0) ?? [];
21925
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `transition-opacity duration-200 ${calculatingPricing ? "opacity-50" : "opacity-100"} ${compact ? "space-y-1.5" : "border-t border-base-300 space-y-2 pt-4"}`, children: [
21926
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `flex justify-between text-base-content/70 ${compact ? "text-xs" : "text-sm"}`, children: [
21927
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Subtotal" }),
21928
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
21929
+ "\xA3",
21930
+ quote.subtotal.toFixed(2)
21931
+ ] })
21932
+ ] }),
21933
+ (quote.promotionDiscount ?? 0) > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `flex justify-between text-green-600 font-semibold ${compact ? "text-xs" : "text-sm"}`, children: [
21934
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
21935
+ "Restaurant Promotion",
21936
+ backendPromos.length > 1 ? "s" : ""
21813
21937
  ] }),
21814
- (pricing.promotionDiscount ?? 0) > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `flex justify-between text-green-600 font-semibold ${compact ? "text-xs" : "text-sm"}`, children: [
21815
- /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
21816
- "Restaurant Promotion",
21817
- backendPromos.length > 1 ? "s" : ""
21938
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
21939
+ "-\xA3",
21940
+ quote.promotionDiscount.toFixed(2)
21941
+ ] })
21942
+ ] }),
21943
+ (quote.promoDiscount ?? 0) > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `flex justify-between text-success font-medium ${compact ? "text-xs" : "text-sm"}`, children: [
21944
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Promo Code Discount" }),
21945
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
21946
+ "-\xA3",
21947
+ quote.promoDiscount.toFixed(2)
21948
+ ] })
21949
+ ] }),
21950
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
21951
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `flex justify-between items-center text-base-content/70 gap-2 ${compact ? "text-xs" : "text-sm"}`, children: [
21952
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1 flex-shrink-0", children: [
21953
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "whitespace-nowrap", children: "Delivery Cost" }),
21954
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative group", children: [
21955
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "text-base-content/30 hover:text-base-content/60 leading-none", children: /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-3 h-3", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" }) }) }),
21956
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute bottom-full left-0 mb-1.5 w-52 hidden group-hover:block z-50", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg-base-content text-base-100 text-[10px] leading-relaxed rounded-lg px-2.5 py-2 shadow-lg", children: "Based on number of restaurants, distance to your delivery address, and catering order size." }) })
21957
+ ] })
21818
21958
  ] }),
21819
- /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
21820
- "-\xA3",
21821
- pricing.promotionDiscount.toFixed(2)
21959
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5 min-w-0", children: [
21960
+ deliveryBreakdown && !compact && /* @__PURE__ */ jsxRuntime.jsx(
21961
+ "button",
21962
+ {
21963
+ onClick: () => setShowDeliveryBreakdown(!showDeliveryBreakdown),
21964
+ className: "text-base-content/40 hover:text-base-content/70",
21965
+ type: "button",
21966
+ children: /* @__PURE__ */ jsxRuntime.jsx(
21967
+ "svg",
21968
+ {
21969
+ className: `w-4 h-4 transition-transform ${showDeliveryBreakdown ? "rotate-180" : ""}`,
21970
+ fill: "none",
21971
+ stroke: "currentColor",
21972
+ viewBox: "0 0 24 24",
21973
+ children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 9l-7 7-7-7" })
21974
+ }
21975
+ )
21976
+ }
21977
+ ),
21978
+ distanceInMiles && onClearAddress && /* @__PURE__ */ jsxRuntime.jsx(
21979
+ "button",
21980
+ {
21981
+ type: "button",
21982
+ onClick: onClearAddress,
21983
+ className: "text-red-400 hover:text-red-600 transition-colors flex-shrink-0",
21984
+ title: "Change address",
21985
+ children: /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-3.5 h-3.5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", strokeWidth: 2.5, children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M6 18L18 6M6 6l12 12" }) })
21986
+ }
21987
+ ),
21988
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
21989
+ "\xA3",
21990
+ quote.deliveryFee.toFixed(2)
21991
+ ] }),
21992
+ !distanceInMiles && onPlaceSelect && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-base-content/40 text-xs italic", children: "(min)" })
21822
21993
  ] })
21823
21994
  ] }),
21824
- (pricing.promoDiscount ?? 0) > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `flex justify-between text-success font-medium ${compact ? "text-xs" : "text-sm"}`, children: [
21825
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Promo Code Discount" }),
21995
+ !distanceInMiles && onPlaceSelect && /* @__PURE__ */ jsxRuntime.jsx(InlineAddressInput, { onPlaceSelect }),
21996
+ showDeliveryBreakdown && quote.mealSessions && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pl-4 space-y-1 text-xs text-base-content/60", children: quote.mealSessions.map((session, index) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-between", children: [
21826
21997
  /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
21827
- "-\xA3",
21828
- pricing.promoDiscount.toFixed(2)
21998
+ session.sessionName,
21999
+ ":"
22000
+ ] }),
22001
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
22002
+ "\xA3",
22003
+ session.deliveryFee.toFixed(2)
21829
22004
  ] })
21830
- ] }),
21831
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
21832
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `flex justify-between items-center text-base-content/70 gap-2 ${compact ? "text-xs" : "text-sm"}`, children: [
21833
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1 flex-shrink-0", children: [
21834
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "whitespace-nowrap", children: "Delivery Cost" }),
21835
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative group", children: [
21836
- /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "text-base-content/30 hover:text-base-content/60 leading-none", children: /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-3 h-3", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" }) }) }),
21837
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute bottom-full left-0 mb-1.5 w-52 hidden group-hover:block z-50", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg-base-content text-base-100 text-[10px] leading-relaxed rounded-lg px-2.5 py-2 shadow-lg", children: "Based on number of restaurants, distance to your delivery address, and catering order size." }) })
21838
- ] })
21839
- ] }),
21840
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5 min-w-0", children: [
21841
- deliveryBreakdown && !compact && /* @__PURE__ */ jsxRuntime.jsx(
21842
- "button",
21843
- {
21844
- onClick: () => setShowDeliveryBreakdown(!showDeliveryBreakdown),
21845
- className: "text-base-content/40 hover:text-base-content/70",
21846
- type: "button",
21847
- children: /* @__PURE__ */ jsxRuntime.jsx(
21848
- "svg",
21849
- {
21850
- className: `w-4 h-4 transition-transform ${showDeliveryBreakdown ? "rotate-180" : ""}`,
21851
- fill: "none",
21852
- stroke: "currentColor",
21853
- viewBox: "0 0 24 24",
21854
- children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 9l-7 7-7-7" })
21855
- }
21856
- )
21857
- }
21858
- ),
21859
- distanceInMiles && onClearAddress && /* @__PURE__ */ jsxRuntime.jsx(
21860
- "button",
21861
- {
21862
- type: "button",
21863
- onClick: onClearAddress,
21864
- className: "text-red-400 hover:text-red-600 transition-colors flex-shrink-0",
21865
- title: "Change address",
21866
- children: /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-3.5 h-3.5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", strokeWidth: 2.5, children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M6 18L18 6M6 6l12 12" }) })
21867
- }
21868
- ),
21869
- /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
21870
- "\xA3",
21871
- pricing.deliveryFee.toFixed(2)
21872
- ] }),
21873
- !distanceInMiles && onPlaceSelect && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-base-content/40 text-xs italic", children: "(min)" })
21874
- ] })
22005
+ ] }, index)) }),
22006
+ deliveryBreakdown?.requiresCustomQuote && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-2 p-2 bg-warning/10 border border-warning/30 rounded text-warning-content", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs", children: "\u26A0\uFE0F Delivery exceeds 6 miles. Final fee subject to review." }) })
22007
+ ] }),
22008
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `flex justify-between font-bold text-base-content border-t border-base-300 ${compact ? "text-sm pt-2" : "text-lg pt-3"}`, children: [
22009
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Total" }),
22010
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-right", children: [
22011
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { children: [
22012
+ "\xA3",
22013
+ quote.total.toFixed(2)
21875
22014
  ] }),
21876
- !distanceInMiles && onPlaceSelect && /* @__PURE__ */ jsxRuntime.jsx(InlineAddressInput, { onPlaceSelect }),
21877
- showDeliveryBreakdown && pricing.mealSessions && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pl-4 space-y-1 text-xs text-base-content/60", children: pricing.mealSessions.map((session, index) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-between", children: [
21878
- /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
21879
- session.sessionName,
21880
- ":"
21881
- ] }),
21882
- /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
21883
- "\xA3",
21884
- session.deliveryFee.toFixed(2)
21885
- ] })
21886
- ] }, index)) }),
21887
- deliveryBreakdown?.requiresCustomQuote && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-2 p-2 bg-warning/10 border border-warning/30 rounded text-warning-content", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs", children: "\u26A0\uFE0F Delivery exceeds 6 miles. Final fee subject to review." }) })
21888
- ] }),
21889
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `flex justify-between font-bold text-base-content border-t border-base-300 ${compact ? "text-sm pt-2" : "text-lg pt-3"}`, children: [
21890
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Total" }),
21891
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-right", children: [
21892
- /* @__PURE__ */ jsxRuntime.jsxs("p", { children: [
21893
- "\xA3",
21894
- pricing.total.toFixed(2)
21895
- ] }),
21896
- (pricing.totalDiscount ?? 0) > 0 && /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-xs line-through font-normal text-base-content/50", children: [
21897
- "\xA3",
21898
- (pricing.subtotal + pricing.deliveryFee).toFixed(2)
21899
- ] })
22015
+ (quote.totalDiscount ?? 0) > 0 && /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-xs line-through font-normal text-base-content/50", children: [
22016
+ "\xA3",
22017
+ (quote.subtotal + quote.deliveryFee).toFixed(2)
21900
22018
  ] })
21901
22019
  ] })
21902
- ] });
21903
- }
21904
- if (estimatedTotal !== void 0) {
21905
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-between pt-4 border-t border-base-300", children: [
21906
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-semibold text-base-content", children: "Estimated Total:" }),
21907
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-bold text-xl text-base-content", children: [
21908
- "\xA3",
21909
- estimatedTotal.toFixed(2)
21910
- ] })
21911
- ] });
21912
- }
21913
- return null;
22020
+ ] })
22021
+ ] });
21914
22022
  }
21915
22023
  function ViewOrderModal({
21916
22024
  isOpen,
@@ -23068,7 +23176,9 @@ function RestaurantMenuBrowser({
23068
23176
  const [isDescriptionExpanded, setIsDescriptionExpanded] = react.useState(false);
23069
23177
  const [isDescriptionOverflowing, setIsDescriptionOverflowing] = react.useState(false);
23070
23178
  const descriptionRef = react.useRef(null);
23071
- const [restaurantMenuItems, setRestaurantMenuItems] = react.useState([]);
23179
+ const [restaurantMenuItems, setRestaurantMenuItems] = react.useState(
23180
+ []
23181
+ );
23072
23182
  const [restaurantMenuItemsLoading, setRestaurantMenuItemsLoading] = react.useState(false);
23073
23183
  const restaurantItemsCache = react.useRef(/* @__PURE__ */ new Map());
23074
23184
  react.useEffect(() => {
@@ -23142,12 +23252,19 @@ function RestaurantMenuBrowser({
23142
23252
  closeRestaurantSearch();
23143
23253
  };
23144
23254
  const scrollTimer = setTimeout(() => {
23145
- document.addEventListener("scroll", handleScroll, { capture: true, passive: true });
23255
+ document.addEventListener("scroll", handleScroll, {
23256
+ capture: true,
23257
+ passive: true
23258
+ });
23146
23259
  }, 100);
23147
- document.addEventListener("pointerdown", handlePointerDown, { capture: true });
23260
+ document.addEventListener("pointerdown", handlePointerDown, {
23261
+ capture: true
23262
+ });
23148
23263
  return () => {
23149
23264
  clearTimeout(scrollTimer);
23150
- document.removeEventListener("pointerdown", handlePointerDown, { capture: true });
23265
+ document.removeEventListener("pointerdown", handlePointerDown, {
23266
+ capture: true
23267
+ });
23151
23268
  document.removeEventListener("scroll", handleScroll, { capture: true });
23152
23269
  };
23153
23270
  }, [isRestaurantSearchOpen, restaurantSearchQuery]);
@@ -23430,7 +23547,10 @@ function RestaurantMenuBrowser({
23430
23547
  () => availableRestaurants.find((r) => r.id === selectedRestaurantId) || null,
23431
23548
  [availableRestaurants, selectedRestaurantId]
23432
23549
  );
23433
- const restaurantItems = react.useMemo(() => dietaryFilteredItems, [dietaryFilteredItems]);
23550
+ const restaurantItems = react.useMemo(
23551
+ () => dietaryFilteredItems,
23552
+ [dietaryFilteredItems]
23553
+ );
23434
23554
  const filteredRestaurantItems = react.useMemo(() => {
23435
23555
  if (!isRestaurantSearchActive) return restaurantItems;
23436
23556
  const query = restaurantSearchQuery.toLowerCase();
@@ -23543,17 +23663,31 @@ function RestaurantMenuBrowser({
23543
23663
  isRestaurantSearchActive
23544
23664
  ]);
23545
23665
  const firstMenuGroupName = groupedItems[0]?.name ?? null;
23546
- const ensureMenuItemsForBundle = react.useCallback(async (bundle) => {
23547
- const restaurantIds = [...new Set(bundle.items.map((i) => i.restaurantId).filter(Boolean))];
23548
- const missing = restaurantIds.filter((id) => !restaurantItemsCache.current.has(id));
23549
- if (missing.length > 0) {
23550
- const fetched = await Promise.all(missing.map((id) => cateringService.getMenuItemsByRestaurant(id)));
23551
- missing.forEach((id, idx) => {
23552
- restaurantItemsCache.current.set(id, (fetched[idx] || []).map(mapToMenuItem));
23553
- });
23554
- }
23555
- return restaurantIds.flatMap((id) => restaurantItemsCache.current.get(id) ?? []);
23556
- }, []);
23666
+ const ensureMenuItemsForBundle = react.useCallback(
23667
+ async (bundle) => {
23668
+ const restaurantIds = [
23669
+ ...new Set(bundle.items.map((i) => i.restaurantId).filter(Boolean))
23670
+ ];
23671
+ const missing = restaurantIds.filter(
23672
+ (id) => !restaurantItemsCache.current.has(id)
23673
+ );
23674
+ if (missing.length > 0) {
23675
+ const fetched = await Promise.all(
23676
+ missing.map((id) => cateringService.getMenuItemsByRestaurant(id))
23677
+ );
23678
+ missing.forEach((id, idx) => {
23679
+ restaurantItemsCache.current.set(
23680
+ id,
23681
+ (fetched[idx] || []).map(mapToMenuItem)
23682
+ );
23683
+ });
23684
+ }
23685
+ return restaurantIds.flatMap(
23686
+ (id) => restaurantItemsCache.current.get(id) ?? []
23687
+ );
23688
+ },
23689
+ []
23690
+ );
23557
23691
  const handleAddBundle = react.useCallback(
23558
23692
  async (bundle, guestQuantity) => {
23559
23693
  setAddingBundleId(bundle.id);
@@ -23735,7 +23869,7 @@ function RestaurantMenuBrowser({
23735
23869
  }
23736
23870
  ),
23737
23871
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1 p-3 flex flex-col relative", children: [
23738
- restaurant.logoImageUrl && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute top-1/2 right-2 -translate-y-1/2 w-12 h-12 rounded-full overflow-hidden border-2 border-white shadow-md", children: /* @__PURE__ */ jsxRuntime.jsx(
23872
+ restaurant.logoImageUrl && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute top-1/2 right-2 -translate-y-1/2 w-12 h-12 rounded-full overflow-hidden border-2 border-white", children: /* @__PURE__ */ jsxRuntime.jsx(
23739
23873
  "img",
23740
23874
  {
23741
23875
  src: restaurant.logoImageUrl,
@@ -23749,7 +23883,7 @@ function RestaurantMenuBrowser({
23749
23883
  restaurant.minCateringOrderQuantity,
23750
23884
  " items"
23751
23885
  ] }) }) : null,
23752
- isUnavailableForSession && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-1.5 min-h-8 space-y-0.5", children: [
23886
+ isUnavailableForSession && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-1.5 min-h-8 space-y-1.5", children: [
23753
23887
  /* @__PURE__ */ jsxRuntime.jsxs(
23754
23888
  "div",
23755
23889
  {
@@ -23765,68 +23899,35 @@ function RestaurantMenuBrowser({
23765
23899
  ]
23766
23900
  }
23767
23901
  ),
23768
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex items-center justify-between gap-2", children: [
23769
- /* @__PURE__ */ jsxRuntime.jsxs(
23770
- "div",
23771
- {
23772
- className: `flex min-w-0 items-center gap-1.5 text-[11px] leading-4 ${cateringWindowInfo.isAvailable ? "text-gray-500" : "text-red-500 font-semibold"}`,
23773
- children: [
23774
- /* @__PURE__ */ jsxRuntime.jsx(
23775
- lucideReact.Clock3,
23776
- {
23777
- className: `h-3.5 w-3.5 flex-shrink-0 ${cateringWindowInfo.isAvailable ? "text-gray-400" : "text-red-500"}`
23778
- }
23779
- ),
23780
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "line-clamp-1", title: hoursTooltipText, children: cateringWindowInfo.text })
23781
- ]
23782
- }
23783
- ),
23784
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative flex-shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx(
23785
- "button",
23786
- {
23787
- ref: (element) => {
23788
- if (element) {
23789
- hoursInfoButtonRefs.current.set(restaurant.id, element);
23790
- } else {
23791
- hoursInfoButtonRefs.current.delete(restaurant.id);
23792
- }
23793
- },
23794
- type: "button",
23795
- "aria-label": `View weekly catering hours for ${restaurant.restaurant_name}`,
23796
- onClick: (event) => {
23797
- event.stopPropagation();
23798
- if (!isMobileViewport) {
23799
- updateHoursInfoPosition(restaurant.id);
23800
- }
23801
- setOpenHoursInfoRestaurantId(
23802
- (current) => current === restaurant.id ? null : restaurant.id
23803
- );
23804
- },
23805
- onMouseEnter: () => {
23806
- if (!isMobileViewport) {
23807
- updateHoursInfoPosition(restaurant.id);
23808
- setHoveredHoursInfoRestaurantId(restaurant.id);
23809
- }
23810
- },
23811
- onMouseLeave: () => {
23812
- if (!isMobileViewport) {
23813
- setHoveredHoursInfoRestaurantId(
23814
- (current) => current === restaurant.id ? null : current
23815
- );
23902
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative flex items-center gap-2", children: /* @__PURE__ */ jsxRuntime.jsxs(
23903
+ "div",
23904
+ {
23905
+ className: `flex min-w-0 items-center gap-1.5 text-[11px] leading-4 ${cateringWindowInfo.isAvailable ? "text-gray-500" : "text-red-500 font-semibold"}`,
23906
+ children: [
23907
+ /* @__PURE__ */ jsxRuntime.jsx(
23908
+ lucideReact.Clock3,
23909
+ {
23910
+ className: `h-3.5 w-3.5 flex-shrink-0 ${cateringWindowInfo.isAvailable ? "text-gray-400" : "text-red-500"}`
23816
23911
  }
23817
- },
23818
- className: "flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-full border border-base-300 bg-white text-gray-500 shadow-sm transition-colors hover:text-primary focus:outline-none",
23819
- title: "View weekly catering hours",
23820
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Info, { className: "h-4 w-4" })
23821
- }
23822
- ) })
23823
- ] })
23912
+ ),
23913
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "line-clamp-1", title: hoursTooltipText, children: cateringWindowInfo.text })
23914
+ ]
23915
+ }
23916
+ ) })
23824
23917
  ] }),
23825
23918
  (() => {
23826
23919
  if (isUnavailableForSession) return null;
23827
23920
  const restaurantLoc = restaurant.address?.location;
23828
- const userLoc = contactInfo?.latitude && contactInfo?.longitude ? { latitude: contactInfo.latitude, longitude: contactInfo.longitude } : null;
23829
- const distance = userLoc && restaurantLoc ? haversineDistanceMiles(userLoc.latitude, userLoc.longitude, restaurantLoc.latitude, restaurantLoc.longitude) : null;
23921
+ const userLoc = contactInfo?.latitude && contactInfo?.longitude ? {
23922
+ latitude: contactInfo.latitude,
23923
+ longitude: contactInfo.longitude
23924
+ } : null;
23925
+ const distance = userLoc && restaurantLoc ? haversineDistanceMiles(
23926
+ userLoc.latitude,
23927
+ userLoc.longitude,
23928
+ restaurantLoc.latitude,
23929
+ restaurantLoc.longitude
23930
+ ) : null;
23830
23931
  const rating = restaurant.averageRating && parseFloat(restaurant.averageRating) > 0 ? parseFloat(restaurant.averageRating) : null;
23831
23932
  const priceRange = restaurant.priceRange;
23832
23933
  const tags = restaurant.tags?.filter(Boolean) ?? [];
@@ -23949,27 +24050,34 @@ function RestaurantMenuBrowser({
23949
24050
  ] }),
23950
24051
  document.body
23951
24052
  ) : null;
23952
- const renderCategoryFilters = () => /* @__PURE__ */ jsxRuntime.jsx("div", { ref: expandedSessionIndex === sessionIndex ? categoriesRowRef : void 0, style: { contain: "inline-size" }, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-x-auto pb-2 pt-1 scrollbar-hide", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-2 md:gap-3", children: categoriesLoading ? [...Array(8)].map((_, index) => /* @__PURE__ */ jsxRuntime.jsx(CategoryButtonSkeleton, {}, index)) : categories.map((category) => /* @__PURE__ */ jsxRuntime.jsxs(
23953
- "button",
24053
+ const renderCategoryFilters = () => /* @__PURE__ */ jsxRuntime.jsx(
24054
+ "div",
23954
24055
  {
23955
- onClick: () => setSelectedCategoryId(
23956
- selectedCategoryId === category.id ? null : category.id
23957
- ),
23958
- className: `w-20 flex-shrink-0 py-1.5 rounded-xl text-sm font-medium transition-all border flex flex-col items-center justify-center gap-0.5 leading-none ${category.images || category.icon ? "min-h-16" : ""} ${selectedCategoryId === category.id ? "border-primary text-primary" : "border-transparent text-gray-700 hover:text-primary"}`,
23959
- children: [
23960
- category.images ? /* @__PURE__ */ jsxRuntime.jsx(
23961
- "img",
23962
- {
23963
- src: category.images,
23964
- alt: category.name,
23965
- className: "h-8 w-8 md:h-9 md:w-9 object-cover rounded-full border border-base-300"
23966
- }
23967
- ) : category.icon ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex h-6 md:h-7 items-center justify-center text-xl md:text-2xl leading-none", children: category.icon }) : null,
23968
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-center text-xs md:text-sm", children: category.name })
23969
- ]
23970
- },
23971
- category.id
23972
- )) }) }) });
24056
+ ref: expandedSessionIndex === sessionIndex ? categoriesRowRef : void 0,
24057
+ style: { contain: "inline-size" },
24058
+ children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-x-auto pb-2 pt-1 scrollbar-hide", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-2 md:gap-3", children: categoriesLoading ? [...Array(8)].map((_, index) => /* @__PURE__ */ jsxRuntime.jsx(CategoryButtonSkeleton, {}, index)) : categories.map((category) => /* @__PURE__ */ jsxRuntime.jsxs(
24059
+ "button",
24060
+ {
24061
+ onClick: () => setSelectedCategoryId(
24062
+ selectedCategoryId === category.id ? null : category.id
24063
+ ),
24064
+ className: `w-20 flex-shrink-0 py-1.5 rounded-xl text-sm font-medium transition-all border flex flex-col items-center justify-center gap-0.5 leading-none ${category.images || category.icon ? "min-h-16" : ""} ${selectedCategoryId === category.id ? "border-primary text-primary" : "border-transparent text-gray-700 hover:text-primary"}`,
24065
+ children: [
24066
+ category.images ? /* @__PURE__ */ jsxRuntime.jsx(
24067
+ "img",
24068
+ {
24069
+ src: category.images,
24070
+ alt: category.name,
24071
+ className: "h-8 w-8 md:h-9 md:w-9 object-cover rounded-full border border-base-300"
24072
+ }
24073
+ ) : category.icon ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex h-6 md:h-7 items-center justify-center text-xl md:text-2xl leading-none", children: category.icon }) : null,
24074
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-center text-xs md:text-sm", children: category.name })
24075
+ ]
24076
+ },
24077
+ category.id
24078
+ )) }) })
24079
+ }
24080
+ );
23973
24081
  if (selectedRestaurantId && selectedRestaurant) {
23974
24082
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { contain: "inline-size" }, children: [
23975
24083
  /* @__PURE__ */ jsxRuntime.jsxs(
@@ -24002,14 +24110,27 @@ function RestaurantMenuBrowser({
24002
24110
  /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-2xl font-bold text-gray-900", children: selectedRestaurant.restaurant_name }),
24003
24111
  (() => {
24004
24112
  const restaurantLoc = selectedRestaurant.address?.location;
24005
- const userLoc = contactInfo?.latitude && contactInfo?.longitude ? { latitude: contactInfo.latitude, longitude: contactInfo.longitude } : null;
24006
- const distance = userLoc && restaurantLoc ? haversineDistanceMiles(userLoc.latitude, userLoc.longitude, restaurantLoc.latitude, restaurantLoc.longitude) : null;
24113
+ const userLoc = contactInfo?.latitude && contactInfo?.longitude ? {
24114
+ latitude: contactInfo.latitude,
24115
+ longitude: contactInfo.longitude
24116
+ } : null;
24117
+ const distance = userLoc && restaurantLoc ? haversineDistanceMiles(
24118
+ userLoc.latitude,
24119
+ userLoc.longitude,
24120
+ restaurantLoc.latitude,
24121
+ restaurantLoc.longitude
24122
+ ) : null;
24007
24123
  const rating = selectedRestaurant.averageRating && parseFloat(selectedRestaurant.averageRating) > 0 ? parseFloat(selectedRestaurant.averageRating) : null;
24008
24124
  const advanceNoticeText = getRestaurantAdvanceNoticeText(selectedRestaurant);
24009
- const noticeMet = isRestaurantAdvanceNoticeMet(selectedRestaurant, activeSession?.sessionDate, activeSession?.eventTime);
24125
+ const noticeMet = isRestaurantAdvanceNoticeMet(
24126
+ selectedRestaurant,
24127
+ activeSession?.sessionDate,
24128
+ activeSession?.eventTime
24129
+ );
24010
24130
  const priceRange = selectedRestaurant.priceRange;
24011
24131
  const tags = selectedRestaurant.tags?.filter(Boolean).slice(0, 3) ?? [];
24012
- if (!rating && !distance && !advanceNoticeText && !priceRange && tags.length === 0) return null;
24132
+ if (!rating && !distance && !advanceNoticeText && !priceRange && tags.length === 0)
24133
+ return null;
24013
24134
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-1 mb-1 flex flex-col gap-1", children: [
24014
24135
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-x-3 gap-y-1", children: [
24015
24136
  rating !== null && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-1 text-sm text-gray-500 whitespace-nowrap", children: [
@@ -24025,10 +24146,21 @@ function RestaurantMenuBrowser({
24025
24146
  priceRange && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-gray-500 whitespace-nowrap", children: priceRange }),
24026
24147
  advanceNoticeText && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
24027
24148
  (rating !== null || distance !== null || priceRange) && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-gray-300", children: "\xB7" }),
24028
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: `flex items-center gap-1 text-sm whitespace-nowrap ${noticeMet ? "text-gray-500" : "text-gray-500"}`, children: [
24029
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Clock3, { className: `h-3.5 w-3.5 flex-shrink-0 ${noticeMet ? "text-gray-400" : "text-red-500"}` }),
24030
- advanceNoticeText
24031
- ] })
24149
+ /* @__PURE__ */ jsxRuntime.jsxs(
24150
+ "span",
24151
+ {
24152
+ className: `flex items-center gap-1 text-sm whitespace-nowrap ${noticeMet ? "text-gray-500" : "text-gray-500"}`,
24153
+ children: [
24154
+ /* @__PURE__ */ jsxRuntime.jsx(
24155
+ lucideReact.Clock3,
24156
+ {
24157
+ className: `h-3.5 w-3.5 flex-shrink-0 ${noticeMet ? "text-gray-400" : "text-red-500"}`
24158
+ }
24159
+ ),
24160
+ advanceNoticeText
24161
+ ]
24162
+ }
24163
+ )
24032
24164
  ] })
24033
24165
  ] }),
24034
24166
  tags.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-gray-500", children: tags.join(" - ") })
@@ -24063,42 +24195,79 @@ function RestaurantMenuBrowser({
24063
24195
  const promos = selectedRestaurantId ? restaurantPromotions[selectedRestaurantId] ?? [] : [];
24064
24196
  if (promos.length === 0) return null;
24065
24197
  const discountLabel = (promo) => promo.promotionType === "BUY_MORE_SAVE_MORE" && promo.discountTiers?.length ? `Up to ${Math.max(...promo.discountTiers.map((t) => Number(t.discountPercentage)))}% OFF` : `${Number(promo.discountPercentage)}% OFF`;
24066
- const endDateLabel = (promo) => new Date(promo.endDate).toLocaleDateString("en-GB", { day: "numeric", month: "short" });
24067
- const sortedTiers = (promo) => [...promo.discountTiers ?? []].sort((a, b) => a.minQuantity - b.minQuantity);
24198
+ const endDateLabel = (promo) => new Date(promo.endDate).toLocaleDateString("en-GB", {
24199
+ day: "numeric",
24200
+ month: "short"
24201
+ });
24202
+ const sortedTiers = (promo) => [...promo.discountTiers ?? []].sort(
24203
+ (a, b) => a.minQuantity - b.minQuantity
24204
+ );
24068
24205
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-3", children: [
24069
24206
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 mb-2", children: [
24070
24207
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-semibold text-gray-900", children: "Active Offers" }),
24071
24208
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "bg-primary text-white text-xs font-bold px-2 py-0.5 rounded-full", children: promos.length })
24072
24209
  ] }),
24073
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex gap-3 overflow-x-auto pb-1 scrollbar-hide snap-x snap-mandatory", children: promos.map((promo) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-shrink-0 snap-start bg-white border border-base-200 rounded-2xl p-4 min-w-[220px] max-w-[280px] shadow-sm", children: [
24074
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-2 mb-2", children: [
24075
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[11px] font-semibold text-gray-400 uppercase tracking-wide truncate", children: promo.name }),
24076
- /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4 flex-shrink-0 text-primary", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M7 7h.01M7 3h5c.512 0 1.024.195 1.414.586l7 7a2 2 0 010 2.828l-7 7a2 2 0 01-2.828 0l-7-7A1.994 1.994 0 013 12V7a4 4 0 014-4z" }) })
24077
- ] }),
24078
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-lg font-black text-gray-900 leading-none", children: discountLabel(promo) }),
24079
- promo.promotionType === "BUY_MORE_SAVE_MORE" && sortedTiers(promo).length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-1 mt-2.5", children: sortedTiers(promo).map((tier, idx) => /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-[11px] font-medium bg-primary/10 text-primary px-2 py-0.5 rounded-full", children: [
24080
- tier.minQuantity,
24081
- "+ \u2192 ",
24082
- Number(tier.discountPercentage),
24083
- "%"
24084
- ] }, idx)) }),
24085
- promo.description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-gray-400 mt-1.5 line-clamp-2", children: promo.description }),
24086
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap gap-x-2 gap-y-0.5 mt-2.5 text-xs text-gray-400", children: [
24087
- promo.minOrderAmount > 0 && /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
24088
- "Min. \xA3",
24089
- promo.minOrderAmount
24090
- ] }),
24091
- promo.maxDiscountAmount && /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
24092
- "\xB7 Max. \xA3",
24093
- promo.maxDiscountAmount,
24094
- " off"
24095
- ] }),
24096
- /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
24097
- "\xB7 Until ",
24098
- endDateLabel(promo)
24099
- ] })
24100
- ] })
24101
- ] }, promo.id)) })
24210
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex gap-3 overflow-x-auto pb-1 scrollbar-hide snap-x snap-mandatory", children: promos.map((promo) => /* @__PURE__ */ jsxRuntime.jsxs(
24211
+ "div",
24212
+ {
24213
+ className: "flex-shrink-0 snap-start bg-white border border-base-200 rounded-2xl p-4 min-w-[220px] max-w-[280px] shadow-sm",
24214
+ children: [
24215
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-2 mb-2", children: [
24216
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[11px] font-semibold text-gray-400 uppercase tracking-wide truncate", children: promo.name }),
24217
+ /* @__PURE__ */ jsxRuntime.jsx(
24218
+ "svg",
24219
+ {
24220
+ className: "w-4 h-4 flex-shrink-0 text-primary",
24221
+ fill: "none",
24222
+ stroke: "currentColor",
24223
+ viewBox: "0 0 24 24",
24224
+ children: /* @__PURE__ */ jsxRuntime.jsx(
24225
+ "path",
24226
+ {
24227
+ strokeLinecap: "round",
24228
+ strokeLinejoin: "round",
24229
+ strokeWidth: 2,
24230
+ d: "M7 7h.01M7 3h5c.512 0 1.024.195 1.414.586l7 7a2 2 0 010 2.828l-7 7a2 2 0 01-2.828 0l-7-7A1.994 1.994 0 013 12V7a4 4 0 014-4z"
24231
+ }
24232
+ )
24233
+ }
24234
+ )
24235
+ ] }),
24236
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-lg font-black text-gray-900 leading-none", children: discountLabel(promo) }),
24237
+ promo.promotionType === "BUY_MORE_SAVE_MORE" && sortedTiers(promo).length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-1 mt-2.5", children: sortedTiers(promo).map((tier, idx) => /* @__PURE__ */ jsxRuntime.jsxs(
24238
+ "span",
24239
+ {
24240
+ className: "text-[11px] font-medium bg-primary/10 text-primary px-2 py-0.5 rounded-full",
24241
+ children: [
24242
+ tier.minQuantity,
24243
+ "+ \u2192",
24244
+ " ",
24245
+ Number(tier.discountPercentage),
24246
+ "%"
24247
+ ]
24248
+ },
24249
+ idx
24250
+ )) }),
24251
+ promo.description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-gray-400 mt-1.5 line-clamp-2", children: promo.description }),
24252
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap gap-x-2 gap-y-0.5 mt-2.5 text-xs text-gray-400", children: [
24253
+ promo.minOrderAmount > 0 && /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
24254
+ "Min. \xA3",
24255
+ promo.minOrderAmount
24256
+ ] }),
24257
+ promo.maxDiscountAmount && /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
24258
+ "\xB7 Max. \xA3",
24259
+ promo.maxDiscountAmount,
24260
+ " off"
24261
+ ] }),
24262
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
24263
+ "\xB7 Until ",
24264
+ endDateLabel(promo)
24265
+ ] })
24266
+ ] })
24267
+ ]
24268
+ },
24269
+ promo.id
24270
+ )) })
24102
24271
  ] });
24103
24272
  })(),
24104
24273
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-2", children: renderDietaryFilters() }),
@@ -24111,58 +24280,64 @@ function RestaurantMenuBrowser({
24111
24280
  top: stickyTopOffset + 8
24112
24281
  },
24113
24282
  children: [
24114
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `relative flex-1 min-w-0 ${isRestaurantSearchOpen ? "hidden md:block" : ""}`, children: [
24115
- /* @__PURE__ */ jsxRuntime.jsx(
24116
- "div",
24117
- {
24118
- ref: setPillRowEl,
24119
- "data-pill-row": true,
24120
- className: "overflow-x-auto scrollbar-hide rounded-full border border-base-300 bg-white/50 px-2 shadow-sm backdrop-blur-md flex items-center h-11",
24121
- children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-2 md:gap-5", children: pillRowGroupNames.map((name) => {
24122
- const isActive = activeGroupName === name;
24123
- return /* @__PURE__ */ jsxRuntime.jsx(
24124
- "button",
24125
- {
24126
- ref: (el) => {
24127
- if (el) groupButtonRefs.current.set(name, el);
24128
- else groupButtonRefs.current.delete(name);
24129
- },
24130
- onClick: () => handlePillClick(name),
24131
- className: `flex-shrink-0 whitespace-nowrap rounded-full px-3 py-1.5 text-sm font-semibold transition-colors ${isActive ? "bg-primary text-white" : "text-gray-500 hover:bg-black/5 hover:text-gray-700"}`,
24132
- children: name
24283
+ /* @__PURE__ */ jsxRuntime.jsxs(
24284
+ "div",
24285
+ {
24286
+ className: `relative flex-1 min-w-0 ${isRestaurantSearchOpen ? "hidden md:block" : ""}`,
24287
+ children: [
24288
+ /* @__PURE__ */ jsxRuntime.jsx(
24289
+ "div",
24290
+ {
24291
+ ref: setPillRowEl,
24292
+ "data-pill-row": true,
24293
+ className: "overflow-x-auto scrollbar-hide rounded-full border border-base-300 bg-white/50 px-2 shadow-sm backdrop-blur-md flex items-center h-11",
24294
+ children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-2 md:gap-5", children: pillRowGroupNames.map((name) => {
24295
+ const isActive = activeGroupName === name;
24296
+ return /* @__PURE__ */ jsxRuntime.jsx(
24297
+ "button",
24298
+ {
24299
+ ref: (el) => {
24300
+ if (el) groupButtonRefs.current.set(name, el);
24301
+ else groupButtonRefs.current.delete(name);
24302
+ },
24303
+ onClick: () => handlePillClick(name),
24304
+ className: `flex-shrink-0 whitespace-nowrap rounded-full px-3 py-1.5 text-sm font-semibold transition-colors ${isActive ? "bg-primary text-white" : "text-gray-500 hover:bg-black/5 hover:text-gray-700"}`,
24305
+ children: name
24306
+ },
24307
+ name
24308
+ );
24309
+ }) })
24310
+ }
24311
+ ),
24312
+ canScrollLeft && /* @__PURE__ */ jsxRuntime.jsx(
24313
+ "button",
24314
+ {
24315
+ onClick: () => scrollPillRow("left"),
24316
+ className: "group absolute left-0 top-0 bottom-0 z-10 flex w-14 items-center justify-start rounded-l-full pl-3",
24317
+ style: {
24318
+ background: "linear-gradient(to right, rgba(255,255,255,0.95) 50%, transparent)"
24133
24319
  },
24134
- name
24135
- );
24136
- }) })
24137
- }
24138
- ),
24139
- canScrollLeft && /* @__PURE__ */ jsxRuntime.jsx(
24140
- "button",
24141
- {
24142
- onClick: () => scrollPillRow("left"),
24143
- className: "group absolute left-0 top-0 bottom-0 z-10 flex w-14 items-center justify-start rounded-l-full pl-3",
24144
- style: {
24145
- background: "linear-gradient(to right, rgba(255,255,255,0.95) 50%, transparent)"
24146
- },
24147
- "aria-label": "Scroll left",
24148
- type: "button",
24149
- children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex items-center justify-center rounded-full p-1 transition-colors group-hover:bg-gray-300/50", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronLeft, { className: "h-5 w-5 text-gray-600" }) })
24150
- }
24151
- ),
24152
- canScrollRight && /* @__PURE__ */ jsxRuntime.jsx(
24153
- "button",
24154
- {
24155
- onClick: () => scrollPillRow("right"),
24156
- className: "group absolute right-0 top-0 bottom-0 z-10 flex w-14 items-center justify-end rounded-r-full pr-3",
24157
- style: {
24158
- background: "linear-gradient(to left, rgba(255,255,255,0.95) 50%, transparent)"
24159
- },
24160
- "aria-label": "Scroll right",
24161
- type: "button",
24162
- children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex items-center justify-center rounded-full p-1 transition-colors group-hover:bg-gray-300/50", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { className: "h-5 w-5 text-gray-600" }) })
24163
- }
24164
- )
24165
- ] }),
24320
+ "aria-label": "Scroll left",
24321
+ type: "button",
24322
+ children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex items-center justify-center rounded-full p-1 transition-colors group-hover:bg-gray-300/50", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronLeft, { className: "h-5 w-5 text-gray-600" }) })
24323
+ }
24324
+ ),
24325
+ canScrollRight && /* @__PURE__ */ jsxRuntime.jsx(
24326
+ "button",
24327
+ {
24328
+ onClick: () => scrollPillRow("right"),
24329
+ className: "group absolute right-0 top-0 bottom-0 z-10 flex w-14 items-center justify-end rounded-r-full pr-3",
24330
+ style: {
24331
+ background: "linear-gradient(to left, rgba(255,255,255,0.95) 50%, transparent)"
24332
+ },
24333
+ "aria-label": "Scroll right",
24334
+ type: "button",
24335
+ children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex items-center justify-center rounded-full p-1 transition-colors group-hover:bg-gray-300/50", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { className: "h-5 w-5 text-gray-600" }) })
24336
+ }
24337
+ )
24338
+ ]
24339
+ }
24340
+ ),
24166
24341
  /* @__PURE__ */ jsxRuntime.jsx(
24167
24342
  "div",
24168
24343
  {
@@ -24410,15 +24585,33 @@ function RestaurantMenuBrowser({
24410
24585
  ] })
24411
24586
  ] }),
24412
24587
  (() => {
24413
- const matched = apiSearchResults.restaurants.map((r) => availableRestaurants.find((ar) => ar.id === r.id)).filter((r) => r !== void 0);
24588
+ const matched = apiSearchResults.restaurants.map(
24589
+ (r) => availableRestaurants.find((ar) => ar.id === r.id)
24590
+ ).filter((r) => r !== void 0);
24414
24591
  const available = matched.filter((r) => {
24415
- const windowInfo = getRestaurantCateringWindowInfo(r, activeSession?.sessionDate, activeSession?.eventTime);
24416
- const noticeMet = isRestaurantAdvanceNoticeMet(r, activeSession?.sessionDate, activeSession?.eventTime);
24592
+ const windowInfo = getRestaurantCateringWindowInfo(
24593
+ r,
24594
+ activeSession?.sessionDate,
24595
+ activeSession?.eventTime
24596
+ );
24597
+ const noticeMet = isRestaurantAdvanceNoticeMet(
24598
+ r,
24599
+ activeSession?.sessionDate,
24600
+ activeSession?.eventTime
24601
+ );
24417
24602
  return windowInfo.isAvailable && noticeMet;
24418
24603
  });
24419
24604
  const unavailable = matched.filter((r) => {
24420
- const windowInfo = getRestaurantCateringWindowInfo(r, activeSession?.sessionDate, activeSession?.eventTime);
24421
- const noticeMet = isRestaurantAdvanceNoticeMet(r, activeSession?.sessionDate, activeSession?.eventTime);
24605
+ const windowInfo = getRestaurantCateringWindowInfo(
24606
+ r,
24607
+ activeSession?.sessionDate,
24608
+ activeSession?.eventTime
24609
+ );
24610
+ const noticeMet = isRestaurantAdvanceNoticeMet(
24611
+ r,
24612
+ activeSession?.sessionDate,
24613
+ activeSession?.eventTime
24614
+ );
24422
24615
  return !windowInfo.isAvailable || !noticeMet;
24423
24616
  });
24424
24617
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", children: [
@@ -24472,20 +24665,42 @@ function RestaurantMenuBrowser({
24472
24665
  ] })
24473
24666
  ] }) : null : /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: restaurantsLoading ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-1 sm:grid-cols-2 xl:grid-cols-3 gap-3 mt-3", children: Array.from({ length: 6 }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsx(RestaurantMenuBrowserCardSkeleton, {}, i)) }) : filteredRestaurants.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-center py-6 mt-3", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-gray-500 text-sm", children: "No restaurants found." }) }) : (() => {
24474
24667
  const available = filteredRestaurants.filter((r) => {
24475
- const windowInfo = getRestaurantCateringWindowInfo(r, activeSession?.sessionDate, activeSession?.eventTime);
24476
- const noticeMet = isRestaurantAdvanceNoticeMet(r, activeSession?.sessionDate, activeSession?.eventTime);
24668
+ const windowInfo = getRestaurantCateringWindowInfo(
24669
+ r,
24670
+ activeSession?.sessionDate,
24671
+ activeSession?.eventTime
24672
+ );
24673
+ const noticeMet = isRestaurantAdvanceNoticeMet(
24674
+ r,
24675
+ activeSession?.sessionDate,
24676
+ activeSession?.eventTime
24677
+ );
24477
24678
  return windowInfo.isAvailable && noticeMet;
24478
24679
  });
24479
24680
  const unavailable = filteredRestaurants.filter((r) => {
24480
- const windowInfo = getRestaurantCateringWindowInfo(r, activeSession?.sessionDate, activeSession?.eventTime);
24481
- const noticeMet = isRestaurantAdvanceNoticeMet(r, activeSession?.sessionDate, activeSession?.eventTime);
24681
+ const windowInfo = getRestaurantCateringWindowInfo(
24682
+ r,
24683
+ activeSession?.sessionDate,
24684
+ activeSession?.eventTime
24685
+ );
24686
+ const noticeMet = isRestaurantAdvanceNoticeMet(
24687
+ r,
24688
+ activeSession?.sessionDate,
24689
+ activeSession?.eventTime
24690
+ );
24482
24691
  return !windowInfo.isAvailable || !noticeMet;
24483
24692
  });
24484
24693
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: restaurantListRef, className: "mt-3 space-y-6", children: [
24485
- available.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-1 sm:grid-cols-2 xl:grid-cols-3 gap-3", children: available.map((restaurant) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-full", children: renderRestaurantCard(restaurant, () => handleSelectRestaurant(restaurant.id)) }, restaurant.id)) }),
24694
+ available.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-1 sm:grid-cols-2 xl:grid-cols-3 gap-3", children: available.map((restaurant) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-full", children: renderRestaurantCard(
24695
+ restaurant,
24696
+ () => handleSelectRestaurant(restaurant.id)
24697
+ ) }, restaurant.id)) }),
24486
24698
  unavailable.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
24487
24699
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs font-semibold text-gray-400 uppercase tracking-widest mb-3", children: "Unavailable today" }),
24488
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-1 sm:grid-cols-2 xl:grid-cols-3 gap-3", children: unavailable.map((restaurant) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-full", children: renderRestaurantCard(restaurant, () => handleSelectRestaurant(restaurant.id)) }, restaurant.id)) })
24700
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-1 sm:grid-cols-2 xl:grid-cols-3 gap-3", children: unavailable.map((restaurant) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-full", children: renderRestaurantCard(
24701
+ restaurant,
24702
+ () => handleSelectRestaurant(restaurant.id)
24703
+ ) }, restaurant.id)) })
24489
24704
  ] })
24490
24705
  ] });
24491
24706
  })() })
@@ -27501,13 +27716,10 @@ function CheckoutScreen() {
27501
27716
  ] })
27502
27717
  ] });
27503
27718
  }
27504
- function ShareCartButton({ className = "" }) {
27719
+ function useShareCart() {
27505
27720
  const { mealSessions, eventDetails } = useCateringState();
27506
- const [status, setStatus] = react.useState(
27507
- "idle"
27508
- );
27721
+ const [status, setStatus] = react.useState("idle");
27509
27722
  const hasItems = mealSessions.some((s) => s.orderItems.length > 0);
27510
- if (!hasItems) return null;
27511
27723
  const handleShare = async () => {
27512
27724
  if (status === "loading") return;
27513
27725
  setStatus("loading");
@@ -27522,11 +27734,10 @@ function ShareCartButton({ className = "" }) {
27522
27734
  } : void 0
27523
27735
  );
27524
27736
  const { id } = await cateringService.createSharedCart(snapshot);
27525
- const shareUrl = `${window.location.origin}${window.location.pathname}?sharedCart=${id}`;
27526
27737
  try {
27527
- await navigator.clipboard.writeText(shareUrl);
27738
+ await navigator.clipboard.writeText(id);
27528
27739
  } catch {
27529
- window.prompt("Copy your cart link:", shareUrl);
27740
+ window.prompt("Copy your cart code:", id);
27530
27741
  }
27531
27742
  setStatus("done");
27532
27743
  setTimeout(() => setStatus("idle"), 2500);
@@ -27536,39 +27747,8 @@ function ShareCartButton({ className = "" }) {
27536
27747
  setTimeout(() => setStatus("idle"), 2500);
27537
27748
  }
27538
27749
  };
27539
- const label = status === "loading" ? "Creating link\u2026" : status === "done" ? "Link copied \u2713" : status === "error" ? "Try again" : "Share cart";
27540
- return /* @__PURE__ */ jsxRuntime.jsxs(
27541
- "button",
27542
- {
27543
- type: "button",
27544
- onClick: handleShare,
27545
- disabled: status === "loading",
27546
- title: "Create a link to share this cart",
27547
- className: `inline-flex items-center justify-center gap-1.5 rounded-lg border border-primary px-3 py-3 text-sm font-semibold text-primary transition-colors hover:bg-primary/5 disabled:cursor-not-allowed disabled:opacity-60 ${className}`,
27548
- children: [
27549
- /* @__PURE__ */ jsxRuntime.jsx(
27550
- "svg",
27551
- {
27552
- xmlns: "http://www.w3.org/2000/svg",
27553
- className: "h-4 w-4",
27554
- fill: "none",
27555
- viewBox: "0 0 24 24",
27556
- stroke: "currentColor",
27557
- strokeWidth: 2,
27558
- children: /* @__PURE__ */ jsxRuntime.jsx(
27559
- "path",
27560
- {
27561
- strokeLinecap: "round",
27562
- strokeLinejoin: "round",
27563
- d: "M8.684 13.342C8.886 12.938 9 12.482 9 12c0-.482-.114-.938-.316-1.342m0 2.684a3 3 0 110-2.684m0 2.684l6.632 3.316m-6.632-6l6.632-3.316m0 0a3 3 0 105.367-2.684 3 3 0 00-5.367 2.684zm0 9.316a3 3 0 105.368 2.684 3 3 0 00-5.368-2.684z"
27564
- }
27565
- )
27566
- }
27567
- ),
27568
- label
27569
- ]
27570
- }
27571
- );
27750
+ const label = status === "loading" ? "Creating code\u2026" : status === "done" ? "Code copied" : status === "error" ? "Try again" : "Share cart";
27751
+ return { status, hasItems, handleShare, label };
27572
27752
  }
27573
27753
  function EmptySessionWarningModal({
27574
27754
  sessionName,
@@ -28545,6 +28725,8 @@ function CateringOrderBuilder() {
28545
28725
  const [isMobileCartMenuOpen, setIsMobileCartMenuOpen] = react.useState(false);
28546
28726
  const [isMobileChatMenuOpen, setIsMobileChatMenuOpen] = react.useState(false);
28547
28727
  const [isDesktopCartMenuOpen, setIsDesktopCartMenuOpen] = react.useState(false);
28728
+ const shareCart = useShareCart();
28729
+ const importCart = useImportCart();
28548
28730
  const [isAIMobileUnavailableOpen, setIsAIMobileUnavailableOpen] = react.useState(false);
28549
28731
  const storage = useStorage();
28550
28732
  const [rightPanelTab, setRightPanelTabState] = react.useState(() => {
@@ -29829,7 +30011,7 @@ function CateringOrderBuilder() {
29829
30011
  }
29830
30012
  ) : /* @__PURE__ */ jsxRuntime.jsx(AIChat, {}),
29831
30013
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-auto flex-shrink-0 flex flex-col gap-1.5", children: effectiveRightPanelTab === "ai" ? /* @__PURE__ */ jsxRuntime.jsx(AISuggestionsBottomButton, {}) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
29832
- totalItems > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-2 pb-1 border-t border-base-300 pt-3", children: /* @__PURE__ */ jsxRuntime.jsx(
30014
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-2 pb-1 border-t border-base-300 pt-3", children: /* @__PURE__ */ jsxRuntime.jsx(
29833
30015
  PricingSummary,
29834
30016
  {
29835
30017
  pricing,
@@ -29910,6 +30092,50 @@ function CateringOrderBuilder() {
29910
30092
  ]
29911
30093
  }
29912
30094
  ),
30095
+ shareCart.hasItems && /* @__PURE__ */ jsxRuntime.jsxs(
30096
+ "button",
30097
+ {
30098
+ onClick: shareCart.handleShare,
30099
+ disabled: shareCart.status === "loading",
30100
+ title: "Copy a code to share this cart",
30101
+ className: "flex w-full items-center gap-2 px-3 py-2.5 text-left text-sm text-gray-700 transition-colors hover:bg-base-100 disabled:cursor-not-allowed disabled:opacity-50",
30102
+ children: [
30103
+ shareCart.status === "loading" ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "loading loading-spinner loading-xs" }) : /* @__PURE__ */ jsxRuntime.jsx(
30104
+ "svg",
30105
+ {
30106
+ xmlns: "http://www.w3.org/2000/svg",
30107
+ className: "h-4 w-4",
30108
+ fill: "none",
30109
+ viewBox: "0 0 24 24",
30110
+ stroke: "currentColor",
30111
+ strokeWidth: 2,
30112
+ children: /* @__PURE__ */ jsxRuntime.jsx(
30113
+ "path",
30114
+ {
30115
+ strokeLinecap: "round",
30116
+ strokeLinejoin: "round",
30117
+ d: shareCart.status === "done" ? "M5 13l4 4L19 7" : "M8.684 13.342C8.886 12.938 9 12.482 9 12c0-.482-.114-.938-.316-1.342m0 2.684a3 3 0 110-2.684m0 2.684l6.632 3.316m-6.632-6l6.632-3.316m0 0a3 3 0 105.367-2.684 3 3 0 00-5.367 2.684zm0 9.316a3 3 0 105.368 2.684 3 3 0 00-5.368-2.684z"
30118
+ }
30119
+ )
30120
+ }
30121
+ ),
30122
+ shareCart.label
30123
+ ]
30124
+ }
30125
+ ),
30126
+ /* @__PURE__ */ jsxRuntime.jsxs(
30127
+ "button",
30128
+ {
30129
+ onClick: importCart.handleImport,
30130
+ disabled: importCart.status === "loading",
30131
+ title: "Load a cart from a shared code",
30132
+ className: "flex w-full items-center gap-2 px-3 py-2.5 text-left text-sm text-gray-700 transition-colors hover:bg-base-100 disabled:cursor-not-allowed disabled:opacity-50",
30133
+ children: [
30134
+ importCart.status === "loading" ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "loading loading-spinner loading-xs" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ClipboardPaste, { className: "h-4 w-4" }),
30135
+ importCart.label
30136
+ ]
30137
+ }
30138
+ ),
29913
30139
  /* @__PURE__ */ jsxRuntime.jsxs(
29914
30140
  "button",
29915
30141
  {
@@ -29929,7 +30155,6 @@ function CateringOrderBuilder() {
29929
30155
  )
29930
30156
  ] })
29931
30157
  ] }),
29932
- /* @__PURE__ */ jsxRuntime.jsx(ShareCartButton, {}),
29933
30158
  /* @__PURE__ */ jsxRuntime.jsx(
29934
30159
  "button",
29935
30160
  {
@@ -30127,6 +30352,50 @@ function CateringOrderBuilder() {
30127
30352
  ]
30128
30353
  }
30129
30354
  ),
30355
+ shareCart.hasItems && /* @__PURE__ */ jsxRuntime.jsxs(
30356
+ "button",
30357
+ {
30358
+ onClick: shareCart.handleShare,
30359
+ disabled: shareCart.status === "loading",
30360
+ title: "Copy a code to share this cart",
30361
+ className: "flex w-full items-center gap-2 px-3 py-2.5 text-left text-sm text-gray-700 transition-colors hover:bg-base-100 disabled:cursor-not-allowed disabled:opacity-50",
30362
+ children: [
30363
+ shareCart.status === "loading" ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "loading loading-spinner loading-xs" }) : /* @__PURE__ */ jsxRuntime.jsx(
30364
+ "svg",
30365
+ {
30366
+ xmlns: "http://www.w3.org/2000/svg",
30367
+ className: "h-4 w-4",
30368
+ fill: "none",
30369
+ viewBox: "0 0 24 24",
30370
+ stroke: "currentColor",
30371
+ strokeWidth: 2,
30372
+ children: /* @__PURE__ */ jsxRuntime.jsx(
30373
+ "path",
30374
+ {
30375
+ strokeLinecap: "round",
30376
+ strokeLinejoin: "round",
30377
+ d: shareCart.status === "done" ? "M5 13l4 4L19 7" : "M8.684 13.342C8.886 12.938 9 12.482 9 12c0-.482-.114-.938-.316-1.342m0 2.684a3 3 0 110-2.684m0 2.684l6.632 3.316m-6.632-6l6.632-3.316m0 0a3 3 0 105.367-2.684 3 3 0 00-5.367 2.684zm0 9.316a3 3 0 105.368 2.684 3 3 0 00-5.368-2.684z"
30378
+ }
30379
+ )
30380
+ }
30381
+ ),
30382
+ shareCart.label
30383
+ ]
30384
+ }
30385
+ ),
30386
+ /* @__PURE__ */ jsxRuntime.jsxs(
30387
+ "button",
30388
+ {
30389
+ onClick: importCart.handleImport,
30390
+ disabled: importCart.status === "loading",
30391
+ title: "Load a cart from a shared code",
30392
+ className: "flex w-full items-center gap-2 px-3 py-2.5 text-left text-sm text-gray-700 transition-colors hover:bg-base-100 disabled:cursor-not-allowed disabled:opacity-50",
30393
+ children: [
30394
+ importCart.status === "loading" ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "loading loading-spinner loading-xs" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ClipboardPaste, { className: "h-4 w-4" }),
30395
+ importCart.label
30396
+ ]
30397
+ }
30398
+ ),
30130
30399
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mx-3 border-t border-base-200" }),
30131
30400
  /* @__PURE__ */ jsxRuntime.jsxs(
30132
30401
  "button",