react-native-fpay 0.1.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 (167) hide show
  1. package/Fpay.podspec +20 -0
  2. package/LICENSE +20 -0
  3. package/README.md +37 -0
  4. package/android/build.gradle +67 -0
  5. package/android/src/main/AndroidManifest.xml +2 -0
  6. package/android/src/main/java/com/fpay/FpayModule.kt +15 -0
  7. package/android/src/main/java/com/fpay/FpayPackage.kt +31 -0
  8. package/ios/Fpay.h +5 -0
  9. package/ios/Fpay.mm +21 -0
  10. package/lib/module/FountainPayProvider.js +18 -0
  11. package/lib/module/FountainPayProvider.js.map +1 -0
  12. package/lib/module/core/api/client.js +47 -0
  13. package/lib/module/core/api/client.js.map +1 -0
  14. package/lib/module/core/api/index.js +35 -0
  15. package/lib/module/core/api/index.js.map +1 -0
  16. package/lib/module/core/types/index.js +4 -0
  17. package/lib/module/core/types/index.js.map +1 -0
  18. package/lib/module/engine/BLEReceiverService.js +190 -0
  19. package/lib/module/engine/BLEReceiverService.js.map +1 -0
  20. package/lib/module/engine/BLESenderService.js +259 -0
  21. package/lib/module/engine/BLESenderService.js.map +1 -0
  22. package/lib/module/engine/FPEngine.js +340 -0
  23. package/lib/module/engine/FPEngine.js.map +1 -0
  24. package/lib/module/engine/NearbyUsersService.js +87 -0
  25. package/lib/module/engine/NearbyUsersService.js.map +1 -0
  26. package/lib/module/index.js +16 -0
  27. package/lib/module/index.js.map +1 -0
  28. package/lib/module/package.json +1 -0
  29. package/lib/module/ui/components/FPButton.js +71 -0
  30. package/lib/module/ui/components/FPButton.js.map +1 -0
  31. package/lib/module/ui/components/LoadingAnimation/InLoading.js +74 -0
  32. package/lib/module/ui/components/LoadingAnimation/InLoading.js.map +1 -0
  33. package/lib/module/ui/components/LoadingAnimation/index.js +82 -0
  34. package/lib/module/ui/components/LoadingAnimation/index.js.map +1 -0
  35. package/lib/module/ui/components/OtpInput/OTPInputView.js +290 -0
  36. package/lib/module/ui/components/OtpInput/OTPInputView.js.map +1 -0
  37. package/lib/module/ui/components/OtpInput/Styles.js +20 -0
  38. package/lib/module/ui/components/OtpInput/Styles.js.map +1 -0
  39. package/lib/module/ui/components/OtpInput/helpers/codeToArray.js +7 -0
  40. package/lib/module/ui/components/OtpInput/helpers/codeToArray.js.map +1 -0
  41. package/lib/module/ui/components/OtpInput/helpers/device.js +9 -0
  42. package/lib/module/ui/components/OtpInput/helpers/device.js.map +1 -0
  43. package/lib/module/ui/components/OtpInput/helpers/styles.js +17 -0
  44. package/lib/module/ui/components/OtpInput/helpers/styles.js.map +1 -0
  45. package/lib/module/ui/components/OtpInput/helpers/types.js +4 -0
  46. package/lib/module/ui/components/OtpInput/helpers/types.js.map +1 -0
  47. package/lib/module/ui/components/OtpInput/index.js +45 -0
  48. package/lib/module/ui/components/OtpInput/index.js.map +1 -0
  49. package/lib/module/ui/components/PulseAnimation.js +61 -0
  50. package/lib/module/ui/components/PulseAnimation.js.map +1 -0
  51. package/lib/module/ui/modals/FPPaymentRequestModal.js +253 -0
  52. package/lib/module/ui/modals/FPPaymentRequestModal.js.map +1 -0
  53. package/lib/module/ui/modals/FPShell.js +180 -0
  54. package/lib/module/ui/modals/FPShell.js.map +1 -0
  55. package/lib/module/ui/screens/ReceiveScreen.js +291 -0
  56. package/lib/module/ui/screens/ReceiveScreen.js.map +1 -0
  57. package/lib/module/ui/screens/SendScreen.js +216 -0
  58. package/lib/module/ui/screens/SendScreen.js.map +1 -0
  59. package/lib/module/ui/screens/sub/BluetoothSubScreen.js +403 -0
  60. package/lib/module/ui/screens/sub/BluetoothSubScreen.js.map +1 -0
  61. package/lib/module/ui/screens/sub/NFCSubScreen.js +169 -0
  62. package/lib/module/ui/screens/sub/NFCSubScreen.js.map +1 -0
  63. package/lib/module/ui/screens/sub/NQRSubScreen.js +136 -0
  64. package/lib/module/ui/screens/sub/NQRSubScreen.js.map +1 -0
  65. package/lib/module/ui/screens/sub/ProximitySubScreen.js +501 -0
  66. package/lib/module/ui/screens/sub/ProximitySubScreen.js.map +1 -0
  67. package/lib/module/ui/screens/sub/TransferSubScreen.js +361 -0
  68. package/lib/module/ui/screens/sub/TransferSubScreen.js.map +1 -0
  69. package/lib/module/ui/theme/index.js +64 -0
  70. package/lib/module/ui/theme/index.js.map +1 -0
  71. package/lib/module/useFountainPay.js +82 -0
  72. package/lib/module/useFountainPay.js.map +1 -0
  73. package/lib/typescript/package.json +1 -0
  74. package/lib/typescript/src/FountainPayProvider.d.ts +7 -0
  75. package/lib/typescript/src/FountainPayProvider.d.ts.map +1 -0
  76. package/lib/typescript/src/core/api/client.d.ts +7 -0
  77. package/lib/typescript/src/core/api/client.d.ts.map +1 -0
  78. package/lib/typescript/src/core/api/index.d.ts +67 -0
  79. package/lib/typescript/src/core/api/index.d.ts.map +1 -0
  80. package/lib/typescript/src/core/types/index.d.ts +130 -0
  81. package/lib/typescript/src/core/types/index.d.ts.map +1 -0
  82. package/lib/typescript/src/engine/BLEReceiverService.d.ts +43 -0
  83. package/lib/typescript/src/engine/BLEReceiverService.d.ts.map +1 -0
  84. package/lib/typescript/src/engine/BLESenderService.d.ts +39 -0
  85. package/lib/typescript/src/engine/BLESenderService.d.ts.map +1 -0
  86. package/lib/typescript/src/engine/FPEngine.d.ts +24 -0
  87. package/lib/typescript/src/engine/FPEngine.d.ts.map +1 -0
  88. package/lib/typescript/src/engine/NearbyUsersService.d.ts +19 -0
  89. package/lib/typescript/src/engine/NearbyUsersService.d.ts.map +1 -0
  90. package/lib/typescript/src/index.d.ts +4 -0
  91. package/lib/typescript/src/index.d.ts.map +1 -0
  92. package/lib/typescript/src/ui/components/FPButton.d.ts +12 -0
  93. package/lib/typescript/src/ui/components/FPButton.d.ts.map +1 -0
  94. package/lib/typescript/src/ui/components/LoadingAnimation/InLoading.d.ts +7 -0
  95. package/lib/typescript/src/ui/components/LoadingAnimation/InLoading.d.ts.map +1 -0
  96. package/lib/typescript/src/ui/components/LoadingAnimation/index.d.ts +6 -0
  97. package/lib/typescript/src/ui/components/LoadingAnimation/index.d.ts.map +1 -0
  98. package/lib/typescript/src/ui/components/OtpInput/OTPInputView.d.ts +29 -0
  99. package/lib/typescript/src/ui/components/OtpInput/OTPInputView.d.ts.map +1 -0
  100. package/lib/typescript/src/ui/components/OtpInput/Styles.d.ts +330 -0
  101. package/lib/typescript/src/ui/components/OtpInput/Styles.d.ts.map +1 -0
  102. package/lib/typescript/src/ui/components/OtpInput/helpers/codeToArray.d.ts +6 -0
  103. package/lib/typescript/src/ui/components/OtpInput/helpers/codeToArray.d.ts.map +1 -0
  104. package/lib/typescript/src/ui/components/OtpInput/helpers/device.d.ts +6 -0
  105. package/lib/typescript/src/ui/components/OtpInput/helpers/device.d.ts.map +1 -0
  106. package/lib/typescript/src/ui/components/OtpInput/helpers/styles.d.ts +6 -0
  107. package/lib/typescript/src/ui/components/OtpInput/helpers/styles.d.ts.map +1 -0
  108. package/lib/typescript/src/ui/components/OtpInput/helpers/types.d.ts +84 -0
  109. package/lib/typescript/src/ui/components/OtpInput/helpers/types.d.ts.map +1 -0
  110. package/lib/typescript/src/ui/components/OtpInput/index.d.ts +9 -0
  111. package/lib/typescript/src/ui/components/OtpInput/index.d.ts.map +1 -0
  112. package/lib/typescript/src/ui/components/PulseAnimation.d.ts +2 -0
  113. package/lib/typescript/src/ui/components/PulseAnimation.d.ts.map +1 -0
  114. package/lib/typescript/src/ui/modals/FPPaymentRequestModal.d.ts +2 -0
  115. package/lib/typescript/src/ui/modals/FPPaymentRequestModal.d.ts.map +1 -0
  116. package/lib/typescript/src/ui/modals/FPShell.d.ts +2 -0
  117. package/lib/typescript/src/ui/modals/FPShell.d.ts.map +1 -0
  118. package/lib/typescript/src/ui/screens/ReceiveScreen.d.ts +10 -0
  119. package/lib/typescript/src/ui/screens/ReceiveScreen.d.ts.map +1 -0
  120. package/lib/typescript/src/ui/screens/SendScreen.d.ts +9 -0
  121. package/lib/typescript/src/ui/screens/SendScreen.d.ts.map +1 -0
  122. package/lib/typescript/src/ui/screens/sub/BluetoothSubScreen.d.ts +552 -0
  123. package/lib/typescript/src/ui/screens/sub/BluetoothSubScreen.d.ts.map +1 -0
  124. package/lib/typescript/src/ui/screens/sub/NFCSubScreen.d.ts +19 -0
  125. package/lib/typescript/src/ui/screens/sub/NFCSubScreen.d.ts.map +1 -0
  126. package/lib/typescript/src/ui/screens/sub/NQRSubScreen.d.ts +13 -0
  127. package/lib/typescript/src/ui/screens/sub/NQRSubScreen.d.ts.map +1 -0
  128. package/lib/typescript/src/ui/screens/sub/ProximitySubScreen.d.ts +552 -0
  129. package/lib/typescript/src/ui/screens/sub/ProximitySubScreen.d.ts.map +1 -0
  130. package/lib/typescript/src/ui/screens/sub/TransferSubScreen.d.ts +12 -0
  131. package/lib/typescript/src/ui/screens/sub/TransferSubScreen.d.ts.map +1 -0
  132. package/lib/typescript/src/ui/theme/index.d.ts +62 -0
  133. package/lib/typescript/src/ui/theme/index.d.ts.map +1 -0
  134. package/lib/typescript/src/useFountainPay.d.ts +3 -0
  135. package/lib/typescript/src/useFountainPay.d.ts.map +1 -0
  136. package/package.json +217 -0
  137. package/src/FountainPayProvider.tsx +21 -0
  138. package/src/core/api/client.ts +47 -0
  139. package/src/core/api/index.ts +61 -0
  140. package/src/core/types/index.ts +144 -0
  141. package/src/engine/BLEReceiverService.ts +244 -0
  142. package/src/engine/BLESenderService.ts +314 -0
  143. package/src/engine/FPEngine.ts +370 -0
  144. package/src/engine/NearbyUsersService.ts +106 -0
  145. package/src/index.ts +30 -0
  146. package/src/ui/components/FPButton.tsx +42 -0
  147. package/src/ui/components/LoadingAnimation/InLoading.tsx +88 -0
  148. package/src/ui/components/LoadingAnimation/index.tsx +93 -0
  149. package/src/ui/components/OtpInput/OTPInputView.tsx +243 -0
  150. package/src/ui/components/OtpInput/Styles.ts +19 -0
  151. package/src/ui/components/OtpInput/helpers/codeToArray.ts +3 -0
  152. package/src/ui/components/OtpInput/helpers/device.ts +6 -0
  153. package/src/ui/components/OtpInput/helpers/styles.ts +17 -0
  154. package/src/ui/components/OtpInput/helpers/types.ts +88 -0
  155. package/src/ui/components/OtpInput/index.tsx +51 -0
  156. package/src/ui/components/PulseAnimation.tsx +78 -0
  157. package/src/ui/modals/FPPaymentRequestModal.tsx +158 -0
  158. package/src/ui/modals/FPShell.tsx +107 -0
  159. package/src/ui/screens/ReceiveScreen.tsx +119 -0
  160. package/src/ui/screens/SendScreen.tsx +86 -0
  161. package/src/ui/screens/sub/BluetoothSubScreen.tsx +433 -0
  162. package/src/ui/screens/sub/NFCSubScreen.tsx +83 -0
  163. package/src/ui/screens/sub/NQRSubScreen.tsx +61 -0
  164. package/src/ui/screens/sub/ProximitySubScreen.tsx +390 -0
  165. package/src/ui/screens/sub/TransferSubScreen.tsx +146 -0
  166. package/src/ui/theme/index.ts +24 -0
  167. package/src/useFountainPay.ts +95 -0
