@reblu/site-blocks 0.6.0 → 0.8.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/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
+ import { ShopErrorCode, PageDetail, PageListItem, ShopProductListItem, ShopFacets, ShopOrder } from '@reblu/site-contracts';
1
2
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { PageDetail, PageListItem, ShopProductListItem, ShopFacets, ShopOrder } from '@reblu/site-contracts';
3
3
  import { ReactNode, FormEvent } from 'react';
4
4
 
5
5
  declare function readingTime(content: string | null | undefined): number | null;
@@ -29,6 +29,30 @@ interface ShareUrls {
29
29
  }
30
30
  declare function buildShareUrls(url: string, title: string): ShareUrls;
31
31
 
32
+ /**
33
+ * Default Spanish copy for every stable `ShopErrorCode` (REB-836) the shop
34
+ * write endpoints (`checkout`/`validateCart`/`applyDiscount`) may return in
35
+ * the error body's optional `code` field — see `ApiError.body.code` in
36
+ * `@reblu/site-client`. A SITE overrides any subset through
37
+ * {@link getShopErrorMessage}'s `overrides` parameter, or ignores `code`
38
+ * entirely and reads `ApiError.message` as before (REB-836 is additive).
39
+ */
40
+ declare const DEFAULT_SHOP_ERROR_MESSAGES: Record<ShopErrorCode, string>;
41
+ /** Fallback copy used when `code` is missing or not recognised. */
42
+ declare const DEFAULT_SHOP_ERROR_FALLBACK_MESSAGE = "No se ha podido completar la operaci\u00F3n. Int\u00E9ntalo de nuevo.";
43
+ /**
44
+ * Resolves the user-facing message for a checkout/validate-cart/apply-discount
45
+ * error `code` (REB-836) — e.g. `ApiError.body?.code` from `@reblu/site-client`.
46
+ *
47
+ * @param code - The stable error code, or `null`/`undefined` when the response
48
+ * carried none (an older base-api, or a non-shop error).
49
+ * @param overrides - Replaces any subset of {@link DEFAULT_SHOP_ERROR_MESSAGES}
50
+ * without having to restate every other code — e.g. for a non-Spanish SITE.
51
+ * @param fallback - Used when `code` is missing or unrecognised.
52
+ * Defaults to {@link DEFAULT_SHOP_ERROR_FALLBACK_MESSAGE}.
53
+ */
54
+ declare function getShopErrorMessage(code: string | null | undefined, overrides?: Partial<Record<ShopErrorCode, string>>, fallback?: string): string;
55
+
32
56
  /**
33
57
  * Canonical Blog markdown → **safe HTML** pipeline for the Reblu SITE SDK.
34
58
  *
@@ -384,47 +408,6 @@ interface ShopFiltersProps {
384
408
  declare function shouldRenderShopFilters(facets: ShopFacets, active?: ShopFiltersActive): boolean;
385
409
  declare function ShopFilters({ facets, hrefs, active, onChange, priceBands, labels, currencyCode, locale, className, }: ShopFiltersProps): react_jsx_runtime.JSX.Element | null;
386
410
 
387
- /**
388
- * `AddToCartButton` — presentational add-to-cart CTA (REB-829). RSC-safe by
389
- * construction (same contract as `ShopFilters`'s `OptionLink`): passing
390
- * `onAddToCart` only makes sense from a Client Component, but the component
391
- * itself carries no `'use client'` directive, so a Server Component may
392
- * still render it WITHOUT the prop (e.g. a disabled preview state).
393
- */
394
- interface AddToCartButtonLabels {
395
- add: string;
396
- adding: string;
397
- outOfStock: string;
398
- }
399
- interface AddToCartButtonProps {
400
- onAddToCart?: () => void;
401
- disabled?: boolean;
402
- outOfStock?: boolean;
403
- /** True while the add-to-cart call (or a navigation it triggers) is in flight. */
404
- pending?: boolean;
405
- labels?: Partial<AddToCartButtonLabels>;
406
- className?: string;
407
- }
408
- declare function AddToCartButton({ onAddToCart, disabled, outOfStock, pending, labels, className, }: AddToCartButtonProps): react_jsx_runtime.JSX.Element;
409
-
410
- /**
411
- * `CartIcon` — presentational cart badge/link (REB-829). RSC-safe (plain
412
- * `<a href>`, no hooks) — a Server Component can render it directly with a
413
- * value already computed server-side; a Client Component drives `itemCount`
414
- * from `@reblu/site-next/cart`'s `useCart().itemCount`.
415
- */
416
- interface CartIconLabels {
417
- cart: string;
418
- itemsSuffix: (count: number) => string;
419
- }
420
- interface CartIconProps {
421
- itemCount: number;
422
- href: string;
423
- labels?: Partial<CartIconLabels>;
424
- className?: string;
425
- }
426
- declare function CartIcon({ itemCount, href, labels, className }: CartIconProps): react_jsx_runtime.JSX.Element;
427
-
428
411
  /**
429
412
  * `CartLineList` — presentational cart lines (REB-829), container/
430
413
  * presentational split: it takes `items` + optional `onQuantityChange`/
@@ -454,6 +437,8 @@ interface CartLineListLabels {
454
437
  increase: string;
455
438
  remove: string;
456
439
  unitPriceSuffix: string;
440
+ /** REB-837 — default copy for `notice={true}`. */
441
+ cancelledNotice: string;
457
442
  }
