@reblu/site-blocks 0.12.1 → 0.13.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/CHANGELOG.md +46 -0
- package/README.md +74 -0
- package/dist/index.cjs +343 -30
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +124 -2
- package/dist/index.d.ts +124 -2
- package/dist/index.js +335 -29
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,51 @@
|
|
|
1
1
|
# @reblu/site-blocks
|
|
2
2
|
|
|
3
|
+
## 0.13.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 614e826: New drop-in `FullInvoiceFields` (REB-73): the shop checkout's «¿Quieres
|
|
8
|
+
factura completa?» opt-in with the buyer's identifier (Spanish NIF/NIE/CIF,
|
|
9
|
+
EU VAT id, passport or ID document, with its issuing country), name and
|
|
10
|
+
billing address — required, without a toggle, when the cart total is over
|
|
11
|
+
`ShopConfig.simplifiedInvoiceCapCents`. Controlled and hook-free; with
|
|
12
|
+
`isOverSimplifiedInvoiceCap` and `toCheckoutInvoiceFields`, which builds the
|
|
13
|
+
`wantsFullInvoice`/`billing` checkout body fields.
|
|
14
|
+
- 614e826: Shop checkout: no full-invoice opt-in on a shop that issues no invoices (REB-73).
|
|
15
|
+
- `ShopErrorCode` gains `FULL_INVOICE_UNAVAILABLE` (HTTP 422,
|
|
16
|
+
`details.field: 'wantsFullInvoice'`): `wantsFullInvoice: true` sent to a shop
|
|
17
|
+
whose invoicing is off (`ShopConfig.simplifiedInvoiceCapCents` is `null`) is
|
|
18
|
+
refused before any payment instead of succeeding without an invoice. Clients
|
|
19
|
+
that never send the opt-in are unaffected. The union is additive: a SITE
|
|
20
|
+
with an exhaustive `switch` over `ShopErrorCode` (or a
|
|
21
|
+
`Record<ShopErrorCode, …>`) must add the new member when it upgrades.
|
|
22
|
+
- `@reblu/site-blocks`: new `shopIssuesInvoices(config)`; `FullInvoiceFields`
|
|
23
|
+
takes `issuesInvoices` (default `true`) and renders nothing when it is
|
|
24
|
+
`false`, and `toCheckoutInvoiceFields(value, overCap, issuesInvoices)`
|
|
25
|
+
returns no opt-in and no billing block then. Default Spanish copy for the
|
|
26
|
+
new code in `getShopErrorMessage`.
|
|
27
|
+
|
|
28
|
+
- 614e826: Shop: the order's invoice and the simplified-invoice cap (REB-73).
|
|
29
|
+
- `ShopOrder` gains the optional `invoice: { number, url } | null`
|
|
30
|
+
(`ShopOrderInvoice`): once the sale invoice is issued, its number and the
|
|
31
|
+
shop's authenticated client-portal route that serves it — never a signed
|
|
32
|
+
URL, so the link does not expire; the buyer signs in to open it.
|
|
33
|
+
- `ShopConfig` gains `simplifiedInvoiceCapCents` (cents, never above the legal
|
|
34
|
+
300000; `null` while the shop issues no invoices): above it, checkout needs
|
|
35
|
+
the buyer's identifier, name and billing address.
|
|
36
|
+
- `@reblu/site-blocks`: new drop-in `OrderInvoiceLink`, which
|
|
37
|
+
`OrderConfirmation` now renders under a confirmed order (labels
|
|
38
|
+
`invoiceLinkLabel`/`invoiceSignInHint`), and default Spanish copy for the
|
|
39
|
+
`BILLING_DATA_REQUIRED`/`INVOICING_NOT_READY` checkout codes in
|
|
40
|
+
`getShopErrorMessage`.
|
|
41
|
+
|
|
42
|
+
### Patch Changes
|
|
43
|
+
|
|
44
|
+
- Updated dependencies [614e826]
|
|
45
|
+
- Updated dependencies [614e826]
|
|
46
|
+
- Updated dependencies [614e826]
|
|
47
|
+
- @reblu/site-contracts@1.15.0
|
|
48
|
+
|
|
3
49
|
## 0.12.1
|
|
4
50
|
|
|
5
51
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -204,6 +204,8 @@ for the wiring steps and a full example app).
|
|
|
204
204
|
| `CheckoutLoginPrompt` | `.` | `open`, `email`, `onEmailChange`, `onClose`, `onSubmitEmail`, `onContinueAsGuest` | Yes (renders `null` when `open` is false) |
|
|
205
205
|
| `CheckoutForm` | `.` | `contact`, `onContactChange`, `discountCode`, `onDiscountCodeChange`, `onApplyDiscount`, `onRemoveDiscount`, `onSubmit` | Yes |
|
|
206
206
|
| `OrderConfirmation` | `.` | `status`, `order`, `cartHref?`, `onRecheck?` | Yes |
|
|
207
|
+
| `OrderInvoiceLink` | `.` | `invoice` (`order.invoice`), `labels?` | Yes (renders `null` without an invoice) |
|
|
208
|
+
| `FullInvoiceFields` | `.` | `value`, `onChange`, `overCap`, `errors?`, `countries?`, `labels?` | Yes (controlled, no hooks) |
|
|
207
209
|
|
|
208
210
|
**REB-837 breaking move**: `AddToCartButton` and `CartIcon` now carry real
|
|
209
211
|
internal state (the confirmed/error timer, the bump-on-add guard) and ship
|
|
@@ -392,6 +394,78 @@ Every title/description is overridable via `labels` (see
|
|
|
392
394
|
"`useShopOrderStatus` — the order-confirmation flow" for the full wiring
|
|
393
395
|
recipe.
|
|
394
396
|
|
|
397
|
+
### The order's invoice — `OrderInvoiceLink` (REB-73)
|
|
398
|
+
|
|
399
|
+
Once the sale invoice is issued, the order lookup (`client.shop.order(sessionId)`,
|
|
400
|
+
or `useShopOrderStatus`) carries `order.invoice: { number, url }` — `null`
|
|
401
|
+
while there is none. `url` is the shop's **authenticated** client-portal route,
|
|
402
|
+
never a signed URL: the buyer signs in to open the PDF, so the link never
|
|
403
|
+
expires and is safe to show anywhere. `OrderConfirmation` already renders it
|
|
404
|
+
under a confirmed order (`paid`/`found`/`timeout`), with its copy overridable
|
|
405
|
+
through `labels.invoiceLinkLabel` (`{number}` is replaced) and
|
|
406
|
+
`labels.invoiceSignInHint`. To place it elsewhere — an account page, a custom
|
|
407
|
+
confirmation — drop it in:
|
|
408
|
+
|
|
409
|
+
```tsx
|
|
410
|
+
import { OrderInvoiceLink } from '@reblu/site-blocks'
|
|
411
|
+
|
|
412
|
+
// order: ShopOrder from client.shop.order(sessionId) / useShopOrderStatus
|
|
413
|
+
;<OrderInvoiceLink invoice={order.invoice} />
|
|
414
|
+
// «Descargar la factura FAC-2026-0010» + «Te pediremos que inicies sesión para abrirla.»
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
### The full-invoice request — `FullInvoiceFields` (REB-73)
|
|
418
|
+
|
|
419
|
+
A full invoice needs the buyer's identifier — a Spanish NIF/NIE/CIF, or for a
|
|
420
|
+
foreign buyer an EU VAT id, a passport or an ID document of their country,
|
|
421
|
+
with the country that issued it — plus their name and billing address;
|
|
422
|
+
without it the invoice is simplified. Over `ShopConfig.simplifiedInvoiceCapCents`
|
|
423
|
+
a full invoice is the only legal one, so checkout refuses the sale without
|
|
424
|
+
them (`BILLING_DATA_REQUIRED`). Drop the fields into your checkout form and
|
|
425
|
+
send what they produce:
|
|
426
|
+
|
|
427
|
+
```tsx
|
|
428
|
+
'use client'
|
|
429
|
+
import { useState } from 'react'
|
|
430
|
+
import {
|
|
431
|
+
EMPTY_FULL_INVOICE_VALUE,
|
|
432
|
+
FullInvoiceFields,
|
|
433
|
+
isOverSimplifiedInvoiceCap,
|
|
434
|
+
shopIssuesInvoices,
|
|
435
|
+
toCheckoutInvoiceFields,
|
|
436
|
+
} from '@reblu/site-blocks'
|
|
437
|
+
|
|
438
|
+
const [invoice, setInvoice] = useState(EMPTY_FULL_INVOICE_VALUE)
|
|
439
|
+
const issuesInvoices = shopIssuesInvoices(shopConfig)
|
|
440
|
+
const overCap = isOverSimplifiedInvoiceCap(cartTotalCents, shopConfig.simplifiedInvoiceCapCents)
|
|
441
|
+
|
|
442
|
+
<FullInvoiceFields
|
|
443
|
+
value={invoice}
|
|
444
|
+
onChange={setInvoice}
|
|
445
|
+
overCap={overCap}
|
|
446
|
+
issuesInvoices={issuesInvoices}
|
|
447
|
+
/>
|
|
448
|
+
|
|
449
|
+
// in onSubmit:
|
|
450
|
+
await client.shop.checkout({
|
|
451
|
+
...checkoutBody,
|
|
452
|
+
...toCheckoutInvoiceFields(invoice, overCap, issuesInvoices),
|
|
453
|
+
})
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
A shop that issues no invoices (`ShopConfig.simplifiedInvoiceCapCents` is
|
|
457
|
+
`null`) offers no full invoice: pass `issuesInvoices={shopIssuesInvoices(config)}`
|
|
458
|
+
and the block renders nothing, and give the same flag to
|
|
459
|
+
`toCheckoutInvoiceFields(invoice, overCap, issuesInvoices)` so the body never
|
|
460
|
+
carries the opt-in.
|
|
461
|
+
|
|
462
|
+
Checkout refusals tied to invoicing come with their own default copy in
|
|
463
|
+
`getShopErrorMessage`: `BILLING_DATA_REQUIRED` (422 — a full invoice, or a
|
|
464
|
+
total over `ShopConfig.simplifiedInvoiceCapCents`, needs the buyer's
|
|
465
|
+
NIF/NIE or ID document, name and billing address), `INVOICING_NOT_READY`
|
|
466
|
+
(503) and `FULL_INVOICE_UNAVAILABLE` (422 — `wantsFullInvoice: true` sent to a
|
|
467
|
+
shop that issues no invoices).
|
|
468
|
+
|
|
395
469
|
## Product trust items
|
|
396
470
|
|
|
397
471
|
`ProductTrustItems` renders the store-wide trust messages (shipping, returns,
|
package/dist/index.cjs
CHANGED
|
@@ -26,13 +26,17 @@ __export(src_exports, {
|
|
|
26
26
|
CartSummary: () => CartSummary,
|
|
27
27
|
CheckoutForm: () => CheckoutForm,
|
|
28
28
|
CheckoutLoginPrompt: () => CheckoutLoginPrompt,
|
|
29
|
+
DEFAULT_INVOICE_COUNTRIES: () => DEFAULT_INVOICE_COUNTRIES,
|
|
29
30
|
DEFAULT_SHOP_ERROR_FALLBACK_MESSAGE: () => DEFAULT_SHOP_ERROR_FALLBACK_MESSAGE,
|
|
30
31
|
DEFAULT_SHOP_ERROR_MESSAGES: () => DEFAULT_SHOP_ERROR_MESSAGES,
|
|
31
32
|
DEFAULT_SHOP_PRICE_BANDS: () => DEFAULT_SHOP_PRICE_BANDS,
|
|
32
33
|
DEFAULT_TRUST_ICONS: () => DEFAULT_TRUST_ICONS,
|
|
34
|
+
EMPTY_FULL_INVOICE_VALUE: () => EMPTY_FULL_INVOICE_VALUE,
|
|
33
35
|
FaqAccordion: () => FaqAccordion,
|
|
36
|
+
FullInvoiceFields: () => FullInvoiceFields,
|
|
34
37
|
MarkdownRenderer: () => MarkdownRenderer,
|
|
35
38
|
OrderConfirmation: () => OrderConfirmation,
|
|
39
|
+
OrderInvoiceLink: () => OrderInvoiceLink,
|
|
36
40
|
PageBlocks: () => PageBlocks,
|
|
37
41
|
PageCardGrid: () => PageCardGrid,
|
|
38
42
|
ParentPage: () => ParentPage,
|
|
@@ -49,10 +53,13 @@ __export(src_exports, {
|
|
|
49
53
|
formatPrice: () => formatPrice,
|
|
50
54
|
getShopErrorMessage: () => getShopErrorMessage,
|
|
51
55
|
isAllowedYouTubeHost: () => isAllowedYouTubeHost,
|
|
56
|
+
isOverSimplifiedInvoiceCap: () => isOverSimplifiedInvoiceCap,
|
|
52
57
|
markdownToSafeHtml: () => markdownToSafeHtml,
|
|
53
58
|
readingTime: () => readingTime,
|
|
54
59
|
sanitizeHtml: () => sanitizeHtml,
|
|
55
|
-
|
|
60
|
+
shopIssuesInvoices: () => shopIssuesInvoices,
|
|
61
|
+
shouldRenderShopFilters: () => shouldRenderShopFilters,
|
|
62
|
+
toCheckoutInvoiceFields: () => toCheckoutInvoiceFields
|
|
56
63
|
});
|
|
57
64
|
module.exports = __toCommonJS(src_exports);
|
|
58
65
|
|
|
@@ -98,7 +105,11 @@ var DEFAULT_SHOP_ERROR_MESSAGES = {
|
|
|
98
105
|
INVALID_INPUT: "Revisa los datos introducidos.",
|
|
99
106
|
STORE_DISABLED: "La tienda no est\xE1 disponible en este momento.",
|
|
100
107
|
PAYMENT_PROVIDER_ERROR: "No hemos podido conectar con la pasarela de pago. Int\xE9ntalo de nuevo.",
|
|
101
|
-
INTERNAL_ERROR: "Ha ocurrido un error inesperado. Int\xE9ntalo de nuevo en unos minutos."
|
|
108
|
+
INTERNAL_ERROR: "Ha ocurrido un error inesperado. Int\xE9ntalo de nuevo en unos minutos.",
|
|
109
|
+
// REB-73 — checkout refusals before any payment.
|
|
110
|
+
BILLING_DATA_REQUIRED: "Para emitir tu factura necesitamos tu NIF/NIE o un documento de identificaci\xF3n, tu nombre y tu direcci\xF3n de facturaci\xF3n.",
|
|
111
|
+
INVOICING_NOT_READY: "No se puede completar la compra en este momento. Int\xE9ntalo m\xE1s tarde.",
|
|
112
|
+
FULL_INVOICE_UNAVAILABLE: "Esta tienda no emite facturas completas: contin\xFAa sin solicitarla."
|
|
102
113
|
};
|
|
103
114
|
var DEFAULT_SHOP_ERROR_FALLBACK_MESSAGE = "No se ha podido completar la operaci\xF3n. Int\xE9ntalo de nuevo.";
|
|
104
115
|
function getShopErrorMessage(code, overrides, fallback = DEFAULT_SHOP_ERROR_FALLBACK_MESSAGE) {
|
|
@@ -14777,9 +14788,34 @@ function CheckoutForm({
|
|
|
14777
14788
|
}
|
|
14778
14789
|
|
|
14779
14790
|
// src/components/order-confirmation.tsx
|
|
14791
|
+
var import_utils20 = require("@reblu/site-ui/utils");
|
|
14792
|
+
|
|
14793
|
+
// src/components/order-invoice-link.tsx
|
|
14780
14794
|
var import_utils19 = require("@reblu/site-ui/utils");
|
|
14781
14795
|
var import_jsx_runtime18 = require("react/jsx-runtime");
|
|
14782
14796
|
var DEFAULT_LABELS7 = {
|
|
14797
|
+
linkLabel: "Descargar la factura {number}",
|
|
14798
|
+
signInHint: "Te pediremos que inicies sesi\xF3n para abrirla."
|
|
14799
|
+
};
|
|
14800
|
+
function OrderInvoiceLink({ invoice, labels, className }) {
|
|
14801
|
+
if (!invoice) return null;
|
|
14802
|
+
const t = { ...DEFAULT_LABELS7, ...labels };
|
|
14803
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: (0, import_utils19.cn)("space-y-1 text-sm", className), "data-slot": "order-invoice-link", children: [
|
|
14804
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
14805
|
+
"a",
|
|
14806
|
+
{
|
|
14807
|
+
href: invoice.url,
|
|
14808
|
+
className: "font-semibold text-primary underline-offset-2 hover:underline",
|
|
14809
|
+
children: t.linkLabel.replace("{number}", invoice.number)
|
|
14810
|
+
}
|
|
14811
|
+
),
|
|
14812
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { className: "text-muted-foreground", children: t.signInHint })
|
|
14813
|
+
] });
|
|
14814
|
+
}
|
|
14815
|
+
|
|
14816
|
+
// src/components/order-confirmation.tsx
|
|
14817
|
+
var import_jsx_runtime19 = require("react/jsx-runtime");
|
|
14818
|
+
var DEFAULT_LABELS8 = {
|
|
14783
14819
|
pollingTitle: "Confirmando tu pedido\u2026",
|
|
14784
14820
|
pollingDescription: "Estamos procesando el pago, un momento\u2026",
|
|
14785
14821
|
foundTitle: "\xA1Pedido confirmado!",
|
|
@@ -14805,7 +14841,9 @@ var DEFAULT_LABELS7 = {
|
|
|
14805
14841
|
notFoundDescription: "Comprueba el enlace o contacta con nosotros si el problema persiste.",
|
|
14806
14842
|
errorTitle: "Ha ocurrido un error",
|
|
14807
14843
|
errorDescription: "No hemos podido comprobar el estado de tu pedido.",
|
|
14808
|
-
orderReferenceLabel: "Referencia del pedido"
|
|
14844
|
+
orderReferenceLabel: "Referencia del pedido",
|
|
14845
|
+
invoiceLinkLabel: "Descargar la factura {number}",
|
|
14846
|
+
invoiceSignInHint: "Te pediremos que inicies sesi\xF3n para abrirla."
|
|
14809
14847
|
};
|
|
14810
14848
|
function OrderConfirmation({
|
|
14811
14849
|
status,
|
|
@@ -14818,7 +14856,7 @@ function OrderConfirmation({
|
|
|
14818
14856
|
locale,
|
|
14819
14857
|
className
|
|
14820
14858
|
}) {
|
|
14821
|
-
const t = { ...
|
|
14859
|
+
const t = { ...DEFAULT_LABELS8, ...labels };
|
|
14822
14860
|
const isPolling = status === "polling" || status === "loading";
|
|
14823
14861
|
const isFound = status === "found" || status === "paid";
|
|
14824
14862
|
const { title, description } = (() => {
|
|
@@ -14840,48 +14878,55 @@ function OrderConfirmation({
|
|
|
14840
14878
|
const showOrderReference = Boolean(order) && !showFullOrderSummary && (status === "refunded" || status === "partially_refunded" || status === "pending_timeout");
|
|
14841
14879
|
const showSessionReference = !order && sessionId && (status === "timeout" || status === "not_found" || status === "pending_timeout");
|
|
14842
14880
|
const showRecheck = (status === "pending_timeout" || status === "error") && onRecheck;
|
|
14843
|
-
return /* @__PURE__ */ (0,
|
|
14844
|
-
/* @__PURE__ */ (0,
|
|
14845
|
-
/* @__PURE__ */ (0,
|
|
14846
|
-
showFullOrderSummary && order && /* @__PURE__ */ (0,
|
|
14847
|
-
/* @__PURE__ */ (0,
|
|
14848
|
-
/* @__PURE__ */ (0,
|
|
14849
|
-
/* @__PURE__ */ (0,
|
|
14881
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: (0, import_utils20.cn)("space-y-6 text-center", className), "data-slot": "order-confirmation", children: [
|
|
14882
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("h1", { className: "text-3xl font-bold", children: title }),
|
|
14883
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: "text-lg text-muted-foreground", children: description }),
|
|
14884
|
+
showFullOrderSummary && order && /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "space-y-6", children: [
|
|
14885
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "inline-block rounded-xl bg-muted px-6 py-4", children: [
|
|
14886
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: "mb-1 text-xs uppercase tracking-widest text-muted-foreground", children: t.orderNumberLabel }),
|
|
14887
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: "font-mono text-lg font-semibold", children: order.orderNumber })
|
|
14850
14888
|
] }),
|
|
14851
|
-
/* @__PURE__ */ (0,
|
|
14852
|
-
order.items.map((item, idx) => /* @__PURE__ */ (0,
|
|
14889
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "mx-auto max-w-sm space-y-3 rounded-xl border border-border bg-card p-5 text-left", children: [
|
|
14890
|
+
order.items.map((item, idx) => /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
|
|
14853
14891
|
"div",
|
|
14854
14892
|
{
|
|
14855
14893
|
className: "flex justify-between gap-4 text-sm",
|
|
14856
14894
|
children: [
|
|
14857
|
-
/* @__PURE__ */ (0,
|
|
14895
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("span", { className: "max-w-[60%] truncate text-muted-foreground", children: [
|
|
14858
14896
|
item.product.name,
|
|
14859
14897
|
item.variant ? ` (${item.variant.name})` : "",
|
|
14860
14898
|
" x",
|
|
14861
14899
|
item.quantity
|
|
14862
14900
|
] }),
|
|
14863
|
-
/* @__PURE__ */ (0,
|
|
14901
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { children: formatPrice(item.total, currencyCode, locale) })
|
|
14864
14902
|
]
|
|
14865
14903
|
},
|
|
14866
14904
|
idx
|
|
14867
14905
|
)),
|
|
14868
|
-
/* @__PURE__ */ (0,
|
|
14869
|
-
/* @__PURE__ */ (0,
|
|
14870
|
-
/* @__PURE__ */ (0,
|
|
14906
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "space-y-1 border-t border-border pt-3 text-sm", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex justify-between pt-1 text-base font-bold", children: [
|
|
14907
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { children: t.totalLabel }),
|
|
14908
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { children: formatPrice(order.total, currencyCode, locale) })
|
|
14871
14909
|
] }) })
|
|
14872
14910
|
] }),
|
|
14873
|
-
/* @__PURE__ */ (0,
|
|
14911
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("p", { className: "mx-auto max-w-sm text-sm text-muted-foreground", children: [
|
|
14874
14912
|
t.confirmationEmailPrefix,
|
|
14875
14913
|
" ",
|
|
14876
|
-
/* @__PURE__ */ (0,
|
|
14914
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "font-medium text-foreground", children: order.customerEmail }),
|
|
14877
14915
|
"."
|
|
14878
|
-
] })
|
|
14916
|
+
] }),
|
|
14917
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
14918
|
+
OrderInvoiceLink,
|
|
14919
|
+
{
|
|
14920
|
+
invoice: order.invoice,
|
|
14921
|
+
labels: { linkLabel: t.invoiceLinkLabel, signInHint: t.invoiceSignInHint }
|
|
14922
|
+
}
|
|
14923
|
+
)
|
|
14879
14924
|
] }),
|
|
14880
|
-
showOrderReference && order && /* @__PURE__ */ (0,
|
|
14881
|
-
/* @__PURE__ */ (0,
|
|
14882
|
-
/* @__PURE__ */ (0,
|
|
14925
|
+
showOrderReference && order && /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "inline-block rounded-xl bg-muted px-6 py-4", children: [
|
|
14926
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: "mb-1 text-xs uppercase tracking-widest text-muted-foreground", children: t.orderReferenceLabel }),
|
|
14927
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: "font-mono text-lg font-semibold", children: order.orderNumber })
|
|
14883
14928
|
] }),
|
|
14884
|
-
status === "failed" && cartHref && /* @__PURE__ */ (0,
|
|
14929
|
+
status === "failed" && cartHref && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
14885
14930
|
"a",
|
|
14886
14931
|
{
|
|
14887
14932
|
href: cartHref,
|
|
@@ -14889,7 +14934,7 @@ function OrderConfirmation({
|
|
|
14889
14934
|
children: t.backToCartLabel
|
|
14890
14935
|
}
|
|
14891
14936
|
),
|
|
14892
|
-
showRecheck && /* @__PURE__ */ (0,
|
|
14937
|
+
showRecheck && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
14893
14938
|
"button",
|
|
14894
14939
|
{
|
|
14895
14940
|
type: "button",
|
|
@@ -14898,9 +14943,270 @@ function OrderConfirmation({
|
|
|
14898
14943
|
children: t.recheckLabel
|
|
14899
14944
|
}
|
|
14900
14945
|
),
|
|
14901
|
-
showSessionReference && /* @__PURE__ */ (0,
|
|
14902
|
-
/* @__PURE__ */ (0,
|
|
14903
|
-
/* @__PURE__ */ (0,
|
|
14946
|
+
showSessionReference && /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "inline-block rounded-xl bg-muted px-6 py-4", children: [
|
|
14947
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: "mb-1 text-xs uppercase tracking-widest text-muted-foreground", children: t.sessionReferenceLabel }),
|
|
14948
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: "break-all font-mono text-sm font-semibold", children: sessionId })
|
|
14949
|
+
] })
|
|
14950
|
+
] });
|
|
14951
|
+
}
|
|
14952
|
+
|
|
14953
|
+
// src/components/full-invoice-fields.tsx
|
|
14954
|
+
var import_utils21 = require("@reblu/site-ui/utils");
|
|
14955
|
+
var import_jsx_runtime20 = require("react/jsx-runtime");
|
|
14956
|
+
var EMPTY_FULL_INVOICE_VALUE = {
|
|
14957
|
+
wantsFullInvoice: false,
|
|
14958
|
+
billingIdType: "NIF",
|
|
14959
|
+
billingIdCountry: "",
|
|
14960
|
+
billingNif: "",
|
|
14961
|
+
billingName: "",
|
|
14962
|
+
street: "",
|
|
14963
|
+
postalCode: "",
|
|
14964
|
+
city: "",
|
|
14965
|
+
country: "ES"
|
|
14966
|
+
};
|
|
14967
|
+
var DEFAULT_LABELS9 = {
|
|
14968
|
+
toggle: "\xBFQuieres factura completa?",
|
|
14969
|
+
underCapNotice: "Para una factura completa necesitas tu NIF/NIE o un documento de identificaci\xF3n. Si no, recibir\xE1s una factura simplificada.",
|
|
14970
|
+
overCapNotice: "El importe del pedido supera el m\xE1ximo de la factura simplificada: para completar la compra, indica tu NIF/NIE o un documento de identificaci\xF3n, tu nombre y tu direcci\xF3n de facturaci\xF3n.",
|
|
14971
|
+
idType: "Tipo de documento",
|
|
14972
|
+
idCountry: "Pa\xEDs que expidi\xF3 el documento",
|
|
14973
|
+
chooseCountry: "Elige un pa\xEDs",
|
|
14974
|
+
spanishNif: "NIF / NIE / CIF",
|
|
14975
|
+
documentNumber: "N\xFAmero de documento",
|
|
14976
|
+
name: "Nombre o raz\xF3n social",
|
|
14977
|
+
street: "Direcci\xF3n",
|
|
14978
|
+
postalCode: "C\xF3digo postal",
|
|
14979
|
+
city: "Ciudad",
|
|
14980
|
+
country: "Pa\xEDs",
|
|
14981
|
+
idTypeOptions: {
|
|
14982
|
+
NIF: "NIF / NIE / CIF (Espa\xF1a)",
|
|
14983
|
+
"02": "NIF-IVA intracomunitario (otro pa\xEDs de la UE)",
|
|
14984
|
+
"03": "Pasaporte",
|
|
14985
|
+
"04": "Documento oficial de identidad de tu pa\xEDs de residencia",
|
|
14986
|
+
"05": "Certificado de residencia",
|
|
14987
|
+
"06": "Otro documento acreditativo"
|
|
14988
|
+
}
|
|
14989
|
+
};
|
|
14990
|
+
var ID_TYPES = ["NIF", "02", "03", "04", "05", "06"];
|
|
14991
|
+
var DEFAULT_INVOICE_COUNTRIES = [
|
|
14992
|
+
{ code: "ES", name: "Espa\xF1a" },
|
|
14993
|
+
{ code: "DE", name: "Alemania" },
|
|
14994
|
+
{ code: "AD", name: "Andorra" },
|
|
14995
|
+
{ code: "AR", name: "Argentina" },
|
|
14996
|
+
{ code: "AT", name: "Austria" },
|
|
14997
|
+
{ code: "BE", name: "B\xE9lgica" },
|
|
14998
|
+
{ code: "BG", name: "Bulgaria" },
|
|
14999
|
+
{ code: "CY", name: "Chipre" },
|
|
15000
|
+
{ code: "CO", name: "Colombia" },
|
|
15001
|
+
{ code: "HR", name: "Croacia" },
|
|
15002
|
+
{ code: "DK", name: "Dinamarca" },
|
|
15003
|
+
{ code: "SK", name: "Eslovaquia" },
|
|
15004
|
+
{ code: "SI", name: "Eslovenia" },
|
|
15005
|
+
{ code: "US", name: "Estados Unidos" },
|
|
15006
|
+
{ code: "EE", name: "Estonia" },
|
|
15007
|
+
{ code: "FI", name: "Finlandia" },
|
|
15008
|
+
{ code: "FR", name: "Francia" },
|
|
15009
|
+
{ code: "GR", name: "Grecia" },
|
|
15010
|
+
{ code: "HU", name: "Hungr\xEDa" },
|
|
15011
|
+
{ code: "IE", name: "Irlanda" },
|
|
15012
|
+
{ code: "IT", name: "Italia" },
|
|
15013
|
+
{ code: "LV", name: "Letonia" },
|
|
15014
|
+
{ code: "LT", name: "Lituania" },
|
|
15015
|
+
{ code: "LU", name: "Luxemburgo" },
|
|
15016
|
+
{ code: "MT", name: "Malta" },
|
|
15017
|
+
{ code: "MA", name: "Marruecos" },
|
|
15018
|
+
{ code: "MX", name: "M\xE9xico" },
|
|
15019
|
+
{ code: "NL", name: "Pa\xEDses Bajos" },
|
|
15020
|
+
{ code: "PL", name: "Polonia" },
|
|
15021
|
+
{ code: "PT", name: "Portugal" },
|
|
15022
|
+
{ code: "GB", name: "Reino Unido" },
|
|
15023
|
+
{ code: "CZ", name: "Rep\xFAblica Checa" },
|
|
15024
|
+
{ code: "RO", name: "Ruman\xEDa" },
|
|
15025
|
+
{ code: "SE", name: "Suecia" },
|
|
15026
|
+
{ code: "CH", name: "Suiza" },
|
|
15027
|
+
{ code: "VE", name: "Venezuela" }
|
|
15028
|
+
];
|
|
15029
|
+
function shopIssuesInvoices(config) {
|
|
15030
|
+
return config.simplifiedInvoiceCapCents != null;
|
|
15031
|
+
}
|
|
15032
|
+
function isOverSimplifiedInvoiceCap(totalCents, capCents) {
|
|
15033
|
+
return capCents != null && totalCents > capCents;
|
|
15034
|
+
}
|
|
15035
|
+
function toCheckoutInvoiceFields(value, overCap, issuesInvoices = true) {
|
|
15036
|
+
if (!issuesInvoices) return {};
|
|
15037
|
+
if (!value.wantsFullInvoice && !overCap) return {};
|
|
15038
|
+
const name = value.billingName.trim();
|
|
15039
|
+
const [first = "", ...rest] = name.split(/\s+/);
|
|
15040
|
+
const billing = {
|
|
15041
|
+
billingName: name,
|
|
15042
|
+
billingNif: value.billingNif.trim(),
|
|
15043
|
+
billingIdType: value.billingIdType,
|
|
15044
|
+
...value.billingIdType === "NIF" ? {} : { billingIdCountry: value.billingIdCountry },
|
|
15045
|
+
billingAddress: {
|
|
15046
|
+
firstName: first,
|
|
15047
|
+
lastName: rest.join(" ") || first,
|
|
15048
|
+
street: value.street.trim(),
|
|
15049
|
+
city: value.city.trim(),
|
|
15050
|
+
postalCode: value.postalCode.trim(),
|
|
15051
|
+
country: value.country
|
|
15052
|
+
}
|
|
15053
|
+
};
|
|
15054
|
+
return { ...value.wantsFullInvoice ? { wantsFullInvoice: true } : {}, billing };
|
|
15055
|
+
}
|
|
15056
|
+
var FIELD_CLASS = "w-full rounded-lg border border-border bg-background px-3 py-2 text-sm focus:border-primary focus:outline-none focus:ring-2 focus:ring-primary/20";
|
|
15057
|
+
function FullInvoiceFields({
|
|
15058
|
+
value,
|
|
15059
|
+
onChange,
|
|
15060
|
+
overCap,
|
|
15061
|
+
issuesInvoices = true,
|
|
15062
|
+
errors = {},
|
|
15063
|
+
countries = DEFAULT_INVOICE_COUNTRIES,
|
|
15064
|
+
labels,
|
|
15065
|
+
className
|
|
15066
|
+
}) {
|
|
15067
|
+
if (!issuesInvoices) return null;
|
|
15068
|
+
const t = { ...DEFAULT_LABELS9, ...labels };
|
|
15069
|
+
const showFields = value.wantsFullInvoice || overCap;
|
|
15070
|
+
const isSpanishNif = value.billingIdType === "NIF";
|
|
15071
|
+
const set = (key2, next2) => onChange({ ...value, [key2]: next2 });
|
|
15072
|
+
const error = (key2) => errors[key2] ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { id: `full-invoice-${key2}-error`, className: "text-sm text-destructive", children: errors[key2] }) : null;
|
|
15073
|
+
const invalid2 = (key2) => errors[key2] ? { "aria-invalid": true, "aria-describedby": `full-invoice-${key2}-error` } : {};
|
|
15074
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("section", { className: (0, import_utils21.cn)("space-y-4", className), "data-slot": "full-invoice-fields", children: [
|
|
15075
|
+
overCap ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { role: "note", className: "rounded-lg border border-border p-4 text-sm", children: t.overCapNotice }) : /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "space-y-1", children: [
|
|
15076
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("label", { className: "flex items-center gap-2 text-sm font-medium", children: [
|
|
15077
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
15078
|
+
"input",
|
|
15079
|
+
{
|
|
15080
|
+
type: "checkbox",
|
|
15081
|
+
checked: value.wantsFullInvoice,
|
|
15082
|
+
onChange: (e) => set("wantsFullInvoice", e.target.checked)
|
|
15083
|
+
}
|
|
15084
|
+
),
|
|
15085
|
+
t.toggle
|
|
15086
|
+
] }),
|
|
15087
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { className: "text-sm text-muted-foreground", children: t.underCapNotice })
|
|
15088
|
+
] }),
|
|
15089
|
+
showFields && /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "grid grid-cols-1 gap-4 sm:grid-cols-2", children: [
|
|
15090
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "space-y-1", children: [
|
|
15091
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("label", { htmlFor: "full-invoice-id-type", className: "text-sm font-medium", children: t.idType }),
|
|
15092
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
15093
|
+
"select",
|
|
15094
|
+
{
|
|
15095
|
+
id: "full-invoice-id-type",
|
|
15096
|
+
className: FIELD_CLASS,
|
|
15097
|
+
required: true,
|
|
15098
|
+
value: value.billingIdType,
|
|
15099
|
+
onChange: (e) => set("billingIdType", e.target.value),
|
|
15100
|
+
...invalid2("billingIdType"),
|
|
15101
|
+
children: ID_TYPES.map((type) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("option", { value: type, children: t.idTypeOptions[type] }, type))
|
|
15102
|
+
}
|
|
15103
|
+
),
|
|
15104
|
+
error("billingIdType")
|
|
15105
|
+
] }),
|
|
15106
|
+
!isSpanishNif && /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "space-y-1", children: [
|
|
15107
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("label", { htmlFor: "full-invoice-id-country", className: "text-sm font-medium", children: t.idCountry }),
|
|
15108
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
|
|
15109
|
+
"select",
|
|
15110
|
+
{
|
|
15111
|
+
id: "full-invoice-id-country",
|
|
15112
|
+
className: FIELD_CLASS,
|
|
15113
|
+
required: true,
|
|
15114
|
+
value: value.billingIdCountry,
|
|
15115
|
+
onChange: (e) => set("billingIdCountry", e.target.value),
|
|
15116
|
+
...invalid2("billingIdCountry"),
|
|
15117
|
+
children: [
|
|
15118
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("option", { value: "", disabled: true, children: t.chooseCountry }),
|
|
15119
|
+
countries.map((c) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("option", { value: c.code, children: c.name }, c.code))
|
|
15120
|
+
]
|
|
15121
|
+
}
|
|
15122
|
+
),
|
|
15123
|
+
error("billingIdCountry")
|
|
15124
|
+
] }),
|
|
15125
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "space-y-1", children: [
|
|
15126
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("label", { htmlFor: "full-invoice-nif", className: "text-sm font-medium", children: isSpanishNif ? t.spanishNif : t.documentNumber }),
|
|
15127
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
15128
|
+
"input",
|
|
15129
|
+
{
|
|
15130
|
+
id: "full-invoice-nif",
|
|
15131
|
+
className: FIELD_CLASS,
|
|
15132
|
+
required: true,
|
|
15133
|
+
value: value.billingNif,
|
|
15134
|
+
onChange: (e) => set("billingNif", e.target.value),
|
|
15135
|
+
...invalid2("billingNif")
|
|
15136
|
+
}
|
|
15137
|
+
),
|
|
15138
|
+
error("billingNif")
|
|
15139
|
+
] }),
|
|
15140
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "space-y-1", children: [
|
|
15141
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("label", { htmlFor: "full-invoice-name", className: "text-sm font-medium", children: t.name }),
|
|
15142
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
15143
|
+
"input",
|
|
15144
|
+
{
|
|
15145
|
+
id: "full-invoice-name",
|
|
15146
|
+
className: FIELD_CLASS,
|
|
15147
|
+
required: true,
|
|
15148
|
+
value: value.billingName,
|
|
15149
|
+
onChange: (e) => set("billingName", e.target.value),
|
|
15150
|
+
...invalid2("billingName")
|
|
15151
|
+
}
|
|
15152
|
+
),
|
|
15153
|
+
error("billingName")
|
|
15154
|
+
] }),
|
|
15155
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "space-y-1 sm:col-span-2", children: [
|
|
15156
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("label", { htmlFor: "full-invoice-street", className: "text-sm font-medium", children: t.street }),
|
|
15157
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
15158
|
+
"input",
|
|
15159
|
+
{
|
|
15160
|
+
id: "full-invoice-street",
|
|
15161
|
+
className: FIELD_CLASS,
|
|
15162
|
+
required: true,
|
|
15163
|
+
value: value.street,
|
|
15164
|
+
onChange: (e) => set("street", e.target.value),
|
|
15165
|
+
...invalid2("address")
|
|
15166
|
+
}
|
|
15167
|
+
)
|
|
15168
|
+
] }),
|
|
15169
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "space-y-1", children: [
|
|
15170
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("label", { htmlFor: "full-invoice-postal-code", className: "text-sm font-medium", children: t.postalCode }),
|
|
15171
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
15172
|
+
"input",
|
|
15173
|
+
{
|
|
15174
|
+
id: "full-invoice-postal-code",
|
|
15175
|
+
className: FIELD_CLASS,
|
|
15176
|
+
required: true,
|
|
15177
|
+
value: value.postalCode,
|
|
15178
|
+
onChange: (e) => set("postalCode", e.target.value)
|
|
15179
|
+
}
|
|
15180
|
+
)
|
|
15181
|
+
] }),
|
|
15182
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "space-y-1", children: [
|
|
15183
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("label", { htmlFor: "full-invoice-city", className: "text-sm font-medium", children: t.city }),
|
|
15184
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
15185
|
+
"input",
|
|
15186
|
+
{
|
|
15187
|
+
id: "full-invoice-city",
|
|
15188
|
+
className: FIELD_CLASS,
|
|
15189
|
+
required: true,
|
|
15190
|
+
value: value.city,
|
|
15191
|
+
onChange: (e) => set("city", e.target.value)
|
|
15192
|
+
}
|
|
15193
|
+
)
|
|
15194
|
+
] }),
|
|
15195
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "space-y-1", children: [
|
|
15196
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("label", { htmlFor: "full-invoice-country", className: "text-sm font-medium", children: t.country }),
|
|
15197
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
15198
|
+
"select",
|
|
15199
|
+
{
|
|
15200
|
+
id: "full-invoice-country",
|
|
15201
|
+
className: FIELD_CLASS,
|
|
15202
|
+
required: true,
|
|
15203
|
+
value: value.country,
|
|
15204
|
+
onChange: (e) => set("country", e.target.value),
|
|
15205
|
+
children: countries.map((c) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("option", { value: c.code, children: c.name }, c.code))
|
|
15206
|
+
}
|
|
15207
|
+
)
|
|
15208
|
+
] }),
|
|
15209
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "sm:col-span-2", children: error("address") })
|
|
14904
15210
|
] })
|
|
14905
15211
|
] });
|
|
14906
15212
|
}
|
|
@@ -14912,13 +15218,17 @@ function OrderConfirmation({
|
|
|
14912
15218
|
CartSummary,
|
|
14913
15219
|
CheckoutForm,
|
|
14914
15220
|
CheckoutLoginPrompt,
|
|
15221
|
+
DEFAULT_INVOICE_COUNTRIES,
|
|
14915
15222
|
DEFAULT_SHOP_ERROR_FALLBACK_MESSAGE,
|
|
14916
15223
|
DEFAULT_SHOP_ERROR_MESSAGES,
|
|
14917
15224
|
DEFAULT_SHOP_PRICE_BANDS,
|
|
14918
15225
|
DEFAULT_TRUST_ICONS,
|
|
15226
|
+
EMPTY_FULL_INVOICE_VALUE,
|
|
14919
15227
|
FaqAccordion,
|
|
15228
|
+
FullInvoiceFields,
|
|
14920
15229
|
MarkdownRenderer,
|
|
14921
15230
|
OrderConfirmation,
|
|
15231
|
+
OrderInvoiceLink,
|
|
14922
15232
|
PageBlocks,
|
|
14923
15233
|
PageCardGrid,
|
|
14924
15234
|
ParentPage,
|
|
@@ -14935,10 +15245,13 @@ function OrderConfirmation({
|
|
|
14935
15245
|
formatPrice,
|
|
14936
15246
|
getShopErrorMessage,
|
|
14937
15247
|
isAllowedYouTubeHost,
|
|
15248
|
+
isOverSimplifiedInvoiceCap,
|
|
14938
15249
|
markdownToSafeHtml,
|
|
14939
15250
|
readingTime,
|
|
14940
15251
|
sanitizeHtml,
|
|
14941
|
-
|
|
15252
|
+
shopIssuesInvoices,
|
|
15253
|
+
shouldRenderShopFilters,
|
|
15254
|
+
toCheckoutInvoiceFields
|
|
14942
15255
|
});
|
|
14943
15256
|
/*! Bundled license information:
|
|
14944
15257
|
|