@voyantjs/checkout-ui 0.34.0 → 0.37.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.
@@ -1 +1 @@
1
- {"version":3,"file":"collect-payment-dialog.d.ts","sourceRoot":"","sources":["../../src/components/collect-payment-dialog.tsx"],"names":[],"mappings":"AAqBA;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,WAAW,yBAAyB;IACxC,IAAI,EAAE,OAAO,CAAA;IACb,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IACrC,SAAS,EAAE,MAAM,CAAA;IACjB,eAAe,EAAE,MAAM,CAAA;IACvB,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAClC,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACjC,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAChC;;;;OAIG;IACH,oBAAoB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACpC;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,oEAAoE;IACpE,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAaD,wBAAgB,oBAAoB,CAAC,EACnC,IAAI,EACJ,YAAY,EACZ,SAAS,EACT,eAAe,EACf,kBAAkB,EAClB,iBAAiB,EACjB,gBAAgB,EAChB,oBAAoB,EACpB,SAAS,EACT,SAAS,EACT,YAAY,GACb,EAAE,yBAAyB,2CA8G3B"}
1
+ {"version":3,"file":"collect-payment-dialog.d.ts","sourceRoot":"","sources":["../../src/components/collect-payment-dialog.tsx"],"names":[],"mappings":"AAuBA;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,WAAW,yBAAyB;IACxC,IAAI,EAAE,OAAO,CAAA;IACb,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IACrC,SAAS,EAAE,MAAM,CAAA;IACjB,eAAe,EAAE,MAAM,CAAA;IACvB,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAClC,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACjC,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAChC;;;;OAIG;IACH,oBAAoB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACpC;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,oEAAoE;IACpE,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAaD,wBAAgB,oBAAoB,CAAC,EACnC,IAAI,EACJ,YAAY,EACZ,SAAS,EACT,eAAe,EACf,kBAAkB,EAClB,iBAAiB,EACjB,gBAAgB,EAChB,oBAAoB,EACpB,SAAS,EACT,SAAS,EACT,YAAY,GACb,EAAE,yBAAyB,2CA4G3B"}
@@ -1,6 +1,7 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
3
  import { useCollectPayment } from "@voyantjs/checkout-react";
4
+ import { formatMessage } from "@voyantjs/i18n";
4
5
  import { Button } from "@voyantjs/ui/components/button";
5
6
  import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from "@voyantjs/ui/components/dialog";
6
7
  import { Input } from "@voyantjs/ui/components/input";
@@ -8,6 +9,7 @@ import { Label } from "@voyantjs/ui/components/label";
8
9
  import { CheckCircle2, Copy, ExternalLink, Loader2 } from "lucide-react";
9
10
  import { useMemo, useState } from "react";
10
11
  import { toast } from "sonner";
12
+ import { useCheckoutUiMessagesOrDefault } from "../i18n/provider.js";
11
13
  import { PaymentStep } from "./payment-step.js";