458
443
  interface CartLineListProps {
459
444
  items: CartLineItemView[];
@@ -466,12 +451,18 @@ interface CartLineListProps {
466
451
  * only renders the live region.
467
452
  */
468
453
  liveMessage?: string;
454
+ /**
455
+ * REB-837 — a notice shown above the lines. `true` renders the default
456
+ * "pago cancelado" copy (`labels.cancelledNotice`); pass any other
457
+ * `ReactNode` for custom content, or omit/`false` to render nothing.
458
+ */
459
+ notice?: boolean | React.ReactNode;
469
460
  labels?: Partial<CartLineListLabels>;
470
461
  currencyCode?: string;
471
462
  locale?: string;
472
463
  className?: string;
473
464
  }
474
- declare function CartLineList({ items, onQuantityChange, onRemove, liveMessage, labels, currencyCode, locale, className, }: CartLineListProps): react_jsx_runtime.JSX.Element;
465
+ declare function CartLineList({ items, onQuantityChange, onRemove, liveMessage, notice, labels, currencyCode, locale, className, }: CartLineListProps): react_jsx_runtime.JSX.Element;
475
466
 
476
467
  /**
477
468
  * `CartSummary` — presentational price breakdown (REB-829): subtotal,
@@ -492,6 +483,8 @@ interface CartSummaryLabels {
492
483
  */
493
484
  shippingCalculated: string;
494
485
  total: string;
486
+ /** REB-837 — default copy for `notice={true}`. */
487
+ cancelledNotice: string;
495
488
  }
