@evervault/react-native 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +63 -0
- package/android/app/build/generated/source/codegen/java/com/facebook/fbreact/specs/NativeEvervaultSpec.java +60 -0
- package/android/app/build/generated/source/codegen/java/com/facebook/fbreact/specs/NativeRNCWebViewModuleSpec.java +42 -0
- package/android/app/build/generated/source/codegen/java/com/facebook/react/viewmanagers/RNCWebViewManagerDelegate.java +294 -0
- package/android/app/build/generated/source/codegen/java/com/facebook/react/viewmanagers/RNCWebViewManagerInterface.java +104 -0
- package/android/app/build/generated/source/codegen/jni/CMakeLists.txt +36 -0
- package/android/app/build/generated/source/codegen/jni/NativeEvervaultSpec-generated.cpp +62 -0
- package/android/app/build/generated/source/codegen/jni/NativeEvervaultSpec.h +31 -0
- package/android/app/build/generated/source/codegen/jni/RNCWebViewSpec-generated.cpp +38 -0
- package/android/app/build/generated/source/codegen/jni/RNCWebViewSpec.h +31 -0
- package/android/app/build/generated/source/codegen/jni/react/renderer/components/NativeEvervaultSpec/NativeEvervaultSpecJSI-generated.cpp +68 -0
- package/android/app/build/generated/source/codegen/jni/react/renderer/components/NativeEvervaultSpec/NativeEvervaultSpecJSI.h +112 -0
- package/android/app/build/generated/source/codegen/jni/react/renderer/components/RNCWebViewSpec/ComponentDescriptors.cpp +22 -0
- package/android/app/build/generated/source/codegen/jni/react/renderer/components/RNCWebViewSpec/ComponentDescriptors.h +24 -0
- package/android/app/build/generated/source/codegen/jni/react/renderer/components/RNCWebViewSpec/EventEmitters.cpp +241 -0
- package/android/app/build/generated/source/codegen/jni/react/renderer/components/RNCWebViewSpec/EventEmitters.h +263 -0
- package/android/app/build/generated/source/codegen/jni/react/renderer/components/RNCWebViewSpec/Props.cpp +99 -0
- package/android/app/build/generated/source/codegen/jni/react/renderer/components/RNCWebViewSpec/Props.h +488 -0
- package/android/app/build/generated/source/codegen/jni/react/renderer/components/RNCWebViewSpec/RNCWebViewSpecJSI-generated.cpp +35 -0
- package/android/app/build/generated/source/codegen/jni/react/renderer/components/RNCWebViewSpec/RNCWebViewSpecJSI.h +76 -0
- package/android/app/build/generated/source/codegen/jni/react/renderer/components/RNCWebViewSpec/ShadowNodes.cpp +17 -0
- package/android/app/build/generated/source/codegen/jni/react/renderer/components/RNCWebViewSpec/ShadowNodes.h +32 -0
- package/android/app/build/generated/source/codegen/jni/react/renderer/components/RNCWebViewSpec/States.cpp +16 -0
- package/android/app/build/generated/source/codegen/jni/react/renderer/components/RNCWebViewSpec/States.h +29 -0
- package/android/build.gradle +32 -0
- package/android/src/main/java/com/nativeevervault/EvervaultModule.kt +114 -0
- package/android/src/main/java/com/nativeevervault/EvervaultPackage.kt +29 -0
- package/build/Card/Cvc.d.ts +5 -0
- package/build/Card/Cvc.d.ts.map +1 -0
- package/build/Card/Cvc.test.d.ts +2 -0
- package/build/Card/Cvc.test.d.ts.map +1 -0
- package/build/Card/Expiry.d.ts +5 -0
- package/build/Card/Expiry.d.ts.map +1 -0
- package/build/Card/Holder.d.ts +5 -0
- package/build/Card/Holder.d.ts.map +1 -0
- package/build/Card/Number.d.ts +5 -0
- package/build/Card/Number.d.ts.map +1 -0
- package/build/Card/Number.test.d.ts +2 -0
- package/build/Card/Number.test.d.ts.map +1 -0
- package/build/Card/Root.d.ts +36 -0
- package/build/Card/Root.d.ts.map +1 -0
- package/build/Card/Root.test.d.ts +2 -0
- package/build/Card/Root.test.d.ts.map +1 -0
- package/build/Card/index.d.ts +23 -0
- package/build/Card/index.d.ts.map +1 -0
- package/build/Card/schema.d.ts +30 -0
- package/build/Card/schema.d.ts.map +1 -0
- package/build/Card/types.d.ts +31 -0
- package/build/Card/types.d.ts.map +1 -0
- package/build/Card/utils.d.ts +17 -0
- package/build/Card/utils.d.ts.map +1 -0
- package/build/Card/utils.test.d.ts +2 -0
- package/build/Card/utils.test.d.ts.map +1 -0
- package/build/EvervaultProvider.d.ts +7 -0
- package/build/EvervaultProvider.d.ts.map +1 -0
- package/build/EvervaultProvider.test.d.ts +2 -0
- package/build/EvervaultProvider.test.d.ts.map +1 -0
- package/build/Input.d.ts +14 -0
- package/build/Input.d.ts.map +1 -0
- package/build/Input.test.d.ts +2 -0
- package/build/Input.test.d.ts.map +1 -0
- package/build/ThreeDSecure/Frame.d.ts +6 -0
- package/build/ThreeDSecure/Frame.d.ts.map +1 -0
- package/build/ThreeDSecure/Frame.test.d.ts +2 -0
- package/build/ThreeDSecure/Frame.test.d.ts.map +1 -0
- package/build/ThreeDSecure/Root.d.ts +10 -0
- package/build/ThreeDSecure/Root.d.ts.map +1 -0
- package/build/ThreeDSecure/Root.test.d.ts +2 -0
- package/build/ThreeDSecure/Root.test.d.ts.map +1 -0
- package/build/ThreeDSecure/config.d.ts +3 -0
- package/build/ThreeDSecure/config.d.ts.map +1 -0
- package/build/ThreeDSecure/context.d.ts +3 -0
- package/build/ThreeDSecure/context.d.ts.map +1 -0
- package/build/ThreeDSecure/index.d.ts +10 -0
- package/build/ThreeDSecure/index.d.ts.map +1 -0
- package/build/ThreeDSecure/session.d.ts +6 -0
- package/build/ThreeDSecure/session.d.ts.map +1 -0
- package/build/ThreeDSecure/session.test.d.ts +2 -0
- package/build/ThreeDSecure/session.test.d.ts.map +1 -0
- package/build/ThreeDSecure/types.d.ts +57 -0
- package/build/ThreeDSecure/types.d.ts.map +1 -0
- package/build/ThreeDSecure/useThreeDSecure.d.ts +3 -0
- package/build/ThreeDSecure/useThreeDSecure.d.ts.map +1 -0
- package/build/ThreeDSecure/useThreeDSecure.test.d.ts +2 -0
- package/build/ThreeDSecure/useThreeDSecure.test.d.ts.map +1 -0
- package/build/__mocks__/NativeEvervault.d.ts +4 -0
- package/build/__mocks__/NativeEvervault.d.ts.map +1 -0
- package/build/__mocks__/react-native-webview.d.ts +3 -0
- package/build/__mocks__/react-native-webview.d.ts.map +1 -0
- package/build/context.d.ts +9 -0
- package/build/context.d.ts.map +1 -0
- package/build/generated/ios/FBReactNativeSpec/FBReactNativeSpec-generated.mm +2321 -0
- package/build/generated/ios/FBReactNativeSpec/FBReactNativeSpec.h +2761 -0
- package/build/generated/ios/FBReactNativeSpecJSI-generated.cpp +2923 -0
- package/build/generated/ios/FBReactNativeSpecJSI.h +7718 -0
- package/build/generated/ios/NativeEvervaultSpec/NativeEvervaultSpec-generated.mm +74 -0
- package/build/generated/ios/NativeEvervaultSpec/NativeEvervaultSpec.h +80 -0
- package/build/generated/ios/NativeEvervaultSpecJSI-generated.cpp +68 -0
- package/build/generated/ios/NativeEvervaultSpecJSI.h +112 -0
- package/build/generated/ios/RCTModulesConformingToProtocolsProvider.h +18 -0
- package/build/generated/ios/RCTModulesConformingToProtocolsProvider.mm +33 -0
- package/build/generated/ios/RNCWebViewSpec/RNCWebViewSpec-generated.mm +46 -0
- package/build/generated/ios/RNCWebViewSpec/RNCWebViewSpec.h +62 -0
- package/build/generated/ios/RNCWebViewSpecJSI-generated.cpp +35 -0
- package/build/generated/ios/RNCWebViewSpecJSI.h +76 -0
- package/build/generated/ios/react/renderer/components/RNCWebViewSpec/ComponentDescriptors.cpp +22 -0
- package/build/generated/ios/react/renderer/components/RNCWebViewSpec/ComponentDescriptors.h +24 -0
- package/build/generated/ios/react/renderer/components/RNCWebViewSpec/EventEmitters.cpp +241 -0
- package/build/generated/ios/react/renderer/components/RNCWebViewSpec/EventEmitters.h +263 -0
- package/build/generated/ios/react/renderer/components/RNCWebViewSpec/Props.cpp +99 -0
- package/build/generated/ios/react/renderer/components/RNCWebViewSpec/Props.h +488 -0
- package/build/generated/ios/react/renderer/components/RNCWebViewSpec/RCTComponentViewHelpers.h +218 -0
- package/build/generated/ios/react/renderer/components/RNCWebViewSpec/ShadowNodes.cpp +17 -0
- package/build/generated/ios/react/renderer/components/RNCWebViewSpec/ShadowNodes.h +32 -0
- package/build/generated/ios/react/renderer/components/RNCWebViewSpec/States.cpp +16 -0
- package/build/generated/ios/react/renderer/components/RNCWebViewSpec/States.h +29 -0
- package/build/index.cjs.js +7732 -0
- package/build/index.cjs.js.map +1 -0
- package/build/index.d.ts +9 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.esm.js +7702 -0
- package/build/sdk.d.ts +9 -0
- package/build/sdk.d.ts.map +1 -0
- package/build/sdk.test.d.ts +2 -0
- package/build/sdk.test.d.ts.map +1 -0
- package/build/specs/NativeEvervault.d.ts +59 -0
- package/build/specs/NativeEvervault.d.ts.map +1 -0
- package/build/useEvervault.d.ts +2 -0
- package/build/useEvervault.d.ts.map +1 -0
- package/build/useEvervault.test.d.ts +2 -0
- package/build/useEvervault.test.d.ts.map +1 -0
- package/build/utils.d.ts +15 -0
- package/build/utils.d.ts.map +1 -0
- package/ios/NativeEvervault-Bridging-Header.h +2 -0
- package/ios/NativeEvervault.mm +38 -0
- package/ios/NativeEvervault.swift +62 -0
- package/native-evervault.podspec +20 -0
- package/package.json +85 -0
- package/src/Card/Cvc.test.tsx +41 -0
- package/src/Card/Cvc.tsx +51 -0
- package/src/Card/Expiry.tsx +26 -0
- package/src/Card/Holder.tsx +27 -0
- package/src/Card/Number.test.tsx +55 -0
- package/src/Card/Number.tsx +47 -0
- package/src/Card/Root.test.tsx +260 -0
- package/src/Card/Root.tsx +118 -0
- package/src/Card/index.ts +28 -0
- package/src/Card/schema.ts +51 -0
- package/src/Card/types.ts +50 -0
- package/src/Card/utils.test.ts +271 -0
- package/src/Card/utils.ts +127 -0
- package/src/EvervaultProvider.test.tsx +24 -0
- package/src/EvervaultProvider.tsx +43 -0
- package/src/Input.test.tsx +138 -0
- package/src/Input.tsx +136 -0
- package/src/ThreeDSecure/Frame.test.tsx +87 -0
- package/src/ThreeDSecure/Frame.tsx +50 -0
- package/src/ThreeDSecure/Root.test.tsx +67 -0
- package/src/ThreeDSecure/Root.tsx +23 -0
- package/src/ThreeDSecure/config.ts +3 -0
- package/src/ThreeDSecure/context.ts +6 -0
- package/src/ThreeDSecure/index.ts +17 -0
- package/src/ThreeDSecure/session.test.ts +329 -0
- package/src/ThreeDSecure/session.ts +132 -0
- package/src/ThreeDSecure/types.ts +67 -0
- package/src/ThreeDSecure/useThreeDSecure.test.tsx +133 -0
- package/src/ThreeDSecure/useThreeDSecure.ts +47 -0
- package/src/__mocks__/NativeEvervault.ts +13 -0
- package/src/__mocks__/react-native-webview.tsx +6 -0
- package/src/context.ts +14 -0
- package/src/index.ts +21 -0
- package/src/sdk.test.ts +122 -0
- package/src/sdk.ts +71 -0
- package/src/specs/NativeEvervault.ts +67 -0
- package/src/useEvervault.test.tsx +31 -0
- package/src/useEvervault.ts +14 -0
- package/src/utils.ts +41 -0
package/src/Input.tsx
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ForwardedRef,
|
|
3
|
+
forwardRef,
|
|
4
|
+
ReactNode,
|
|
5
|
+
Ref,
|
|
6
|
+
RefObject,
|
|
7
|
+
useCallback,
|
|
8
|
+
useImperativeHandle,
|
|
9
|
+
useRef,
|
|
10
|
+
} from "react";
|
|
11
|
+
import { TextInput, TextInputProps } from "react-native";
|
|
12
|
+
import { mergeRefs } from "./utils";
|
|
13
|
+
import { Controller, useFormContext } from "react-hook-form";
|
|
14
|
+
import MaskInput, { Mask, MaskArray } from "react-native-mask-input";
|
|
15
|
+
|
|
16
|
+
export type EvervaultInput = Pick<
|
|
17
|
+
TextInput,
|
|
18
|
+
| "isFocused"
|
|
19
|
+
| "focus"
|
|
20
|
+
| "blur"
|
|
21
|
+
| "clear"
|
|
22
|
+
| "measure"
|
|
23
|
+
| "measureInWindow"
|
|
24
|
+
| "measureLayout"
|
|
25
|
+
>;
|
|
26
|
+
|
|
27
|
+
function useForwardedInputRef(
|
|
28
|
+
ref: ForwardedRef<EvervaultInput>
|
|
29
|
+
): RefObject<TextInput> {
|
|
30
|
+
const inputRef = useRef<TextInput>(null);
|
|
31
|
+
|
|
32
|
+
useImperativeHandle<EvervaultInput, EvervaultInput>(
|
|
33
|
+
ref,
|
|
34
|
+
useCallback(
|
|
35
|
+
() => ({
|
|
36
|
+
isFocused() {
|
|
37
|
+
return inputRef.current?.isFocused() ?? false;
|
|
38
|
+
},
|
|
39
|
+
focus() {
|
|
40
|
+
inputRef.current?.focus();
|
|
41
|
+
},
|
|
42
|
+
blur() {
|
|
43
|
+
inputRef.current?.blur();
|
|
44
|
+
},
|
|
45
|
+
clear() {
|
|
46
|
+
inputRef.current?.clear();
|
|
47
|
+
},
|
|
48
|
+
measure(callback) {
|
|
49
|
+
inputRef.current?.measure(callback);
|
|
50
|
+
},
|
|
51
|
+
measureInWindow(callback) {
|
|
52
|
+
inputRef.current?.measureInWindow(callback);
|
|
53
|
+
},
|
|
54
|
+
measureLayout(relativeToNativeComponentRef, onSuccess, onFail) {
|
|
55
|
+
inputRef.current?.measureLayout(
|
|
56
|
+
relativeToNativeComponentRef,
|
|
57
|
+
onSuccess,
|
|
58
|
+
onFail
|
|
59
|
+
);
|
|
60
|
+
},
|
|
61
|
+
}),
|
|
62
|
+
[inputRef]
|
|
63
|
+
)
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
return inputRef;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export type BaseEvervaultInputProps = Omit<
|
|
70
|
+
TextInputProps,
|
|
71
|
+
"onChange" | "onChangeText" | "value" | "defaultValue"
|
|
72
|
+
>;
|
|
73
|
+
|
|
74
|
+
export function mask(format: string): MaskArray {
|
|
75
|
+
return format.split("").map((char) => {
|
|
76
|
+
if (char === "9") {
|
|
77
|
+
return /\d/;
|
|
78
|
+
}
|
|
79
|
+
return char;
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export interface EvervaultInputProps<Values extends Record<string, unknown>>
|
|
84
|
+
extends BaseEvervaultInputProps {
|
|
85
|
+
name: keyof Values;
|
|
86
|
+
mask?: Mask;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export const EvervaultInput = forwardRef<
|
|
90
|
+
EvervaultInput,
|
|
91
|
+
EvervaultInputProps<Record<string, unknown>>
|
|
92
|
+
>(function EvervaultInput({ name, mask, ...props }, ref) {
|
|
93
|
+
const inputRef = useForwardedInputRef(ref);
|
|
94
|
+
|
|
95
|
+
const methods = useFormContext();
|
|
96
|
+
|
|
97
|
+
return (
|
|
98
|
+
<Controller
|
|
99
|
+
control={methods.control}
|
|
100
|
+
name={name}
|
|
101
|
+
shouldUnregister
|
|
102
|
+
render={({ field, fieldState }) => (
|
|
103
|
+
<MaskInput
|
|
104
|
+
// Overridable props
|
|
105
|
+
id={field.name}
|
|
106
|
+
{...props}
|
|
107
|
+
// Strict props
|
|
108
|
+
ref={mergeRefs(inputRef, field.ref)}
|
|
109
|
+
editable={!field.disabled && (props.editable ?? true)}
|
|
110
|
+
onBlur={(evt) => {
|
|
111
|
+
methods.setValue(field.name, field.value, {
|
|
112
|
+
shouldDirty: true,
|
|
113
|
+
shouldTouch: true,
|
|
114
|
+
shouldValidate: true,
|
|
115
|
+
});
|
|
116
|
+
props.onBlur?.(evt);
|
|
117
|
+
}}
|
|
118
|
+
mask={mask}
|
|
119
|
+
maskAutoComplete={!!mask}
|
|
120
|
+
value={field.value}
|
|
121
|
+
onChangeText={(masked, unmasked) => {
|
|
122
|
+
methods.setValue(field.name, unmasked, {
|
|
123
|
+
shouldDirty: true,
|
|
124
|
+
shouldValidate: !!fieldState.error || fieldState.isTouched,
|
|
125
|
+
});
|
|
126
|
+
}}
|
|
127
|
+
// Remove unwanted props
|
|
128
|
+
defaultValue={undefined}
|
|
129
|
+
onChange={undefined}
|
|
130
|
+
/>
|
|
131
|
+
)}
|
|
132
|
+
/>
|
|
133
|
+
);
|
|
134
|
+
}) as <Values extends Record<string, unknown>>(
|
|
135
|
+
props: EvervaultInputProps<Values> & { ref?: Ref<EvervaultInput> }
|
|
136
|
+
) => ReactNode;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { render } from "@testing-library/react-native";
|
|
2
|
+
import { WebView } from "../__mocks__/react-native-webview";
|
|
3
|
+
import { ThreeDSecureFrame } from "./Frame";
|
|
4
|
+
import { ErrorBoundary } from "../utils";
|
|
5
|
+
import { EvervaultProvider } from "../EvervaultProvider";
|
|
6
|
+
import { ThreeDSecure } from "./Root";
|
|
7
|
+
import { CHALLENGE_DOMAIN_3DS } from "./config";
|
|
8
|
+
|
|
9
|
+
vi.mock("react-native-webview", () => ({ WebView }));
|
|
10
|
+
|
|
11
|
+
it("throws an error if used outside of an EvervaultProvider", () => {
|
|
12
|
+
const onError = vi.fn();
|
|
13
|
+
render(
|
|
14
|
+
<ErrorBoundary onError={onError}>
|
|
15
|
+
<ThreeDSecureFrame />
|
|
16
|
+
</ErrorBoundary>
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
expect(onError).toHaveBeenCalledWith(
|
|
20
|
+
new Error("`useEvervault` must be used within an `EvervaultProvider`.")
|
|
21
|
+
);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it("throws an error if used outside of a ThreeDSecure component", () => {
|
|
25
|
+
const onError = vi.fn();
|
|
26
|
+
render(
|
|
27
|
+
<ErrorBoundary onError={onError}>
|
|
28
|
+
<EvervaultProvider teamId="team_123" appId="app_123">
|
|
29
|
+
<ThreeDSecureFrame />
|
|
30
|
+
</EvervaultProvider>
|
|
31
|
+
</ErrorBoundary>
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
expect(onError).toHaveBeenCalledWith(
|
|
35
|
+
new Error(
|
|
36
|
+
"`ThreeDSecure.Frame` must be used within a `ThreeDSecure` component."
|
|
37
|
+
)
|
|
38
|
+
);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it("renders null if there is no session", () => {
|
|
42
|
+
const { queryByTestId } = render(
|
|
43
|
+
<EvervaultProvider teamId="team_123" appId="app_123">
|
|
44
|
+
<ThreeDSecure
|
|
45
|
+
state={{
|
|
46
|
+
session: null,
|
|
47
|
+
isVisible: false,
|
|
48
|
+
cancel: vi.fn(),
|
|
49
|
+
start: vi.fn(),
|
|
50
|
+
}}
|
|
51
|
+
>
|
|
52
|
+
<ThreeDSecureFrame />
|
|
53
|
+
</ThreeDSecure>
|
|
54
|
+
</EvervaultProvider>
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
expect(queryByTestId("webview")).toBeNull();
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it("renders a webview with the correct url", () => {
|
|
61
|
+
const { getByTestId } = render(
|
|
62
|
+
<EvervaultProvider teamId="team_123" appId="app_123">
|
|
63
|
+
<ThreeDSecure
|
|
64
|
+
state={{
|
|
65
|
+
session: {
|
|
66
|
+
sessionId: "session_123",
|
|
67
|
+
cancel: vi.fn(),
|
|
68
|
+
get: vi.fn(),
|
|
69
|
+
},
|
|
70
|
+
isVisible: true,
|
|
71
|
+
cancel: vi.fn(),
|
|
72
|
+
start: vi.fn(),
|
|
73
|
+
}}
|
|
74
|
+
>
|
|
75
|
+
<ThreeDSecureFrame />
|
|
76
|
+
</ThreeDSecure>
|
|
77
|
+
</EvervaultProvider>
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
const webview = getByTestId("webview");
|
|
81
|
+
expect(webview).toBeOnTheScreen();
|
|
82
|
+
expect(webview).toHaveProp("source", {
|
|
83
|
+
uri: `https://${CHALLENGE_DOMAIN_3DS}/?session=session_123&app=app_123&team=team_123`,
|
|
84
|
+
});
|
|
85
|
+
expect(webview).toHaveProp("hideKeyboardAccessoryView", true);
|
|
86
|
+
expect(webview).toHaveProp("overScrollMode", "content");
|
|
87
|
+
});
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { useContext, useMemo } from "react";
|
|
2
|
+
import { StyleProp, StyleSheet, ViewStyle } from "react-native";
|
|
3
|
+
import { useEvervault } from "../useEvervault";
|
|
4
|
+
import { WebView } from "react-native-webview";
|
|
5
|
+
import { CHALLENGE_DOMAIN_3DS } from "./config";
|
|
6
|
+
import { ThreeDSecureContext } from "./context";
|
|
7
|
+
|
|
8
|
+
export interface ThreeDSecureFrameProps {
|
|
9
|
+
style?: StyleProp<ViewStyle>;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function ThreeDSecureFrame({ style }: ThreeDSecureFrameProps) {
|
|
13
|
+
const evervault = useEvervault();
|
|
14
|
+
|
|
15
|
+
const context = useContext(ThreeDSecureContext);
|
|
16
|
+
if (!context) {
|
|
17
|
+
throw new Error(
|
|
18
|
+
"`ThreeDSecure.Frame` must be used within a `ThreeDSecure` component."
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const uri = useMemo(() => {
|
|
23
|
+
if (!context.session) return null;
|
|
24
|
+
|
|
25
|
+
const params = new URLSearchParams();
|
|
26
|
+
params.set("session", context.session.sessionId);
|
|
27
|
+
params.set("app", evervault.appId);
|
|
28
|
+
params.set("team", evervault.teamId);
|
|
29
|
+
|
|
30
|
+
return `https://${CHALLENGE_DOMAIN_3DS}/?${params.toString()}`;
|
|
31
|
+
}, [context.session, evervault.appId, evervault.teamId]);
|
|
32
|
+
|
|
33
|
+
if (!uri) return null;
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<WebView
|
|
37
|
+
containerStyle={[defaultStyles.webView, style]}
|
|
38
|
+
source={{ uri }}
|
|
39
|
+
hideKeyboardAccessoryView
|
|
40
|
+
overScrollMode="content"
|
|
41
|
+
/>
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const defaultStyles = StyleSheet.create({
|
|
46
|
+
webView: {
|
|
47
|
+
flex: 1,
|
|
48
|
+
width: "100%",
|
|
49
|
+
},
|
|
50
|
+
});
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { PropsWithChildren } from "react";
|
|
2
|
+
import { EvervaultProvider } from "../EvervaultProvider";
|
|
3
|
+
import { render, screen } from "@testing-library/react-native";
|
|
4
|
+
import { ThreeDSecure } from "./Root";
|
|
5
|
+
import { Text } from "react-native";
|
|
6
|
+
|
|
7
|
+
function wrapper({ children }: PropsWithChildren) {
|
|
8
|
+
return (
|
|
9
|
+
<EvervaultProvider teamId="team_123" appId="app_123">
|
|
10
|
+
{children}
|
|
11
|
+
</EvervaultProvider>
|
|
12
|
+
);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
it("renders null when the session is null", () => {
|
|
16
|
+
render(
|
|
17
|
+
<ThreeDSecure
|
|
18
|
+
state={{
|
|
19
|
+
session: null,
|
|
20
|
+
isVisible: false,
|
|
21
|
+
cancel: vi.fn(),
|
|
22
|
+
start: vi.fn(),
|
|
23
|
+
}}
|
|
24
|
+
>
|
|
25
|
+
<Text testID="child">Hello</Text>
|
|
26
|
+
</ThreeDSecure>,
|
|
27
|
+
{ wrapper }
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
expect(screen.queryByTestId("child")).toBeNull();
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it("renders null when the session is not visible", () => {
|
|
34
|
+
render(
|
|
35
|
+
<ThreeDSecure
|
|
36
|
+
state={{
|
|
37
|
+
session: { sessionId: "session_123", cancel: vi.fn(), get: vi.fn() },
|
|
38
|
+
isVisible: false,
|
|
39
|
+
cancel: vi.fn(),
|
|
40
|
+
start: vi.fn(),
|
|
41
|
+
}}
|
|
42
|
+
>
|
|
43
|
+
<Text testID="child">Hello</Text>
|
|
44
|
+
</ThreeDSecure>,
|
|
45
|
+
{ wrapper }
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
expect(screen.queryByTestId("child")).toBeNull();
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it("renders the children when the session defined and visible", () => {
|
|
52
|
+
render(
|
|
53
|
+
<ThreeDSecure
|
|
54
|
+
state={{
|
|
55
|
+
session: { sessionId: "session_123", cancel: vi.fn(), get: vi.fn() },
|
|
56
|
+
isVisible: true,
|
|
57
|
+
cancel: vi.fn(),
|
|
58
|
+
start: vi.fn(),
|
|
59
|
+
}}
|
|
60
|
+
>
|
|
61
|
+
<Text testID="child">Hello</Text>
|
|
62
|
+
</ThreeDSecure>,
|
|
63
|
+
{ wrapper }
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
expect(screen.getByTestId("child")).toBeOnTheScreen();
|
|
67
|
+
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { ThreeDSecureState } from "./types";
|
|
2
|
+
import { useEvervault } from "../useEvervault";
|
|
3
|
+
import { ThreeDSecureContext } from "./context";
|
|
4
|
+
import { PropsWithChildren } from "react";
|
|
5
|
+
|
|
6
|
+
export interface ThreeDSecureProps extends PropsWithChildren {
|
|
7
|
+
/**
|
|
8
|
+
* The 3DS session state returned from the `useThreeDSecure` hook.
|
|
9
|
+
*/
|
|
10
|
+
state: ThreeDSecureState;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function ThreeDSecure({ state, children }: ThreeDSecureProps) {
|
|
14
|
+
useEvervault();
|
|
15
|
+
|
|
16
|
+
if (!state.session) return null;
|
|
17
|
+
|
|
18
|
+
return (
|
|
19
|
+
<ThreeDSecureContext.Provider value={state}>
|
|
20
|
+
{state.isVisible && children}
|
|
21
|
+
</ThreeDSecureContext.Provider>
|
|
22
|
+
);
|
|
23
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { ThreeDSecure as ThreeDSecureRoot } from "./Root";
|
|
2
|
+
import { ThreeDSecureFrame } from "./Frame";
|
|
3
|
+
|
|
4
|
+
export const ThreeDSecure = Object.assign(ThreeDSecureRoot, {
|
|
5
|
+
Frame: ThreeDSecureFrame,
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
export type { ThreeDSecureProps } from "./Root";
|
|
9
|
+
export type { ThreeDSecureFrameProps } from "./Frame";
|
|
10
|
+
|
|
11
|
+
export type {
|
|
12
|
+
ThreeDSecureState,
|
|
13
|
+
ThreeDSecureSession,
|
|
14
|
+
ThreeDSecureCallbacks,
|
|
15
|
+
} from "./types";
|
|
16
|
+
|
|
17
|
+
export { useThreeDSecure } from "./useThreeDSecure";
|