12
14
  /**
13
15
  * Operator dialog defaults to immediate-charge disabled. Templates that
@@ -20,6 +22,7 @@ const CAPABILITIES = {
20
22
  newCard: false,
21
23
  };
22
24
  export function CollectPaymentDialog({ open, onOpenChange, bookingId, defaultCurrency, defaultAmountCents, defaultPayerEmail, defaultPayerName, defaultPayerLanguage, returnUrl, cancelUrl, cardProvider, }) {
25
+ const messages = useCheckoutUiMessagesOrDefault().collectPaymentDialog;
23
26
  const [amountCents, setAmountCents] = useState(defaultAmountCents ?? 0);
24
27
  const [choice, setChoice] = useState(null);
25
28
  const [result, setResult] = useState(null);
@@ -40,17 +43,17 @@ export function CollectPaymentDialog({ open, onOpenChange, bookingId, defaultCur
40
43
  }
41
44
  async function submit() {
42
45
  if (!choice || choice.type !== "hold") {
43
- toast.error("Pick 'Hold — generate payment link' to produce a shareable link.");
46
+ toast.error(messages.validation.pickHold);
44
47
  return;
45
48
  }
46
49
  if (amountCents <= 0) {
47
- toast.error("Enter an amount above zero.");
50
+ toast.error(messages.validation.amountAboveZero);
48
51
  return;
49
52
  }
50
53
  try {
51
54
  const data = await collect.mutateAsync({ choice, amountCents });
52
55
  setResult(data);
53
- toast.success("Payment link ready — copy or share it with the customer.");
56
+ toast.success(messages.validation.linkReady);
54
57
  }
55
58
  catch (err) {
56
59
  toast.error(err.message);
@@ -60,18 +63,21 @@ export function CollectPaymentDialog({ open, onOpenChange, bookingId, defaultCur
60
63
  onOpenChange(next);
61
64
  if (!next)
62
65
  reset();
63
- }, children: _jsxs(DialogContent, { className: "max-w-xl", children: [_jsxs(DialogHeader, { children: [_jsx(DialogTitle, { children: "Generate payment link" }), _jsx(DialogDescription, { children: "Hold the booking and produce a payment link the customer can open to pay by card or bank transfer. Share it however you prefer (email, chat, etc.)." })] }), result ? (_jsx(ResultPanel, { result: result })) : (_jsxs("div", { className: "flex flex-col gap-5", children: [_jsxs("div", { className: "flex flex-col gap-2", children: [_jsxs(Label, { htmlFor: "collect-amount", children: ["Amount (", defaultCurrency, ")"] }), _jsx(Input, { id: "collect-amount", type: "number", inputMode: "decimal", step: "0.01", min: "0", value: amountInputValue, onChange: (e) => {
66
+ }, children: _jsxs(DialogContent, { className: "max-w-xl", children: [_jsxs(DialogHeader, { children: [_jsx(DialogTitle, { children: messages.title }), _jsx(DialogDescription, { children: messages.description })] }), result ? (_jsx(ResultPanel, { result: result })) : (_jsxs("div", { className: "flex flex-col gap-5", children: [_jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { htmlFor: "collect-amount", children: formatMessage(messages.amountLabel, { currency: defaultCurrency }) }), _jsx(Input, { id: "collect-amount", type: "number", inputMode: "decimal", step: "0.01", min: "0", value: amountInputValue, onChange: (e) => {
64
67
  const raw = Number.parseFloat(e.target.value);
65
68
  setAmountCents(Number.isFinite(raw) ? Math.round(raw * 100) : 0);
66
- } }), _jsx("p", { className: "text-muted-foreground text-xs", children: "Defaults to the booking's sell amount. Override for a deposit or partial collection." })] }), _jsx(PaymentStep, { value: choice, onChange: setChoice, capabilities: CAPABILITIES })] })), _jsx(DialogFooter, { children: result ? (_jsx(Button, { onClick: () => onOpenChange(false), children: "Done" })) : (_jsxs(_Fragment, { children: [_jsx(Button, { variant: "outline", onClick: () => onOpenChange(false), disabled: collect.isPending, children: "Cancel" }), _jsxs(Button, { onClick: submit, disabled: collect.isPending || choice?.type !== "hold", children: [collect.isPending && _jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }), "Generate link"] })] })) })] }) }));
69
+ } }), _jsx("p", { className: "text-muted-foreground text-xs", children: messages.amountHelp })] }), _jsx(PaymentStep, { value: choice, onChange: setChoice, capabilities: CAPABILITIES })] })), _jsx(DialogFooter, { children: result ? (_jsx(Button, { onClick: () => onOpenChange(false), children: messages.done })) : (_jsxs(_Fragment, { children: [_jsx(Button, { variant: "outline", onClick: () => onOpenChange(false), disabled: collect.isPending, children: messages.cancel }), _jsxs(Button, { onClick: submit, disabled: collect.isPending || choice?.type !== "hold", children: [collect.isPending && _jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }), messages.generateLink] })] })) })] }) }));
67
70
  }
68
71
  function ResultPanel({ result }) {
72
+ const messages = useCheckoutUiMessagesOrDefault().collectPaymentDialog;
69
73
  const sessionId = result.paymentSession?.id ?? null;
70
74
  const landingUrl = sessionId && typeof window !== "undefined" ? `${window.location.origin}/pay/${sessionId}` : null;
71
75
  if (!landingUrl) {
72
- return (_jsxs("div", { className: "rounded-xl border border-amber-500/40 bg-amber-500/5 p-5 text-sm", children: ["The session was created but no link could be built. Session id:", " ", _jsx("span", { className: "font-mono", children: sessionId ?? "—" }), "."] }));
76
+ return (_jsx("div", { className: "rounded-xl border border-amber-500/40 bg-amber-500/5 p-5 text-sm", children: formatMessage(messages.result.noLink, {
77
+ sessionId: sessionId ?? messages.result.noSession,
78
+ }) }));
73
79
  }
74
- return (_jsxs("div", { className: "flex flex-col gap-4 rounded-xl border bg-card p-5", children: [_jsxs("div", { className: "flex items-center gap-2 text-emerald-700", children: [_jsx(CheckCircle2, { className: "h-5 w-5" }), _jsx("span", { className: "font-medium", children: "Payment link ready" })] }), _jsx("p", { className: "text-muted-foreground text-sm", children: "Share this link with the customer. They'll choose card or bank transfer on the page." }), _jsxs("div", { className: "flex items-center gap-2 rounded-md border bg-muted/30 p-3 font-mono text-xs", children: [_jsx("span", { className: "flex-1 break-all", children: landingUrl }), _jsx("button", { type: "button", "aria-label": "Copy link", className: "text-muted-foreground hover:text-foreground", onClick: () => {
80
+ return (_jsxs("div", { className: "flex flex-col gap-4 rounded-xl border bg-card p-5", children: [_jsxs("div", { className: "flex items-center gap-2 text-emerald-700", children: [_jsx(CheckCircle2, { className: "h-5 w-5" }), _jsx("span", { className: "font-medium", children: messages.result.ready })] }), _jsx("p", { className: "text-muted-foreground text-sm", children: messages.result.body }), _jsxs("div", { className: "flex items-center gap-2 rounded-md border bg-muted/30 p-3 font-mono text-xs", children: [_jsx("span", { className: "flex-1 break-all", children: landingUrl }), _jsx("button", { type: "button", "aria-label": messages.result.copyLink, className: "text-muted-foreground hover:text-foreground", onClick: () => {
75
81
  navigator.clipboard?.writeText(landingUrl).catch(() => undefined);
76
- }, children: _jsx(Copy, { className: "h-3.5 w-3.5" }) }), _jsx("a", { href: landingUrl, target: "_blank", rel: "noreferrer", "aria-label": "Open link", className: "text-muted-foreground hover:text-foreground", children: _jsx(ExternalLink, { className: "h-3.5 w-3.5" }) })] })] }));
82
+ }, children: _jsx(Copy, { className: "h-3.5 w-3.5" }) }), _jsx("a", { href: landingUrl, target: "_blank", rel: "noreferrer", "aria-label": messages.result.openLink, className: "text-muted-foreground hover:text-foreground", children: _jsx(ExternalLink, { className: "h-3.5 w-3.5" }) })] })] }));
77
83
  }
@@ -1 +1 @@
1
- {"version":3,"file":"payment-link-landing-page.d.ts","sourceRoot":"","sources":["../../src/components/payment-link-landing-page.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,qCAAqC,CAAA;AAa/E,OAAO,EAAE,KAAK,SAAS,EAAY,MAAM,OAAO,CAAA;AAOhD;;;;;;;;;;;;;;;GAeG;AACH,MAAM,WAAW,2BAA2B;IAC1C,OAAO,EAAE,oBAAoB,CAAA;IAC7B,2EAA2E;IAC3E,wBAAwB,CAAC,EAAE,wBAAwB,CAAA;IACnD,gEAAgE;IAChE,WAAW,CAAC,EAAE,SAAS,CAAA;IACvB,yDAAyD;IACzD,WAAW,CAAC,EAAE,SAAS,CAAA;IACvB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,IAAI,CAAA;IACxB;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;;;;;;;;OAQG;IACH,OAAO,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;CACrC;AAED,MAAM,WAAW,wBAAwB;IACvC,eAAe,EAAE,MAAM,CAAA;IACvB,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,uDAAuD;IACvD,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,wBAAgB,sBAAsB,CAAC,EACrC,OAAO,EACP,wBAAwB,EACxB,WAAW,EACX,WAAW,EACX,WAAW,EACX,OAAO,EACP,WAAW,GACZ,EAAE,2BAA2B,2CAc7B"}
1
+ {"version":3,"file":"payment-link-landing-page.d.ts","sourceRoot":"","sources":["../../src/components/payment-link-landing-page.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,qCAAqC,CAAA;AAc/E,OAAO,EAAE,KAAK,SAAS,EAAY,MAAM,OAAO,CAAA;AAUhD;;;;;;;;;;;;;;;GAeG;AACH,MAAM,WAAW,2BAA2B;IAC1C,OAAO,EAAE,oBAAoB,CAAA;IAC7B,2EAA2E;IAC3E,wBAAwB,CAAC,EAAE,wBAAwB,CAAA;IACnD,gEAAgE;IAChE,WAAW,CAAC,EAAE,SAAS,CAAA;IACvB,yDAAyD;IACzD,WAAW,CAAC,EAAE,SAAS,CAAA;IACvB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,IAAI,CAAA;IACxB;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;;;;;;;;OAQG;IACH,OAAO,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;CACrC;AAED,MAAM,WAAW,wBAAwB;IACvC,eAAe,EAAE,MAAM,CAAA;IACvB,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,uDAAuD;IACvD,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,wBAAgB,sBAAsB,CAAC,EACrC,OAAO,EACP,wBAAwB,EACxB,WAAW,EACX,WAAW,EACX,WAAW,EACX,OAAO,EACP,WAAW,GACZ,EAAE,2BAA2B,2CAc7B"}
@@ -1,18 +1,30 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ import { formatMessage } from "@voyantjs/i18n";
3
4
  import { Button } from "@voyantjs/ui/components/button";
4
5
  import { Tabs, TabsContent, TabsList, TabsTrigger } from "@voyantjs/ui/components/tabs";
5
6
  import { cn } from "@voyantjs/ui/lib/utils";
6
7
  import { Building2, CheckCircle2, CircleAlert, Copy, CreditCard, ExternalLink, Loader2, } from "lucide-react";
7
8
  import { useState } from "react";
9
+ import { useCheckoutUiI18nOrDefault, useCheckoutUiMessagesOrDefault } from "../i18n/provider.js";
8
10
  export function PaymentLinkLandingPage({ session, bankTransferInstructions, brandHeader, brandFooter, onPayByCard, onRetry, description, }) {
9
11
  return (_jsxs("div", { className: "mx-auto flex min-h-screen w-full max-w-2xl flex-col gap-6 px-4 py-8", children: [brandHeader, _jsx(Header, { session: session, description: description }), _jsx(Body, { session: session, bankTransferInstructions: bankTransferInstructions, onPayByCard: onPayByCard, onRetry: onRetry }), brandFooter] }));
10
12
  }
11
13
  // ─────────────────────────────────────────────────────────────────────────────
12
14
  function Header({ session, description }) {
13
- return (_jsxs("header", { className: "flex flex-col gap-2 border-b pb-4", children: [_jsx("h1", { className: "font-semibold text-2xl", children: description ?? defaultDescription(session) }), session.notes && _jsx("p", { className: "text-muted-foreground text-sm", children: session.notes }), _jsxs("div", { className: "flex items-baseline gap-3", children: [_jsx("span", { className: "font-semibold text-3xl tabular-nums", children: formatMoneyCents(session.amountCents, session.currency) }), session.expiresAt && session.status !== "paid" && (_jsxs("span", { className: "text-muted-foreground text-sm", children: ["Expires ", formatDateTime(session.expiresAt)] }))] })] }));
15
+ const i18n = useCheckoutUiI18nOrDefault();
16
+ const messages = i18n.messages.paymentLinkLandingPage;
17
+ return (_jsxs("header", { className: "flex flex-col gap-2 border-b pb-4", children: [_jsx("h1", { className: "font-semibold text-2xl", children: description ?? defaultDescription(session, messages) }), session.notes && _jsx("p", { className: "text-muted-foreground text-sm", children: session.notes }), _jsxs("div", { className: "flex items-baseline gap-3", children: [_jsx("span", { className: "font-semibold text-3xl tabular-nums", children: i18n.formatCurrency(session.amountCents / 100, session.currency) }), session.expiresAt && session.status !== "paid" && (_jsx("span", { className: "text-muted-foreground text-sm", children: formatMessage(messages.expires, {
18
+ date: i18n.formatDateTime(session.expiresAt, {
19
+ day: "numeric",
20
+ month: "short",
21
+ hour: "2-digit",
22
+ minute: "2-digit",
23
+ }),
24
+ }) }))] })] }));
14
25
  }
15
26
  function Body({ session, bankTransferInstructions, onPayByCard, onRetry, }) {
27
+ const messages = useCheckoutUiMessagesOrDefault().paymentLinkLandingPage;
16
28
  // Terminal states — short-circuit body to a status panel.
17
29
  if (session.status === "paid")
18
30
  return _jsx(TerminalState, { status: "paid", reason: null });
@@ -33,7 +45,7 @@ function Body({ session, bankTransferInstructions, onPayByCard, onRetry, }) {
33
45
  // No method available — soft fallback (rare; signals a misconfigured
34
46
  // session that has neither a redirect URL nor a bank-transfer block).
35
47
  if (!cardAvailable && !bankAvailable) {
36
- return (_jsxs("div", { className: "rounded-xl border border-amber-500/40 bg-amber-500/5 p-5 text-sm", children: [_jsx("p", { className: "font-medium", children: "No payment method available" }), _jsx("p", { className: "mt-2 text-muted-foreground", children: "This payment link doesn't have any payment methods configured. Please contact your travel agent." })] }));
48
+ return (_jsxs("div", { className: "rounded-xl border border-amber-500/40 bg-amber-500/5 p-5 text-sm", children: [_jsx("p", { className: "font-medium", children: messages.noMethods.title }), _jsx("p", { className: "mt-2 text-muted-foreground", children: messages.noMethods.body })] }));
37
49
  }
38
50
  // Single method — render inline without tabs.
39
51
  if (cardAvailable && !bankAvailable) {
@@ -43,9 +55,11 @@ function Body({ session, bankTransferInstructions, onPayByCard, onRetry, }) {
43
55
  return _jsx(BankTransferPanel, { session: session, instructions: bankTransferInstructions });
44
56
  }
45
57
  // Both methods — tab strip.
46
- return (_jsxs(Tabs, { defaultValue: "card", className: "w-full", children: [_jsxs(TabsList, { className: "grid w-full grid-cols-2", children: [_jsxs(TabsTrigger, { value: "card", children: [_jsx(CreditCard, { className: "mr-2 h-4 w-4" }), "Pay by card"] }), _jsxs(TabsTrigger, { value: "bank", children: [_jsx(Building2, { className: "mr-2 h-4 w-4" }), "Bank transfer"] })] }), _jsx(TabsContent, { value: "card", className: "mt-4", children: _jsx(CardPanel, { session: session, onPayByCard: onPayByCard }) }), _jsx(TabsContent, { value: "bank", className: "mt-4", children: bankTransferInstructions && (_jsx(BankTransferPanel, { session: session, instructions: bankTransferInstructions })) })] }));
58
+ return (_jsxs(Tabs, { defaultValue: "card", className: "w-full", children: [_jsxs(TabsList, { className: "grid w-full grid-cols-2", children: [_jsxs(TabsTrigger, { value: "card", children: [_jsx(CreditCard, { className: "mr-2 h-4 w-4" }), messages.cardTab] }), _jsxs(TabsTrigger, { value: "bank", children: [_jsx(Building2, { className: "mr-2 h-4 w-4" }), messages.bankTab] })] }), _jsx(TabsContent, { value: "card", className: "mt-4", children: _jsx(CardPanel, { session: session, onPayByCard: onPayByCard }) }), _jsx(TabsContent, { value: "bank", className: "mt-4", children: bankTransferInstructions && (_jsx(BankTransferPanel, { session: session, instructions: bankTransferInstructions })) })] }));
47
59
  }
48
60
  function CardPanel({ session, onPayByCard, }) {
61
+ const i18n = useCheckoutUiI18nOrDefault();
62
+ const messages = i18n.messages.paymentLinkLandingPage;
49
63
  const [starting, setStarting] = useState(false);
50
64
  const [error, setError] = useState(null);
51
65
  const handleClick = async () => {
@@ -69,7 +83,7 @@ function CardPanel({ session, onPayByCard, }) {
69
83
  });
70
84
  const body = (await res.json());
71
85
  if (!res.ok || !body.data?.redirectUrl) {
72
- throw new Error(body.error ?? "Card payment couldn't be prepared.");
86
+ throw new Error(body.error ?? messages.card.startFailed);
73
87
  }
74
88
  window.location.href = body.data.redirectUrl;
75
89
  }
@@ -78,18 +92,25 @@ function CardPanel({ session, onPayByCard, }) {
78
92
  setStarting(false);
79
93
  }
80
94
  };
81
- return (_jsxs("div", { className: "rounded-xl border bg-card p-5 shadow-sm", children: [_jsx("p", { className: "mb-4 text-muted-foreground text-sm", children: "You'll be redirected to the secure payment page hosted by the card processor." }), _jsxs(Button, { className: "w-full", disabled: starting, onClick: handleClick, children: [starting && _jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }), "Pay ", formatMoneyCents(session.amountCents, session.currency), !starting && _jsx(ExternalLink, { className: "ml-2 h-4 w-4" })] }), error && (_jsxs("p", { className: "mt-3 text-destructive text-xs", children: [error, " If the issue persists, please pay by bank transfer or contact your travel agent."] }))] }));
95
+ return (_jsxs("div", { className: "rounded-xl border bg-card p-5 shadow-sm", children: [_jsx("p", { className: "mb-4 text-muted-foreground text-sm", children: messages.card.description }), _jsxs(Button, { className: "w-full", disabled: starting, onClick: handleClick, children: [starting && _jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }), formatMessage(messages.card.payAmount, {
96
+ amount: i18n.formatCurrency(session.amountCents / 100, session.currency),
97
+ }), !starting && _jsx(ExternalLink, { className: "ml-2 h-4 w-4" })] }), error && (_jsx("p", { className: "mt-3 text-destructive text-xs", children: formatMessage(messages.card.errorAdvice, { message: error }) }))] }));
82
98
  }
83
99
  function BankTransferPanel({ session, instructions, }) {
100
+ const i18n = useCheckoutUiI18nOrDefault();
101
+ const messages = i18n.messages.paymentLinkLandingPage;
84
102
  const reference = instructions.reference ?? session.externalReference ?? session.clientReference ?? session.id;
85
- return (_jsxs("div", { className: "rounded-xl border bg-card p-5 shadow-sm", children: [_jsxs("p", { className: "mb-4 text-muted-foreground text-sm", children: ["Wire ", formatMoneyCents(session.amountCents, session.currency), " to the account below. Your booking is confirmed once payment is received (typically 1\u20133 business days)."] }), _jsxs("dl", { className: "grid grid-cols-1 gap-2 text-sm", children: [_jsx(Row, { label: "Beneficiary", children: instructions.beneficiaryName }), _jsx(Row, { label: "IBAN", copyValue: instructions.iban, children: _jsx("span", { className: "font-mono", children: instructions.iban }) }), instructions.bic && (_jsx(Row, { label: "BIC / SWIFT", copyValue: instructions.bic, children: _jsx("span", { className: "font-mono", children: instructions.bic }) })), instructions.bankName && _jsx(Row, { label: "Bank", children: instructions.bankName }), _jsx(Row, { label: "Reference", copyValue: reference, children: _jsx("span", { className: "font-mono", children: reference }) })] }), instructions.notes && (_jsx("p", { className: "mt-4 text-muted-foreground text-xs", children: instructions.notes }))] }));
103
+ return (_jsxs("div", { className: "rounded-xl border bg-card p-5 shadow-sm", children: [_jsx("p", { className: "mb-4 text-muted-foreground text-sm", children: formatMessage(messages.bank.instructions, {
104
+ amount: i18n.formatCurrency(session.amountCents / 100, session.currency),
105
+ }) }), _jsxs("dl", { className: "grid grid-cols-1 gap-2 text-sm", children: [_jsx(Row, { label: messages.bank.beneficiary, children: instructions.beneficiaryName }), _jsx(Row, { label: messages.bank.iban, copyValue: instructions.iban, children: _jsx("span", { className: "font-mono", children: instructions.iban }) }), instructions.bic && (_jsx(Row, { label: messages.bank.bicSwift, copyValue: instructions.bic, children: _jsx("span", { className: "font-mono", children: instructions.bic }) })), instructions.bankName && _jsx(Row, { label: messages.bank.bank, children: instructions.bankName }), _jsx(Row, { label: messages.bank.reference, copyValue: reference, children: _jsx("span", { className: "font-mono", children: reference }) })] }), instructions.notes && (_jsx("p", { className: "mt-4 text-muted-foreground text-xs", children: instructions.notes }))] }));
86
106
  }
87
107
  function Row({ label, children, copyValue, }) {
88
108
  return (_jsxs("div", { className: "flex items-baseline justify-between gap-3 border-b py-1.5 last:border-b-0", children: [_jsx("dt", { className: "text-muted-foreground text-xs uppercase tracking-wider", children: label }), _jsxs("dd", { className: "flex items-center gap-2", children: [children, copyValue && _jsx(CopyButton, { value: copyValue })] })] }));
89
109
  }
90
110
  function CopyButton({ value }) {
111
+ const messages = useCheckoutUiMessagesOrDefault().paymentLinkLandingPage;
91
112
  const [copied, setCopied] = useState(false);
92
- return (_jsx("button", { type: "button", "aria-label": copied ? "Copied" : `Copy ${value}`, className: "text-muted-foreground transition-colors hover:text-foreground", onClick: async () => {
113
+ return (_jsx("button", { type: "button", "aria-label": copied ? messages.copy.copied : formatMessage(messages.copy.copyValue, { value }), className: "text-muted-foreground transition-colors hover:text-foreground", onClick: async () => {
93
114
  try {
94
115
  await navigator.clipboard?.writeText(value);
95
116
  setCopied(true);
@@ -102,31 +123,32 @@ function CopyButton({ value }) {
102
123
  }, children: copied ? (_jsx(CheckCircle2, { className: "h-3.5 w-3.5 text-emerald-600" })) : (_jsx(Copy, { className: "h-3.5 w-3.5" })) }));
103
124
  }
104
125
  function TerminalState({ status, reason, onRetry, }) {
126
+ const messages = useCheckoutUiMessagesOrDefault().paymentLinkLandingPage;
105
127
  const [retrying, setRetrying] = useState(false);
106
128
  const [retryError, setRetryError] = useState(null);
107
129
  const cfg = {
108
130
  paid: {
109
131
  icon: _jsx(CheckCircle2, { className: "h-10 w-10 text-emerald-600" }),
110
- title: "Payment received",
111
- body: "Thanks — your booking is confirmed. You'll receive a confirmation email shortly.",
132
+ title: messages.terminal.paid.title,
133
+ body: messages.terminal.paid.body,
112
134
  tone: "border-emerald-500/40 bg-emerald-500/5",
113
135
  },
114
136
  failed: {
115
137
  icon: _jsx(CircleAlert, { className: "h-10 w-10 text-destructive" }),
116
- title: "Payment failed",
117
- body: reason ?? "The payment couldn't be processed. Please try again or contact support.",
138
+ title: messages.terminal.failed.title,
139
+ body: reason ?? messages.terminal.failed.body,
118
140
  tone: "border-destructive/40 bg-destructive/5",
119
141
  },
120
142
  expired: {
121
143
  icon: _jsx(CircleAlert, { className: "h-10 w-10 text-amber-600" }),
122
- title: "Payment link expired",
123
- body: "This payment link has expired. Please request a new one from your travel agent.",
144
+ title: messages.terminal.expired.title,
145
+ body: messages.terminal.expired.body,
124
146
  tone: "border-amber-500/40 bg-amber-500/5",
125
147
  },
126
148
  cancelled: {
127
149
  icon: _jsx(CircleAlert, { className: "h-10 w-10 text-muted-foreground" }),
128
- title: "Payment cancelled",
129
- body: "This payment was cancelled. Please contact your travel agent if this is unexpected.",
150
+ title: messages.terminal.cancelled.title,
151
+ body: messages.terminal.cancelled.body,
130
152
  tone: "border-border bg-muted/20",
131
153
  },
132
154
  }[status];
@@ -140,47 +162,12 @@ function TerminalState({ status, reason, onRetry, }) {
140
162
  setRetryError(err.message);
141
163
  setRetrying(false);
142
164
  }
143
- }, children: [retrying && _jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }), "Try again"] }), retryError && _jsx("p", { className: "text-destructive text-xs", children: retryError })] }))] }));
165
+ }, children: [retrying && _jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }), messages.terminal.tryAgain] }), retryError && _jsx("p", { className: "text-destructive text-xs", children: retryError })] }))] }));
144
166
  }
145
167
  function ProcessingState() {
146
- return (_jsxs("div", { className: "flex flex-col items-center gap-3 rounded-xl border bg-card p-8 text-center", children: [_jsx(Loader2, { className: "h-10 w-10 animate-spin text-muted-foreground" }), _jsx("h2", { className: "font-semibold text-lg", children: "Processing payment\u2026" }), _jsx("p", { className: "max-w-md text-muted-foreground text-sm", children: "We're confirming the payment with the processor. This usually takes a few seconds." })] }));
168
+ const messages = useCheckoutUiMessagesOrDefault().paymentLinkLandingPage;
169
+ return (_jsxs("div", { className: "flex flex-col items-center gap-3 rounded-xl border bg-card p-8 text-center", children: [_jsx(Loader2, { className: "h-10 w-10 animate-spin text-muted-foreground" }), _jsx("h2", { className: "font-semibold text-lg", children: messages.processing.title }), _jsx("p", { className: "max-w-md text-muted-foreground text-sm", children: messages.processing.body })] }));
147
170
  }
148
- function defaultDescription(session) {
149
- switch (session.targetType) {
150
- case "booking":
151
- return "Booking payment";
152
- case "booking_payment_schedule":
153
- return "Booking deposit";
154
- case "booking_guarantee":
155
- return "Booking guarantee";
156
- case "invoice":
157
- return "Invoice payment";
158
- case "order":
159
- return "Order payment";
160
- case "flight_order":
161
- return "Flight payment";
162
- default:
163
- return "Payment";
164
- }
165
- }
166
- function formatMoneyCents(cents, currency) {
167
- const amount = cents / 100;
168
- if (!Number.isFinite(amount))
169
- return `${cents} ${currency}`;
170
- return new Intl.NumberFormat(undefined, {
171
- style: "currency",
172
- currency,
173
- maximumFractionDigits: 2,
174
- }).format(amount);
175
- }
176
- function formatDateTime(iso) {
177
- const d = new Date(iso);
178
- if (Number.isNaN(d.getTime()))
179
- return iso;
180
- return new Intl.DateTimeFormat(undefined, {
181
- day: "numeric",
182
- month: "short",
183
- hour: "2-digit",
184
- minute: "2-digit",
185
- }).format(d);
171
+ function defaultDescription(session, messages) {
172
+ return messages.descriptions[session.targetType] ?? messages.descriptions.default;
186
173
  }
@@ -1 +1 @@
1
- {"version":3,"file":"payment-step.d.ts","sourceRoot":"","sources":["../../src/components/payment-step.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,sBAAsB,IAAI,8BAA8B,EACxD,aAAa,EACb,uBAAuB,EACvB,mBAAmB,EACpB,MAAM,0BAA0B,CAAA;AAMjC,OAAO,EAAE,KAAK,SAAS,EAAY,MAAM,OAAO,CAAA;AAEhD;;;GAGG;AACH,MAAM,WAAW,sBAAuB,SAAQ,8BAA8B;IAC5E,IAAI,CAAC,EAAE,SAAS,CAAA;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,aAAa,GAAG,IAAI,CAAA;IAC3B,QAAQ,EAAE,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI,KAAK,IAAI,CAAA;IAE9C;;;OAGG;IACH,YAAY,EAAE,uBAAuB,CAAA;IAErC,oFAAoF;IACpF,YAAY,CAAC,EAAE,mBAAmB,EAAE,CAAA;IACpC,mBAAmB,CAAC,EAAE,OAAO,CAAA;IAE7B;;;OAGG;IACH,YAAY,CAAC,EAAE,aAAa,CAAC,sBAAsB,CAAC,CAAA;IAEpD,sFAAsF;IACtF,cAAc,CAAC,EAAE,OAAO,CAAA;CACzB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,WAAW,CAAC,EAC1B,KAAK,EACL,QAAQ,EACR,YAAY,EACZ,YAAY,EACZ,mBAAmB,EACnB,YAAY,EACZ,cAAc,GACf,EAAE,gBAAgB,2CA4BlB"}
1
+ {"version":3,"file":"payment-step.d.ts","sourceRoot":"","sources":["../../src/components/payment-step.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,sBAAsB,IAAI,8BAA8B,EACxD,aAAa,EACb,uBAAuB,EACvB,mBAAmB,EACpB,MAAM,0BAA0B,CAAA;AAOjC,OAAO,EAAE,KAAK,SAAS,EAAY,MAAM,OAAO,CAAA;AAIhD;;;GAGG;AACH,MAAM,WAAW,sBAAuB,SAAQ,8BAA8B;IAC5E,IAAI,CAAC,EAAE,SAAS,CAAA;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,aAAa,GAAG,IAAI,CAAA;IAC3B,QAAQ,EAAE,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI,KAAK,IAAI,CAAA;IAE9C;;;OAGG;IACH,YAAY,EAAE,uBAAuB,CAAA;IAErC,oFAAoF;IACpF,YAAY,CAAC,EAAE,mBAAmB,EAAE,CAAA;IACpC,mBAAmB,CAAC,EAAE,OAAO,CAAA;IAE7B;;;OAGG;IACH,YAAY,CAAC,EAAE,aAAa,CAAC,sBAAsB,CAAC,CAAA;IAEpD,sFAAsF;IACtF,cAAc,CAAC,EAAE,OAAO,CAAA;CACzB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,WAAW,CAAC,EAC1B,KAAK,EACL,QAAQ,EACR,YAAY,EACZ,YAAY,EACZ,mBAAmB,EACnB,YAAY,EACZ,cAAc,GACf,EAAE,gBAAgB,2CA2BlB"}
@@ -1,11 +1,13 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ import { formatMessage } from "@voyantjs/i18n";
3
4
  import { Input } from "@voyantjs/ui/components/input";
4
5
  import { Label } from "@voyantjs/ui/components/label";
5
6
  import { RadioGroup, RadioGroupItem } from "@voyantjs/ui/components/radio-group";
6
7
  import { cn } from "@voyantjs/ui/lib/utils";
7
8
  import { Banknote, CreditCard, Wallet } from "lucide-react";
8
9
  import { useState } from "react";
10
+ import { useCheckoutUiMessagesOrDefault } from "../i18n/provider.js";
9
11
  /**
10
12
  * Admin-side payment picker. Renders the sections the parent has wired:
11
13
  *
@@ -19,18 +21,24 @@ import { useState } from "react";
19
21
  * three real choices: charge now, vertical action, or hold + share link.
20
22
  */
