@heyama/pay-react-native 0.0.0-stage → 1.0.1

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.
Files changed (122) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +99 -2
  3. package/assets/fonts/Figtree-Bold.ttf +0 -0
  4. package/assets/fonts/Figtree-ExtraBold.ttf +0 -0
  5. package/assets/fonts/Figtree-Medium.ttf +0 -0
  6. package/assets/fonts/Figtree-Regular.ttf +0 -0
  7. package/assets/fonts/Figtree-SemiBold.ttf +0 -0
  8. package/assets/fonts/OFL.txt +93 -0
  9. package/assets/logos/apple-pay.png +0 -0
  10. package/assets/logos/card.png +0 -0
  11. package/assets/logos/google-pay.png +0 -0
  12. package/assets/logos/mastercard.png +0 -0
  13. package/assets/logos/mixx.png +0 -0
  14. package/assets/logos/moov.png +0 -0
  15. package/assets/logos/mtn.png +0 -0
  16. package/assets/logos/orange.png +0 -0
  17. package/assets/logos/paypal.png +0 -0
  18. package/assets/logos/visa.png +0 -0
  19. package/assets/logos/wave.png +0 -0
  20. package/dist/checkout-core/hooks/use-checkout-controller.d.ts +9 -0
  21. package/dist/checkout-core/hooks/use-checkout-controller.js +319 -0
  22. package/dist/checkout-core/hooks/use-checkout-timers.d.ts +15 -0
  23. package/dist/checkout-core/hooks/use-checkout-timers.js +44 -0
  24. package/dist/checkout-core/hooks/use-phone-number.d.ts +7 -0
  25. package/dist/checkout-core/hooks/use-phone-number.js +82 -0
  26. package/dist/checkout-core/messages/en.d.ts +253 -0
  27. package/dist/checkout-core/messages/en.js +243 -0
  28. package/dist/checkout-core/messages/fr.d.ts +4 -0
  29. package/dist/checkout-core/messages/fr.js +245 -0
  30. package/dist/checkout-core/models/checkout.card.utils.d.ts +22 -0
  31. package/dist/checkout-core/models/checkout.card.utils.js +101 -0
  32. package/dist/checkout-core/models/checkout.constants.d.ts +56 -0
  33. package/dist/checkout-core/models/checkout.constants.js +142 -0
  34. package/dist/checkout-core/models/checkout.enum.d.ts +133 -0
  35. package/dist/checkout-core/models/checkout.enum.js +150 -0
  36. package/dist/checkout-core/models/checkout.interface.d.ts +417 -0
  37. package/dist/checkout-core/models/checkout.interface.js +1 -0
  38. package/dist/checkout-core/models/checkout.money.utils.d.ts +7 -0
  39. package/dist/checkout-core/models/checkout.money.utils.js +21 -0
  40. package/dist/checkout-core/models/checkout.phone.utils.d.ts +33 -0
  41. package/dist/checkout-core/models/checkout.phone.utils.js +159 -0
  42. package/dist/checkout-core/models/checkout.view.utils.d.ts +34 -0
  43. package/dist/checkout-core/models/checkout.view.utils.js +205 -0
  44. package/dist/checkout-core/models/domain.enum.d.ts +56 -0
  45. package/dist/checkout-core/models/domain.enum.js +62 -0
  46. package/dist/components/BrissotoPayProvider.d.ts +6 -0
  47. package/dist/components/BrissotoPayProvider.js +41 -0
  48. package/dist/components/PaymentSheetModal.d.ts +8 -0
  49. package/dist/components/PaymentSheetModal.js +77 -0
  50. package/dist/components/SheetBone.d.ts +3 -0
  51. package/dist/components/SheetBone.js +12 -0
  52. package/dist/components/SheetButton.d.ts +3 -0
  53. package/dist/components/SheetButton.js +33 -0
  54. package/dist/components/SheetCardFields.d.ts +8 -0
  55. package/dist/components/SheetCardFields.js +66 -0
  56. package/dist/components/SheetChosenMethod.d.ts +3 -0
  57. package/dist/components/SheetChosenMethod.js +60 -0
  58. package/dist/components/SheetCodeField.d.ts +8 -0
  59. package/dist/components/SheetCodeField.js +97 -0
  60. package/dist/components/SheetContent.d.ts +3 -0
  61. package/dist/components/SheetContent.js +106 -0
  62. package/dist/components/SheetFailed.d.ts +3 -0
  63. package/dist/components/SheetFailed.js +43 -0
  64. package/dist/components/SheetForm.d.ts +8 -0
  65. package/dist/components/SheetForm.js +101 -0
  66. package/dist/components/SheetHeader.d.ts +6 -0
  67. package/dist/components/SheetHeader.js +69 -0
  68. package/dist/components/SheetIcon.d.ts +3 -0
  69. package/dist/components/SheetIcon.js +70 -0
  70. package/dist/components/SheetLayout.d.ts +9 -0
  71. package/dist/components/SheetLayout.js +48 -0
  72. package/dist/components/SheetLogo.d.ts +3 -0
  73. package/dist/components/SheetLogo.js +20 -0
  74. package/dist/components/SheetMessage.d.ts +3 -0
  75. package/dist/components/SheetMessage.js +15 -0
  76. package/dist/components/SheetMethodCard.d.ts +3 -0
  77. package/dist/components/SheetMethodCard.js +32 -0
  78. package/dist/components/SheetPhoneField.d.ts +3 -0
  79. package/dist/components/SheetPhoneField.js +58 -0
  80. package/dist/components/SheetRow.d.ts +3 -0
  81. package/dist/components/SheetRow.js +28 -0
  82. package/dist/components/SheetSimulator.d.ts +6 -0
  83. package/dist/components/SheetSimulator.js +39 -0
  84. package/dist/components/SheetSkeleton.d.ts +5 -0
  85. package/dist/components/SheetSkeleton.js +23 -0
  86. package/dist/components/SheetSuccess.d.ts +3 -0
  87. package/dist/components/SheetSuccess.js +51 -0
  88. package/dist/components/SheetSummary.d.ts +3 -0
  89. package/dist/components/SheetSummary.js +32 -0
  90. package/dist/components/SheetTerminal.d.ts +3 -0
  91. package/dist/components/SheetTerminal.js +21 -0
  92. package/dist/components/SheetText.d.ts +5 -0
  93. package/dist/components/SheetText.js +25 -0
  94. package/dist/components/SheetToast.d.ts +3 -0
  95. package/dist/components/SheetToast.js +24 -0
  96. package/dist/components/SheetWaiting.d.ts +7 -0
  97. package/dist/components/SheetWaiting.js +77 -0
  98. package/dist/hooks/use-native-platform.d.ts +10 -0
  99. package/dist/hooks/use-native-platform.js +47 -0
  100. package/dist/hooks/use-payment-sheet.d.ts +4 -0
  101. package/dist/hooks/use-payment-sheet.js +10 -0
  102. package/dist/hooks/use-sheet-motion.d.ts +7 -0
  103. package/dist/hooks/use-sheet-motion.js +62 -0
  104. package/dist/hooks/use-sheet-resize.d.ts +6 -0
  105. package/dist/hooks/use-sheet-resize.js +15 -0
  106. package/dist/hooks/use-sheet-theme.d.ts +4 -0
  107. package/dist/hooks/use-sheet-theme.js +12 -0
  108. package/dist/hooks/use-watched-payment.d.ts +6 -0
  109. package/dist/hooks/use-watched-payment.js +17 -0
  110. package/dist/index.d.ts +3 -0
  111. package/dist/index.js +2 -0
  112. package/dist/models/sheet.constants.d.ts +39 -0
  113. package/dist/models/sheet.constants.js +78 -0
  114. package/dist/models/sheet.enum.d.ts +16 -0
  115. package/dist/models/sheet.enum.js +18 -0
  116. package/dist/models/sheet.interface.d.ts +232 -0
  117. package/dist/models/sheet.interface.js +1 -0
  118. package/dist/models/sheet.utils.d.ts +43 -0
  119. package/dist/models/sheet.utils.js +132 -0
  120. package/dist/services/checkout.service.d.ts +7 -0
  121. package/dist/services/checkout.service.js +39 -0
  122. package/package.json +58 -4
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Eases the sheet's height when what it shows changes `shape` (another
3
+ * screen, tab, method, the card fields' page): the next layout animates,
4
+ * on iOS and Android alike. The first one does not: the sheet slides up.
5
+ */
6
+ export declare function useSheetResize(shape: string): void;
@@ -0,0 +1,15 @@
1
+ import { useState } from 'react';
2
+ import { LayoutAnimation } from 'react-native';
3
+ import { SHEET_RESIZE } from "../models/sheet.constants.js";
4
+ /**
5
+ * Eases the sheet's height when what it shows changes `shape` (another
6
+ * screen, tab, method, the card fields' page): the next layout animates,
7
+ * on iOS and Android alike. The first one does not: the sheet slides up.
8
+ */
9
+ export function useSheetResize(shape) {
10
+ const [last, setLast] = useState(shape);
11
+ if (last !== shape) {
12
+ setLast(shape);
13
+ LayoutAnimation.configureNext(SHEET_RESIZE);
14
+ }
15
+ }
@@ -0,0 +1,4 @@
1
+ import type { SheetTheme } from '../models/sheet.interface.js';
2
+ export declare const SheetThemeContext: import("react").Context<SheetTheme>;
3
+ /** The open sheet's colours. */
4
+ export declare function useSheetTheme(): SheetTheme;
@@ -0,0 +1,12 @@
1
+ import { createContext, use } from 'react';
2
+ import { CHECKOUT_COLORS } from "../checkout-core/models/checkout.constants.js";
3
+ import { CheckoutThemeEnum } from "../checkout-core/models/checkout.enum.js";
4
+ export const SheetThemeContext = createContext({
5
+ colors: CHECKOUT_COLORS[CheckoutThemeEnum.LIGHT],
6
+ brand: CHECKOUT_COLORS[CheckoutThemeEnum.LIGHT].ink,
7
+ dark: false,
8
+ });
9
+ /** The open sheet's colours. */
10
+ export function useSheetTheme() {
11
+ return use(SheetThemeContext);
12
+ }
@@ -0,0 +1,6 @@
1
+ import type { CheckoutCalls, WatchedPayment } from '../models/sheet.interface.js';
2
+ /**
3
+ * One payment, live, while `paymentId` is set. Once it is cleared (the sheet
4
+ * closing) the last answer stays, so the sheet slides away unchanged.
5
+ */
6
+ export declare function useWatchedPayment(calls: CheckoutCalls, paymentId: string | null): WatchedPayment;
@@ -0,0 +1,17 @@
1
+ import { useEffect, useState } from 'react';
2
+ /**
3
+ * One payment, live, while `paymentId` is set. Once it is cleared (the sheet
4
+ * closing) the last answer stays, so the sheet slides away unchanged.
5
+ */
6
+ export function useWatchedPayment(calls, paymentId) {
7
+ const [watched, setWatched] = useState({
8
+ view: undefined,
9
+ failed: false,
10
+ });
11
+ useEffect(() => {
12
+ if (!paymentId)
13
+ return undefined;
14
+ return calls.watch(paymentId, (view) => setWatched({ view, failed: false }), () => setWatched((previous) => ({ ...previous, failed: true })));
15
+ }, [calls, paymentId]);
16
+ return watched;
17
+ }
@@ -0,0 +1,3 @@
1
+ export { BrissotoPayProvider } from './components/BrissotoPayProvider.js';
2
+ export { usePaymentSheet } from './hooks/use-payment-sheet.js';
3
+ export type { BrissotoPayProviderProps, PaymentSheet, PaymentSheetError, PaymentSheetResult, PaymentSheetStatus, PresentPaymentOptions, } from './models/sheet.interface.js';
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ export { BrissotoPayProvider } from "./components/BrissotoPayProvider.js";
2
+ export { usePaymentSheet } from "./hooks/use-payment-sheet.js";
@@ -0,0 +1,39 @@
1
+ import type { LayoutAnimationConfig } from 'react-native';
2
+ import en from '../checkout-core/messages/en.js';
3
+ import { LangEnum, ProviderLogoEnum } from '../checkout-core/models/domain.enum.js';
4
+ import { FigtreeEnum } from './sheet.enum.js';
5
+ /** The production backend: Live and Test payments alike. */
6
+ export declare const DEFAULT_URL = "https://api-pay.brissoto.com";
7
+ /** The public Convex functions the web checkout calls, by path. */
8
+ export declare const CHECKOUT_FUNCTIONS: {
9
+ get: string;
10
+ pay: string;
11
+ payWithCode: string;
12
+ checkNow: string;
13
+ open: string;
14
+ cancel: string;
15
+ resend: string;
16
+ simulate: string;
17
+ };
18
+ /** Figtree ships inside the package: `expo-font` loads it when a sheet opens. */
19
+ export declare const FIGTREE_FILES: Record<FigtreeEnum, number>;
20
+ /** The sheet's timezone for dates, as the web checkout's. */
21
+ export declare const TIME_ZONE = "Africa/Douala";
22
+ /** The payer copy the web checkout shows, by language. */
23
+ export declare const MESSAGES: Record<LangEnum, {
24
+ checkout: typeof en;
25
+ }>;
26
+ /** Brand tiles, the web's `public/logo/` PNGs bundled with the package. */
27
+ export declare const PROVIDER_LOGOS: Record<ProviderLogoEnum, number>;
28
+ /** At its tallest, the sheet leaves this share of the screen above it, clear of the status bar. */
29
+ export declare const SHEET_TOP_GAP = 0.1;
30
+ /** How dark the app gets behind the sheet. */
31
+ export declare const SHEET_DIM_OPACITY = 0.4;
32
+ /** How long the sheet takes to slide up or away, in ms. */
33
+ export declare const SHEET_SLIDE_MS = 280;
34
+ /** Points down that close the sheet when the finger lets go. */
35
+ export declare const SHEET_SWIPE_DISTANCE = 120;
36
+ /** A flick down this fast (points per ms) closes it, however short. */
37
+ export declare const SHEET_FLICK_SPEED = 0.8;
38
+ /** How the sheet's height eases from one screen to the next. */
39
+ export declare const SHEET_RESIZE: LayoutAnimationConfig;
@@ -0,0 +1,78 @@
1
+ import figtreeBold from '../../assets/fonts/Figtree-Bold.ttf';
2
+ import figtreeExtraBold from '../../assets/fonts/Figtree-ExtraBold.ttf';
3
+ import figtreeMedium from '../../assets/fonts/Figtree-Medium.ttf';
4
+ import figtreeRegular from '../../assets/fonts/Figtree-Regular.ttf';
5
+ import figtreeSemiBold from '../../assets/fonts/Figtree-SemiBold.ttf';
6
+ import logoApplePay from '../../assets/logos/apple-pay.png';
7
+ import logoCard from '../../assets/logos/card.png';
8
+ import logoGooglePay from '../../assets/logos/google-pay.png';
9
+ import logoMastercard from '../../assets/logos/mastercard.png';
10
+ import logoMixx from '../../assets/logos/mixx.png';
11
+ import logoMoov from '../../assets/logos/moov.png';
12
+ import logoMtn from '../../assets/logos/mtn.png';
13
+ import logoOrange from '../../assets/logos/orange.png';
14
+ import logoPaypal from '../../assets/logos/paypal.png';
15
+ import logoVisa from '../../assets/logos/visa.png';
16
+ import logoWave from '../../assets/logos/wave.png';
17
+ import { LayoutAnimation } from 'react-native';
18
+ import en from "../checkout-core/messages/en.js";
19
+ import fr from "../checkout-core/messages/fr.js";
20
+ import { LangEnum, ProviderLogoEnum, } from "../checkout-core/models/domain.enum.js";
21
+ import { FigtreeEnum } from "./sheet.enum.js";
22
+ /** The production backend: Live and Test payments alike. */
23
+ export const DEFAULT_URL = 'https://api-pay.brissoto.com';
24
+ /** The public Convex functions the web checkout calls, by path. */
25
+ export const CHECKOUT_FUNCTIONS = {
26
+ get: 'checkout/queries:get',
27
+ pay: 'checkout/mutations:pay',
28
+ payWithCode: 'checkout/actions:payWithCode',
29
+ checkNow: 'checkout/mutations:checkNow',
30
+ open: 'checkout/mutations:open',
31
+ cancel: 'checkout/mutations:cancel',
32
+ resend: 'checkout/mutations:resend',
33
+ simulate: 'simulator/mutations:decide',
34
+ };
35
+ /** Figtree ships inside the package: `expo-font` loads it when a sheet opens. */
36
+ export const FIGTREE_FILES = {
37
+ [FigtreeEnum.REGULAR]: figtreeRegular,
38
+ [FigtreeEnum.MEDIUM]: figtreeMedium,
39
+ [FigtreeEnum.SEMI_BOLD]: figtreeSemiBold,
40
+ [FigtreeEnum.BOLD]: figtreeBold,
41
+ [FigtreeEnum.EXTRA_BOLD]: figtreeExtraBold,
42
+ };
43
+ /** The sheet's timezone for dates, as the web checkout's. */
44
+ export const TIME_ZONE = 'Africa/Douala';
45
+ /** The payer copy the web checkout shows, by language. */
46
+ export const MESSAGES = {
47
+ [LangEnum.EN]: { checkout: en },
48
+ [LangEnum.FR]: { checkout: fr },
49
+ };
50
+ /** Brand tiles, the web's `public/logo/` PNGs bundled with the package. */
51
+ export const PROVIDER_LOGOS = {
52
+ [ProviderLogoEnum.ORANGE]: logoOrange,
53
+ [ProviderLogoEnum.MTN]: logoMtn,
54
+ [ProviderLogoEnum.MOOV]: logoMoov,
55
+ [ProviderLogoEnum.WAVE]: logoWave,
56
+ [ProviderLogoEnum.MIXX]: logoMixx,
57
+ [ProviderLogoEnum.VISA]: logoVisa,
58
+ [ProviderLogoEnum.MASTERCARD]: logoMastercard,
59
+ [ProviderLogoEnum.PAYPAL]: logoPaypal,
60
+ [ProviderLogoEnum.CARD]: logoCard,
61
+ [ProviderLogoEnum.APPLE_PAY]: logoApplePay,
62
+ [ProviderLogoEnum.GOOGLE_PAY]: logoGooglePay,
63
+ };
64
+ /** At its tallest, the sheet leaves this share of the screen above it, clear of the status bar. */
65
+ export const SHEET_TOP_GAP = 0.1;
66
+ /** How dark the app gets behind the sheet. */
67
+ export const SHEET_DIM_OPACITY = 0.4;
68
+ /** How long the sheet takes to slide up or away, in ms. */
69
+ export const SHEET_SLIDE_MS = 280;
70
+ /** Points down that close the sheet when the finger lets go. */
71
+ export const SHEET_SWIPE_DISTANCE = 120;
72
+ /** A flick down this fast (points per ms) closes it, however short. */
73
+ export const SHEET_FLICK_SPEED = 0.8;
74
+ /** How the sheet's height eases from one screen to the next. */
75
+ export const SHEET_RESIZE = {
76
+ duration: 220,
77
+ update: { type: LayoutAnimation.Types.easeInEaseOut },
78
+ };
@@ -0,0 +1,16 @@
1
+ /** Figtree's weights the sheet uses. Values are the font family names `expo-font` registers. */
2
+ export declare enum FigtreeEnum {
3
+ REGULAR = "Figtree-Regular",
4
+ MEDIUM = "Figtree-Medium",
5
+ SEMI_BOLD = "Figtree-SemiBold",
6
+ BOLD = "Figtree-Bold",
7
+ EXTRA_BOLD = "Figtree-ExtraBold"
8
+ }
9
+ /** The signs the sheet draws, in a disc. */
10
+ export declare enum SheetIconEnum {
11
+ BAN = "ban",
12
+ CLOCK = "clock",
13
+ LOCK = "lock",
14
+ CROSS = "cross",
15
+ CHECK = "check"
16
+ }
@@ -0,0 +1,18 @@
1
+ /** Figtree's weights the sheet uses. Values are the font family names `expo-font` registers. */
2
+ export var FigtreeEnum;
3
+ (function (FigtreeEnum) {
4
+ FigtreeEnum["REGULAR"] = "Figtree-Regular";
5
+ FigtreeEnum["MEDIUM"] = "Figtree-Medium";
6
+ FigtreeEnum["SEMI_BOLD"] = "Figtree-SemiBold";
7
+ FigtreeEnum["BOLD"] = "Figtree-Bold";
8
+ FigtreeEnum["EXTRA_BOLD"] = "Figtree-ExtraBold";
9
+ })(FigtreeEnum || (FigtreeEnum = {}));
10
+ /** The signs the sheet draws, in a disc. */
11
+ export var SheetIconEnum;
12
+ (function (SheetIconEnum) {
13
+ SheetIconEnum["BAN"] = "ban";
14
+ SheetIconEnum["CLOCK"] = "clock";
15
+ SheetIconEnum["LOCK"] = "lock";
16
+ SheetIconEnum["CROSS"] = "cross";
17
+ SheetIconEnum["CHECK"] = "check";
18
+ })(SheetIconEnum || (SheetIconEnum = {}));
@@ -0,0 +1,232 @@
1
+ import type { ReactNode, Ref, RefObject } from 'react';
2
+ import type { Animated, DimensionValue, GestureResponderHandlers, StyleProp, TextInputInstance, TextInputProps, TextProps, TextStyle } from 'react-native';
3
+ import type { WebView } from 'react-native-webview';
4
+ import type { CheckoutButtonVariantEnum, TerminalKindEnum } from '../checkout-core/models/checkout.enum.js';
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';
7
+ import type { FigtreeEnum, SheetIconEnum } from './sheet.enum.js';
8
+ /**
9
+ * How the sheet ended. `closed`: the payer closed it with the payment still
10
+ * open. A hint only: ship on `payment.paid` from the webhook or `getPayment`.
11
+ */
12
+ export type PaymentSheetStatus = 'paid' | 'pending' | 'cancelled' | 'expired' | 'locked' | 'closed';
13
+ /** Why the sheet could not show the payment: no payment has this id, or it could not load. */
14
+ export type PaymentSheetError = 'not_found' | 'network';
15
+ export interface PaymentSheetResult {
16
+ status: PaymentSheetStatus;
17
+ error?: PaymentSheetError;
18
+ }
19
+ export interface PresentPaymentOptions {
20
+ /** The payment id the app's server got from the server SDK (`pay_…`). */
21
+ paymentId: string;
22
+ }
23
+ export interface PaymentSheet {
24
+ /** Opens the sheet for one payment; resolves when it closes. A second call while one is open rejects. */
25
+ presentPayment: (options: PresentPaymentOptions) => Promise<PaymentSheetResult>;
26
+ }
27
+ export interface BrissotoPayProviderProps {
28
+ /** The Brissoto Pay backend; the production one by default. One backend serves Live and Test. */
29
+ url?: string;
30
+ children?: ReactNode;
31
+ }
32
+ /** The checkout's gateway calls, one interface for the sheet whatever client is behind it. */
33
+ export interface CheckoutCalls {
34
+ /**
35
+ * Follows one payment's checkout view live: `onView` with each answer
36
+ * (null: no payment has this id), `onError` when it cannot load. Answers how to stop.
37
+ */
38
+ watch: (paymentId: string, onView: (view: CheckoutView | null) => void, onError: () => void) => () => void;
39
+ mutations: CheckoutMutations;
40
+ }
41
+ /** The sheet the app asked for, and how to answer it. */
42
+ export interface SheetRequest {
43
+ paymentId: string;
44
+ /** False once closed: the sheet slides away showing its last screen. */
45
+ open: boolean;
46
+ resolve: (result: PaymentSheetResult) => void;
47
+ }
48
+ /** A payment as the sheet follows it: undefined while loading, null for an id that matches none. */
49
+ export interface WatchedPayment {
50
+ view: CheckoutView | null | undefined;
51
+ /** It could not load. */
52
+ failed: boolean;
53
+ }
54
+ export interface PaymentSheetModalProps {
55
+ calls: CheckoutCalls;
56
+ request: SheetRequest;
57
+ onClose: (result: PaymentSheetResult) => void;
58
+ }
59
+ export interface SheetContentProps {
60
+ calls: CheckoutCalls;
61
+ watched: WatchedPayment;
62
+ /** Fonts still loading: the sheet shows its skeleton. */
63
+ fontsReady: boolean;
64
+ deviceLocale: string;
65
+ onClose: () => void;
66
+ /** On the sheet's top: dragged down, the sheet follows, and far enough it closes. */
67
+ dragHandlers: GestureResponderHandlers;
68
+ }
69
+ /** How the bottom sheet moves: up when it opens, with the finger, away once closed. */
70
+ export interface SheetMotion {
71
+ /** Still on screen: open, or sliding away. */
72
+ shown: boolean;
73
+ /** How far below its place the sheet is drawn. */
74
+ translateY: Animated.AnimatedAddition;
75
+ /** The dim over the app, lighter as the sheet goes down. */
76
+ dim: Animated.AnimatedInterpolation<number>;
77
+ dragHandlers: GestureResponderHandlers;
78
+ /** Room left above the sheet at its tallest, in points. */
79
+ topGap: number;
80
+ }
81
+ /** The sheet's look: the checkout colours of its theme and the app's colour. */
82
+ export interface SheetTheme {
83
+ colors: CheckoutColors;
84
+ brand: string;
85
+ dark: boolean;
86
+ }
87
+ export interface SheetTextProps extends TextProps {
88
+ weight?: FigtreeEnum;
89
+ size?: number;
90
+ color?: string;
91
+ style?: StyleProp<TextStyle>;
92
+ }
93
+ export interface SheetHeaderProps {
94
+ view: CheckoutView | null | undefined;
95
+ /** Bones for the logo and name; close works from the first frame. */
96
+ loading: boolean;
97
+ onClose: () => void;
98
+ dragHandlers: GestureResponderHandlers;
99
+ }
100
+ export interface SheetSummaryProps {
101
+ view: CheckoutView;
102
+ }
103
+ export interface SheetInputProps extends TextInputProps {
104
+ ref?: Ref<TextInputInstance>;
105
+ }
106
+ /** A dead end: what happened, why, and its sign. */
107
+ export interface SheetMessageProps {
108
+ title: string;
109
+ body: string;
110
+ /** A ban sign by default: a payment the sheet cannot show. */
111
+ icon?: SheetIconEnum;
112
+ /** The lock is red. */
113
+ danger?: boolean;
114
+ }
115
+ /** A screen the payer cannot act on (expired, cancelled, locked, nothing to pay with). */
116
+ export interface SheetTerminalProps extends SheetClosingProps {
117
+ kind: TerminalKindEnum;
118
+ }
119
+ /** A screen of the sheet: what scrolls, then what stays pinned at the bottom above "Payment secured by". */
120
+ export interface SheetLayoutProps {
121
+ children: ReactNode;
122
+ foot?: ReactNode;
123
+ /** "Payment secured by Brissoto Pay" under the foot: once a payment shows. */
124
+ secure?: boolean;
125
+ }
126
+ /** A screen drawn from the shared checkout controller. */
127
+ export interface SheetScreenProps {
128
+ core: CheckoutCore;
129
+ }
130
+ /** A screen that can close the sheet itself (Done, Return to the app). */
131
+ export interface SheetClosingProps extends SheetScreenProps {
132
+ onClose: () => void;
133
+ }
134
+ export interface SheetPhoneFieldProps extends SheetScreenProps {
135
+ /** The number field, so a Pay with a wrong number can bring it to the payer. */
136
+ phoneRef: Ref<TextInputInstance>;
137
+ }
138
+ export interface SheetFormProps extends SheetPhoneFieldProps {
139
+ cardFields: CardFieldsBridge;
140
+ }
141
+ /** The card fields' WebView, and the way what its page says reaches the core. */
142
+ export interface CardFieldsBridge {
143
+ /** `WebView<object>`: its default `WebView<undefined>` types no props. */
144
+ page: RefObject<WebView<object> | null>;
145
+ /** A message the card fields page sent, already checked to come from it. */
146
+ receive: (message: CardFieldsMessage) => void;
147
+ }
148
+ /** What only the phone does for the checkout core, and the card fields' end of it. */
149
+ export interface NativePlatform {
150
+ platform: CheckoutPlatform;
151
+ cardFields: CardFieldsBridge;
152
+ }
153
+ export interface SheetCardFieldsProps extends SheetScreenProps {
154
+ bridge: CardFieldsBridge;
155
+ }
156
+ export interface SheetButtonProps {
157
+ label: string;
158
+ onPress: () => void;
159
+ variant?: CheckoutButtonVariantEnum;
160
+ /** On its way: a spinner, and no second press. */
161
+ busy?: boolean;
162
+ disabled?: boolean;
163
+ /** Looks off but still answers: Pay says what is missing. */
164
+ inactive?: boolean;
165
+ }
166
+ /** A brand tile: the provider's logo, square, at one of `LOGO_SIZE`. */
167
+ export interface SheetLogoProps {
168
+ logo: ProviderLogoEnum;
169
+ size?: number;
170
+ /** Greyed with its method. */
171
+ muted?: boolean;
172
+ }
173
+ /** One method in the grid: its logo, name, network or why it is greyed, and a radio dot. */
174
+ export interface MethodCardProps {
175
+ logo: ProviderLogoEnum;
176
+ name: string;
177
+ sub: string;
178
+ /** Greyed and not pressable: in maintenance, or not offered yet. */
179
+ muted: boolean;
180
+ onSelect?: () => void;
181
+ }
182
+ export interface ChosenMethodProps {
183
+ logo: ProviderLogoEnum;
184
+ name: string;
185
+ /** Its network. */
186
+ sub: string;
187
+ /** Back to the list. */
188
+ onChange: () => void;
189
+ }
190
+ export interface MethodGridCard extends MethodCardProps {
191
+ id: string;
192
+ }
193
+ export interface MethodGridProps {
194
+ cards: Array<MethodGridCard>;
195
+ }
196
+ export interface SheetIconProps {
197
+ kind: SheetIconEnum;
198
+ color: string;
199
+ /** The disc behind it. */
200
+ background: string;
201
+ /** The disc's side; the sign grows with it. */
202
+ size?: number;
203
+ }
204
+ /** A label and its value, one row of a receipt or a waiting payment. */
205
+ export interface SheetRowProps {
206
+ label: string;
207
+ children: ReactNode;
208
+ /** The value in the danger colour: the last seconds of the clock. */
209
+ urgent?: boolean;
210
+ }
211
+ export interface SheetToastProps {
212
+ message: string | null;
213
+ }
214
+ export interface BoneProps {
215
+ /** Points, or a share of the row (`100%`). */
216
+ width: DimensionValue;
217
+ height: number;
218
+ radius?: number;
219
+ }
220
+ /** What the card fields page's address carries. */
221
+ export interface CardFieldsAddress {
222
+ /** Where the checkout is served (`CheckoutView.siteUrl`). */
223
+ siteUrl: string;
224
+ /** The method's `cardFieldsPath`. */
225
+ path: string;
226
+ paymentId: string;
227
+ method: string;
228
+ /** The app colour, a hex code. */
229
+ color: string;
230
+ dark: boolean;
231
+ lang: LangEnum;
232
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,43 @@
1
+ import { CheckoutThemeEnum } from '../checkout-core/models/checkout.enum.js';
2
+ import { LangEnum } from '../checkout-core/models/domain.enum.js';
3
+ import type { CountryEnum } from '../checkout-core/models/domain.enum.js';
4
+ import type { CardFieldsMessage, CheckoutView } from '../checkout-core/models/checkout.interface.js';
5
+ import type { CardFieldsAddress, PaymentSheetResult } from './sheet.interface.js';
6
+ /** The payment's language, else the device's when the sheet speaks it, else English. */
7
+ export declare function sheetLanguage(payment: LangEnum | null, deviceLocale: string): LangEnum;
8
+ /** The payment's theme, else the device's scheme. */
9
+ export declare function sheetTheme(payment: CheckoutThemeEnum | null, scheme: string | null | undefined): CheckoutThemeEnum;
10
+ /** What `presentPayment` answers when the sheet closes on this payment. */
11
+ export declare function sheetResult(view: CheckoutView | null | undefined, failed: boolean): PaymentSheetResult;
12
+ /** `cm` → 🇨🇲: the country's flag, as the phone draws it. */
13
+ export declare function flagOf(country: CountryEnum): string;
14
+ /**
15
+ * Seconds before the prompt can be sent again, from the waiting clock
16
+ * (`waitLeft`) and the second of the wait it was last sent at (0: Pay).
17
+ */
18
+ export declare function resendLeftOf(waitLeft: number, sentAt: number): number;
19
+ /**
20
+ * The card fields page the sheet loads: English under `/en`, French the bare
21
+ * path asking for French (as the checkout link does), with the payment, the
22
+ * method and the sheet's look.
23
+ */
24
+ export declare function cardFieldsUrl({ siteUrl, path, paymentId, method, color, dark, lang, }: CardFieldsAddress): string;
25
+ /** `https://pay.brissoto.com/en/checkout` → `https://pay.brissoto.com`; null for anything not on the web. */
26
+ export declare function originOf(url: string): string | null;
27
+ /** The card fields page itself, in either language: the one page its WebView may load. */
28
+ export declare function isCardFieldsPage(url: string, page: string): boolean;
29
+ /**
30
+ * What the card fields page said, as the core reads it, when it is one of
31
+ * its messages; anything else, Pay itself included, is dropped.
32
+ */
33
+ export declare function cardFieldsMessageOf(data: string): CardFieldsMessage | null;
34
+ /**
35
+ * Runs in the card fields page before it loads. At the top of a WebView the
36
+ * page tells its checkout by posting to itself: what it posts from its own
37
+ * origin goes on to the sheet, Pay (which only the sheet sends) aside.
38
+ */
39
+ export declare function cardFieldsBridge(): string;
40
+ /** Tells the card fields page that Pay was pressed, as the web checkout does. */
41
+ export declare function cardFieldsSubmit(): string;
42
+ /** Letting go of the sheet's top `dy` points lower, at `vy` points per ms: far enough, or flicked, it closes. */
43
+ export declare function sheetSwipeCloses(dy: number, vy: number): boolean;
@@ -0,0 +1,132 @@
1
+ import { RESEND_SECONDS, WAIT_SECONDS, } from "../checkout-core/models/checkout.constants.js";
2
+ import { CardFieldsMessageEnum, CheckoutPaymentStatusEnum, CheckoutThemeEnum, PayRefusalEnum, } from "../checkout-core/models/checkout.enum.js";
3
+ import { AttemptStatusEnum, LangEnum, } from "../checkout-core/models/domain.enum.js";
4
+ import { SHEET_FLICK_SPEED, SHEET_SWIPE_DISTANCE } from "./sheet.constants.js";
5
+ /** The payment's language, else the device's when the sheet speaks it, else English. */
6
+ export function sheetLanguage(payment, deviceLocale) {
7
+ if (payment)
8
+ return payment;
9
+ const device = deviceLocale.slice(0, 2).toLowerCase();
10
+ return Object.values(LangEnum).find((lang) => lang === device) ?? LangEnum.EN;
11
+ }
12
+ /** The payment's theme, else the device's scheme. */
13
+ export function sheetTheme(payment, scheme) {
14
+ return (payment ??
15
+ (scheme === CheckoutThemeEnum.DARK
16
+ ? CheckoutThemeEnum.DARK
17
+ : CheckoutThemeEnum.LIGHT));
18
+ }
19
+ /** What `presentPayment` answers when the sheet closes on this payment. */
20
+ export function sheetResult(view, failed) {
21
+ if (view === null)
22
+ return { status: 'closed', error: 'not_found' };
23
+ if (!view)
24
+ return failed
25
+ ? { status: 'closed', error: 'network' }
26
+ : { status: 'closed' };
27
+ if (view.status !== CheckoutPaymentStatusEnum.PENDING) {
28
+ return { status: view.status };
29
+ }
30
+ // A prompt still on the phone: approved later, the payment goes through.
31
+ return {
32
+ status: view.attempt?.status === AttemptStatusEnum.PENDING ? 'pending' : 'closed',
33
+ };
34
+ }
35
+ /** `cm` → 🇨🇲: the country's flag, as the phone draws it. */
36
+ export function flagOf(country) {
37
+ return String.fromCodePoint(...[...country.toUpperCase()].map((letter) => 0x1f1e6 + letter.charCodeAt(0) - 'A'.charCodeAt(0)));
38
+ }
39
+ /**
40
+ * Seconds before the prompt can be sent again, from the waiting clock
41
+ * (`waitLeft`) and the second of the wait it was last sent at (0: Pay).
42
+ */
43
+ export function resendLeftOf(waitLeft, sentAt) {
44
+ const waited = WAIT_SECONDS - waitLeft - sentAt;
45
+ return Math.max(0, RESEND_SECONDS - waited);
46
+ }
47
+ /**
48
+ * The card fields page the sheet loads: English under `/en`, French the bare
49
+ * path asking for French (as the checkout link does), with the payment, the
50
+ * method and the sheet's look.
51
+ */
52
+ export function cardFieldsUrl({ siteUrl, path, paymentId, method, color, dark, lang, }) {
53
+ const query = new URLSearchParams({
54
+ payment: paymentId,
55
+ method,
56
+ color,
57
+ theme: dark ? CheckoutThemeEnum.DARK : CheckoutThemeEnum.LIGHT,
58
+ ...(lang === LangEnum.FR ? { lang } : {}),
59
+ });
60
+ const prefix = lang === LangEnum.EN ? `/${lang}` : '';
61
+ return `${siteUrl}${prefix}${path}?${query.toString()}`;
62
+ }
63
+ const WEB_ADDRESS = /^(https?:\/\/[^/?#]+)([^?#]*)/i;
64
+ const LANG_PREFIX = new RegExp(`^/(?:${Object.values(LangEnum).join('|')})(?=/|$)`);
65
+ /** `https://pay.brissoto.com/en/checkout` → `https://pay.brissoto.com`; null for anything not on the web. */
66
+ export function originOf(url) {
67
+ return WEB_ADDRESS.exec(url)?.[1].toLowerCase() ?? null;
68
+ }
69
+ /** The path of a web address without its language and trailing slash. */
70
+ function pageOf(url) {
71
+ const path = WEB_ADDRESS.exec(url)[2].replace(LANG_PREFIX, '');
72
+ return path.replace(/\/+$/, '');
73
+ }
74
+ /** The card fields page itself, in either language: the one page its WebView may load. */
75
+ export function isCardFieldsPage(url, page) {
76
+ const origin = originOf(url);
77
+ return (origin !== null && origin === originOf(page) && pageOf(url) === pageOf(page));
78
+ }
79
+ /**
80
+ * What the card fields page said, as the core reads it, when it is one of
81
+ * its messages; anything else, Pay itself included, is dropped.
82
+ */
83
+ export function cardFieldsMessageOf(data) {
84
+ let message;
85
+ try {
86
+ message = JSON.parse(data);
87
+ }
88
+ catch {
89
+ return null;
90
+ }
91
+ switch (message?.type) {
92
+ case CardFieldsMessageEnum.STATE:
93
+ return typeof message.complete === 'boolean'
94
+ ? { type: message.type, complete: message.complete }
95
+ : null;
96
+ case CardFieldsMessageEnum.HEIGHT:
97
+ return typeof message.height === 'number' && message.height >= 0
98
+ ? { type: message.type, height: message.height }
99
+ : null;
100
+ case CardFieldsMessageEnum.DONE:
101
+ return { type: message.type };
102
+ case CardFieldsMessageEnum.REFUSED:
103
+ return Object.values(PayRefusalEnum).includes(message.reason)
104
+ ? { type: message.type, reason: message.reason }
105
+ : { type: message.type };
106
+ default:
107
+ return null;
108
+ }
109
+ }
110
+ /**
111
+ * Runs in the card fields page before it loads. At the top of a WebView the
112
+ * page tells its checkout by posting to itself: what it posts from its own
113
+ * origin goes on to the sheet, Pay (which only the sheet sends) aside.
114
+ */
115
+ export function cardFieldsBridge() {
116
+ return `window.addEventListener('message', function (event) {
117
+ var data = event.data;
118
+ if (event.origin !== window.location.origin || event.source !== window) return;
119
+ if (!data || typeof data.type !== 'string' || data.type === '${CardFieldsMessageEnum.SUBMIT}') return;
120
+ window.ReactNativeWebView.postMessage(JSON.stringify(data));
121
+ });
122
+ true;`;
123
+ }
124
+ /** Tells the card fields page that Pay was pressed, as the web checkout does. */
125
+ export function cardFieldsSubmit() {
126
+ return `window.postMessage({ type: '${CardFieldsMessageEnum.SUBMIT}' }, window.location.origin);
127
+ true;`;
128
+ }
129
+ /** Letting go of the sheet's top `dy` points lower, at `vy` points per ms: far enough, or flicked, it closes. */
130
+ export function sheetSwipeCloses(dy, vy) {
131
+ return dy > SHEET_SWIPE_DISTANCE || (dy > 0 && vy > SHEET_FLICK_SPEED);
132
+ }
@@ -0,0 +1,7 @@
1
+ import type { ConvexReactClient } from 'convex/react';
2
+ import type { CheckoutCalls } from '../models/sheet.interface.js';
3
+ /**
4
+ * The checkout's calls over the Convex client: the same public functions the
5
+ * web checkout calls, by path, so the package needs none of the backend's code.
6
+ */
7
+ export declare function convexCheckoutCalls(client: ConvexReactClient): CheckoutCalls;