@heyama/pay-react-native 1.0.0 → 1.0.2
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/checkout-core/hooks/use-checkout-controller.js +20 -20
- package/dist/checkout-core/hooks/use-checkout-timers.d.ts +6 -3
- package/dist/checkout-core/hooks/use-checkout-timers.js +6 -6
- package/dist/checkout-core/messages/en.d.ts +1 -0
- package/dist/checkout-core/messages/en.js +1 -0
- package/dist/checkout-core/messages/fr.js +1 -0
- package/dist/checkout-core/models/checkout.enum.d.ts +9 -1
- package/dist/checkout-core/models/checkout.enum.js +9 -0
- package/dist/checkout-core/models/checkout.interface.d.ts +9 -2
- package/dist/components/PaymentSheetModal.js +6 -1
- package/dist/components/SheetChosenMethod.d.ts +3 -0
- package/dist/components/SheetChosenMethod.js +60 -0
- package/dist/components/SheetCodeField.js +3 -1
- package/dist/components/SheetContent.js +1 -1
- package/dist/components/SheetFailed.js +2 -2
- package/dist/components/SheetForm.d.ts +2 -1
- package/dist/components/SheetForm.js +4 -3
- package/dist/components/SheetIcon.js +9 -2
- package/dist/components/SheetLayout.d.ts +5 -4
- package/dist/components/SheetLayout.js +22 -9
- package/dist/components/SheetMessage.js +1 -1
- package/dist/components/SheetMethodCard.d.ts +2 -2
- package/dist/components/SheetMethodCard.js +5 -12
- package/dist/components/SheetPhoneField.js +4 -2
- package/dist/components/SheetSimulator.js +1 -1
- package/dist/components/SheetSuccess.js +1 -1
- package/dist/components/SheetText.d.ts +2 -2
- package/dist/components/SheetText.js +4 -2
- package/dist/components/SheetToast.d.ts +6 -2
- package/dist/components/SheetToast.js +58 -11
- package/dist/components/SheetWaiting.js +1 -1
- package/dist/models/sheet.constants.d.ts +2 -0
- package/dist/models/sheet.constants.js +2 -0
- package/dist/models/sheet.interface.d.ts +12 -3
- package/package.json +1 -1
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
2
2
|
import { useFormatter, useTranslations } from 'use-intl';
|
|
3
3
|
import { COPIED_MS, FLOW_TRAITS, OTP_MAX_LENGTH, OTP_PATTERN, } from "../models/checkout.constants.js";
|
|
4
|
-
import { CardFieldsMessageEnum, CheckoutScreenEnum, CheckoutTabEnum, MethodFlowEnum, MethodStateEnum, PayRefusalEnum, } from "../models/checkout.enum.js";
|
|
4
|
+
import { CardFieldsMessageEnum, CheckoutScreenEnum, CheckoutTabEnum, CheckoutToastToneEnum, MethodFlowEnum, MethodStateEnum, PayRefusalEnum, } from "../models/checkout.enum.js";
|
|
5
5
|
import { CountryEnum } from "../models/domain.enum.js";
|
|
6
6
|
import { cardLabel } from "../models/checkout.card.utils.js";
|
|
7
7
|
import { formatMoney } from "../models/checkout.money.utils.js";
|
|
8
8
|
import { maskE164 } from "../models/checkout.phone.utils.js";
|
|
9
|
-
import { countriesOf, deriveCheckout, initialUi, screenOf, waitLeftOf, } from "../models/checkout.view.utils.js";
|
|
9
|
+
import { countriesOf, deriveCheckout, initialUi, logoOf, screenOf, waitLeftOf, } from "../models/checkout.view.utils.js";
|
|
10
10
|
import { useNow, useReturnCountdown, useToast } from "./use-checkout-timers.js";
|
|
11
11
|
import { usePhoneNumber } from "./use-phone-number.js";
|
|
12
12
|
/** Before the payment has loaded, or for a link that matches none. */
|
|
@@ -84,7 +84,7 @@ export function useCheckoutController(view, { clues, mutations, platform }) {
|
|
|
84
84
|
if (!waiting || waitLeft > 0)
|
|
85
85
|
return;
|
|
86
86
|
update({ dismissed: attemptReference });
|
|
87
|
-
showToast(noAnswer);
|
|
87
|
+
showToast(noAnswer, CheckoutToastToneEnum.WARNING);
|
|
88
88
|
}, [waiting, waitLeft, attemptReference, noAnswer, showToast, update]);
|
|
89
89
|
const paymentId = view?.id;
|
|
90
90
|
// A payer opened the link, said once per page (the dashboard's preview has no mutations).
|
|
@@ -131,7 +131,7 @@ export function useCheckoutController(view, { clues, mutations, platform }) {
|
|
|
131
131
|
break;
|
|
132
132
|
case CardFieldsMessageEnum.REFUSED:
|
|
133
133
|
update({ cardPaying: false });
|
|
134
|
-
showToast(message.reason ? refusals(message.reason) : failedToast);
|
|
134
|
+
showToast(message.reason ? refusals(message.reason) : failedToast, CheckoutToastToneEnum.WARNING);
|
|
135
135
|
break;
|
|
136
136
|
}
|
|
137
137
|
};
|
|
@@ -139,7 +139,7 @@ export function useCheckoutController(view, { clues, mutations, platform }) {
|
|
|
139
139
|
}, [update, showToast, refusals, failedToast, platform]);
|
|
140
140
|
/* ---------------------------------------------------------- helpers */
|
|
141
141
|
const reference = attempt?.reference ?? view?.id ?? '';
|
|
142
|
-
const comingSoon = (name) => toast.show(t('toast.soon', { method: name }));
|
|
142
|
+
const comingSoon = (name) => toast.show(t('toast.soon', { method: name }), CheckoutToastToneEnum.INFO);
|
|
143
143
|
/**
|
|
144
144
|
* Starts an attempt with the number, and the payment code of an OTP
|
|
145
145
|
* method; a second tap while one is on its way does nothing.
|
|
@@ -155,9 +155,9 @@ export function useCheckoutController(view, { clues, mutations, platform }) {
|
|
|
155
155
|
: mutations.payWithCode({ ...args, otp }))
|
|
156
156
|
.then((result) => {
|
|
157
157
|
if (!result.ok)
|
|
158
|
-
toast.show(t(`refusals.${result.reason}`));
|
|
158
|
+
toast.show(t(`refusals.${result.reason}`), CheckoutToastToneEnum.WARNING);
|
|
159
159
|
})
|
|
160
|
-
.catch(() => toast.show(t('toast.failed')))
|
|
160
|
+
.catch(() => toast.show(t('toast.failed'), CheckoutToastToneEnum.WARNING))
|
|
161
161
|
.finally(() => {
|
|
162
162
|
paying.current = false;
|
|
163
163
|
update({ submitting: false });
|
|
@@ -188,7 +188,7 @@ export function useCheckoutController(view, { clues, mutations, platform }) {
|
|
|
188
188
|
comingSoon(method.name);
|
|
189
189
|
}
|
|
190
190
|
else if (method.state === MethodStateEnum.MAINTENANCE) {
|
|
191
|
-
toast.show(method.note ?? t('toast.unavailable', { method: method.name }));
|
|
191
|
+
toast.show(method.note ?? t('toast.unavailable', { method: method.name }), CheckoutToastToneEnum.WARNING, logoOf(method));
|
|
192
192
|
}
|
|
193
193
|
else {
|
|
194
194
|
update({
|
|
@@ -205,7 +205,7 @@ export function useCheckoutController(view, { clues, mutations, platform }) {
|
|
|
205
205
|
switchToDetected: () => {
|
|
206
206
|
const detected = derived.mismatch;
|
|
207
207
|
update({ method: detected.id });
|
|
208
|
-
toast.show(t('toast.switched', { method: detected.name }));
|
|
208
|
+
toast.show(t('toast.switched', { method: detected.name }), CheckoutToastToneEnum.SUCCESS, logoOf(detected));
|
|
209
209
|
},
|
|
210
210
|
pay: () => {
|
|
211
211
|
const { selected } = derived;
|
|
@@ -225,11 +225,11 @@ export function useCheckoutController(view, { clues, mutations, platform }) {
|
|
|
225
225
|
}
|
|
226
226
|
const otp = selected.flow === MethodFlowEnum.OTP;
|
|
227
227
|
if (otp && !OTP_PATTERN.test(ui.code)) {
|
|
228
|
-
toast.show(t(`refusals.${PayRefusalEnum.CODE}`));
|
|
228
|
+
toast.show(t(`refusals.${PayRefusalEnum.CODE}`), CheckoutToastToneEnum.WARNING);
|
|
229
229
|
return;
|
|
230
230
|
}
|
|
231
231
|
if (!mutations) {
|
|
232
|
-
toast.show(t('toast.preview'));
|
|
232
|
+
toast.show(t('toast.preview'), CheckoutToastToneEnum.INFO);
|
|
233
233
|
return;
|
|
234
234
|
}
|
|
235
235
|
submit(selected.id, {
|
|
@@ -240,7 +240,7 @@ export function useCheckoutController(view, { clues, mutations, platform }) {
|
|
|
240
240
|
// Only offered while an OTP method, which always has its code, is picked.
|
|
241
241
|
cannotDial: () => {
|
|
242
242
|
const method = derived.selected;
|
|
243
|
-
toast.show(t('toast.dial', { code: method.otpCode, method: method.name }));
|
|
243
|
+
toast.show(t('toast.dial', { code: method.otpCode, method: method.name }), CheckoutToastToneEnum.INFO, logoOf(method));
|
|
244
244
|
},
|
|
245
245
|
// Only on the failure screen, which the preview never shows.
|
|
246
246
|
retry: () => {
|
|
@@ -273,15 +273,15 @@ export function useCheckoutController(view, { clues, mutations, platform }) {
|
|
|
273
273
|
resend: () => {
|
|
274
274
|
void mutations
|
|
275
275
|
.resend({ paymentId: view.id })
|
|
276
|
-
.then((result) =>
|
|
277
|
-
? t('toast.resent', { phone: maskE164(attempt.phone) })
|
|
278
|
-
: t('toast.resend_wait')))
|
|
279
|
-
.catch(() => toast.show(t('toast.failed')));
|
|
276
|
+
.then((result) => result.ok
|
|
277
|
+
? toast.show(t('toast.resent', { phone: maskE164(attempt.phone) }), CheckoutToastToneEnum.SUCCESS)
|
|
278
|
+
: toast.show(t('toast.resend_wait'), CheckoutToastToneEnum.INFO))
|
|
279
|
+
.catch(() => toast.show(t('toast.failed'), CheckoutToastToneEnum.WARNING));
|
|
280
280
|
},
|
|
281
281
|
cancel: () => {
|
|
282
282
|
void mutations
|
|
283
283
|
.cancel({ paymentId: view.id })
|
|
284
|
-
.catch(() => toast.show(t('toast.failed')));
|
|
284
|
+
.catch(() => toast.show(t('toast.failed'), CheckoutToastToneEnum.WARNING));
|
|
285
285
|
},
|
|
286
286
|
returnNow: goBack,
|
|
287
287
|
stayHere: countdown.stop,
|
|
@@ -292,11 +292,11 @@ export function useCheckoutController(view, { clues, mutations, platform }) {
|
|
|
292
292
|
clearTimeout(copiedTimer.current);
|
|
293
293
|
setCopied(true);
|
|
294
294
|
copiedTimer.current = setTimeout(() => setCopied(false), COPIED_MS);
|
|
295
|
-
toast.show(t('toast.copied'));
|
|
295
|
+
toast.show(t('toast.copied'), CheckoutToastToneEnum.SUCCESS);
|
|
296
296
|
},
|
|
297
297
|
downloadReceipt: () => {
|
|
298
298
|
platform.saveReceipt(`receipt-${reference}.txt`, receiptText(view));
|
|
299
|
-
toast.show(t('toast.downloaded'));
|
|
299
|
+
toast.show(t('toast.downloaded'), CheckoutToastToneEnum.SUCCESS);
|
|
300
300
|
},
|
|
301
301
|
simulate: (outcome) => {
|
|
302
302
|
void mutations.simulate({ paymentId: view.id, outcome });
|
|
@@ -310,7 +310,7 @@ export function useCheckoutController(view, { clues, mutations, platform }) {
|
|
|
310
310
|
waitLeft,
|
|
311
311
|
returnLeft: countdown.left,
|
|
312
312
|
helpOpen,
|
|
313
|
-
|
|
313
|
+
toast: toast.toast,
|
|
314
314
|
copied,
|
|
315
315
|
preview: !mutations,
|
|
316
316
|
cardHeight,
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import type { CheckoutToastToneEnum } from '../models/checkout.enum.js';
|
|
2
|
+
import type { ProviderLogoEnum } from '../models/domain.enum.js';
|
|
3
|
+
import type { CheckoutToast } from '../models/checkout.interface.js';
|
|
1
4
|
/** The time now, moving once a second while `running`: the waiting screen's clock. */
|
|
2
5
|
export declare function useNow(running: boolean): number;
|
|
3
6
|
/**
|
|
@@ -8,8 +11,8 @@ export declare function useReturnCountdown(running: boolean, onDone: () => void)
|
|
|
8
11
|
left: number | null;
|
|
9
12
|
stop: () => void;
|
|
10
13
|
};
|
|
11
|
-
/** One short message at a time at the top of the page. */
|
|
14
|
+
/** One short message at a time at the top of the page, with its tone and the method it is about. */
|
|
12
15
|
export declare function useToast(): {
|
|
13
|
-
|
|
14
|
-
show: (
|
|
16
|
+
toast: CheckoutToast | null;
|
|
17
|
+
show: (message: string, tone: CheckoutToastToneEnum, logo?: ProviderLogoEnum | null) => void;
|
|
15
18
|
};
|
|
@@ -30,15 +30,15 @@ export function useReturnCountdown(running, onDone) {
|
|
|
30
30
|
}, [running, left, onDone]);
|
|
31
31
|
return { left, stop: () => setLeft(null) };
|
|
32
32
|
}
|
|
33
|
-
/** One short message at a time at the top of the page. */
|
|
33
|
+
/** One short message at a time at the top of the page, with its tone and the method it is about. */
|
|
34
34
|
export function useToast() {
|
|
35
|
-
const [
|
|
35
|
+
const [toast, setToast] = useState(null);
|
|
36
36
|
const timer = useRef(undefined);
|
|
37
37
|
useEffect(() => () => clearTimeout(timer.current), []);
|
|
38
|
-
const show = useCallback((
|
|
38
|
+
const show = useCallback((message, tone, logo = null) => {
|
|
39
39
|
clearTimeout(timer.current);
|
|
40
|
-
|
|
41
|
-
timer.current = setTimeout(() =>
|
|
40
|
+
setToast({ message, tone, logo });
|
|
41
|
+
timer.current = setTimeout(() => setToast(null), TOAST_MS);
|
|
42
42
|
}, []);
|
|
43
|
-
return {
|
|
43
|
+
return { toast, show };
|
|
44
44
|
}
|
|
@@ -217,6 +217,7 @@ export default {
|
|
|
217
217
|
method: 'This method is not available right now. Pick another one.',
|
|
218
218
|
phone: 'This number does not belong to this method’s country.',
|
|
219
219
|
code: 'Enter the payment code you generated.',
|
|
220
|
+
busy: 'Your earlier attempts are still in progress. Wait for their answer before trying again.',
|
|
220
221
|
},
|
|
221
222
|
toast: {
|
|
222
223
|
copied: 'Reference copied',
|
|
@@ -218,6 +218,7 @@ const messages = {
|
|
|
218
218
|
method: "Ce moyen n'est pas disponible pour le moment. Choisissez-en un autre.",
|
|
219
219
|
phone: "Ce numéro n'est pas du pays de ce moyen.",
|
|
220
220
|
code: 'Saisissez le code de paiement que vous avez généré.',
|
|
221
|
+
busy: 'Vos tentatives précédentes sont encore en cours. Attendez leur réponse avant de réessayer.',
|
|
221
222
|
},
|
|
222
223
|
toast: {
|
|
223
224
|
copied: 'Référence copiée',
|
|
@@ -55,7 +55,9 @@ export declare enum PayRefusalEnum {
|
|
|
55
55
|
METHOD = "method",
|
|
56
56
|
PHONE = "phone",
|
|
57
57
|
/** An OTP method came without a valid code. */
|
|
58
|
-
CODE = "code"
|
|
58
|
+
CODE = "code",
|
|
59
|
+
/** Earlier attempts still pending could use up the payment's tries. */
|
|
60
|
+
BUSY = "busy"
|
|
59
61
|
}
|
|
60
62
|
/**
|
|
61
63
|
* What a provider's card fields page and the checkout tell each other through
|
|
@@ -129,3 +131,9 @@ export declare enum CheckoutThemeEnum {
|
|
|
129
131
|
LIGHT = "light",
|
|
130
132
|
DARK = "dark"
|
|
131
133
|
}
|
|
134
|
+
/** What a toast says: done, a problem, or just good to know. Sets its icon. */
|
|
135
|
+
export declare enum CheckoutToastToneEnum {
|
|
136
|
+
SUCCESS = "success",
|
|
137
|
+
WARNING = "warning",
|
|
138
|
+
INFO = "info"
|
|
139
|
+
}
|
|
@@ -64,6 +64,8 @@ export var PayRefusalEnum;
|
|
|
64
64
|
PayRefusalEnum["PHONE"] = "phone";
|
|
65
65
|
/** An OTP method came without a valid code. */
|
|
66
66
|
PayRefusalEnum["CODE"] = "code";
|
|
67
|
+
/** Earlier attempts still pending could use up the payment's tries. */
|
|
68
|
+
PayRefusalEnum["BUSY"] = "busy";
|
|
67
69
|
})(PayRefusalEnum || (PayRefusalEnum = {}));
|
|
68
70
|
/**
|
|
69
71
|
* What a provider's card fields page and the checkout tell each other through
|
|
@@ -146,3 +148,10 @@ export var CheckoutThemeEnum;
|
|
|
146
148
|
CheckoutThemeEnum["LIGHT"] = "light";
|
|
147
149
|
CheckoutThemeEnum["DARK"] = "dark";
|
|
148
150
|
})(CheckoutThemeEnum || (CheckoutThemeEnum = {}));
|
|
151
|
+
/** What a toast says: done, a problem, or just good to know. Sets its icon. */
|
|
152
|
+
export var CheckoutToastToneEnum;
|
|
153
|
+
(function (CheckoutToastToneEnum) {
|
|
154
|
+
CheckoutToastToneEnum["SUCCESS"] = "success";
|
|
155
|
+
CheckoutToastToneEnum["WARNING"] = "warning";
|
|
156
|
+
CheckoutToastToneEnum["INFO"] = "info";
|
|
157
|
+
})(CheckoutToastToneEnum || (CheckoutToastToneEnum = {}));
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { CardFieldsMessageEnum, CheckoutPaymentStatusEnum, CheckoutScreenEnum, CheckoutTabEnum, CheckoutThemeEnum, MethodBrandEnum, MethodFlowEnum, MethodKindEnum, MethodStateEnum, PayRefusalEnum, PhoneErrorEnum, SimulatorOutcomeEnum, SupportChannelEnum } from './checkout.enum.js';
|
|
1
|
+
import type { CardFieldsMessageEnum, CheckoutPaymentStatusEnum, CheckoutToastToneEnum, CheckoutScreenEnum, CheckoutTabEnum, CheckoutThemeEnum, MethodBrandEnum, MethodFlowEnum, MethodKindEnum, MethodStateEnum, PayRefusalEnum, PhoneErrorEnum, SimulatorOutcomeEnum, SupportChannelEnum } from './checkout.enum.js';
|
|
2
2
|
import type { AttemptStatusEnum, CountryEnum, CurrencyEnum, FailureReasonEnum, LangEnum, ProviderLogoEnum } from './domain.enum.js';
|
|
3
3
|
export interface CheckoutApp {
|
|
4
4
|
name: string;
|
|
@@ -231,6 +231,13 @@ export interface CheckoutCoreActions {
|
|
|
231
231
|
simulate: (outcome: SimulatorOutcomeEnum) => void;
|
|
232
232
|
}
|
|
233
233
|
/** The checkout's state and actions, the same on the web page and in the payment sheet. */
|
|
234
|
+
/** One short message over the page. */
|
|
235
|
+
export interface CheckoutToast {
|
|
236
|
+
message: string;
|
|
237
|
+
tone: CheckoutToastToneEnum;
|
|
238
|
+
/** The method it is about, shown in place of the tone's icon. */
|
|
239
|
+
logo: ProviderLogoEnum | null;
|
|
240
|
+
}
|
|
234
241
|
export interface CheckoutCore {
|
|
235
242
|
/** Null for a link that matches no payment. */
|
|
236
243
|
view: CheckoutView | null;
|
|
@@ -242,7 +249,7 @@ export interface CheckoutCore {
|
|
|
242
249
|
/** Seconds before the success screen sends the payer back, null once stopped. */
|
|
243
250
|
returnLeft: number | null;
|
|
244
251
|
helpOpen: boolean;
|
|
245
|
-
|
|
252
|
+
toast: CheckoutToast | null;
|
|
246
253
|
copied: boolean;
|
|
247
254
|
/** The Branding tab's preview: nothing can be paid. */
|
|
248
255
|
preview: boolean;
|
|
@@ -60,7 +60,10 @@ export function PaymentSheetModal({ calls, request, onClose, }) {
|
|
|
60
60
|
] }) }), _jsx(Animated.View, { style: [
|
|
61
61
|
styles.stage,
|
|
62
62
|
{ transform: [{ translateY: motion.translateY }] },
|
|
63
|
-
], children: _jsx(
|
|
63
|
+
], children: _jsx(View, { style: [styles.stage, { paddingTop: motion.topGap }], children: _jsxs(KeyboardAvoidingView, { behavior: "padding", style: styles.sheet, children: [_jsx(View, { testID: "payment-sheet-floor", style: [
|
|
64
|
+
styles.floor,
|
|
65
|
+
{ backgroundColor: theme.colors.surface },
|
|
66
|
+
] }), _jsx(IntlProvider, { locale: lang, messages: MESSAGES[lang], timeZone: TIME_ZONE, children: _jsx(SheetThemeContext, { value: theme, children: _jsx(SheetContent, { calls: calls, watched: watched, fontsReady: fontsLoaded || fontsError !== null, deviceLocale: deviceLocale, onClose: close, dragHandlers: motion.dragHandlers }) }) })] }) }) })] }) }));
|
|
64
67
|
}
|
|
65
68
|
const styles = StyleSheet.create({
|
|
66
69
|
screen: { flex: 1 },
|
|
@@ -69,4 +72,6 @@ const styles = StyleSheet.create({
|
|
|
69
72
|
// The app's dim shows through around the sheet.
|
|
70
73
|
stage: { flex: 1, justifyContent: 'flex-end', pointerEvents: 'box-none' },
|
|
71
74
|
sheet: { flexShrink: 1 },
|
|
75
|
+
// Under the sheet's rounded top, down to the screen's bottom.
|
|
76
|
+
floor: { position: 'absolute', top: 14, right: 0, bottom: 0, left: 0 },
|
|
72
77
|
});
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { ChosenMethodProps } from '../models/sheet.interface.js';
|
|
2
|
+
/** The method picked, on one row, with Change back to the list: as on the web checkout. */
|
|
3
|
+
export declare function SheetChosenMethod({ logo, name, sub, onChange, }: ChosenMethodProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { StyleSheet, TouchableOpacity, View } from 'react-native';
|
|
3
|
+
import { useTranslations } from 'use-intl';
|
|
4
|
+
import { LOGO_SIZE } from "../checkout-core/models/checkout.constants.js";
|
|
5
|
+
import { useSheetTheme } from "../hooks/use-sheet-theme.js";
|
|
6
|
+
import { FigtreeEnum } from "../models/sheet.enum.js";
|
|
7
|
+
import { SheetLogo } from "./SheetLogo.js";
|
|
8
|
+
import { SheetText } from "./SheetText.js";
|
|
9
|
+
/** The method picked, on one row, with Change back to the list: as on the web checkout. */
|
|
10
|
+
export function SheetChosenMethod({ logo, name, sub, onChange, }) {
|
|
11
|
+
const t = useTranslations('checkout');
|
|
12
|
+
const { colors, brand } = useSheetTheme();
|
|
13
|
+
return (_jsxs(View, { testID: "chosen-method", style: [
|
|
14
|
+
styles.row,
|
|
15
|
+
{ borderColor: colors.line2, backgroundColor: colors.surface },
|
|
16
|
+
], children: [_jsxs(View, { children: [_jsx(SheetLogo, { logo: logo, size: LOGO_SIZE.ROW }), _jsx(View, { style: [
|
|
17
|
+
styles.badge,
|
|
18
|
+
{ borderColor: colors.surface, backgroundColor: brand },
|
|
19
|
+
], children: _jsx(View, { style: styles.check }) })] }), _jsxs(View, { style: styles.text, children: [_jsx(SheetText, { weight: FigtreeEnum.SEMI_BOLD, size: 14, numberOfLines: 1, children: name }), _jsx(SheetText, { size: 12, color: colors.muted, numberOfLines: 1, children: sub })] }), _jsx(TouchableOpacity, { onPress: onChange, activeOpacity: 0.7, accessibilityRole: "button", accessibilityLabel: t('change'), hitSlop: 6, style: styles.change, children: _jsx(SheetText, { weight: FigtreeEnum.BOLD, size: 12, color: brand, children: t('change') }) })] }));
|
|
20
|
+
}
|
|
21
|
+
const styles = StyleSheet.create({
|
|
22
|
+
row: {
|
|
23
|
+
flexDirection: 'row',
|
|
24
|
+
alignItems: 'center',
|
|
25
|
+
gap: 12,
|
|
26
|
+
height: 48,
|
|
27
|
+
marginTop: 12,
|
|
28
|
+
borderWidth: 1,
|
|
29
|
+
borderRadius: 12,
|
|
30
|
+
paddingLeft: 8,
|
|
31
|
+
paddingRight: 6,
|
|
32
|
+
},
|
|
33
|
+
badge: {
|
|
34
|
+
position: 'absolute',
|
|
35
|
+
right: -4,
|
|
36
|
+
bottom: -4,
|
|
37
|
+
width: 16,
|
|
38
|
+
height: 16,
|
|
39
|
+
alignItems: 'center',
|
|
40
|
+
justifyContent: 'center',
|
|
41
|
+
borderWidth: 2,
|
|
42
|
+
borderRadius: 8,
|
|
43
|
+
},
|
|
44
|
+
check: {
|
|
45
|
+
width: 3.5,
|
|
46
|
+
height: 6.5,
|
|
47
|
+
marginTop: -1,
|
|
48
|
+
borderColor: 'white',
|
|
49
|
+
borderRightWidth: 1.6,
|
|
50
|
+
borderBottomWidth: 1.6,
|
|
51
|
+
transform: [{ rotate: '45deg' }],
|
|
52
|
+
},
|
|
53
|
+
text: { flex: 1, minWidth: 0 },
|
|
54
|
+
change: {
|
|
55
|
+
height: 32,
|
|
56
|
+
justifyContent: 'center',
|
|
57
|
+
borderRadius: 8,
|
|
58
|
+
paddingHorizontal: 10,
|
|
59
|
+
},
|
|
60
|
+
});
|
|
@@ -47,7 +47,9 @@ export function SheetCodeField({ core }) {
|
|
|
47
47
|
actions.cannotDial();
|
|
48
48
|
});
|
|
49
49
|
};
|
|
50
|
-
return (_jsxs(View, { style: styles.section, children: [_jsx(SheetText, { weight: FigtreeEnum.BOLD, style: styles.label, children: t('otp_label') }), _jsx(SheetInput, { ref: field, accessibilityLabel: t('otp_label'), keyboardType: "number-pad", textContentType: "oneTimeCode", autoComplete: "sms-otp",
|
|
50
|
+
return (_jsxs(View, { style: styles.section, children: [_jsx(SheetText, { weight: FigtreeEnum.BOLD, style: styles.label, children: t('otp_label') }), _jsx(SheetInput, { ref: field, accessibilityLabel: t('otp_label'), keyboardType: "number-pad", textContentType: "oneTimeCode", autoComplete: "sms-otp",
|
|
51
|
+
// iOS's number keypads have no Go key: asking for one adds a bar above them.
|
|
52
|
+
returnKeyType: Platform.OS === 'android' ? 'go' : undefined, maxLength: OTP_MAX_LENGTH, value: ui.code, onChangeText: actions.setCode, onFocus: () => setFocused(true), onBlur: () => setFocused(false), onSubmitEditing: actions.pay, editable: !ui.submitting, style: [styles.input, { borderColor: focused ? brand : colors.line3 }] }), _jsxs(View, { style: [styles.help, { backgroundColor: colors.fill2 }], children: [_jsx(SheetText, { paragraph: true, size: 13, color: colors.ink2, style: styles.grow, children: t('otp_help', { method: method.name }) }), _jsxs(TouchableOpacity, { onPress: dial, activeOpacity: 0.7, accessibilityRole: "button", accessibilityLabel: t('sheet.dial', { code }), style: [
|
|
51
53
|
styles.dial,
|
|
52
54
|
{ borderColor: colors.line3, backgroundColor: colors.surface },
|
|
53
55
|
], children: [_jsx(View, { style: [styles.phone, { borderColor: colors.ink }], children: _jsx(View, { style: [styles.speaker, { backgroundColor: colors.ink }] }) }), _jsx(SheetText, { weight: FigtreeEnum.BOLD, size: 14, children: code })] })] })] }));
|
|
@@ -93,7 +93,7 @@ export function SheetContent({ calls, watched, fontsReady, deviceLocale, onClose
|
|
|
93
93
|
currency: CURRENCY_LABEL[view.currency],
|
|
94
94
|
}), busy: busy, inactive: !canPay, onPress: actions.pay }), children: [_jsx(SheetSummary, { view: view }), _jsx(SheetForm, { core: core, phoneRef: phoneRef, cardFields: cardFields })] }));
|
|
95
95
|
}
|
|
96
|
-
return (_jsxs(View, { testID: "payment-sheet", accessibilityViewIsModal: true, onAccessibilityEscape: onClose, style: [styles.sheet, { backgroundColor: colors.surface }], children: [_jsx(SheetHeader, { view: view, loading: loading, onClose: onClose, dragHandlers: dragHandlers }), body, _jsx(SheetToast, {
|
|
96
|
+
return (_jsxs(View, { testID: "payment-sheet", accessibilityViewIsModal: true, onAccessibilityEscape: onClose, style: [styles.sheet, { backgroundColor: colors.surface }], children: [_jsx(SheetHeader, { view: view, loading: loading, onClose: onClose, dragHandlers: dragHandlers }), body, _jsx(SheetToast, { toast: core.toast })] }));
|
|
97
97
|
}
|
|
98
98
|
const styles = StyleSheet.create({
|
|
99
99
|
// As tall as its screen; past the room it has, the screen scrolls.
|
|
@@ -29,10 +29,10 @@ export function SheetFailed({ core }) {
|
|
|
29
29
|
? t('retry_code')
|
|
30
30
|
: t('retry'), busy: ui.submitting, onPress: actions.retry }), _jsx(SheetButton, { variant: CheckoutButtonVariantEnum.SECONDARY, label: suggestion
|
|
31
31
|
? t('try_with', { method: suggestion.name })
|
|
32
|
-
: t('use_another'), onPress: actions.useAnother })] }), children: _jsxs(View, { style: styles.failed, children: [_jsx(SheetIcon, { kind: SheetIconEnum.CROSS, color: colors.danger, background: colors.dangerSoft }), _jsx(SheetText, { weight: FigtreeEnum.BOLD, size: 22, accessibilityRole: "header", style: styles.title, children: t(`failure.${reason}.title`, values) }), _jsx(SheetText, { size: 15, color: colors.inkStrong, children: t(`failure.${reason}.body`, values) }), _jsx(SheetText, { color: colors.ink2, style: styles.next, children: t(`failure.${reason}.next`, values) }), _jsxs(View, { style: [styles.rows, { borderColor: colors.line }], children: [_jsx(SheetRow, { label: t('amount'), children: formatMoney(view.amount, view.currency) }), _jsxs(SheetRow, { label: t('method'), children: [_jsx(SheetLogo, { logo: logoOf(attempt) }), _jsx(SheetText, { weight: FigtreeEnum.SEMI_BOLD, children: attempt.methodName })] }), _jsx(SheetRow, { label: t('tries_left'), children: t('tries_value', {
|
|
32
|
+
: t('use_another'), onPress: actions.useAnother })] }), children: _jsxs(View, { style: styles.failed, children: [_jsx(SheetIcon, { kind: SheetIconEnum.CROSS, color: colors.danger, background: colors.dangerSoft }), _jsx(SheetText, { weight: FigtreeEnum.BOLD, size: 22, accessibilityRole: "header", style: styles.title, children: t(`failure.${reason}.title`, values) }), _jsx(SheetText, { paragraph: true, size: 15, color: colors.inkStrong, children: t(`failure.${reason}.body`, values) }), _jsx(SheetText, { paragraph: true, color: colors.ink2, style: styles.next, children: t(`failure.${reason}.next`, values) }), _jsxs(View, { style: [styles.rows, { borderColor: colors.line }], children: [_jsx(SheetRow, { label: t('amount'), children: formatMoney(view.amount, view.currency) }), _jsxs(SheetRow, { label: t('method'), children: [_jsx(SheetLogo, { logo: logoOf(attempt) }), _jsx(SheetText, { weight: FigtreeEnum.SEMI_BOLD, children: attempt.methodName })] }), _jsx(SheetRow, { label: t('tries_left'), children: t('tries_value', {
|
|
33
33
|
left: view.attemptsLeft,
|
|
34
34
|
max: view.maxAttempts,
|
|
35
|
-
}) })] }), reason !== FailureReasonEnum.MISMATCH && (_jsx(SheetText, { size: 13, color: colors.muted, style: styles.note, children: t('not_charged') }))] }) }));
|
|
35
|
+
}) })] }), reason !== FailureReasonEnum.MISMATCH && (_jsx(SheetText, { paragraph: true, size: 13, color: colors.muted, style: styles.note, children: t('not_charged') }))] }) }));
|
|
36
36
|
}
|
|
37
37
|
const styles = StyleSheet.create({
|
|
38
38
|
failed: { paddingHorizontal: 18, paddingTop: 28 },
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { SheetFormProps } from '../models/sheet.interface.js';
|
|
2
2
|
/**
|
|
3
3
|
* The form of design A: the country when there are several, the Mobile
|
|
4
|
-
* Money / Card tabs, the methods two by two
|
|
4
|
+
* Money / Card tabs, the methods two by two (the one picked on its own row),
|
|
5
|
+
* the number, the payment code
|
|
5
6
|
* of an OTP method, and a card's fields.
|
|
6
7
|
*/
|
|
7
8
|
export declare function SheetForm({ core, phoneRef, cardFields }: SheetFormProps): import("react").JSX.Element;
|
|
@@ -7,6 +7,7 @@ import { useSheetTheme } from "../hooks/use-sheet-theme.js";
|
|
|
7
7
|
import { FigtreeEnum } from "../models/sheet.enum.js";
|
|
8
8
|
import { flagOf } from "../models/sheet.utils.js";
|
|
9
9
|
import { SheetCardFields } from "./SheetCardFields.js";
|
|
10
|
+
import { SheetChosenMethod } from "./SheetChosenMethod.js";
|
|
10
11
|
import { SheetCodeField } from "./SheetCodeField.js";
|
|
11
12
|
import { SheetMethodCard } from "./SheetMethodCard.js";
|
|
12
13
|
import { SheetPhoneField } from "./SheetPhoneField.js";
|
|
@@ -21,7 +22,8 @@ function MethodGrid({ cards }) {
|
|
|
21
22
|
}
|
|
22
23
|
/**
|
|
23
24
|
* The form of design A: the country when there are several, the Mobile
|
|
24
|
-
* Money / Card tabs, the methods two by two
|
|
25
|
+
* Money / Card tabs, the methods two by two (the one picked on its own row),
|
|
26
|
+
* the number, the payment code
|
|
25
27
|
* of an OTP method, and a card's fields.
|
|
26
28
|
*/
|
|
27
29
|
export function SheetForm({ core, phoneRef, cardFields }) {
|
|
@@ -39,7 +41,6 @@ export function SheetForm({ core, phoneRef, cardFields }) {
|
|
|
39
41
|
logo: logoOf(method),
|
|
40
42
|
name: method.name,
|
|
41
43
|
sub: subOf(method),
|
|
42
|
-
checked: derived.selected?.id === method.id,
|
|
43
44
|
muted: method.state !== MethodStateEnum.AVAILABLE,
|
|
44
45
|
onSelect: () => actions.selectMethod(method),
|
|
45
46
|
});
|
|
@@ -60,7 +61,7 @@ export function SheetForm({ core, phoneRef, cardFields }) {
|
|
|
60
61
|
? { backgroundColor: colors.ink, borderColor: colors.ink }
|
|
61
62
|
: { borderColor: colors.line3 },
|
|
62
63
|
], children: [_jsx(SheetText, { size: 14, children: flagOf(country) }), _jsx(SheetText, { weight: FigtreeEnum.SEMI_BOLD, size: 13, color: on ? colors.surface : colors.ink, children: t(`countries.${country}`) })] }, country));
|
|
63
|
-
}) })), _jsxs(View, { accessibilityRole: "tablist", style: [styles.tabs, { backgroundColor: colors.fill }], children: [tab(CheckoutTabEnum.MOBILE_MONEY, t('tab_wallet')), tab(CheckoutTabEnum.CARD, t('card'))] }), _jsx(MethodGrid, { cards: cards }), !onCard && _jsx(SheetPhoneField, { core: core, phoneRef: phoneRef }), !onCard && derived.selected?.flow === MethodFlowEnum.OTP && (_jsx(SheetCodeField, { core: core })), onCard && derived.selected?.flow === MethodFlowEnum.CARD_FIELDS && (_jsx(SheetCardFields, { core: core, bridge: cardFields }))] }));
|
|
64
|
+
}) })), _jsxs(View, { accessibilityRole: "tablist", style: [styles.tabs, { backgroundColor: colors.fill }], children: [tab(CheckoutTabEnum.MOBILE_MONEY, t('tab_wallet')), tab(CheckoutTabEnum.CARD, t('card'))] }), derived.selected ? (_jsx(SheetChosenMethod, { logo: logoOf(derived.selected), name: derived.selected.name, sub: derived.selected.network, onChange: actions.openPicker })) : (_jsx(MethodGrid, { cards: cards })), !onCard && _jsx(SheetPhoneField, { core: core, phoneRef: phoneRef }), !onCard && derived.selected?.flow === MethodFlowEnum.OTP && (_jsx(SheetCodeField, { core: core })), onCard && derived.selected?.flow === MethodFlowEnum.CARD_FIELDS && (_jsx(SheetCardFields, { core: core, bridge: cardFields }))] }));
|
|
64
65
|
}
|
|
65
66
|
const styles = StyleSheet.create({
|
|
66
67
|
form: { paddingHorizontal: 18, paddingTop: 14, paddingBottom: 8 },
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { jsx as _jsx,
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { StyleSheet, View } from 'react-native';
|
|
3
3
|
import { SheetIconEnum } from "../models/sheet.enum.js";
|
|
4
4
|
/** A sign in a disc, drawn with views: the sheet ships no icon font or SVG. */
|
|
@@ -12,7 +12,8 @@ export function SheetIcon({ kind, color, background, size = 48, }) {
|
|
|
12
12
|
sign = _jsx(View, { style: [styles.check, line] });
|
|
13
13
|
break;
|
|
14
14
|
case SheetIconEnum.CROSS:
|
|
15
|
-
|
|
15
|
+
// Crossed in a box of their own length: centred in the disc.
|
|
16
|
+
sign = (_jsxs(View, { style: styles.cross, children: [_jsx(View, { style: [styles.bar, styles.up, ink] }), _jsx(View, { style: [styles.bar, styles.down, ink] })] }));
|
|
16
17
|
break;
|
|
17
18
|
case SheetIconEnum.CLOCK:
|
|
18
19
|
sign = (_jsxs(View, { style: [styles.ring, line], children: [_jsx(View, { style: [styles.hour, ink] }), _jsx(View, { style: [styles.minute, ink] })] }));
|
|
@@ -43,6 +44,12 @@ const styles = StyleSheet.create({
|
|
|
43
44
|
borderBottomWidth: 3,
|
|
44
45
|
transform: [{ rotate: '45deg' }],
|
|
45
46
|
},
|
|
47
|
+
cross: {
|
|
48
|
+
width: 18,
|
|
49
|
+
height: 18,
|
|
50
|
+
alignItems: 'center',
|
|
51
|
+
justifyContent: 'center',
|
|
52
|
+
},
|
|
46
53
|
bar: { position: 'absolute', width: 18, height: 2.6, borderRadius: 1.3 },
|
|
47
54
|
up: { transform: [{ rotate: '45deg' }] },
|
|
48
55
|
down: { transform: [{ rotate: '-45deg' }] },
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import type { SheetLayoutProps } from '../models/sheet.interface.js';
|
|
2
2
|
/**
|
|
3
|
-
* What scrolls, then
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
3
|
+
* What scrolls, then "Payment secured by Brissoto Pay" over the actions
|
|
4
|
+
* pinned at the bottom, so Pay sits right on the keyboard. What scrolls is
|
|
5
|
+
* as tall as it is, until the sheet runs out of room. The keyboard pushes
|
|
6
|
+
* the actions up, without the room kept for the home bar: what scrolls
|
|
7
|
+
* follows to its end, where the number is.
|
|
7
8
|
*/
|
|
8
9
|
export declare function SheetLayout({ children, foot, secure, }: SheetLayoutProps): import("react").JSX.Element;
|
|
@@ -1,25 +1,37 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import { useEffect, useRef } from 'react';
|
|
3
|
-
import { Keyboard, ScrollView, StyleSheet, View } from 'react-native';
|
|
2
|
+
import { useEffect, useRef, useState } from 'react';
|
|
3
|
+
import { Keyboard, Platform, ScrollView, StyleSheet, View } from 'react-native';
|
|
4
4
|
import { useTranslations } from 'use-intl';
|
|
5
5
|
import { useSheetTheme } from "../hooks/use-sheet-theme.js";
|
|
6
6
|
import { FigtreeEnum } from "../models/sheet.enum.js";
|
|
7
7
|
import { SheetText } from "./SheetText.js";
|
|
8
8
|
/**
|
|
9
|
-
* What scrolls, then
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
9
|
+
* What scrolls, then "Payment secured by Brissoto Pay" over the actions
|
|
10
|
+
* pinned at the bottom, so Pay sits right on the keyboard. What scrolls is
|
|
11
|
+
* as tall as it is, until the sheet runs out of room. The keyboard pushes
|
|
12
|
+
* the actions up, without the room kept for the home bar: what scrolls
|
|
13
|
+
* follows to its end, where the number is.
|
|
13
14
|
*/
|
|
14
15
|
export function SheetLayout({ children, foot, secure = true, }) {
|
|
15
16
|
const t = useTranslations('checkout');
|
|
16
17
|
const { colors } = useSheetTheme();
|
|
17
18
|
const scroller = useRef(null);
|
|
19
|
+
const [keyboard, setKeyboard] = useState(false);
|
|
18
20
|
useEffect(() => {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
+
// iOS tells before the keyboard moves, Android only once it has.
|
|
22
|
+
const ios = Platform.OS === 'ios';
|
|
23
|
+
const listeners = [
|
|
24
|
+
Keyboard.addListener('keyboardDidShow', () => scroller.current?.scrollToEnd()),
|
|
25
|
+
Keyboard.addListener(ios ? 'keyboardWillShow' : 'keyboardDidShow', () => setKeyboard(true)),
|
|
26
|
+
Keyboard.addListener(ios ? 'keyboardWillHide' : 'keyboardDidHide', () => setKeyboard(false)),
|
|
27
|
+
];
|
|
28
|
+
return () => listeners.forEach((listener) => listener.remove());
|
|
21
29
|
}, []);
|
|
22
|
-
return (_jsxs(_Fragment, { children: [_jsx(ScrollView, { ref: scroller, style: styles.body, contentContainerStyle: styles.content, keyboardShouldPersistTaps: "handled", keyboardDismissMode: "interactive", children: children }), (foot || secure) && (_jsxs(View, {
|
|
30
|
+
return (_jsxs(_Fragment, { children: [_jsx(ScrollView, { ref: scroller, style: styles.body, contentContainerStyle: styles.content, keyboardShouldPersistTaps: "handled", keyboardDismissMode: "interactive", children: children }), (foot || secure) && (_jsxs(View, { testID: "sheet-foot", style: [
|
|
31
|
+
styles.foot,
|
|
32
|
+
keyboard && styles.footOnKeyboard,
|
|
33
|
+
{ borderColor: colors.line },
|
|
34
|
+
], children: [secure && (_jsxs(SheetText, { size: 11.5, color: colors.muted, style: styles.secure, children: [t('secured_by'), ' ', _jsx(SheetText, { weight: FigtreeEnum.BOLD, size: 11.5, children: "Brissoto Pay" })] })), foot] }))] }));
|
|
23
35
|
}
|
|
24
36
|
const styles = StyleSheet.create({
|
|
25
37
|
body: { flexGrow: 0, flexShrink: 1, marginTop: 6 },
|
|
@@ -31,5 +43,6 @@ const styles = StyleSheet.create({
|
|
|
31
43
|
paddingBottom: 28,
|
|
32
44
|
gap: 10,
|
|
33
45
|
},
|
|
46
|
+
footOnKeyboard: { paddingBottom: 12 },
|
|
34
47
|
secure: { textAlign: 'center' },
|
|
35
48
|
});
|
|
@@ -7,7 +7,7 @@ import { SheetText } from "./SheetText.js";
|
|
|
7
7
|
/** A dead end the payer cannot fix here: its sign, what happened and why. */
|
|
8
8
|
export function SheetMessage({ title, body, icon = SheetIconEnum.BAN, danger = false, }) {
|
|
9
9
|
const { colors } = useSheetTheme();
|
|
10
|
-
return (_jsxs(View, { style: styles.message, children: [_jsx(SheetIcon, { kind: icon, color: danger ? colors.danger : colors.ink2, background: danger ? colors.dangerSoft : colors.fill2 }), _jsx(SheetText, { weight: FigtreeEnum.BOLD, size: 22, accessibilityRole: "header", style: styles.title, children: title }), _jsx(SheetText, { size: 15, color: colors.inkStrong, children: body })] }));
|
|
10
|
+
return (_jsxs(View, { style: styles.message, children: [_jsx(SheetIcon, { kind: icon, color: danger ? colors.danger : colors.ink2, background: danger ? colors.dangerSoft : colors.fill2 }), _jsx(SheetText, { weight: FigtreeEnum.BOLD, size: 22, accessibilityRole: "header", style: styles.title, children: title }), _jsx(SheetText, { paragraph: true, size: 15, color: colors.inkStrong, children: body })] }));
|
|
11
11
|
}
|
|
12
12
|
const styles = StyleSheet.create({
|
|
13
13
|
message: { paddingHorizontal: 18, paddingTop: 28 },
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { MethodCardProps } from '../models/sheet.interface.js';
|
|
2
|
-
/** One method of the grid: logo and radio dot, then its name and network, or why it is greyed. */
|
|
3
|
-
export declare function SheetMethodCard({ logo, name, sub,
|
|
2
|
+
/** One method of the grid: logo and radio dot, then its name and network, or why it is greyed. Picked, it becomes the chosen row. */
|
|
3
|
+
export declare function SheetMethodCard({ logo, name, sub, muted, onSelect, }: MethodCardProps): import("react").JSX.Element;
|
|
@@ -5,19 +5,12 @@ import { useSheetTheme } from "../hooks/use-sheet-theme.js";
|
|
|
5
5
|
import { FigtreeEnum } from "../models/sheet.enum.js";
|
|
6
6
|
import { SheetLogo } from "./SheetLogo.js";
|
|
7
7
|
import { SheetText } from "./SheetText.js";
|
|
8
|
-
/** One method of the grid: logo and radio dot, then its name and network, or why it is greyed. */
|
|
9
|
-
export function SheetMethodCard({ logo, name, sub,
|
|
10
|
-
const { colors
|
|
11
|
-
return (_jsxs(TouchableOpacity, { onPress: onSelect, disabled: muted, activeOpacity: 0.7, accessibilityRole: "radio", accessibilityLabel: `${name}, ${sub}`, accessibilityState: { checked, disabled: muted }, style: [
|
|
12
|
-
styles.card,
|
|
13
|
-
checked
|
|
14
|
-
? { borderColor: brand, borderWidth: 2, padding: 11 }
|
|
15
|
-
: { borderColor: colors.line2 },
|
|
16
|
-
], children: [_jsxs(View, { style: styles.top, children: [_jsx(SheetLogo, { logo: logo, size: LOGO_SIZE.ROW, muted: muted }), _jsx(View, { style: [
|
|
8
|
+
/** One method of the grid: logo and radio dot, then its name and network, or why it is greyed. Picked, it becomes the chosen row. */
|
|
9
|
+
export function SheetMethodCard({ logo, name, sub, muted, onSelect, }) {
|
|
10
|
+
const { colors } = useSheetTheme();
|
|
11
|
+
return (_jsxs(TouchableOpacity, { onPress: onSelect, disabled: muted, activeOpacity: 0.7, accessibilityRole: "radio", accessibilityLabel: `${name}, ${sub}`, accessibilityState: { checked: false, disabled: muted }, style: [styles.card, { borderColor: colors.line2 }], children: [_jsxs(View, { style: styles.top, children: [_jsx(SheetLogo, { logo: logo, size: LOGO_SIZE.ROW, muted: muted }), _jsx(View, { style: [
|
|
17
12
|
styles.radio,
|
|
18
|
-
|
|
19
|
-
? { borderColor: brand, borderWidth: 6 }
|
|
20
|
-
: { borderColor: muted ? colors.line2 : colors.line4 },
|
|
13
|
+
{ borderColor: muted ? colors.line2 : colors.line4 },
|
|
21
14
|
] })] }), _jsx(SheetText, { weight: FigtreeEnum.BOLD, size: 15, numberOfLines: 1, color: muted ? colors.muted : colors.ink, children: name }), _jsx(SheetText, { size: 12.5, numberOfLines: 1, color: muted ? colors.warnInk : colors.muted, children: sub })] }));
|
|
22
15
|
}
|
|
23
16
|
const styles = StyleSheet.create({
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { Pressable, StyleSheet, View } from 'react-native';
|
|
2
|
+
import { Platform, Pressable, StyleSheet, View } from 'react-native';
|
|
3
3
|
import { useTranslations } from 'use-intl';
|
|
4
4
|
import { useSheetTheme } from "../hooks/use-sheet-theme.js";
|
|
5
5
|
import { FigtreeEnum } from "../models/sheet.enum.js";
|
|
@@ -22,7 +22,9 @@ export function SheetPhoneField({ core, phoneRef }) {
|
|
|
22
22
|
? brand
|
|
23
23
|
: colors.line3,
|
|
24
24
|
},
|
|
25
|
-
], children: [_jsxs(View, { style: [styles.dial, { borderColor: colors.line2 }], children: [_jsx(SheetText, { size: 16, children: flagOf(ui.country) }), _jsx(SheetText, { weight: FigtreeEnum.SEMI_BOLD, size: 16, children: `+${phone.dial}` })] }), _jsx(SheetInput, { ref: phoneRef, accessibilityLabel: t('phone_label'), keyboardType: "phone-pad", textContentType: "telephoneNumber", autoComplete: "tel",
|
|
25
|
+
], children: [_jsxs(View, { style: [styles.dial, { borderColor: colors.line2 }], children: [_jsx(SheetText, { size: 16, children: flagOf(ui.country) }), _jsx(SheetText, { weight: FigtreeEnum.SEMI_BOLD, size: 16, children: `+${phone.dial}` })] }), _jsx(SheetInput, { ref: phoneRef, accessibilityLabel: t('phone_label'), keyboardType: "phone-pad", textContentType: "telephoneNumber", autoComplete: "tel",
|
|
26
|
+
// iOS's number keypads have no Go key: asking for one adds a bar above them.
|
|
27
|
+
returnKeyType: Platform.OS === 'android' ? 'go' : undefined, placeholder: phone.placeholder, value: phone.value, onChangeText: (text) => void phone.type(text, text.length), onFocus: phone.onFocus, onBlur: phone.onBlur, onSubmitEditing: actions.pay, editable: !ui.submitting, style: styles.input })] }), _jsx(View, { accessibilityLiveRegion: "polite", style: styles.message, children: error ? (_jsx(SheetText, { paragraph: true, weight: FigtreeEnum.MEDIUM, size: 13, color: colors.danger, children: t(`phone_errors.${error}`) })) : mismatch ? (_jsxs(View, { style: styles.mismatch, children: [_jsx(SheetLogo, { logo: mismatch.logos[0] }), _jsx(SheetText, { paragraph: true, size: 13, color: colors.ink2, style: styles.grow, children: t('mismatch', { method: mismatch.name }) }), _jsx(Pressable, { onPress: actions.switchToDetected, accessibilityRole: "button", hitSlop: 6, style: [styles.switch, { borderColor: colors.line3 }], children: _jsx(SheetText, { weight: FigtreeEnum.SEMI_BOLD, size: 13, children: t('switch_to') }) })] })) : (selected && (_jsx(SheetText, { paragraph: true, size: 13, color: colors.muted, children: t('helper', { method: selected.name }) }))) })] }));
|
|
26
28
|
}
|
|
27
29
|
const styles = StyleSheet.create({
|
|
28
30
|
section: { marginTop: 18 },
|
|
@@ -18,7 +18,7 @@ export function SheetSimulator({ core }) {
|
|
|
18
18
|
return (_jsxs(View, { accessibilityLabel: t('simulator.title'), style: [
|
|
19
19
|
styles.panel,
|
|
20
20
|
{ backgroundColor: colors.warnSoft, borderColor: colors.warnLine },
|
|
21
|
-
], children: [_jsx(SheetText, { weight: FigtreeEnum.EXTRA_BOLD, size: 12, color: colors.warnInk2, style: styles.title, children: t('simulator.title') }), _jsxs(SheetText, { size: 13, color: colors.warnInk2, style: styles.body, children: [t('simulator.body'), traits.prompt &&
|
|
21
|
+
], children: [_jsx(SheetText, { weight: FigtreeEnum.EXTRA_BOLD, size: 12, color: colors.warnInk2, style: styles.title, children: t('simulator.title') }), _jsxs(SheetText, { paragraph: true, size: 13, color: colors.warnInk2, style: styles.body, children: [t('simulator.body'), traits.prompt &&
|
|
22
22
|
` ${t('simulator.no_answer', { suffix: SIMULATOR_NO_ANSWER_SUFFIX })}`] }), _jsx(View, { style: styles.outcomes, children: outcomes.map((outcome) => (_jsx(TouchableOpacity, { onPress: () => core.actions.simulate(outcome), activeOpacity: 0.7, accessibilityRole: "button", style: [
|
|
23
23
|
styles.outcome,
|
|
24
24
|
{ backgroundColor: colors.surface, borderColor: colors.warnLine },
|
|
@@ -26,7 +26,7 @@ export function SheetSuccess({ core, onClose }) {
|
|
|
26
26
|
// Nothing stops the countdown in the sheet: it always runs here.
|
|
27
27
|
, {
|
|
28
28
|
// Nothing stops the countdown in the sheet: it always runs here.
|
|
29
|
-
label: t('sheet.done_in', { seconds: returnLeft }), onPress: onClose }), children: _jsxs(View, { style: styles.success, children: [_jsx(View, { style: styles.icon, children: _jsx(SheetIcon, { kind: SheetIconEnum.CHECK, color: colors.surface, background: colors.successInk, size: 64 }) }), _jsx(SheetText, { weight: FigtreeEnum.EXTRA_BOLD, size: 22, accessibilityRole: "header", style: [styles.center, styles.title], children: t('success_title') }), _jsxs(View, { style: styles.amountRow, children: [_jsx(SheetText, { weight: FigtreeEnum.EXTRA_BOLD, size: 34, style: styles.amount, children: formatAmount(view.amount, view.currency) }), _jsx(SheetText, { weight: FigtreeEnum.SEMI_BOLD, size: 16, color: colors.ink2, children: CURRENCY_LABEL[view.currency] })] }), _jsx(SheetText, { color: colors.muted, style: styles.center, children: t('paid_to', { app: view.app.name }) }), _jsxs(View, { style: [styles.rows, { borderColor: colors.line }], children: [_jsxs(SheetRow, { label: t('method'), children: [_jsx(SheetLogo, { logo: logoOf(attempt) }), _jsx(SheetText, { weight: FigtreeEnum.SEMI_BOLD, children: attempt.methodName })] }), attempt.phone && (_jsx(SheetRow, { label: t('number'), children: maskE164(attempt.phone) })), attempt.card && (_jsx(SheetRow, { label: t('card'), children: cardLabel(attempt.card) })), _jsx(SheetRow, { label: t('date'), children: format.dateTime(view.paidAt, {
|
|
29
|
+
label: t('sheet.done_in', { seconds: returnLeft }), onPress: onClose }), children: _jsxs(View, { style: styles.success, children: [_jsx(View, { style: styles.icon, children: _jsx(SheetIcon, { kind: SheetIconEnum.CHECK, color: colors.surface, background: colors.successInk, size: 64 }) }), _jsx(SheetText, { weight: FigtreeEnum.EXTRA_BOLD, size: 22, accessibilityRole: "header", style: [styles.center, styles.title], children: t('success_title') }), _jsxs(View, { style: styles.amountRow, children: [_jsx(SheetText, { weight: FigtreeEnum.EXTRA_BOLD, size: 34, style: styles.amount, children: formatAmount(view.amount, view.currency) }), _jsx(SheetText, { weight: FigtreeEnum.SEMI_BOLD, size: 16, color: colors.ink2, children: CURRENCY_LABEL[view.currency] })] }), _jsx(SheetText, { paragraph: true, color: colors.muted, style: styles.center, children: t('paid_to', { app: view.app.name }) }), _jsxs(View, { style: [styles.rows, { borderColor: colors.line }], children: [_jsxs(SheetRow, { label: t('method'), children: [_jsx(SheetLogo, { logo: logoOf(attempt) }), _jsx(SheetText, { weight: FigtreeEnum.SEMI_BOLD, children: attempt.methodName })] }), attempt.phone && (_jsx(SheetRow, { label: t('number'), children: maskE164(attempt.phone) })), attempt.card && (_jsx(SheetRow, { label: t('card'), children: cardLabel(attempt.card) })), _jsx(SheetRow, { label: t('date'), children: format.dateTime(view.paidAt, {
|
|
30
30
|
day: 'numeric',
|
|
31
31
|
month: 'short',
|
|
32
32
|
year: 'numeric',
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { SheetInputProps, SheetTextProps } from '../models/sheet.interface.js';
|
|
2
|
-
/** Every text of the sheet: Figtree, in the sheet's ink unless told otherwise. */
|
|
3
|
-
export declare function SheetText({ weight, size, color, style, ...props }: SheetTextProps): import("react").JSX.Element;
|
|
2
|
+
/** Every text of the sheet: Figtree, in the sheet's ink unless told otherwise; a paragraph's lines spaced as on the web. */
|
|
3
|
+
export declare function SheetText({ weight, size, color, paragraph, style, ...props }: SheetTextProps): import("react").JSX.Element;
|
|
4
4
|
/** Every field of the sheet: Figtree at 16, so iOS never zooms, in the sheet's ink. */
|
|
5
5
|
export declare function SheetInput({ style, ...props }: SheetInputProps): import("react").JSX.Element;
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { Text, TextInput } from 'react-native';
|
|
3
3
|
import { useSheetTheme } from "../hooks/use-sheet-theme.js";
|
|
4
|
+
import { PARAGRAPH_LINE_HEIGHT } from "../models/sheet.constants.js";
|
|
4
5
|
import { FigtreeEnum } from "../models/sheet.enum.js";
|
|
5
|
-
/** Every text of the sheet: Figtree, in the sheet's ink unless told otherwise. */
|
|
6
|
-
export function SheetText({ weight = FigtreeEnum.REGULAR, size = 14, color, style, ...props }) {
|
|
6
|
+
/** Every text of the sheet: Figtree, in the sheet's ink unless told otherwise; a paragraph's lines spaced as on the web. */
|
|
7
|
+
export function SheetText({ weight = FigtreeEnum.REGULAR, size = 14, color, paragraph = false, style, ...props }) {
|
|
7
8
|
const { colors } = useSheetTheme();
|
|
8
9
|
return (_jsx(Text, { ...props, style: [
|
|
9
10
|
{ fontFamily: weight, fontSize: size, color: color ?? colors.ink },
|
|
11
|
+
paragraph && { lineHeight: Math.round(size * PARAGRAPH_LINE_HEIGHT) },
|
|
10
12
|
style,
|
|
11
13
|
] }));
|
|
12
14
|
}
|
|
@@ -1,3 +1,7 @@
|
|
|
1
1
|
import type { SheetToastProps } from '../models/sheet.interface.js';
|
|
2
|
-
/**
|
|
3
|
-
|
|
2
|
+
/**
|
|
3
|
+
* One short message at a time, in a small card at the top of the sheet:
|
|
4
|
+
* the method's logo, else the tone's disc (a check when done, "!" for a
|
|
5
|
+
* problem, "i" to know). As on the web checkout.
|
|
6
|
+
*/
|
|
7
|
+
export declare function SheetToast({ toast }: SheetToastProps): import("react").JSX.Element | null;
|
|
@@ -1,24 +1,71 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { StyleSheet, View } from 'react-native';
|
|
3
|
+
import { CheckoutToastToneEnum } from "../checkout-core/models/checkout.enum.js";
|
|
3
4
|
import { useSheetTheme } from "../hooks/use-sheet-theme.js";
|
|
4
5
|
import { FigtreeEnum } from "../models/sheet.enum.js";
|
|
6
|
+
import { SheetLogo } from "./SheetLogo.js";
|
|
5
7
|
import { SheetText } from "./SheetText.js";
|
|
6
|
-
/**
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
/**
|
|
9
|
+
* One short message at a time, in a small card at the top of the sheet:
|
|
10
|
+
* the method's logo, else the tone's disc (a check when done, "!" for a
|
|
11
|
+
* problem, "i" to know). As on the web checkout.
|
|
12
|
+
*/
|
|
13
|
+
export function SheetToast({ toast }) {
|
|
14
|
+
const { colors, dark } = useSheetTheme();
|
|
15
|
+
if (!toast)
|
|
10
16
|
return null;
|
|
11
|
-
|
|
17
|
+
const disc = {
|
|
18
|
+
[CheckoutToastToneEnum.SUCCESS]: colors.successInk,
|
|
19
|
+
[CheckoutToastToneEnum.WARNING]: colors.warnInk,
|
|
20
|
+
[CheckoutToastToneEnum.INFO]: colors.muted,
|
|
21
|
+
}[toast.tone];
|
|
22
|
+
return (_jsx(View, { pointerEvents: "none", style: styles.place, children: _jsxs(View, { testID: "sheet-toast", accessibilityLiveRegion: "polite", accessibilityRole: "alert", style: [
|
|
23
|
+
styles.toast,
|
|
24
|
+
{
|
|
25
|
+
backgroundColor: dark ? colors.fill3 : colors.surface,
|
|
26
|
+
borderColor: colors.line3,
|
|
27
|
+
},
|
|
28
|
+
], children: [toast.logo ? (_jsx(SheetLogo, { logo: toast.logo })) : (_jsx(View, { testID: `toast-${toast.tone}`, style: [styles.disc, { backgroundColor: disc }], children: toast.tone === CheckoutToastToneEnum.SUCCESS ? (_jsx(View, { style: styles.check })) : (_jsx(SheetText, { weight: FigtreeEnum.BOLD, size: 12, color: "white", style: styles.glyph, children: toast.tone === CheckoutToastToneEnum.WARNING ? '!' : 'i' })) })), _jsx(SheetText, { weight: FigtreeEnum.SEMI_BOLD, size: 13.5, style: styles.text, children: toast.message })] }) }));
|
|
12
29
|
}
|
|
13
30
|
const styles = StyleSheet.create({
|
|
14
|
-
|
|
31
|
+
place: {
|
|
15
32
|
position: 'absolute',
|
|
16
|
-
top:
|
|
33
|
+
top: 12,
|
|
17
34
|
left: 18,
|
|
18
35
|
right: 18,
|
|
36
|
+
alignItems: 'center',
|
|
37
|
+
},
|
|
38
|
+
toast: {
|
|
39
|
+
flexDirection: 'row',
|
|
40
|
+
alignItems: 'center',
|
|
41
|
+
gap: 10,
|
|
42
|
+
borderWidth: 1,
|
|
19
43
|
borderRadius: 12,
|
|
20
|
-
|
|
21
|
-
|
|
44
|
+
paddingVertical: 10,
|
|
45
|
+
paddingLeft: 12,
|
|
46
|
+
paddingRight: 16,
|
|
47
|
+
shadowColor: 'black',
|
|
48
|
+
shadowOpacity: 0.18,
|
|
49
|
+
shadowRadius: 16,
|
|
50
|
+
shadowOffset: { width: 0, height: 8 },
|
|
51
|
+
elevation: 6,
|
|
52
|
+
},
|
|
53
|
+
disc: {
|
|
54
|
+
width: 20,
|
|
55
|
+
height: 20,
|
|
56
|
+
borderRadius: 10,
|
|
57
|
+
alignItems: 'center',
|
|
58
|
+
justifyContent: 'center',
|
|
59
|
+
},
|
|
60
|
+
check: {
|
|
61
|
+
width: 5,
|
|
62
|
+
height: 9,
|
|
63
|
+
marginTop: -2,
|
|
64
|
+
borderColor: 'white',
|
|
65
|
+
borderRightWidth: 2,
|
|
66
|
+
borderBottomWidth: 2,
|
|
67
|
+
transform: [{ rotate: '45deg' }],
|
|
22
68
|
},
|
|
23
|
-
|
|
69
|
+
glyph: { lineHeight: 14, textAlign: 'center' },
|
|
70
|
+
text: { flexShrink: 1 },
|
|
24
71
|
});
|
|
@@ -39,7 +39,7 @@ export function SheetWaiting({ core }) {
|
|
|
39
39
|
: t('resend'), disabled: resendLeft > 0, onPress: () => {
|
|
40
40
|
setSentAt(WAIT_SECONDS - waitLeft);
|
|
41
41
|
actions.resend();
|
|
42
|
-
} })), _jsx(Pressable, { onPress: actions.useAnother, accessibilityRole: "button", style: styles.link, children: _jsx(SheetText, { weight: FigtreeEnum.SEMI_BOLD, style: styles.center, children: t('use_another') }) })] }), children: _jsxs(View, { style: styles.waiting, children: [_jsxs(View, { style: styles.pulse, children: [_jsx(View, { style: [styles.halo, styles.outer, { backgroundColor: brand }] }), _jsx(View, { style: [styles.halo, styles.inner, { backgroundColor: brand }] }), _jsx(View, { testID: "icon-phone", style: [styles.phone, { borderColor: brand }], children: _jsx(View, { style: [styles.speaker, { backgroundColor: brand }] }) })] }), _jsx(SheetText, { weight: FigtreeEnum.EXTRA_BOLD, size: 21, accessibilityRole: "header", style: [styles.center, styles.title], children: prompt ? t('sheet.approve_title') : t('checking_title') }), _jsx(SheetText, { size: 14, color: colors.muted, style: styles.center, children: attempt.phone
|
|
42
|
+
} })), _jsx(Pressable, { onPress: actions.useAnother, accessibilityRole: "button", style: styles.link, children: _jsx(SheetText, { weight: FigtreeEnum.SEMI_BOLD, style: styles.center, children: t('use_another') }) })] }), children: _jsxs(View, { style: styles.waiting, children: [_jsxs(View, { style: styles.pulse, children: [_jsx(View, { style: [styles.halo, styles.outer, { backgroundColor: brand }] }), _jsx(View, { style: [styles.halo, styles.inner, { backgroundColor: brand }] }), _jsx(View, { testID: "icon-phone", style: [styles.phone, { borderColor: brand }], children: _jsx(View, { style: [styles.speaker, { backgroundColor: brand }] }) })] }), _jsx(SheetText, { weight: FigtreeEnum.EXTRA_BOLD, size: 21, accessibilityRole: "header", style: [styles.center, styles.title], children: prompt ? t('sheet.approve_title') : t('checking_title') }), _jsx(SheetText, { paragraph: true, size: 14, color: colors.muted, style: styles.center, children: attempt.phone
|
|
43
43
|
? prompt
|
|
44
44
|
? t('sheet.approve_body', {
|
|
45
45
|
method: attempt.methodName,
|
|
@@ -37,3 +37,5 @@ export declare const SHEET_SWIPE_DISTANCE = 120;
|
|
|
37
37
|
export declare const SHEET_FLICK_SPEED = 0.8;
|
|
38
38
|
/** How the sheet's height eases from one screen to the next. */
|
|
39
39
|
export declare const SHEET_RESIZE: LayoutAnimationConfig;
|
|
40
|
+
/** A paragraph's line height, as a share of its size: the web checkout's 1.5, a touch tighter for Figtree on phones. */
|
|
41
|
+
export declare const PARAGRAPH_LINE_HEIGHT = 1.45;
|
|
@@ -76,3 +76,5 @@ export const SHEET_RESIZE = {
|
|
|
76
76
|
duration: 220,
|
|
77
77
|
update: { type: LayoutAnimation.Types.easeInEaseOut },
|
|
78
78
|
};
|
|
79
|
+
/** A paragraph's line height, as a share of its size: the web checkout's 1.5, a touch tighter for Figtree on phones. */
|
|
80
|
+
export const PARAGRAPH_LINE_HEIGHT = 1.45;
|
|
@@ -3,7 +3,7 @@ import type { Animated, DimensionValue, GestureResponderHandlers, StyleProp, Tex
|
|
|
3
3
|
import type { WebView } from 'react-native-webview';
|
|
4
4
|
import type { CheckoutButtonVariantEnum, TerminalKindEnum } from '../checkout-core/models/checkout.enum.js';
|
|
5
5
|
import type { LangEnum, ProviderLogoEnum } from '../checkout-core/models/domain.enum.js';
|
|
6
|
-
import type { CardFieldsMessage, CheckoutColors, CheckoutCore, CheckoutMutations, CheckoutPlatform, CheckoutView } from '../checkout-core/models/checkout.interface.js';
|
|
6
|
+
import type { CardFieldsMessage, CheckoutColors, CheckoutCore, CheckoutToast, CheckoutMutations, CheckoutPlatform, CheckoutView } from '../checkout-core/models/checkout.interface.js';
|
|
7
7
|
import type { FigtreeEnum, SheetIconEnum } from './sheet.enum.js';
|
|
8
8
|
/**
|
|
9
9
|
* How the sheet ended. `closed`: the payer closed it with the payment still
|
|
@@ -88,6 +88,8 @@ export interface SheetTextProps extends TextProps {
|
|
|
88
88
|
weight?: FigtreeEnum;
|
|
89
89
|
size?: number;
|
|
90
90
|
color?: string;
|
|
91
|
+
/** Text that may wrap: lines spaced as on the web checkout. */
|
|
92
|
+
paragraph?: boolean;
|
|
91
93
|
style?: StyleProp<TextStyle>;
|
|
92
94
|
}
|
|
93
95
|
export interface SheetHeaderProps {
|
|
@@ -175,11 +177,18 @@ export interface MethodCardProps {
|
|
|
175
177
|
logo: ProviderLogoEnum;
|
|
176
178
|
name: string;
|
|
177
179
|
sub: string;
|
|
178
|
-
checked: boolean;
|
|
179
180
|
/** Greyed and not pressable: in maintenance, or not offered yet. */
|
|
180
181
|
muted: boolean;
|
|
181
182
|
onSelect?: () => void;
|
|
182
183
|
}
|
|
184
|
+
export interface ChosenMethodProps {
|
|
185
|
+
logo: ProviderLogoEnum;
|
|
186
|
+
name: string;
|
|
187
|
+
/** Its network. */
|
|
188
|
+
sub: string;
|
|
189
|
+
/** Back to the list. */
|
|
190
|
+
onChange: () => void;
|
|
191
|
+
}
|
|
183
192
|
export interface MethodGridCard extends MethodCardProps {
|
|
184
193
|
id: string;
|
|
185
194
|
}
|
|
@@ -202,7 +211,7 @@ export interface SheetRowProps {
|
|
|
202
211
|
urgent?: boolean;
|
|
203
212
|
}
|
|
204
213
|
export interface SheetToastProps {
|
|
205
|
-
|
|
214
|
+
toast: CheckoutToast | null;
|
|
206
215
|
}
|
|
207
216
|
export interface BoneProps {
|
|
208
217
|
/** Points, or a share of the row (`100%`). */
|