@12-apps/payments-frontend 3.9.0 → 3.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -2
- package/src/activation/charge-copy.ts +10 -0
- package/src/activation/use-activation-charge.ts +10 -8
- package/src/card/copy.ts +115 -0
- package/src/card/cpf.ts +12 -5
- package/src/card/fields.tsx +17 -12
- package/src/card/format.ts +32 -16
- package/src/card/index.ts +3 -1
- package/src/card/pt-BR.ts +51 -0
- package/src/card/stripe-token.ts +5 -6
- package/src/card/tokenize.ts +28 -32
- package/src/components/CheckoutPayment.tsx +37 -201
- package/src/components/ConfirmCredentialSave.tsx +8 -10
- package/src/components/ConnectionCard.tsx +23 -18
- package/src/components/ConnectionProbe.tsx +3 -1
- package/src/components/CredentialFieldStack.tsx +8 -2
- package/src/components/CredentialFields.tsx +13 -6
- package/src/components/CredentialFormAlerts.tsx +28 -19
- package/src/components/EnvironmentTabs.tsx +23 -15
- package/src/components/OAuthPanel.tsx +5 -6
- package/src/components/PaymentProviderSettings.tsx +45 -13
- package/src/components/ProviderConnection.tsx +37 -28
- package/src/components/ProviderList.tsx +6 -3
- package/src/components/ProviderPriorityList.tsx +18 -16
- package/src/components/ProviderStatusBar.tsx +24 -24
- package/src/components/SetupGuideSection.tsx +15 -6
- package/src/components/checkout/apple-pay-button.tsx +19 -9
- package/src/components/checkout/buyer-fields.ts +5 -3
- package/src/components/checkout/buyer-gate.ts +68 -0
- package/src/components/checkout/buyer-info-form.tsx +14 -15
- package/src/components/checkout/card-instruments.ts +31 -12
- package/src/components/checkout/card-view.tsx +11 -7
- package/src/components/checkout/checkout-flow.tsx +4 -1
- package/src/components/checkout/checkout-steps.tsx +3 -1
- package/src/components/checkout/client-context.tsx +28 -16
- package/src/components/checkout/client.ts +43 -16
- package/src/components/checkout/copy-context.tsx +83 -0
- package/src/components/checkout/google-pay-button.tsx +19 -7
- package/src/components/checkout/method-picker.tsx +34 -10
- package/src/components/checkout/payer-summary.tsx +8 -6
- package/src/components/checkout/payment-error-panel.tsx +8 -5
- package/src/components/checkout/pix-view.tsx +16 -9
- package/src/components/checkout/providers/hosted-link.tsx +26 -16
- package/src/components/checkout/pt-BR.ts +27 -0
- package/src/components/checkout/screens-copy.ts +201 -0
- package/src/components/checkout/screens-pt-BR.ts +101 -0
- package/src/components/checkout/transport.ts +34 -8
- package/src/components/checkout/use-card-checkout.ts +13 -5
- package/src/components/checkout/use-checkout-controller.ts +5 -48
- package/src/components/checkout/view-copy.ts +13 -0
- package/src/components/checkout/wallet-pane.tsx +13 -8
- package/src/components/checkout-payment-copy.ts +88 -0
- package/src/components/checkout-payment-pt-BR.ts +50 -0
- package/src/components/checkout-payment-types.ts +25 -0
- package/src/components/checkout-payment-views.tsx +225 -0
- package/src/components/connection-state.ts +22 -10
- package/src/components/credential-rules.ts +8 -3
- package/src/components/platform/ConnectApplicationPanel.tsx +6 -2
- package/src/components/platform/ConnectEnvironmentCard.tsx +19 -15
- package/src/components/platform/HomologacaoGuideCard.tsx +23 -19
- package/src/components/platform/HomologacaoOutcomeCard.tsx +24 -16
- package/src/components/platform/PlatformHomologacao.tsx +12 -8
- package/src/components/settings-copy-context.tsx +50 -0
- package/src/components/settings-copy.ts +304 -0
- package/src/components/settings-pt-BR.ts +169 -0
- package/src/flows/copy.ts +12 -0
- package/src/flows/create-payment-flows.tsx +8 -1
- package/src/flows/runtime.tsx +12 -4
- package/src/flows/screens-vault.tsx +10 -10
- package/src/flows/types.ts +5 -2
- package/src/flows/use-add-card.ts +10 -5
- package/src/index.ts +63 -0
|
@@ -8,6 +8,7 @@ import type { MaskedProviderConfig, ProviderDescriptor } from '@12-apps/payments
|
|
|
8
8
|
import type { PaymentsSettingsClient } from '../client';
|
|
9
9
|
import { isConnected } from './connection-state';
|
|
10
10
|
import { ProbeAlert, ProbeChecklist, type VerifyProbe } from './CredentialFormAlerts';
|
|
11
|
+
import { usePaymentsSettingsCopy } from './settings-copy-context';
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
14
|
* "Testar conexão" for a store whose connection is a GRANT, not a form.
|
|
@@ -41,6 +42,7 @@ export function ConnectionProbe({
|
|
|
41
42
|
const [busy, setBusy] = useState(false);
|
|
42
43
|
const [error, setError] = useState<string | null>(null);
|
|
43
44
|
const [probe, setProbe] = useState<VerifyProbe | null>(null);
|
|
45
|
+
const copy = usePaymentsSettingsCopy().credentials;
|
|
44
46
|
if (!isConnected(config)) return null;
|
|
45
47
|
|
|
46
48
|
const verify = async () => {
|
|
@@ -69,7 +71,7 @@ export function ConnectionProbe({
|
|
|
69
71
|
onClick={() => void verify()}
|
|
70
72
|
sx={{ textTransform: 'none' }}
|
|
71
73
|
>
|
|
72
|
-
{busy ? <CircularProgress size={18} /> :
|
|
74
|
+
{busy ? <CircularProgress size={18} /> : copy.probeAction}
|
|
73
75
|
</Button>
|
|
74
76
|
{error ? <Alert severity="error">{error}</Alert> : null}
|
|
75
77
|
{probe ? <ProbeAlert probe={probe} busy={busy} onRetry={() => void verify()} /> : null}
|
|
@@ -8,6 +8,7 @@ import { CredentialField } from './CredentialFields';
|
|
|
8
8
|
import { saveLabel } from './credential-rules';
|
|
9
9
|
import { FormActions, ReverifyWarning } from './CredentialFormAlerts';
|
|
10
10
|
import type { CredentialFormState } from './ProviderCredentialForm';
|
|
11
|
+
import { usePaymentsSettingsCopy } from './settings-copy-context';
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
14
|
* The live inputs for the step still owed, plus the one button that commits
|
|
@@ -27,9 +28,10 @@ export function CredentialFields({
|
|
|
27
28
|
/** A real charge has landed through this connection — see `ReverifyWarning`. */
|
|
28
29
|
proven: boolean;
|
|
29
30
|
}) {
|
|
31
|
+
const copy = usePaymentsSettingsCopy().credentials;
|
|
30
32
|
return (
|
|
31
33
|
<Stack spacing={2}>
|
|
32
|
-
{proven ? <ReverifyWarning /> : null}
|
|
34
|
+
{proven ? <ReverifyWarning displayName={descriptor.displayName} /> : null}
|
|
33
35
|
{descriptor.credentialSchema.map((spec) => (
|
|
34
36
|
<CredentialField
|
|
35
37
|
key={spec.key}
|
|
@@ -46,7 +48,11 @@ export function CredentialFields({
|
|
|
46
48
|
))}
|
|
47
49
|
<FormActions
|
|
48
50
|
busy={form.busy}
|
|
49
|
-
label={saveLabel(descriptor, form.complete)}
|
|
51
|
+
label={saveLabel(copy, descriptor, form.complete)}
|
|
52
|
+
// The FACT, not the words. This bar used to read `label.includes(
|
|
53
|
+
// 'testar')` to decide which promise to print — which quietly made the
|
|
54
|
+
// sentence depend on how a host spelled its button (FUT-760).
|
|
55
|
+
willTest={form.complete}
|
|
50
56
|
disabled={form.nothingEdited || !form.valid}
|
|
51
57
|
onSave={form.requestSave}
|
|
52
58
|
/>
|
|
@@ -5,6 +5,8 @@ import { Box, Button, Stack, TextField, Typography } from '@mui/material';
|
|
|
5
5
|
import type { CredentialFieldSpec, MaskedFieldState } from '@12-apps/payments-backend';
|
|
6
6
|
|
|
7
7
|
import { LINKISH_SX, T } from './panel-tokens';
|
|
8
|
+
import { usePaymentsSettingsCopy } from './settings-copy-context';
|
|
9
|
+
import type { CredentialFormCopy } from './settings-copy';
|
|
8
10
|
|
|
9
11
|
/**
|
|
10
12
|
* The schema-driven credential inputs, and the one-line summary a finished
|
|
@@ -27,6 +29,7 @@ function secretPresentation(
|
|
|
27
29
|
state: MaskedFieldState | undefined,
|
|
28
30
|
value: string | undefined,
|
|
29
31
|
required: boolean,
|
|
32
|
+
copy: CredentialFormCopy,
|
|
30
33
|
): FieldPresentation {
|
|
31
34
|
const configured = state?.configured ?? false;
|
|
32
35
|
return {
|
|
@@ -34,7 +37,7 @@ function secretPresentation(
|
|
|
34
37
|
value: value ?? '',
|
|
35
38
|
required: required && !configured,
|
|
36
39
|
placeholder: configured ? (state?.hint ?? '') : undefined,
|
|
37
|
-
helperText: configured ?
|
|
40
|
+
helperText: configured ? copy.configuredKeepBlank : undefined,
|
|
38
41
|
};
|
|
39
42
|
}
|
|
40
43
|
|
|
@@ -42,8 +45,9 @@ function fieldPresentation(
|
|
|
42
45
|
spec: CredentialFieldSpec,
|
|
43
46
|
state: MaskedFieldState | undefined,
|
|
44
47
|
value: string | undefined,
|
|
48
|
+
copy: CredentialFormCopy,
|
|
45
49
|
): FieldPresentation {
|
|
46
|
-
if (spec.secret) return secretPresentation(state, value, spec.required);
|
|
50
|
+
if (spec.secret) return secretPresentation(state, value, spec.required, copy);
|
|
47
51
|
const configured = state?.configured ?? false;
|
|
48
52
|
return {
|
|
49
53
|
type: 'text',
|
|
@@ -83,7 +87,8 @@ interface CredentialFieldProps {
|
|
|
83
87
|
|
|
84
88
|
/** One schema-driven form field. Secrets are write-only: hint, never value. */
|
|
85
89
|
export function CredentialField({ spec, state, value, onChange, check }: CredentialFieldProps) {
|
|
86
|
-
const
|
|
90
|
+
const copy = usePaymentsSettingsCopy().credentials;
|
|
91
|
+
const presentation = fieldPresentation(spec, state, value, copy);
|
|
87
92
|
// Label ABOVE the box, not floating in it. Four credentials whose names are
|
|
88
93
|
// the only thing distinguishing them (`sk_`, `pk_`, `whsec_`, `acct_`) are
|
|
89
94
|
// read as a column, and a floating label disappears the moment a value is
|
|
@@ -103,7 +108,7 @@ export function CredentialField({ spec, state, value, onChange, check }: Credent
|
|
|
103
108
|
{spec.label}
|
|
104
109
|
{spec.advanced ? (
|
|
105
110
|
<Box component="span" sx={{ fontWeight: 500, color: T.ink4 }}>
|
|
106
|
-
{
|
|
111
|
+
{copy.advancedSuffix}
|
|
107
112
|
</Box>
|
|
108
113
|
) : null}
|
|
109
114
|
</Typography>
|
|
@@ -222,16 +227,18 @@ export function DoneRow({
|
|
|
222
227
|
value,
|
|
223
228
|
mono,
|
|
224
229
|
onEdit,
|
|
225
|
-
editLabel
|
|
230
|
+
editLabel,
|
|
226
231
|
testId,
|
|
227
232
|
}: {
|
|
228
233
|
label: string;
|
|
229
234
|
value: string;
|
|
230
235
|
mono?: boolean;
|
|
231
236
|
onEdit: () => void;
|
|
237
|
+
/** Defaults to the host's `changeAction` when the caller names none. */
|
|
232
238
|
editLabel?: string;
|
|
233
239
|
testId: string;
|
|
234
240
|
}) {
|
|
241
|
+
const copy = usePaymentsSettingsCopy().credentials;
|
|
235
242
|
return (
|
|
236
243
|
// Green, not grey: a finished step reads as an achievement at a glance, and
|
|
237
244
|
// the whole point of collapsing it is that the eye can skip it on the way to
|
|
@@ -263,7 +270,7 @@ export function DoneRow({
|
|
|
263
270
|
</Typography>
|
|
264
271
|
<Box sx={{ flexGrow: 1 }} />
|
|
265
272
|
<Button size="small" onClick={onEdit} data-testid={`${testId}-edit`} sx={LINKISH_SX}>
|
|
266
|
-
{editLabel}
|
|
273
|
+
{editLabel ?? copy.changeAction}
|
|
267
274
|
</Button>
|
|
268
275
|
</Stack>
|
|
269
276
|
);
|
|
@@ -4,8 +4,11 @@ import { Alert, Box, Button, CircularProgress, Stack, Typography } from '@mui/ma
|
|
|
4
4
|
|
|
5
5
|
import type { VerifiedProviderConfig } from '@12-apps/payments-backend';
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import { environmentLabels } from './EnvironmentTabs';
|
|
8
|
+
import type { CredentialFormCopy } from './settings-copy';
|
|
9
|
+
import { usePaymentsSettingsCopy } from './settings-copy-context';
|
|
8
10
|
import { BAR_MSG_SX, BAR_SX, BTN_PRIMARY_SX } from './panel-tokens';
|
|
11
|
+
import { richText } from './rich-text';
|
|
9
12
|
|
|
10
13
|
/**
|
|
11
14
|
* The credential step's alerts and its one button.
|
|
@@ -41,14 +44,13 @@ export function ProbeAlert({
|
|
|
41
44
|
onRetry: () => void;
|
|
42
45
|
}) {
|
|
43
46
|
if (probe.ok) return null;
|
|
44
|
-
const
|
|
47
|
+
const copy = usePaymentsSettingsCopy();
|
|
48
|
+
const where = environmentLabels(copy.environment)[probe.environment];
|
|
45
49
|
// The ADAPTER's sentence when it has one. Only it knows the provider's name,
|
|
46
50
|
// what that provider's own app calls this field and which screen states it —
|
|
47
51
|
// "confira as credenciais deste ambiente" is advice you can follow all
|
|
48
52
|
// afternoon without ever finding the value you were asked to check.
|
|
49
|
-
const message =
|
|
50
|
-
probe.message ??
|
|
51
|
-
`Não foi possível conectar em ${where}. Confira as credenciais deste ambiente.`;
|
|
53
|
+
const message = probe.message ?? copy.credentials.probeFailed(where);
|
|
52
54
|
|
|
53
55
|
// An outage is not a rejection. The credential is already SAVED and may well
|
|
54
56
|
// be perfect; nothing was learned about it. So it is amber rather than red,
|
|
@@ -69,7 +71,7 @@ export function ProbeAlert({
|
|
|
69
71
|
data-testid="payments-verify-retry"
|
|
70
72
|
sx={{ textTransform: 'none' }}
|
|
71
73
|
>
|
|
72
|
-
|
|
74
|
+
{copy.credentials.probeAction}
|
|
73
75
|
</Button>
|
|
74
76
|
) : undefined
|
|
75
77
|
}
|
|
@@ -94,11 +96,13 @@ const SCREEN_READER_ONLY = {
|
|
|
94
96
|
} as const;
|
|
95
97
|
|
|
96
98
|
/** How each verdict reads at a glance — the mark, and what it is called. */
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
99
|
+
function checkMarks(copy: CredentialFormCopy) {
|
|
100
|
+
return {
|
|
101
|
+
PASS: { mark: '✓', color: 'success.main', label: copy.checkPass },
|
|
102
|
+
FAIL: { mark: '✕', color: 'error.main', label: copy.checkFail },
|
|
103
|
+
UNCHECKED: { mark: '–', color: 'text.secondary', label: copy.uncheckable },
|
|
104
|
+
} as const;
|
|
105
|
+
}
|
|
102
106
|
|
|
103
107
|
/**
|
|
104
108
|
* What the probe established, credential by credential (FUT-796).
|
|
@@ -122,12 +126,13 @@ export function ProbeChecklist({
|
|
|
122
126
|
/** Keep only the verdicts this predicate accepts — see `ProviderForm`. */
|
|
123
127
|
only?: (key: string) => boolean;
|
|
124
128
|
}) {
|
|
129
|
+
const marks = checkMarks(usePaymentsSettingsCopy().credentials);
|
|
125
130
|
const shown = (probe.checks ?? []).filter((check) => only?.(check.key) ?? true);
|
|
126
131
|
if (shown.length === 0) return null;
|
|
127
132
|
return (
|
|
128
133
|
<Stack spacing={0.5} data-testid="payments-probe-checks">
|
|
129
134
|
{shown.map((check) => {
|
|
130
|
-
const { mark, color, label } =
|
|
135
|
+
const { mark, color, label } = marks[check.status];
|
|
131
136
|
return (
|
|
132
137
|
<Stack
|
|
133
138
|
key={check.key}
|
|
@@ -164,11 +169,11 @@ export function ProbeChecklist({
|
|
|
164
169
|
* correct and entirely invisible, and an owner who came to fix a typo deserves
|
|
165
170
|
* to learn it before typing rather than from a quiet storefront.
|
|
166
171
|
*/
|
|
167
|
-
export function ReverifyWarning() {
|
|
172
|
+
export function ReverifyWarning({ displayName }: { displayName: string }) {
|
|
173
|
+
const copy = usePaymentsSettingsCopy().credentials;
|
|
168
174
|
return (
|
|
169
175
|
<Alert severity="warning" data-testid="payments-reverify-warning">
|
|
170
|
-
|
|
171
|
-
e a loja <strong>para de receber</strong> por este provedor até que ela termine.
|
|
176
|
+
{richText(copy.reverifyWarning(displayName))}
|
|
172
177
|
</Alert>
|
|
173
178
|
);
|
|
174
179
|
}
|
|
@@ -187,23 +192,27 @@ export function ReverifyWarning() {
|
|
|
187
192
|
export function FormActions({
|
|
188
193
|
busy,
|
|
189
194
|
label,
|
|
195
|
+
willTest,
|
|
190
196
|
disabled,
|
|
191
197
|
onSave,
|
|
192
198
|
}: {
|
|
193
199
|
busy: string | null;
|
|
194
200
|
label: string;
|
|
201
|
+
/** Whether pressing save will also SEND the set to the provider. */
|
|
202
|
+
willTest: boolean;
|
|
195
203
|
disabled: boolean;
|
|
196
204
|
onSave: () => void;
|
|
197
205
|
}) {
|
|
198
206
|
// The bar states what pressing it costs, which is the half a verb cannot
|
|
199
207
|
// carry: a complete set is sent to the provider on save, and a partial one is
|
|
200
208
|
// only written down. The owner reads the promise and the button in one line.
|
|
209
|
+
const copy = usePaymentsSettingsCopy().credentials;
|
|
201
210
|
const message =
|
|
202
211
|
busy === 'verify'
|
|
203
|
-
?
|
|
204
|
-
:
|
|
205
|
-
?
|
|
206
|
-
:
|
|
212
|
+
? copy.probeRunning
|
|
213
|
+
: willTest
|
|
214
|
+
? copy.probeSaveNote
|
|
215
|
+
: copy.probeIncompleteNote;
|
|
207
216
|
|
|
208
217
|
return (
|
|
209
218
|
<Box sx={BAR_SX} data-testid="payments-form-bar">
|
|
@@ -5,12 +5,19 @@ import { Alert, Box, Tab, Tabs, Typography } from '@mui/material';
|
|
|
5
5
|
import type { PaymentEnvironment } from '@12-apps/payments-backend';
|
|
6
6
|
|
|
7
7
|
import { T } from './panel-tokens';
|
|
8
|
+
import type { EnvironmentCopy } from './settings-copy';
|
|
9
|
+
import { usePaymentsSettingsCopy } from './settings-copy-context';
|
|
8
10
|
|
|
9
|
-
/**
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
/**
|
|
12
|
+
* One environment's human name — the tabs and the probe result share it.
|
|
13
|
+
*
|
|
14
|
+
* Built from the host's pack rather than declared here (FUT-760): the names
|
|
15
|
+
* appear inside the probe's own failure sentence too, so one spelling has to
|
|
16
|
+
* serve both or the screen contradicts itself.
|
|
17
|
+
*/
|
|
18
|
+
export function environmentLabels(copy: EnvironmentCopy): Record<PaymentEnvironment, string> {
|
|
19
|
+
return { SANDBOX: copy.sandbox, PRODUCTION: copy.production };
|
|
20
|
+
}
|
|
14
21
|
|
|
15
22
|
/**
|
|
16
23
|
* Sentence case, because these are place names rather than shouted commands —
|
|
@@ -47,6 +54,7 @@ export function EnvironmentSelector({
|
|
|
47
54
|
environment: PaymentEnvironment;
|
|
48
55
|
onChange: (next: PaymentEnvironment) => void;
|
|
49
56
|
}) {
|
|
57
|
+
const copy = usePaymentsSettingsCopy().environment;
|
|
50
58
|
// A segmented control, not underlined tabs. Two options that CHANGE WHAT
|
|
51
59
|
// EVERY FIELD BELOW MEANS should look like a switch being thrown, and the
|
|
52
60
|
// label above says which switch — "Ambiente" alone reads as a page section.
|
|
@@ -55,12 +63,12 @@ export function EnvironmentSelector({
|
|
|
55
63
|
<Typography
|
|
56
64
|
sx={{ display: 'block', fontSize: '12px', fontWeight: 650, color: T.ink2, mb: '5px' }}
|
|
57
65
|
>
|
|
58
|
-
|
|
66
|
+
{copy.groupLabel}
|
|
59
67
|
</Typography>
|
|
60
68
|
<Tabs
|
|
61
69
|
value={environment}
|
|
62
70
|
onChange={(_, next: PaymentEnvironment) => onChange(next)}
|
|
63
|
-
aria-label=
|
|
71
|
+
aria-label={copy.groupLabel}
|
|
64
72
|
data-testid="payments-environment-tabs"
|
|
65
73
|
slotProps={{ indicator: { sx: { display: 'none' } } }}
|
|
66
74
|
sx={{
|
|
@@ -73,13 +81,13 @@ export function EnvironmentSelector({
|
|
|
73
81
|
}}
|
|
74
82
|
>
|
|
75
83
|
<Tab
|
|
76
|
-
label=
|
|
84
|
+
label={copy.sandbox}
|
|
77
85
|
value="SANDBOX"
|
|
78
86
|
data-testid="payments-environment-SANDBOX"
|
|
79
87
|
sx={TAB_SX}
|
|
80
88
|
/>
|
|
81
89
|
<Tab
|
|
82
|
-
label=
|
|
90
|
+
label={copy.production}
|
|
83
91
|
value="PRODUCTION"
|
|
84
92
|
data-testid="payments-environment-PRODUCTION"
|
|
85
93
|
sx={TAB_SX}
|
|
@@ -126,7 +134,9 @@ export function EnvironmentNotice({
|
|
|
126
134
|
*/
|
|
127
135
|
band?: boolean;
|
|
128
136
|
}) {
|
|
129
|
-
const
|
|
137
|
+
const copy = usePaymentsSettingsCopy().environment;
|
|
138
|
+
const elsewhere =
|
|
139
|
+
active !== null && active !== environment ? environmentLabels(copy)[active] : null;
|
|
130
140
|
const production = environment === 'PRODUCTION';
|
|
131
141
|
return (
|
|
132
142
|
<Alert
|
|
@@ -137,12 +147,10 @@ export function EnvironmentNotice({
|
|
|
137
147
|
sx={band ? { borderRadius: 0, py: 0.5, px: 3 } : { py: 0.5 }}
|
|
138
148
|
>
|
|
139
149
|
<strong>
|
|
140
|
-
{production ?
|
|
150
|
+
{production ? copy.productionMeaning : copy.sandboxMeaning}
|
|
141
151
|
</strong>{' '}
|
|
142
|
-
{production
|
|
143
|
-
|
|
144
|
-
: 'Nenhum valor sai ou entra de verdade.'}
|
|
145
|
-
{elsewhere ? ` Hoje a loja está usando ${elsewhere}.` : ''}
|
|
152
|
+
{production ? copy.productionConsequence : copy.sandboxConsequence}
|
|
153
|
+
{elsewhere ? copy.storeIsUsing(elsewhere) : ''}
|
|
146
154
|
</Alert>
|
|
147
155
|
);
|
|
148
156
|
}
|
|
@@ -8,6 +8,7 @@ import { LINKISH_SX } from './panel-tokens';
|
|
|
8
8
|
import { ProviderConnection } from './ProviderConnection';
|
|
9
9
|
import type { ActivePanelProps } from './ProviderPanel';
|
|
10
10
|
import { ProviderCard } from './ProviderPanel';
|
|
11
|
+
import { usePaymentsSettingsCopy } from './settings-copy-context';
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
14
|
* The OAuth branch of a provider's screen, and the switch between its two
|
|
@@ -108,6 +109,7 @@ export function OAuthPanel({
|
|
|
108
109
|
walkthrough: (path: 'oauth' | 'credentials') => ReactNode;
|
|
109
110
|
form: ReactNode;
|
|
110
111
|
}) {
|
|
112
|
+
const copy = usePaymentsSettingsCopy().oauth;
|
|
111
113
|
// Which path the owner is on. The disclosure is no longer just a container —
|
|
112
114
|
// opening it CHOOSES the credentials path, so the panel has to know.
|
|
113
115
|
const [manual, setManual] = useState(false);
|
|
@@ -119,10 +121,7 @@ export function OAuthPanel({
|
|
|
119
121
|
if (!prepareConnect) {
|
|
120
122
|
return (
|
|
121
123
|
<ProviderCard header={statusBar}>
|
|
122
|
-
<Alert severity="info">
|
|
123
|
-
Este provedor conecta por autorização, mas o botão de conexão não está disponível nesta
|
|
124
|
-
instalação. Você ainda pode conectar informando as credenciais manualmente.
|
|
125
|
-
</Alert>
|
|
124
|
+
<Alert severity="info">{copy.connectUnavailable}</Alert>
|
|
126
125
|
{form}
|
|
127
126
|
{probe}
|
|
128
127
|
{verification}
|
|
@@ -134,7 +133,7 @@ export function OAuthPanel({
|
|
|
134
133
|
<ProviderCard header={statusBar}>
|
|
135
134
|
{manual ? (
|
|
136
135
|
<PathSwitch
|
|
137
|
-
label=
|
|
136
|
+
label={copy.preferOAuth}
|
|
138
137
|
expanded={false}
|
|
139
138
|
onChange={() => setManual(false)}
|
|
140
139
|
testId="payments-oauth-fallback"
|
|
@@ -153,7 +152,7 @@ export function OAuthPanel({
|
|
|
153
152
|
{probe}
|
|
154
153
|
{descriptor.credentialSchema.length > 0 ? (
|
|
155
154
|
<PathSwitch
|
|
156
|
-
label=
|
|
155
|
+
label={copy.preferCredentials}
|
|
157
156
|
expanded={manual}
|
|
158
157
|
onChange={setManual}
|
|
159
158
|
testId="payments-manual-fallback"
|
|
@@ -21,6 +21,8 @@ import {
|
|
|
21
21
|
type ProviderChangeHandler,
|
|
22
22
|
} from './settings-state';
|
|
23
23
|
import { openSection, SetupGuideSection } from './SetupGuideSection';
|
|
24
|
+
import type { PaymentsSettingsCopy } from './settings-copy';
|
|
25
|
+
import { PaymentsSettingsCopyProvider } from './settings-copy-context';
|
|
24
26
|
|
|
25
27
|
/**
|
|
26
28
|
* Plug-and-play settings page for payment providers — the reusable
|
|
@@ -40,6 +42,15 @@ import { openSection, SetupGuideSection } from './SetupGuideSection';
|
|
|
40
42
|
*/
|
|
41
43
|
export interface PaymentProviderSettingsProps {
|
|
42
44
|
client: PaymentsSettingsClient;
|
|
45
|
+
/**
|
|
46
|
+
* Every sentence this surface renders (FUT-760).
|
|
47
|
+
*
|
|
48
|
+
* REQUIRED, with no default in the package: a default would be one product's
|
|
49
|
+
* Portuguese compiled into every other product's settings screen. Passed
|
|
50
|
+
* once, here, and read from context by the fifteen components below —
|
|
51
|
+
* `PT_BR_PAYMENTS_SETTINGS_COPY` reproduces today's wording verbatim.
|
|
52
|
+
*/
|
|
53
|
+
copy: PaymentsSettingsCopy;
|
|
43
54
|
/** Called after any state-changing action, e.g. to refresh host UI. */
|
|
44
55
|
onChanged?: (config: MaskedProviderConfig) => void;
|
|
45
56
|
/**
|
|
@@ -233,8 +244,34 @@ function ProviderScreen({ onBack, ...panel }: ProviderScreenProps) {
|
|
|
233
244
|
);
|
|
234
245
|
}
|
|
235
246
|
|
|
247
|
+
/**
|
|
248
|
+
* The walkthrough slot the panel renders, per the connection path it has open.
|
|
249
|
+
*
|
|
250
|
+
* Extracted for the size gate, and it reads better here anyway: the mount above
|
|
251
|
+
* is about resolving WHICH provider is open, and this is about what its
|
|
252
|
+
* walkthrough shows once one is.
|
|
253
|
+
*/
|
|
254
|
+
function guideSlot(
|
|
255
|
+
guide: ProviderSetupGuide | null,
|
|
256
|
+
ack: { confirmed: boolean; confirm: () => void; withdraw: () => void },
|
|
257
|
+
) {
|
|
258
|
+
return ({ path, ...slots }: Parameters<NonNullable<ProviderScreenProps['guide']>>[0]) => (
|
|
259
|
+
<SetupGuideSection
|
|
260
|
+
// Which walkthrough, per the path the panel has open. Only the SECTIONS
|
|
261
|
+
// differ; `blocked`/`hidden` at the call site stay computed from the base
|
|
262
|
+
// guide, which `credentialsPath` is required to mirror.
|
|
263
|
+
guide={guideForPath(guide, path)}
|
|
264
|
+
confirmed={ack.confirmed}
|
|
265
|
+
onConfirm={ack.confirm}
|
|
266
|
+
onReopen={ack.withdraw}
|
|
267
|
+
{...slots}
|
|
268
|
+
/>
|
|
269
|
+
);
|
|
270
|
+
}
|
|
271
|
+
|
|
236
272
|
export function PaymentProviderSettings({
|
|
237
273
|
client,
|
|
274
|
+
copy,
|
|
238
275
|
onChanged,
|
|
239
276
|
prepareConnect,
|
|
240
277
|
initialProvider = null,
|
|
@@ -268,10 +305,15 @@ export function PaymentProviderSettings({
|
|
|
268
305
|
if (!view) return <CircularProgress data-testid="payments-settings-loading" />;
|
|
269
306
|
|
|
270
307
|
if (!active) {
|
|
271
|
-
return
|
|
308
|
+
return (
|
|
309
|
+
<PaymentsSettingsCopyProvider copy={copy}>
|
|
310
|
+
<ProviderList view={view} client={client} reload={reload} onSelect={openProvider} />
|
|
311
|
+
</PaymentsSettingsCopyProvider>
|
|
312
|
+
);
|
|
272
313
|
}
|
|
273
314
|
|
|
274
315
|
return (
|
|
316
|
+
<PaymentsSettingsCopyProvider copy={copy}>
|
|
275
317
|
<ProviderScreen
|
|
276
318
|
descriptor={active}
|
|
277
319
|
config={activeConfig}
|
|
@@ -296,18 +338,8 @@ export function PaymentProviderSettings({
|
|
|
296
338
|
onVerified: () => void reload(),
|
|
297
339
|
onSetupIncomplete: ack.withdraw,
|
|
298
340
|
})}
|
|
299
|
-
guide={(
|
|
300
|
-
<SetupGuideSection
|
|
301
|
-
// Which walkthrough, per the path the panel has open. Only the
|
|
302
|
-
// SECTIONS differ; `blocked`/`hidden` above stay computed from the
|
|
303
|
-
// base guide, which `credentialsPath` is required to mirror.
|
|
304
|
-
guide={guideForPath(guide, path)}
|
|
305
|
-
confirmed={ack.confirmed}
|
|
306
|
-
onConfirm={ack.confirm}
|
|
307
|
-
onReopen={ack.withdraw}
|
|
308
|
-
{...slots}
|
|
309
|
-
/>
|
|
310
|
-
)}
|
|
341
|
+
guide={guideSlot(guide, ack)}
|
|
311
342
|
/>
|
|
343
|
+
</PaymentsSettingsCopyProvider>
|
|
312
344
|
);
|
|
313
345
|
}
|