21
23
  export function PaymentStep({ value, onChange, capabilities, savedMethods, loadingSavedMethods, extraOptions, hideHoldOption, }) {
22
- return (_jsxs("div", { className: "flex flex-col gap-5", children: [_jsxs("div", { children: [_jsx("h2", { className: "font-semibold text-base", children: "Payment" }), _jsx("p", { className: "text-muted-foreground text-sm", children: "Pick a saved method or use a different payment option." })] }), capabilities.chargeSavedCard && (_jsx(SavedMethodsSection, { loading: loadingSavedMethods, methods: savedMethods ?? [], selectedId: value?.type === "saved_method" ? value.method.id : null, onSelect: (method) => onChange({ type: "saved_method", method }) })), _jsx(AltMethodsSection, { value: value, onChange: onChange, showNewCard: !!capabilities.newCard, extraOptions: extraOptions ?? [], hideHoldOption: hideHoldOption })] }));
24
+ const messages = useCheckoutUiMessagesOrDefault().paymentStep;
25
+ return (_jsxs("div", { className: "flex flex-col gap-5", children: [_jsxs("div", { children: [_jsx("h2", { className: "font-semibold text-base", children: messages.title }), _jsx("p", { className: "text-muted-foreground text-sm", children: messages.description })] }), capabilities.chargeSavedCard && (_jsx(SavedMethodsSection, { loading: loadingSavedMethods, methods: savedMethods ?? [], selectedId: value?.type === "saved_method" ? value.method.id : null, onSelect: (method) => onChange({ type: "saved_method", method }) })), _jsx(AltMethodsSection, { value: value, onChange: onChange, showNewCard: !!capabilities.newCard, extraOptions: extraOptions ?? [], hideHoldOption: hideHoldOption })] }));
23
26
  }
