@open-mercato/checkout 0.6.6-develop.6184.1.b7e55f8d61 → 0.6.6-develop.6201.1.8ceb502c4b
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/modules/checkout/__integration__/TC-CHKT-035.spec.js +2 -2
- package/dist/modules/checkout/__integration__/TC-CHKT-035.spec.js.map +2 -2
- package/dist/modules/checkout/components/PayPage.js +163 -103
- package/dist/modules/checkout/components/PayPage.js.map +2 -2
- package/package.json +5 -5
- package/src/modules/checkout/__integration__/TC-CHKT-035.spec.ts +2 -2
- package/src/modules/checkout/components/PayPage.tsx +160 -99
- package/src/modules/checkout/components/__tests__/PayPage.ds-contract.test.ts +26 -0
|
@@ -41,8 +41,8 @@ test.describe("TC-CHKT-035: Terms/privacy links open popup with sanitized markdo
|
|
|
41
41
|
expect(await page.evaluate(() => window.__checkoutTermsInjected ?? null)).toBeNull();
|
|
42
42
|
await page.getByRole("button", { name: /close/i }).click();
|
|
43
43
|
await expect(page.getByRole("dialog")).toBeHidden();
|
|
44
|
-
await page.
|
|
45
|
-
await page.
|
|
44
|
+
await page.getByRole("checkbox", { name: /terms of service/i }).check();
|
|
45
|
+
await page.getByRole("checkbox", { name: /privacy policy/i }).check();
|
|
46
46
|
await page.getByRole("button", { name: /pay now/i }).click();
|
|
47
47
|
await page.waitForURL(new RegExp(`/pay/${link.slug}/success/`));
|
|
48
48
|
const transactionId = page.url().split("/").pop();
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/checkout/__integration__/TC-CHKT-035.spec.ts"],
|
|
4
|
-
"sourcesContent": ["import { expect, test } from '@playwright/test'\nimport { getAuthToken } from '@open-mercato/core/modules/core/__integration__/helpers/api'\nimport {\n createCheckoutClientHeaders,\n createFixedTemplateInput,\n createLinkFixture,\n deleteCheckoutEntityIfExists,\n readCheckoutTransaction,\n} from './helpers/fixtures'\n\ntest.describe('TC-CHKT-035: Terms/privacy links open popup with sanitized markdown content and accepted proof is stored on transaction', () => {\n test('opens the legal-document modal, keeps unsafe markdown inert, and persists consent proof on the transaction', async ({ page, request }) => {\n let token: string | null = null\n let linkId: string | null = null\n\n try {\n token = await getAuthToken(request)\n const link = await createLinkFixture(request, token, {\n ...createFixedTemplateInput({\n status: 'active',\n collectCustomerDetails: false,\n legalDocuments: {\n terms: {\n title: 'Terms of Service',\n markdown: '<script>window.__checkoutTermsInjected = true</script>\\n\\n**Keep this safe**',\n required: true,\n },\n privacyPolicy: {\n title: 'Privacy Policy',\n markdown: 'We only use your data for this checkout.',\n required: true,\n },\n },\n }),\n })\n linkId = link.id\n\n await page.context().setExtraHTTPHeaders(createCheckoutClientHeaders())\n await page.goto(`/pay/${encodeURIComponent(link.slug)}`)\n await page.getByRole('button', { name: /read document/i }).first().click()\n\n await expect(page.getByRole('dialog')).toBeVisible()\n await expect(page.getByRole('heading', { name: 'Terms of Service' })).toBeVisible()\n await expect(page.getByText('Keep this safe')).toBeVisible()\n expect(await page.evaluate(() => (window as Window & { __checkoutTermsInjected?: boolean }).__checkoutTermsInjected ?? null)).toBeNull()\n await page.getByRole('button', { name: /close/i }).click()\n await expect(page.getByRole('dialog')).toBeHidden()\n\n await page.
|
|
5
|
-
"mappings": "AAAA,SAAS,QAAQ,YAAY;AAC7B,SAAS,oBAAoB;AAC7B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAEP,KAAK,SAAS,2HAA2H,MAAM;AAC7I,OAAK,8GAA8G,OAAO,EAAE,MAAM,QAAQ,MAAM;AAC9I,QAAI,QAAuB;AAC3B,QAAI,SAAwB;AAE5B,QAAI;AACF,cAAQ,MAAM,aAAa,OAAO;AAClC,YAAM,OAAO,MAAM,kBAAkB,SAAS,OAAO;AAAA,QACnD,GAAG,yBAAyB;AAAA,UAC1B,QAAQ;AAAA,UACR,wBAAwB;AAAA,UACxB,gBAAgB;AAAA,YACd,OAAO;AAAA,cACL,OAAO;AAAA,cACP,UAAU;AAAA,cACV,UAAU;AAAA,YACZ;AAAA,YACA,eAAe;AAAA,cACb,OAAO;AAAA,cACP,UAAU;AAAA,cACV,UAAU;AAAA,YACZ;AAAA,UACF;AAAA,QACF,CAAC;AAAA,MACH,CAAC;AACD,eAAS,KAAK;AAEd,YAAM,KAAK,QAAQ,EAAE,oBAAoB,4BAA4B,CAAC;AACtE,YAAM,KAAK,KAAK,QAAQ,mBAAmB,KAAK,IAAI,CAAC,EAAE;AACvD,YAAM,KAAK,UAAU,UAAU,EAAE,MAAM,iBAAiB,CAAC,EAAE,MAAM,EAAE,MAAM;AAEzE,YAAM,OAAO,KAAK,UAAU,QAAQ,CAAC,EAAE,YAAY;AACnD,YAAM,OAAO,KAAK,UAAU,WAAW,EAAE,MAAM,mBAAmB,CAAC,CAAC,EAAE,YAAY;AAClF,YAAM,OAAO,KAAK,UAAU,gBAAgB,CAAC,EAAE,YAAY;AAC3D,aAAO,MAAM,KAAK,SAAS,MAAO,OAA0D,2BAA2B,IAAI,CAAC,EAAE,SAAS;AACvI,YAAM,KAAK,UAAU,UAAU,EAAE,MAAM,SAAS,CAAC,EAAE,MAAM;AACzD,YAAM,OAAO,KAAK,UAAU,QAAQ,CAAC,EAAE,WAAW;AAElD,YAAM,KAAK,
|
|
4
|
+
"sourcesContent": ["import { expect, test } from '@playwright/test'\nimport { getAuthToken } from '@open-mercato/core/modules/core/__integration__/helpers/api'\nimport {\n createCheckoutClientHeaders,\n createFixedTemplateInput,\n createLinkFixture,\n deleteCheckoutEntityIfExists,\n readCheckoutTransaction,\n} from './helpers/fixtures'\n\ntest.describe('TC-CHKT-035: Terms/privacy links open popup with sanitized markdown content and accepted proof is stored on transaction', () => {\n test('opens the legal-document modal, keeps unsafe markdown inert, and persists consent proof on the transaction', async ({ page, request }) => {\n let token: string | null = null\n let linkId: string | null = null\n\n try {\n token = await getAuthToken(request)\n const link = await createLinkFixture(request, token, {\n ...createFixedTemplateInput({\n status: 'active',\n collectCustomerDetails: false,\n legalDocuments: {\n terms: {\n title: 'Terms of Service',\n markdown: '<script>window.__checkoutTermsInjected = true</script>\\n\\n**Keep this safe**',\n required: true,\n },\n privacyPolicy: {\n title: 'Privacy Policy',\n markdown: 'We only use your data for this checkout.',\n required: true,\n },\n },\n }),\n })\n linkId = link.id\n\n await page.context().setExtraHTTPHeaders(createCheckoutClientHeaders())\n await page.goto(`/pay/${encodeURIComponent(link.slug)}`)\n await page.getByRole('button', { name: /read document/i }).first().click()\n\n await expect(page.getByRole('dialog')).toBeVisible()\n await expect(page.getByRole('heading', { name: 'Terms of Service' })).toBeVisible()\n await expect(page.getByText('Keep this safe')).toBeVisible()\n expect(await page.evaluate(() => (window as Window & { __checkoutTermsInjected?: boolean }).__checkoutTermsInjected ?? null)).toBeNull()\n await page.getByRole('button', { name: /close/i }).click()\n await expect(page.getByRole('dialog')).toBeHidden()\n\n await page.getByRole('checkbox', { name: /terms of service/i }).check()\n await page.getByRole('checkbox', { name: /privacy policy/i }).check()\n await page.getByRole('button', { name: /pay now/i }).click()\n await page.waitForURL(new RegExp(`/pay/${link.slug}/success/`))\n\n const transactionId = page.url().split('/').pop()\n expect(transactionId).toBeTruthy()\n\n const transaction = await readCheckoutTransaction(request, token, transactionId!)\n expect(transaction.acceptedLegalConsents).toMatchObject({\n terms: {\n title: 'Terms of Service',\n required: true,\n markdownHash: expect.any(String),\n acceptedAt: expect.any(String),\n },\n privacyPolicy: {\n title: 'Privacy Policy',\n required: true,\n markdownHash: expect.any(String),\n acceptedAt: expect.any(String),\n },\n })\n } finally {\n await deleteCheckoutEntityIfExists(request, token, 'links', linkId)\n }\n })\n})\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,QAAQ,YAAY;AAC7B,SAAS,oBAAoB;AAC7B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAEP,KAAK,SAAS,2HAA2H,MAAM;AAC7I,OAAK,8GAA8G,OAAO,EAAE,MAAM,QAAQ,MAAM;AAC9I,QAAI,QAAuB;AAC3B,QAAI,SAAwB;AAE5B,QAAI;AACF,cAAQ,MAAM,aAAa,OAAO;AAClC,YAAM,OAAO,MAAM,kBAAkB,SAAS,OAAO;AAAA,QACnD,GAAG,yBAAyB;AAAA,UAC1B,QAAQ;AAAA,UACR,wBAAwB;AAAA,UACxB,gBAAgB;AAAA,YACd,OAAO;AAAA,cACL,OAAO;AAAA,cACP,UAAU;AAAA,cACV,UAAU;AAAA,YACZ;AAAA,YACA,eAAe;AAAA,cACb,OAAO;AAAA,cACP,UAAU;AAAA,cACV,UAAU;AAAA,YACZ;AAAA,UACF;AAAA,QACF,CAAC;AAAA,MACH,CAAC;AACD,eAAS,KAAK;AAEd,YAAM,KAAK,QAAQ,EAAE,oBAAoB,4BAA4B,CAAC;AACtE,YAAM,KAAK,KAAK,QAAQ,mBAAmB,KAAK,IAAI,CAAC,EAAE;AACvD,YAAM,KAAK,UAAU,UAAU,EAAE,MAAM,iBAAiB,CAAC,EAAE,MAAM,EAAE,MAAM;AAEzE,YAAM,OAAO,KAAK,UAAU,QAAQ,CAAC,EAAE,YAAY;AACnD,YAAM,OAAO,KAAK,UAAU,WAAW,EAAE,MAAM,mBAAmB,CAAC,CAAC,EAAE,YAAY;AAClF,YAAM,OAAO,KAAK,UAAU,gBAAgB,CAAC,EAAE,YAAY;AAC3D,aAAO,MAAM,KAAK,SAAS,MAAO,OAA0D,2BAA2B,IAAI,CAAC,EAAE,SAAS;AACvI,YAAM,KAAK,UAAU,UAAU,EAAE,MAAM,SAAS,CAAC,EAAE,MAAM;AACzD,YAAM,OAAO,KAAK,UAAU,QAAQ,CAAC,EAAE,WAAW;AAElD,YAAM,KAAK,UAAU,YAAY,EAAE,MAAM,oBAAoB,CAAC,EAAE,MAAM;AACtE,YAAM,KAAK,UAAU,YAAY,EAAE,MAAM,kBAAkB,CAAC,EAAE,MAAM;AACpE,YAAM,KAAK,UAAU,UAAU,EAAE,MAAM,WAAW,CAAC,EAAE,MAAM;AAC3D,YAAM,KAAK,WAAW,IAAI,OAAO,QAAQ,KAAK,IAAI,WAAW,CAAC;AAE9D,YAAM,gBAAgB,KAAK,IAAI,EAAE,MAAM,GAAG,EAAE,IAAI;AAChD,aAAO,aAAa,EAAE,WAAW;AAEjC,YAAM,cAAc,MAAM,wBAAwB,SAAS,OAAO,aAAc;AAChF,aAAO,YAAY,qBAAqB,EAAE,cAAc;AAAA,QACtD,OAAO;AAAA,UACL,OAAO;AAAA,UACP,UAAU;AAAA,UACV,cAAc,OAAO,IAAI,MAAM;AAAA,UAC/B,YAAY,OAAO,IAAI,MAAM;AAAA,QAC/B;AAAA,QACA,eAAe;AAAA,UACb,OAAO;AAAA,UACP,UAAU;AAAA,UACV,cAAc,OAAO,IAAI,MAAM;AAAA,UAC/B,YAAY,OAAO,IAAI,MAAM;AAAA,QAC/B;AAAA,MACF,CAAC;AAAA,IACH,UAAE;AACA,YAAM,6BAA6B,SAAS,OAAO,SAAS,MAAM;AAAA,IACpE;AAAA,EACF,CAAC;AACH,CAAC;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -16,9 +16,18 @@ import { mapCrudServerErrorToFormErrors } from "@open-mercato/ui/backend/utils/s
|
|
|
16
16
|
import { Alert, AlertDescription, AlertTitle } from "@open-mercato/ui/primitives/alert";
|
|
17
17
|
import { Button } from "@open-mercato/ui/primitives/button";
|
|
18
18
|
import { Card, CardContent } from "@open-mercato/ui/primitives/card";
|
|
19
|
+
import { Checkbox } from "@open-mercato/ui/primitives/checkbox";
|
|
19
20
|
import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@open-mercato/ui/primitives/dialog";
|
|
20
21
|
import { Input } from "@open-mercato/ui/primitives/input";
|
|
21
22
|
import { PasswordInput } from "@open-mercato/ui/primitives/password-input";
|
|
23
|
+
import { Radio, RadioGroup } from "@open-mercato/ui/primitives/radio";
|
|
24
|
+
import {
|
|
25
|
+
Select,
|
|
26
|
+
SelectContent,
|
|
27
|
+
SelectItem,
|
|
28
|
+
SelectTrigger,
|
|
29
|
+
SelectValue
|
|
30
|
+
} from "@open-mercato/ui/primitives/select";
|
|
22
31
|
import { Spinner } from "@open-mercato/ui/primitives/spinner";
|
|
23
32
|
import { Textarea } from "@open-mercato/ui/primitives/textarea";
|
|
24
33
|
import {
|
|
@@ -36,6 +45,24 @@ const LEGAL_CONSENT_HANDLE = ComponentReplacementHandles.section("checkout.pay-p
|
|
|
36
45
|
const GATEWAY_FORM_HANDLE = ComponentReplacementHandles.section("checkout.pay-page", "gateway-form");
|
|
37
46
|
const HELP_HANDLE = ComponentReplacementHandles.section("checkout.pay-page", "help");
|
|
38
47
|
const FOOTER_HANDLE = ComponentReplacementHandles.section("checkout.pay-page", "footer");
|
|
48
|
+
const CHECKOUT_THEME_FALLBACKS = {
|
|
49
|
+
accent: "#1E3A8A",
|
|
50
|
+
accentSecondary: "#F59E0B",
|
|
51
|
+
darkBackground: "#0B1020",
|
|
52
|
+
lightBackground: "#F5EFE6",
|
|
53
|
+
darkText: "#F8FAFC",
|
|
54
|
+
lightText: "#111827",
|
|
55
|
+
darkMutedText: "#CBD5E1",
|
|
56
|
+
lightMutedText: "#6B7280",
|
|
57
|
+
darkSurface: "#111827",
|
|
58
|
+
lightSurface: "#FFFFFF",
|
|
59
|
+
darkShell: "#020617",
|
|
60
|
+
lightShell: "#FFFDF8",
|
|
61
|
+
darkBorder: "#E2E8F0",
|
|
62
|
+
inputBackground: "rgba(255, 255, 255, 0.96)",
|
|
63
|
+
inputText: "#0F172A"
|
|
64
|
+
};
|
|
65
|
+
const PAY_PAGE_EMPTY_SELECT_VALUE = "__om_checkout_empty__";
|
|
39
66
|
function clamp(value, min, max) {
|
|
40
67
|
return Math.min(Math.max(value, min), max);
|
|
41
68
|
}
|
|
@@ -135,22 +162,33 @@ function withAlpha(color, alpha) {
|
|
|
135
162
|
function getContrastText(color) {
|
|
136
163
|
const { r, g, b } = hexToRgb(color);
|
|
137
164
|
const luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
|
|
138
|
-
return luminance > 0.62 ?
|
|
165
|
+
return luminance > 0.62 ? CHECKOUT_THEME_FALLBACKS.inputText : CHECKOUT_THEME_FALLBACKS.darkText;
|
|
139
166
|
}
|
|
140
167
|
function resolveThemeTokens(payload, prefersDark) {
|
|
141
|
-
const accent = normalizeHexColor(payload?.primaryColor,
|
|
142
|
-
const accentSecondary = normalizeHexColor(payload?.secondaryColor,
|
|
168
|
+
const accent = normalizeHexColor(payload?.primaryColor, CHECKOUT_THEME_FALLBACKS.accent);
|
|
169
|
+
const accentSecondary = normalizeHexColor(payload?.secondaryColor, CHECKOUT_THEME_FALLBACKS.accentSecondary);
|
|
143
170
|
const requestedMode = payload?.themeMode ?? "auto";
|
|
144
171
|
const mode = requestedMode === "dark" || requestedMode === "auto" && prefersDark ? "dark" : "light";
|
|
145
|
-
const background = normalizeHexColor(
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
172
|
+
const background = normalizeHexColor(
|
|
173
|
+
payload?.backgroundColor,
|
|
174
|
+
mode === "dark" ? CHECKOUT_THEME_FALLBACKS.darkBackground : CHECKOUT_THEME_FALLBACKS.lightBackground
|
|
175
|
+
);
|
|
176
|
+
const text = mode === "dark" ? CHECKOUT_THEME_FALLBACKS.darkText : CHECKOUT_THEME_FALLBACKS.lightText;
|
|
177
|
+
const mutedText = mode === "dark" ? CHECKOUT_THEME_FALLBACKS.darkMutedText : CHECKOUT_THEME_FALLBACKS.lightMutedText;
|
|
178
|
+
const surface = mixHexColors(
|
|
179
|
+
background,
|
|
180
|
+
mode === "dark" ? CHECKOUT_THEME_FALLBACKS.darkSurface : CHECKOUT_THEME_FALLBACKS.lightSurface,
|
|
181
|
+
mode === "dark" ? 0.62 : 0.76
|
|
182
|
+
);
|
|
149
183
|
const surfaceMuted = mixHexColors(accentSecondary, background, mode === "dark" ? 0.18 : 0.88);
|
|
150
184
|
const surfaceStrong = mixHexColors(accent, background, mode === "dark" ? 0.22 : 0.9);
|
|
151
|
-
const border = withAlpha(mode === "dark" ?
|
|
185
|
+
const border = withAlpha(mode === "dark" ? CHECKOUT_THEME_FALLBACKS.darkBorder : accent, mode === "dark" ? 0.16 : 0.14);
|
|
152
186
|
const borderStrong = withAlpha(accent, mode === "dark" ? 0.34 : 0.22);
|
|
153
|
-
const shellBackground = mixHexColors(
|
|
187
|
+
const shellBackground = mixHexColors(
|
|
188
|
+
background,
|
|
189
|
+
mode === "dark" ? CHECKOUT_THEME_FALLBACKS.darkShell : CHECKOUT_THEME_FALLBACKS.lightShell,
|
|
190
|
+
mode === "dark" ? 0.82 : 0.64
|
|
191
|
+
);
|
|
154
192
|
const heroStart = withAlpha(accent, mode === "dark" ? 0.26 : 0.16);
|
|
155
193
|
const heroEnd = withAlpha(accentSecondary, mode === "dark" ? 0.22 : 0.2);
|
|
156
194
|
const errorBase = mode === "dark" ? "#F87171" : "#DC2626";
|
|
@@ -172,7 +210,7 @@ function resolveThemeTokens(payload, prefersDark) {
|
|
|
172
210
|
surfaceStrong,
|
|
173
211
|
border,
|
|
174
212
|
borderStrong,
|
|
175
|
-
shadow: mode === "dark" ? `0 32px 80px ${withAlpha(
|
|
213
|
+
shadow: mode === "dark" ? `0 32px 80px ${withAlpha(CHECKOUT_THEME_FALLBACKS.darkShell, 0.55)}` : `0 28px 72px ${withAlpha(accent, 0.12)}`,
|
|
176
214
|
accentShadow: `0 22px 48px ${withAlpha(accent, mode === "dark" ? 0.3 : 0.22)}`,
|
|
177
215
|
heroBackground: `linear-gradient(145deg, ${heroStart} 0%, ${heroEnd} 100%)`,
|
|
178
216
|
errorText: mode === "dark" ? "#FCA5A5" : "#B91C1C",
|
|
@@ -182,11 +220,18 @@ function resolveThemeTokens(payload, prefersDark) {
|
|
|
182
220
|
errorRing: withAlpha(errorBase, mode === "dark" ? 0.28 : 0.18)
|
|
183
221
|
};
|
|
184
222
|
}
|
|
185
|
-
function buildReadableInputStyle(themeTokens, hasError) {
|
|
223
|
+
function buildReadableInputStyle(themeTokens, hasError, disabled = false) {
|
|
224
|
+
if (disabled) {
|
|
225
|
+
return {
|
|
226
|
+
background: "var(--bg-disabled)",
|
|
227
|
+
color: "var(--text-disabled)",
|
|
228
|
+
borderColor: "var(--border-disabled)"
|
|
229
|
+
};
|
|
230
|
+
}
|
|
186
231
|
return {
|
|
187
|
-
background:
|
|
188
|
-
color:
|
|
189
|
-
borderColor: hasError ? themeTokens.errorBorder : withAlpha(
|
|
232
|
+
background: CHECKOUT_THEME_FALLBACKS.inputBackground,
|
|
233
|
+
color: CHECKOUT_THEME_FALLBACKS.inputText,
|
|
234
|
+
borderColor: hasError ? themeTokens.errorBorder : withAlpha(CHECKOUT_THEME_FALLBACKS.inputText, 0.12),
|
|
190
235
|
boxShadow: hasError ? `0 0 0 3px ${themeTokens.errorRing}` : void 0
|
|
191
236
|
};
|
|
192
237
|
}
|
|
@@ -196,14 +241,6 @@ function buildValidationMessageStyle(themeTokens) {
|
|
|
196
241
|
fontWeight: 500
|
|
197
242
|
};
|
|
198
243
|
}
|
|
199
|
-
function buildValidationNoticeStyle(themeTokens) {
|
|
200
|
-
return {
|
|
201
|
-
borderColor: themeTokens.errorBorder,
|
|
202
|
-
background: themeTokens.errorSurface,
|
|
203
|
-
color: themeTokens.errorText,
|
|
204
|
-
boxShadow: `0 0 0 1px ${themeTokens.errorSurfaceStrong} inset`
|
|
205
|
-
};
|
|
206
|
-
}
|
|
207
244
|
function formatPublicFieldValue(value, booleanLabels) {
|
|
208
245
|
if (Array.isArray(value)) return value.map((entry) => String(entry)).join(", ");
|
|
209
246
|
if (typeof value === "boolean") {
|
|
@@ -279,7 +316,7 @@ function buildButtonStyle(themeTokens, variant = "solid") {
|
|
|
279
316
|
boxShadow: themeTokens.accentShadow
|
|
280
317
|
};
|
|
281
318
|
}
|
|
282
|
-
const READABLE_INPUT_CLASSNAME = "border bg-white/95 text-slate-900 placeholder:text-slate-400 disabled:cursor-not-allowed disabled:
|
|
319
|
+
const READABLE_INPUT_CLASSNAME = "border bg-white/95 text-slate-900 placeholder:text-slate-400 disabled:cursor-not-allowed disabled:bg-bg-disabled disabled:border-border-disabled disabled:text-text-disabled";
|
|
283
320
|
function PayPageSurface({
|
|
284
321
|
previewBanner,
|
|
285
322
|
leftColumn,
|
|
@@ -481,12 +518,11 @@ function PayPageCustomerForm({
|
|
|
481
518
|
},
|
|
482
519
|
children: [
|
|
483
520
|
/* @__PURE__ */ jsx(
|
|
484
|
-
|
|
521
|
+
Checkbox,
|
|
485
522
|
{
|
|
486
|
-
type: "checkbox",
|
|
487
523
|
checked: value === true,
|
|
488
524
|
disabled: inputsLocked,
|
|
489
|
-
|
|
525
|
+
onCheckedChange: (checked) => onFieldChange(field.key, checked === true)
|
|
490
526
|
}
|
|
491
527
|
),
|
|
492
528
|
/* @__PURE__ */ jsxs("span", { className: "space-y-1", children: [
|
|
@@ -511,19 +547,30 @@ function PayPageCustomerForm({
|
|
|
511
547
|
disabled: inputsLocked,
|
|
512
548
|
onChange: (event) => onFieldChange(field.key, event.target.value),
|
|
513
549
|
placeholder: field.placeholder ?? void 0,
|
|
514
|
-
style: buildReadableInputStyle(themeTokens, Boolean(fieldError))
|
|
550
|
+
style: buildReadableInputStyle(themeTokens, Boolean(fieldError), inputsLocked)
|
|
515
551
|
}
|
|
516
552
|
) : field.kind === "select" || field.kind === "radio" ? /* @__PURE__ */ jsxs(
|
|
517
|
-
|
|
553
|
+
Select,
|
|
518
554
|
{
|
|
519
|
-
|
|
520
|
-
value: typeof value === "string" ? value : "",
|
|
555
|
+
value: typeof value === "string" && value.length > 0 ? value : PAY_PAGE_EMPTY_SELECT_VALUE,
|
|
521
556
|
disabled: inputsLocked,
|
|
522
|
-
|
|
523
|
-
|
|
557
|
+
onValueChange: (nextValue) => {
|
|
558
|
+
onFieldChange(field.key, nextValue === PAY_PAGE_EMPTY_SELECT_VALUE ? "" : nextValue);
|
|
559
|
+
},
|
|
524
560
|
children: [
|
|
525
|
-
/* @__PURE__ */ jsx(
|
|
526
|
-
|
|
561
|
+
/* @__PURE__ */ jsx(
|
|
562
|
+
SelectTrigger,
|
|
563
|
+
{
|
|
564
|
+
className: `rounded-xl ${READABLE_INPUT_CLASSNAME}`,
|
|
565
|
+
"aria-invalid": Boolean(fieldError),
|
|
566
|
+
style: buildReadableInputStyle(themeTokens, Boolean(fieldError), inputsLocked),
|
|
567
|
+
children: /* @__PURE__ */ jsx(SelectValue, { placeholder: t("checkout.payPage.fields.selectPlaceholder", "Select...") })
|
|
568
|
+
}
|
|
569
|
+
),
|
|
570
|
+
/* @__PURE__ */ jsxs(SelectContent, { children: [
|
|
571
|
+
/* @__PURE__ */ jsx(SelectItem, { value: PAY_PAGE_EMPTY_SELECT_VALUE, children: t("checkout.payPage.fields.selectPlaceholder", "Select...") }),
|
|
572
|
+
(field.options ?? []).map((option) => /* @__PURE__ */ jsx(SelectItem, { value: option.value, children: option.label }, option.value))
|
|
573
|
+
] })
|
|
527
574
|
]
|
|
528
575
|
}
|
|
529
576
|
) : /* @__PURE__ */ jsx(
|
|
@@ -536,7 +583,7 @@ function PayPageCustomerForm({
|
|
|
536
583
|
onChange: (event) => onFieldChange(field.key, event.target.value),
|
|
537
584
|
placeholder: field.placeholder ?? void 0,
|
|
538
585
|
autoComplete: semanticType === "email" ? "email" : semanticType === "phone" ? "tel" : void 0,
|
|
539
|
-
style: buildReadableInputStyle(themeTokens, Boolean(fieldError))
|
|
586
|
+
style: buildReadableInputStyle(themeTokens, Boolean(fieldError), inputsLocked)
|
|
540
587
|
}
|
|
541
588
|
)
|
|
542
589
|
] }),
|
|
@@ -583,39 +630,48 @@ function PayPagePricing({
|
|
|
583
630
|
payload.customAmountMin != null ? formatAmount(payload.customAmountMin, payload.customAmountCurrencyCode) : null,
|
|
584
631
|
payload.customAmountMax != null ? formatAmount(payload.customAmountMax, payload.customAmountCurrencyCode) : null
|
|
585
632
|
].filter(Boolean).join(" - "),
|
|
586
|
-
style: buildReadableInputStyle(themeTokens, Boolean(fieldErrors.amount))
|
|
633
|
+
style: buildReadableInputStyle(themeTokens, Boolean(fieldErrors.amount), inputsLocked)
|
|
587
634
|
}
|
|
588
635
|
),
|
|
589
636
|
fieldErrors.amount ? /* @__PURE__ */ jsx("p", { className: "text-sm", style: buildValidationMessageStyle(themeTokens), children: translateValidationMessage(fieldErrors.amount, "amount") }) : null
|
|
590
637
|
] }) : null,
|
|
591
|
-
payload.pricingMode === "price_list" ? /* @__PURE__ */ jsxs(
|
|
592
|
-
|
|
593
|
-
|
|
638
|
+
payload.pricingMode === "price_list" ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
639
|
+
/* @__PURE__ */ jsx(
|
|
640
|
+
RadioGroup,
|
|
594
641
|
{
|
|
595
|
-
className: "
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
642
|
+
className: "space-y-3",
|
|
643
|
+
value: selectedPriceItemId ?? "",
|
|
644
|
+
disabled: inputsLocked,
|
|
645
|
+
onValueChange: (itemId) => {
|
|
646
|
+
const item = (payload.priceListItems ?? []).find((candidate) => candidate.id === itemId);
|
|
647
|
+
if (item) onPriceItemSelect(item);
|
|
599
648
|
},
|
|
600
|
-
children: [
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
649
|
+
children: (payload.priceListItems ?? []).map((item) => /* @__PURE__ */ jsxs(
|
|
650
|
+
"label",
|
|
651
|
+
{
|
|
652
|
+
className: "flex cursor-pointer items-center justify-between gap-3 rounded-xl border px-4 py-4 text-sm transition",
|
|
653
|
+
style: {
|
|
654
|
+
background: selectedPriceItemId === item.id ? withAlpha(themeTokens.accent, 0.08) : withAlpha(themeTokens.shellBackground, 0.66),
|
|
655
|
+
borderColor: selectedPriceItemId === item.id ? themeTokens.borderStrong : themeTokens.border
|
|
656
|
+
},
|
|
657
|
+
children: [
|
|
658
|
+
/* @__PURE__ */ jsxs("span", { className: "flex items-center gap-3", children: [
|
|
659
|
+
/* @__PURE__ */ jsx(
|
|
660
|
+
Radio,
|
|
661
|
+
{
|
|
662
|
+
value: item.id,
|
|
663
|
+
disabled: inputsLocked
|
|
664
|
+
}
|
|
665
|
+
),
|
|
666
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium", children: item.description })
|
|
667
|
+
] }),
|
|
668
|
+
/* @__PURE__ */ jsx("span", { className: "whitespace-nowrap font-semibold", children: formatAmount(item.amount, item.currencyCode) })
|
|
669
|
+
]
|
|
670
|
+
},
|
|
671
|
+
item.id
|
|
672
|
+
))
|
|
673
|
+
}
|
|
674
|
+
),
|
|
619
675
|
fieldErrors.selectedPriceItemId ? /* @__PURE__ */ jsx("p", { className: "text-sm", style: buildValidationMessageStyle(themeTokens), children: translateValidationMessage(fieldErrors.selectedPriceItemId, "selectedPriceItemId") }) : null
|
|
620
676
|
] }) : null
|
|
621
677
|
] });
|
|
@@ -677,12 +733,11 @@ function PayPageLegalConsent({
|
|
|
677
733
|
},
|
|
678
734
|
children: /* @__PURE__ */ jsxs("label", { className: "flex items-start gap-3 text-sm", children: [
|
|
679
735
|
/* @__PURE__ */ jsx(
|
|
680
|
-
|
|
736
|
+
Checkbox,
|
|
681
737
|
{
|
|
682
|
-
type: "checkbox",
|
|
683
738
|
checked: acceptedLegalConsents.terms === true,
|
|
684
739
|
disabled: inputsLocked,
|
|
685
|
-
|
|
740
|
+
onCheckedChange: (checked) => onConsentChange("terms", checked === true)
|
|
686
741
|
}
|
|
687
742
|
),
|
|
688
743
|
/* @__PURE__ */ jsxs("span", { className: "space-y-2", children: [
|
|
@@ -721,12 +776,11 @@ function PayPageLegalConsent({
|
|
|
721
776
|
},
|
|
722
777
|
children: /* @__PURE__ */ jsxs("label", { className: "flex items-start gap-3 text-sm", children: [
|
|
723
778
|
/* @__PURE__ */ jsx(
|
|
724
|
-
|
|
779
|
+
Checkbox,
|
|
725
780
|
{
|
|
726
|
-
type: "checkbox",
|
|
727
781
|
checked: acceptedLegalConsents.privacyPolicy === true,
|
|
728
782
|
disabled: inputsLocked,
|
|
729
|
-
|
|
783
|
+
onCheckedChange: (checked) => onConsentChange("privacyPolicy", checked === true)
|
|
730
784
|
}
|
|
731
785
|
),
|
|
732
786
|
/* @__PURE__ */ jsxs("span", { className: "space-y-2", children: [
|
|
@@ -782,7 +836,7 @@ function PayPagePaymentForm({
|
|
|
782
836
|
const t = useT();
|
|
783
837
|
const embeddedPaymentSession = paymentSession?.type === "embedded" ? paymentSession : null;
|
|
784
838
|
return /* @__PURE__ */ jsxs("section", { className: "space-y-4", children: [
|
|
785
|
-
submissionError ? /* @__PURE__ */ jsx(
|
|
839
|
+
submissionError ? /* @__PURE__ */ jsx(Alert, { status: "error", style: "lighter", size: "default", children: /* @__PURE__ */ jsx(AlertDescription, { children: submissionError }) }) : null,
|
|
786
840
|
/* @__PURE__ */ jsx(InjectionSpot, { spotId: "checkout.pay-page:gateway-widget:before", context: injectionContext }),
|
|
787
841
|
embeddedPaymentSession && embeddedRenderer ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
788
842
|
/* @__PURE__ */ jsx(InjectionSpot, { spotId: "checkout.pay-page:gateway-widget:renderer:before", context: injectionContext }),
|
|
@@ -947,33 +1001,31 @@ function PayPageFooter({ payload, themeTokens }) {
|
|
|
947
1001
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-3 sm:justify-end", children: [
|
|
948
1002
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-xs", style: { color: themeTokens.mutedText }, children: [
|
|
949
1003
|
/* @__PURE__ */ jsx("label", { htmlFor: selectId, children: t("common.language", "Language") }),
|
|
950
|
-
/* @__PURE__ */ jsxs(
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
)
|
|
976
|
-
] })
|
|
1004
|
+
/* @__PURE__ */ jsxs(
|
|
1005
|
+
Select,
|
|
1006
|
+
{
|
|
1007
|
+
value: locale,
|
|
1008
|
+
onValueChange: (nextLocale) => setLocale(nextLocale),
|
|
1009
|
+
disabled: pending,
|
|
1010
|
+
children: [
|
|
1011
|
+
/* @__PURE__ */ jsx(
|
|
1012
|
+
SelectTrigger,
|
|
1013
|
+
{
|
|
1014
|
+
id: selectId,
|
|
1015
|
+
size: "sm",
|
|
1016
|
+
className: "w-auto min-w-28 rounded-full text-xs font-medium",
|
|
1017
|
+
style: {
|
|
1018
|
+
background: withAlpha(themeTokens.surface, 0.92),
|
|
1019
|
+
borderColor: themeTokens.borderStrong,
|
|
1020
|
+
color: themeTokens.text
|
|
1021
|
+
},
|
|
1022
|
+
children: /* @__PURE__ */ jsx(SelectValue, {})
|
|
1023
|
+
}
|
|
1024
|
+
),
|
|
1025
|
+
/* @__PURE__ */ jsx(SelectContent, { children: locales.map((entry) => /* @__PURE__ */ jsx(SelectItem, { value: entry, children: languageLabels[entry] }, entry)) })
|
|
1026
|
+
]
|
|
1027
|
+
}
|
|
1028
|
+
)
|
|
977
1029
|
] }),
|
|
978
1030
|
/* @__PURE__ */ jsx("div", { className: "text-xs uppercase tracking-widest", children: payload.gatewayProviderKey ?? t("checkout.payPage.header.autoProvider", "Configured in checkout") })
|
|
979
1031
|
] })
|
|
@@ -1484,13 +1536,21 @@ function PayPage({
|
|
|
1484
1536
|
);
|
|
1485
1537
|
}
|
|
1486
1538
|
if (loadError || !payload) {
|
|
1487
|
-
return /* @__PURE__ */ jsx("div", { className: "mx-auto max-w-3xl px-4 py-16", children: /* @__PURE__ */
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1539
|
+
return /* @__PURE__ */ jsx("div", { className: "mx-auto max-w-3xl px-4 py-16", children: /* @__PURE__ */ jsx(
|
|
1540
|
+
Alert,
|
|
1541
|
+
{
|
|
1542
|
+
status: "error",
|
|
1543
|
+
style: "lighter",
|
|
1544
|
+
size: "default",
|
|
1545
|
+
action: /* @__PURE__ */ jsx(Button, { type: "button", variant: "outline", onClick: () => {
|
|
1546
|
+
void loadPayload();
|
|
1547
|
+
}, children: t("checkout.payPage.actions.retry", "Retry") }),
|
|
1548
|
+
children: /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
|
|
1549
|
+
/* @__PURE__ */ jsx(AlertTitle, { children: t("checkout.payPage.errors.loadTitle", "Unable to load payment link") }),
|
|
1550
|
+
/* @__PURE__ */ jsx(AlertDescription, { children: loadError ?? t("checkout.payPage.errors.loadMessage", "We couldn't load this payment page. Please try again.") })
|
|
1551
|
+
] })
|
|
1552
|
+
}
|
|
1553
|
+
) });
|
|
1494
1554
|
}
|
|
1495
1555
|
if (payload.requiresPassword) {
|
|
1496
1556
|
return /* @__PURE__ */ jsx(
|