@reblu/site-blocks 0.28.0 → 0.30.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.cjs CHANGED
@@ -24,15 +24,22 @@ __export(src_exports, {
24
24
  AddedToCartToast: () => AddedToCartToast,
25
25
  ArbitrationBadge: () => ArbitrationBadge,
26
26
  CartAdjustmentsNotice: () => CartAdjustmentsNotice,
27
+ CartLineIncludes: () => CartLineIncludes,
27
28
  CartLineList: () => CartLineList,
28
29
  CartSummary: () => CartSummary,
30
+ CheckoutDeliveryChoice: () => CheckoutDeliveryChoice,
29
31
  CheckoutForm: () => CheckoutForm,
30
32
  CheckoutLoginPrompt: () => CheckoutLoginPrompt,
33
+ CheckoutPayAction: () => CheckoutPayAction,
34
+ CheckoutQuoteSummary: () => CheckoutQuoteSummary,
35
+ CheckoutTermsAcceptance: () => CheckoutTermsAcceptance,
31
36
  ContactInterestField: () => ContactInterestField,
32
37
  CourseCatalogFilters: () => CourseCatalogFilters,
33
38
  CourseDescription: () => CourseDescription,
34
39
  CoursePurchaseTerms: () => CoursePurchaseTerms,
35
40
  DATA_REQUEST_TYPES: () => import_site_contracts.DATA_REQUEST_TYPES,
41
+ DEFAULT_CHECKOUT_DELIVERY_CHOICE_LABELS: () => DEFAULT_CHECKOUT_DELIVERY_CHOICE_LABELS,
42
+ DEFAULT_CHECKOUT_QUOTE_SUMMARY_LABELS: () => DEFAULT_CHECKOUT_QUOTE_SUMMARY_LABELS,
36
43
  DEFAULT_COURSE_CATALOG_FILTERS_LABELS: () => DEFAULT_COURSE_CATALOG_FILTERS_LABELS,
37
44
  DEFAULT_COURSE_PRICE_BANDS: () => DEFAULT_COURSE_PRICE_BANDS,
38
45
  DEFAULT_COURSE_PURCHASE_TERMS_LABELS: () => DEFAULT_COURSE_PURCHASE_TERMS_LABELS,
@@ -44,6 +51,7 @@ __export(src_exports, {
44
51
  DEFAULT_TRUST_BADGE_HEADINGS: () => DEFAULT_TRUST_BADGE_HEADINGS,
45
52
  DEFAULT_TRUST_BADGE_TYPE_ORDER: () => DEFAULT_TRUST_BADGE_TYPE_ORDER,
46
53
  DEFAULT_TRUST_ICONS: () => DEFAULT_TRUST_ICONS,
54
+ EMPTY_CHECKOUT_ADDRESS: () => EMPTY_CHECKOUT_ADDRESS,
47
55
  EMPTY_FULL_INVOICE_VALUE: () => EMPTY_FULL_INVOICE_VALUE,
48
56
  FaqAccordion: () => FaqAccordion,
49
57
  FullInvoiceFields: () => FullInvoiceFields,
@@ -66,18 +74,23 @@ __export(src_exports, {
66
74
  TrustBadges: () => TrustBadges,
67
75
  buildFaqPageJsonLd: () => buildFaqPageJsonLd,
68
76
  buildShareUrls: () => buildShareUrls,
77
+ bundleComponentsToIncludes: () => bundleComponentsToIncludes,
69
78
  collectFaqItems: () => collectFaqItems,
79
+ defaultCheckoutFulfillment: () => defaultCheckoutFulfillment,
70
80
  formatPrice: () => formatPrice,
71
81
  getShopErrorMessage: () => getShopErrorMessage,
72
82
  isAllowedYouTubeHost: () => isAllowedYouTubeHost,
73
83
  isOverSimplifiedInvoiceCap: () => isOverSimplifiedInvoiceCap,
74
84
  markdownToPlainText: () => markdownToPlainText,
75
85
  markdownToSafeHtml: () => markdownToSafeHtml,
86
+ quoteRequiresDelivery: () => quoteRequiresDelivery,
76
87
  readingTime: () => readingTime,
77
88
  sanitizeHtml: () => sanitizeHtml,
78
89
  shopIssuesInvoices: () => shopIssuesInvoices,
79
90
  shouldRenderShopFilters: () => shouldRenderShopFilters,
80
- toCheckoutInvoiceFields: () => toCheckoutInvoiceFields
91
+ toCheckoutFulfillmentFields: () => toCheckoutFulfillmentFields,
92
+ toCheckoutInvoiceFields: () => toCheckoutInvoiceFields,
93
+ toCheckoutTermsFields: () => toCheckoutTermsFields
81
94
  });
82
95
  module.exports = __toCommonJS(src_exports);
83
96
 
@@ -15156,15 +15169,43 @@ function CourseCatalogFilters({
15156
15169
 
15157
15170
  // src/components/cart-line-list.tsx
15158
15171
  var import_utils17 = require("@reblu/site-ui/utils");
15159
- var import_jsx_runtime21 = require("react/jsx-runtime");
15172
+ var import_jsx_runtime21 = (
15173
+ // eslint-disable-next-line react/no-array-index-key -- entries are positional, SITE-built rows
15174
+ require("react/jsx-runtime")
15175
+ );
15160
15176
  var DEFAULT_LABELS2 = {
15161
15177
  quantityLabel: "Cantidad",
15162
15178
  decrease: "Reducir cantidad",
15163
15179
  increase: "Aumentar cantidad",
15164
15180
  remove: "Eliminar",
15165
15181
  unitPriceSuffix: "/ ud.",
15166
- cancelledNotice: "Pago cancelado: tu carrito sigue aqu\xED"
15182
+ cancelledNotice: "Pago cancelado: tu carrito sigue aqu\xED",
15183
+ includesSummary: "Qu\xE9 incluye"
15167
15184
  };
15185
+ function CartLineIncludes({ entries, note, className }) {
15186
+ const hasNote = note != null && note !== false && note !== "";
15187
+ if (entries.length === 0 && !hasNote) return null;
15188
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
15189
+ "div",
15190
+ {
15191
+ className: (0, import_utils17.cn)("mt-2 space-y-2 rounded-lg bg-muted px-4 py-3 text-sm", className),
15192
+ "data-slot": "cart-line-includes",
15193
+ children: [
15194
+ entries.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("dl", { className: "grid grid-cols-[max-content_1fr] gap-x-4 gap-y-1.5", children: entries.map((entry, idx) => /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "contents", children: [
15195
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("dt", { className: "font-semibold text-muted-foreground", children: entry.label }),
15196
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("dd", { className: "m-0", children: entry.value })
15197
+ ] }, idx)) }),
15198
+ hasNote && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { className: "text-muted-foreground", children: note })
15199
+ ]
15200
+ }
15201
+ );
15202
+ }
15203
+ function bundleComponentsToIncludes(components) {
15204
+ return components.map(({ quantity, component }) => ({
15205
+ label: component.name,
15206
+ value: `x${quantity}`
15207
+ }));
15208
+ }
15168
15209
  function lineKey(productId, variantId) {
15169
15210
  return `${productId}-${variantId ?? "no-variant"}`;
15170
15211
  }
@@ -15175,6 +15216,7 @@ function CartLineList({
15175
15216
  liveMessage,
15176
15217
  notice,
15177
15218
  lineMessage,
15219
+ lineIncludes,
15178
15220
  labels,
15179
15221
  currencyCode,
15180
15222
  locale,
@@ -15198,6 +15240,7 @@ function CartLineList({
15198
15240
  const atMax = item.quantity >= maxQty;
15199
15241
  const atMin = item.quantity <= 1;
15200
15242
  const message = lineMessage?.(item);
15243
+ const includes = lineIncludes?.(item);
15201
15244
  return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
15202
15245
  "li",
15203
15246
  {
@@ -15262,7 +15305,11 @@ function CartLineList({
15262
15305
  "data-slot": "cart-line-list-line-message",
15263
15306
  children: message
15264
15307
  }
15265
- )
15308
+ ),
15309
+ includes != null && includes !== false && /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("details", { className: "mt-2", "data-slot": "cart-line-list-includes", children: [
15310
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("summary", { className: "cursor-pointer text-sm font-semibold text-primary", children: t.includesSummary }),
15311
+ includes
15312
+ ] })
15266
15313
  ] }),
15267
15314
  /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "flex-shrink-0 text-right", children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { className: "text-base font-bold", children: formatPrice(item.unitPrice * item.quantity, currencyCode, locale) }) })