24
27
  // ─────────────────────────────────────────────────────────────────────────────
25
28
  function SavedMethodsSection({ loading, methods, selectedId, onSelect, }) {
26
- return (_jsxs("section", { className: "rounded-xl border bg-card p-5 shadow-sm", children: [_jsxs("header", { className: "mb-3 flex items-center justify-between", children: [_jsx("h3", { className: "font-medium text-sm", children: "Saved payment methods" }), methods.length > 0 && (_jsxs("span", { className: "text-muted-foreground text-xs", children: [methods.length, " on file"] }))] }), loading ? (_jsx("div", { className: "h-16 animate-pulse rounded-md bg-muted/40" })) : methods.length === 0 ? (_jsx("div", { className: "rounded-md border border-dashed p-4 text-center text-muted-foreground text-xs", children: "No saved methods on file for this contact." })) : (_jsx("ul", { className: "flex flex-col gap-2", children: methods.map((m) => {
29
+ const messages = useCheckoutUiMessagesOrDefault().paymentStep.savedMethods;
30
+ return (_jsxs("section", { className: "rounded-xl border bg-card p-5 shadow-sm", children: [_jsxs("header", { className: "mb-3 flex items-center justify-between", children: [_jsx("h3", { className: "font-medium text-sm", children: messages.title }), methods.length > 0 && (_jsx("span", { className: "text-muted-foreground text-xs", children: formatMessage(messages.countOnFile, { count: methods.length }) }))] }), loading ? (_jsx("div", { className: "h-16 animate-pulse rounded-md bg-muted/40" })) : methods.length === 0 ? (_jsx("div", { className: "rounded-md border border-dashed p-4 text-center text-muted-foreground text-xs", children: messages.empty })) : (_jsx("ul", { className: "flex flex-col gap-2", children: methods.map((m) => {
27
31
  const selected = selectedId === m.id;
28
32
  return (_jsx("li", { children: _jsxs("button", { type: "button", onClick: () => onSelect(m), className: cn("flex w-full items-center gap-3 rounded-md border bg-background p-3 text-left transition-colors", selected
29
33
  ? "border-primary ring-2 ring-primary/20"
30
- : "hover:border-primary/40 hover:bg-accent/30"), children: [_jsx(BrandTile, { brand: m.brand }), _jsxs("div", { className: "flex min-w-0 flex-1 flex-col leading-tight", children: [_jsxs("span", { className: "font-medium text-sm", children: [m.label, m.last4 && (_jsxs(_Fragment, { children: [" ···· ", _jsx("span", { className: "font-mono", children: m.last4 })] })), m.isDefault && (_jsx("span", { className: "ml-2 rounded-full bg-primary/10 px-1.5 py-0.5 font-medium text-[9px] text-primary uppercase tracking-wider", children: "Default" }))] }), m.expiryMonth && m.expiryYear && (_jsxs("span", { className: "text-muted-foreground text-xs", children: ["Expires ", String(m.expiryMonth).padStart(2, "0"), "/", m.expiryYear] }))] }), selected && _jsx("span", { className: "font-medium text-primary text-xs", children: "Selected" })] }) }, m.id));
34
+ : "hover:border-primary/40 hover:bg-accent/30"), children: [_jsx(BrandTile, { brand: m.brand }), _jsxs("div", { className: "flex min-w-0 flex-1 flex-col leading-tight", children: [_jsxs("span", { className: "font-medium text-sm", children: [m.label, m.last4 && (_jsxs(_Fragment, { children: [" ···· ", _jsx("span", { className: "font-mono", children: m.last4 })] })), m.isDefault && (_jsx("span", { className: "ml-2 rounded-full bg-primary/10 px-1.5 py-0.5 font-medium text-[9px] text-primary uppercase tracking-wider", children: messages.defaultBadge }))] }), m.expiryMonth && m.expiryYear && (_jsx("span", { className: "text-muted-foreground text-xs", children: formatMessage(messages.expires, {
35
+ month: String(m.expiryMonth).padStart(2, "0"),
36
+ year: m.expiryYear,
37
+ }) }))] }), selected && (_jsx("span", { className: "font-medium text-primary text-xs", children: messages.selected }))] }) }, m.id));
31
38
  }) }))] }));
32
39
  }
33
40
  function AltMethodsSection({ value, onChange, showNewCard, extraOptions, hideHoldOption, }) {
41
+ const messages = useCheckoutUiMessagesOrDefault().paymentStep.otherOptions;
34
42
  const [newCardName, setNewCardName] = useState("");
35
43
  const [newCardNumber, setNewCardNumber] = useState("");
36
44
  const [newCardExp, setNewCardExp] = useState("");
@@ -63,28 +71,28 @@ function AltMethodsSection({ value, onChange, showNewCard, extraOptions, hideHol
63
71
  onChange({ type: "extra", optionId: id.slice("extra:".length) });
64
72
  }
65
73
  };
66
- return (_jsxs("section", { className: "rounded-xl border bg-card p-5 shadow-sm", children: [_jsx("header", { className: "mb-3 flex items-center justify-between", children: _jsx("h3", { className: "font-medium text-sm", children: "Other payment options" }) }), _jsxs(RadioGroup, { value: activeId ?? "__none", onValueChange: (v) => {
74
+ return (_jsxs("section", { className: "rounded-xl border bg-card p-5 shadow-sm", children: [_jsx("header", { className: "mb-3 flex items-center justify-between", children: _jsx("h3", { className: "font-medium text-sm", children: messages.title }) }), _jsxs(RadioGroup, { value: activeId ?? "__none", onValueChange: (v) => {
67
75
  if (!v)
68
76
  return;
69
77
  if (v === "new_card" || v === "hold" || v.startsWith("extra:")) {
70
78
  setAlt(v);
71
79
  }
72
- }, className: "flex flex-col gap-2", children: [showNewCard && (_jsx(AltRow, { id: "new_card", icon: _jsx(CreditCard, { className: "h-4 w-4 text-muted-foreground" }), title: "New credit / debit card", body: "Charge a one-off card now.", active: activeId === "new_card", children: activeId === "new_card" && (_jsxs("div", { className: "mt-3 grid grid-cols-1 gap-3 md:grid-cols-3", children: [_jsx(Field, { label: "Cardholder name", children: _jsx(Input, { value: newCardName, onChange: (e) => {
80
+ }, className: "flex flex-col gap-2", children: [showNewCard && (_jsx(AltRow, { id: "new_card", icon: _jsx(CreditCard, { className: "h-4 w-4 text-muted-foreground" }), title: messages.newCard.title, body: messages.newCard.body, active: activeId === "new_card", children: activeId === "new_card" && (_jsxs("div", { className: "mt-3 grid grid-cols-1 gap-3 md:grid-cols-3", children: [_jsx(Field, { label: messages.newCard.cardholderName, children: _jsx(Input, { value: newCardName, onChange: (e) => {
73
81
  setNewCardName(e.target.value);
74
82
  if (value?.type === "new_card") {
75
83
  onChange({ ...value, cardholderName: e.target.value });
76
84
  }
77
- } }) }), _jsx(Field, { label: "Card number", children: _jsx(Input, { inputMode: "numeric", placeholder: "\u2022\u2022\u2022\u2022 \u2022\u2022\u2022\u2022 \u2022\u2022\u2022\u2022 \u2022\u2022\u2022\u2022", value: newCardNumber, onChange: (e) => {
85
+ } }) }), _jsx(Field, { label: messages.newCard.cardNumber, children: _jsx(Input, { inputMode: "numeric", placeholder: messages.newCard.cardNumberPlaceholder, value: newCardNumber, onChange: (e) => {
78
86
  setNewCardNumber(e.target.value);
79
87
  if (value?.type === "new_card") {
80
88
  onChange({ ...value, cardToken: tokenizeNewCard(e.target.value) });
81
89
  }
82
- } }) }), _jsx(Field, { label: "MM/YY", children: _jsx(Input, { value: newCardExp, onChange: (e) => {
90
+ } }) }), _jsx(Field, { label: messages.newCard.expiry, children: _jsx(Input, { value: newCardExp, onChange: (e) => {
83
91
  setNewCardExp(e.target.value);
84
92
  if (value?.type === "new_card") {
85
93
  onChange({ ...value, expiry: e.target.value });
86
94
  }
87
- }, placeholder: "08/29" }) })] })) })), extraOptions.map((opt) => (_jsx(AltRow, { id: `extra:${opt.id}`, icon: opt.icon, title: opt.label, body: opt.description, active: activeId === `extra:${opt.id}` }, opt.id))), !hideHoldOption && (_jsx(AltRow, { id: "hold", icon: _jsx(Wallet, { className: "h-4 w-4 text-muted-foreground" }), title: "Hold \u2014 generate payment link", body: "Lock the order and generate a payment link the customer can open to pay by card or bank transfer. Share it however you prefer.", active: activeId === "hold" }))] }), showNewCard && (_jsxs("p", { className: "mt-4 flex items-start gap-1.5 text-[11px] text-muted-foreground", children: [_jsx(Banknote, { className: "mt-0.5 h-3 w-3" }), "Card numbers entered here are tokenized in production via the processor's hosted form \u2014 never sent through this UI."] }))] }));
95
+ }, placeholder: messages.newCard.expiryPlaceholder }) })] })) })), extraOptions.map((opt) => (_jsx(AltRow, { id: `extra:${opt.id}`, icon: opt.icon, title: opt.label, body: opt.description, active: activeId === `extra:${opt.id}` }, opt.id))), !hideHoldOption && (_jsx(AltRow, { id: "hold", icon: _jsx(Wallet, { className: "h-4 w-4 text-muted-foreground" }), title: messages.hold.title, body: messages.hold.body, active: activeId === "hold" }))] }), showNewCard && (_jsxs("p", { className: "mt-4 flex items-start gap-1.5 text-[11px] text-muted-foreground", children: [_jsx(Banknote, { className: "mt-0.5 h-3 w-3" }), messages.cardSecurityNote] }))] }));
88
96
  }
89
97
  function AltRow({ id, icon, title, body, active, children, }) {
90
98
  const inputId = `payment-step-${id}`;
@@ -94,7 +102,8 @@ function Field({ label, children }) {
94
102
  return (_jsxs("div", { className: "flex flex-col gap-1.5", children: [_jsx(Label, { className: "text-[11px] uppercase tracking-wider text-muted-foreground", children: label }), children] }));
95
103
  }
96
104
  function BrandTile({ brand }) {
97
- return (_jsx("span", { className: "flex h-9 w-12 shrink-0 items-center justify-center rounded-md border bg-muted/30 font-mono text-[10px] uppercase tracking-wider", children: (brand ?? "card").slice(0, 4) }));
105
+ const messages = useCheckoutUiMessagesOrDefault().paymentStep.otherOptions;
106
+ return (_jsx("span", { className: "flex h-9 w-12 shrink-0 items-center justify-center rounded-md border bg-muted/30 font-mono text-[10px] uppercase tracking-wider", children: (brand ?? messages.brandFallback).slice(0, 4) }));
98
107
  }
99
108
  function tokenizeNewCard(number) {
100
109
  // Demo "tokenization" — in production the processor's hosted form
@@ -0,0 +1,3 @@
1
+ import type { CheckoutUiMessages } from "./messages.js";
2
+ export declare const checkoutUiEn: CheckoutUiMessages;
3
+ //# sourceMappingURL=en.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"en.d.ts","sourceRoot":"","sources":["../../src/i18n/en.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAA;AAEvD,eAAO,MAAM,YAAY,EAAE,kBAsH1B,CAAA"}
@@ -0,0 +1,114 @@
1
+ export const checkoutUiEn = {
2
+ paymentLinkLandingPage: {
3
+ cardTab: "Pay by card",
4
+ bankTab: "Bank transfer",
5
+ expires: "Expires {date}",
6
+ noMethods: {
7
+ title: "No payment method available",
8
+ body: "This payment link doesn't have any payment methods configured. Please contact your travel agent.",
9
+ },
10
+ card: {
11
+ description: "You'll be redirected to the secure payment page hosted by the card processor.",
12
+ payAmount: "Pay {amount}",
13
+ startFailed: "Card payment couldn't be prepared.",
14
+ errorAdvice: "{message} If the issue persists, please pay by bank transfer or contact your travel agent.",
15
+ },
16
+ bank: {
17
+ instructions: "Wire {amount} to the account below. Your booking is confirmed once payment is received (typically 1-3 business days).",
18
+ beneficiary: "Beneficiary",
19
+ iban: "IBAN",
20
+ bicSwift: "BIC / SWIFT",
21
+ bank: "Bank",
22
+ reference: "Reference",
23
+ },
24
+ copy: {
25
+ copied: "Copied",
26
+ copyValue: "Copy {value}",
27
+ },
28
+ terminal: {
29
+ paid: {
30
+ title: "Payment received",
31
+ body: "Thanks - your booking is confirmed. You'll receive a confirmation email shortly.",
32
+ },
33
+ failed: {
34
+ title: "Payment failed",
35
+ body: "The payment couldn't be processed. Please try again or contact support.",
36
+ },
37
+ expired: {
38
+ title: "Payment link expired",
39
+ body: "This payment link has expired. Please request a new one from your travel agent.",
40
+ },
41
+ cancelled: {
42
+ title: "Payment cancelled",
43
+ body: "This payment was cancelled. Please contact your travel agent if this is unexpected.",
44
+ },
45
+ tryAgain: "Try again",
46
+ },
47
+ processing: {
48
+ title: "Processing payment...",
49
+ body: "We're confirming the payment with the processor. This usually takes a few seconds.",
50
+ },
51
+ descriptions: {
52
+ booking: "Booking payment",
53
+ booking_payment_schedule: "Booking deposit",
54
+ booking_guarantee: "Booking guarantee",
55
+ invoice: "Invoice payment",
56
+ order: "Order payment",
57
+ flight_order: "Flight payment",
58
+ other: "Payment",
59
+ default: "Payment",
60
+ },
61
+ },
62
+ paymentStep: {
63
+ title: "Payment",
64
+ description: "Pick a saved method or use a different payment option.",
65
+ savedMethods: {
66
+ title: "Saved payment methods",
67
+ countOnFile: "{count} on file",
68
+ empty: "No saved methods on file for this contact.",
69
+ defaultBadge: "Default",
70
+ expires: "Expires {month}/{year}",
71
+ selected: "Selected",
72
+ },
73
+ otherOptions: {
74
+ title: "Other payment options",
75
+ newCard: {
76
+ title: "New credit / debit card",
77
+ body: "Charge a one-off card now.",
78
+ cardholderName: "Cardholder name",
79
+ cardNumber: "Card number",
80
+ expiry: "MM/YY",
81
+ cardNumberPlaceholder: ".... .... .... ....",
82
+ expiryPlaceholder: "08/29",
83
+ },
84
+ hold: {
85
+ title: "Hold - generate payment link",
86
+ body: "Lock the order and generate a payment link the customer can open to pay by card or bank transfer. Share it however you prefer.",
87
+ },
88
+ cardSecurityNote: "Card numbers entered here are tokenized in production via the processor's hosted form - never sent through this UI.",
89
+ brandFallback: "card",
90
+ },
91
+ },
92
+ collectPaymentDialog: {
93
+ title: "Generate payment link",
94
+ description: "Hold the booking and produce a payment link the customer can open to pay by card or bank transfer. Share it however you prefer (email, chat, etc.).",
95
+ amountLabel: "Amount ({currency})",
96
+ amountHelp: "Defaults to the booking's sell amount. Override for a deposit or partial collection.",
97
+ cancel: "Cancel",
98
+ done: "Done",
99
+ generateLink: "Generate link",
100
+ validation: {
101
+ pickHold: "Pick 'Hold - generate payment link' to produce a shareable link.",
102
+ amountAboveZero: "Enter an amount above zero.",
103
+ linkReady: "Payment link ready - copy or share it with the customer.",
104
+ },
105
+ result: {
106
+ noLink: "The session was created but no link could be built. Session id: {sessionId}.",
107
+ noSession: "-",
108
+ ready: "Payment link ready",
109
+ body: "Share this link with the customer. They'll choose card or bank transfer on the page.",
110
+ copyLink: "Copy link",
111
+ openLink: "Open link",
112
+ },
113
+ },
114
+ };
@@ -0,0 +1,5 @@
1
+ export { checkoutUiEn } from "./en.js";
2
+ export type { CheckoutPaymentTargetType, CheckoutUiMessages } from "./messages.js";
3
+ export { type CheckoutUiMessageOverrides, CheckoutUiMessagesProvider, checkoutUiMessageDefinitions, getCheckoutUiI18n, resolveCheckoutUiMessages, useCheckoutUiI18n, useCheckoutUiI18nOrDefault, useCheckoutUiMessages, useCheckoutUiMessagesOrDefault, } from "./provider.js";
4
+ export { checkoutUiRo } from "./ro.js";
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/i18n/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AACtC,YAAY,EAAE,yBAAyB,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAA;AAClF,OAAO,EACL,KAAK,0BAA0B,EAC/B,0BAA0B,EAC1B,4BAA4B,EAC5B,iBAAiB,EACjB,yBAAyB,EACzB,iBAAiB,EACjB,0BAA0B,EAC1B,qBAAqB,EACrB,8BAA8B,GAC/B,MAAM,eAAe,CAAA;AACtB,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA"}
@@ -0,0 +1,3 @@
1
+ export { checkoutUiEn } from "./en.js";
2
+ export { CheckoutUiMessagesProvider, checkoutUiMessageDefinitions, getCheckoutUiI18n, resolveCheckoutUiMessages, useCheckoutUiI18n, useCheckoutUiI18nOrDefault, useCheckoutUiMessages, useCheckoutUiMessagesOrDefault, } from "./provider.js";
3
+ export { checkoutUiRo } from "./ro.js";
@@ -0,0 +1,108 @@
1
+ import type { PublicPaymentSession } from "@voyantjs/finance/public-validation";
2
+ export type CheckoutPaymentTargetType = PublicPaymentSession["targetType"];
3
+ export type CheckoutUiMessages = {
4
+ paymentLinkLandingPage: {
5
+ cardTab: string;
6
+ bankTab: string;
7
+ expires: string;
8
+ noMethods: {
9
+ title: string;
10
+ body: string;
11
+ };
12
+ card: {
13
+ description: string;
14
+ payAmount: string;
15
+ startFailed: string;
16
+ errorAdvice: string;
17
+ };
18
+ bank: {
19
+ instructions: string;
20
+ beneficiary: string;
21
+ iban: string;
22
+ bicSwift: string;
23
+ bank: string;
24
+ reference: string;
25
+ };
26
+ copy: {
27
+ copied: string;
28
+ copyValue: string;
29
+ };
30
+ terminal: {
31
+ paid: {
32
+ title: string;
33
+ body: string;
34
+ };
35
+ failed: {
36
+ title: string;
37
+ body: string;
38
+ };
39
+ expired: {
40
+ title: string;
41
+ body: string;
42
+ };
43
+ cancelled: {
44
+ title: string;
45
+ body: string;
46
+ };
47
+ tryAgain: string;
48
+ };
49
+ processing: {
50
+ title: string;
51
+ body: string;
52
+ };
53
+ descriptions: Record<CheckoutPaymentTargetType | "default", string>;
54
+ };
55
+ paymentStep: {
56
+ title: string;
57
+ description: string;
58
+ savedMethods: {
59
+ title: string;
60
+ countOnFile: string;
61
+ empty: string;
62
+ defaultBadge: string;
63
+ expires: string;
64
+ selected: string;
65
+ };
66
+ otherOptions: {
67
+ title: string;
68
+ newCard: {
69
+ title: string;
70
+ body: string;
71
+ cardholderName: string;
72
+ cardNumber: string;
73
+ expiry: string;
74
+ cardNumberPlaceholder: string;
75
+ expiryPlaceholder: string;
76
+ };
77
+ hold: {
78
+ title: string;
79
+ body: string;
80
+ };
81
+ cardSecurityNote: string;
82
+ brandFallback: string;
83
+ };
84
+ };
85
+ collectPaymentDialog: {
86
+ title: string;
87
+ description: string;
88
+ amountLabel: string;
89
+ amountHelp: string;
90
+ cancel: string;
91
+ done: string;
92
+ generateLink: string;
93
+ validation: {
94
+ pickHold: string;
95
+ amountAboveZero: string;
96
+ linkReady: string;
97
+ };
98
+ result: {
99
+ noLink: string;
100
+ noSession: string;
101
+ ready: string;
102
+ body: string;
103
+ copyLink: string;
104
+ openLink: string;
105
+ };
106
+ };
107
+ };
108
+ //# sourceMappingURL=messages.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../src/i18n/messages.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,qCAAqC,CAAA;AAE/E,MAAM,MAAM,yBAAyB,GAAG,oBAAoB,CAAC,YAAY,CAAC,CAAA;AAE1E,MAAM,MAAM,kBAAkB,GAAG;IAC/B,sBAAsB,EAAE;QACtB,OAAO,EAAE,MAAM,CAAA;QACf,OAAO,EAAE,MAAM,CAAA;QACf,OAAO,EAAE,MAAM,CAAA;QACf,SAAS,EAAE;YACT,KAAK,EAAE,MAAM,CAAA;YACb,IAAI,EAAE,MAAM,CAAA;SACb,CAAA;QACD,IAAI,EAAE;YACJ,WAAW,EAAE,MAAM,CAAA;YACnB,SAAS,EAAE,MAAM,CAAA;YACjB,WAAW,EAAE,MAAM,CAAA;YACnB,WAAW,EAAE,MAAM,CAAA;SACpB,CAAA;QACD,IAAI,EAAE;YACJ,YAAY,EAAE,MAAM,CAAA;YACpB,WAAW,EAAE,MAAM,CAAA;YACnB,IAAI,EAAE,MAAM,CAAA;YACZ,QAAQ,EAAE,MAAM,CAAA;YAChB,IAAI,EAAE,MAAM,CAAA;YACZ,SAAS,EAAE,MAAM,CAAA;SAClB,CAAA;QACD,IAAI,EAAE;YACJ,MAAM,EAAE,MAAM,CAAA;YACd,SAAS,EAAE,MAAM,CAAA;SAClB,CAAA;QACD,QAAQ,EAAE;YACR,IAAI,EAAE;gBACJ,KAAK,EAAE,MAAM,CAAA;gBACb,IAAI,EAAE,MAAM,CAAA;aACb,CAAA;YACD,MAAM,EAAE;gBACN,KAAK,EAAE,MAAM,CAAA;gBACb,IAAI,EAAE,MAAM,CAAA;aACb,CAAA;YACD,OAAO,EAAE;gBACP,KAAK,EAAE,MAAM,CAAA;gBACb,IAAI,EAAE,MAAM,CAAA;aACb,CAAA;YACD,SAAS,EAAE;gBACT,KAAK,EAAE,MAAM,CAAA;gBACb,IAAI,EAAE,MAAM,CAAA;aACb,CAAA;YACD,QAAQ,EAAE,MAAM,CAAA;SACjB,CAAA;QACD,UAAU,EAAE;YACV,KAAK,EAAE,MAAM,CAAA;YACb,IAAI,EAAE,MAAM,CAAA;SACb,CAAA;QACD,YAAY,EAAE,MAAM,CAAC,yBAAyB,GAAG,SAAS,EAAE,MAAM,CAAC,CAAA;KACpE,CAAA;IACD,WAAW,EAAE;QACX,KAAK,EAAE,MAAM,CAAA;QACb,WAAW,EAAE,MAAM,CAAA;QACnB,YAAY,EAAE;YACZ,KAAK,EAAE,MAAM,CAAA;YACb,WAAW,EAAE,MAAM,CAAA;YACnB,KAAK,EAAE,MAAM,CAAA;YACb,YAAY,EAAE,MAAM,CAAA;YACpB,OAAO,EAAE,MAAM,CAAA;YACf,QAAQ,EAAE,MAAM,CAAA;SACjB,CAAA;QACD,YAAY,EAAE;YACZ,KAAK,EAAE,MAAM,CAAA;YACb,OAAO,EAAE;gBACP,KAAK,EAAE,MAAM,CAAA;gBACb,IAAI,EAAE,MAAM,CAAA;gBACZ,cAAc,EAAE,MAAM,CAAA;gBACtB,UAAU,EAAE,MAAM,CAAA;gBAClB,MAAM,EAAE,MAAM,CAAA;gBACd,qBAAqB,EAAE,MAAM,CAAA;gBAC7B,iBAAiB,EAAE,MAAM,CAAA;aAC1B,CAAA;YACD,IAAI,EAAE;gBACJ,KAAK,EAAE,MAAM,CAAA;gBACb,IAAI,EAAE,MAAM,CAAA;aACb,CAAA;YACD,gBAAgB,EAAE,MAAM,CAAA;YACxB,aAAa,EAAE,MAAM,CAAA;SACtB,CAAA;KACF,CAAA;IACD,oBAAoB,EAAE;QACpB,KAAK,EAAE,MAAM,CAAA;QACb,WAAW,EAAE,MAAM,CAAA;QACnB,WAAW,EAAE,MAAM,CAAA;QACnB,UAAU,EAAE,MAAM,CAAA;QAClB,MAAM,EAAE,MAAM,CAAA;QACd,IAAI,EAAE,MAAM,CAAA;QACZ,YAAY,EAAE,MAAM,CAAA;QACpB,UAAU,EAAE;YACV,QAAQ,EAAE,MAAM,CAAA;YAChB,eAAe,EAAE,MAAM,CAAA;YACvB,SAAS,EAAE,MAAM,CAAA;SAClB,CAAA;QACD,MAAM,EAAE;YACN,MAAM,EAAE,MAAM,CAAA;YACd,SAAS,EAAE,MAAM,CAAA;YACjB,KAAK,EAAE,MAAM,CAAA;YACb,IAAI,EAAE,MAAM,CAAA;YACZ,QAAQ,EAAE,MAAM,CAAA;YAChB,QAAQ,EAAE,MAAM,CAAA;SACjB,CAAA;KACF,CAAA;CACF,CAAA"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,26 @@
1
+ import { type LocaleMessageOverrides, type PackageI18nValue } from "@voyantjs/i18n";
2
+ import type { ReactNode } from "react";
3
+ import type { CheckoutUiMessages } from "./messages.js";
4
+ export declare const checkoutUiMessageDefinitions: {
5
+ en: CheckoutUiMessages;
6
+ ro: CheckoutUiMessages;
7
+ };
8
+ export type CheckoutUiMessageOverrides = LocaleMessageOverrides<CheckoutUiMessages>;
9
+ export declare function resolveCheckoutUiMessages({ locale, overrides, }: {
10
+ locale: string | null | undefined;
11
+ overrides?: CheckoutUiMessageOverrides | null;
12
+ }): CheckoutUiMessages;
13
+ export declare function getCheckoutUiI18n({ locale, overrides, }: {
14
+ locale?: string | null | undefined;
15
+ overrides?: CheckoutUiMessageOverrides | null;
16
+ }): PackageI18nValue<CheckoutUiMessages>;
17
+ export declare function CheckoutUiMessagesProvider({ children, locale, overrides, }: {
18
+ children: ReactNode;
19
+ locale: string | null | undefined;
20
+ overrides?: CheckoutUiMessageOverrides | null;
21
+ }): import("react/jsx-runtime").JSX.Element;
22
+ export declare const useCheckoutUiI18n: () => PackageI18nValue<CheckoutUiMessages>;
23
+ export declare const useCheckoutUiMessages: () => CheckoutUiMessages;
24
+ export declare function useCheckoutUiI18nOrDefault(): PackageI18nValue<CheckoutUiMessages>;
25
+ export declare function useCheckoutUiMessagesOrDefault(): CheckoutUiMessages;
26
+ //# sourceMappingURL=provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../src/i18n/provider.tsx"],"names":[],"mappings":"AAEA,OAAO,EAIL,KAAK,sBAAsB,EAC3B,KAAK,gBAAgB,EAEtB,MAAM,gBAAgB,CAAA;AACvB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAGtC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAA;AAKvD,eAAO,MAAM,4BAA4B;;;CAGe,CAAA;AAExD,MAAM,MAAM,0BAA0B,GAAG,sBAAsB,CAAC,kBAAkB,CAAC,CAAA;AASnF,wBAAgB,yBAAyB,CAAC,EACxC,MAAM,EACN,SAAS,GACV,EAAE;IACD,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAA;IACjC,SAAS,CAAC,EAAE,0BAA0B,GAAG,IAAI,CAAA;CAC9C,sBAOA;AAED,wBAAgB,iBAAiB,CAAC,EAChC,MAAM,EACN,SAAS,GACV,EAAE;IACD,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAA;IAClC,SAAS,CAAC,EAAE,0BAA0B,GAAG,IAAI,CAAA;CAC9C,GAAG,gBAAgB,CAAC,kBAAkB,CAAC,CAMvC;AAED,wBAAgB,0BAA0B,CAAC,EACzC,QAAQ,EACR,MAAM,EACN,SAAS,GACV,EAAE;IACD,QAAQ,EAAE,SAAS,CAAA;IACnB,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAA;IACjC,SAAS,CAAC,EAAE,0BAA0B,GAAG,IAAI,CAAA;CAC9C,2CAWA;AAED,eAAO,MAAM,iBAAiB,4CAA4B,CAAA;AAC1D,eAAO,MAAM,qBAAqB,0BAAgC,CAAA;AAElE,wBAAgB,0BAA0B,yCAEzC;AAED,wBAAgB,8BAA8B,uBAE7C"}
@@ -0,0 +1,41 @@
1
+ "use client";
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { createLocaleFormatters, createPackageMessagesContext, resolvePackageMessages, } from "@voyantjs/i18n";
4
+ import { checkoutUiEn } from "./en.js";
5
+ import { checkoutUiRo } from "./ro.js";
6
+ const fallbackLocale = "en";
7
+ export const checkoutUiMessageDefinitions = {
8
+ en: checkoutUiEn,
9
+ ro: checkoutUiRo,
10
+ };
11
+ const checkoutUiContext = createPackageMessagesContext("CheckoutUiMessages");
12
+ const defaultCheckoutUiI18n = {
13
+ messages: checkoutUiEn,
14
+ ...createLocaleFormatters(fallbackLocale),
15
+ };
16
+ export function resolveCheckoutUiMessages({ locale, overrides, }) {
17
+ return resolvePackageMessages({
18
+ definitions: checkoutUiMessageDefinitions,
19
+ fallbackLocale,
20
+ locale,
21
+ overrides,
22
+ });
23
+ }
24
+ export function getCheckoutUiI18n({ locale, overrides, }) {
25
+ const resolvedLocale = locale ?? fallbackLocale;
26
+ return {
27
+ messages: resolveCheckoutUiMessages({ locale: resolvedLocale, overrides }),
28
+ ...createLocaleFormatters(resolvedLocale),
29
+ };
30
+ }
31
+ export function CheckoutUiMessagesProvider({ children, locale, overrides, }) {
32
+ return (_jsx(checkoutUiContext.ResolvedMessagesProvider, { definitions: checkoutUiMessageDefinitions, fallbackLocale: fallbackLocale, locale: locale, overrides: overrides, children: children }));
33
+ }
34
+ export const useCheckoutUiI18n = checkoutUiContext.useI18n;
35
+ export const useCheckoutUiMessages = checkoutUiContext.useMessages;
36
+ export function useCheckoutUiI18nOrDefault() {
37
+ return checkoutUiContext.useOptionalI18n() ?? defaultCheckoutUiI18n;
38
+ }
39
+ export function useCheckoutUiMessagesOrDefault() {
40
+ return useCheckoutUiI18nOrDefault().messages;
41
+ }
@@ -0,0 +1,3 @@
1
+ import type { CheckoutUiMessages } from "./messages.js";
2
+ export declare const checkoutUiRo: CheckoutUiMessages;
3
+ //# sourceMappingURL=ro.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ro.d.ts","sourceRoot":"","sources":["../../src/i18n/ro.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAA;AAEvD,eAAO,MAAM,YAAY,EAAE,kBAuH1B,CAAA"}
@@ -0,0 +1,114 @@
1
+ export const checkoutUiRo = {
2
+ paymentLinkLandingPage: {
3
+ cardTab: "Plateste cu cardul",
4
+ bankTab: "Transfer bancar",
5
+ expires: "Expira {date}",
6
+ noMethods: {
7
+ title: "Nicio metoda de plata disponibila",
8
+ body: "Acest link de plata nu are metode de plata configurate. Contacteaza agentul de turism.",
9
+ },
10
+ card: {
11
+ description: "Vei fi redirectionat catre pagina securizata a procesatorului de carduri.",
12
+ payAmount: "Plateste {amount}",
13
+ startFailed: "Plata cu cardul nu a putut fi pregatita.",
14
+ errorAdvice: "{message} Daca problema persista, plateste prin transfer bancar sau contacteaza agentul de turism.",
15
+ },
16
+ bank: {
17
+ instructions: "Transfera {amount} in contul de mai jos. Rezervarea este confirmata dupa incasarea platii (de obicei 1-3 zile lucratoare).",
18
+ beneficiary: "Beneficiar",
19
+ iban: "IBAN",
20
+ bicSwift: "BIC / SWIFT",
21
+ bank: "Banca",
22
+ reference: "Referinta",
23
+ },
24
+ copy: {
25
+ copied: "Copiat",
26
+ copyValue: "Copiaza {value}",
27
+ },
28
+ terminal: {
29
+ paid: {
30
+ title: "Plata incasata",
31
+ body: "Multumim - rezervarea este confirmata. Vei primi in curand un email de confirmare.",
32
+ },
33
+ failed: {
34
+ title: "Plata esuata",
35
+ body: "Plata nu a putut fi procesata. Incearca din nou sau contacteaza suportul.",
36
+ },
37
+ expired: {
38
+ title: "Link de plata expirat",
39
+ body: "Acest link de plata a expirat. Cere un link nou de la agentul de turism.",
40
+ },
41
+ cancelled: {
42
+ title: "Plata anulata",
43
+ body: "Aceasta plata a fost anulata. Contacteaza agentul de turism daca nu te asteptai la asta.",
44
+ },
45
+ tryAgain: "Incearca din nou",
46
+ },
47
+ processing: {
48
+ title: "Se proceseaza plata...",
49
+ body: "Confirmam plata cu procesatorul. De obicei dureaza cateva secunde.",
50
+ },
51
+ descriptions: {
52
+ booking: "Plata rezervare",
53
+ booking_payment_schedule: "Avans rezervare",
54
+ booking_guarantee: "Garantie rezervare",
55
+ invoice: "Plata factura",
56
+ order: "Plata comanda",
57
+ flight_order: "Plata zbor",
58
+ other: "Plata",
59
+ default: "Plata",
60
+ },
61
+ },
62
+ paymentStep: {
63
+ title: "Plata",
64
+ description: "Alege o metoda salvata sau foloseste alta optiune de plata.",
65
+ savedMethods: {
66
+ title: "Metode de plata salvate",
67
+ countOnFile: "{count} salvate",
68
+ empty: "Nu exista metode salvate pentru acest contact.",
69
+ defaultBadge: "Implicit",
70
+ expires: "Expira {month}/{year}",
71
+ selected: "Selectata",
72
+ },
73
+ otherOptions: {
74
+ title: "Alte optiuni de plata",
75
+ newCard: {
76
+ title: "Card nou de credit / debit",
77
+ body: "Debiteaza acum un card punctual.",
78
+ cardholderName: "Nume detinator card",
79
+ cardNumber: "Numar card",
80
+ expiry: "LL/AA",
81
+ cardNumberPlaceholder: ".... .... .... ....",
82
+ expiryPlaceholder: "08/29",
83
+ },
84
+ hold: {
85
+ title: "Retine - genereaza link de plata",
86
+ body: "Blocheaza comanda si genereaza un link de plata pe care clientul il poate deschide pentru plata cu cardul sau transfer bancar. Distribuie-l cum preferi.",
87
+ },
88
+ cardSecurityNote: "Numerele de card introduse aici sunt tokenizate in productie prin formularul gazduit de procesator - nu sunt trimise niciodata prin acest UI.",
89
+ brandFallback: "card",
90
+ },
91
+ },
92
+ collectPaymentDialog: {
93
+ title: "Genereaza link de plata",
94
+ description: "Retine rezervarea si genereaza un link de plata pe care clientul il poate deschide pentru plata cu cardul sau transfer bancar. Distribuie-l cum preferi (email, chat etc.).",
95
+ amountLabel: "Suma ({currency})",
96
+ amountHelp: "Implicit este suma de vanzare a rezervarii. Modifica pentru avans sau plata partiala.",
97
+ cancel: "Anuleaza",
98
+ done: "Gata",
99
+ generateLink: "Genereaza link",
100
+ validation: {
101
+ pickHold: "Alege 'Retine - genereaza link de plata' pentru a crea un link distribuibil.",
102
+ amountAboveZero: "Introdu o suma mai mare decat zero.",
103
+ linkReady: "Linkul de plata este gata - copiaza-l sau trimite-l clientului.",
104
+ },
105
+ result: {
106
+ noLink: "Sesiunea a fost creata, dar linkul nu a putut fi construit. ID sesiune: {sessionId}.",
107
+ noSession: "-",
108
+ ready: "Link de plata gata",
109
+ body: "Trimite acest link clientului. Va alege cardul sau transferul bancar pe pagina.",
110
+ copyLink: "Copiaza linkul",
111
+ openLink: "Deschide linkul",
112
+ },
113
+ },
114
+ };
package/dist/index.d.ts CHANGED
@@ -18,4 +18,6 @@ export type { PaymentChoice, PaymentStepCapabilities, SavedPaymentAccount, } fro
18
18
  export { CollectPaymentDialog, type CollectPaymentDialogProps, } from "./components/collect-payment-dialog.js";
19
19
  export { type BankTransferInstructions, PaymentLinkLandingPage, type PaymentLinkLandingPageProps, } from "./components/payment-link-landing-page.js";
20
20
  export { PaymentStep, type PaymentStepExtraOption, type PaymentStepProps, } from "./components/payment-step.js";
21
+ export type { CheckoutPaymentTargetType, CheckoutUiMessages } from "./i18n/index.js";
22
+ export { type CheckoutUiMessageOverrides, CheckoutUiMessagesProvider, checkoutUiMessageDefinitions, getCheckoutUiI18n, resolveCheckoutUiMessages, useCheckoutUiI18n, useCheckoutUiI18nOrDefault, useCheckoutUiMessages, useCheckoutUiMessagesOrDefault, } from "./i18n/index.js";
21
23
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,YAAY,EACV,aAAa,EACb,uBAAuB,EACvB,mBAAmB,GACpB,MAAM,0BAA0B,CAAA;AACjC,OAAO,EACL,oBAAoB,EACpB,KAAK,yBAAyB,GAC/B,MAAM,wCAAwC,CAAA;AAC/C,OAAO,EACL,KAAK,wBAAwB,EAC7B,sBAAsB,EACtB,KAAK,2BAA2B,GACjC,MAAM,2CAA2C,CAAA;AAClD,OAAO,EACL,WAAW,EACX,KAAK,sBAAsB,EAC3B,KAAK,gBAAgB,GACtB,MAAM,8BAA8B,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,YAAY,EACV,aAAa,EACb,uBAAuB,EACvB,mBAAmB,GACpB,MAAM,0BAA0B,CAAA;AACjC,OAAO,EACL,oBAAoB,EACpB,KAAK,yBAAyB,GAC/B,MAAM,wCAAwC,CAAA;AAC/C,OAAO,EACL,KAAK,wBAAwB,EAC7B,sBAAsB,EACtB,KAAK,2BAA2B,GACjC,MAAM,2CAA2C,CAAA;AAClD,OAAO,EACL,WAAW,EACX,KAAK,sBAAsB,EAC3B,KAAK,gBAAgB,GACtB,MAAM,8BAA8B,CAAA;AACrC,YAAY,EAAE,yBAAyB,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AACpF,OAAO,EACL,KAAK,0BAA0B,EAC/B,0BAA0B,EAC1B,4BAA4B,EAC5B,iBAAiB,EACjB,yBAAyB,EACzB,iBAAiB,EACjB,0BAA0B,EAC1B,qBAAqB,EACrB,8BAA8B,GAC/B,MAAM,iBAAiB,CAAA"}
package/dist/index.js CHANGED
@@ -17,3 +17,4 @@
17
17
  export { CollectPaymentDialog, } from "./components/collect-payment-dialog.js";
18
18
  export { PaymentLinkLandingPage, } from "./components/payment-link-landing-page.js";
19
19
  export { PaymentStep, } from "./components/payment-step.js";
20
+ export { CheckoutUiMessagesProvider, checkoutUiMessageDefinitions, getCheckoutUiI18n, resolveCheckoutUiMessages, useCheckoutUiI18n, useCheckoutUiI18nOrDefault, useCheckoutUiMessages, useCheckoutUiMessagesOrDefault, } from "./i18n/index.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@voyantjs/checkout-ui",
3
- "version": "0.34.0",
3
+ "version": "0.37.0",
4
4
  "license": "Apache-2.0",
5
5
  "repository": {
6
6
  "type": "git",
@@ -18,6 +18,21 @@
18
18
  "./styles.css": {
19
19
  "default": "./src/styles.css"
20
20
  },
21
+ "./i18n": {
22
+ "types": "./dist/i18n/index.d.ts",
23
+ "import": "./dist/i18n/index.js",
24
+ "default": "./dist/i18n/index.js"
25
+ },
26
+ "./i18n/en": {
27
+ "types": "./dist/i18n/en.d.ts",
28
+ "import": "./dist/i18n/en.js",
29
+ "default": "./dist/i18n/en.js"
30
+ },
31
+ "./i18n/ro": {
32
+ "types": "./dist/i18n/ro.d.ts",
33
+ "import": "./dist/i18n/ro.js",
34
+ "default": "./dist/i18n/ro.js"
35
+ },
21
36
  "./components/*": {
22
37
  "types": "./dist/components/*.d.ts",
23
38
  "import": "./dist/components/*.js",
@@ -29,11 +44,12 @@
29
44
  "react": "^19.0.0",
30
45
  "react-dom": "^19.0.0",
31
46
  "sonner": "^2.0.0",
32
- "@voyantjs/checkout": "0.34.0",
33
- "@voyantjs/checkout-react": "0.34.0",
34
- "@voyantjs/finance": "0.34.0",
35
- "@voyantjs/finance-react": "0.34.0",
36
- "@voyantjs/ui": "0.34.0"
47
+ "@voyantjs/checkout": "0.37.0",
48
+ "@voyantjs/checkout-react": "0.37.0",
49
+ "@voyantjs/finance": "0.37.0",
50
+ "@voyantjs/finance-react": "0.37.0",
51
+ "@voyantjs/i18n": "0.37.0",
52
+ "@voyantjs/ui": "0.37.0"
37
53
  },
38
54
  "devDependencies": {
39
55
  "@tanstack/react-query": "^5.96.2",
@@ -45,11 +61,12 @@
45
61
  "sonner": "^2.0.7",
46
62
  "typescript": "^6.0.2",
47
63
  "vitest": "^4.1.2",
48
- "@voyantjs/checkout": "0.34.0",
49
- "@voyantjs/checkout-react": "0.34.0",
50
- "@voyantjs/finance": "0.34.0",
51
- "@voyantjs/finance-react": "0.34.0",
52
- "@voyantjs/ui": "0.34.0",
64
+ "@voyantjs/checkout": "0.37.0",
65
+ "@voyantjs/checkout-react": "0.37.0",
66
+ "@voyantjs/finance": "0.37.0",
67
+ "@voyantjs/finance-react": "0.37.0",
68
+ "@voyantjs/i18n": "0.37.0",
69
+ "@voyantjs/ui": "0.37.0",
53
70
  "@voyantjs/voyant-typescript-config": "0.1.0"
54
71
  },
55
72
  "files": [