@asteby/storefront-react 0.25.0 → 0.26.1
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 +35 -2
- package/dist/account-server.cjs +128 -19
- package/dist/account-server.cjs.map +1 -1
- package/dist/account-server.d.cts +67 -4
- package/dist/account-server.d.ts +67 -4
- package/dist/account-server.js +125 -20
- package/dist/account-server.js.map +1 -1
- package/dist/account.cjs +252 -7
- package/dist/account.cjs.map +1 -1
- package/dist/account.css +91 -0
- package/dist/account.d.cts +130 -6
- package/dist/account.d.ts +130 -6
- package/dist/account.js +247 -8
- package/dist/account.js.map +1 -1
- package/dist/checkout.cjs +162 -8
- package/dist/checkout.cjs.map +1 -1
- package/dist/checkout.d.cts +104 -4
- package/dist/checkout.d.ts +104 -4
- package/dist/checkout.js +158 -10
- package/dist/checkout.js.map +1 -1
- package/dist/chunk-Z4C4LKXF.js +25 -0
- package/dist/chunk-Z4C4LKXF.js.map +1 -0
- package/dist/fiscal-server.cjs +27 -2
- package/dist/fiscal-server.cjs.map +1 -1
- package/dist/fiscal-server.d.cts +10 -1
- package/dist/fiscal-server.d.ts +10 -1
- package/dist/fiscal-server.js +26 -3
- package/dist/fiscal-server.js.map +1 -1
- package/dist/fit-key-B9sYQVwG.d.cts +49 -0
- package/dist/fit-key-B9sYQVwG.d.ts +49 -0
- package/dist/fitment.cjs +54 -9
- package/dist/fitment.cjs.map +1 -1
- package/dist/fitment.d.cts +20 -2
- package/dist/fitment.d.ts +20 -2
- package/dist/fitment.js +54 -10
- package/dist/fitment.js.map +1 -1
- package/dist/settings-types-jxFQFFqP.d.cts +77 -0
- package/dist/settings-types-jxFQFFqP.d.ts +77 -0
- package/dist/subjects-server.cjs +248 -0
- package/dist/subjects-server.cjs.map +1 -0
- package/dist/subjects-server.d.cts +130 -0
- package/dist/subjects-server.d.ts +130 -0
- package/dist/subjects-server.js +217 -0
- package/dist/subjects-server.js.map +1 -0
- package/dist/subjects.cjs +501 -0
- package/dist/subjects.cjs.map +1 -0
- package/dist/subjects.css +166 -0
- package/dist/subjects.d.cts +178 -0
- package/dist/subjects.d.ts +178 -0
- package/dist/subjects.js +465 -0
- package/dist/subjects.js.map +1 -0
- package/package.json +23 -2
- package/dist/types-D7pVK0GK.d.cts +0 -39
- package/dist/types-D7pVK0GK.d.ts +0 -39
package/dist/checkout.d.cts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
|
-
import { ReactNode } from 'react';
|
|
3
|
-
import { Address, CartLine, CartCost, Money, ShippingRate, PickupOption } from '@asteby/storefront';
|
|
2
|
+
import { ReactNode, RefObject } from 'react';
|
|
3
|
+
import { Address, CartLine, CartCost, Money, ShippingRate, PickupOption, DeliveryOptions as DeliveryOptions$1 } from '@asteby/storefront';
|
|
4
4
|
import { F as FieldErrors, g as FieldMessages, a as CheckoutFieldClassNames } from './fields-vnMUi2HB.cjs';
|
|
5
5
|
export { C as CheckoutField, b as CheckoutFieldProps, c as CheckoutSelectProps, E as ErrorSummary, d as ErrorSummaryItem, e as ErrorSummaryProps, f as FieldErrorsState, U as UseFieldErrorsOptions, h as fieldMessages, u as useFieldErrors, v as validationMessage } from './fields-vnMUi2HB.cjs';
|
|
6
6
|
|
|
@@ -290,6 +290,11 @@ type DeliveryMessages = {
|
|
|
290
290
|
/** The rates could not be quoted (`error`). */
|
|
291
291
|
error: string;
|
|
292
292
|
retry: string;
|
|
293
|
+
/** The order reaches the free-shipping minimum: nothing to choose. */
|
|
294
|
+
freeShipping: string;
|
|
295
|
+
freeShippingNote: string;
|
|
296
|
+
/** Screen-reader status when the rates are ready (`{n}` = how many). */
|
|
297
|
+
ratesReady: string;
|
|
293
298
|
};
|
|
294
299
|
/** Messages for a locale (`es*` default, `en*`), with optional overrides. */
|
|
295
300
|
declare function deliveryMessages(locale?: string | null, overrides?: Partial<DeliveryMessages> | null): DeliveryMessages;
|
|
@@ -342,7 +347,7 @@ declare function isQuoteChange(err: {
|
|
|
342
347
|
*/
|
|
343
348
|
declare function matchRate<R extends Pick<ShippingRate, 'id' | 'carrier' | 'service_code' | 'title'>>(previous: Pick<ShippingRate, 'carrier' | 'service_code' | 'title'> | null | undefined, rates: readonly R[]): R | null;
|
|
344
349
|
|
|
345
|
-
type DeliveryOptionsClassNames = Partial<Record<'root' | 'option' | 'radio' | 'mark' | 'body' | 'title' | 'carrier' | 'service' | 'eta' | 'badges' | 'badge' | 'price' | 'free' | 'note' | 'partial' | 'skeleton' | 'more' | 'moreSummary' | 'group' | 'groupTitle' | 'error' | 'retry', string>>;
|
|
350
|
+
type DeliveryOptionsClassNames = Partial<Record<'root' | 'option' | 'radio' | 'mark' | 'body' | 'title' | 'carrier' | 'service' | 'eta' | 'badges' | 'badge' | 'price' | 'free' | 'freeBanner' | 'note' | 'partial' | 'skeleton' | 'more' | 'moreSummary' | 'group' | 'groupTitle' | 'error' | 'retry', string>>;
|
|
346
351
|
type DeliveryOptionsProps = {
|
|
347
352
|
rates: readonly ShippingRate[];
|
|
348
353
|
pickup?: readonly PickupOption[];
|
|
@@ -363,6 +368,14 @@ type DeliveryOptionsProps = {
|
|
|
363
368
|
requoted?: boolean;
|
|
364
369
|
/** Rates are being quoted again: skeleton rows (no rates yet) or the current rows dimmed, `aria-busy`. */
|
|
365
370
|
loading?: boolean;
|
|
371
|
+
/**
|
|
372
|
+
* The order reaches the free-shipping minimum (`DeliveryOptions.free`, configured by the organization): no carrier
|
|
373
|
+
* selector, just "Free shipping" and the rate is submitted by itself so the buyer goes straight to payment.
|
|
374
|
+
* With pickup branches the plain rows stay (delivery or pickup is still a real choice).
|
|
375
|
+
*/
|
|
376
|
+
free?: boolean;
|
|
377
|
+
/** Rates just arrived by themselves (auto quote): a polite screen-reader status says how many. */
|
|
378
|
+
announceReady?: boolean;
|
|
366
379
|
/** Quote deadline note: `always` (default), only when it is `soon`, or `never`. */
|
|
367
380
|
quoteNote?: 'always' | 'soon' | 'never';
|
|
368
381
|
/** Time zone of the note. Default: the buyer's browser. */
|
|
@@ -475,4 +488,91 @@ type FlatRatesOptions = {
|
|
|
475
488
|
*/
|
|
476
489
|
declare function flatRates<R extends ShippingRate>(input: readonly R[], options?: FlatRatesOptions): RecommendedRate<R>[];
|
|
477
490
|
|
|
478
|
-
|
|
491
|
+
/**
|
|
492
|
+
* One-step delivery: as soon as the address is complete the shipping rates load by themselves (debounced), the default
|
|
493
|
+
* rate is preselected and payment is ready. No "continue" button, no choosing again.
|
|
494
|
+
*
|
|
495
|
+
* The hook is transport-agnostic: the shop gives `quote(address)` (save the address in the cart, read the delivery
|
|
496
|
+
* options) and renders the result with `<DeliveryOptions>`. Only the fields that change the price re-quote (country,
|
|
497
|
+
* postal code, state, city): editing the street number, the phone or the reference does not. Free shipping and fixed
|
|
498
|
+
* prices come from the server (`DeliveryOptions.free` / `.fixed`, configured per organization): nothing here knows an
|
|
499
|
+
* amount.
|
|
500
|
+
*/
|
|
501
|
+
|
|
502
|
+
/** What the shop reads from the address fields of the form. Keys follow the `name` of each input. */
|
|
503
|
+
type QuoteAddress = {
|
|
504
|
+
country_code: string;
|
|
505
|
+
zip: string;
|
|
506
|
+
province: string;
|
|
507
|
+
city: string;
|
|
508
|
+
neighborhood: string;
|
|
509
|
+
address1: string;
|
|
510
|
+
[key: string]: string;
|
|
511
|
+
};
|
|
512
|
+
type AutoQuoteStatus =
|
|
513
|
+
/** Address incomplete: nothing is quoted yet. */
|
|
514
|
+
'idle'
|
|
515
|
+
/** Complete address, waiting for the buyer to stop typing. */
|
|
516
|
+
| 'waiting' | 'loading' | 'ready' | 'error';
|
|
517
|
+
type UseAutoQuoteOptions = {
|
|
518
|
+
/** The form that holds the address inputs (events are listened to on it). */
|
|
519
|
+
formRef: RefObject<HTMLFormElement | null>;
|
|
520
|
+
/**
|
|
521
|
+
* Saves the address and returns the delivery options for it. Receives an `AbortSignal` that fires when a newer
|
|
522
|
+
* quote replaces this one: ignore its result then (the hook already does).
|
|
523
|
+
*
|
|
524
|
+
* Only price fields re-quote, so the address saved here can lag behind the form (street, number, reference): the
|
|
525
|
+
* shop's submit must save the full address again before choosing the delivery and paying. The server validates the
|
|
526
|
+
* chosen rate against the saved address (a rate of another postal code is refused), so a stale quote never sets a price.
|
|
527
|
+
*/
|
|
528
|
+
quote: (address: QuoteAddress, signal: AbortSignal) => Promise<DeliveryOptions$1>;
|
|
529
|
+
/** `name` of each address input. Default: `country_code`, `zip`, `province`, `city`, `neighborhood`, `address1`. */
|
|
530
|
+
names?: Partial<Record<'country_code' | 'zip' | 'province' | 'city' | 'neighborhood' | 'address1', string>>;
|
|
531
|
+
/** Fields that must be filled to quote. Default: all of the six names above except `country_code`. */
|
|
532
|
+
required?: ReadonlyArray<keyof QuoteAddress>;
|
|
533
|
+
/** A postal code is valid to quote. Default: 5 digits. */
|
|
534
|
+
validPostalCode?: (zip: string) => boolean;
|
|
535
|
+
/** Country used when the form has no country input. Default `MX`. */
|
|
536
|
+
defaultCountry?: string;
|
|
537
|
+
/** Quiet time after the last keystroke. Default 600 ms. */
|
|
538
|
+
debounceMs?: number;
|
|
539
|
+
/** Picks the preselected rate. Default: {@link defaultRate} (the cheapest). */
|
|
540
|
+
pickDefault?: (delivery: DeliveryOptions$1) => ShippingRate | null;
|
|
541
|
+
/** The rate (`rate:<id>`) already saved in the cart: kept when the quote still offers it. */
|
|
542
|
+
savedValue?: string | null;
|
|
543
|
+
enabled?: boolean;
|
|
544
|
+
/** Fires with the options of every successful quote. */
|
|
545
|
+
onQuoted?: (delivery: DeliveryOptions$1) => void;
|
|
546
|
+
};
|
|
547
|
+
type UseAutoQuoteResult = {
|
|
548
|
+
status: AutoQuoteStatus;
|
|
549
|
+
/** The last good quote (kept while a new one loads, so the list does not flash). `null` before the first. */
|
|
550
|
+
delivery: DeliveryOptions$1 | null;
|
|
551
|
+
/** `rate:<id>` to preselect (the saved rate if still offered, else the default), `null` when none. */
|
|
552
|
+
defaultValue: string | null;
|
|
553
|
+
/** The address the current `delivery` was quoted for. */
|
|
554
|
+
quotedFor: QuoteAddress | null;
|
|
555
|
+
/** Quote again now (retry button). */
|
|
556
|
+
retry: () => void;
|
|
557
|
+
/** Plain-language status for a live region ("Buscando…", "Listo", …) keys, not text. */
|
|
558
|
+
announce: 'searching' | 'ready' | 'free' | 'error' | null;
|
|
559
|
+
};
|
|
560
|
+
declare const DEFAULT_QUOTE_NAMES: {
|
|
561
|
+
readonly country_code: "country_code";
|
|
562
|
+
readonly zip: "zip";
|
|
563
|
+
readonly province: "province";
|
|
564
|
+
readonly city: "city";
|
|
565
|
+
readonly neighborhood: "neighborhood";
|
|
566
|
+
readonly address1: "address1";
|
|
567
|
+
};
|
|
568
|
+
/** Only these change the price of a shipment; any other field of the form (street, phone, reference…) never re-quotes. */
|
|
569
|
+
declare const QUOTE_KEYS: readonly ["country_code", "zip", "province", "city"];
|
|
570
|
+
/** Identity of a quote: equal fingerprints share the same rates. */
|
|
571
|
+
declare function quoteFingerprint(a: Pick<QuoteAddress, (typeof QUOTE_KEYS)[number]>): string;
|
|
572
|
+
/** The default rate: the cheapest one that is not a pickup (ties keep the server order, which already puts the best first). */
|
|
573
|
+
declare function defaultRate(delivery: Pick<DeliveryOptions$1, 'rates'>): ShippingRate | null;
|
|
574
|
+
/** Reads the address from the form; `null` when it is not complete yet. */
|
|
575
|
+
declare function readQuoteAddress(form: HTMLFormElement | null, opts?: Pick<UseAutoQuoteOptions, 'names' | 'required' | 'validPostalCode' | 'defaultCountry'>): QuoteAddress | null;
|
|
576
|
+
declare function useAutoQuote(options: UseAutoQuoteOptions): UseAutoQuoteResult;
|
|
577
|
+
|
|
578
|
+
export { ADDRESS_FILL_EVENT_FLAG, type AddressFieldKey, AddressFields, type AddressFieldsMessages, type AddressFieldsProps, type AutoQuoteStatus, type Brand, type BrandKind, BrandMark, type BrandMarkProps, type BrandMarkSource, CheckoutFieldClassNames, type ContactFieldKey, ContactFields, type ContactFieldsProps, DEFAULT_QUOTE_NAMES, type DeliveryMessages, DeliveryOptions, type DeliveryOptionsClassNames, type DeliveryOptionsProps, FieldErrors, type FieldLayoutClassNames, FieldMessages, type FlatRatesOptions, OrderSummary, type OrderSummaryClassNames, OrderSummaryDisclosure, type OrderSummaryDisclosureProps, type OrderSummaryMessages, type OrderSummaryProps, type PostalCodeInfo, QUOTE_KEYS, type QuoteAddress, type QuoteNote, type RateBadge, type RateGroup, type RateTag, type RecommendRatesOptions, type RecommendedRate, type RecommendedRates, type UseAutoQuoteOptions, type UseAutoQuoteResult, addressFieldsMessages, brandKey, brandLogo, brandName, dedupeRates, defaultRate, deliveryMessages, findBrand, flatRates, isAddressFillEvent, isQuoteChange, listBrands, matchRate, orderSummaryMessages, quoteDeadline, quoteFingerprint, quoteNote, rateBadges, rateCarrier, rateEta, rateService, readQuoteAddress, recommendRates, useAutoQuote };
|
package/dist/checkout.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
|
-
import { ReactNode } from 'react';
|
|
3
|
-
import { Address, CartLine, CartCost, Money, ShippingRate, PickupOption } from '@asteby/storefront';
|
|
2
|
+
import { ReactNode, RefObject } from 'react';
|
|
3
|
+
import { Address, CartLine, CartCost, Money, ShippingRate, PickupOption, DeliveryOptions as DeliveryOptions$1 } from '@asteby/storefront';
|
|
4
4
|
import { F as FieldErrors, g as FieldMessages, a as CheckoutFieldClassNames } from './fields-vnMUi2HB.js';
|
|
5
5
|
export { C as CheckoutField, b as CheckoutFieldProps, c as CheckoutSelectProps, E as ErrorSummary, d as ErrorSummaryItem, e as ErrorSummaryProps, f as FieldErrorsState, U as UseFieldErrorsOptions, h as fieldMessages, u as useFieldErrors, v as validationMessage } from './fields-vnMUi2HB.js';
|
|
6
6
|
|
|
@@ -290,6 +290,11 @@ type DeliveryMessages = {
|
|
|
290
290
|
/** The rates could not be quoted (`error`). */
|
|
291
291
|
error: string;
|
|
292
292
|
retry: string;
|
|
293
|
+
/** The order reaches the free-shipping minimum: nothing to choose. */
|
|
294
|
+
freeShipping: string;
|
|
295
|
+
freeShippingNote: string;
|
|
296
|
+
/** Screen-reader status when the rates are ready (`{n}` = how many). */
|
|
297
|
+
ratesReady: string;
|
|
293
298
|
};
|
|
294
299
|
/** Messages for a locale (`es*` default, `en*`), with optional overrides. */
|
|
295
300
|
declare function deliveryMessages(locale?: string | null, overrides?: Partial<DeliveryMessages> | null): DeliveryMessages;
|
|
@@ -342,7 +347,7 @@ declare function isQuoteChange(err: {
|
|
|
342
347
|
*/
|
|
343
348
|
declare function matchRate<R extends Pick<ShippingRate, 'id' | 'carrier' | 'service_code' | 'title'>>(previous: Pick<ShippingRate, 'carrier' | 'service_code' | 'title'> | null | undefined, rates: readonly R[]): R | null;
|
|
344
349
|
|
|
345
|
-
type DeliveryOptionsClassNames = Partial<Record<'root' | 'option' | 'radio' | 'mark' | 'body' | 'title' | 'carrier' | 'service' | 'eta' | 'badges' | 'badge' | 'price' | 'free' | 'note' | 'partial' | 'skeleton' | 'more' | 'moreSummary' | 'group' | 'groupTitle' | 'error' | 'retry', string>>;
|
|
350
|
+
type DeliveryOptionsClassNames = Partial<Record<'root' | 'option' | 'radio' | 'mark' | 'body' | 'title' | 'carrier' | 'service' | 'eta' | 'badges' | 'badge' | 'price' | 'free' | 'freeBanner' | 'note' | 'partial' | 'skeleton' | 'more' | 'moreSummary' | 'group' | 'groupTitle' | 'error' | 'retry', string>>;
|
|
346
351
|
type DeliveryOptionsProps = {
|
|
347
352
|
rates: readonly ShippingRate[];
|
|
348
353
|
pickup?: readonly PickupOption[];
|
|
@@ -363,6 +368,14 @@ type DeliveryOptionsProps = {
|
|
|
363
368
|
requoted?: boolean;
|
|
364
369
|
/** Rates are being quoted again: skeleton rows (no rates yet) or the current rows dimmed, `aria-busy`. */
|
|
365
370
|
loading?: boolean;
|
|
371
|
+
/**
|
|
372
|
+
* The order reaches the free-shipping minimum (`DeliveryOptions.free`, configured by the organization): no carrier
|
|
373
|
+
* selector, just "Free shipping" and the rate is submitted by itself so the buyer goes straight to payment.
|
|
374
|
+
* With pickup branches the plain rows stay (delivery or pickup is still a real choice).
|
|
375
|
+
*/
|
|
376
|
+
free?: boolean;
|
|
377
|
+
/** Rates just arrived by themselves (auto quote): a polite screen-reader status says how many. */
|
|
378
|
+
announceReady?: boolean;
|
|
366
379
|
/** Quote deadline note: `always` (default), only when it is `soon`, or `never`. */
|
|
367
380
|
quoteNote?: 'always' | 'soon' | 'never';
|
|
368
381
|
/** Time zone of the note. Default: the buyer's browser. */
|
|
@@ -475,4 +488,91 @@ type FlatRatesOptions = {
|
|
|
475
488
|
*/
|
|
476
489
|
declare function flatRates<R extends ShippingRate>(input: readonly R[], options?: FlatRatesOptions): RecommendedRate<R>[];
|
|
477
490
|
|
|
478
|
-
|
|
491
|
+
/**
|
|
492
|
+
* One-step delivery: as soon as the address is complete the shipping rates load by themselves (debounced), the default
|
|
493
|
+
* rate is preselected and payment is ready. No "continue" button, no choosing again.
|
|
494
|
+
*
|
|
495
|
+
* The hook is transport-agnostic: the shop gives `quote(address)` (save the address in the cart, read the delivery
|
|
496
|
+
* options) and renders the result with `<DeliveryOptions>`. Only the fields that change the price re-quote (country,
|
|
497
|
+
* postal code, state, city): editing the street number, the phone or the reference does not. Free shipping and fixed
|
|
498
|
+
* prices come from the server (`DeliveryOptions.free` / `.fixed`, configured per organization): nothing here knows an
|
|
499
|
+
* amount.
|
|
500
|
+
*/
|
|
501
|
+
|
|
502
|
+
/** What the shop reads from the address fields of the form. Keys follow the `name` of each input. */
|
|
503
|
+
type QuoteAddress = {
|
|
504
|
+
country_code: string;
|
|
505
|
+
zip: string;
|
|
506
|
+
province: string;
|
|
507
|
+
city: string;
|
|
508
|
+
neighborhood: string;
|
|
509
|
+
address1: string;
|
|
510
|
+
[key: string]: string;
|
|
511
|
+
};
|
|
512
|
+
type AutoQuoteStatus =
|
|
513
|
+
/** Address incomplete: nothing is quoted yet. */
|
|
514
|
+
'idle'
|
|
515
|
+
/** Complete address, waiting for the buyer to stop typing. */
|
|
516
|
+
| 'waiting' | 'loading' | 'ready' | 'error';
|
|
517
|
+
type UseAutoQuoteOptions = {
|
|
518
|
+
/** The form that holds the address inputs (events are listened to on it). */
|
|
519
|
+
formRef: RefObject<HTMLFormElement | null>;
|
|
520
|
+
/**
|
|
521
|
+
* Saves the address and returns the delivery options for it. Receives an `AbortSignal` that fires when a newer
|
|
522
|
+
* quote replaces this one: ignore its result then (the hook already does).
|
|
523
|
+
*
|
|
524
|
+
* Only price fields re-quote, so the address saved here can lag behind the form (street, number, reference): the
|
|
525
|
+
* shop's submit must save the full address again before choosing the delivery and paying. The server validates the
|
|
526
|
+
* chosen rate against the saved address (a rate of another postal code is refused), so a stale quote never sets a price.
|
|
527
|
+
*/
|
|
528
|
+
quote: (address: QuoteAddress, signal: AbortSignal) => Promise<DeliveryOptions$1>;
|
|
529
|
+
/** `name` of each address input. Default: `country_code`, `zip`, `province`, `city`, `neighborhood`, `address1`. */
|
|
530
|
+
names?: Partial<Record<'country_code' | 'zip' | 'province' | 'city' | 'neighborhood' | 'address1', string>>;
|
|
531
|
+
/** Fields that must be filled to quote. Default: all of the six names above except `country_code`. */
|
|
532
|
+
required?: ReadonlyArray<keyof QuoteAddress>;
|
|
533
|
+
/** A postal code is valid to quote. Default: 5 digits. */
|
|
534
|
+
validPostalCode?: (zip: string) => boolean;
|
|
535
|
+
/** Country used when the form has no country input. Default `MX`. */
|
|
536
|
+
defaultCountry?: string;
|
|
537
|
+
/** Quiet time after the last keystroke. Default 600 ms. */
|
|
538
|
+
debounceMs?: number;
|
|
539
|
+
/** Picks the preselected rate. Default: {@link defaultRate} (the cheapest). */
|
|
540
|
+
pickDefault?: (delivery: DeliveryOptions$1) => ShippingRate | null;
|
|
541
|
+
/** The rate (`rate:<id>`) already saved in the cart: kept when the quote still offers it. */
|
|
542
|
+
savedValue?: string | null;
|
|
543
|
+
enabled?: boolean;
|
|
544
|
+
/** Fires with the options of every successful quote. */
|
|
545
|
+
onQuoted?: (delivery: DeliveryOptions$1) => void;
|
|
546
|
+
};
|
|
547
|
+
type UseAutoQuoteResult = {
|
|
548
|
+
status: AutoQuoteStatus;
|
|
549
|
+
/** The last good quote (kept while a new one loads, so the list does not flash). `null` before the first. */
|
|
550
|
+
delivery: DeliveryOptions$1 | null;
|
|
551
|
+
/** `rate:<id>` to preselect (the saved rate if still offered, else the default), `null` when none. */
|
|
552
|
+
defaultValue: string | null;
|
|
553
|
+
/** The address the current `delivery` was quoted for. */
|
|
554
|
+
quotedFor: QuoteAddress | null;
|
|
555
|
+
/** Quote again now (retry button). */
|
|
556
|
+
retry: () => void;
|
|
557
|
+
/** Plain-language status for a live region ("Buscando…", "Listo", …) keys, not text. */
|
|
558
|
+
announce: 'searching' | 'ready' | 'free' | 'error' | null;
|
|
559
|
+
};
|
|
560
|
+
declare const DEFAULT_QUOTE_NAMES: {
|
|
561
|
+
readonly country_code: "country_code";
|
|
562
|
+
readonly zip: "zip";
|
|
563
|
+
readonly province: "province";
|
|
564
|
+
readonly city: "city";
|
|
565
|
+
readonly neighborhood: "neighborhood";
|
|
566
|
+
readonly address1: "address1";
|
|
567
|
+
};
|
|
568
|
+
/** Only these change the price of a shipment; any other field of the form (street, phone, reference…) never re-quotes. */
|
|
569
|
+
declare const QUOTE_KEYS: readonly ["country_code", "zip", "province", "city"];
|
|
570
|
+
/** Identity of a quote: equal fingerprints share the same rates. */
|
|
571
|
+
declare function quoteFingerprint(a: Pick<QuoteAddress, (typeof QUOTE_KEYS)[number]>): string;
|
|
572
|
+
/** The default rate: the cheapest one that is not a pickup (ties keep the server order, which already puts the best first). */
|
|
573
|
+
declare function defaultRate(delivery: Pick<DeliveryOptions$1, 'rates'>): ShippingRate | null;
|
|
574
|
+
/** Reads the address from the form; `null` when it is not complete yet. */
|
|
575
|
+
declare function readQuoteAddress(form: HTMLFormElement | null, opts?: Pick<UseAutoQuoteOptions, 'names' | 'required' | 'validPostalCode' | 'defaultCountry'>): QuoteAddress | null;
|
|
576
|
+
declare function useAutoQuote(options: UseAutoQuoteOptions): UseAutoQuoteResult;
|
|
577
|
+
|
|
578
|
+
export { ADDRESS_FILL_EVENT_FLAG, type AddressFieldKey, AddressFields, type AddressFieldsMessages, type AddressFieldsProps, type AutoQuoteStatus, type Brand, type BrandKind, BrandMark, type BrandMarkProps, type BrandMarkSource, CheckoutFieldClassNames, type ContactFieldKey, ContactFields, type ContactFieldsProps, DEFAULT_QUOTE_NAMES, type DeliveryMessages, DeliveryOptions, type DeliveryOptionsClassNames, type DeliveryOptionsProps, FieldErrors, type FieldLayoutClassNames, FieldMessages, type FlatRatesOptions, OrderSummary, type OrderSummaryClassNames, OrderSummaryDisclosure, type OrderSummaryDisclosureProps, type OrderSummaryMessages, type OrderSummaryProps, type PostalCodeInfo, QUOTE_KEYS, type QuoteAddress, type QuoteNote, type RateBadge, type RateGroup, type RateTag, type RecommendRatesOptions, type RecommendedRate, type RecommendedRates, type UseAutoQuoteOptions, type UseAutoQuoteResult, addressFieldsMessages, brandKey, brandLogo, brandName, dedupeRates, defaultRate, deliveryMessages, findBrand, flatRates, isAddressFillEvent, isQuoteChange, listBrands, matchRate, orderSummaryMessages, quoteDeadline, quoteFingerprint, quoteNote, rateBadges, rateCarrier, rateEta, rateService, readQuoteAddress, recommendRates, useAutoQuote };
|
package/dist/checkout.js
CHANGED
|
@@ -6,7 +6,7 @@ import { ProductThumb } from './chunk-VHEY5AU3.js';
|
|
|
6
6
|
import './chunk-6CVKW7F3.js';
|
|
7
7
|
import { useResolvedLocale } from './chunk-T52H5HL3.js';
|
|
8
8
|
import './chunk-DQBL2DFJ.js';
|
|
9
|
-
import { useId, useState, useRef, useEffect, useMemo, useSyncExternalStore } from 'react';
|
|
9
|
+
import { useId, useState, useRef, useEffect, useMemo, useCallback, useSyncExternalStore } from 'react';
|
|
10
10
|
import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
|
|
11
11
|
import { formatMoney } from '@asteby/storefront';
|
|
12
12
|
|
|
@@ -563,7 +563,10 @@ var ES3 = {
|
|
|
563
563
|
moreOptions: "Ver m\xE1s opciones ({n})",
|
|
564
564
|
otherCarriers: "Otras opciones",
|
|
565
565
|
error: "No pudimos consultar las opciones de env\xEDo en este momento.",
|
|
566
|
-
retry: "Intentar de nuevo"
|
|
566
|
+
retry: "Intentar de nuevo",
|
|
567
|
+
freeShipping: "Env\xEDo gratis",
|
|
568
|
+
freeShippingNote: "Tu pedido ya incluye el env\xEDo: no tienes que elegir paqueter\xEDa.",
|
|
569
|
+
ratesReady: "Opciones de env\xEDo listas ({n})."
|
|
567
570
|
};
|
|
568
571
|
var EN3 = {
|
|
569
572
|
etaOne: "Arrives in 1 business day",
|
|
@@ -586,7 +589,10 @@ var EN3 = {
|
|
|
586
589
|
moreOptions: "Show more options ({n})",
|
|
587
590
|
otherCarriers: "Other options",
|
|
588
591
|
error: "We couldn't get delivery options right now.",
|
|
589
|
-
retry: "Try again"
|
|
592
|
+
retry: "Try again",
|
|
593
|
+
freeShipping: "Free shipping",
|
|
594
|
+
freeShippingNote: "Shipping is included in your order: there is no carrier to choose.",
|
|
595
|
+
ratesReady: "Delivery options ready ({n})."
|
|
590
596
|
};
|
|
591
597
|
function deliveryMessages(locale, overrides) {
|
|
592
598
|
const base = (locale ?? "es-MX").toLowerCase().startsWith("en") ? EN3 : ES3;
|
|
@@ -679,13 +685,13 @@ function isQuoteChange(err) {
|
|
|
679
685
|
}
|
|
680
686
|
function matchRate(previous, rates) {
|
|
681
687
|
if (!previous) return null;
|
|
682
|
-
const
|
|
683
|
-
const sameCarrier = (r) =>
|
|
688
|
+
const norm3 = (s) => (s ?? "").trim().toLowerCase();
|
|
689
|
+
const sameCarrier = (r) => norm3(r.carrier) === norm3(previous.carrier);
|
|
684
690
|
if (previous.service_code) {
|
|
685
|
-
const hit = rates.find((r) => sameCarrier(r) &&
|
|
691
|
+
const hit = rates.find((r) => sameCarrier(r) && norm3(r.service_code) === norm3(previous.service_code));
|
|
686
692
|
if (hit) return hit;
|
|
687
693
|
}
|
|
688
|
-
return rates.find((r) => sameCarrier(r) &&
|
|
694
|
+
return rates.find((r) => sameCarrier(r) && norm3(r.title) === norm3(previous.title)) ?? null;
|
|
689
695
|
}
|
|
690
696
|
var SR_ONLY = { position: "absolute", width: 1, height: 1, overflow: "hidden", clip: "rect(0 0 0 0)", whiteSpace: "nowrap" };
|
|
691
697
|
var useHydrated = () => useSyncExternalStore(
|
|
@@ -722,7 +728,8 @@ function DeliveryOptions(props) {
|
|
|
722
728
|
children,
|
|
723
729
|
layout = "list",
|
|
724
730
|
error,
|
|
725
|
-
onRetry
|
|
731
|
+
onRetry,
|
|
732
|
+
free = false
|
|
726
733
|
} = props;
|
|
727
734
|
const locale = useResolvedLocale(props.locale);
|
|
728
735
|
const m = useMemo(() => deliveryMessages(locale, props.messages), [locale, props.messages]);
|
|
@@ -790,17 +797,24 @@ function DeliveryOptions(props) {
|
|
|
790
797
|
] }, rate.id);
|
|
791
798
|
};
|
|
792
799
|
const errorText = error ? typeof error === "string" ? error : m.error : null;
|
|
800
|
+
const freeRate = free && !loading && pickup.length === 0 ? rates.find((r) => !r.pickup) ?? null : null;
|
|
793
801
|
return /* @__PURE__ */ jsxs("div", { className: cx.root, "data-sf-delivery": true, "data-layout": layout, "aria-busy": loading || void 0, children: [
|
|
794
802
|
partial && !errorText ? /* @__PURE__ */ jsx("p", { role: "status", className: cx.partial, "data-sf-delivery-partial": true, children: m.partial }) : null,
|
|
795
803
|
requoted ? /* @__PURE__ */ jsx("p", { role: "status", className: cx.partial, "data-sf-delivery-requoted": true, children: m.requoted }) : null,
|
|
796
804
|
loading ? /* @__PURE__ */ jsx("span", { style: SR_ONLY, role: "status", "data-sf-delivery-loading": true, children: m.loading }) : null,
|
|
805
|
+
props.announceReady && !loading && rates.length > 0 ? /* @__PURE__ */ jsx("span", { style: SR_ONLY, role: "status", "data-sf-delivery-ready": true, children: freeRate ? m.freeShipping : m.ratesReady.replace("{n}", String(rates.length)) }) : null,
|
|
797
806
|
errorText && rates.length === 0 && !loading ? /* @__PURE__ */ jsxs("div", { role: "alert", className: cx.error, "data-sf-delivery-error": true, children: [
|
|
798
807
|
/* @__PURE__ */ jsx("p", { children: errorText }),
|
|
799
808
|
onRetry ? /* @__PURE__ */ jsx("button", { type: "button", className: cx.retry, onClick: onRetry, "data-sf-delivery-retry": true, children: m.retry }) : null
|
|
800
809
|
] }) : null,
|
|
810
|
+
freeRate ? /* @__PURE__ */ jsxs("div", { className: cx.freeBanner, role: props.announceReady ? void 0 : "status", "data-sf-delivery-free-banner": true, children: [
|
|
811
|
+
/* @__PURE__ */ jsx("input", { type: "hidden", name, value: rateValue(freeRate), ...testId ? { "data-testid": testId } : {} }),
|
|
812
|
+
/* @__PURE__ */ jsx("p", { className: cx.free, "data-sf-delivery-free-title": true, children: /* @__PURE__ */ jsx("strong", { children: m.freeShipping }) }),
|
|
813
|
+
/* @__PURE__ */ jsx("p", { className: cx.note, children: m.freeShippingNote })
|
|
814
|
+
] }) : null,
|
|
801
815
|
children,
|
|
802
816
|
loading && rates.length === 0 ? [0, 1, 2].map((i) => /* @__PURE__ */ jsx("div", { className: cx.skeleton, "data-sf-delivery-skeleton": true, "aria-hidden": "true" }, i)) : null,
|
|
803
|
-
flat ? flat.map(({ rate, tags }) => rateRow(rate, { tags: showBadges ? tags : [] })) : plan ? plan.recommended.map(({ rate, tags }) => rateRow(rate, { tags: showBadges ? tags : [] })) : rates.map((rate) => rateRow(rate, { tags: badges.get(rate.id) ?? [] })),
|
|
817
|
+
freeRate ? null : flat ? flat.map(({ rate, tags }) => rateRow(rate, { tags: showBadges ? tags : [] })) : plan ? plan.recommended.map(({ rate, tags }) => rateRow(rate, { tags: showBadges ? tags : [] })) : rates.map((rate) => rateRow(rate, { tags: badges.get(rate.id) ?? [] })),
|
|
804
818
|
plan && plan.moreCount > 0 ? /* @__PURE__ */ jsxs("details", { className: cx.more, "data-sf-delivery-more": true, ...inMore ? { open: true } : {}, children: [
|
|
805
819
|
/* @__PURE__ */ jsx("summary", { className: cx.moreSummary, "data-sf-delivery-more-summary": true, children: m.moreOptions.replace("{n}", String(plan.moreCount)) }),
|
|
806
820
|
/* @__PURE__ */ jsx("div", { "data-sf-delivery-groups": true, children: plan.more.map((g) => {
|
|
@@ -827,7 +841,141 @@ function DeliveryOptions(props) {
|
|
|
827
841
|
deadline ? /* @__PURE__ */ jsx("p", { className: cx.note, "data-sf-delivery-note": true, "data-soon": shownNote?.soon || void 0, "aria-live": "polite", children: shownNote?.text ?? "" }) : null
|
|
828
842
|
] });
|
|
829
843
|
}
|
|
844
|
+
var DEFAULT_QUOTE_NAMES = {
|
|
845
|
+
country_code: "country_code",
|
|
846
|
+
zip: "zip",
|
|
847
|
+
province: "province",
|
|
848
|
+
city: "city",
|
|
849
|
+
neighborhood: "neighborhood",
|
|
850
|
+
address1: "address1"
|
|
851
|
+
};
|
|
852
|
+
var DEFAULT_REQUIRED = ["zip", "province", "city", "neighborhood", "address1"];
|
|
853
|
+
var QUOTE_KEYS = ["country_code", "zip", "province", "city"];
|
|
854
|
+
var norm2 = (v) => v.normalize("NFD").replace(/[̀-ͯ]/g, "").trim().toLowerCase();
|
|
855
|
+
function quoteFingerprint(a) {
|
|
856
|
+
return QUOTE_KEYS.map((k) => norm2(a[k] ?? "")).join("|");
|
|
857
|
+
}
|
|
858
|
+
function defaultRate(delivery) {
|
|
859
|
+
let best = null;
|
|
860
|
+
for (const r of delivery.rates) {
|
|
861
|
+
if (r.pickup) continue;
|
|
862
|
+
if (!best || Number(r.cost.amount) < Number(best.cost.amount)) best = r;
|
|
863
|
+
}
|
|
864
|
+
return best;
|
|
865
|
+
}
|
|
866
|
+
function readQuoteAddress(form, opts = {}) {
|
|
867
|
+
if (!form) return null;
|
|
868
|
+
const names = { ...DEFAULT_QUOTE_NAMES, ...opts.names };
|
|
869
|
+
const data = new FormData(form);
|
|
870
|
+
const get = (name) => String(data.get(name) ?? "").trim();
|
|
871
|
+
const address = {
|
|
872
|
+
country_code: get(names.country_code) || opts.defaultCountry || "MX",
|
|
873
|
+
zip: get(names.zip),
|
|
874
|
+
province: get(names.province),
|
|
875
|
+
city: get(names.city),
|
|
876
|
+
neighborhood: get(names.neighborhood),
|
|
877
|
+
address1: get(names.address1)
|
|
878
|
+
};
|
|
879
|
+
const valid = opts.validPostalCode ?? ((z) => /^\d{5}$/.test(z));
|
|
880
|
+
if (!valid(address.zip)) return null;
|
|
881
|
+
for (const k of opts.required ?? DEFAULT_REQUIRED) if (!address[k]) return null;
|
|
882
|
+
return address;
|
|
883
|
+
}
|
|
884
|
+
function useAutoQuote(options) {
|
|
885
|
+
const { formRef, debounceMs = 600, enabled = true } = options;
|
|
886
|
+
const [status, setStatus] = useState("idle");
|
|
887
|
+
const [delivery, setDelivery] = useState(null);
|
|
888
|
+
const [quotedFor, setQuotedFor] = useState(null);
|
|
889
|
+
const opts = useRef(options);
|
|
890
|
+
opts.current = options;
|
|
891
|
+
const timer = useRef(null);
|
|
892
|
+
const inflight = useRef(null);
|
|
893
|
+
const quotedFp = useRef(null);
|
|
894
|
+
const pendingFp = useRef(null);
|
|
895
|
+
const run = useCallback((address, fp) => {
|
|
896
|
+
inflight.current?.abort();
|
|
897
|
+
const ctl = new AbortController();
|
|
898
|
+
inflight.current = ctl;
|
|
899
|
+
pendingFp.current = fp;
|
|
900
|
+
setStatus("loading");
|
|
901
|
+
opts.current.quote(address, ctl.signal).then((d) => {
|
|
902
|
+
if (ctl.signal.aborted) return;
|
|
903
|
+
quotedFp.current = fp;
|
|
904
|
+
pendingFp.current = null;
|
|
905
|
+
setDelivery(d);
|
|
906
|
+
setQuotedFor(address);
|
|
907
|
+
setStatus("ready");
|
|
908
|
+
opts.current.onQuoted?.(d);
|
|
909
|
+
}).catch(() => {
|
|
910
|
+
if (ctl.signal.aborted) return;
|
|
911
|
+
pendingFp.current = null;
|
|
912
|
+
quotedFp.current = null;
|
|
913
|
+
setStatus("error");
|
|
914
|
+
});
|
|
915
|
+
}, []);
|
|
916
|
+
const evaluate = useCallback(
|
|
917
|
+
(force) => {
|
|
918
|
+
const address = readQuoteAddress(formRef.current, opts.current);
|
|
919
|
+
if (!address) {
|
|
920
|
+
if (timer.current) clearTimeout(timer.current);
|
|
921
|
+
timer.current = null;
|
|
922
|
+
inflight.current?.abort();
|
|
923
|
+
pendingFp.current = null;
|
|
924
|
+
setStatus("idle");
|
|
925
|
+
return;
|
|
926
|
+
}
|
|
927
|
+
const fp = quoteFingerprint(address);
|
|
928
|
+
if (!force && (fp === quotedFp.current || fp === pendingFp.current)) {
|
|
929
|
+
if (timer.current) clearTimeout(timer.current);
|
|
930
|
+
timer.current = null;
|
|
931
|
+
if (fp === quotedFp.current) setStatus("ready");
|
|
932
|
+
return;
|
|
933
|
+
}
|
|
934
|
+
if (timer.current) clearTimeout(timer.current);
|
|
935
|
+
if (force) {
|
|
936
|
+
timer.current = null;
|
|
937
|
+
run(address, fp);
|
|
938
|
+
return;
|
|
939
|
+
}
|
|
940
|
+
setStatus("waiting");
|
|
941
|
+
timer.current = setTimeout(() => {
|
|
942
|
+
timer.current = null;
|
|
943
|
+
const latest = readQuoteAddress(formRef.current, opts.current);
|
|
944
|
+
if (latest) run(latest, quoteFingerprint(latest));
|
|
945
|
+
}, debounceMs);
|
|
946
|
+
},
|
|
947
|
+
[debounceMs, formRef, run]
|
|
948
|
+
);
|
|
949
|
+
useEffect(() => {
|
|
950
|
+
const form = formRef.current;
|
|
951
|
+
if (!enabled || !form) return;
|
|
952
|
+
const onChange = () => evaluate(false);
|
|
953
|
+
form.addEventListener("input", onChange);
|
|
954
|
+
form.addEventListener("change", onChange);
|
|
955
|
+
const first = setTimeout(onChange, 0);
|
|
956
|
+
return () => {
|
|
957
|
+
clearTimeout(first);
|
|
958
|
+
form.removeEventListener("input", onChange);
|
|
959
|
+
form.removeEventListener("change", onChange);
|
|
960
|
+
if (timer.current) clearTimeout(timer.current);
|
|
961
|
+
inflight.current?.abort();
|
|
962
|
+
};
|
|
963
|
+
}, [enabled, evaluate, formRef]);
|
|
964
|
+
const retry = useCallback(() => evaluate(true), [evaluate]);
|
|
965
|
+
const defaultValue = useMemo(() => {
|
|
966
|
+
if (!delivery) return null;
|
|
967
|
+
const saved = opts.current.savedValue;
|
|
968
|
+
if (saved?.startsWith("rate:")) {
|
|
969
|
+
const hit = delivery.rates.find((r) => `rate:${r.id}` === saved);
|
|
970
|
+
if (hit) return `rate:${hit.id}`;
|
|
971
|
+
}
|
|
972
|
+
const pick = (opts.current.pickDefault ?? defaultRate)(delivery);
|
|
973
|
+
return pick ? `rate:${pick.id}` : null;
|
|
974
|
+
}, [delivery, options.savedValue]);
|
|
975
|
+
const announce = status === "loading" || status === "waiting" ? "searching" : status === "error" ? "error" : status === "ready" ? delivery?.free ? "free" : "ready" : null;
|
|
976
|
+
return { status, delivery, defaultValue, quotedFor, retry, announce };
|
|
977
|
+
}
|
|
830
978
|
|
|
831
|
-
export { ADDRESS_FILL_EVENT_FLAG, AddressFields, ContactFields, DeliveryOptions, OrderSummary, OrderSummaryDisclosure, addressFieldsMessages, dedupeRates, deliveryMessages, flatRates, isAddressFillEvent, isQuoteChange, matchRate, orderSummaryMessages, quoteDeadline, quoteNote, rateBadges, rateCarrier, rateEta, rateService, recommendRates };
|
|
979
|
+
export { ADDRESS_FILL_EVENT_FLAG, AddressFields, ContactFields, DEFAULT_QUOTE_NAMES, DeliveryOptions, OrderSummary, OrderSummaryDisclosure, QUOTE_KEYS, addressFieldsMessages, dedupeRates, defaultRate, deliveryMessages, flatRates, isAddressFillEvent, isQuoteChange, matchRate, orderSummaryMessages, quoteDeadline, quoteFingerprint, quoteNote, rateBadges, rateCarrier, rateEta, rateService, readQuoteAddress, recommendRates, useAutoQuote };
|
|
832
980
|
//# sourceMappingURL=checkout.js.map
|
|
833
981
|
//# sourceMappingURL=checkout.js.map
|