15268
15315
  ]
@@ -16175,9 +16222,399 @@ function FullInvoiceFields({
16175
16222
  ] });
16176
16223
  }
16177
16224
 
16178
- // src/components/contact-interest-field.tsx
16225
+ // src/components/checkout-delivery-choice.tsx
16179
16226
  var import_utils26 = require("@reblu/site-ui/utils");
16180
16227
  var import_jsx_runtime30 = require("react/jsx-runtime");
16228
+ var EMPTY_CHECKOUT_ADDRESS = {
16229
+ firstName: "",
16230
+ lastName: "",
16231
+ street: "",
16232
+ postalCode: "",
16233
+ city: "",
16234
+ region: ""
16235
+ };
16236
+ var DEFAULT_CHECKOUT_DELIVERY_CHOICE_LABELS = {
16237
+ legend: "Entrega",
16238
+ free: "Gratis",
16239
+ pickupPointsLegend: "Punto de recogida",
16240
+ addressLegend: "Direcci\xF3n de entrega",
16241
+ firstName: "Nombre",
16242
+ lastName: "Apellidos",
16243
+ street: "Direcci\xF3n",
16244
+ postalCode: "C\xF3digo postal",
16245
+ city: "Ciudad",
16246
+ region: "Provincia"
16247
+ };
16248
+ var INPUT_CLASS = "w-full rounded-lg border bg-background px-3 py-2 text-sm transition focus:outline-none focus:ring-2 focus:ring-primary/20";
16249
+ var ADDRESS_FIELDS = [
16250
+ { key: "firstName", autoComplete: "shipping given-name", required: true },
16251
+ { key: "lastName", autoComplete: "shipping family-name", required: true },
16252
+ { key: "street", autoComplete: "shipping street-address", required: true, wide: true },
16253
+ { key: "postalCode", autoComplete: "shipping postal-code", required: true },
16254
+ { key: "city", autoComplete: "shipping address-level2", required: true },
16255
+ { key: "region", autoComplete: "shipping address-level1", required: false }
16256
+ ];
16257
+ function pickupDescription(location2) {
16258
+ return [
16259
+ `${location2.address}, ${location2.postalCode} ${location2.city}`,
16260
+ location2.openingHoursText,
16261
+ location2.pickupReadyText
16262
+ ].filter(Boolean).join(". ");
16263
+ }
16264
+ function CheckoutDeliveryChoice({
16265
+ delivery,
16266
+ copy,
16267
+ value,
16268
+ onChange,
16269
+ address,
16270
+ onAddressChange,
16271
+ addressErrors,
16272
+ error,
16273
+ quote,
16274
+ requiresDelivery = true,
16275
+ labels,
16276
+ currencyCode,
16277
+ locale,
16278
+ id: uid = "checkout-delivery",
16279
+ className
16280
+ }) {
16281
+ const t = { ...DEFAULT_CHECKOUT_DELIVERY_CHOICE_LABELS, ...labels };
16282
+ const { homeDelivery, pickup } = delivery.methods;
16283
+ if (!requiresDelivery || !homeDelivery && !pickup) return null;
16284
+ const price = (cents) => formatPrice(cents, currencyCode, locale);
16285
+ const quotedShipping = quote?.fulfillment.type === "SHIPPING" ? quote.shipping : null;
16286
+ const homeCost = quotedShipping ? quotedShipping.isFree ? t.free : price(quotedShipping.cost) : delivery.shippingEnabled && delivery.defaultShippingCost ? price(delivery.defaultShippingCost) : t.free;
16287
+ const isPickup = value?.type === "PICKUP";
16288
+ const isShipping = value?.type === "SHIPPING";
16289
+ const errorId = `${uid}-delivery-error`;
16290
+ return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(
16291
+ "fieldset",
16292
+ {
16293
+ "data-slot": "checkout-delivery",
16294
+ "aria-describedby": error ? errorId : void 0,
16295
+ className: (0, import_utils26.cn)("space-y-4", className),
16296
+ children: [
16297
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("legend", { className: "mb-2 text-lg font-semibold", children: t.legend }),
16298
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("div", { className: "grid gap-3 sm:grid-cols-2", children: [
16299
+ homeDelivery ? /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("label", { className: "flex cursor-pointer items-start gap-3 rounded-xl border border-border p-4 has-[:checked]:border-primary", children: [
16300
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
16301
+ "input",
16302
+ {
16303
+ type: "radio",
16304
+ name: `${uid}-method`,
16305
+ checked: isShipping,
16306
+ onChange: () => onChange({ type: "SHIPPING" }),
16307
+ className: "mt-0.5 size-4 accent-primary"
16308
+ }
16309
+ ),
16310
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("span", { className: "flex-1 space-y-1", children: [
16311
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("span", { className: "flex justify-between gap-2 font-medium", children: [
16312
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { children: copy.shippingOptionLabel }),
16313
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: "tabular-nums", children: homeCost })
16314
+ ] }),
16315
+ delivery.estimatedDeliveryText ? /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: "block text-sm text-muted-foreground", children: delivery.estimatedDeliveryText }) : null
16316
+ ] })
16317
+ ] }) : null,
16318
+ pickup ? /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("label", { className: "flex cursor-pointer items-start gap-3 rounded-xl border border-border p-4 has-[:checked]:border-primary", children: [
16319
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
16320
+ "input",
16321
+ {
16322
+ type: "radio",
16323
+ name: `${uid}-method`,
16324
+ checked: isPickup,
16325
+ onChange: () => onChange({ type: "PICKUP" }),
16326
+ className: "mt-0.5 size-4 accent-primary"
16327
+ }
16328
+ ),
16329
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("span", { className: "flex flex-1 justify-between gap-2 font-medium", children: [
16330
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { children: copy.pickupOptionLabel }),
16331
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { children: t.free })
16332
+ ] })
16333
+ ] }) : null
16334
+ ] }),
16335
+ error ? /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("p", { id: errorId, role: "alert", className: "text-sm text-destructive", children: error }) : null,
16336
+ isPickup ? /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("div", { role: "radiogroup", "aria-labelledby": `${uid}-points`, className: "space-y-2", children: [
16337
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("p", { id: `${uid}-points`, className: "text-sm font-medium", children: t.pickupPointsLegend }),
16338
+ delivery.pickupLocations.map((location2) => {
16339
+ const descId = `${uid}-point-${location2.id}`;
16340
+ return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(
16341
+ "label",
16342
+ {
16343
+ className: "flex cursor-pointer items-start gap-3 rounded-lg border border-border p-3 has-[:checked]:border-primary",
16344
+ children: [
16345
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
16346
+ "input",
16347
+ {
16348
+ type: "radio",
16349
+ name: `${uid}-point`,
16350
+ checked: value?.pickupLocationId === location2.id,
16351
+ onChange: () => onChange({ type: "PICKUP", pickupLocationId: location2.id }),
16352
+ "aria-describedby": descId,
16353
+ className: "mt-0.5 size-4 accent-primary"
16354
+ }
16355
+ ),
16356
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("span", { className: "space-y-0.5 text-sm", children: [
16357
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: "block font-medium", children: location2.name }),
16358
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { id: descId, className: "block text-muted-foreground", children: pickupDescription(location2) })
16359
+ ] })
16360
+ ]
16361
+ },
16362
+ location2.id
16363
+ );
16364
+ })
16365
+ ] }) : null,
16366
+ isShipping ? /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("fieldset", { className: "space-y-3", children: [
16367
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("legend", { className: "mb-2 text-sm font-medium", children: t.addressLegend }),
16368
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("div", { className: "grid grid-cols-1 gap-4 sm:grid-cols-2", children: ADDRESS_FIELDS.map(({ key: key2, autoComplete, required, wide }) => {
16369
+ const fieldId = `${uid}-${key2}`;
16370
+ const fieldError = addressErrors?.[key2];
16371
+ return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("div", { className: (0, import_utils26.cn)("space-y-1", wide && "sm:col-span-2"), children: [
16372
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("label", { htmlFor: fieldId, className: "text-sm font-medium", children: t[key2] }),
16373
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
16374
+ "input",
16375
+ {
16376
+ id: fieldId,
16377
+ type: "text",
16378
+ required,
16379
+ autoComplete,
16380
+ value: address[key2],
16381
+ onChange: (e) => onAddressChange({ ...address, [key2]: e.target.value }),
16382
+ "aria-invalid": fieldError ? true : void 0,
16383
+ "aria-describedby": fieldError ? `${fieldId}-error` : void 0,
16384
+ className: (0, import_utils26.cn)(
16385
+ INPUT_CLASS,
16386
+ fieldError ? "border-destructive" : "border-border focus:border-primary"
16387
+ )
16388
+ }
16389
+ ),
16390
+ fieldError ? /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("p", { id: `${fieldId}-error`, className: "text-sm text-destructive", children: fieldError }) : null
16391
+ ] }, key2);
16392
+ }) })
16393
+ ] }) : null
16394
+ ]
16395
+ }
16396
+ );
16397
+ }
16398
+ function defaultCheckoutFulfillment(delivery) {
16399
+ if (!delivery) return null;
16400
+ if (delivery.methods.homeDelivery) return { type: "SHIPPING" };
16401
+ if (!delivery.methods.pickup) return null;
16402
+ const [only, ...rest] = delivery.pickupLocations;
16403
+ return only && rest.length === 0 ? { type: "PICKUP", pickupLocationId: only.id } : { type: "PICKUP" };
16404
+ }
16405
+ function quoteRequiresDelivery(quote) {
16406
+ return quote ? quote.lines.some((line) => line.isShippable) : true;
16407
+ }
16408
+ function toCheckoutFulfillmentFields(value, address, requiresDelivery = true) {
16409
+ if (!value || !requiresDelivery) return { fulfillment: { type: "SHIPPING" } };
16410
+ if (value.type === "PICKUP") {
16411
+ return { fulfillment: value.pickupLocationId ? { type: "PICKUP", pickupLocationId: value.pickupLocationId } : { type: "PICKUP" } };
16412
+ }
16413
+ const shippingAddress = {
16414
+ firstName: address.firstName.trim(),
16415
+ lastName: address.lastName.trim(),
16416
+ street: address.street.trim(),
16417
+ postalCode: address.postalCode.trim(),
16418
+ city: address.city.trim(),
16419
+ ...address.region.trim() ? { region: address.region.trim() } : {}
16420
+ };
16421
+ return { fulfillment: { type: "SHIPPING" }, shippingAddress };
16422
+ }
16423
+
16424
+ // src/components/checkout-quote-summary.tsx
16425
+ var import_utils27 = require("@reblu/site-ui/utils");
16426
+ var import_jsx_runtime31 = require("react/jsx-runtime");
16427
+ var DEFAULT_CHECKOUT_QUOTE_SUMMARY_LABELS = {
16428
+ subtotal: "Subtotal",
16429
+ discount: (codeOrLabel, isAutomatic) => isAutomatic ? codeOrLabel : `Descuento (${codeOrLabel})`,
16430
+ free: "Gratis",
16431
+ delivery: "Entrega",
16432
+ remainingForFree: (amount) => `Te faltan ${amount} para el env\xEDo gratis`,
16433
+ taxIncluded: (label) => `De los cuales ${label}`,
16434
+ total: "Total",
16435
+ taxesIncludedNote: "Impuestos incluidos",
16436
+ quantityTimesUnit: (quantity, unit) => `${quantity} \xD7 ${unit}`
16437
+ };
16438
+ function Row({
16439
+ name,
16440
+ value,
16441
+ className
16442
+ }) {
16443
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("div", { "data-slot": "checkout-quote-row", className: (0, import_utils27.cn)("flex justify-between gap-4", className), children: [
16444
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("dt", { children: name }),
16445
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("dd", { className: "shrink-0 tabular-nums", children: value })
16446
+ ] });
16447
+ }
16448
+ function CheckoutQuoteSummary({
16449
+ quote,
16450
+ heading,
16451
+ headingLevel = 2,
16452
+ labels,
16453
+ currencyCode,
16454
+ locale,
16455
+ className
16456
+ }) {
16457
+ const t = { ...DEFAULT_CHECKOUT_QUOTE_SUMMARY_LABELS, ...labels };
16458
+ const price = (cents) => formatPrice(cents, currencyCode, locale);
16459
+ const { fulfillment, shipping, tax, discount } = quote;
16460
+ const Tag = `h${headingLevel}`;
16461
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("section", { "data-slot": "checkout-quote-summary", className: slotClassName("space-y-4", "", className), children: [
16462
+ heading ? /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(Tag, { className: "text-lg font-semibold", children: heading }) : null,
16463
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("ul", { className: "space-y-3 text-sm", children: quote.lines.map((line) => /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("li", { className: "flex justify-between gap-4", children: [
16464
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("div", { className: "min-w-0 space-y-0.5", children: [
16465
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("p", { className: "font-medium", children: line.name }),
16466
+ line.variantName ? /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("p", { className: "text-muted-foreground", children: line.variantName }) : null,
16467
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("p", { className: "flex flex-wrap items-center gap-2 text-muted-foreground", children: [
16468
+ line.kindLabel ? /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { "data-slot": "checkout-quote-kind", className: "rounded-full border border-border px-2 py-0.5 text-xs font-medium text-foreground", children: line.kindLabel }) : null,
16469
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { children: t.quantityTimesUnit(line.quantity, price(line.unitPrice)) })
16470
+ ] })
16471
+ ] }),
16472
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { className: "shrink-0 tabular-nums", children: price(line.total) })
16473
+ ] }, `${line.productId}-${line.variantId ?? ""}`)) }),
16474
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("dl", { className: "space-y-2 border-t border-border pt-3 text-sm", children: [
16475
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(Row, { name: t.subtotal, value: price(quote.subtotal) }),
16476
+ discount && discount.amount > 0 ? /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
16477
+ Row,
16478
+ {
16479
+ className: "text-green-700 dark:text-green-400",
16480
+ name: t.discount(discount.isAutomatic ? discount.label ?? discount.code : discount.code, discount.isAutomatic),
16481
+ value: `\u2212${price(discount.amount)}`
16482
+ }
16483
+ ) : null,
16484
+ fulfillment.type ? /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
16485
+ Row,
16486
+ {
16487
+ name: /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(import_jsx_runtime31.Fragment, { children: [
16488
+ fulfillment.label ?? t.delivery,
16489
+ fulfillment.type === "PICKUP" && fulfillment.pickupLocation ? /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { className: "block text-muted-foreground", children: fulfillment.pickupLocation.name }) : null
16490
+ ] }),
16491
+ value: fulfillment.type === "PICKUP" || shipping.isFree ? t.free : price(shipping.cost)
16492
+ }
16493
+ ) : null,
16494
+ tax.isLineVisible ? tax.breakdown.map((entry) => /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
16495
+ Row,
16496
+ {
16497
+ className: tax.isIncluded ? "text-muted-foreground" : void 0,
16498
+ name: tax.isIncluded ? t.taxIncluded(entry.label) : entry.label,
16499
+ value: price(entry.amount)
16500
+ },
16501
+ entry.label
16502
+ )) : null,
16503
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(Row, { className: "border-t border-border pt-2 text-base font-bold", name: t.total, value: price(quote.total) })
16504
+ ] }),
16505
+ tax.isIncluded ? /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("p", { className: "text-sm text-muted-foreground", children: t.taxesIncludedNote }) : null,
16506
+ fulfillment.type === "SHIPPING" && !shipping.isFree && shipping.remainingForFree ? /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("p", { className: "text-sm text-muted-foreground", children: t.remainingForFree(price(shipping.remainingForFree)) }) : null,
16507
+ fulfillment.type && quote.deliveryEstimateText ? /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("p", { "data-slot": "checkout-quote-estimate", className: "text-sm text-muted-foreground", children: quote.deliveryEstimateText }) : null,
16508
+ quote.discountError ? /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("p", { role: "status", className: "text-sm text-destructive", children: quote.discountError.message }) : null,
16509
+ quote.blockingReason ? /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("p", { role: "alert", className: "rounded-lg border border-destructive/50 bg-destructive/10 p-3 text-sm text-destructive", children: quote.blockingReason.message }) : null
16510
+ ] });
16511
+ }
16512
+
16513
+ // src/components/checkout-terms-acceptance.tsx
16514
+ var import_utils28 = require("@reblu/site-ui/utils");
16515
+ var import_jsx_runtime32 = require("react/jsx-runtime");
16516
+ function splitTermsLabel(label) {
16517
+ const at = label.indexOf("{terms}");
16518
+ return at === -1 ? [`${label} `, ""] : [label.slice(0, at), label.slice(at + "{terms}".length)];
16519
+ }
16520
+ function CheckoutTermsAcceptance({
16521
+ copy,
16522
+ termsHref,
16523
+ checked,
16524
+ onCheckedChange,
16525
+ error,
16526
+ newTabHint = "(se abre en una pesta\xF1a nueva)",
16527
+ id,
16528
+ className
16529
+ }) {
16530
+ if (!copy.termsVersion) return null;
16531
+ const boxId = id ?? "checkout-terms";
16532
+ const errorId = `${boxId}-error`;
16533
+ const [before, after] = splitTermsLabel(copy.termsCheckboxLabel).map(
16534
+ (part) => part.replaceAll("{tenant}", copy.tenantName)
16535
+ );
16536
+ const newTab = copy.isTermsLinkNewTab;
16537
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { "data-slot": "checkout-terms", className: (0, import_utils28.cn)("space-y-1", className), children: [
16538
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: "flex items-start gap-3", children: [
16539
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
16540
+ "input",
16541
+ {
16542
+ id: boxId,
16543
+ type: "checkbox",
16544
+ required: true,
16545
+ checked,
16546
+ onChange: (e) => onCheckedChange(e.target.checked),
16547
+ "aria-invalid": error ? true : void 0,
16548
+ "aria-describedby": error ? errorId : void 0,
16549
+ className: "mt-0.5 size-5 shrink-0 cursor-pointer accent-primary"
16550
+ }
16551
+ ),
16552
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("label", { htmlFor: boxId, className: "text-sm leading-relaxed", children: [
16553
+ before,
16554
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
16555
+ "a",
16556
+ {
16557
+ href: copy.termsLinkUrl ?? termsHref,
16558
+ ...newTab ? { target: "_blank", rel: "noopener noreferrer" } : {},
16559
+ className: "font-medium underline underline-offset-2 hover:text-primary",
16560
+ children: [
16561
+ copy.termsLinkText,
16562
+ newTab ? /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(import_jsx_runtime32.Fragment, { children: [
16563
+ " ",
16564
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: "sr-only", children: newTabHint })
16565
+ ] }) : null
16566
+ ]
16567
+ }
16568
+ ),
16569
+ after
16570
+ ] })
16571
+ ] }),
16572
+ error ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("p", { id: errorId, className: "pl-8 text-sm text-destructive", children: error }) : null
16573
+ ] });
16574
+ }
16575
+ function toCheckoutTermsFields(copy, accepted) {
16576
+ const version = copy?.termsVersion;
16577
+ return version ? { acceptsTerms: accepted, termsVersionId: version.id } : {};
16578
+ }
16579
+
16580
+ // src/components/checkout-pay-action.tsx
16581
+ var import_utils29 = require("@reblu/site-ui/utils");
16582
+ var import_jsx_runtime33 = require("react/jsx-runtime");
16583
+ function CheckoutPayAction({
16584
+ label,
16585
+ notice,
16586
+ submitting = false,
16587
+ submittingLabel = "Procesando\u2026",
16588
+ disabled = false,
16589
+ id = "checkout-pay",
16590
+ className,
16591
+ buttonClassName,
16592
+ noticeClassName
16593
+ }) {
16594
+ const noticeId = `${id}-notice`;
16595
+ const isDisabled = submitting || disabled;
16596
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { "data-slot": "checkout-pay-action", className: (0, import_utils29.cn)("space-y-3", className), children: [
16597
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
16598
+ "button",
16599
+ {
16600
+ type: "submit",
16601
+ disabled: isDisabled,
16602
+ "aria-busy": submitting || void 0,
16603
+ "aria-describedby": notice ? noticeId : void 0,
16604
+ className: buttonClassName ?? (0, import_utils29.cn)(
16605
+ "flex w-full items-center justify-center gap-2 rounded-xl px-4 py-3 text-base font-semibold transition-all",
16606
+ isDisabled ? "cursor-not-allowed bg-muted text-muted-foreground" : "cursor-pointer bg-primary text-primary-foreground hover:bg-primary/90"
16607
+ ),
16608
+ children: submitting ? submittingLabel : label
16609
+ }
16610
+ ),
16611
+ notice ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("p", { id: noticeId, "data-slot": "checkout-pay-notice", className: noticeClassName ?? "text-sm text-muted-foreground", children: notice }) : null
16612
+ ] });
16613
+ }
16614
+
16615
+ // src/components/contact-interest-field.tsx
16616
+ var import_utils30 = require("@reblu/site-ui/utils");
16617
+ var import_jsx_runtime34 = require("react/jsx-runtime");
16181
16618
  function ContactInterestField({
16182
16619
  interest,
16183
16620
  value,
@@ -16194,18 +16631,18 @@ function ContactInterestField({
16194
16631
  else next2.delete(option2);
16195
16632
  onChange(interest.options.filter((candidate) => next2.has(candidate)));
16196
16633
  };
16197
- return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("fieldset", { "data-slot": "contact-interest", className: (0, import_utils26.cn)("space-y-2", className), children: [
16198
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("legend", { className: "text-sm font-medium", children: interest.label }),
16199
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("div", { className: "flex flex-col gap-2", children: interest.options.map((option2, index) => {
16634
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("fieldset", { "data-slot": "contact-interest", className: (0, import_utils30.cn)("space-y-2", className), children: [
16635
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("legend", { className: "text-sm font-medium", children: interest.label }),
16636
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { className: "flex flex-col gap-2", children: interest.options.map((option2, index) => {
16200
16637
  const id = `${idPrefix}-${index}`;
16201
- return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(
16638
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(
16202
16639
  "label",
16203
16640
  {
16204
16641
  htmlFor: id,
16205
16642
  "data-slot": "contact-interest-option",
16206
16643
  className: "flex items-center gap-2 text-sm",
16207
16644
  children: [
16208
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
16645
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
16209
16646
  "input",
16210
16647
  {
16211
16648
  id,
@@ -16232,15 +16669,22 @@ var import_site_contracts = require("@reblu/site-contracts");
16232
16669
  AddedToCartToast,
16233
16670
  ArbitrationBadge,
16234
16671
  CartAdjustmentsNotice,
16672
+ CartLineIncludes,
16235
16673
  CartLineList,
16236
16674
  CartSummary,
16675
+ CheckoutDeliveryChoice,
16237
16676
  CheckoutForm,
16238
16677
  CheckoutLoginPrompt,
16678
+ CheckoutPayAction,
16679
+ CheckoutQuoteSummary,
16680
+ CheckoutTermsAcceptance,
16239
16681
  ContactInterestField,
16240
16682
  CourseCatalogFilters,
16241
16683
  CourseDescription,
16242
16684
  CoursePurchaseTerms,
16243
16685
  DATA_REQUEST_TYPES,
16686
+ DEFAULT_CHECKOUT_DELIVERY_CHOICE_LABELS,
16687
+ DEFAULT_CHECKOUT_QUOTE_SUMMARY_LABELS,
16244
16688
  DEFAULT_COURSE_CATALOG_FILTERS_LABELS,
16245
16689
  DEFAULT_COURSE_PRICE_BANDS,
16246
16690
  DEFAULT_COURSE_PURCHASE_TERMS_LABELS,
@@ -16252,6 +16696,7 @@ var import_site_contracts = require("@reblu/site-contracts");
16252
16696
  DEFAULT_TRUST_BADGE_HEADINGS,
16253
16697
  DEFAULT_TRUST_BADGE_TYPE_ORDER,
16254
16698
  DEFAULT_TRUST_ICONS,
16699
+ EMPTY_CHECKOUT_ADDRESS,
16255
16700
  EMPTY_FULL_INVOICE_VALUE,
16256
16701
  FaqAccordion,
16257
16702
  FullInvoiceFields,
@@ -16274,18 +16719,23 @@ var import_site_contracts = require("@reblu/site-contracts");
16274
16719
  TrustBadges,
16275
16720
  buildFaqPageJsonLd,
16276
16721
  buildShareUrls,
16722
+ bundleComponentsToIncludes,
16277
16723
  collectFaqItems,
16724
+ defaultCheckoutFulfillment,
16278
16725
  formatPrice,
16279
16726
  getShopErrorMessage,
16280
16727
  isAllowedYouTubeHost,
16281
16728
  isOverSimplifiedInvoiceCap,
16282
16729
  markdownToPlainText,
16283
16730
  markdownToSafeHtml,
16731
+ quoteRequiresDelivery,
16284
16732
  readingTime,
16285
16733
  sanitizeHtml,
16286
16734
  shopIssuesInvoices,
16287
16735
  shouldRenderShopFilters,
16288
- toCheckoutInvoiceFields
16736
+ toCheckoutFulfillmentFields,
16737
+ toCheckoutInvoiceFields,
16738
+ toCheckoutTermsFields
16289
16739
  });
16290
16740
  /*! Bundled license information:
16291
16741