@@ -0,0 +1,93 @@
1
+ import React, { useEffect, useRef, useState } from 'react';
2
+ import { Modal } from 'react-native';
3
+ import styled from 'styled-components/native';
4
+ import { Animated, Easing } from "react-native";
5
+ import Svg, { Circle, G } from "react-native-svg";
6
+
7
+
8
+ type Props = {
9
+ text?: string;
10
+ };
11
+
12
+ const Overlay = styled.View`
13
+ position: absolute;
14
+ top: 0;
15
+ right: 0;
16
+ bottom: 0;
17
+ left: 0;
18
+
19
+ align-items: center;
20
+ justify-content: center;
21
+
22
+ background-color: rgba(100, 100, 100, 0.2);
23
+ `;
24
+
25
+ const IndicatorContainer = styled.View`
26
+ padding: 12px;
27
+ background-color: #ffffff;
28
+ border-radius: 12px;
29
+ align-items: center;
30
+ `;
31
+
32
+ const IndicatorText = styled.Text`
33
+ font-size: 18px;
34
+ margin-top: 12px;
35
+ color: #003333;
36
+ `;
37
+
38
+
39
+ const AnimatedSvg = Animated.createAnimatedComponent(Svg);
40
+
41
+ const LoadingAnimation = ({ text = 'Loading...' }: Props) => {
42
+ const [color, setColor] = useState<'teal' | 'royalblue'>('teal');
43
+
44
+ const rotate = useRef(new Animated.Value(0)).current;
45
+
46
+ useEffect(() => {
47
+ Animated.loop(
48
+ Animated.timing(rotate, {
49
+ toValue: 1,
50
+ duration: 800,
51
+ easing: Easing.linear,
52
+ useNativeDriver: true,
53
+ })
54
+ ).start();
55
+ }, [rotate]);
56
+
57
+ const spin = rotate.interpolate({
58
+ inputRange: [0, 1],
59
+ outputRange: ["0deg", "360deg"],
60
+ });
61
+
62
+
63
+
64
+ return (
65
+ <Modal transparent animationType="none">
66
+ <Overlay>
67
+ <IndicatorContainer>
68
+ <AnimatedSvg
69
+ width={80}
70
+ height={80}
71
+ viewBox="0 0 100 100"
72
+ style={{ transform: [{ rotate: spin }] }}
73
+ >
74
+ <G>
75
+ <Circle
76
+ cx="50"
77
+ cy="50"
78
+ r="33"
79
+ stroke="#0a3d2e"
80
+ strokeWidth="4"
81
+ strokeLinecap="round"
82
+ strokeDasharray="52 52"
83
+ fill="none"
84
+ />
85
+ </G>
86
+ </AnimatedSvg>
87
+ </IndicatorContainer>
88
+ </Overlay>
89
+ </Modal>
90
+ );
91
+ };
92
+
93
+ export default LoadingAnimation;
@@ -0,0 +1,243 @@
1
+ import type { InputProps, OTPInputViewState } from './helpers/types';
2
+ import React, { Component } from 'react'
3
+ import { View, TextInput, TouchableWithoutFeedback, Keyboard, Platform, I18nManager, type EmitterSubscription, } from 'react-native'
4
+ import Clipboard from '@react-native-community/clipboard';
5
+ import styles from './helpers/styles'
6
+ import { isAutoFillSupported } from './helpers/device'
7
+ import { codeToArray } from './helpers/codeToArray'
8
+
9
+
10
+ type TextInputRef = React.ElementRef<typeof TextInput>;
11
+
12
+ export default class OTPInputView extends Component<InputProps, OTPInputViewState> {
13
+
14
+ private fields: Array<TextInputRef | null> = [];
15
+
16
+ private keyboardDidHideListener?: EmitterSubscription;
17
+ private timer?: NodeJS.Timeout;
18
+ private hasCheckedClipBoard?: boolean;
19
+ private clipBoardCode?: string;
20
+
21
+ constructor(props: InputProps) {
22
+ super(props)
23
+ const { code } = props
24
+ this.state = {
25
+ digits: codeToArray(code),
26
+ selectedIndex: props.autoFocusOnLoad ? 0 : -1,
27
+ }
28
+ }
29
+
30
+ UNSAFE_componentWillReceiveProps(nextProps: InputProps) {
31
+ const { code } = this.props
32
+ if (nextProps.code !== code) {
33
+ this.setState({ digits: codeToArray(nextProps.code) })
34
+ }
35
+ }
36
+
37
+ componentDidMount() {
38
+ this.copyCodeFromClipBoardOnAndroid()
39
+ this.bringUpKeyBoardIfNeeded()
40
+ this.keyboardDidHideListener = Keyboard.addListener('keyboardDidHide', this.handleKeyboardDidHide)
41
+ }
42
+
43
+ componentWillUnmount() {
44
+ if (this.timer) {
45
+ clearInterval(this.timer)
46
+ }
47
+ this.keyboardDidHideListener?.remove()
48
+ }
49
+
50
+ private copyCodeFromClipBoardOnAndroid = () => {
51
+ if (Platform.OS === "android") {
52
+ this.checkPinCodeFromClipBoard()
53
+ this.timer = setInterval(this.checkPinCodeFromClipBoard, 400)
54
+ }
55
+ }
56
+
57
+ bringUpKeyBoardIfNeeded = () => {
58
+ const { autoFocusOnLoad, pinCount } = this.props
59
+ const digits = this.getDigits()
60
+ const focusIndex = digits.length ? digits.length - 1 : 0
61
+ if (focusIndex < pinCount && autoFocusOnLoad) {
62
+ this.focusField(focusIndex)
63
+ }
64
+ }
65
+
66
+ getDigits = () => {
67
+ const { digits: innerDigits } = this.state
68
+ const { code } = this.props
69
+ return code === undefined ? innerDigits : code.split("")
70
+ }
71
+
72
+ private handleKeyboardDidHide = () => {
73
+ this.blurAllFields()
74
+ }
75
+
76
+ private notifyCodeChanged = () => {
77
+ const { digits } = this.state
78
+ const code = digits.join("")
79
+ const { onCodeChanged } = this.props
80
+ if (onCodeChanged) {
81
+ onCodeChanged(code)
82
+ }
83
+ }
84
+
85
+ checkPinCodeFromClipBoard = () => {
86
+ const { pinCount, onCodeFilled } = this.props
87
+ const regexp = new RegExp(`^\\d{${pinCount}}$`)
88
+ Clipboard.getString().then(code => {
89
+ if (this.hasCheckedClipBoard && regexp.test(code) && (this.clipBoardCode !== code)) {
90
+ this.setState({
91
+ digits: code.split(""),
92
+ }, () => {
93
+ this.blurAllFields()
94
+ this.notifyCodeChanged()
95
+ onCodeFilled && onCodeFilled(code)
96
+ })
97
+ }
98
+ this.clipBoardCode = code
99
+ this.hasCheckedClipBoard = true
100
+ }).catch(() => {
101
+ })
102
+ }
103
+
104
+ private handleChangeText = (index: number, text: string) => {
105
+ const { onCodeFilled, pinCount } = this.props
106
+ const digits = this.getDigits()
107
+ let newdigits: any = digits.slice()
108
+ const oldTextLength = newdigits[index] ? newdigits[index].length : 0
109
+ const newTextLength = text.length
110
+ if (newTextLength - oldTextLength === pinCount) { // user pasted text in.
111
+ newdigits = text.split("").slice(oldTextLength, newTextLength)
112
+ this.setState({ digits: newdigits }, this.notifyCodeChanged)
113
+ } else {
114
+ if (text.length === 0) {
115
+ if (newdigits.length > 0) {
116
+ newdigits = newdigits.slice(0, newdigits.length - 1)
117
+ }
118
+ } else {
119
+ text.split("").forEach((value) => {
120
+ if(index < pinCount) {
121
+ newdigits[index] = value;
122
+ index += 1;
123
+ }
124
+ })
125
+ index -= 1
126
+ }
127
+ this.setState({ digits: newdigits }, this.notifyCodeChanged)
128
+ }
129
+
130
+ let result = newdigits.join("")
131
+ if (result.length >= pinCount) {
132
+ onCodeFilled && onCodeFilled(result)
133
+ this.focusField(pinCount - 1)
134
+ this.blurAllFields()
135
+ } else {
136
+ if (text.length > 0 && index < pinCount - 1) {
137
+ this.focusField(index + 1)
138
+ }
139
+ }
140
+ }
141
+
142
+ private handleKeyPressTextInput = (index: number, key: string) => {
143
+ const digits = this.getDigits()
144
+ if (key === 'Backspace') {
145
+ if (!digits[index] && index > 0) {
146
+ this.handleChangeText(index - 1, '')
147
+ this.focusField(index - 1)
148
+ }
149
+ }
150
+ }
151
+
152
+
153
+
154
+ focusField = (index: number) => {
155
+ if (index < this.fields.length) {
156
+ this.fields[index]?.focus();
157
+ this.setState({ selectedIndex: index });
158
+ }
159
+ }
160
+
161
+ blurAllFields = () => {
162
+ this.fields.forEach(field => field?.blur());
163
+ this.setState({ selectedIndex: -1 });
164
+ }
165
+
166
+
167
+ clearAllFields = () => {
168
+ const { clearInputs, code } = this.props;
169
+ if (clearInputs && code === "") {
170
+ this.setState({ digits: [], selectedIndex: 0 })
171
+ }
172
+ }
173
+
174
+ renderOneInputField = (_: TextInput, index: number) => {
175
+ const { codeInputFieldStyle, codeInputHighlightStyle, secureTextEntry, editable, keyboardType, selectionColor, keyboardAppearance, showSoftInputOnFocus } = this.props
176
+ const { defaultTextFieldStyle } = styles
177
+ const { selectedIndex, digits } = this.state
178
+ const { clearInputs, placeholderCharacter, placeholderTextColor } = this.props
179
+ const { color: defaultPlaceholderTextColor } = { ...defaultTextFieldStyle, ...codeInputFieldStyle }
180
+ return (
181
+ <View pointerEvents="none" key={index + "view"} testID="inputSlotView">
182
+ <TextInput
183
+ testID="textInput"
184
+ underlineColorAndroid='rgba(0,0,0,0)'
185
+ style={selectedIndex === index ? [defaultTextFieldStyle, codeInputFieldStyle, codeInputHighlightStyle] : [defaultTextFieldStyle, codeInputFieldStyle]}
186
+ ref={(ref) => {
187
+ this.fields[index] = ref;
188
+ }}
189
+ onChangeText={text => {
190
+ this.handleChangeText(index, text)
191
+ }}
192
+ onKeyPress={({ nativeEvent: { key } }) => { this.handleKeyPressTextInput(index, key) }}
193
+ value={ !clearInputs ? digits[index]: "" }
194
+ keyboardAppearance={keyboardAppearance}
195
+ keyboardType={keyboardType}
196
+ textContentType={isAutoFillSupported ? "oneTimeCode" : "none"}
197
+ key={index}
198
+ selectionColor={selectionColor}
199
+ secureTextEntry={secureTextEntry}
200
+ // showSoftInputOnFocus={showSoftInputOnFocus}
201
+ editable={editable}
202
+ placeholder={placeholderCharacter}
203
+ placeholderTextColor={placeholderTextColor || defaultPlaceholderTextColor}
204
+ />
205
+ </View>
206
+ )
207
+ }
208
+
209
+ renderTextFields = () => {
210
+ const { pinCount } = this.props
211
+ const array = new Array(pinCount).fill(0)
212
+ return array.map(this.renderOneInputField)
213
+ }
214
+
215
+ render() {
216
+ const { pinCount, style, clearInputs } = this.props
217
+ const digits = this.getDigits()
218
+ return (
219
+ <View
220
+ testID="OTPInputView"
221
+ style={style}
222
+ >
223
+ <TouchableWithoutFeedback
224
+ onPress={() => {
225
+ if (!clearInputs) {
226
+ let filledPinCount = digits.filter((digit) => { return (digit !== null && digit !== undefined) }).length
227
+ this.focusField(Math.min(filledPinCount, pinCount - 1))
228
+ } else {
229
+ this.clearAllFields();
230
+ this.focusField(0)
231
+ }
232
+ }}
233
+ >
234
+ <View
235
+ style={{ flexDirection: 'row', justifyContent: 'center', alignItems: 'center', width: '100%', height: 100 , gap: '10px' }}
236
+ >
237
+ {this.renderTextFields()}
238
+ </View>
239
+ </TouchableWithoutFeedback>
240
+ </View>
241
+ );
242
+ }
243
+ }
@@ -0,0 +1,19 @@
1
+ import styled from "styled-components/native";
2
+
3
+ export const HideInput = styled.TextInput`
4
+ width: 80%;
5
+ margin: auto;
6
+ padding: 14px 8px;
7
+ border: 1px solid #000;
8
+ display: none;
9
+ `;
10
+
11
+ export const Otpinput = styled.View`
12
+ width: 50px;
13
+ height: 50px;
14
+ border-radius: 8px;
15
+ border: 1px solid #333;
16
+ display: flex;
17
+ align-items: center;
18
+ justify-content: center;
19
+ `;
@@ -0,0 +1,3 @@
1
+ export const codeToArray = (code?: string): string[] => code?.split("") ?? [];
2
+
3
+ export default { codeToArray }
@@ -0,0 +1,6 @@
1
+ import { Platform } from 'react-native'
2
+
3
+ const majorVersionIOS = parseInt(String(Platform.Version), 10);
4
+ export const isAutoFillSupported = (Platform.OS === 'ios' && majorVersionIOS >= 12)
5
+
6
+ export default { isAutoFillSupported }
@@ -0,0 +1,17 @@
1
+ import { StyleSheet, type TextStyle, } from 'react-native';
2
+
3
+
4
+ const styles = StyleSheet.create<{defaultTextFieldStyle: TextStyle}>({
5
+ defaultTextFieldStyle : {
6
+ width : 65,
7
+ height : 65,
8
+ borderColor : 'rgba(226, 226, 226, 1)',
9
+ borderWidth : 1,
10
+ borderRadius : 2,
11
+ textAlign : 'center',
12
+ color: 'rgba(226, 226, 226, 1)',
13
+ marginHorizontal: 3.5
14
+ },
15
+ });
16
+
17
+ export default styles;
@@ -0,0 +1,88 @@
1
+ import * as React from 'react'
2
+ import type { TextStyle, ViewStyle } from 'react-native';
3
+
4
+ type KeyboardType = 'default' | 'email-address' | 'number-pad' | 'phone-pad';
5
+
6
+ export interface InputProps {
7
+ /**
8
+ * Digits of pins in the OTP
9
+ */
10
+ pinCount: number;
11
+ /**
12
+ * Style of the input fields
13
+ */
14
+ codeInputFieldStyle?: TextStyle;
15
+ /**
16
+ * Style of highlighted status for input fields
17
+ */
18
+ codeInputHighlightStyle?: TextStyle;
19
+ /**
20
+ * Callback function
21
+ * Trigger when all fields of the OTP has been filled
22
+ *
23
+ * @param code The verification code
24
+ */
25
+ onCodeFilled?: (code: string) => void;
26
+ /**
27
+ * Callback function
28
+ * Trigger when a field of the OTP is changed
29
+ *
30
+ * @param code The verification code
31
+ */
32
+ onCodeChanged?: (code: string) => void;
33
+ /**
34
+ * If keyboard is automatically brought up when OTP is loaded.
35
+ */
36
+ autoFocusOnLoad?: boolean;
37
+ /**
38
+ * Initial pin code
39
+ */
40
+ code?: string;
41
+ /**
42
+ * Secure input text
43
+ */
44
+ secureTextEntry?: boolean;
45
+ /**
46
+ * Set editable for inputs
47
+ */
48
+ editable?: boolean;
49
+ /**
50
+ * Type of the keyboard
51
+ */
52
+ keyboardType?: KeyboardType;
53
+ /**
54
+ * Placeholder character to fill all inputs when the OTP is empty
55
+ */
56
+ placeholderCharacter?: string;
57
+ /**
58
+ * Placeholder text color of inputs
59
+ */
60
+ placeholderTextColor?: string;
61
+ /**
62
+ * Style of the OTP container view
63
+ */
64
+ style?: ViewStyle;
65
+ /**
66
+ * The highlight (and cursor on iOS) color of the text input.
67
+ */
68
+ selectionColor?: string;
69
+ /**
70
+ * If inputs are automatically cleared.
71
+ */
72
+ clearInputs?: boolean;
73
+
74
+ /**
75
+ * Keyboard appearance. The value can be 'default', 'dark' or 'light'.
76
+ */
77
+ keyboardAppearance?: 'default' | 'dark' | 'light';
78
+
79
+ /**
80
+ * Keyboard auto-appear on focus. The value can be 'false' or 'true'.
81
+ */
82
+ showSoftInputOnFocus?: boolean,
83
+ }
84
+
85
+ export interface OTPInputViewState {
86
+ digits: string[];
87
+ selectedIndex: number;
88
+ }
@@ -0,0 +1,51 @@
1
+ import {View, StyleSheet} from 'react-native';
2
+ // import { NumPad } from "frontatish";
3
+ import React from 'react';
4
+ import OTPInputView from './OTPInputView';
5
+
6
+ type PropT = {
7
+ callBack: Function;
8
+ pinvalue?: any;
9
+ isSecure?: boolean;
10
+ count?: number;
11
+ };
12
+
13
+ export default function OTPInputs({
14
+ callBack,
15
+ pinvalue = '',
16
+ isSecure = true,
17
+ count = 4,
18
+ }: PropT) {
19
+
20
+ return (
21
+ <OTPInputView
22
+ style={{width: '100%', backgroundColor: 'transparent'}}
23
+ codeInputFieldStyle={styles.underlineStyleBase}
24
+ codeInputHighlightStyle={styles.underlineStyleHighLighted}
25
+ secureTextEntry={isSecure}
26
+ pinCount={count}
27
+ autoFocusOnLoad
28
+ placeholderCharacter={''}
29
+ onCodeFilled={code => {
30
+ callBack(code);
31
+ }}
32
+ />
33
+ );
34
+ }
35
+
36
+ const styles = StyleSheet.create({
37
+ underlineStyleBase: {
38
+ width: 60,
39
+ height: 60,
40
+ borderWidth: 1,
41
+ borderStyle: 'solid',
42
+ borderColor: '#ccc',
43
+ color: '#000',
44
+ textAlign: 'center',
45
+ borderRadius: 5,
46
+ },
47
+
48
+ underlineStyleHighLighted: {
49
+ borderColor: '#032b27',
50
+ },
51
+ });
@@ -0,0 +1,78 @@
1
+ import { useEffect, useRef } from "react";
2
+ import { Animated, Easing } from "react-native";
3
+ import styled from 'styled-components/native';
4
+
5
+
6
+ const PulseRing = styled(Animated.View)<{ delay?: number }>`
7
+ position: absolute;
8
+ width: 200px;
9
+ height: 200px;
10
+ border-radius: 100%;
11
+ border-width: 2px;
12
+ border-color: #0a3d2e;
13
+ `;
14
+
15
+ // Pulse Animation Component
16
+ export const PulseAnimation: React.FC = () => {
17
+ const pulse1 = useRef(new Animated.Value(0)).current;
18
+ const pulse2 = useRef(new Animated.Value(0)).current;
19
+ const pulse3 = useRef(new Animated.Value(0)).current;
20
+ const AnimatedPulseRing = Animated.createAnimatedComponent(PulseRing);
21
+
22
+
23
+ useEffect(() => {
24
+ const createPulse = (value: Animated.Value, delay: number) => {
25
+ return Animated.loop(
26
+ Animated.sequence([
27
+ Animated.delay(delay),
28
+ Animated.parallel([
29
+ Animated.timing(value, {
30
+ toValue: 1,
31
+ duration: 2000,
32
+ easing: Easing.out(Easing.ease),
33
+ useNativeDriver: true,
34
+ }),
35
+ ]),
36
+ Animated.timing(value, {
37
+ toValue: 0,
38
+ duration: 0,
39
+ useNativeDriver: true,
40
+ }),
41
+ ])
42
+ );
43
+ };
44
+
45
+ const animations = Animated.parallel([
46
+ createPulse(pulse1, 0),
47
+ createPulse(pulse2, 500),
48
+ createPulse(pulse3, 1000),
49
+ ]);
50
+
51
+ animations.start();
52
+
53
+ return () => animations.stop();
54
+ }, []);
55
+
56
+ const pulseStyle = (animValue: Animated.Value) => ({
57
+ transform: [
58
+ {
59
+ scale: animValue.interpolate({
60
+ inputRange: [0, 1],
61
+ outputRange: [1, 2],
62
+ }),
63
+ },
64
+ ],
65
+ opacity: animValue.interpolate({
66
+ inputRange: [0, 0.5, 1],
67
+ outputRange: [0.5, 0.3, 0],
68
+ }),
69
+ });
70
+
71
+ return (
72
+ <>
73
+ <AnimatedPulseRing style={pulseStyle(pulse1)} />
74
+ <AnimatedPulseRing style={pulseStyle(pulse2)} />
75
+ <AnimatedPulseRing style={pulseStyle(pulse3)} />
76
+ </>
77
+ );
78
+ };