496
489
  interface CartSummaryProps {
497
490
  /** Integer cents. */
@@ -506,12 +499,70 @@ interface CartSummaryProps {
506
499
  shippingEnabled?: boolean;
507
500
  /** Integer cents — the final charged amount. */
508
501
  total: number;
502
+ /**
503
+ * REB-837 — a notice shown above the breakdown. `true` renders the
504
+ * default "pago cancelado" copy (`labels.cancelledNotice`) — the standard
505
+ * message for a visitor returning from a cancelled Stripe Checkout
506
+ * session (`useCheckoutReturn().status === 'cancelled'`). Pass any other
507
+ * `ReactNode` for custom content, or omit/`false` to render nothing.
508
+ */
509
+ notice?: boolean | React.ReactNode;
509
510
  labels?: Partial<CartSummaryLabels>;
510
511
  currencyCode?: string;
511
512
  locale?: string;
512
513
  className?: string;
513
514
  }
514
- declare function CartSummary({ subtotal, discount, discountCode, shipping, shippingEnabled, total, labels, currencyCode, locale, className, }: CartSummaryProps): react_jsx_runtime.JSX.Element;
515
+ declare function CartSummary({ subtotal, discount, discountCode, shipping, shippingEnabled, total, notice, labels, currencyCode, locale, className, }: CartSummaryProps): react_jsx_runtime.JSX.Element;
516
+
517
+ /**
518
+ * `AddedToCartToast` — add-to-cart feedback toast CONTENT (REB-837). Pure
519
+ * presentational, no hooks.
520
+ *
521
+ * Deliberately does NOT import `@reblu/site-ui`'s `Toast` (the root entry):
522
+ * that barrel also re-exports `Button`, which this package's own
523
+ * `test/rsc-safety.test.ts` bans from the RSC-safe root entry (a Radix
524
+ * `Slot` copy whose server-evaluability depends on a CONSUMER's resolution —
525
+ * see that test's docblock). `Toast`'s small shell is reproduced inline here
526
+ * with `cn` from the certified-React-free `@reblu/site-ui/utils`, same
527
+ * pattern as every other organism in this file's sibling components. A SITE
528
+ * that wants `@reblu/site-ui`'s standalone `Toast` directly still can — the
529
+ * two are independent, not layered.
530
+ *
531
+ * This is the CONTENT to pass into whatever toaster the consuming SITE
532
+ * already mounts (sonner's `toast.custom((id) => <AddedToCartToast ... />,
533
+ * { id: `cart-add-${productId}` })` — a stable per-product id lets a repeat
534
+ * add UPDATE the same toast instead of stacking a new one). It never renders
535
+ * its own `aria-live` region: the host toaster's live region owns
536
+ * announcement, so adding a second one here would double-announce.
537
+ *
538
+ * `imageUrl` only renders a thumbnail when it's a real, non-blank string —
539
+ * an empty/whitespace value (a product with no image) renders no `<img>`
540
+ * rather than a broken one.
541
+ *
542
+ * `cartHref` is a plain `href` the consumer builds, rendered as a real
543
+ * `<a>` — never a `useRouter().push(...)` call, which breaks outside the
544
+ * Next.js App Router and in non-router test renders.
545
+ */
546
+ type AddedToCartToastStatus = 'success' | 'error' | 'outOfStock';
547
+ interface AddedToCartToastLabels {
548
+ success: string;
549
+ error: string;
550
+ outOfStock: string;
551
+ viewCart: string;
552
+ }
553
+ interface AddedToCartToastProps {
554
+ status?: AddedToCartToastStatus;
555
+ productName: string;
556
+ /** The resulting line quantity, e.g. from `addItem`'s outcome. Only shown when > 1. */
557
+ quantity?: number;
558
+ /** Rendered as a thumbnail ONLY when non-empty after trimming. */
559
+ imageUrl?: string;
560
+ /** "Ver carrito" link target — a real href, not a router navigation. */
561
+ cartHref: string;
562
+ labels?: Partial<AddedToCartToastLabels>;
563
+ className?: string;
564
+ }
565
+ declare function AddedToCartToast({ status, productName, quantity, imageUrl, cartHref, labels, className, }: AddedToCartToastProps): react_jsx_runtime.JSX.Element;
515
566
 
516
567
  /**
517
568
  * `CheckoutLoginPrompt` — the "login prompt hook" the checkout flow needs
@@ -594,6 +645,14 @@ interface CheckoutFormProps {
594
645
  contact: CheckoutContactValues;
595
646
  onContactChange: (values: CheckoutContactValues) => void;
596
647
  contactErrors?: CheckoutContactErrors;
648
+ /** Country asserted by the SITE for national phone input; omit rather than guessing. */
649
+ phoneRegion?: string;
650
+ /** Optional raw checkout API error body; only INVALID_INPUT/customerPhone marks the phone field. */
651
+ checkoutError?: {
652
+ code?: unknown;
653
+ error?: unknown;
654
+ details?: unknown;
655
+ } | null;
597
656
  discountCode: string;
598
657
  onDiscountCodeChange: (value: string) => void;
599
658
  onApplyDiscount: () => void;
@@ -619,18 +678,23 @@ interface CheckoutFormProps {
619
678
  locale?: string;
620
679
  className?: string;
621
680
  }
622
- declare function CheckoutForm({ contact, onContactChange, contactErrors, discountCode, onDiscountCodeChange, onApplyDiscount, onRemoveDiscount, appliedDiscount, discountApplying, discountError, loginPrompt, children, submitting, submitDisabled, onSubmit, labels, currencyCode, locale, className, }: CheckoutFormProps): react_jsx_runtime.JSX.Element;
681
+ declare function CheckoutForm({ contact, onContactChange, contactErrors, phoneRegion, checkoutError, discountCode, onDiscountCodeChange, onApplyDiscount, onRemoveDiscount, appliedDiscount, discountApplying, discountError, loginPrompt, children, submitting, submitDisabled, onSubmit, labels, currencyCode, locale, className, }: CheckoutFormProps): react_jsx_runtime.JSX.Element;
623
682
 
624
683
  /**
625
- * `OrderConfirmation` — presentational order-confirmation view (REB-829).
626
- * Pure data + status in, RSC-safe (no hooks). The consuming SITE owns the
627
- * actual lookup/polling (`client.shop.order(sessionId)` via a Route Handler
628
- * built from `createShopOrderRoute`, retried while `'polling'` — the Stripe
629
- * webhook that creates the order may not have landed yet) and passes the
630
- * resulting `status`/`order` in.
684
+ * `OrderConfirmation` — presentational order-confirmation view (REB-829,
685
+ * extended REB-837). Pure data + status in, RSC-safe (no hooks). The
686
+ * consuming SITE owns the actual lookup/polling — today via
687
+ * `@reblu/site-next/shop`'s `useShopOrderStatus(sessionId)` hook — and
688
+ * passes the resulting `status`/`order` straight through.
689
+ *
690
+ * Backward compatible: the original three states (`polling`, `found`,
691
+ * `timeout`) keep their EXACT existing copy and behavior. REB-837 adds
692
+ * `useShopOrderStatus`'s native vocabulary (`loading`/`paid` are drop-in
693
+ * aliases for `polling`/`found`) plus five new terminal states with their
694
+ * own default Spanish copy, all overridable via `labels`.
631
695
  */
632
696
  type OrderConfirmationOrder = ShopOrder;
633
- type OrderConfirmationStatus = 'polling' | 'found' | 'timeout';
697
+ type OrderConfirmationStatus = 'polling' | 'found' | 'timeout' | 'loading' | 'paid' | 'pending_timeout' | 'failed' | 'refunded' | 'partially_refunded' | 'not_found' | 'error';
634
698
  interface OrderConfirmationLabels {
635
699
  pollingTitle: string;
636
700
  pollingDescription: string;
@@ -642,17 +706,38 @@ interface OrderConfirmationLabels {
642
706
  totalLabel: string;
643
707
  confirmationEmailPrefix: string;
644
708
  sessionReferenceLabel: string;
709
+ /** REB-837 */
710
+ failedTitle: string;
711
+ failedDescription: string;
712
+ backToCartLabel: string;
713
+ refundedTitle: string;
714
+ refundedDescription: string;
715
+ partiallyRefundedTitle: string;
716
+ partiallyRefundedDescription: string;
717
+ pendingTimeoutTitle: string;
718
+ pendingTimeoutDescription: string;
719
+ recheckLabel: string;
720
+ notFoundTitle: string;
721
+ notFoundDescription: string;
722
+ errorTitle: string;
723
+ errorDescription: string;
724
+ /** REB-837 review fix — label for the neutral order-number-only reference shown on refunded/pending_timeout. */
725
+ orderReferenceLabel: string;
645
726
  }
646
727
  interface OrderConfirmationProps {
647
728
  status: OrderConfirmationStatus;
648
729
  order: OrderConfirmationOrder | null;
649
- /** Shown as a fallback reference when `status === 'timeout'` and no order was found. */
730
+ /** Shown as a fallback reference when there is no order to display. */
650
731
  sessionId?: string;
732
+ /** "Volver al carrito" target, shown on `status === 'failed'`. Omit to render no link. */
733
+ cartHref?: string;
734
+ /** Called by the "Volver a comprobar" button on `pending_timeout`/`error`. Omit to render no button. */
735
+ onRecheck?: () => void;
651
736
  labels?: Partial<OrderConfirmationLabels>;
652
737
  currencyCode?: string;
653
738
  locale?: string;
654
739
  className?: string;
655
740
  }
656
- declare function OrderConfirmation({ status, order, sessionId, labels, currencyCode, locale, className, }: OrderConfirmationProps): react_jsx_runtime.JSX.Element;
741
+ declare function OrderConfirmation({ status, order, sessionId, cartHref, onRecheck, labels, currencyCode, locale, className, }: OrderConfirmationProps): react_jsx_runtime.JSX.Element;
657
742
 
658
- export { ALLOWED_YOUTUBE_HOSTS, AddToCartButton, type AddToCartButtonLabels, type AddToCartButtonProps, CartIcon, type CartIconLabels, type CartIconProps, type CartLineItemView, CartLineList, type CartLineListLabels, type CartLineListProps, CartSummary, type CartSummaryLabels, type CartSummaryProps, type CheckoutAppliedDiscount, type CheckoutContactErrors, type CheckoutContactValues, CheckoutForm, type CheckoutFormLabels, type CheckoutFormProps, CheckoutLoginPrompt, type CheckoutLoginPromptLabels, type CheckoutLoginPromptProps, DEFAULT_SHOP_PRICE_BANDS, MarkdownRenderer, type MarkdownRendererProps, OrderConfirmation, type OrderConfirmationLabels, type OrderConfirmationOrder, type OrderConfirmationProps, type OrderConfirmationStatus, ProductCard, type ProductCardProps, ProfileCard, type ProfileCardProps, SafeHtml, type SafeHtmlProps, type ShareUrls, type ShopFilterPriceBand, ShopFilters, type ShopFiltersActive, type ShopFiltersHrefs, type ShopFiltersLabels, type ShopFiltersProps, Specialty, type SpecialtyProps, Treatment, type TreatmentProps, buildShareUrls, formatPrice, isAllowedYouTubeHost, markdownToSafeHtml, readingTime, sanitizeHtml, shouldRenderShopFilters };
743
+ export { ALLOWED_YOUTUBE_HOSTS, AddedToCartToast, type AddedToCartToastLabels, type AddedToCartToastProps, type AddedToCartToastStatus, type CartLineItemView, CartLineList, type CartLineListLabels, type CartLineListProps, CartSummary, type CartSummaryLabels, type CartSummaryProps, type CheckoutAppliedDiscount, type CheckoutContactErrors, type CheckoutContactValues, CheckoutForm, type CheckoutFormLabels, type CheckoutFormProps, CheckoutLoginPrompt, type CheckoutLoginPromptLabels, type CheckoutLoginPromptProps, DEFAULT_SHOP_ERROR_FALLBACK_MESSAGE, DEFAULT_SHOP_ERROR_MESSAGES, DEFAULT_SHOP_PRICE_BANDS, MarkdownRenderer, type MarkdownRendererProps, OrderConfirmation, type OrderConfirmationLabels, type OrderConfirmationOrder, type OrderConfirmationProps, type OrderConfirmationStatus, ProductCard, type ProductCardProps, ProfileCard, type ProfileCardProps, SafeHtml, type SafeHtmlProps, type ShareUrls, type ShopFilterPriceBand, ShopFilters, type ShopFiltersActive, type ShopFiltersHrefs, type ShopFiltersLabels, type ShopFiltersProps, Specialty, type SpecialtyProps, Treatment, type TreatmentProps, buildShareUrls, formatPrice, getShopErrorMessage, isAllowedYouTubeHost, markdownToSafeHtml, readingTime, sanitizeHtml, shouldRenderShopFilters };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
+ import { ShopErrorCode, PageDetail, PageListItem, ShopProductListItem, ShopFacets, ShopOrder } from '@reblu/site-contracts';
1
2
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { PageDetail, PageListItem, ShopProductListItem, ShopFacets, ShopOrder } from '@reblu/site-contracts';
3
3
  import { ReactNode, FormEvent } from 'react';
4
4
 
5
5
  declare function readingTime(content: string | null | undefined): number | null;
@@ -29,6 +29,30 @@ interface ShareUrls {
29
29
  }
30
30
  declare function buildShareUrls(url: string, title: string): ShareUrls;
31
31
 
32
+ /**
33
+ * Default Spanish copy for every stable `ShopErrorCode` (REB-836) the shop
34
+ * write endpoints (`checkout`/`validateCart`/`applyDiscount`) may return in
35
+ * the error body's optional `code` field — see `ApiError.body.code` in
36
+ * `@reblu/site-client`. A SITE overrides any subset through
37
+ * {@link getShopErrorMessage}'s `overrides` parameter, or ignores `code`
38
+ * entirely and reads `ApiError.message` as before (REB-836 is additive).
39
+ */
40
+ declare const DEFAULT_SHOP_ERROR_MESSAGES: Record<ShopErrorCode, string>;
41
+ /** Fallback copy used when `code` is missing or not recognised. */
42
+ declare const DEFAULT_SHOP_ERROR_FALLBACK_MESSAGE = "No se ha podido completar la operaci\u00F3n. Int\u00E9ntalo de nuevo.";
43
+ /**
44
+ * Resolves the user-facing message for a checkout/validate-cart/apply-discount
45
+ * error `code` (REB-836) — e.g. `ApiError.body?.code` from `@reblu/site-client`.
46
+ *
47
+ * @param code - The stable error code, or `null`/`undefined` when the response
48
+ * carried none (an older base-api, or a non-shop error).
49
+ * @param overrides - Replaces any subset of {@link DEFAULT_SHOP_ERROR_MESSAGES}
50
+ * without having to restate every other code — e.g. for a non-Spanish SITE.
51
+ * @param fallback - Used when `code` is missing or unrecognised.
52
+ * Defaults to {@link DEFAULT_SHOP_ERROR_FALLBACK_MESSAGE}.
53
+ */
54
+ declare function getShopErrorMessage(code: string | null | undefined, overrides?: Partial<Record<ShopErrorCode, string>>, fallback?: string): string;
55
+
32
56
  /**
33
57
  * Canonical Blog markdown → **safe HTML** pipeline for the Reblu SITE SDK.
34
58
  *
@@ -384,47 +408,6 @@ interface ShopFiltersProps {
384
408
  declare function shouldRenderShopFilters(facets: ShopFacets, active?: ShopFiltersActive): boolean;
385
409
  declare function ShopFilters({ facets, hrefs, active, onChange, priceBands, labels, currencyCode, locale, className, }: ShopFiltersProps): react_jsx_runtime.JSX.Element | null;
386
410
 
387
- /**
388
- * `AddToCartButton` — presentational add-to-cart CTA (REB-829). RSC-safe by
389
- * construction (same contract as `ShopFilters`'s `OptionLink`): passing
390
- * `onAddToCart` only makes sense from a Client Component, but the component
391
- * itself carries no `'use client'` directive, so a Server Component may
392
- * still render it WITHOUT the prop (e.g. a disabled preview state).
393
- */
394
- interface AddToCartButtonLabels {
395
- add: string;
396
- adding: string;
397
- outOfStock: string;
398
- }
399
- interface AddToCartButtonProps {
400
- onAddToCart?: () => void;
401
- disabled?: boolean;
402
- outOfStock?: boolean;
403
- /** True while the add-to-cart call (or a navigation it triggers) is in flight. */
404
- pending?: boolean;
405
- labels?: Partial<AddToCartButtonLabels>;
406
- className?: string;
407
- }
408
- declare function AddToCartButton({ onAddToCart, disabled, outOfStock, pending, labels, className, }: AddToCartButtonProps): react_jsx_runtime.JSX.Element;
409
-
410
- /**
411
- * `CartIcon` — presentational cart badge/link (REB-829). RSC-safe (plain
412
- * `<a href>`, no hooks) — a Server Component can render it directly with a
413
- * value already computed server-side; a Client Component drives `itemCount`
414
- * from `@reblu/site-next/cart`'s `useCart().itemCount`.
415
- */
416
- interface CartIconLabels {
417
- cart: string;
418
- itemsSuffix: (count: number) => string;
419
- }
420
- interface CartIconProps {
421
- itemCount: number;
422
- href: string;
423
- labels?: Partial<CartIconLabels>;
424
- className?: string;
425
- }
426
- declare function CartIcon({ itemCount, href, labels, className }: CartIconProps): react_jsx_runtime.JSX.Element;
427
-
428
411
  /**
429
412
  * `CartLineList` — presentational cart lines (REB-829), container/
430
413
  * presentational split: it takes `items` + optional `onQuantityChange`/
@@ -454,6 +437,8 @@ interface CartLineListLabels {
454
437
  increase: string;
455
438
  remove: string;
456
439
  unitPriceSuffix: string;
440
+ /** REB-837 — default copy for `notice={true}`. */
441
+ cancelledNotice: string;
457
442
  }
458
443
  interface CartLineListProps {
459
444
  items: CartLineItemView[];
@@ -466,12 +451,18 @@ interface CartLineListProps {
466
451
  * only renders the live region.
467
452
  */
468
453
  liveMessage?: string;
454
+ /**
455
+ * REB-837 — a notice shown above the lines. `true` renders the default
456
+ * "pago cancelado" copy (`labels.cancelledNotice`); pass any other
457
+ * `ReactNode` for custom content, or omit/`false` to render nothing.
458
+ */
459
+ notice?: boolean | React.ReactNode;
469
460
  labels?: Partial<CartLineListLabels>;
470
461
  currencyCode?: string;
471
462
  locale?: string;
472
463
  className?: string;
473
464
  }
474
- declare function CartLineList({ items, onQuantityChange, onRemove, liveMessage, labels, currencyCode, locale, className, }: CartLineListProps): react_jsx_runtime.JSX.Element;
465
+ declare function CartLineList({ items, onQuantityChange, onRemove, liveMessage, notice, labels, currencyCode, locale, className, }: CartLineListProps): react_jsx_runtime.JSX.Element;
475
466
 
476
467
  /**
477
468
  * `CartSummary` — presentational price breakdown (REB-829): subtotal,
@@ -492,6 +483,8 @@ interface CartSummaryLabels {
492
483
  */
493
484
  shippingCalculated: string;
494
485
  total: string;
486
+ /** REB-837 — default copy for `notice={true}`. */
487
+ cancelledNotice: string;
495
488
  }
496
489
  interface CartSummaryProps {
497
490
  /** Integer cents. */
@@ -506,12 +499,70 @@ interface CartSummaryProps {
506
499
  shippingEnabled?: boolean;
507
500
  /** Integer cents — the final charged amount. */
508
501
  total: number;
502
+ /**
503
+ * REB-837 — a notice shown above the breakdown. `true` renders the
504
+ * default "pago cancelado" copy (`labels.cancelledNotice`) — the standard
505
+ * message for a visitor returning from a cancelled Stripe Checkout
506
+ * session (`useCheckoutReturn().status === 'cancelled'`). Pass any other
507
+ * `ReactNode` for custom content, or omit/`false` to render nothing.
508
+ */
509
+ notice?: boolean | React.ReactNode;
509
510
  labels?: Partial<CartSummaryLabels>;
510
511
  currencyCode?: string;
511
512
  locale?: string;
512
513
  className?: string;
513
514
  }
514
- declare function CartSummary({ subtotal, discount, discountCode, shipping, shippingEnabled, total, labels, currencyCode, locale, className, }: CartSummaryProps): react_jsx_runtime.JSX.Element;
515
+ declare function CartSummary({ subtotal, discount, discountCode, shipping, shippingEnabled, total, notice, labels, currencyCode, locale, className, }: CartSummaryProps): react_jsx_runtime.JSX.Element;
516
+
517
+ /**
518
+ * `AddedToCartToast` — add-to-cart feedback toast CONTENT (REB-837). Pure
519
+ * presentational, no hooks.
520
+ *
521
+ * Deliberately does NOT import `@reblu/site-ui`'s `Toast` (the root entry):
522
+ * that barrel also re-exports `Button`, which this package's own
523
+ * `test/rsc-safety.test.ts` bans from the RSC-safe root entry (a Radix
524
+ * `Slot` copy whose server-evaluability depends on a CONSUMER's resolution —
525
+ * see that test's docblock). `Toast`'s small shell is reproduced inline here
526
+ * with `cn` from the certified-React-free `@reblu/site-ui/utils`, same
527
+ * pattern as every other organism in this file's sibling components. A SITE
528
+ * that wants `@reblu/site-ui`'s standalone `Toast` directly still can — the
529
+ * two are independent, not layered.
530
+ *
531
+ * This is the CONTENT to pass into whatever toaster the consuming SITE
532
+ * already mounts (sonner's `toast.custom((id) => <AddedToCartToast ... />,
533
+ * { id: `cart-add-${productId}` })` — a stable per-product id lets a repeat
534
+ * add UPDATE the same toast instead of stacking a new one). It never renders
535
+ * its own `aria-live` region: the host toaster's live region owns
536
+ * announcement, so adding a second one here would double-announce.
537
+ *
538
+ * `imageUrl` only renders a thumbnail when it's a real, non-blank string —
539
+ * an empty/whitespace value (a product with no image) renders no `<img>`
540
+ * rather than a broken one.
541
+ *
542
+ * `cartHref` is a plain `href` the consumer builds, rendered as a real
543
+ * `<a>` — never a `useRouter().push(...)` call, which breaks outside the
544
+ * Next.js App Router and in non-router test renders.
545
+ */
546
+ type AddedToCartToastStatus = 'success' | 'error' | 'outOfStock';
547
+ interface AddedToCartToastLabels {
548
+ success: string;
549
+ error: string;
550
+ outOfStock: string;
551
+ viewCart: string;
552
+ }
553
+ interface AddedToCartToastProps {
554
+ status?: AddedToCartToastStatus;
555
+ productName: string;
556
+ /** The resulting line quantity, e.g. from `addItem`'s outcome. Only shown when > 1. */
557
+ quantity?: number;
558
+ /** Rendered as a thumbnail ONLY when non-empty after trimming. */
559
+ imageUrl?: string;
560
+ /** "Ver carrito" link target — a real href, not a router navigation. */
561
+ cartHref: string;
562
+ labels?: Partial<AddedToCartToastLabels>;
563
+ className?: string;
564
+ }
565
+ declare function AddedToCartToast({ status, productName, quantity, imageUrl, cartHref, labels, className, }: AddedToCartToastProps): react_jsx_runtime.JSX.Element;
515
566
 
516
567
  /**
517
568
  * `CheckoutLoginPrompt` — the "login prompt hook" the checkout flow needs
@@ -594,6 +645,14 @@ interface CheckoutFormProps {
594
645
  contact: CheckoutContactValues;
595
646
  onContactChange: (values: CheckoutContactValues) => void;
596
647
  contactErrors?: CheckoutContactErrors;
648
+ /** Country asserted by the SITE for national phone input; omit rather than guessing. */
649
+ phoneRegion?: string;
650
+ /** Optional raw checkout API error body; only INVALID_INPUT/customerPhone marks the phone field. */
651
+ checkoutError?: {
652
+ code?: unknown;
653
+ error?: unknown;
654
+ details?: unknown;
655
+ } | null;
597
656
  discountCode: string;
598
657
  onDiscountCodeChange: (value: string) => void;
599
658
  onApplyDiscount: () => void;
@@ -619,18 +678,23 @@ interface CheckoutFormProps {
619
678
  locale?: string;
620
679
  className?: string;
621
680
  }
622
- declare function CheckoutForm({ contact, onContactChange, contactErrors, discountCode, onDiscountCodeChange, onApplyDiscount, onRemoveDiscount, appliedDiscount, discountApplying, discountError, loginPrompt, children, submitting, submitDisabled, onSubmit, labels, currencyCode, locale, className, }: CheckoutFormProps): react_jsx_runtime.JSX.Element;
681
+ declare function CheckoutForm({ contact, onContactChange, contactErrors, phoneRegion, checkoutError, discountCode, onDiscountCodeChange, onApplyDiscount, onRemoveDiscount, appliedDiscount, discountApplying, discountError, loginPrompt, children, submitting, submitDisabled, onSubmit, labels, currencyCode, locale, className, }: CheckoutFormProps): react_jsx_runtime.JSX.Element;
623
682
 
624
683
  /**
625
- * `OrderConfirmation` — presentational order-confirmation view (REB-829).
626
- * Pure data + status in, RSC-safe (no hooks). The consuming SITE owns the
627
- * actual lookup/polling (`client.shop.order(sessionId)` via a Route Handler
628
- * built from `createShopOrderRoute`, retried while `'polling'` — the Stripe
629
- * webhook that creates the order may not have landed yet) and passes the
630
- * resulting `status`/`order` in.
684
+ * `OrderConfirmation` — presentational order-confirmation view (REB-829,
685
+ * extended REB-837). Pure data + status in, RSC-safe (no hooks). The
686
+ * consuming SITE owns the actual lookup/polling — today via
687
+ * `@reblu/site-next/shop`'s `useShopOrderStatus(sessionId)` hook — and
688
+ * passes the resulting `status`/`order` straight through.
689
+ *
690
+ * Backward compatible: the original three states (`polling`, `found`,
691
+ * `timeout`) keep their EXACT existing copy and behavior. REB-837 adds
692
+ * `useShopOrderStatus`'s native vocabulary (`loading`/`paid` are drop-in
693
+ * aliases for `polling`/`found`) plus five new terminal states with their
694
+ * own default Spanish copy, all overridable via `labels`.
631
695
  */
632
696
  type OrderConfirmationOrder = ShopOrder;
633
- type OrderConfirmationStatus = 'polling' | 'found' | 'timeout';
697
+ type OrderConfirmationStatus = 'polling' | 'found' | 'timeout' | 'loading' | 'paid' | 'pending_timeout' | 'failed' | 'refunded' | 'partially_refunded' | 'not_found' | 'error';
634
698
  interface OrderConfirmationLabels {
635
699
  pollingTitle: string;
636
700
  pollingDescription: string;
@@ -642,17 +706,38 @@ interface OrderConfirmationLabels {
642
706
  totalLabel: string;
643
707
  confirmationEmailPrefix: string;
644
708
  sessionReferenceLabel: string;
709
+ /** REB-837 */
710
+ failedTitle: string;
711
+ failedDescription: string;
712
+ backToCartLabel: string;
713
+ refundedTitle: string;
714
+ refundedDescription: string;
715
+ partiallyRefundedTitle: string;
716
+ partiallyRefundedDescription: string;
717
+ pendingTimeoutTitle: string;
718
+ pendingTimeoutDescription: string;
719
+ recheckLabel: string;
720
+ notFoundTitle: string;
721
+ notFoundDescription: string;
722
+ errorTitle: string;
723
+ errorDescription: string;
724
+ /** REB-837 review fix — label for the neutral order-number-only reference shown on refunded/pending_timeout. */
725
+ orderReferenceLabel: string;
645
726
  }
646
727
  interface OrderConfirmationProps {
647
728
  status: OrderConfirmationStatus;
648
729
  order: OrderConfirmationOrder | null;
649
- /** Shown as a fallback reference when `status === 'timeout'` and no order was found. */
730
+ /** Shown as a fallback reference when there is no order to display. */
650
731
  sessionId?: string;
732
+ /** "Volver al carrito" target, shown on `status === 'failed'`. Omit to render no link. */
733
+ cartHref?: string;
734
+ /** Called by the "Volver a comprobar" button on `pending_timeout`/`error`. Omit to render no button. */
735
+ onRecheck?: () => void;
651
736
  labels?: Partial<OrderConfirmationLabels>;
652
737
  currencyCode?: string;
653
738
  locale?: string;
654
739
  className?: string;
655
740
  }
656
- declare function OrderConfirmation({ status, order, sessionId, labels, currencyCode, locale, className, }: OrderConfirmationProps): react_jsx_runtime.JSX.Element;
741
+ declare function OrderConfirmation({ status, order, sessionId, cartHref, onRecheck, labels, currencyCode, locale, className, }: OrderConfirmationProps): react_jsx_runtime.JSX.Element;
657
742
 
658
- export { ALLOWED_YOUTUBE_HOSTS, AddToCartButton, type AddToCartButtonLabels, type AddToCartButtonProps, CartIcon, type CartIconLabels, type CartIconProps, type CartLineItemView, CartLineList, type CartLineListLabels, type CartLineListProps, CartSummary, type CartSummaryLabels, type CartSummaryProps, type CheckoutAppliedDiscount, type CheckoutContactErrors, type CheckoutContactValues, CheckoutForm, type CheckoutFormLabels, type CheckoutFormProps, CheckoutLoginPrompt, type CheckoutLoginPromptLabels, type CheckoutLoginPromptProps, DEFAULT_SHOP_PRICE_BANDS, MarkdownRenderer, type MarkdownRendererProps, OrderConfirmation, type OrderConfirmationLabels, type OrderConfirmationOrder, type OrderConfirmationProps, type OrderConfirmationStatus, ProductCard, type ProductCardProps, ProfileCard, type ProfileCardProps, SafeHtml, type SafeHtmlProps, type ShareUrls, type ShopFilterPriceBand, ShopFilters, type ShopFiltersActive, type ShopFiltersHrefs, type ShopFiltersLabels, type ShopFiltersProps, Specialty, type SpecialtyProps, Treatment, type TreatmentProps, buildShareUrls, formatPrice, isAllowedYouTubeHost, markdownToSafeHtml, readingTime, sanitizeHtml, shouldRenderShopFilters };
743
+ export { ALLOWED_YOUTUBE_HOSTS, AddedToCartToast, type AddedToCartToastLabels, type AddedToCartToastProps, type AddedToCartToastStatus, type CartLineItemView, CartLineList, type CartLineListLabels, type CartLineListProps, CartSummary, type CartSummaryLabels, type CartSummaryProps, type CheckoutAppliedDiscount, type CheckoutContactErrors, type CheckoutContactValues, CheckoutForm, type CheckoutFormLabels, type CheckoutFormProps, CheckoutLoginPrompt, type CheckoutLoginPromptLabels, type CheckoutLoginPromptProps, DEFAULT_SHOP_ERROR_FALLBACK_MESSAGE, DEFAULT_SHOP_ERROR_MESSAGES, DEFAULT_SHOP_PRICE_BANDS, MarkdownRenderer, type MarkdownRendererProps, OrderConfirmation, type OrderConfirmationLabels, type OrderConfirmationOrder, type OrderConfirmationProps, type OrderConfirmationStatus, ProductCard, type ProductCardProps, ProfileCard, type ProfileCardProps, SafeHtml, type SafeHtmlProps, type ShareUrls, type ShopFilterPriceBand, ShopFilters, type ShopFiltersActive, type ShopFiltersHrefs, type ShopFiltersLabels, type ShopFiltersProps, Specialty, type SpecialtyProps, Treatment, type TreatmentProps, buildShareUrls, formatPrice, getShopErrorMessage, isAllowedYouTubeHost, markdownToSafeHtml, readingTime, sanitizeHtml, shouldRenderShopFilters };