@liquidcommerce/elements-sdk 2.6.0-beta.130 → 2.6.0-beta.132

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.
@@ -2,6 +2,8 @@ export interface IApiErrorDetail {
2
2
  field?: string;
3
3
  message: string;
4
4
  code?: string;
5
+ retailerId?: string;
6
+ fulfillmentId?: string;
5
7
  }
6
8
  export interface ApiError {
7
9
  status: number;
@@ -1,5 +1,5 @@
1
1
  import type { ICheckoutAmounts, ICheckoutBilling, ICheckoutCustomer, ICheckoutEvent, ICheckoutFulfillment, ICheckoutFulfillmentMethod, ICheckoutGiftCard, ICheckoutGiftRecipient, ICheckoutItem, ICheckoutMarketingPreferences, ICheckoutPaymentConfirm, ICheckoutPaymentSession, ICheckoutPresale, ICheckoutPromoCode, ICheckoutRetailer, ICheckoutShippingAddress } from '@/interfaces/api/checkout.interface';
2
- export type DeliveryWindowLapse = 'expired' | 'unavailable';
2
+ export type DeliveryWindowLapse = 'expired' | 'unavailable' | 'required';
3
3
  export interface ICheckoutItemStore extends ICheckoutItem {
4
4
  loading: boolean;
5
5
  updating: boolean;
@@ -67,6 +67,7 @@ export interface ICheckoutStore {
67
67
  fulfillments: Record<string, ICheckoutFulfillment>;
68
68
  deliveryWindowLapses: Record<string, DeliveryWindowLapse>;
69
69
  deliveryScheduleNotice: string | null;
70
+ splitStoreDeliveryRefused: boolean;
70
71
  retailers: Record<string, ICheckoutRetailer>;
71
72
  amounts: ICheckoutAmounts;
72
73
  orderNumber: string | null;
@@ -1,5 +1,6 @@
1
1
  import type { CartEventLevel, CartEventType, FulfillmentType } from '@/enums';
2
2
  import type { ILocation } from '@/interfaces/api/address.interface';
3
+ import type { DeliveryAvailability } from '@/interfaces/api/delivery.interface';
3
4
  import type { IProductPresale } from '@/interfaces/api/product.interface';
4
5
  export interface ICartUpdateItem {
5
6
  id?: string;
@@ -24,6 +25,7 @@ export interface ICartFulfillment {
24
25
  subtotal: number;
25
26
  hasUnmetMinimumPurchaseAmount: boolean;
26
27
  minimumPurchaseAmount: number;
28
+ deliveryAvailability?: DeliveryAvailability;
27
29
  }
28
30
  export interface ICartRetailer {
29
31
  id: string;
@@ -1,7 +1,7 @@
1
1
  import type { CheckoutEventLevel, CheckoutEventType, FulfillmentType } from '@/enums';
2
2
  import type { IAddressAddress, IAddressCoordinates, ILocation } from '@/interfaces/api/address.interface';
3
3
  import type { ICart, ICartUpdateItem } from '@/interfaces/api/cart.interface';
4
- import type { CheckoutDeliveryScheduling, CheckoutDeliverySelection } from '@/interfaces/api/delivery.interface';
4
+ import type { CheckoutDeliveryScheduling, CheckoutDeliverySelection, DeliveryAvailability } from '@/interfaces/api/delivery.interface';
5
5
  import type { IProductPresale } from '@/interfaces/api/product.interface';
6
6
  export interface ICheckoutComplete {
7
7
  orderNumber: string;
@@ -99,6 +99,7 @@ export interface ICheckoutItemsUpdateParams {
99
99
  cartId: string;
100
100
  items: ICheckoutUpdateItem[];
101
101
  location?: ILocation;
102
+ checkout?: ICheckoutFulfillmentCarryOver;
102
103
  }
103
104
  export interface ICheckoutItemsUpdateResponse {
104
105
  cart: ICart;
@@ -137,6 +138,7 @@ export interface ICheckoutFulfillmentMethod {
137
138
  partNumber: string;
138
139
  retailerId: string;
139
140
  reason: CheckoutFulfillmentUnavailableReason | null;
141
+ deliveryAvailability?: DeliveryAvailability;
140
142
  }
141
143
  export type ICheckoutFulfillmentCarryOver = Omit<ICheckoutPrepareParams, 'cartId' | 'token' | 'deliveryTips' | 'deliveryInstructions' | 'deliverySelections' | 'deliverySlotsFulfillmentId'>;
142
144
  export interface ICheckoutFulfillmentParams {
@@ -1,5 +1,6 @@
1
1
  import type { FulfillmentType } from '@/enums';
2
2
  import type { IAddressAddress, IAddressCoordinates, ILocation } from '@/interfaces/api/address.interface';
3
+ import type { DeliveryAvailability } from '@/interfaces/api/delivery.interface';
3
4
  export interface IProductAvailabilityParams {
4
5
  identifiers: string[];
5
6
  location?: ILocation;
@@ -83,6 +84,7 @@ export interface IFulfillment {
83
84
  fee: number;
84
85
  timezone: string;
85
86
  hourStatus: IProductFulfillmentHourStatus;
87
+ deliveryAvailability?: DeliveryAvailability;
86
88
  }
87
89
  export type IRetailerAddress = IAddressAddress & IAddressCoordinates;
88
90
  export interface IRetailer {
@@ -1,7 +1,9 @@
1
1
  import { BaseComponent } from '@/core/base-component.service';
2
+ import type { ICartFulfillmentStore } from '@/core/store/interfaces/cart.interface';
2
3
  export interface ICartItemComponentParams {
3
4
  itemId: string;
4
5
  }
6
+ export declare function cartItemExpectationText(fulfillment: ICartFulfillmentStore, hasEngraving: boolean): string;
5
7
  export declare class CartItemComponent extends BaseComponent<ICartItemComponentParams, null> {
6
8
  get hostClasses(): string[];
7
9
  get hostAttributes(): Record<string, string>;
@@ -36,8 +36,11 @@ export declare class CheckoutCommands extends BaseCommand {
36
36
  private findOfferedDeliverySlot;
37
37
  loadDeliverySlots(fulfillmentId: string): Promise<DeliverySlot[]>;
38
38
  chooseDeliverySlot(fulfillmentId: string, slotId: string | null): Promise<void>;
39
+ private deliverySelectionError;
39
40
  private completionError;
41
+ private freshCart;
40
42
  private dropDeliveryScheduling;
43
+ private lapsedWindowGroupIds;
41
44
  private forgetDeliveryWindow;
42
45
  private assertDeliverySlotChoosable;
43
46
  private responseFulfillments;
@@ -47,7 +50,11 @@ export declare class CheckoutCommands extends BaseCommand {
47
50
  private expiredDeliveryMarksWith;
48
51
  private pruneExpiredDeliveryWindows;
49
52
  private expireDeliveryWindows;
53
+ private requestPrepare;
54
+ private withStoreNamedFailure;
55
+ private knownRetailers;
50
56
  private prepareWithWindowRecovery;
57
+ private prepareRecoveringWindow;
51
58
  retryLoadCheckout(): Promise<void>;
52
59
  private paymentSessionRequest;
53
60
  constructor();
@@ -152,6 +159,8 @@ export declare class CheckoutCommands extends BaseCommand {
152
159
  private deliveryMethodCarryOver;
153
160
  private refreshPaymentAfterDeliveryMethodSwitch;
154
161
  changeDeliveryLocation(trigger?: HTMLElement | null): void;
162
+ private updateItemsOnCheckout;
163
+ private static lostCustomer;
155
164
  private syncFromItemUpdate;
156
165
  private syncCheckoutState;
157
166
  private refreshCheckout;
@@ -1,6 +1,6 @@
1
1
  import { BaseComponent } from '@/core/base-component.service';
2
2
  import type { ICheckoutComponent } from '@/interfaces/configs';
3
- import type { PlacedDeliveryWindow } from '@/utils/delivery-scheduling';
3
+ import type { PlacedDelivery } from '@/utils/delivery-scheduling';
4
4
  export interface ICheckoutCompletedComponentParams {
5
5
  orderNumber: string;
6
6
  orderTotal: number;
@@ -10,11 +10,13 @@ export interface ICheckoutCompletedComponentParams {
10
10
  checkoutToken?: string;
11
11
  cartId?: string;
12
12
  isCompleted?: boolean;
13
- deliveryWindows?: PlacedDeliveryWindow[];
13
+ delivery?: PlacedDelivery;
14
14
  }
15
15
  export declare class CheckoutCompletedComponent extends BaseComponent<ICheckoutCompletedComponentParams, ICheckoutComponent> {
16
16
  get hostClasses(): string[];
17
17
  private hasAnnouncedCompletion;
18
18
  protected afterRender(): void;
19
+ private createDeliveryLine;
20
+ private createDeliveryGroup;
19
21
  protected template(): HTMLElement[];
20
22
  }
@@ -1,5 +1,7 @@
1
1
  import { BaseComponent } from '@/core/base-component.service';
2
+ import type { ICheckoutFulfillmentMethod } from '@/interfaces/api/checkout.interface';
2
3
  import type { ICheckoutComponent } from '@/interfaces/configs';
4
+ export declare function deliveryMethodExpectationText(method: ICheckoutFulfillmentMethod): string;
3
5
  export declare class CheckoutDeliveryMethodComponent extends BaseComponent<null, ICheckoutComponent> {
4
6
  get hostClasses(): string[];
5
7
  constructor();
@@ -36,7 +36,9 @@ export declare class CheckoutDeliverySchedulingComponent extends BaseComponent<n
36
36
  private closePicker;
37
37
  private saveDraft;
38
38
  private createGroup;
39
- private get schedulingAllowed();
39
+ private get severalGroups();
40
+ private retailerOf;
41
+ private pickerTitle;
40
42
  private summaryText;
41
43
  private radio;
42
44
  private createDates;
@@ -30,6 +30,7 @@ export declare class CheckoutPaymentComponent extends BaseComponent<ICheckoutSen
30
30
  private lastAnnouncedPaymentError;
31
31
  private updateErrorMessage;
32
32
  private showError;
33
+ private createHeader;
33
34
  protected template(): HTMLElement[];
34
35
  private handleSaveButtonClick;
35
36
  private validatePrerequisites;
@@ -1,24 +1,35 @@
1
1
  import type { ApiError } from '@/core/api/api-result';
2
2
  import type { DeliveryWindowLapse } from '@/core/store/interfaces/checkout.interface';
3
3
  import type { StoreService } from '@/core/store/store.service';
4
- import type { ICheckoutFulfillment, ICheckoutRetailer, ICheckoutShippingAddress } from '@/interfaces/api/checkout.interface';
4
+ import { type FulfillmentType } from '@/enums';
5
+ import type { ICart } from '@/interfaces/api/cart.interface';
6
+ import type { ICheckoutFulfillment, ICheckoutItem, ICheckoutRetailer, ICheckoutShippingAddress } from '@/interfaces/api/checkout.interface';
5
7
  import type { CheckoutDeliveryScheduling, DeliverySlot } from '@/interfaces/api/delivery.interface';
8
+ import type { IFulfillment } from '@/interfaces/api/product.interface';
6
9
  export declare const LAPSED_DELIVERY_WINDOW_CODES: readonly string[];
7
10
  export declare const DELIVERY_WINDOW_EXPIRED_MESSAGE = "Your delivery window has passed. Choose a new delivery time.";
8
11
  export declare const DELIVERY_WINDOW_UNAVAILABLE_MESSAGE = "Your delivery window is no longer available. Choose a new delivery time.";
12
+ export declare const DELIVERY_WINDOW_REQUIRED_MESSAGE = "The store cannot deliver now. Choose a delivery time.";
9
13
  export declare const UNSUPPORTED_DELIVERY_SCHEDULING_CODES: readonly string[];
10
14
  export declare const DELIVERY_SELECTION_NOT_ACCEPTED_CODE = "delivery_selection_not_accepted";
11
15
  export declare const DELIVERY_SELECTION_NOT_ACCEPTED_MESSAGE = "We couldn't save that delivery time. Choose a delivery time again.";
12
16
  export declare const SAVED_DELIVERY_WINDOW_LABEL = "Scheduled delivery";
13
17
  export declare const DELIVERY_SCHEDULING_UNAVAILABLE_MESSAGE = "Scheduled delivery isn't available for this order right now. We'll deliver as soon as possible.";
18
+ export declare const MULTIPLE_FULFILLMENT_OPTIONS_PER_STORE_CODE = "multiple_fulfillment_options_per_store";
19
+ export declare const MULTIPLE_FULFILLMENT_OPTIONS_PER_STORE_MESSAGE = "Scheduled delivery cannot be combined with another delivery method from the same store. Choose ASAP delivery, or use one delivery method for all items from this store.";
20
+ export declare const CLOSED_STORE_MULTIPLE_FULFILLMENT_OPTIONS_MESSAGE = "This store is closed now. Use one delivery method for all items from this store.";
21
+ export declare function splitStoreRefusalMessage(store: Pick<StoreService, 'get'>): string;
22
+ export declare function freshCartSplitStoreRefusalMessage(cart: Pick<ICart, 'retailers'>): string;
14
23
  export declare function expiredDeliveryFulfillmentIds(store: Pick<StoreService, 'get'>): string[];
15
24
  export declare function deliveryWindowLapseOf(error: Pick<ApiError, 'errors'> | null | undefined): DeliveryWindowLapse;
16
25
  export type DeliveryWindowLapseText = 'message' | 'label';
17
26
  export declare function deliveryWindowLapseMessage(lapse: DeliveryWindowLapse | null | undefined, text?: DeliveryWindowLapseText): string;
18
27
  export declare function lapsedDeliveryWindowMessage(store: Pick<StoreService, 'get'>, fulfillmentId: string, text?: DeliveryWindowLapseText): string;
19
28
  export declare function withoutDeliveryWindow(fulfillment: ICheckoutFulfillment): ICheckoutFulfillment;
29
+ export declare function deliveryErrorFulfillmentIds(error: Pick<ApiError, 'errors'> | null | undefined): string[];
20
30
  export declare function isLapsedDeliveryWindowError(error: Pick<ApiError, 'errors'> | null | undefined): boolean;
21
31
  export declare function isNotAcceptedDeliverySelectionError(error: Pick<ApiError, 'errors'> | null | undefined): boolean;
32
+ export declare function isMultipleFulfillmentOptionsPerStoreError(error: Pick<ApiError, 'errors'> | null | undefined): boolean;
22
33
  export declare function isUnsupportedDeliverySchedulingError(error: Pick<ApiError, 'errors'> | null | undefined): boolean;
23
34
  export declare function deliveryAddressKey(address: ICheckoutShippingAddress | null | undefined): string;
24
35
  export declare function isFutureDeliverySlot(slot: DeliverySlot | null | undefined, now?: number): boolean;
@@ -27,17 +38,35 @@ export declare function isLapsedSelectedDeliverySlot(scheduling: CheckoutDeliver
27
38
  export declare function deliverySchedulesReady(fulfillments: Record<string, ICheckoutFulfillment>, now?: number, expired?: string[]): boolean;
28
39
  export declare function deliveryChoicesMade(fulfillments: Record<string, ICheckoutFulfillment>, expired?: string[]): boolean;
29
40
  export declare function hasDeliveryScheduling(fulfillments: Record<string, ICheckoutFulfillment> | null | undefined): boolean;
30
- export declare function deliverySchedulingAllowed(fulfillments: Record<string, ICheckoutFulfillment> | null | undefined): boolean;
41
+ export declare function retailerOfFulfillment(retailers: Record<string, ICheckoutRetailer> | null | undefined, fulfillmentId: string): ICheckoutRetailer | undefined;
42
+ export declare function deliveryWindowNeededMessage(store: Pick<StoreService, 'get'>, fulfillmentIds: string[]): string;
43
+ export declare function hasSeveralDeliveryGroups(fulfillments: Record<string, ICheckoutFulfillment> | null | undefined): boolean;
31
44
  export declare function deliveryTimeZone(timezone: string | null | undefined): string;
45
+ export declare function deliveryDateTimeFormat(timezone: string, options: Omit<Intl.DateTimeFormatOptions, 'timeZone'>): Intl.DateTimeFormat;
32
46
  export declare function deliveryDateLabel(slot: DeliverySlot, timezone: string): string;
33
47
  export declare function deliveryTimeZoneName(timezone: string, style?: 'short' | 'long'): string;
34
48
  export declare function deliveryTimeLabel(slot: DeliverySlot, timezone: string): string;
35
49
  export declare function deliveryWindowLabel(slot: DeliverySlot, timezone: string): string;
36
50
  export declare function deliveryScheduledLabel(slot: DeliverySlot, timezone: string): string;
37
51
  export declare function deliveryCutoffLabel(slot: DeliverySlot, timezone: string): string;
38
- export interface PlacedDeliveryWindow {
39
- retailerName: string | null;
52
+ export interface PlacedDeliveryLine {
53
+ heading: string;
40
54
  label: string;
41
55
  }
42
- export declare function placedDeliveryWindows(fulfillments: Record<string, ICheckoutFulfillment> | null | undefined, retailers: Record<string, ICheckoutRetailer> | null | undefined): PlacedDeliveryWindow[];
56
+ export interface PlacedDelivery {
57
+ perGroup: boolean;
58
+ lines: PlacedDeliveryLine[];
59
+ }
60
+ export declare function placedDeliveryLines(fulfillments: Record<string, ICheckoutFulfillment> | null | undefined, retailers: Record<string, ICheckoutRetailer> | null | undefined, items?: Record<string, ICheckoutItem> | null): PlacedDelivery;
61
+ type FulfillmentAvailability = Pick<IFulfillment, 'hourStatus' | 'deliveryAvailability'>;
62
+ type SchedulingAvailability = Pick<IFulfillment, 'deliveryAvailability'>;
63
+ export declare function deliversNow(fulfillment: FulfillmentAvailability): boolean;
64
+ export declare function takesOrdersForLater(fulfillment: SchedulingAvailability, now?: number): boolean;
65
+ export declare function nextScheduledDeliverySlot(fulfillment: SchedulingAvailability, now?: number): DeliverySlot | null;
66
+ export declare function isDeliveryPurchasable(fulfillment: FulfillmentAvailability, now?: number): boolean;
67
+ export declare function isOnDemandUnpurchasable(type: FulfillmentType, fulfillment: FulfillmentAvailability): boolean;
68
+ export declare function preferredOnDemandFulfillment<T extends FulfillmentAvailability>(fulfillments: T[], now?: number): T | undefined;
69
+ export declare function nextArrivalLabel(fulfillment: SchedulingAvailability, now?: number): string | null;
70
+ export declare function scheduleDeliveryText(fulfillment: SchedulingAvailability, now?: number): string | null;
43
71
  export declare function resolveDeliverySlot(scheduling: CheckoutDeliveryScheduling | undefined, advertised: DeliverySlot, now?: number): DeliverySlot | null;
72
+ export {};
@@ -0,0 +1,8 @@
1
+ import type { ApiError } from '@/core/api/api-result';
2
+ export declare const FULFILLMENT_UNAVAILABLE_CODE = "fulfillment_unavailable";
3
+ export interface FulfillmentRetailer {
4
+ id: string;
5
+ name: string;
6
+ fulfillments: Record<string, unknown>;
7
+ }
8
+ export declare function fulfillmentUnavailableMessage(error: Pick<ApiError, 'errors'> | null | undefined, retailers: FulfillmentRetailer[]): string | null;
@@ -461,7 +461,7 @@ Loads the full list of delivery windows for one fulfillment. Checkout prepare re
461
461
  chooseDeliverySlot(fulfillmentId: string, slotId: string | null): Promise<void>
462
462
  ```
463
463
 
464
- Saves a window from the last loaded list for one fulfillment, or `null` for as soon as possible (only when `availability.canDeliverNow` is true). The promise resolves after prepare accepts and echoes that exact selection. It rejects malformed arguments, unknown fulfillments, windows that were not offered, concurrent checkout updates, a checkout with more than one fulfillment group (only a checkout with one group can be scheduled) and server errors; a rejected save keeps the previously accepted choice, except after `delivery_selection_not_accepted` (below). Slot IDs come from the server; do not build them.
464
+ Saves a window from the last loaded list for one fulfillment, or `null` for as soon as possible (only when `availability.canDeliverNow` is true). The promise resolves after prepare accepts and echoes that exact selection. It rejects malformed arguments, unknown fulfillments, windows that were not offered, concurrent checkout updates and server errors; a rejected save keeps the previously accepted choice, except after `delivery_selection_not_accepted` (below). Slot IDs come from the server; do not build them.
465
465
 
466
466
  `getDetails().deliveryScheduling[fulfillmentId]` returns the availability, the accepted `selectedSlotId` and `selectedSlot` (the accepted window's `start`, `end` and `cutoff`).
467
467
 
@@ -476,11 +476,13 @@ if (fulfillmentId) {
476
476
 
477
477
  ### Expired windows
478
478
 
479
- If a saved window's cutoff passes, or the store's hours or zone rules no longer allow it, before the order is placed, the server answers Place Order, or any other checkout update, with error code `delivery_window_expired` or `delivery_window_unavailable`. Both are recovered the same way; only the message differs ("Your delivery window has passed. Choose a new delivery time." or "Your delivery window is no longer available. Choose a new delivery time."). The SDK then clears the window, marks the fulfillment as needing a new choice, shows the message, opens the picker and blocks payment and Place Order until the shopper saves a new choice. An update that hit the error is sent once more without the window, so the shopper's change still applies. Customer, address, payment, tip and notes stay as they were. A custom UI recovers the same way: load the windows again and call `chooseDeliverySlot`.
479
+ If a saved window's cutoff passes, or the store's hours or zone rules no longer allow it, before the order is placed, the server answers Place Order, or any other checkout update, with error code `delivery_window_expired` or `delivery_window_unavailable`. Place Order on a store that cannot deliver now with no saved window answers `delivery_window_required`. All three are recovered the same way; only the message differs ("Your delivery window has passed. Choose a new delivery time.", "Your delivery window is no longer available. Choose a new delivery time." or "The store cannot deliver now. Choose a delivery time."). The SDK then clears the window, marks the fulfillment as needing a new choice, shows the message, opens the picker and blocks payment and Place Order until the shopper saves a new choice. An update that hit the error is sent once more without the window, so the shopper's change still applies. Customer, address, payment, tip and notes stay as they were. A custom UI recovers the same way: load the windows again and call `chooseDeliverySlot`.
480
480
 
481
481
  If prepare did not keep the window that was sent (error code `delivery_selection_not_accepted`, HTTP 409), the SDK drops the window it holds for that fulfillment so no later update sends it again. `chooseDeliverySlot` rejects with "We couldn't save that delivery time. Choose a delivery time again."; on any other update the window is recovered as an unavailable one.
482
482
 
483
- When scheduled delivery stops applying to the order (`delivery_scheduling_not_enabled`, `delivery_windows_unsupported`, `multiple_fulfillment_groups` or `delivery_scheduling_unsupported`), the SDK drops the saved window with a re-prepare, keeps the rest of checkout and shows "Scheduled delivery isn't available for this order right now. We'll deliver as soon as possible." The picker does not open; the response no longer carries `deliveryScheduling`, so the delivery time row goes away. Switching the delivery method never carries a window over to the new fulfillment.
483
+ If a store cannot fulfill the selected delivery method at all, pickup included (error code `fulfillment_unavailable`, for example a closed store that offers no delivery window, or no estimate for the address), the SDK shows "W & J Wines & Spirits cannot fulfill this order now. Choose another store or delivery method." in place of the server's message, on loading the checkout, on any checkout update, on Place Order and on the cart's go-to-checkout. The store name comes from the cart or the checkout; when neither names the store, the message starts with "A store in your cart". The error detail carries the LC `retailerId` and `fulfillmentId` of each refused selection, so a custom UI can point at the store the same way. When AccelPay returns no estimates at all, Cloud refuses every selection, so the message names every store in the cart, even when the cause is the address.
484
+
485
+ When scheduled delivery stops applying to the order (`delivery_scheduling_not_enabled`, `delivery_windows_unsupported` or `delivery_scheduling_unsupported`, and `multiple_fulfillment_groups` from an older server that schedules one group only), the SDK drops the saved window with a re-prepare, keeps the rest of checkout and shows "Scheduled delivery isn't available for this order right now. We'll deliver as soon as possible." The picker does not open; the response no longer carries `deliveryScheduling`, so the delivery time row goes away. Switching the delivery method never carries a window over to the new fulfillment.
484
486
 
485
487
  ## Use Cases
486
488
 
@@ -155,6 +155,7 @@ interface IFulfillment {
155
155
  fee: number;
156
156
  timezone: string;
157
157
  hourStatus: { isOpen: boolean; openTime: string; isClosed: boolean; closeTime: string };
158
+ deliveryAvailability?: DeliveryAvailability; // same-day only, where the retailer schedules delivery
158
159
  }
159
160
 
160
161
  interface IProduct {
@@ -590,7 +590,7 @@ export interface DeliveryAvailability {
590
590
  canDeliverNow: boolean;
591
591
  canSchedule: boolean;
592
592
  timezone: string | null; // store IANA time zone; null when the server has none (the SDK then shows UTC)
593
- nextSlot: DeliverySlot | null;
593
+ nextSlot: DeliverySlot | null; // null on a product fulfillment of a closed store: checkout gives the windows
594
594
  checkedAt: string;
595
595
  }
596
596
 
@@ -152,7 +152,10 @@ on render, and a live region recreated with its text already in place is not ann
152
152
  - An option in a single-select group carries its **whole** visible content in its accessible name.
153
153
  `option` and `radio` have presentational children, so the name is the only channel: a delivery
154
154
  option names the retailer, the price, the timing, the delivery fee and — for same-day — the
155
- store address and whether it is currently closed.
155
+ store address and whether it is currently closed. A closed store that schedules delivery leads
156
+ with that instead ("Columbus Avenue Wines, closed now, schedule delivery"), followed by
157
+ "next arrival Thu, Oct 8, 1 PM – 2 PM ET" only when the server sends a next window; its card
158
+ stays enabled.
156
159
  - The California Proposition 65 warning on the product is a native `<details>` / `<summary>`
157
160
  disclosure: the summary is a button that exposes its expanded state, and `Enter` / `Space` toggle
158
161
  it with no scripting involved. Its `+` / `−` indicator is decorative and hidden. In checkout it is
@@ -14,6 +14,8 @@ The Cart component automatically:
14
14
  - Persists cart across sessions and tabs
15
15
  - Provides checkout navigation
16
16
 
17
+ A same-day line from a store that is closed now but takes orders for later (its fulfillment's `deliveryAvailability` says it cannot deliver now and can schedule) shows "Schedule delivery" in place of the delivery estimate. The shopper chooses the delivery window in checkout.
18
+
17
19
  ## Basic Usage
18
20
 
19
21
  The cart is automatically available when using the SDK - no explicit injection needed for the drawer. However, you need a way for users to open it.
@@ -909,8 +909,12 @@ fails, the shopper can retry or explicitly choose the visible channel preference
909
909
 
910
910
  When an AccelPay retailer has scheduled delivery turned on, checkout shows a **Delivery time** row for that delivery, between the delivery details and payment. It reads "As soon as possible" while the store can deliver now, or asks for a window when it cannot. The row's button reads **Schedule** while the row is on as soon as possible, **Edit** after a window is saved, and **Schedule delivery** when the shopper must choose a window. It opens a dialog that loads the windows for that delivery: date cards for today and the next 7 days, then arrival windows in the retailer's time zone, named once above the list ("Times in Eastern Time"). The window list scrolls inside the dialog and keeps the chosen window in view. The first window shows "Order by" with its cutoff, and **As soon as possible** sits next to it when the store can deliver now. Choices are drafts until **Save**; Cancel, Close and Escape discard them.
911
911
 
912
- The accepted window shows in the row and on the items in the order summary ("Scheduled for Thu, Oct 8, 1 PM – 2 PM ET"), and on the thank-you page as "Delivery time" with "Thu, Oct 8, 1 PM – 2 PM ET" (with more than one window, each line names its retailer). An ASAP order adds no line there. If the window's cutoff passes before the order is placed, the SDK clears it, shows "Your delivery window has passed. Choose a new delivery time.", reopens the picker and keeps Place Order disabled until a new choice is saved. If the store no longer offers the window, the same happens with "Your delivery window is no longer available. Choose a new delivery time." Everything else the shopper entered stays.
912
+ The accepted window shows in the row and on the items in the order summary ("Scheduled for Thu, Oct 8, 1 PM – 2 PM ET"), and on the thank-you page as "Delivery time" with "Thu, Oct 8, 1 PM – 2 PM ET". An ASAP order adds no line there. If the window's cutoff passes before the order is placed, the SDK clears it, shows "Your delivery window has passed. Choose a new delivery time.", reopens the picker and keeps Place Order disabled until a new choice is saved. If the store no longer offers the window, the same happens with "Your delivery window is no longer available. Choose a new delivery time." Everything else the shopper entered stays.
913
913
 
914
- A checkout with more than one fulfillment group cannot be scheduled: the row reads "As soon as possible" with no picker button, and no window is asked for. While a store that cannot deliver now has no accepted window, the express wallet buttons stay off, like the card form.
914
+ A store that was added to the cart while closed cannot deliver now, so checkout asks for a window and offers no ASAP. If a store closes after the shopper chose ASAP, Place Order answers `delivery_window_required`: the SDK shows "The store cannot deliver now. Choose a delivery time.", opens the picker and keeps Place Order disabled until a window is saved.
915
+
916
+ In a checkout with more than one fulfillment group (another store, or shipping), each same-day group with scheduled delivery gets its own **Delivery time** row and its own picker, which loads that group's windows. Its button reads **Schedule this store's delivery** (**Edit** after a window is saved), and the picker is named after the store ("Schedule delivery from Columbus Avenue Wines"). Every prepare sends each group's current choice, so saving one group keeps the other's window. A group whose store can deliver now stays on as soon as possible; a group whose store cannot needs its own window before payment and Place Order. When a window lapses, only that group's window is cleared and only its picker reopens: the SDK clears the window whose cutoff passed on the page, and for `delivery_window_required` marks the groups that have no window. When an error names its group (`fulfillmentId` on the error entry), only that group is cleared; when it names none and the SDK cannot place it, every saved window is cleared. Until each store that cannot deliver now has a window, payment says which: "Choose a delivery window for Amsterdam Liquors before continuing." In an order with more than one fulfillment group, the thank-you page has one line per group, named after its store: the accepted window for a scheduled group ("Columbus Avenue Wines" with "Thu, Oct 8, 1 PM – 2 PM ET"), and the group's own expectation for the others ("Harbor Spirits" with "Ships in 3-5 days"). A scheduled group never shows the as-soon-as-possible expectation. While a store that cannot deliver now has no accepted window, the express wallet buttons stay off, like the card form. When checkout refuses a store that has scheduled delivery and also another delivery method (`multiple_fulfillment_options_per_store`, code 5516), the SDK shows the refusal as the checkout error and keeps the saved windows: "Scheduled delivery cannot be combined with another delivery method from the same store. Choose ASAP delivery, or use one delivery method for all items from this store." When that store is closed now, the text leaves out ASAP: "This store is closed now. Use one delivery method for all items from this store." When Place Order is refused, the SDK reads the cart again and decides "closed now" from its `deliveryAvailability`, because a store can close after the last prepare. Place Order and the express wallet stay off until a prepare succeeds after a change to the cart or to a delivery choice.
917
+
918
+ In the delivery-method switch, a same-day method whose `deliveryAvailability` says the store cannot deliver now but can schedule shows "Schedule delivery" in place of its delivery estimate. Without `deliveryAvailability` the card shows the estimate as before.
915
919
 
916
920
  Checkouts without scheduled delivery are unchanged. For a custom UI, see `actions.checkout.loadDeliverySlots` and `actions.checkout.chooseDeliverySlot` in the checkout actions reference, and the `checkout_delivery_selection_updated` event.
@@ -480,6 +480,12 @@ await window.LiquidCommerce.elements.actions.address.setAddressManually(
480
480
  );
481
481
  ```
482
482
 
483
+ ## Buying when a retailer is closed
484
+
485
+ A same-day retailer whose store schedules delivery can take orders while it is closed. Its fulfillment then carries `deliveryAvailability`. When that says the store cannot deliver now but can schedule (`status: 'available'`, `canSchedule: true`), the retailer card stays on and shows "Schedule delivery". The product page shows no time: the server sends `nextSlot: null` for a closed store, and checkout asks the shopper to choose a delivery window. Add to Cart stays on. Screen readers hear "Columbus Avenue Wines, closed now, schedule delivery" in place of "Currently closed". When the server does send a `nextSlot`, the card adds it in the retailer's time zone ("Schedule delivery · Thu, Oct 8, 1 PM – 2 PM ET") and screen readers hear "…, next arrival Thu, Oct 8, 1 PM – 2 PM ET". The SDK selects a retailer that can deliver now first, then one that schedules delivery, and goes to shipping only when neither is available.
486
+
487
+ A closed store without scheduled delivery is blocked as before. An unknown or unavailable `deliveryAvailability`, or a `nextSlot` whose order cutoff has passed, never turns purchase on.
488
+
483
489
  ## Presale Products
484
490
 
485
491
  Products in presale mode:
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "description": "LiquidCommerce Elements SDK",
4
4
  "license": "UNLICENSED",
5
5
  "author": "LiquidCommerce Team",
6
- "version": "2.6.0-beta.130",
6
+ "version": "2.6.0-beta.132",
7
7
  "homepage": "https://docs.liquidcommerce.co/elements-sdk",
8
8
  "repository": {
9
9
  "type": "git",