@evervault/evervault-react-native 0.2.2 → 0.3.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 +52 -12
- package/android/build.gradle +5 -3
- package/android/gradle.properties +1 -1
- package/android/src/main/java/com/evervaultsdk/EvervaultSdkModule.kt +34 -5
- package/android/src/main/java/com/evervaultsdk/EvervaultSdkPackage.kt +1 -1
- package/evervault-react-native.podspec +1 -1
- package/lib/commonjs/components/Card/Card.js +115 -0
- package/lib/commonjs/components/Card/Card.js.map +1 -0
- package/lib/commonjs/components/Card/CardCVC.js +53 -0
- package/lib/commonjs/components/Card/CardCVC.js.map +1 -0
- package/lib/commonjs/components/Card/CardExpiry.js +40 -0
- package/lib/commonjs/components/Card/CardExpiry.js.map +1 -0
- package/lib/commonjs/components/Card/CardHolder.js +38 -0
- package/lib/commonjs/components/Card/CardHolder.js.map +1 -0
- package/lib/commonjs/components/Card/CardNumber.js +63 -0
- package/lib/commonjs/components/Card/CardNumber.js.map +1 -0
- package/lib/commonjs/components/Card/context.js +23 -0
- package/lib/commonjs/components/Card/context.js.map +1 -0
- package/lib/commonjs/components/Card/index.js +20 -0
- package/lib/commonjs/components/Card/index.js.map +1 -0
- package/lib/commonjs/components/Card/types.js +6 -0
- package/lib/commonjs/components/Card/types.js.map +1 -0
- package/lib/commonjs/components/Card/utilities.js +85 -0
- package/lib/commonjs/components/Card/utilities.js.map +1 -0
- package/lib/commonjs/components/Common/Error.js +2 -0
- package/lib/commonjs/components/Common/Error.js.map +1 -0
- package/lib/commonjs/components/index.js +3 -0
- package/lib/commonjs/components/index.js.map +1 -0
- package/lib/commonjs/index.js +18 -16
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/native.js +17 -0
- package/lib/commonjs/native.js.map +1 -0
- package/lib/commonjs/sdk.js +22 -0
- package/lib/commonjs/sdk.js.map +1 -0
- package/lib/module/components/Card/Card.js +110 -0
- package/lib/module/components/Card/Card.js.map +1 -0
- package/lib/module/components/Card/CardCVC.js +44 -0
- package/lib/module/components/Card/CardCVC.js.map +1 -0
- package/lib/module/components/Card/CardExpiry.js +34 -0
- package/lib/module/components/Card/CardExpiry.js.map +1 -0
- package/lib/module/components/Card/CardHolder.js +32 -0
- package/lib/module/components/Card/CardHolder.js.map +1 -0
- package/lib/module/components/Card/CardNumber.js +57 -0
- package/lib/module/components/Card/CardNumber.js.map +1 -0
- package/lib/module/components/Card/context.js +16 -0
- package/lib/module/components/Card/context.js.map +1 -0
- package/lib/module/components/Card/index.js +3 -0
- package/lib/module/components/Card/index.js.map +1 -0
- package/lib/module/components/Card/types.js +2 -0
- package/lib/module/components/Card/types.js.map +1 -0
- package/lib/module/components/Card/utilities.js +77 -0
- package/lib/module/components/Card/utilities.js.map +1 -0
- package/lib/module/components/Common/Error.js +2 -0
- package/lib/module/components/Common/Error.js.map +1 -0
- package/lib/module/components/index.js +2 -0
- package/lib/module/components/index.js.map +1 -0
- package/lib/module/index.js +2 -16
- package/lib/module/index.js.map +1 -1
- package/lib/module/native.js +11 -0
- package/lib/module/native.js.map +1 -0
- package/lib/module/sdk.js +15 -0
- package/lib/module/sdk.js.map +1 -0
- package/lib/typescript/src/components/Card/Card.d.ts +30 -0
- package/lib/typescript/src/components/Card/Card.d.ts.map +1 -0
- package/lib/typescript/src/components/Card/CardCVC.d.ts +6 -0
- package/lib/typescript/src/components/Card/CardCVC.d.ts.map +1 -0
- package/lib/typescript/src/components/Card/CardExpiry.d.ts +6 -0
- package/lib/typescript/src/components/Card/CardExpiry.d.ts.map +1 -0
- package/lib/typescript/src/components/Card/CardHolder.d.ts +7 -0
- package/lib/typescript/src/components/Card/CardHolder.d.ts.map +1 -0
- package/lib/typescript/src/components/Card/CardNumber.d.ts +8 -0
- package/lib/typescript/src/components/Card/CardNumber.d.ts.map +1 -0
- package/lib/typescript/src/components/Card/context.d.ts +13 -0
- package/lib/typescript/src/components/Card/context.d.ts.map +1 -0
- package/lib/typescript/src/components/Card/index.d.ts +3 -0
- package/lib/typescript/src/components/Card/index.d.ts.map +1 -0
- package/lib/typescript/src/components/Card/types.d.ts +13 -0
- package/lib/typescript/src/components/Card/types.d.ts.map +1 -0
- package/lib/typescript/src/components/Card/utilities.d.ts +8 -0
- package/lib/typescript/src/components/Card/utilities.d.ts.map +1 -0
- package/lib/typescript/src/components/Common/Error.d.ts +1 -0
- package/lib/typescript/src/components/Common/Error.d.ts.map +1 -0
- package/lib/typescript/src/components/index.d.ts +1 -0
- package/lib/typescript/src/components/index.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +3 -2
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/native.d.ts +2 -0
- package/lib/typescript/src/native.d.ts.map +1 -0
- package/lib/typescript/src/sdk.d.ts +3 -0
- package/lib/typescript/src/sdk.d.ts.map +1 -0
- package/package.json +29 -23
- package/src/components/Card/Card.tsx +156 -0
- package/src/components/Card/CardCVC.tsx +47 -0
- package/src/components/Card/CardExpiry.tsx +39 -0
- package/src/components/Card/CardHolder.tsx +39 -0
- package/src/components/Card/CardNumber.tsx +64 -0
- package/src/components/Card/context.tsx +26 -0
- package/src/components/Card/index.ts +2 -0
- package/src/components/Card/types.ts +15 -0
- package/src/components/Card/utilities.ts +105 -0
- package/src/components/Common/Error.tsx +0 -0
- package/src/components/index.ts +1 -0
- package/src/index.tsx +3 -26
- package/src/native.ts +18 -0
- package/src/sdk.ts +17 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { useEffect } from 'react';
|
|
2
|
+
import { TextInput } from 'react-native';
|
|
3
|
+
import { useCardContext } from './context';
|
|
4
|
+
import { BaseProps } from './Card';
|
|
5
|
+
|
|
6
|
+
export interface CardHolderProps extends BaseProps {
|
|
7
|
+
autoFocus?: boolean;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function CardHolder({
|
|
11
|
+
autoFocus,
|
|
12
|
+
disabled,
|
|
13
|
+
placeholder,
|
|
14
|
+
readOnly,
|
|
15
|
+
}: CardHolderProps) {
|
|
16
|
+
const context = useCardContext();
|
|
17
|
+
|
|
18
|
+
const { onBlur, onChange } = context.register('name');
|
|
19
|
+
|
|
20
|
+
useEffect(() => {
|
|
21
|
+
context.setRegisteredFields((prev) => new Set(prev).add('name'));
|
|
22
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
23
|
+
}, []);
|
|
24
|
+
|
|
25
|
+
return (
|
|
26
|
+
<TextInput
|
|
27
|
+
id="name"
|
|
28
|
+
value={context.values.name}
|
|
29
|
+
readOnly={readOnly}
|
|
30
|
+
onBlur={onBlur}
|
|
31
|
+
autoFocus={autoFocus}
|
|
32
|
+
editable={disabled}
|
|
33
|
+
selectTextOnFocus={disabled}
|
|
34
|
+
placeholder={placeholder}
|
|
35
|
+
autoComplete="cc-name"
|
|
36
|
+
onChangeText={(v) => onChange(v)}
|
|
37
|
+
/>
|
|
38
|
+
);
|
|
39
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { validateNumber } from '@evervault/card-validator';
|
|
2
|
+
import { useEffect, useMemo, useRef } from 'react';
|
|
3
|
+
import { TextInputMask } from 'react-native-masked-text';
|
|
4
|
+
import { useCardContext } from './context';
|
|
5
|
+
import { BaseProps } from './Card';
|
|
6
|
+
|
|
7
|
+
interface CardNumberProps extends BaseProps {
|
|
8
|
+
autoFocus?: boolean;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function CardNumber({
|
|
12
|
+
autoFocus,
|
|
13
|
+
disabled,
|
|
14
|
+
placeholder,
|
|
15
|
+
readOnly,
|
|
16
|
+
style,
|
|
17
|
+
}: CardNumberProps) {
|
|
18
|
+
const context = useCardContext();
|
|
19
|
+
const ref = useRef<TextInputMask>(null);
|
|
20
|
+
|
|
21
|
+
const [innerValue, mask] = useMemo(() => {
|
|
22
|
+
const value = context.values.number;
|
|
23
|
+
|
|
24
|
+
const { brand } = validateNumber(value);
|
|
25
|
+
|
|
26
|
+
const masks = {
|
|
27
|
+
'default': '9999 9999 9999 9999',
|
|
28
|
+
'unionpay': '9999 9999 9999 9999 999',
|
|
29
|
+
'american-express': '9999 999999 99999',
|
|
30
|
+
} as Record<string, string>;
|
|
31
|
+
|
|
32
|
+
if (brand && !!masks[brand]) {
|
|
33
|
+
return [value, masks[brand]];
|
|
34
|
+
}
|
|
35
|
+
return [value, masks.default];
|
|
36
|
+
}, [context.values.number]);
|
|
37
|
+
|
|
38
|
+
const { onBlur, onChange } = context.register('number');
|
|
39
|
+
|
|
40
|
+
useEffect(() => {
|
|
41
|
+
context.setRegisteredFields((prev) => new Set(prev).add('number'));
|
|
42
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
43
|
+
}, []);
|
|
44
|
+
|
|
45
|
+
return (
|
|
46
|
+
<TextInputMask
|
|
47
|
+
style={style}
|
|
48
|
+
ref={ref}
|
|
49
|
+
type="custom"
|
|
50
|
+
options={{ mask }}
|
|
51
|
+
id="number"
|
|
52
|
+
value={innerValue}
|
|
53
|
+
onChangeText={onChange}
|
|
54
|
+
onBlur={onBlur}
|
|
55
|
+
readOnly={readOnly}
|
|
56
|
+
inputMode="numeric"
|
|
57
|
+
autoFocus={autoFocus}
|
|
58
|
+
placeholder={placeholder}
|
|
59
|
+
editable={disabled}
|
|
60
|
+
selectTextOnFocus={disabled}
|
|
61
|
+
autoComplete="cc-number"
|
|
62
|
+
/>
|
|
63
|
+
);
|
|
64
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { UseFormReturn } from 'shared';
|
|
2
|
+
import { Dispatch, SetStateAction, createContext, useContext } from 'react';
|
|
3
|
+
import { CardForm } from './types';
|
|
4
|
+
import { CardField } from 'types';
|
|
5
|
+
|
|
6
|
+
type Context<T> = {
|
|
7
|
+
values: CardForm;
|
|
8
|
+
register: UseFormReturn<T>['register'];
|
|
9
|
+
setRegisteredFields: Dispatch<SetStateAction<Set<CardField>>>;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export const CardContext = createContext<Context<CardForm>>({
|
|
13
|
+
values: {
|
|
14
|
+
name: '',
|
|
15
|
+
number: '',
|
|
16
|
+
cvc: '',
|
|
17
|
+
expiry: '',
|
|
18
|
+
},
|
|
19
|
+
register: () => ({
|
|
20
|
+
onChange: () => { },
|
|
21
|
+
onBlur: () => { },
|
|
22
|
+
}),
|
|
23
|
+
setRegisteredFields: () => { },
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
export const useCardContext = () => useContext(CardContext);
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { CardBrandName } from 'types';
|
|
2
|
+
|
|
3
|
+
export interface CardConfig {
|
|
4
|
+
autoFocus?: boolean;
|
|
5
|
+
acceptedBrands?: CardBrandName[];
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface CardForm {
|
|
9
|
+
name: string;
|
|
10
|
+
number: string;
|
|
11
|
+
cvc: string;
|
|
12
|
+
expiry: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export { CardBrandName };
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import {
|
|
2
|
+
validateNumber,
|
|
3
|
+
validateExpiry,
|
|
4
|
+
validateCVC,
|
|
5
|
+
CardNumberValidationResult,
|
|
6
|
+
} from '@evervault/card-validator';
|
|
7
|
+
import type { CardForm } from './types';
|
|
8
|
+
import type { CardBrandName, CardField, CardPayload } from 'types';
|
|
9
|
+
import { UseFormReturn } from 'shared';
|
|
10
|
+
|
|
11
|
+
export async function changePayload(
|
|
12
|
+
encrypt: (value: string) => Promise<string>,
|
|
13
|
+
form: UseFormReturn<CardForm>,
|
|
14
|
+
fields: CardField[]
|
|
15
|
+
): Promise<CardPayload> {
|
|
16
|
+
const { name, number, expiry, cvc } = form.values;
|
|
17
|
+
const {
|
|
18
|
+
brand,
|
|
19
|
+
localBrands,
|
|
20
|
+
bin,
|
|
21
|
+
lastFour,
|
|
22
|
+
isValid: isValidCardNumber,
|
|
23
|
+
} = validateNumber(number);
|
|
24
|
+
|
|
25
|
+
return {
|
|
26
|
+
card: {
|
|
27
|
+
name,
|
|
28
|
+
brand,
|
|
29
|
+
localBrands,
|
|
30
|
+
bin,
|
|
31
|
+
lastFour,
|
|
32
|
+
number: isValidCardNumber ? await encryptedNumber(encrypt, number) : null,
|
|
33
|
+
expiry: formatExpiry(expiry),
|
|
34
|
+
cvc: await encryptedCVC(encrypt, cvc, number),
|
|
35
|
+
},
|
|
36
|
+
isValid: form.isValid,
|
|
37
|
+
isComplete: isComplete(form, fields),
|
|
38
|
+
errors: Object.keys(form.errors ?? {}).length > 0 ? form.errors : null,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function isComplete(form: UseFormReturn<CardForm>, fields: CardField[]) {
|
|
43
|
+
if (fields.includes('name')) {
|
|
44
|
+
if (form.values.name.length === 0) return false;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (fields.includes('number')) {
|
|
48
|
+
const cardValidation = validateNumber(form.values.number);
|
|
49
|
+
if (!cardValidation.isValid) return false;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (fields.includes('expiry')) {
|
|
53
|
+
const expiryValidation = validateExpiry(form.values.expiry.replace(" / ", ""));
|
|
54
|
+
if (!expiryValidation.isValid) return false;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (fields.includes('cvc')) {
|
|
58
|
+
const cvcValidation = validateCVC(form.values.cvc, form.values.number);
|
|
59
|
+
if (!cvcValidation.isValid) return false;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function isAcceptedBrand(
|
|
66
|
+
acceptedBrands: CardBrandName[] | undefined,
|
|
67
|
+
cardNumberValidationResult: CardNumberValidationResult
|
|
68
|
+
): boolean {
|
|
69
|
+
if (!acceptedBrands) return true;
|
|
70
|
+
const { brand, localBrands } = cardNumberValidationResult;
|
|
71
|
+
|
|
72
|
+
const isBrandAccepted = brand !== null && acceptedBrands.includes(brand);
|
|
73
|
+
const isLocalBrandAccepted = localBrands.some((localBrand) =>
|
|
74
|
+
acceptedBrands.includes(localBrand)
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
return isBrandAccepted || isLocalBrandAccepted;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function formatExpiry(expiry: string) {
|
|
81
|
+
const parsedExpiry = validateExpiry(expiry.replace(" / ", ""));
|
|
82
|
+
|
|
83
|
+
return {
|
|
84
|
+
month: parsedExpiry.month,
|
|
85
|
+
year: parsedExpiry.year,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
async function encryptedNumber(
|
|
90
|
+
encrypt: (value: string) => Promise<string>,
|
|
91
|
+
number: string
|
|
92
|
+
) {
|
|
93
|
+
return encrypt(number);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
async function encryptedCVC(
|
|
97
|
+
encrypt: (value: string) => Promise<string>,
|
|
98
|
+
cvc: string,
|
|
99
|
+
cardNumber: string
|
|
100
|
+
) {
|
|
101
|
+
const { isValid } = validateCVC(cvc, cardNumber);
|
|
102
|
+
|
|
103
|
+
if (!isValid) return null;
|
|
104
|
+
return encrypt(cvc);
|
|
105
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
// export * from './Card';
|
package/src/index.tsx
CHANGED
|
@@ -1,26 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
`The package '@evervault/evervault-react-native' doesn't seem to be linked. Make sure: \n\n` +
|
|
5
|
-
Platform.select({ ios: "- You have run 'pod install'\n", default: '' }) +
|
|
6
|
-
'- You rebuilt the app after installing the package\n' +
|
|
7
|
-
'- You are not using Expo Go\n';
|
|
8
|
-
|
|
9
|
-
const EvervaultSdk = NativeModules.EvervaultSdk
|
|
10
|
-
? NativeModules.EvervaultSdk
|
|
11
|
-
: new Proxy(
|
|
12
|
-
{},
|
|
13
|
-
{
|
|
14
|
-
get() {
|
|
15
|
-
throw new Error(LINKING_ERROR);
|
|
16
|
-
},
|
|
17
|
-
}
|
|
18
|
-
);
|
|
19
|
-
|
|
20
|
-
export async function init(teamUuid: string, appUuid: string): Promise<void> {
|
|
21
|
-
return EvervaultSdk.initialize(teamUuid, appUuid);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export async function encrypt(data: any): Promise<string> {
|
|
25
|
-
return EvervaultSdk.encrypt(data);
|
|
26
|
-
}
|
|
1
|
+
export { type CardProps, Card } from './components/Card/Card';
|
|
2
|
+
export { init, encrypt } from './sdk';
|
|
3
|
+
export type { CardPayload, CardExpiry } from 'types';
|
package/src/native.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { NativeModules, Platform } from 'react-native';
|
|
2
|
+
|
|
3
|
+
const LINKING_ERROR =
|
|
4
|
+
`The package '@evervault/evervault-react-native' doesn't seem to be linked. Make sure: \n\n` +
|
|
5
|
+
Platform.select({ ios: "- You have run 'pod install'\n", default: '' }) +
|
|
6
|
+
'- You rebuilt the app after installing the package\n' +
|
|
7
|
+
'- You are not using Expo Go\n';
|
|
8
|
+
|
|
9
|
+
export const EvervaultSdk = NativeModules.EvervaultSdk
|
|
10
|
+
? NativeModules.EvervaultSdk
|
|
11
|
+
: new Proxy(
|
|
12
|
+
{},
|
|
13
|
+
{
|
|
14
|
+
get() {
|
|
15
|
+
throw new Error(LINKING_ERROR);
|
|
16
|
+
},
|
|
17
|
+
}
|
|
18
|
+
);
|
package/src/sdk.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Platform } from "react-native";
|
|
2
|
+
import { EvervaultSdk } from "./native";
|
|
3
|
+
|
|
4
|
+
export async function init(teamUuid: string, appUuid: string): Promise<void> {
|
|
5
|
+
return EvervaultSdk.initialize(teamUuid, appUuid);
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export async function encrypt(data: any): Promise<string> {
|
|
9
|
+
if (Platform.OS === "android" && typeof data !== "string") {
|
|
10
|
+
throw new Error(`The Evervault SDK does not currently support encrypting non-string data on Android.
|
|
11
|
+
If this is required for your use case, please get in touch with us at support@evervault.com. Please do not
|
|
12
|
+
serialize other data types to strings and pass them to this method as this will result in the data
|
|
13
|
+
type being returned in it's stringified form when decryption occurs.`);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return EvervaultSdk.encrypt(data.toString());
|
|
17
|
+
}
|