@asteby/storefront-react 0.8.0 → 0.10.0
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 +60 -1
- package/dist/cart.js +2 -1
- package/dist/cart.js.map +1 -1
- package/dist/checkout.cjs +440 -0
- package/dist/checkout.cjs.map +1 -0
- package/dist/checkout.css +100 -0
- package/dist/checkout.d.cts +197 -0
- package/dist/checkout.d.ts +197 -0
- package/dist/checkout.js +243 -0
- package/dist/checkout.js.map +1 -0
- package/dist/choices-DEPE9KRq.d.cts +130 -0
- package/dist/choices-DEPE9KRq.d.ts +130 -0
- package/dist/chunk-DSZVJ2PW.js +180 -0
- package/dist/chunk-DSZVJ2PW.js.map +1 -0
- package/dist/chunk-ISEOCKIR.js +160 -0
- package/dist/chunk-ISEOCKIR.js.map +1 -0
- package/dist/chunk-T52H5HL3.js +11 -0
- package/dist/chunk-T52H5HL3.js.map +1 -0
- package/dist/{chunk-2WZIWIBW.js → chunk-ZBH7JYU4.js} +4 -10
- package/dist/chunk-ZBH7JYU4.js.map +1 -0
- package/dist/payments-server.cjs +369 -0
- package/dist/payments-server.cjs.map +1 -0
- package/dist/payments-server.d.cts +145 -0
- package/dist/payments-server.d.ts +145 -0
- package/dist/payments-server.js +191 -0
- package/dist/payments-server.js.map +1 -0
- package/dist/payments.cjs +639 -2
- package/dist/payments.cjs.map +1 -1
- package/dist/payments.css +57 -0
- package/dist/payments.d.cts +137 -21
- package/dist/payments.d.ts +137 -21
- package/dist/payments.js +332 -37
- package/dist/payments.js.map +1 -1
- package/dist/promotions.js +2 -1
- package/dist/promotions.js.map +1 -1
- package/package.json +24 -2
- package/dist/chunk-2WZIWIBW.js.map +0 -1
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Default sheet for <DeliveryOptions> and the brand marks (`@asteby/storefront-react/checkout.css`). Optional and
|
|
3
|
+
* neutral: layout, badges, skeleton and the reserved line of the quote note. Colors come from `currentColor` and a few
|
|
4
|
+
* variables the shop can set (light and dark):
|
|
5
|
+
* --sf-brand-mark-ring hairline around a mark (default rgb(127 127 127 / .35))
|
|
6
|
+
* --sf-brand-mark-bg/fg badge of a brand outside the catalog
|
|
7
|
+
* --sf-delivery-badge-bg / --sf-delivery-badge-fg
|
|
8
|
+
* --sf-delivery-muted secondary text (default currentColor at 70%)
|
|
9
|
+
*/
|
|
10
|
+
[data-sf-delivery] {
|
|
11
|
+
display: grid;
|
|
12
|
+
gap: 0.75rem;
|
|
13
|
+
}
|
|
14
|
+
[data-sf-delivery-option] {
|
|
15
|
+
display: flex;
|
|
16
|
+
align-items: center;
|
|
17
|
+
gap: 0.75rem;
|
|
18
|
+
min-height: 44px;
|
|
19
|
+
cursor: pointer;
|
|
20
|
+
}
|
|
21
|
+
[data-sf-delivery-option][data-loading] {
|
|
22
|
+
opacity: 0.6;
|
|
23
|
+
transition: opacity 150ms;
|
|
24
|
+
}
|
|
25
|
+
[data-sf-delivery-body] {
|
|
26
|
+
display: flex;
|
|
27
|
+
flex: 1 1 auto;
|
|
28
|
+
min-width: 0;
|
|
29
|
+
flex-direction: column;
|
|
30
|
+
gap: 0.125rem;
|
|
31
|
+
}
|
|
32
|
+
[data-sf-delivery-title] {
|
|
33
|
+
overflow-wrap: anywhere;
|
|
34
|
+
}
|
|
35
|
+
[data-sf-delivery-carrier] {
|
|
36
|
+
font-weight: 600;
|
|
37
|
+
}
|
|
38
|
+
[data-sf-delivery-service],
|
|
39
|
+
[data-sf-delivery-eta] {
|
|
40
|
+
color: var(--sf-delivery-muted, color-mix(in srgb, currentColor 72%, transparent));
|
|
41
|
+
}
|
|
42
|
+
[data-sf-delivery-eta] {
|
|
43
|
+
font-size: 0.875em;
|
|
44
|
+
}
|
|
45
|
+
[data-sf-delivery-badges] {
|
|
46
|
+
display: flex;
|
|
47
|
+
flex-wrap: wrap;
|
|
48
|
+
gap: 0.375rem;
|
|
49
|
+
margin-top: 0.25rem;
|
|
50
|
+
}
|
|
51
|
+
[data-sf-delivery-badge] {
|
|
52
|
+
display: inline-flex;
|
|
53
|
+
align-items: center;
|
|
54
|
+
border-radius: 999px;
|
|
55
|
+
padding: 0.0625rem 0.5rem;
|
|
56
|
+
font-size: 0.75em;
|
|
57
|
+
font-weight: 600;
|
|
58
|
+
line-height: 1.5;
|
|
59
|
+
background: var(--sf-delivery-badge-bg, color-mix(in srgb, currentColor 10%, transparent));
|
|
60
|
+
color: var(--sf-delivery-badge-fg, inherit);
|
|
61
|
+
}
|
|
62
|
+
[data-sf-delivery-price] {
|
|
63
|
+
flex: none;
|
|
64
|
+
font-weight: 600;
|
|
65
|
+
font-variant-numeric: tabular-nums;
|
|
66
|
+
text-align: right;
|
|
67
|
+
}
|
|
68
|
+
[data-sf-delivery-note] {
|
|
69
|
+
min-height: 1.5em; /* reserved before hydration: the text never shifts the layout */
|
|
70
|
+
margin: 0;
|
|
71
|
+
font-size: 0.75rem;
|
|
72
|
+
color: var(--sf-delivery-muted, color-mix(in srgb, currentColor 72%, transparent));
|
|
73
|
+
}
|
|
74
|
+
[data-sf-delivery-skeleton] {
|
|
75
|
+
height: 4.5rem;
|
|
76
|
+
border-radius: 0.375rem;
|
|
77
|
+
background: linear-gradient(90deg, color-mix(in srgb, currentColor 6%, transparent) 0%, color-mix(in srgb, currentColor 12%, transparent) 50%, color-mix(in srgb, currentColor 6%, transparent) 100%);
|
|
78
|
+
background-size: 200% 100%;
|
|
79
|
+
animation: sf-delivery-shimmer 1.2s ease-in-out infinite;
|
|
80
|
+
}
|
|
81
|
+
@keyframes sf-delivery-shimmer {
|
|
82
|
+
from {
|
|
83
|
+
background-position: 100% 0;
|
|
84
|
+
}
|
|
85
|
+
to {
|
|
86
|
+
background-position: -100% 0;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
@media (prefers-reduced-motion: reduce) {
|
|
90
|
+
[data-sf-delivery-skeleton] {
|
|
91
|
+
animation: none;
|
|
92
|
+
}
|
|
93
|
+
[data-sf-delivery-option][data-loading] {
|
|
94
|
+
transition: none;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
[data-sf-brand-mark] {
|
|
98
|
+
display: inline-block;
|
|
99
|
+
vertical-align: middle;
|
|
100
|
+
}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
import { ShippingRate, PickupOption, Money } from '@asteby/storefront';
|
|
4
|
+
|
|
5
|
+
type BrandMarkProps = {
|
|
6
|
+
/** Provider identifier (`fedex`, `oxxo`, `mercadopago`, `7eleven`…). Unknown keys get a neutral monogram. */
|
|
7
|
+
brand: string | null | undefined;
|
|
8
|
+
/** Licensed logo sent by the provider (`PaymentPoint.logo_url`…). Only `https:`; it wins over the badge. */
|
|
9
|
+
logoUrl?: string | null;
|
|
10
|
+
/** Height in px. The badge is 3:2 (width = 1.5 × height). Default 24. */
|
|
11
|
+
size?: number;
|
|
12
|
+
/**
|
|
13
|
+
* Accessible name. Omit it when the brand name is already written next to the mark (the usual case): the mark is then
|
|
14
|
+
* decorative (`aria-hidden`).
|
|
15
|
+
*/
|
|
16
|
+
title?: string;
|
|
17
|
+
className?: string;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* The mark of a carrier, card network, wallet or cash point: an inline SVG badge in the brand color with its short
|
|
21
|
+
* wordmark (no network request, same size on the server and in the browser, so no layout shift). With `logoUrl` it
|
|
22
|
+
* draws the provider's licensed logo instead, lazily, with fixed dimensions.
|
|
23
|
+
*
|
|
24
|
+
* The badge carries its own background, so it keeps its contrast on light and dark themes; a hairline
|
|
25
|
+
* (`--sf-brand-mark-ring`) separates it from the page.
|
|
26
|
+
*/
|
|
27
|
+
declare function BrandMark({ brand, logoUrl, size, title, className }: BrandMarkProps): react.JSX.Element;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Shared catalog of the brands a checkout names: parcel carriers, card networks, wallets and cash payment points.
|
|
31
|
+
*
|
|
32
|
+
* Keys are the stable identifiers the providers already send (`ShippingRate.carrier` of Skydropx / Envía, the
|
|
33
|
+
* `PaymentPoint.payment_point` or `id` of the payment addon, a `PaymentMethod.key`). Nothing here decides what a shop
|
|
34
|
+
* offers: the server lists the rates and methods; this only gives each one its commercial name and a mark.
|
|
35
|
+
*
|
|
36
|
+
* Marks are typographic badges drawn by `<BrandMark>` (brand color + short wordmark): no third-party logo files are
|
|
37
|
+
* bundled, so there is no licensing question and no extra request. A provider that holds a licensed logo sends it as
|
|
38
|
+
* `logo_url` and it wins over the badge. Colors are close approximations of each brand's public color.
|
|
39
|
+
*/
|
|
40
|
+
type BrandKind = 'carrier' | 'card' | 'wallet' | 'cash' | 'bank';
|
|
41
|
+
type Brand = {
|
|
42
|
+
key: string;
|
|
43
|
+
/** Commercial name, as the brand writes it. */
|
|
44
|
+
name: string;
|
|
45
|
+
kind: BrandKind;
|
|
46
|
+
/** Badge background. */
|
|
47
|
+
bg: string;
|
|
48
|
+
/** Badge text color (AA on `bg`). */
|
|
49
|
+
fg: string;
|
|
50
|
+
/** Short wordmark drawn in the badge (`\n` = two lines). Default: `name`. */
|
|
51
|
+
mark?: string;
|
|
52
|
+
/** Special drawings instead of a wordmark. */
|
|
53
|
+
shape?: 'mastercard';
|
|
54
|
+
};
|
|
55
|
+
/** `"FedEx México"`, `"fedex_mx"` and `"FEDEX"` all become `fedex`. Lowercase ASCII letters and digits only. */
|
|
56
|
+
declare function brandKey(raw: string | null | undefined): string;
|
|
57
|
+
/** Catalog entry for a provider identifier, or `null` when the brand is not in the catalog. */
|
|
58
|
+
declare function findBrand(raw: string | null | undefined): Brand | null;
|
|
59
|
+
/**
|
|
60
|
+
* Commercial name for a provider identifier: the catalog's (`fedex` → "FedEx") or, for an unknown one, the identifier
|
|
61
|
+
* in title case (`"envios_rapidos"` → "Envios Rapidos"). `null` for an empty input.
|
|
62
|
+
*/
|
|
63
|
+
declare function brandName(raw: string | null | undefined): string | null;
|
|
64
|
+
/** Every brand of the catalog (for docs, previews and tests). */
|
|
65
|
+
declare function listBrands(kind?: BrandKind): Brand[];
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Pure helpers for the "Delivery" step: how to name a carrier rate, its arrival time, which rate is the cheapest or the
|
|
69
|
+
* fastest, and one human note for the quote deadline. No amounts are computed: `cost` is shown as the server sends it;
|
|
70
|
+
* comparing two costs to flag the cheapest is the only arithmetic.
|
|
71
|
+
*/
|
|
72
|
+
|
|
73
|
+
type DeliveryMessages = {
|
|
74
|
+
/** `{n}` = business days. */
|
|
75
|
+
etaOne: string;
|
|
76
|
+
etaMany: string;
|
|
77
|
+
/** `{min}` / `{max}` = business days. */
|
|
78
|
+
etaRange: string;
|
|
79
|
+
etaUpTo: string;
|
|
80
|
+
etaFrom: string;
|
|
81
|
+
cheapest: string;
|
|
82
|
+
fastest: string;
|
|
83
|
+
free: string;
|
|
84
|
+
pickupTitle: string;
|
|
85
|
+
/** Quote deadline, `{time}` = local time. */
|
|
86
|
+
quoteToday: string;
|
|
87
|
+
quoteTomorrow: string;
|
|
88
|
+
/** `{date}` = short date + time. */
|
|
89
|
+
quoteLater: string;
|
|
90
|
+
quoteSoon: string;
|
|
91
|
+
partial: string;
|
|
92
|
+
loading: string;
|
|
93
|
+
/** The quote expired or changed and the rates were reloaded. */
|
|
94
|
+
requoted: string;
|
|
95
|
+
};
|
|
96
|
+
/** Messages for a locale (`es*` default, `en*`), with optional overrides. */
|
|
97
|
+
declare function deliveryMessages(locale?: string | null, overrides?: Partial<DeliveryMessages> | null): DeliveryMessages;
|
|
98
|
+
/** Commercial carrier name of a rate (`fedex` → "FedEx"); `null` without carrier. */
|
|
99
|
+
declare function rateCarrier(rate: Pick<ShippingRate, 'carrier'>): string | null;
|
|
100
|
+
/**
|
|
101
|
+
* Service name without the carrier repeated: "FedEx Express Saver" with carrier `fedex` → "Express Saver". Falls back
|
|
102
|
+
* to the title when stripping would leave nothing.
|
|
103
|
+
*/
|
|
104
|
+
declare function rateService(rate: Pick<ShippingRate, 'title' | 'carrier'>): string;
|
|
105
|
+
/** Arrival time of a rate: business days from the provider, else the server `eta` text as is. */
|
|
106
|
+
declare function rateEta(rate: Pick<ShippingRate, 'eta' | 'eta_days_min' | 'eta_days_max'>, messages?: DeliveryMessages): string | null;
|
|
107
|
+
type RateBadge = 'cheapest' | 'fastest';
|
|
108
|
+
/**
|
|
109
|
+
* Badges per rate id. Only with two or more rates, only when one rate is strictly the cheapest (same currency) or
|
|
110
|
+
* strictly the fastest: a tie gets no badge, so the badge always tells the buyer something.
|
|
111
|
+
*/
|
|
112
|
+
declare function rateBadges(rates: readonly ShippingRate[]): Map<string, RateBadge[]>;
|
|
113
|
+
/** Earliest `expires_at` of the rates (the deadline of the whole list), or `null`. */
|
|
114
|
+
declare function quoteDeadline(rates: readonly Pick<ShippingRate, 'expires_at'>[]): Date | null;
|
|
115
|
+
type QuoteNote = {
|
|
116
|
+
text: string;
|
|
117
|
+
soon: boolean;
|
|
118
|
+
};
|
|
119
|
+
/**
|
|
120
|
+
* One human note for the quote deadline, in the buyer's time zone (or `timeZone`): "valid until 9:39 p.m.", "until
|
|
121
|
+
* tomorrow at…", "until Oct 24, …", or "expire soon" within `soonMinutes` (default 15). `null` when already past.
|
|
122
|
+
*/
|
|
123
|
+
declare function quoteNote(deadline: Date | null, opts?: {
|
|
124
|
+
locale?: string;
|
|
125
|
+
now?: Date;
|
|
126
|
+
timeZone?: string;
|
|
127
|
+
soonMinutes?: number;
|
|
128
|
+
messages?: DeliveryMessages;
|
|
129
|
+
}): QuoteNote | null;
|
|
130
|
+
/**
|
|
131
|
+
* `true` when saving a shipping rate failed because the quote expired or the rates changed, so the shop should reload
|
|
132
|
+
* the rates (and keep the address) instead of showing a generic failure. Recognizes the explicit codes
|
|
133
|
+
* (`quote_expired`, `rate_expired`…, any status), a `409`, and the generic `422` on the rate field that older servers
|
|
134
|
+
* answer when the provider re-quoted with new ids. 5xx and other 4xx stay real failures.
|
|
135
|
+
*/
|
|
136
|
+
declare function isQuoteChange(err: {
|
|
137
|
+
status?: number;
|
|
138
|
+
code?: string | null;
|
|
139
|
+
field?: string | null;
|
|
140
|
+
} | null | undefined): boolean;
|
|
141
|
+
/**
|
|
142
|
+
* The rate of a fresh quote that matches the one the buyer had chosen (same carrier and service), so a re-quote keeps
|
|
143
|
+
* the choice even though the provider issued new ids. `null` when that service is no longer offered.
|
|
144
|
+
*/
|
|
145
|
+
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;
|
|
146
|
+
|
|
147
|
+
type DeliveryOptionsClassNames = Partial<Record<'root' | 'option' | 'radio' | 'mark' | 'body' | 'title' | 'carrier' | 'service' | 'eta' | 'badges' | 'badge' | 'price' | 'free' | 'note' | 'partial' | 'skeleton', string>>;
|
|
148
|
+
type DeliveryOptionsProps = {
|
|
149
|
+
rates: readonly ShippingRate[];
|
|
150
|
+
pickup?: readonly PickupOption[];
|
|
151
|
+
/** Radio group name. Default `delivery_choice`. */
|
|
152
|
+
name?: string;
|
|
153
|
+
/** Form value of a rate. Default `rate:<id>`. */
|
|
154
|
+
rateValue?: (rate: ShippingRate) => string;
|
|
155
|
+
/** Form value of a pickup branch. Default `pickup:<branch_id>`. */
|
|
156
|
+
pickupValue?: (branch: PickupOption) => string;
|
|
157
|
+
/** Uncontrolled preselection. Default: the first rate. `null`: nothing preselected. */
|
|
158
|
+
defaultValue?: string | null;
|
|
159
|
+
/** Controlled value (use with `onValueChange`). */
|
|
160
|
+
value?: string;
|
|
161
|
+
onValueChange?: (value: string) => void;
|
|
162
|
+
/** Some provider did not answer (`DeliveryOptions.partial`): one neutral note above the list. */
|
|
163
|
+
partial?: boolean;
|
|
164
|
+
/** The previous quote expired or changed and these rates are fresh: one status note above the list. */
|
|
165
|
+
requoted?: boolean;
|
|
166
|
+
/** Rates are being quoted again: skeleton rows (no rates yet) or the current rows dimmed, `aria-busy`. */
|
|
167
|
+
loading?: boolean;
|
|
168
|
+
/** Quote deadline note: `always` (default), only when it is `soon`, or `never`. */
|
|
169
|
+
quoteNote?: 'always' | 'soon' | 'never';
|
|
170
|
+
/** Time zone of the note. Default: the buyer's browser. */
|
|
171
|
+
timeZone?: string;
|
|
172
|
+
/** Show the carrier marks. Default true. */
|
|
173
|
+
marks?: boolean;
|
|
174
|
+
/** Cheapest / fastest badges. Default true. */
|
|
175
|
+
badges?: boolean;
|
|
176
|
+
required?: boolean;
|
|
177
|
+
locale?: string;
|
|
178
|
+
messages?: Partial<DeliveryMessages>;
|
|
179
|
+
renderAmount?: (amount: Money) => ReactNode;
|
|
180
|
+
classNames?: DeliveryOptionsClassNames;
|
|
181
|
+
/** `data-testid` of every radio. */
|
|
182
|
+
testId?: string;
|
|
183
|
+
/** Rows the shop renders before the rates (e.g. "home delivery, rates after the address"). */
|
|
184
|
+
children?: ReactNode;
|
|
185
|
+
};
|
|
186
|
+
/**
|
|
187
|
+
* The rates and pickup branches of "Delivery" as native radios: carrier mark and commercial name, readable service,
|
|
188
|
+
* arrival time, cheapest / fastest badges, price as the server sends it, and ONE note for the quote deadline in the
|
|
189
|
+
* buyer's time zone. Works without JavaScript (plain radios in the page form); the note appears after hydration in a
|
|
190
|
+
* reserved line, so it never shifts the layout.
|
|
191
|
+
*
|
|
192
|
+
* Wrap it in the shop's own `<fieldset><legend>`. Style it with `classNames` and/or the default sheet
|
|
193
|
+
* `@asteby/storefront-react/checkout.css`.
|
|
194
|
+
*/
|
|
195
|
+
declare function DeliveryOptions(props: DeliveryOptionsProps): react.JSX.Element;
|
|
196
|
+
|
|
197
|
+
export { type Brand, type BrandKind, BrandMark, type BrandMarkProps, type DeliveryMessages, DeliveryOptions, type DeliveryOptionsClassNames, type DeliveryOptionsProps, type QuoteNote, type RateBadge, brandKey, brandName, deliveryMessages, findBrand, isQuoteChange, listBrands, matchRate, quoteDeadline, quoteNote, rateBadges, rateCarrier, rateEta, rateService };
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
import { ShippingRate, PickupOption, Money } from '@asteby/storefront';
|
|
4
|
+
|
|
5
|
+
type BrandMarkProps = {
|
|
6
|
+
/** Provider identifier (`fedex`, `oxxo`, `mercadopago`, `7eleven`…). Unknown keys get a neutral monogram. */
|
|
7
|
+
brand: string | null | undefined;
|
|
8
|
+
/** Licensed logo sent by the provider (`PaymentPoint.logo_url`…). Only `https:`; it wins over the badge. */
|
|
9
|
+
logoUrl?: string | null;
|
|
10
|
+
/** Height in px. The badge is 3:2 (width = 1.5 × height). Default 24. */
|
|
11
|
+
size?: number;
|
|
12
|
+
/**
|
|
13
|
+
* Accessible name. Omit it when the brand name is already written next to the mark (the usual case): the mark is then
|
|
14
|
+
* decorative (`aria-hidden`).
|
|
15
|
+
*/
|
|
16
|
+
title?: string;
|
|
17
|
+
className?: string;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* The mark of a carrier, card network, wallet or cash point: an inline SVG badge in the brand color with its short
|
|
21
|
+
* wordmark (no network request, same size on the server and in the browser, so no layout shift). With `logoUrl` it
|
|
22
|
+
* draws the provider's licensed logo instead, lazily, with fixed dimensions.
|
|
23
|
+
*
|
|
24
|
+
* The badge carries its own background, so it keeps its contrast on light and dark themes; a hairline
|
|
25
|
+
* (`--sf-brand-mark-ring`) separates it from the page.
|
|
26
|
+
*/
|
|
27
|
+
declare function BrandMark({ brand, logoUrl, size, title, className }: BrandMarkProps): react.JSX.Element;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Shared catalog of the brands a checkout names: parcel carriers, card networks, wallets and cash payment points.
|
|
31
|
+
*
|
|
32
|
+
* Keys are the stable identifiers the providers already send (`ShippingRate.carrier` of Skydropx / Envía, the
|
|
33
|
+
* `PaymentPoint.payment_point` or `id` of the payment addon, a `PaymentMethod.key`). Nothing here decides what a shop
|
|
34
|
+
* offers: the server lists the rates and methods; this only gives each one its commercial name and a mark.
|
|
35
|
+
*
|
|
36
|
+
* Marks are typographic badges drawn by `<BrandMark>` (brand color + short wordmark): no third-party logo files are
|
|
37
|
+
* bundled, so there is no licensing question and no extra request. A provider that holds a licensed logo sends it as
|
|
38
|
+
* `logo_url` and it wins over the badge. Colors are close approximations of each brand's public color.
|
|
39
|
+
*/
|
|
40
|
+
type BrandKind = 'carrier' | 'card' | 'wallet' | 'cash' | 'bank';
|
|
41
|
+
type Brand = {
|
|
42
|
+
key: string;
|
|
43
|
+
/** Commercial name, as the brand writes it. */
|
|
44
|
+
name: string;
|
|
45
|
+
kind: BrandKind;
|
|
46
|
+
/** Badge background. */
|
|
47
|
+
bg: string;
|
|
48
|
+
/** Badge text color (AA on `bg`). */
|
|
49
|
+
fg: string;
|
|
50
|
+
/** Short wordmark drawn in the badge (`\n` = two lines). Default: `name`. */
|
|
51
|
+
mark?: string;
|
|
52
|
+
/** Special drawings instead of a wordmark. */
|
|
53
|
+
shape?: 'mastercard';
|
|
54
|
+
};
|
|
55
|
+
/** `"FedEx México"`, `"fedex_mx"` and `"FEDEX"` all become `fedex`. Lowercase ASCII letters and digits only. */
|
|
56
|
+
declare function brandKey(raw: string | null | undefined): string;
|
|
57
|
+
/** Catalog entry for a provider identifier, or `null` when the brand is not in the catalog. */
|
|
58
|
+
declare function findBrand(raw: string | null | undefined): Brand | null;
|
|
59
|
+
/**
|
|
60
|
+
* Commercial name for a provider identifier: the catalog's (`fedex` → "FedEx") or, for an unknown one, the identifier
|
|
61
|
+
* in title case (`"envios_rapidos"` → "Envios Rapidos"). `null` for an empty input.
|
|
62
|
+
*/
|
|
63
|
+
declare function brandName(raw: string | null | undefined): string | null;
|
|
64
|
+
/** Every brand of the catalog (for docs, previews and tests). */
|
|
65
|
+
declare function listBrands(kind?: BrandKind): Brand[];
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Pure helpers for the "Delivery" step: how to name a carrier rate, its arrival time, which rate is the cheapest or the
|
|
69
|
+
* fastest, and one human note for the quote deadline. No amounts are computed: `cost` is shown as the server sends it;
|
|
70
|
+
* comparing two costs to flag the cheapest is the only arithmetic.
|
|
71
|
+
*/
|
|
72
|
+
|
|
73
|
+
type DeliveryMessages = {
|
|
74
|
+
/** `{n}` = business days. */
|
|
75
|
+
etaOne: string;
|
|
76
|
+
etaMany: string;
|
|
77
|
+
/** `{min}` / `{max}` = business days. */
|
|
78
|
+
etaRange: string;
|
|
79
|
+
etaUpTo: string;
|
|
80
|
+
etaFrom: string;
|
|
81
|
+
cheapest: string;
|
|
82
|
+
fastest: string;
|
|
83
|
+
free: string;
|
|
84
|
+
pickupTitle: string;
|
|
85
|
+
/** Quote deadline, `{time}` = local time. */
|
|
86
|
+
quoteToday: string;
|
|
87
|
+
quoteTomorrow: string;
|
|
88
|
+
/** `{date}` = short date + time. */
|
|
89
|
+
quoteLater: string;
|
|
90
|
+
quoteSoon: string;
|
|
91
|
+
partial: string;
|
|
92
|
+
loading: string;
|
|
93
|
+
/** The quote expired or changed and the rates were reloaded. */
|
|
94
|
+
requoted: string;
|
|
95
|
+
};
|
|
96
|
+
/** Messages for a locale (`es*` default, `en*`), with optional overrides. */
|
|
97
|
+
declare function deliveryMessages(locale?: string | null, overrides?: Partial<DeliveryMessages> | null): DeliveryMessages;
|
|
98
|
+
/** Commercial carrier name of a rate (`fedex` → "FedEx"); `null` without carrier. */
|
|
99
|
+
declare function rateCarrier(rate: Pick<ShippingRate, 'carrier'>): string | null;
|
|
100
|
+
/**
|
|
101
|
+
* Service name without the carrier repeated: "FedEx Express Saver" with carrier `fedex` → "Express Saver". Falls back
|
|
102
|
+
* to the title when stripping would leave nothing.
|
|
103
|
+
*/
|
|
104
|
+
declare function rateService(rate: Pick<ShippingRate, 'title' | 'carrier'>): string;
|
|
105
|
+
/** Arrival time of a rate: business days from the provider, else the server `eta` text as is. */
|
|
106
|
+
declare function rateEta(rate: Pick<ShippingRate, 'eta' | 'eta_days_min' | 'eta_days_max'>, messages?: DeliveryMessages): string | null;
|
|
107
|
+
type RateBadge = 'cheapest' | 'fastest';
|
|
108
|
+
/**
|
|
109
|
+
* Badges per rate id. Only with two or more rates, only when one rate is strictly the cheapest (same currency) or
|
|
110
|
+
* strictly the fastest: a tie gets no badge, so the badge always tells the buyer something.
|
|
111
|
+
*/
|
|
112
|
+
declare function rateBadges(rates: readonly ShippingRate[]): Map<string, RateBadge[]>;
|
|
113
|
+
/** Earliest `expires_at` of the rates (the deadline of the whole list), or `null`. */
|
|
114
|
+
declare function quoteDeadline(rates: readonly Pick<ShippingRate, 'expires_at'>[]): Date | null;
|
|
115
|
+
type QuoteNote = {
|
|
116
|
+
text: string;
|
|
117
|
+
soon: boolean;
|
|
118
|
+
};
|
|
119
|
+
/**
|
|
120
|
+
* One human note for the quote deadline, in the buyer's time zone (or `timeZone`): "valid until 9:39 p.m.", "until
|
|
121
|
+
* tomorrow at…", "until Oct 24, …", or "expire soon" within `soonMinutes` (default 15). `null` when already past.
|
|
122
|
+
*/
|
|
123
|
+
declare function quoteNote(deadline: Date | null, opts?: {
|
|
124
|
+
locale?: string;
|
|
125
|
+
now?: Date;
|
|
126
|
+
timeZone?: string;
|
|
127
|
+
soonMinutes?: number;
|
|
128
|
+
messages?: DeliveryMessages;
|
|
129
|
+
}): QuoteNote | null;
|
|
130
|
+
/**
|
|
131
|
+
* `true` when saving a shipping rate failed because the quote expired or the rates changed, so the shop should reload
|
|
132
|
+
* the rates (and keep the address) instead of showing a generic failure. Recognizes the explicit codes
|
|
133
|
+
* (`quote_expired`, `rate_expired`…, any status), a `409`, and the generic `422` on the rate field that older servers
|
|
134
|
+
* answer when the provider re-quoted with new ids. 5xx and other 4xx stay real failures.
|
|
135
|
+
*/
|
|
136
|
+
declare function isQuoteChange(err: {
|
|
137
|
+
status?: number;
|
|
138
|
+
code?: string | null;
|
|
139
|
+
field?: string | null;
|
|
140
|
+
} | null | undefined): boolean;
|
|
141
|
+
/**
|
|
142
|
+
* The rate of a fresh quote that matches the one the buyer had chosen (same carrier and service), so a re-quote keeps
|
|
143
|
+
* the choice even though the provider issued new ids. `null` when that service is no longer offered.
|
|
144
|
+
*/
|
|
145
|
+
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;
|
|
146
|
+
|
|
147
|
+
type DeliveryOptionsClassNames = Partial<Record<'root' | 'option' | 'radio' | 'mark' | 'body' | 'title' | 'carrier' | 'service' | 'eta' | 'badges' | 'badge' | 'price' | 'free' | 'note' | 'partial' | 'skeleton', string>>;
|
|
148
|
+
type DeliveryOptionsProps = {
|
|
149
|
+
rates: readonly ShippingRate[];
|
|
150
|
+
pickup?: readonly PickupOption[];
|
|
151
|
+
/** Radio group name. Default `delivery_choice`. */
|
|
152
|
+
name?: string;
|
|
153
|
+
/** Form value of a rate. Default `rate:<id>`. */
|
|
154
|
+
rateValue?: (rate: ShippingRate) => string;
|
|
155
|
+
/** Form value of a pickup branch. Default `pickup:<branch_id>`. */
|
|
156
|
+
pickupValue?: (branch: PickupOption) => string;
|
|
157
|
+
/** Uncontrolled preselection. Default: the first rate. `null`: nothing preselected. */
|
|
158
|
+
defaultValue?: string | null;
|
|
159
|
+
/** Controlled value (use with `onValueChange`). */
|
|
160
|
+
value?: string;
|
|
161
|
+
onValueChange?: (value: string) => void;
|
|
162
|
+
/** Some provider did not answer (`DeliveryOptions.partial`): one neutral note above the list. */
|
|
163
|
+
partial?: boolean;
|
|
164
|
+
/** The previous quote expired or changed and these rates are fresh: one status note above the list. */
|
|
165
|
+
requoted?: boolean;
|
|
166
|
+
/** Rates are being quoted again: skeleton rows (no rates yet) or the current rows dimmed, `aria-busy`. */
|
|
167
|
+
loading?: boolean;
|
|
168
|
+
/** Quote deadline note: `always` (default), only when it is `soon`, or `never`. */
|
|
169
|
+
quoteNote?: 'always' | 'soon' | 'never';
|
|
170
|
+
/** Time zone of the note. Default: the buyer's browser. */
|
|
171
|
+
timeZone?: string;
|
|
172
|
+
/** Show the carrier marks. Default true. */
|
|
173
|
+
marks?: boolean;
|
|
174
|
+
/** Cheapest / fastest badges. Default true. */
|
|
175
|
+
badges?: boolean;
|
|
176
|
+
required?: boolean;
|
|
177
|
+
locale?: string;
|
|
178
|
+
messages?: Partial<DeliveryMessages>;
|
|
179
|
+
renderAmount?: (amount: Money) => ReactNode;
|
|
180
|
+
classNames?: DeliveryOptionsClassNames;
|
|
181
|
+
/** `data-testid` of every radio. */
|
|
182
|
+
testId?: string;
|
|
183
|
+
/** Rows the shop renders before the rates (e.g. "home delivery, rates after the address"). */
|
|
184
|
+
children?: ReactNode;
|
|
185
|
+
};
|
|
186
|
+
/**
|
|
187
|
+
* The rates and pickup branches of "Delivery" as native radios: carrier mark and commercial name, readable service,
|
|
188
|
+
* arrival time, cheapest / fastest badges, price as the server sends it, and ONE note for the quote deadline in the
|
|
189
|
+
* buyer's time zone. Works without JavaScript (plain radios in the page form); the note appears after hydration in a
|
|
190
|
+
* reserved line, so it never shifts the layout.
|
|
191
|
+
*
|
|
192
|
+
* Wrap it in the shop's own `<fieldset><legend>`. Style it with `classNames` and/or the default sheet
|
|
193
|
+
* `@asteby/storefront-react/checkout.css`.
|
|
194
|
+
*/
|
|
195
|
+
declare function DeliveryOptions(props: DeliveryOptionsProps): react.JSX.Element;
|
|
196
|
+
|
|
197
|
+
export { type Brand, type BrandKind, BrandMark, type BrandMarkProps, type DeliveryMessages, DeliveryOptions, type DeliveryOptionsClassNames, type DeliveryOptionsProps, type QuoteNote, type RateBadge, brandKey, brandName, deliveryMessages, findBrand, isQuoteChange, listBrands, matchRate, quoteDeadline, quoteNote, rateBadges, rateCarrier, rateEta, rateService };
|