@liquidcommerce/elements-sdk 2.7.43 → 2.7.45
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/README.md +5 -3
- package/dist/index.checkout.esm.js +10921 -8952
- package/dist/index.esm.js +15834 -13867
- package/dist/ssr-stub.esm.js +3 -0
- package/dist/types/core/a11y/focus-manager.service.d.ts +1 -1
- package/dist/types/core/api/api-result.d.ts +3 -0
- package/dist/types/core/client/actions/client-analytics-action.service.d.ts +35 -0
- package/dist/types/core/client/actions/client-checkout-action.service.d.ts +6 -0
- package/dist/types/core/client/client-action.service.d.ts +1 -0
- package/dist/types/core/client/client-config.service.d.ts +2 -0
- package/dist/types/core/google-tag-manager.service.d.ts +3 -2
- package/dist/types/core/pubsub/interfaces/checkout.interface.d.ts +6 -0
- package/dist/types/core/pubsub/interfaces/core.interface.d.ts +3 -1
- package/dist/types/core/store/interfaces/checkout.interface.d.ts +4 -0
- package/dist/types/enums/core.enum.d.ts +3 -0
- package/dist/types/index.checkout.d.ts +4 -2
- package/dist/types/index.d.ts +1 -0
- package/dist/types/interfaces/analytics.interface.d.ts +41 -0
- package/dist/types/interfaces/api/cart.interface.d.ts +2 -0
- package/dist/types/interfaces/api/checkout.interface.d.ts +7 -1
- package/dist/types/interfaces/api/delivery.interface.d.ts +24 -0
- package/dist/types/interfaces/api/index.d.ts +1 -0
- package/dist/types/interfaces/api/product.interface.d.ts +2 -0
- package/dist/types/interfaces/client.interface.d.ts +5 -0
- package/dist/types/interfaces/config.interface.d.ts +1 -0
- package/dist/types/modules/cart/cart.commands.d.ts +3 -1
- package/dist/types/modules/cart/components/cart-item.component.d.ts +2 -0
- package/dist/types/modules/checkout/checkout.commands.d.ts +41 -0
- package/dist/types/modules/checkout/components/checkout-completed.component.d.ts +4 -0
- package/dist/types/modules/checkout/components/checkout-delivery-method.component.d.ts +2 -0
- package/dist/types/modules/checkout/components/checkout-delivery-scheduling.component.d.ts +53 -0
- package/dist/types/modules/checkout/components/checkout-express-checkout.component.d.ts +3 -0
- package/dist/types/modules/checkout/components/checkout-item.component.d.ts +2 -0
- package/dist/types/modules/checkout/components/checkout-payment.component.d.ts +3 -0
- package/dist/types/modules/checkout/components/index.d.ts +1 -0
- package/dist/types/modules/product-list/product-list.commands.d.ts +5 -0
- package/dist/types/ssr/stub.checkout.d.ts +3 -1
- package/dist/types/ssr/stub.d.ts +3 -1
- package/dist/types/utils/delivery-scheduling.d.ts +75 -0
- package/dist/types/utils/fulfillment-unavailable.d.ts +8 -0
- package/docs/v1/README.md +1 -0
- package/docs/v1/api/actions/analytics-actions.md +326 -0
- package/docs/v1/api/actions/checkout-actions.md +47 -2
- package/docs/v1/api/actions/product-actions.md +1 -0
- package/docs/v1/api/client.md +9 -2
- package/docs/v1/api/configuration.md +4 -0
- package/docs/v1/api/typescript-types.md +110 -1
- package/docs/v1/guides/accessibility.md +8 -1
- package/docs/v1/guides/cart-component.md +2 -0
- package/docs/v1/guides/checkout-component.md +64 -2
- package/docs/v1/guides/events.md +36 -2
- package/docs/v1/guides/product-component.md +6 -0
- package/docs/v1/reference/analytics.md +52 -9
- package/package.json +4 -4
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { BaseComponent } from '@/core/base-component.service';
|
|
2
|
+
import type { ICheckoutComponent } from '@/interfaces/configs';
|
|
3
|
+
export declare class CheckoutDeliverySchedulingComponent extends BaseComponent<null, ICheckoutComponent> {
|
|
4
|
+
private draft;
|
|
5
|
+
private dialog;
|
|
6
|
+
private paintScheduled;
|
|
7
|
+
private error;
|
|
8
|
+
private pendingFocus;
|
|
9
|
+
private restoreTrigger;
|
|
10
|
+
private releaseFocusTrap;
|
|
11
|
+
private readonly focusManager;
|
|
12
|
+
private handledExpired;
|
|
13
|
+
private loadToken;
|
|
14
|
+
private announcedNotice;
|
|
15
|
+
private timesScroll;
|
|
16
|
+
constructor();
|
|
17
|
+
private get busy();
|
|
18
|
+
private get expiredIds();
|
|
19
|
+
protected afterRender(): void;
|
|
20
|
+
protected onStoreChanged(): boolean;
|
|
21
|
+
private update;
|
|
22
|
+
private paint;
|
|
23
|
+
private showDialog;
|
|
24
|
+
private settle;
|
|
25
|
+
private keepTimeInView;
|
|
26
|
+
protected disconnected(): void;
|
|
27
|
+
private endPicker;
|
|
28
|
+
private draftFulfillment;
|
|
29
|
+
private openForNewlyExpired;
|
|
30
|
+
private dayKey;
|
|
31
|
+
private todayKey;
|
|
32
|
+
private draftScheduling;
|
|
33
|
+
private openPicker;
|
|
34
|
+
private loadSlots;
|
|
35
|
+
private whenIdle;
|
|
36
|
+
private closePicker;
|
|
37
|
+
private saveDraft;
|
|
38
|
+
private createGroup;
|
|
39
|
+
private get severalGroups();
|
|
40
|
+
private retailerOf;
|
|
41
|
+
private pickerTitle;
|
|
42
|
+
private summaryText;
|
|
43
|
+
private radio;
|
|
44
|
+
private createDates;
|
|
45
|
+
private createTimes;
|
|
46
|
+
private createNotice;
|
|
47
|
+
private createLoading;
|
|
48
|
+
private createDialogShell;
|
|
49
|
+
private fillDialog;
|
|
50
|
+
private captureViewState;
|
|
51
|
+
private createRows;
|
|
52
|
+
protected template(): HTMLElement[];
|
|
53
|
+
}
|
|
@@ -8,6 +8,7 @@ export declare class CheckoutExpressCheckoutComponent extends BaseComponent<IChe
|
|
|
8
8
|
private section;
|
|
9
9
|
private walletHost;
|
|
10
10
|
private completionElement;
|
|
11
|
+
private beginCheckoutReported;
|
|
11
12
|
private stripe;
|
|
12
13
|
private stripeElements;
|
|
13
14
|
private expressElement;
|
|
@@ -19,6 +20,7 @@ export declare class CheckoutExpressCheckoutComponent extends BaseComponent<IChe
|
|
|
19
20
|
private hasAvailableWallets;
|
|
20
21
|
private availableWallets;
|
|
21
22
|
private hasSettledAvailability;
|
|
23
|
+
private scheduleReadyAtMount;
|
|
22
24
|
private lastPublishedAvailability;
|
|
23
25
|
get hostClasses(): string[];
|
|
24
26
|
constructor();
|
|
@@ -27,6 +29,7 @@ export declare class CheckoutExpressCheckoutComponent extends BaseComponent<IChe
|
|
|
27
29
|
private get isCompletingExpress();
|
|
28
30
|
private get isButtonsOnly();
|
|
29
31
|
private get isReadyForPayment();
|
|
32
|
+
private get isDeliveryScheduleReady();
|
|
30
33
|
private get isGiftOrder();
|
|
31
34
|
protected template(): HTMLElement[];
|
|
32
35
|
protected afterRender(): void;
|
|
@@ -7,6 +7,8 @@ export declare class CheckoutItemComponent extends BaseComponent<ICheckoutItemCo
|
|
|
7
7
|
get hostClasses(): string[];
|
|
8
8
|
constructor();
|
|
9
9
|
onStoreChanged(changes: IOnStoreChanged[]): boolean | undefined;
|
|
10
|
+
private deliveryExpectation;
|
|
11
|
+
private updateDeliveryExpectation;
|
|
10
12
|
private updateEngravingElement;
|
|
11
13
|
private setupMinimumPurchaseAlert;
|
|
12
14
|
private updateTrashButtonState;
|
|
@@ -18,6 +18,8 @@ export declare class CheckoutPaymentComponent extends BaseComponent<ICheckoutSen
|
|
|
18
18
|
get hostClasses(): string[];
|
|
19
19
|
constructor();
|
|
20
20
|
private getInjectedPaymentMethod;
|
|
21
|
+
private scheduleReady;
|
|
22
|
+
private deliveryPaymentReady;
|
|
21
23
|
onStoreWatch(changes: IOnStoreChanged[]): void;
|
|
22
24
|
private handleBillingSameAsShippingChange;
|
|
23
25
|
afterRender(): Promise<void>;
|
|
@@ -28,6 +30,7 @@ export declare class CheckoutPaymentComponent extends BaseComponent<ICheckoutSen
|
|
|
28
30
|
private lastAnnouncedPaymentError;
|
|
29
31
|
private updateErrorMessage;
|
|
30
32
|
private showError;
|
|
33
|
+
private createHeader;
|
|
31
34
|
protected template(): HTMLElement[];
|
|
32
35
|
private handleSaveButtonClick;
|
|
33
36
|
private validatePrerequisites;
|
|
@@ -6,6 +6,7 @@ export * from './checkout-completed.component';
|
|
|
6
6
|
export * from './checkout-deliver-to.component';
|
|
7
7
|
export * from './checkout-deliver-to-summary.component';
|
|
8
8
|
export * from './checkout-delivery-method.component';
|
|
9
|
+
export * from './checkout-delivery-scheduling.component';
|
|
9
10
|
export * from './checkout-express-checkout.component';
|
|
10
11
|
export * from './checkout-express-completion.component';
|
|
11
12
|
export * from './checkout-gift-cards.component';
|
|
@@ -28,4 +28,9 @@ export declare class ProductListCommands extends BaseCommand {
|
|
|
28
28
|
selectFulfillment: (slug: string, productId: string, selectedFulfillmentId: string) => Promise<void>;
|
|
29
29
|
updateQuantity: (slug: string, productId: string, quantity: number) => void;
|
|
30
30
|
saveEngravingLines(slug: string, productId: string, engravingLines: string[]): void;
|
|
31
|
+
private trackListPage;
|
|
32
|
+
trackSelectItem(slug: string, productId: string): void;
|
|
33
|
+
trackSearch(searchTerm: string): void;
|
|
34
|
+
private toAnalyticsItem;
|
|
35
|
+
private getListName;
|
|
31
36
|
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export type { DebugMode, ElementsEnv } from '../enums/core.enum';
|
|
2
2
|
export { DEBUG_MODE, ELEMENTS_ENV } from '../enums/core.enum';
|
|
3
|
-
export type {
|
|
3
|
+
export type { IAnalyticsAddress, IAnalyticsAddressFailure, IAnalyticsAvailability, IAnalyticsFulfillmentAvailability, IAnalyticsItem, IAnalyticsItemList, } from '../interfaces/analytics.interface';
|
|
4
|
+
export type { IAnalyticsActions, IElementsCheckoutActions, IElementsCheckoutClient, } from '../interfaces/client.interface';
|
|
4
5
|
export type { IInjectedComponent } from '../interfaces/component.interface';
|
|
5
6
|
export type { ILiquidCommerceElementsCheckoutClientConfig } from '../interfaces/config.interface';
|
|
6
7
|
export declare function ElementsCheckout(..._args: any[]): Promise<null>;
|
|
8
|
+
export type { CheckoutDeliveryScheduling, CheckoutDeliverySelection, DeliveryAvailability, DeliverySlot, } from '../interfaces/api/delivery.interface';
|
package/dist/types/ssr/stub.d.ts
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
export { SDKError, isSDKError } from '../core/sdk-error-handler';
|
|
2
2
|
export type { CartEventLevel, CartEventType, CheckoutEventLevel, CheckoutEventType, ComponentType, DebugMode, DisplayModeType, ElementsEnv, FulfillmentType, NavigationSourceType, } from '../enums/core.enum';
|
|
3
3
|
export { CART_EVENT_LEVEL, CART_EVENT_TYPE, CHECKOUT_EVENT_LEVEL, CHECKOUT_EVENT_TYPE, COMPONENT_TYPE, DEBUG_MODE, DISPLAY_MODE, ELEMENTS_ACTIONS_EVENT, ELEMENTS_ENV, ELEMENTS_FORM, FULFILLMENT_TYPE, NAVIGATION_SOURCE, } from '../enums/core.enum';
|
|
4
|
-
export type {
|
|
4
|
+
export type { IAnalyticsAddress, IAnalyticsAddressFailure, IAnalyticsAvailability, IAnalyticsFulfillmentAvailability, IAnalyticsItem, IAnalyticsItemList, } from '../interfaces/analytics.interface';
|
|
5
|
+
export type { IAnalyticsActions, ILiquidCommerceElementsActions, ILiquidCommerceElementsBuilderClient, ILiquidCommerceElementsClient, } from '../interfaces/client.interface';
|
|
5
6
|
export type { IInjectedComponent } from '../interfaces/component.interface';
|
|
6
7
|
export type { IElementsGTMConfig, IElementsProxyConfig, ILiquidCommerceElementsBuilderConfig, ILiquidCommerceElementsCheckoutConfig, ILiquidCommerceElementsConfig, ILiquidCommerceElementsDevelopmentConfig, } from '../interfaces/config.interface';
|
|
7
8
|
export type * from '../interfaces/configs';
|
|
8
9
|
export type { IBuilderInjectElementParams, IInjectCheckoutBuilderParams, IInjectCheckoutParams, IInjectProductElement, IInjectProductListFiltersParams, IInjectProductListParams, IInjectProductListSearchParams, ProductListFilterType, } from '../interfaces/injection.interface';
|
|
9
10
|
export declare function Elements(..._args: any[]): Promise<null>;
|
|
10
11
|
export declare function ElementsBuilder(..._args: any[]): Promise<null>;
|
|
12
|
+
export type { CheckoutDeliveryScheduling, CheckoutDeliverySelection, DeliveryAvailability, DeliverySlot, } from '../interfaces/api/delivery.interface';
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import type { ApiError } from '@/core/api/api-result';
|
|
2
|
+
import type { DeliveryWindowLapse } from '@/core/store/interfaces/checkout.interface';
|
|
3
|
+
import type { StoreService } from '@/core/store/store.service';
|
|
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';
|
|
7
|
+
import type { CheckoutDeliveryScheduling, DeliverySlot } from '@/interfaces/api/delivery.interface';
|
|
8
|
+
import type { IFulfillment } from '@/interfaces/api/product.interface';
|
|
9
|
+
export declare const LAPSED_DELIVERY_WINDOW_CODES: readonly string[];
|
|
10
|
+
export declare const DELIVERY_WINDOW_EXPIRED_MESSAGE = "Your delivery window has passed. Choose a new delivery time.";
|
|
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.";
|
|
13
|
+
export declare const UNSUPPORTED_DELIVERY_SCHEDULING_CODES: readonly string[];
|
|
14
|
+
export declare const DELIVERY_SELECTION_NOT_ACCEPTED_CODE = "delivery_selection_not_accepted";
|
|
15
|
+
export declare const DELIVERY_SELECTION_NOT_ACCEPTED_MESSAGE = "We couldn't save that delivery time. Choose a delivery time again.";
|
|
16
|
+
export declare const SAVED_DELIVERY_WINDOW_LABEL = "Scheduled delivery";
|
|
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 splitStoreMessageFromStore(store: Pick<StoreService, 'get'>): string;
|
|
22
|
+
export declare function splitStoreMessageFromError(error: Pick<ApiError, 'errors'> | null | undefined): string | null;
|
|
23
|
+
export declare function splitStoreRefusalText(error: Pick<ApiError, 'errors'> | null | undefined, store: Pick<StoreService, 'get'>): string;
|
|
24
|
+
export declare function splitStoreMessageFromCart(cart: Pick<ICart, 'retailers'>): string;
|
|
25
|
+
export declare function expiredDeliveryFulfillmentIds(store: Pick<StoreService, 'get'>): string[];
|
|
26
|
+
export declare function deliveryWindowLapseOf(error: Pick<ApiError, 'errors'> | null | undefined): DeliveryWindowLapse;
|
|
27
|
+
export type DeliveryWindowLapseText = 'message' | 'label';
|
|
28
|
+
export declare function deliveryWindowLapseMessage(lapse: DeliveryWindowLapse | null | undefined, text?: DeliveryWindowLapseText): string;
|
|
29
|
+
export declare function lapsedDeliveryWindowMessage(store: Pick<StoreService, 'get'>, fulfillmentId: string, text?: DeliveryWindowLapseText): string;
|
|
30
|
+
export declare function withoutDeliveryWindow(fulfillment: ICheckoutFulfillment): ICheckoutFulfillment;
|
|
31
|
+
export declare function deliveryErrorFulfillmentIds(error: Pick<ApiError, 'errors'> | null | undefined): string[];
|
|
32
|
+
export declare function isLapsedDeliveryWindowError(error: Pick<ApiError, 'errors'> | null | undefined): boolean;
|
|
33
|
+
export declare function isNotAcceptedDeliverySelectionError(error: Pick<ApiError, 'errors'> | null | undefined): boolean;
|
|
34
|
+
export declare function isMultipleFulfillmentOptionsPerStoreError(error: Pick<ApiError, 'errors'> | null | undefined): boolean;
|
|
35
|
+
export declare function isUnsupportedDeliverySchedulingError(error: Pick<ApiError, 'errors'> | null | undefined): boolean;
|
|
36
|
+
export declare function deliveryAddressKey(address: ICheckoutShippingAddress | null | undefined): string;
|
|
37
|
+
export declare function isFutureDeliverySlot(slot: DeliverySlot | null | undefined, now?: number): boolean;
|
|
38
|
+
export declare function selectedDeliverySlot(scheduling: CheckoutDeliveryScheduling | null | undefined): DeliverySlot | null;
|
|
39
|
+
export declare function isLapsedSelectedDeliverySlot(scheduling: CheckoutDeliveryScheduling | null | undefined, now?: number): boolean;
|
|
40
|
+
export declare function deliverySchedulesReady(fulfillments: Record<string, ICheckoutFulfillment>, now?: number, expired?: string[]): boolean;
|
|
41
|
+
export declare function deliveryChoicesMade(fulfillments: Record<string, ICheckoutFulfillment>, expired?: string[]): boolean;
|
|
42
|
+
export declare function hasDeliveryScheduling(fulfillments: Record<string, ICheckoutFulfillment> | null | undefined): boolean;
|
|
43
|
+
export declare function retailerOfFulfillment(retailers: Record<string, ICheckoutRetailer> | null | undefined, fulfillmentId: string): ICheckoutRetailer | undefined;
|
|
44
|
+
export declare function deliveryWindowNeededMessage(store: Pick<StoreService, 'get'>, fulfillmentIds: string[]): string;
|
|
45
|
+
export declare function hasSeveralDeliveryGroups(fulfillments: Record<string, ICheckoutFulfillment> | null | undefined): boolean;
|
|
46
|
+
export declare function deliveryTimeZone(): string;
|
|
47
|
+
export declare function deliveryDateTimeFormat(timezone: string, options: Omit<Intl.DateTimeFormatOptions, 'timeZone'>): Intl.DateTimeFormat;
|
|
48
|
+
export declare function deliveryTimeZoneName(timezone: string, style?: 'short' | 'long'): string;
|
|
49
|
+
export declare function deliveryTimeLabel(slot: DeliverySlot, timezone: string): string;
|
|
50
|
+
export declare function deliveryWindowLabel(slot: DeliverySlot, timezone: string): string;
|
|
51
|
+
export declare function deliveryScheduledLabel(slot: DeliverySlot, timezone: string): string;
|
|
52
|
+
export declare function deliveryCutoffLabel(slot: DeliverySlot, timezone: string): string;
|
|
53
|
+
export interface PlacedDeliveryLine {
|
|
54
|
+
heading: string;
|
|
55
|
+
label: string;
|
|
56
|
+
}
|
|
57
|
+
export interface PlacedDelivery {
|
|
58
|
+
perGroup: boolean;
|
|
59
|
+
lines: PlacedDeliveryLine[];
|
|
60
|
+
}
|
|
61
|
+
export declare function placedDeliveryLines(fulfillments: Record<string, ICheckoutFulfillment> | null | undefined, retailers: Record<string, ICheckoutRetailer> | null | undefined, items?: Record<string, ICheckoutItem> | null): PlacedDelivery;
|
|
62
|
+
type FulfillmentAvailability = Pick<IFulfillment, 'hourStatus' | 'deliveryAvailability'>;
|
|
63
|
+
type SchedulingAvailability = Pick<IFulfillment, 'deliveryAvailability'>;
|
|
64
|
+
export declare function deliversNow(fulfillment: FulfillmentAvailability): boolean;
|
|
65
|
+
export declare function takesOrdersForLater(fulfillment: SchedulingAvailability, now?: number): boolean;
|
|
66
|
+
export declare function nextScheduledDeliverySlot(fulfillment: SchedulingAvailability, now?: number): DeliverySlot | null;
|
|
67
|
+
export declare function isDeliveryPurchasable(fulfillment: FulfillmentAvailability, now?: number): boolean;
|
|
68
|
+
export declare function isOnDemandUnpurchasable(type: FulfillmentType, fulfillment: FulfillmentAvailability): boolean;
|
|
69
|
+
export declare function preferredOnDemandFulfillment<T extends FulfillmentAvailability>(fulfillments: T[], now?: number): T | undefined;
|
|
70
|
+
export declare function nextArrivalLabel(fulfillment: SchedulingAvailability, now?: number): string | null;
|
|
71
|
+
export declare const DELIVERY_TEXT_LINE_BREAK = "\n";
|
|
72
|
+
export declare function scheduleDeliveryText(fulfillment: SchedulingAvailability, now?: number): string | null;
|
|
73
|
+
export declare function spokenDeliveryText(text: string): string;
|
|
74
|
+
export declare function resolveDeliverySlot(scheduling: CheckoutDeliveryScheduling | undefined, advertised: DeliverySlot, now?: number): DeliverySlot | null;
|
|
75
|
+
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;
|
package/docs/v1/README.md
CHANGED
|
@@ -52,6 +52,7 @@ Complete API documentation:
|
|
|
52
52
|
- **[Address Actions](./api/actions/address-actions.md)** - `actions.address.*`
|
|
53
53
|
- **[Cart Actions](./api/actions/cart-actions.md)** - `actions.cart.*`
|
|
54
54
|
- **[Checkout Actions](./api/actions/checkout-actions.md)** - `actions.checkout.*`
|
|
55
|
+
- **[Analytics Actions](./api/actions/analytics-actions.md)** - `actions.analytics.*`
|
|
55
56
|
|
|
56
57
|
### Architecture (To Be Done In Future Versions)
|
|
57
58
|
|
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
# Analytics Actions API
|
|
2
|
+
|
|
3
|
+
Analytics actions report shopper steps that **your own UI** renders to the same Google Tag Manager /
|
|
4
|
+
GA4 stream that Elements components report to. Use them when you build part of the shopping
|
|
5
|
+
experience yourself — a product page, an address picker, a cart — and use Elements for the rest,
|
|
6
|
+
typically the checkout. They are available on the full client (`actions.analytics.*`) and on the
|
|
7
|
+
checkout-only client (`ElementsCheckout(...).actions.analytics.*`).
|
|
8
|
+
|
|
9
|
+
Each action pushes a GA4 event onto `window.dataLayer` in exactly the shape the SDK's own components
|
|
10
|
+
use — the same event name, the same `items[]` fields, the same `tenant_*` source fields and
|
|
11
|
+
`send_to` targets — so your reports and GTM triggers treat them like any other Elements event. See
|
|
12
|
+
[Analytics & Google Tag Manager](../../reference/analytics.md) for how the containers are loaded and
|
|
13
|
+
how events are queued.
|
|
14
|
+
|
|
15
|
+
## What to report, and what not to
|
|
16
|
+
|
|
17
|
+
- **Report only steps your UI renders.** A step an Elements component renders is already reported
|
|
18
|
+
by that component: reporting it again counts it twice. A product shown with `injectProductElement`
|
|
19
|
+
sends its own `view_item`, and adding it to the cart from that component sends `add_to_cart` and
|
|
20
|
+
`view_cart`. A list placed with `injectProductList` sends `view_item_list`, `select_item` and, from
|
|
21
|
+
its search box, `search`. The Elements cart sends `view_cart` when it opens and `remove_from_cart`
|
|
22
|
+
when an item goes.
|
|
23
|
+
- **The checkout reports itself.** `add_shipping_info`, `add_payment_info`, `purchase`, and the promo
|
|
24
|
+
code and gift card events come from the Elements checkout, so there are no actions for them.
|
|
25
|
+
- **Report once per state, not once per render.** A framework that re-renders, or runs effects
|
|
26
|
+
twice in development, should guard each report with the state it describes (for example the
|
|
27
|
+
product and size a `view_item` was sent for).
|
|
28
|
+
- **Where events go.** Events are sent only in `production` and `staging`, never in Builder mode.
|
|
29
|
+
They target the partner's enabled LiquidCommerce and partner GTM containers through `send_to`.
|
|
30
|
+
When neither container is enabled, an event still goes onto a `window.dataLayer` that is already on
|
|
31
|
+
the page — your own GTM's, for example — without `send_to`, exactly as the SDK's own events do.
|
|
32
|
+
Events reported before GTM finishes initializing are queued and sent once it is ready.
|
|
33
|
+
- **Reporting never breaks your page.** Malformed input does not throw: the event is skipped and a
|
|
34
|
+
warning is logged (visible with `debugMode: 'console'`, and sent to LiquidCommerce telemetry).
|
|
35
|
+
|
|
36
|
+
## The item
|
|
37
|
+
|
|
38
|
+
Every ecommerce action takes `IAnalyticsItem`, built from the product data your page already has:
|
|
39
|
+
|
|
40
|
+
```typescript
|
|
41
|
+
interface IAnalyticsItem {
|
|
42
|
+
id: string; // the selected size's id → item_id and product_id
|
|
43
|
+
name: string; // → item_name
|
|
44
|
+
brand?: string;
|
|
45
|
+
size?: string; // "750 ML"
|
|
46
|
+
categoryPath?: string; // product catPath, "spirits > whiskey > bourbon" → item_category 1–3
|
|
47
|
+
price?: number; // unit price in CENTS, as product responses carry it → dollars
|
|
48
|
+
quantity?: number;
|
|
49
|
+
type?: string;
|
|
50
|
+
subType?: string;
|
|
51
|
+
image?: string;
|
|
52
|
+
upc?: string;
|
|
53
|
+
groupingId?: string; // product salsifyGrouping
|
|
54
|
+
index?: number; // position in a list (viewItemList / selectItem)
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
From a product response (`getProductAvailabilityByState`, or the availability API your page loads
|
|
59
|
+
the product with):
|
|
60
|
+
|
|
61
|
+
```javascript
|
|
62
|
+
const product = response.products[0];
|
|
63
|
+
const size = product.sizes[selectedSizeId];
|
|
64
|
+
|
|
65
|
+
const item = {
|
|
66
|
+
id: size.id,
|
|
67
|
+
name: product.name,
|
|
68
|
+
brand: product.brand,
|
|
69
|
+
size: size.size,
|
|
70
|
+
categoryPath: product.catPath,
|
|
71
|
+
price: selectedVariant ? selectedVariant.price : product.priceInfo.average,
|
|
72
|
+
type: product.type,
|
|
73
|
+
subType: product.subType,
|
|
74
|
+
image: size.image,
|
|
75
|
+
upc: size.upc,
|
|
76
|
+
groupingId: product.salsifyGrouping,
|
|
77
|
+
};
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
`price` is in cents and is sent in dollars, like every Elements ecommerce event. Before the shopper
|
|
81
|
+
has an address, the SDK's own product component reports the product's average price; report the
|
|
82
|
+
selected variant's price once there is one.
|
|
83
|
+
|
|
84
|
+
An event is skipped, with a warning naming the problem, when an item has no `id` or `name`, a
|
|
85
|
+
negative or non-numeric `price`, a `quantity` that is not a positive integer, an `index` that is not
|
|
86
|
+
a non-negative integer, or a non-string text field; when a list of items is empty; when a list, an
|
|
87
|
+
option, an address field or coordinates have the wrong type; or when a `reason` / `error` is missing.
|
|
88
|
+
An omitted or empty `placesId` / `formattedAddress` is left out of the event rather than sent blank.
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## actions.analytics.search()
|
|
93
|
+
|
|
94
|
+
`search` — the shopper searches the catalog with your own search box. Sent as `search_term`, trimmed.
|
|
95
|
+
A product list's own search box reports its searches itself.
|
|
96
|
+
|
|
97
|
+
```typescript
|
|
98
|
+
search(searchTerm: string): void
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
```javascript
|
|
102
|
+
actions.analytics.search(input.value);
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## actions.analytics.viewItem()
|
|
108
|
+
|
|
109
|
+
`view_item` — the shopper sees a product. Report it when the product is shown and again when the
|
|
110
|
+
shopper switches size, as the SDK's product component does.
|
|
111
|
+
|
|
112
|
+
```typescript
|
|
113
|
+
viewItem(item: IAnalyticsItem): void
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
```javascript
|
|
117
|
+
actions.analytics.viewItem(item);
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## actions.analytics.viewItemList()
|
|
123
|
+
|
|
124
|
+
`view_item_list` — the shopper sees a list of products.
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
viewItemList(items: IAnalyticsItem[], list?: { id?: string; name?: string }): void
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
```javascript
|
|
131
|
+
actions.analytics.viewItemList(
|
|
132
|
+
products.map((item, index) => ({ ...item, index })),
|
|
133
|
+
{ id: 'holiday-gifts', name: 'Holiday Gifts' }
|
|
134
|
+
);
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
## actions.analytics.selectItem()
|
|
140
|
+
|
|
141
|
+
`select_item` — the shopper picks a product from a list.
|
|
142
|
+
|
|
143
|
+
```typescript
|
|
144
|
+
selectItem(item: IAnalyticsItem, list?: { id?: string; name?: string }): void
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## actions.analytics.addToCart()
|
|
150
|
+
|
|
151
|
+
`add_to_cart` — `item.quantity` is the quantity added (default 1). `value` is `price × quantity`.
|
|
152
|
+
|
|
153
|
+
```typescript
|
|
154
|
+
addToCart(item: IAnalyticsItem): void
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Report it when the shopper commits to the product in your UI. `actions.cart.addProduct()` and
|
|
158
|
+
`actions.checkout.addProduct()` already report it (the latter reports `begin_checkout` too); `actions.checkout.addAnonymousProduct()` does
|
|
159
|
+
not, because hosts often call it ahead of time to prepare a checkout before the shopper commits.
|
|
160
|
+
|
|
161
|
+
```javascript
|
|
162
|
+
actions.analytics.addToCart({ ...item, quantity: 2 });
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
## actions.analytics.removeFromCart()
|
|
168
|
+
|
|
169
|
+
`remove_from_cart` — `item.quantity` is the quantity removed.
|
|
170
|
+
|
|
171
|
+
```typescript
|
|
172
|
+
removeFromCart(item: IAnalyticsItem): void
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## actions.analytics.viewCart()
|
|
178
|
+
|
|
179
|
+
`view_cart` — the shopper sees a cart your UI renders.
|
|
180
|
+
|
|
181
|
+
```typescript
|
|
182
|
+
viewCart(items: IAnalyticsItem[]): void
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
## actions.analytics.beginCheckout()
|
|
188
|
+
|
|
189
|
+
`begin_checkout` — the shopper commits to buying `items`. `value` is the sum of `price × quantity`.
|
|
190
|
+
|
|
191
|
+
```typescript
|
|
192
|
+
beginCheckout(items: IAnalyticsItem[], options?: { coupon?: string }): void
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
```javascript
|
|
196
|
+
// "Proceed to checkout" in your own UI, before injecting the Elements checkout
|
|
197
|
+
actions.analytics.addToCart({ ...item, quantity });
|
|
198
|
+
actions.analytics.beginCheckout([{ ...item, quantity }], { coupon: 'WELCOME10' });
|
|
199
|
+
await client.injectCheckout({ containerId: 'checkout', checkoutId });
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
Report it when **you** inject the checkout (`injectCheckout()` / `injectCheckoutElement()`) after
|
|
203
|
+
your own "Proceed" control. Don't report it when Elements started the checkout — it reports these
|
|
204
|
+
itself:
|
|
205
|
+
|
|
206
|
+
- the Elements cart's Checkout button, including when it redirects to your checkout page
|
|
207
|
+
(`checkout.pageUrl`) — so a page that injects the checkout for a shopper arriving from that
|
|
208
|
+
button must not report it again;
|
|
209
|
+
- `actions.checkout.addProduct()`;
|
|
210
|
+
- `actions.checkout.openCheckout()` and `toggleCheckout()` when they open the drawer;
|
|
211
|
+
- a presale added from the product component, which goes straight to checkout;
|
|
212
|
+
- the first wallet tap on express buttons placed on their own (below).
|
|
213
|
+
|
|
214
|
+
Wallet (Apple Pay / Google Pay) buttons placed on their own with `injectExpressCheckout` /
|
|
215
|
+
`injectExpressCheckoutElement` report `begin_checkout` themselves on the first tap — a wallet order
|
|
216
|
+
never passes through your "Proceed" control. Don't report it for them. If the buttons sit on your
|
|
217
|
+
product page and the checkout behind them was created with `addAnonymousProduct`, report the add
|
|
218
|
+
when the shopper taps: the tap happens inside Stripe's frame, and
|
|
219
|
+
[`lce:actions.checkout_express_checkout_started`](../../guides/events.md) is how your page hears of
|
|
220
|
+
it.
|
|
221
|
+
|
|
222
|
+
```javascript
|
|
223
|
+
window.addEventListener('lce:actions.checkout_express_checkout_started', () => {
|
|
224
|
+
actions.analytics.addToCart({ ...item, quantity });
|
|
225
|
+
});
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
---
|
|
229
|
+
|
|
230
|
+
## actions.analytics.addressUpdated()
|
|
231
|
+
|
|
232
|
+
`address_updated` — an address the shopper chose in your UI resolved.
|
|
233
|
+
|
|
234
|
+
```typescript
|
|
235
|
+
addressUpdated(address: {
|
|
236
|
+
placesId?: string; // → address_id
|
|
237
|
+
formattedAddress?: string;
|
|
238
|
+
address: Partial<IAddressAddress>;
|
|
239
|
+
coordinates?: IAddressCoordinates;
|
|
240
|
+
}): void
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
```javascript
|
|
244
|
+
actions.analytics.addressUpdated({
|
|
245
|
+
placesId,
|
|
246
|
+
formattedAddress: details.formattedAddress,
|
|
247
|
+
address: details.address,
|
|
248
|
+
coordinates: details.coordinates,
|
|
249
|
+
});
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
`actions.address.setAddressByPlacesId()` and `setAddressManually()` already report it.
|
|
253
|
+
|
|
254
|
+
---
|
|
255
|
+
|
|
256
|
+
## actions.analytics.addressFailed()
|
|
257
|
+
|
|
258
|
+
`address_failed` — an address the shopper chose could not be resolved or used.
|
|
259
|
+
|
|
260
|
+
```typescript
|
|
261
|
+
addressFailed(failure: {
|
|
262
|
+
placesId?: string;
|
|
263
|
+
formattedAddress?: string;
|
|
264
|
+
address?: Partial<IAddressAddress>;
|
|
265
|
+
error: string; // → address_error_message
|
|
266
|
+
}): void
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
---
|
|
270
|
+
|
|
271
|
+
## actions.analytics.productNoAvailability()
|
|
272
|
+
|
|
273
|
+
`product_no_availability` — no size of the product sells where the shopper is.
|
|
274
|
+
|
|
275
|
+
```typescript
|
|
276
|
+
productNoAvailability(details: {
|
|
277
|
+
item: IAnalyticsItem; // the product, keyed on the selected size
|
|
278
|
+
reason: string; // → availability_reason
|
|
279
|
+
address?: Partial<IAddressAddress>;
|
|
280
|
+
}): void
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
The no-availability events carry `product_*` fields rather than an `items[]` array, as the SDK's own
|
|
284
|
+
do, and `product_price` is sent **in cents** (the raw `item.price`), matching them.
|
|
285
|
+
|
|
286
|
+
---
|
|
287
|
+
|
|
288
|
+
## actions.analytics.productSizeNoAvailability()
|
|
289
|
+
|
|
290
|
+
`product_size_no_availability` — the selected size has no fulfillment at the shopper's address,
|
|
291
|
+
though another size does. `item.id` and `item.size` are sent as `size_id` and `size_name`.
|
|
292
|
+
|
|
293
|
+
```typescript
|
|
294
|
+
productSizeNoAvailability(details: { item: IAnalyticsItem; reason: string; address?: Partial<IAddressAddress> }): void
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
---
|
|
298
|
+
|
|
299
|
+
## actions.analytics.productFulfillmentNoAvailability()
|
|
300
|
+
|
|
301
|
+
`product_fulfillment_no_availability` — one fulfillment method (`onDemand` or `shipping`) can't be
|
|
302
|
+
used for the selected size: not offered there, or the retailer is closed.
|
|
303
|
+
|
|
304
|
+
```typescript
|
|
305
|
+
productFulfillmentNoAvailability(details: {
|
|
306
|
+
item: IAnalyticsItem;
|
|
307
|
+
reason: string;
|
|
308
|
+
address?: Partial<IAddressAddress>;
|
|
309
|
+
fulfillmentType: 'onDemand' | 'shipping';
|
|
310
|
+
}): void
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
```javascript
|
|
314
|
+
actions.analytics.productFulfillmentNoAvailability({
|
|
315
|
+
item,
|
|
316
|
+
reason: 'Not available in NY',
|
|
317
|
+
address: details.address,
|
|
318
|
+
fulfillmentType: 'onDemand',
|
|
319
|
+
});
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
## Related
|
|
323
|
+
|
|
324
|
+
- [Analytics & Google Tag Manager](../../reference/analytics.md)
|
|
325
|
+
- [Product Actions](./product-actions.md) · [Address Actions](./address-actions.md) · [Cart Actions](./cart-actions.md) · [Checkout Actions](./checkout-actions.md)
|
|
326
|
+
- [TypeScript Types](../typescript-types.md)
|
|
@@ -12,7 +12,8 @@ Checkout actions allow you to programmatically control the checkout flow.
|
|
|
12
12
|
openCheckout(): void
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
-
Opens the checkout drawer or navigates to checkout page.
|
|
15
|
+
Opens the checkout drawer or navigates to checkout page. Reports `begin_checkout` for the cart's items
|
|
16
|
+
to GTM, as the cart's own Checkout button does, unless the drawer already shows the checkout.
|
|
16
17
|
|
|
17
18
|
```javascript
|
|
18
19
|
window.LiquidCommerce.elements.actions.checkout.openCheckout();
|
|
@@ -36,7 +37,7 @@ window.LiquidCommerce.elements.actions.checkout.closeCheckout();
|
|
|
36
37
|
toggleCheckout(): void
|
|
37
38
|
```
|
|
38
39
|
|
|
39
|
-
Toggles checkout open/closed.
|
|
40
|
+
Toggles checkout open/closed. Opening it reports `begin_checkout`, as `openCheckout()` does.
|
|
40
41
|
|
|
41
42
|
```javascript
|
|
42
43
|
window.LiquidCommerce.elements.actions.checkout.toggleCheckout();
|
|
@@ -64,6 +65,8 @@ addProduct(params: IAddProductParams[], openCheckout?: boolean): Promise<void>
|
|
|
64
65
|
|
|
65
66
|
Add products and open checkout in one call. Products are added to the cart (via the cart action, or directly when none is wired up), then checkout is prepared and opened. For a checkout without a cart session, use `addAnonymousProduct`.
|
|
66
67
|
|
|
68
|
+
Reports `add_to_cart` for the added products and then `begin_checkout` for the cart to GTM, so don't report either again with [`actions.analytics`](./analytics-actions.md).
|
|
69
|
+
|
|
67
70
|
`IAddProductParams.engravingLines?: string[]` — optional engraving. Same rules as [`actions.cart.addProduct()`](./cart-actions.md#actionscartaddproduct): invalid input is ignored, blanks stripped, lines clamped to the product's `maxLines` / `maxCharsPerLine`, and engraving is dropped (without failing) when the product, variant, or fulfillment doesn't support it.
|
|
68
71
|
|
|
69
72
|
```javascript
|
|
@@ -402,6 +405,7 @@ console.log(`Is Gift: ${checkout.isGift}`);
|
|
|
402
405
|
|
|
403
406
|
```typescript
|
|
404
407
|
interface ICheckoutDetailsEventData {
|
|
408
|
+
deliveryScheduling: Record<string, CheckoutDeliveryScheduling>; // keyed by fulfillment ID; empty without scheduled delivery
|
|
405
409
|
token: string;
|
|
406
410
|
cartId: string;
|
|
407
411
|
isGift: boolean;
|
|
@@ -439,6 +443,47 @@ const availability = await window.LiquidCommerce.elements.actions.checkout
|
|
|
439
443
|
| `identifiers` | string[] | Yes | Array of product UPCs, SKUs, or IDs |
|
|
440
444
|
| `state` | string | No | Two-letter state code (e.g., `'NY'`) |
|
|
441
445
|
|
|
446
|
+
## Delivery scheduling actions
|
|
447
|
+
|
|
448
|
+
Available on both `Elements()` and `ElementsCheckout()` when a checkout fulfillment carries `deliveryScheduling` (an AccelPay retailer with scheduled delivery turned on). Checkouts without it keep their usual behaviour, and `getDetails().deliveryScheduling` is an empty map.
|
|
449
|
+
|
|
450
|
+
### `actions.checkout.loadDeliverySlots(fulfillmentId)`
|
|
451
|
+
|
|
452
|
+
```typescript
|
|
453
|
+
loadDeliverySlots(fulfillmentId: string): Promise<DeliverySlot[]>
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
Loads the full list of delivery windows for one fulfillment. Checkout prepare returns the list only on request, so outside this call `deliveryScheduling.slots` is empty and `availability.nextSlot` names the first window. The call sends the whole current checkout to prepare, plus `deliverySlotsFulfillmentId`, and resolves with the windows that can still be ordered. Each window's `cutoff` is the latest time to place the order for it ("Order by"). Show times in `availability.timezone`.
|
|
457
|
+
|
|
458
|
+
### `actions.checkout.chooseDeliverySlot(fulfillmentId, slotId)`
|
|
459
|
+
|
|
460
|
+
```typescript
|
|
461
|
+
chooseDeliverySlot(fulfillmentId: string, slotId: string | null): Promise<void>
|
|
462
|
+
```
|
|
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 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
|
+
|
|
466
|
+
`getDetails().deliveryScheduling[fulfillmentId]` returns the availability, the accepted `selectedSlotId` and `selectedSlot` (the accepted window's `start`, `end` and `cutoff`).
|
|
467
|
+
|
|
468
|
+
```javascript
|
|
469
|
+
const actions = client.actions.checkout;
|
|
470
|
+
const [fulfillmentId] = Object.keys(actions.getDetails().deliveryScheduling);
|
|
471
|
+
if (fulfillmentId) {
|
|
472
|
+
const slots = await actions.loadDeliverySlots(fulfillmentId);
|
|
473
|
+
if (slots.length) await actions.chooseDeliverySlot(fulfillmentId, slots[0].id);
|
|
474
|
+
}
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
### Expired windows
|
|
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`. 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
|
+
|
|
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
|
+
|
|
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.
|
|
486
|
+
|
|
442
487
|
## Use Cases
|
|
443
488
|
|
|
444
489
|
### Pre-fill for Logged-In Users
|