@reblu/site-blocks 0.29.0 → 0.31.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 +31 -0
- package/README.md +217 -6
- package/dist/client.cjs +632 -0
- package/dist/client.cjs.map +1 -1
- package/dist/client.d.cts +105 -3
- package/dist/client.d.ts +105 -3
- package/dist/client.js +629 -0
- package/dist/client.js.map +1 -1
- package/dist/full-invoice-fields-DMX0sjPG.d.cts +140 -0
- package/dist/full-invoice-fields-DMX0sjPG.d.ts +140 -0
- package/dist/index.cjs +859 -342
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +202 -131
- package/dist/index.d.ts +202 -131
- package/dist/index.js +844 -342
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
- package/dist/_heading-BsNbc1wc.d.cts +0 -4
- package/dist/_heading-BsNbc1wc.d.ts +0 -4
package/dist/client.cjs
CHANGED
|
@@ -34,9 +34,12 @@ __export(client_exports, {
|
|
|
34
34
|
AddToCartButton: () => AddToCartButton,
|
|
35
35
|
CartIcon: () => CartIcon,
|
|
36
36
|
Collection: () => Collection,
|
|
37
|
+
CourseGuestCheckoutForm: () => CourseGuestCheckoutForm,
|
|
37
38
|
CourseSyllabus: () => CourseSyllabus,
|
|
38
39
|
DATA_REQUEST_FIELD_LIMITS: () => DATA_REQUEST_FIELD_LIMITS,
|
|
39
40
|
DATA_REQUEST_TYPES: () => import_site_contracts.DATA_REQUEST_TYPES,
|
|
41
|
+
DEFAULT_COURSE_GUEST_CHECKOUT_ERROR_MESSAGES: () => DEFAULT_COURSE_GUEST_CHECKOUT_ERROR_MESSAGES,
|
|
42
|
+
DEFAULT_COURSE_GUEST_CHECKOUT_FORM_LABELS: () => DEFAULT_COURSE_GUEST_CHECKOUT_FORM_LABELS,
|
|
40
43
|
DEFAULT_COURSE_SYLLABUS_LABELS: () => DEFAULT_COURSE_SYLLABUS_LABELS,
|
|
41
44
|
DEFAULT_DATA_REQUEST_FORM_LABELS: () => DEFAULT_DATA_REQUEST_FORM_LABELS,
|
|
42
45
|
DEFAULT_PRODUCT_CAROUSEL_LABELS: () => DEFAULT_PRODUCT_CAROUSEL_LABELS,
|
|
@@ -1598,14 +1601,643 @@ function WithdrawalRequestForm({
|
|
|
1598
1601
|
}
|
|
1599
1602
|
);
|
|
1600
1603
|
}
|
|
1604
|
+
|
|
1605
|
+
// src/components/course-guest-checkout-form.tsx
|
|
1606
|
+
var import_react8 = require("react");
|
|
1607
|
+
var import_utils14 = require("@reblu/site-ui/utils");
|
|
1608
|
+
|
|
1609
|
+
// src/lib/course-guest-checkout.ts
|
|
1610
|
+
function toAcademyCheckoutInvoiceFields(value, overCap, issuesInvoices = true) {
|
|
1611
|
+
if (!issuesInvoices) return {};
|
|
1612
|
+
if (!value.wantsFullInvoice && !overCap) return {};
|
|
1613
|
+
const billing = {
|
|
1614
|
+
billingName: value.billingName.trim(),
|
|
1615
|
+
billingNif: value.billingNif.trim(),
|
|
1616
|
+
billingIdType: value.billingIdType,
|
|
1617
|
+
...value.billingIdType === "NIF" ? {} : { billingIdCountry: value.billingIdCountry },
|
|
1618
|
+
billingAddress: {
|
|
1619
|
+
street: value.street.trim(),
|
|
1620
|
+
postalCode: value.postalCode.trim(),
|
|
1621
|
+
city: value.city.trim(),
|
|
1622
|
+
country: value.country
|
|
1623
|
+
}
|
|
1624
|
+
};
|
|
1625
|
+
return { ...value.wantsFullInvoice ? { wantsFullInvoice: true } : {}, billing };
|
|
1626
|
+
}
|
|
1627
|
+
|
|
1628
|
+
// src/components/checkout-pay-action.tsx
|
|
1629
|
+
var import_utils11 = require("@reblu/site-ui/utils");
|
|
1630
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
1631
|
+
function CheckoutPayAction({
|
|
1632
|
+
label,
|
|
1633
|
+
notice,
|
|
1634
|
+
submitting = false,
|
|
1635
|
+
submittingLabel = "Procesando\u2026",
|
|
1636
|
+
disabled = false,
|
|
1637
|
+
id = "checkout-pay",
|
|
1638
|
+
className,
|
|
1639
|
+
buttonClassName,
|
|
1640
|
+
noticeClassName
|
|
1641
|
+
}) {
|
|
1642
|
+
const noticeId = `${id}-notice`;
|
|
1643
|
+
const isDisabled = submitting || disabled;
|
|
1644
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { "data-slot": "checkout-pay-action", className: (0, import_utils11.cn)("space-y-3", className), children: [
|
|
1645
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1646
|
+
"button",
|
|
1647
|
+
{
|
|
1648
|
+
type: "submit",
|
|
1649
|
+
disabled: isDisabled,
|
|
1650
|
+
"aria-busy": submitting || void 0,
|
|
1651
|
+
"aria-describedby": notice ? noticeId : void 0,
|
|
1652
|
+
className: buttonClassName ?? (0, import_utils11.cn)(
|
|
1653
|
+
"flex w-full items-center justify-center gap-2 rounded-xl px-4 py-3 text-base font-semibold transition-all",
|
|
1654
|
+
isDisabled ? "cursor-not-allowed bg-muted text-muted-foreground" : "cursor-pointer bg-primary text-primary-foreground hover:bg-primary/90"
|
|
1655
|
+
),
|
|
1656
|
+
children: submitting ? submittingLabel : label
|
|
1657
|
+
}
|
|
1658
|
+
),
|
|
1659
|
+
notice ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { id: noticeId, "data-slot": "checkout-pay-notice", className: noticeClassName ?? "text-sm text-muted-foreground", children: notice }) : null
|
|
1660
|
+
] });
|
|
1661
|
+
}
|
|
1662
|
+
|
|
1663
|
+
// src/components/checkout-terms-acceptance.tsx
|
|
1664
|
+
var import_utils12 = require("@reblu/site-ui/utils");
|
|
1665
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
1666
|
+
function splitTermsLabel(label) {
|
|
1667
|
+
const at = label.indexOf("{terms}");
|
|
1668
|
+
return at === -1 ? [`${label} `, ""] : [label.slice(0, at), label.slice(at + "{terms}".length)];
|
|
1669
|
+
}
|
|
1670
|
+
function CheckoutTermsAcceptance({
|
|
1671
|
+
copy,
|
|
1672
|
+
termsHref,
|
|
1673
|
+
checked,
|
|
1674
|
+
onCheckedChange,
|
|
1675
|
+
error,
|
|
1676
|
+
newTabHint = "(se abre en una pesta\xF1a nueva)",
|
|
1677
|
+
id,
|
|
1678
|
+
className
|
|
1679
|
+
}) {
|
|
1680
|
+
if (!copy.termsVersion) return null;
|
|
1681
|
+
const boxId = id ?? "checkout-terms";
|
|
1682
|
+
const errorId = `${boxId}-error`;
|
|
1683
|
+
const [before, after] = splitTermsLabel(copy.termsCheckboxLabel).map(
|
|
1684
|
+
(part) => part.replaceAll("{tenant}", copy.tenantName)
|
|
1685
|
+
);
|
|
1686
|
+
const newTab = copy.isTermsLinkNewTab;
|
|
1687
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { "data-slot": "checkout-terms", className: (0, import_utils12.cn)("space-y-1", className), children: [
|
|
1688
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex items-start gap-3", children: [
|
|
1689
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1690
|
+
"input",
|
|
1691
|
+
{
|
|
1692
|
+
id: boxId,
|
|
1693
|
+
type: "checkbox",
|
|
1694
|
+
required: true,
|
|
1695
|
+
checked,
|
|
1696
|
+
onChange: (e) => onCheckedChange(e.target.checked),
|
|
1697
|
+
"aria-invalid": error ? true : void 0,
|
|
1698
|
+
"aria-describedby": error ? errorId : void 0,
|
|
1699
|
+
className: "mt-0.5 size-5 shrink-0 cursor-pointer accent-primary"
|
|
1700
|
+
}
|
|
1701
|
+
),
|
|
1702
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("label", { htmlFor: boxId, className: "text-sm leading-relaxed", children: [
|
|
1703
|
+
before,
|
|
1704
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
1705
|
+
"a",
|
|
1706
|
+
{
|
|
1707
|
+
href: copy.termsLinkUrl ?? termsHref,
|
|
1708
|
+
...newTab ? { target: "_blank", rel: "noopener noreferrer" } : {},
|
|
1709
|
+
className: "font-medium underline underline-offset-2 hover:text-primary",
|
|
1710
|
+
children: [
|
|
1711
|
+
copy.termsLinkText,
|
|
1712
|
+
newTab ? /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
|
|
1713
|
+
" ",
|
|
1714
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "sr-only", children: newTabHint })
|
|
1715
|
+
] }) : null
|
|
1716
|
+
]
|
|
1717
|
+
}
|
|
1718
|
+
),
|
|
1719
|
+
after
|
|
1720
|
+
] })
|
|
1721
|
+
] }),
|
|
1722
|
+
error ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { id: errorId, className: "pl-8 text-sm text-destructive", children: error }) : null
|
|
1723
|
+
] });
|
|
1724
|
+
}
|
|
1725
|
+
function toCheckoutTermsFields(copy, accepted) {
|
|
1726
|
+
const version = copy?.termsVersion;
|
|
1727
|
+
return version ? { acceptsTerms: accepted, termsVersionId: version.id } : {};
|
|
1728
|
+
}
|
|
1729
|
+
|
|
1730
|
+
// src/components/full-invoice-fields.tsx
|
|
1731
|
+
var import_utils13 = require("@reblu/site-ui/utils");
|
|
1732
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
1733
|
+
var EMPTY_FULL_INVOICE_VALUE = {
|
|
1734
|
+
wantsFullInvoice: false,
|
|
1735
|
+
billingIdType: "NIF",
|
|
1736
|
+
billingIdCountry: "",
|
|
1737
|
+
billingNif: "",
|
|
1738
|
+
billingName: "",
|
|
1739
|
+
street: "",
|
|
1740
|
+
postalCode: "",
|
|
1741
|
+
city: "",
|
|
1742
|
+
country: "ES"
|
|
1743
|
+
};
|
|
1744
|
+
var DEFAULT_LABELS5 = {
|
|
1745
|
+
toggle: "\xBFQuieres factura completa?",
|
|
1746
|
+
underCapNotice: "Para una factura completa necesitas tu NIF/NIE o un documento de identificaci\xF3n. Si no, recibir\xE1s una factura simplificada.",
|
|
1747
|
+
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.",
|
|
1748
|
+
idType: "Tipo de documento",
|
|
1749
|
+
idCountry: "Pa\xEDs que expidi\xF3 el documento",
|
|
1750
|
+
chooseCountry: "Elige un pa\xEDs",
|
|
1751
|
+
spanishNif: "NIF / NIE / CIF",
|
|
1752
|
+
documentNumber: "N\xFAmero de documento",
|
|
1753
|
+
name: "Nombre o raz\xF3n social",
|
|
1754
|
+
street: "Direcci\xF3n",
|
|
1755
|
+
postalCode: "C\xF3digo postal",
|
|
1756
|
+
city: "Ciudad",
|
|
1757
|
+
country: "Pa\xEDs",
|
|
1758
|
+
idTypeOptions: {
|
|
1759
|
+
NIF: "NIF / NIE / CIF (Espa\xF1a)",
|
|
1760
|
+
"02": "NIF-IVA intracomunitario (otro pa\xEDs de la UE)",
|
|
1761
|
+
"03": "Pasaporte",
|
|
1762
|
+
"04": "Documento oficial de identidad de tu pa\xEDs de residencia",
|
|
1763
|
+
"05": "Certificado de residencia",
|
|
1764
|
+
"06": "Otro documento acreditativo"
|
|
1765
|
+
}
|
|
1766
|
+
};
|
|
1767
|
+
var ID_TYPES = ["NIF", "02", "03", "04", "05", "06"];
|
|
1768
|
+
var DEFAULT_INVOICE_COUNTRIES = [
|
|
1769
|
+
{ code: "ES", name: "Espa\xF1a" },
|
|
1770
|
+
{ code: "DE", name: "Alemania" },
|
|
1771
|
+
{ code: "AD", name: "Andorra" },
|
|
1772
|
+
{ code: "AR", name: "Argentina" },
|
|
1773
|
+
{ code: "AT", name: "Austria" },
|
|
1774
|
+
{ code: "BE", name: "B\xE9lgica" },
|
|
1775
|
+
{ code: "BG", name: "Bulgaria" },
|
|
1776
|
+
{ code: "CY", name: "Chipre" },
|
|
1777
|
+
{ code: "CO", name: "Colombia" },
|
|
1778
|
+
{ code: "HR", name: "Croacia" },
|
|
1779
|
+
{ code: "DK", name: "Dinamarca" },
|
|
1780
|
+
{ code: "SK", name: "Eslovaquia" },
|
|
1781
|
+
{ code: "SI", name: "Eslovenia" },
|
|
1782
|
+
{ code: "US", name: "Estados Unidos" },
|
|
1783
|
+
{ code: "EE", name: "Estonia" },
|
|
1784
|
+
{ code: "FI", name: "Finlandia" },
|
|
1785
|
+
{ code: "FR", name: "Francia" },
|
|
1786
|
+
{ code: "GR", name: "Grecia" },
|
|
1787
|
+
{ code: "HU", name: "Hungr\xEDa" },
|
|
1788
|
+
{ code: "IE", name: "Irlanda" },
|
|
1789
|
+
{ code: "IT", name: "Italia" },
|
|
1790
|
+
{ code: "LV", name: "Letonia" },
|
|
1791
|
+
{ code: "LT", name: "Lituania" },
|
|
1792
|
+
{ code: "LU", name: "Luxemburgo" },
|
|
1793
|
+
{ code: "MT", name: "Malta" },
|
|
1794
|
+
{ code: "MA", name: "Marruecos" },
|
|
1795
|
+
{ code: "MX", name: "M\xE9xico" },
|
|
1796
|
+
{ code: "NL", name: "Pa\xEDses Bajos" },
|
|
1797
|
+
{ code: "PL", name: "Polonia" },
|
|
1798
|
+
{ code: "PT", name: "Portugal" },
|
|
1799
|
+
{ code: "GB", name: "Reino Unido" },
|
|
1800
|
+
{ code: "CZ", name: "Rep\xFAblica Checa" },
|
|
1801
|
+
{ code: "RO", name: "Ruman\xEDa" },
|
|
1802
|
+
{ code: "SE", name: "Suecia" },
|
|
1803
|
+
{ code: "CH", name: "Suiza" },
|
|
1804
|
+
{ code: "VE", name: "Venezuela" }
|
|
1805
|
+
];
|
|
1806
|
+
function isOverSimplifiedInvoiceCap(totalCents, capCents) {
|
|
1807
|
+
return capCents != null && totalCents > capCents;
|
|
1808
|
+
}
|
|
1809
|
+
var FIELD_CLASS3 = "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";
|
|
1810
|
+
function FullInvoiceFields({
|
|
1811
|
+
value,
|
|
1812
|
+
onChange,
|
|
1813
|
+
overCap,
|
|
1814
|
+
issuesInvoices = true,
|
|
1815
|
+
errors = {},
|
|
1816
|
+
countries = DEFAULT_INVOICE_COUNTRIES,
|
|
1817
|
+
labels,
|
|
1818
|
+
className
|
|
1819
|
+
}) {
|
|
1820
|
+
if (!issuesInvoices) return null;
|
|
1821
|
+
const t = { ...DEFAULT_LABELS5, ...labels };
|
|
1822
|
+
const showFields = value.wantsFullInvoice || overCap;
|
|
1823
|
+
const isSpanishNif = value.billingIdType === "NIF";
|
|
1824
|
+
const set = (key, next) => onChange({ ...value, [key]: next });
|
|
1825
|
+
const error = (key) => errors[key] ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { id: `full-invoice-${key}-error`, className: "text-sm text-destructive", children: errors[key] }) : null;
|
|
1826
|
+
const invalid = (key) => errors[key] ? { "aria-invalid": true, "aria-describedby": `full-invoice-${key}-error` } : {};
|
|
1827
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("section", { className: (0, import_utils13.cn)("space-y-4", className), "data-slot": "full-invoice-fields", children: [
|
|
1828
|
+
overCap ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { role: "note", className: "rounded-lg border border-border p-4 text-sm", children: t.overCapNotice }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "space-y-1", children: [
|
|
1829
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("label", { className: "flex items-center gap-2 text-sm font-medium", children: [
|
|
1830
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1831
|
+
"input",
|
|
1832
|
+
{
|
|
1833
|
+
type: "checkbox",
|
|
1834
|
+
checked: value.wantsFullInvoice,
|
|
1835
|
+
onChange: (e) => set("wantsFullInvoice", e.target.checked)
|
|
1836
|
+
}
|
|
1837
|
+
),
|
|
1838
|
+
t.toggle
|
|
1839
|
+
] }),
|
|
1840
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: "text-sm text-muted-foreground", children: t.underCapNotice })
|
|
1841
|
+
] }),
|
|
1842
|
+
showFields && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "grid grid-cols-1 gap-4 sm:grid-cols-2", children: [
|
|
1843
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "space-y-1", children: [
|
|
1844
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("label", { htmlFor: "full-invoice-id-type", className: "text-sm font-medium", children: t.idType }),
|
|
1845
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1846
|
+
"select",
|
|
1847
|
+
{
|
|
1848
|
+
id: "full-invoice-id-type",
|
|
1849
|
+
className: FIELD_CLASS3,
|
|
1850
|
+
required: true,
|
|
1851
|
+
value: value.billingIdType,
|
|
1852
|
+
onChange: (e) => set("billingIdType", e.target.value),
|
|
1853
|
+
...invalid("billingIdType"),
|
|
1854
|
+
children: ID_TYPES.map((type) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("option", { value: type, children: t.idTypeOptions[type] }, type))
|
|
1855
|
+
}
|
|
1856
|
+
),
|
|
1857
|
+
error("billingIdType")
|
|
1858
|
+
] }),
|
|
1859
|
+
!isSpanishNif && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "space-y-1", children: [
|
|
1860
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("label", { htmlFor: "full-invoice-id-country", className: "text-sm font-medium", children: t.idCountry }),
|
|
1861
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
1862
|
+
"select",
|
|
1863
|
+
{
|
|
1864
|
+
id: "full-invoice-id-country",
|
|
1865
|
+
className: FIELD_CLASS3,
|
|
1866
|
+
required: true,
|
|
1867
|
+
value: value.billingIdCountry,
|
|
1868
|
+
onChange: (e) => set("billingIdCountry", e.target.value),
|
|
1869
|
+
...invalid("billingIdCountry"),
|
|
1870
|
+
children: [
|
|
1871
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("option", { value: "", disabled: true, children: t.chooseCountry }),
|
|
1872
|
+
countries.map((c) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("option", { value: c.code, children: c.name }, c.code))
|
|
1873
|
+
]
|
|
1874
|
+
}
|
|
1875
|
+
),
|
|
1876
|
+
error("billingIdCountry")
|
|
1877
|
+
] }),
|
|
1878
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "space-y-1", children: [
|
|
1879
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("label", { htmlFor: "full-invoice-nif", className: "text-sm font-medium", children: isSpanishNif ? t.spanishNif : t.documentNumber }),
|
|
1880
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1881
|
+
"input",
|
|
1882
|
+
{
|
|
1883
|
+
id: "full-invoice-nif",
|
|
1884
|
+
className: FIELD_CLASS3,
|
|
1885
|
+
required: true,
|
|
1886
|
+
value: value.billingNif,
|
|
1887
|
+
onChange: (e) => set("billingNif", e.target.value),
|
|
1888
|
+
...invalid("billingNif")
|
|
1889
|
+
}
|
|
1890
|
+
),
|
|
1891
|
+
error("billingNif")
|
|
1892
|
+
] }),
|
|
1893
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "space-y-1", children: [
|
|
1894
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("label", { htmlFor: "full-invoice-name", className: "text-sm font-medium", children: t.name }),
|
|
1895
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1896
|
+
"input",
|
|
1897
|
+
{
|
|
1898
|
+
id: "full-invoice-name",
|
|
1899
|
+
className: FIELD_CLASS3,
|
|
1900
|
+
required: true,
|
|
1901
|
+
value: value.billingName,
|
|
1902
|
+
onChange: (e) => set("billingName", e.target.value),
|
|
1903
|
+
...invalid("billingName")
|
|
1904
|
+
}
|
|
1905
|
+
),
|
|
1906
|
+
error("billingName")
|
|
1907
|
+
] }),
|
|
1908
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "space-y-1 sm:col-span-2", children: [
|
|
1909
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("label", { htmlFor: "full-invoice-street", className: "text-sm font-medium", children: t.street }),
|
|
1910
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1911
|
+
"input",
|
|
1912
|
+
{
|
|
1913
|
+
id: "full-invoice-street",
|
|
1914
|
+
className: FIELD_CLASS3,
|
|
1915
|
+
required: true,
|
|
1916
|
+
value: value.street,
|
|
1917
|
+
onChange: (e) => set("street", e.target.value),
|
|
1918
|
+
...invalid("address")
|
|
1919
|
+
}
|
|
1920
|
+
)
|
|
1921
|
+
] }),
|
|
1922
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "space-y-1", children: [
|
|
1923
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("label", { htmlFor: "full-invoice-postal-code", className: "text-sm font-medium", children: t.postalCode }),
|
|
1924
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1925
|
+
"input",
|
|
1926
|
+
{
|
|
1927
|
+
id: "full-invoice-postal-code",
|
|
1928
|
+
className: FIELD_CLASS3,
|
|
1929
|
+
required: true,
|
|
1930
|
+
value: value.postalCode,
|
|
1931
|
+
onChange: (e) => set("postalCode", e.target.value)
|
|
1932
|
+
}
|
|
1933
|
+
)
|
|
1934
|
+
] }),
|
|
1935
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "space-y-1", children: [
|
|
1936
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("label", { htmlFor: "full-invoice-city", className: "text-sm font-medium", children: t.city }),
|
|
1937
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1938
|
+
"input",
|
|
1939
|
+
{
|
|
1940
|
+
id: "full-invoice-city",
|
|
1941
|
+
className: FIELD_CLASS3,
|
|
1942
|
+
required: true,
|
|
1943
|
+
value: value.city,
|
|
1944
|
+
onChange: (e) => set("city", e.target.value)
|
|
1945
|
+
}
|
|
1946
|
+
)
|
|
1947
|
+
] }),
|
|
1948
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "space-y-1", children: [
|
|
1949
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("label", { htmlFor: "full-invoice-country", className: "text-sm font-medium", children: t.country }),
|
|
1950
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1951
|
+
"select",
|
|
1952
|
+
{
|
|
1953
|
+
id: "full-invoice-country",
|
|
1954
|
+
className: FIELD_CLASS3,
|
|
1955
|
+
required: true,
|
|
1956
|
+
value: value.country,
|
|
1957
|
+
onChange: (e) => set("country", e.target.value),
|
|
1958
|
+
children: countries.map((c) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("option", { value: c.code, children: c.name }, c.code))
|
|
1959
|
+
}
|
|
1960
|
+
)
|
|
1961
|
+
] }),
|
|
1962
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "sm:col-span-2", children: error("address") })
|
|
1963
|
+
] })
|
|
1964
|
+
] });
|
|
1965
|
+
}
|
|
1966
|
+
|
|
1967
|
+
// src/components/course-guest-checkout-form.tsx
|
|
1968
|
+
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
1969
|
+
var DEFAULT_COURSE_GUEST_CHECKOUT_FORM_LABELS = {
|
|
1970
|
+
firstNameLabel: "Nombre",
|
|
1971
|
+
lastNameLabel: "Apellidos",
|
|
1972
|
+
emailLabel: "Email",
|
|
1973
|
+
total: (total) => `Total (impuestos incluidos): ${total}`,
|
|
1974
|
+
submit: "Continuar al pago",
|
|
1975
|
+
submitting: "Procesando\u2026",
|
|
1976
|
+
firstNameRequired: "Indica tu nombre.",
|
|
1977
|
+
lastNameRequired: "Indica tus apellidos.",
|
|
1978
|
+
emailInvalid: "Introduce un email v\xE1lido.",
|
|
1979
|
+
termsRequired: "Para continuar, acepta las condiciones.",
|
|
1980
|
+
consentRequired: "Para continuar, marca esta casilla.",
|
|
1981
|
+
requestRequiredNotice: "Este curso se solicita antes de pagar. Completa la solicitud.",
|
|
1982
|
+
genericError: "No hemos podido iniciar el pago. Int\xE9ntalo de nuevo."
|
|
1983
|
+
};
|
|
1984
|
+
var DEFAULT_COURSE_GUEST_CHECKOUT_ERROR_MESSAGES = {
|
|
1985
|
+
INVALID_INPUT: "Revisa los datos introducidos.",
|
|
1986
|
+
RATE_LIMITED: "Demasiados intentos. Espera unos minutos e int\xE9ntalo de nuevo.",
|
|
1987
|
+
COURSE_NOT_FOUND: "Este curso ya no est\xE1 disponible.",
|
|
1988
|
+
SALES_CLOSED: "Este curso no est\xE1 a la venta en este momento.",
|
|
1989
|
+
ENROLLMENT_REQUEST_REQUIRED: "Este curso se solicita antes de pagar.",
|
|
1990
|
+
INVOICING_NOT_READY: "No se puede completar la compra en este momento. Int\xE9ntalo m\xE1s tarde.",
|
|
1991
|
+
TERMS_NOT_ACCEPTED: "Para continuar, acepta las condiciones.",
|
|
1992
|
+
TERMS_VERSION_CHANGED: "Las condiciones se han actualizado. Recarga la p\xE1gina y vuelve a aceptarlas.",
|
|
1993
|
+
CONSENT_REQUIRED: "Para continuar, marca la casilla del curso.",
|
|
1994
|
+
CONSENT_VERSION_CHANGED: "El texto de la casilla ha cambiado. Recarga la p\xE1gina y vuelve a marcarla.",
|
|
1995
|
+
INVALID_BILLING: "Revisa los datos de facturaci\xF3n."
|
|
1996
|
+
};
|
|
1997
|
+
var EMAIL_PATTERN3 = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
1998
|
+
var FIELD_CLASS4 = "w-full rounded-lg border bg-background px-3 py-2 text-sm transition focus:outline-none focus:ring-2 focus:ring-primary/20";
|
|
1999
|
+
async function postToRoute3(endpoint, input) {
|
|
2000
|
+
try {
|
|
2001
|
+
const res = await fetch(endpoint, {
|
|
2002
|
+
method: "POST",
|
|
2003
|
+
headers: { "Content-Type": "application/json" },
|
|
2004
|
+
body: JSON.stringify(input)
|
|
2005
|
+
});
|
|
2006
|
+
const json = await res.json().catch(() => null);
|
|
2007
|
+
if (res.ok && json?.data) return { ok: true, data: json.data };
|
|
2008
|
+
return {
|
|
2009
|
+
ok: false,
|
|
2010
|
+
status: res.status,
|
|
2011
|
+
...typeof json?.code === "string" ? { code: json.code } : {},
|
|
2012
|
+
...json?.details !== void 0 ? { details: json.details } : {}
|
|
2013
|
+
};
|
|
2014
|
+
} catch {
|
|
2015
|
+
return { ok: false, status: 0 };
|
|
2016
|
+
}
|
|
2017
|
+
}
|
|
2018
|
+
function fieldErrorsOf(details) {
|
|
2019
|
+
const errors = details?.fieldErrors;
|
|
2020
|
+
if (typeof errors !== "object" || errors === null) return {};
|
|
2021
|
+
return Object.fromEntries(
|
|
2022
|
+
Object.entries(errors).filter(
|
|
2023
|
+
(entry) => typeof entry[1] === "string"
|
|
2024
|
+
)
|
|
2025
|
+
);
|
|
2026
|
+
}
|
|
2027
|
+
function toInvoiceErrors(fieldErrors) {
|
|
2028
|
+
const out = {};
|
|
2029
|
+
for (const key of ["billingIdType", "billingIdCountry", "billingNif", "billingName"]) {
|
|
2030
|
+
if (fieldErrors[key]) out[key] = fieldErrors[key];
|
|
2031
|
+
}
|
|
2032
|
+
if (fieldErrors.billingAddress) out.address = fieldErrors.billingAddress;
|
|
2033
|
+
return out;
|
|
2034
|
+
}
|
|
2035
|
+
function CourseGuestCheckoutForm({
|
|
2036
|
+
course,
|
|
2037
|
+
copy,
|
|
2038
|
+
termsHref,
|
|
2039
|
+
requestForm,
|
|
2040
|
+
issuesInvoices = true,
|
|
2041
|
+
simplifiedInvoiceCapCents = null,
|
|
2042
|
+
submit,
|
|
2043
|
+
endpoint = "/api/academy/checkout",
|
|
2044
|
+
onRedirect,
|
|
2045
|
+
onError,
|
|
2046
|
+
labels,
|
|
2047
|
+
errorMessages,
|
|
2048
|
+
invoiceLabels,
|
|
2049
|
+
invoiceCountries,
|
|
2050
|
+
currencyCode,
|
|
2051
|
+
locale,
|
|
2052
|
+
className
|
|
2053
|
+
}) {
|
|
2054
|
+
const t = {
|
|
2055
|
+
...DEFAULT_COURSE_GUEST_CHECKOUT_FORM_LABELS,
|
|
2056
|
+
...labels
|
|
2057
|
+
};
|
|
2058
|
+
const messages = { ...DEFAULT_COURSE_GUEST_CHECKOUT_ERROR_MESSAGES, ...errorMessages };
|
|
2059
|
+
const id = (0, import_react8.useId)();
|
|
2060
|
+
const [firstName, setFirstName] = (0, import_react8.useState)("");
|
|
2061
|
+
const [lastName, setLastName] = (0, import_react8.useState)("");
|
|
2062
|
+
const [email, setEmail] = (0, import_react8.useState)("");
|
|
2063
|
+
const [acceptsTerms, setAcceptsTerms] = (0, import_react8.useState)(false);
|
|
2064
|
+
const [acceptsConsent, setAcceptsConsent] = (0, import_react8.useState)(false);
|
|
2065
|
+
const [invoice, setInvoice] = (0, import_react8.useState)(EMPTY_FULL_INVOICE_VALUE);
|
|
2066
|
+
const [errors, setErrors] = (0, import_react8.useState)({});
|
|
2067
|
+
const [invoiceErrors, setInvoiceErrors] = (0, import_react8.useState)({});
|
|
2068
|
+
const [formError, setFormError] = (0, import_react8.useState)(null);
|
|
2069
|
+
const [submitting, setSubmitting] = (0, import_react8.useState)(false);
|
|
2070
|
+
const [needsRequest, setNeedsRequest] = (0, import_react8.useState)(false);
|
|
2071
|
+
const consent = course.withdrawalConsent;
|
|
2072
|
+
const hasTerms = Boolean(copy.termsVersion);
|
|
2073
|
+
const overCap = isOverSimplifiedInvoiceCap(course.priceCents, simplifiedInvoiceCapCents);
|
|
2074
|
+
const formattedTotal = formatPrice(course.priceCents, currencyCode, locale);
|
|
2075
|
+
const notice = copy.payNotice ? copy.payNotice.replaceAll("{total}", formattedTotal).replaceAll("{tenant}", copy.tenantName) : null;
|
|
2076
|
+
if (needsRequest) {
|
|
2077
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { "data-slot": "course-guest-checkout-request", className: (0, import_utils14.cn)("space-y-4", className), children: [
|
|
2078
|
+
t.requestRequiredNotice ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: "text-sm text-muted-foreground", children: t.requestRequiredNotice }) : null,
|
|
2079
|
+
requestForm
|
|
2080
|
+
] });
|
|
2081
|
+
}
|
|
2082
|
+
async function handleSubmit(event) {
|
|
2083
|
+
event.preventDefault();
|
|
2084
|
+
if (submitting) return;
|
|
2085
|
+
setFormError(null);
|
|
2086
|
+
setInvoiceErrors({});
|
|
2087
|
+
const next = {};
|
|
2088
|
+
if (!firstName.trim()) next.firstName = t.firstNameRequired;
|
|
2089
|
+
if (!lastName.trim()) next.lastName = t.lastNameRequired;
|
|
2090
|
+
if (!EMAIL_PATTERN3.test(email.trim())) next.email = t.emailInvalid;
|
|
2091
|
+
if (hasTerms && !acceptsTerms) next.terms = t.termsRequired;
|
|
2092
|
+
if (consent && !acceptsConsent) next.consent = t.consentRequired;
|
|
2093
|
+
setErrors(next);
|
|
2094
|
+
if (Object.keys(next).length > 0) return;
|
|
2095
|
+
const input = {
|
|
2096
|
+
courseSlug: course.slug,
|
|
2097
|
+
firstName: firstName.trim(),
|
|
2098
|
+
lastName: lastName.trim(),
|
|
2099
|
+
email: email.trim(),
|
|
2100
|
+
...toCheckoutTermsFields(copy, acceptsTerms),
|
|
2101
|
+
...consent ? { acceptsWithdrawalWaiver: acceptsConsent, withdrawalWaiverVersion: consent.version } : {},
|
|
2102
|
+
...toAcademyCheckoutInvoiceFields(invoice, overCap, issuesInvoices)
|
|
2103
|
+
};
|
|
2104
|
+
setSubmitting(true);
|
|
2105
|
+
try {
|
|
2106
|
+
const result = await (submit ?? ((body) => postToRoute3(endpoint, body)))(input).catch(
|
|
2107
|
+
() => ({ ok: false, status: 0 })
|
|
2108
|
+
);
|
|
2109
|
+
if (result.ok) {
|
|
2110
|
+
;
|
|
2111
|
+
(onRedirect ?? ((url) => window.location.assign(url)))(result.data.url);
|
|
2112
|
+
return;
|
|
2113
|
+
}
|
|
2114
|
+
onError?.(result);
|
|
2115
|
+
if (result.code === "ENROLLMENT_REQUEST_REQUIRED") {
|
|
2116
|
+
setNeedsRequest(true);
|
|
2117
|
+
return;
|
|
2118
|
+
}
|
|
2119
|
+
if (result.code === "INVALID_BILLING")
|
|
2120
|
+
setInvoiceErrors(toInvoiceErrors(fieldErrorsOf(result.details)));
|
|
2121
|
+
const code = result.code;
|
|
2122
|
+
setFormError(code && messages[code] || t.genericError);
|
|
2123
|
+
} finally {
|
|
2124
|
+
setSubmitting(false);
|
|
2125
|
+
}
|
|
2126
|
+
}
|
|
2127
|
+
const fieldError = (field) => errors[field] ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { id: `${id}-${field}-error`, className: "text-xs text-destructive", children: errors[field] }) : null;
|
|
2128
|
+
const invalid = (field) => errors[field] ? { "aria-invalid": true, "aria-describedby": `${id}-${field}-error` } : {};
|
|
2129
|
+
const border = (field) => errors[field] ? "border-destructive" : "border-border";
|
|
2130
|
+
const textField = (field, label, value, onChange, autoComplete) => /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "space-y-1", children: [
|
|
2131
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("label", { htmlFor: `${id}-${field}`, className: "text-sm font-medium", children: label }),
|
|
2132
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2133
|
+
"input",
|
|
2134
|
+
{
|
|
2135
|
+
id: `${id}-${field}`,
|
|
2136
|
+
type: field === "email" ? "email" : "text",
|
|
2137
|
+
autoComplete,
|
|
2138
|
+
maxLength: field === "email" ? 254 : 200,
|
|
2139
|
+
value,
|
|
2140
|
+
onChange: (e) => onChange(e.target.value),
|
|
2141
|
+
...invalid(field),
|
|
2142
|
+
className: (0, import_utils14.cn)(FIELD_CLASS4, border(field))
|
|
2143
|
+
}
|
|
2144
|
+
),
|
|
2145
|
+
fieldError(field)
|
|
2146
|
+
] });
|
|
2147
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
|
|
2148
|
+
"form",
|
|
2149
|
+
{
|
|
2150
|
+
noValidate: true,
|
|
2151
|
+
onSubmit: handleSubmit,
|
|
2152
|
+
"data-slot": "course-guest-checkout-form",
|
|
2153
|
+
className: (0, import_utils14.cn)("space-y-6", className),
|
|
2154
|
+
children: [
|
|
2155
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "grid grid-cols-1 gap-4 sm:grid-cols-2", children: [
|
|
2156
|
+
textField("firstName", t.firstNameLabel, firstName, setFirstName, "given-name"),
|
|
2157
|
+
textField("lastName", t.lastNameLabel, lastName, setLastName, "family-name"),
|
|
2158
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "sm:col-span-2", children: textField("email", t.emailLabel, email, setEmail, "email") })
|
|
2159
|
+
] }),
|
|
2160
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2161
|
+
FullInvoiceFields,
|
|
2162
|
+
{
|
|
2163
|
+
value: invoice,
|
|
2164
|
+
onChange: setInvoice,
|
|
2165
|
+
overCap,
|
|
2166
|
+
issuesInvoices,
|
|
2167
|
+
errors: invoiceErrors,
|
|
2168
|
+
countries: invoiceCountries,
|
|
2169
|
+
labels: {
|
|
2170
|
+
...copy.fullInvoiceCheckboxLabel ? { toggle: copy.fullInvoiceCheckboxLabel } : {},
|
|
2171
|
+
...copy.fullInvoiceHelpText ? { underCapNotice: copy.fullInvoiceHelpText } : {},
|
|
2172
|
+
...invoiceLabels
|
|
2173
|
+
}
|
|
2174
|
+
}
|
|
2175
|
+
),
|
|
2176
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "space-y-3", children: [
|
|
2177
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2178
|
+
CheckoutTermsAcceptance,
|
|
2179
|
+
{
|
|
2180
|
+
copy,
|
|
2181
|
+
termsHref,
|
|
2182
|
+
checked: acceptsTerms,
|
|
2183
|
+
onCheckedChange: setAcceptsTerms,
|
|
2184
|
+
error: errors.terms,
|
|
2185
|
+
id: `${id}-terms`
|
|
2186
|
+
}
|
|
2187
|
+
),
|
|
2188
|
+
consent ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
|
|
2189
|
+
"div",
|
|
2190
|
+
{
|
|
2191
|
+
"data-slot": "course-guest-checkout-consent",
|
|
2192
|
+
"data-kind": consent.kind,
|
|
2193
|
+
className: "space-y-1",
|
|
2194
|
+
children: [
|
|
2195
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex items-start gap-3", children: [
|
|
2196
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2197
|
+
"input",
|
|
2198
|
+
{
|
|
2199
|
+
id: `${id}-consent`,
|
|
2200
|
+
type: "checkbox",
|
|
2201
|
+
checked: acceptsConsent,
|
|
2202
|
+
onChange: (e) => setAcceptsConsent(e.target.checked),
|
|
2203
|
+
...invalid("consent"),
|
|
2204
|
+
className: "mt-0.5 size-5 shrink-0 cursor-pointer accent-primary"
|
|
2205
|
+
}
|
|
2206
|
+
),
|
|
2207
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("label", { htmlFor: `${id}-consent`, className: "text-sm leading-relaxed", children: consent.text })
|
|
2208
|
+
] }),
|
|
2209
|
+
errors.consent ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { id: `${id}-consent-error`, className: "pl-8 text-sm text-destructive", children: errors.consent }) : null
|
|
2210
|
+
]
|
|
2211
|
+
}
|
|
2212
|
+
) : null
|
|
2213
|
+
] }),
|
|
2214
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { "data-slot": "course-guest-checkout-total", className: "text-base font-semibold", children: t.total(formattedTotal) }),
|
|
2215
|
+
formError ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { role: "alert", className: "text-sm text-destructive", children: formError }) : null,
|
|
2216
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2217
|
+
CheckoutPayAction,
|
|
2218
|
+
{
|
|
2219
|
+
label: copy.continueToPaymentLabel ?? t.submit,
|
|
2220
|
+
notice,
|
|
2221
|
+
submitting,
|
|
2222
|
+
submittingLabel: t.submitting,
|
|
2223
|
+
id: `${id}-pay`
|
|
2224
|
+
}
|
|
2225
|
+
)
|
|
2226
|
+
]
|
|
2227
|
+
}
|
|
2228
|
+
);
|
|
2229
|
+
}
|
|
1601
2230
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1602
2231
|
0 && (module.exports = {
|
|
1603
2232
|
AddToCartButton,
|
|
1604
2233
|
CartIcon,
|
|
1605
2234
|
Collection,
|
|
2235
|
+
CourseGuestCheckoutForm,
|
|
1606
2236
|
CourseSyllabus,
|
|
1607
2237
|
DATA_REQUEST_FIELD_LIMITS,
|
|
1608
2238
|
DATA_REQUEST_TYPES,
|
|
2239
|
+
DEFAULT_COURSE_GUEST_CHECKOUT_ERROR_MESSAGES,
|
|
2240
|
+
DEFAULT_COURSE_GUEST_CHECKOUT_FORM_LABELS,
|
|
1609
2241
|
DEFAULT_COURSE_SYLLABUS_LABELS,
|
|
1610
2242
|
DEFAULT_DATA_REQUEST_FORM_LABELS,
|
|
1611
2243
|
DEFAULT_PRODUCT_CAROUSEL_LABELS,
|