@rownd/react-native 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 (175) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +213 -0
  3. package/android/build.gradle +59 -0
  4. package/android/src/main/AndroidManifest.xml +4 -0
  5. package/android/src/main/java/com/reactnative/ReactNativePackage.java +22 -0
  6. package/android/src/main/java/com/reactnative/ReactNativeViewManager.java +31 -0
  7. package/ios/ReactNative.xcodeproj/project.pbxproj +282 -0
  8. package/ios/ReactNative.xcodeproj/project.xcworkspace/contents.xcworkspacedata +4 -0
  9. package/ios/ReactNativeViewManager.m +34 -0
  10. package/lib/commonjs/assets/images/checkmark--filled.svg +12 -0
  11. package/lib/commonjs/assets/images/email-verify-waiting.svg +36 -0
  12. package/lib/commonjs/assets/images/phone-verify-waiting.svg +26 -0
  13. package/lib/commonjs/components/AuthenticatedComponent.js +35 -0
  14. package/lib/commonjs/components/AuthenticatedComponent.js.map +1 -0
  15. package/lib/commonjs/components/AutoSigninDialog.js +119 -0
  16. package/lib/commonjs/components/AutoSigninDialog.js.map +1 -0
  17. package/lib/commonjs/components/DefaultContext.js +269 -0
  18. package/lib/commonjs/components/DefaultContext.js.map +1 -0
  19. package/lib/commonjs/components/GlobalContext.js +340 -0
  20. package/lib/commonjs/components/GlobalContext.js.map +1 -0
  21. package/lib/commonjs/components/RowndComponents.js +29 -0
  22. package/lib/commonjs/components/RowndComponents.js.map +1 -0
  23. package/lib/commonjs/components/RowndProvider.js +55 -0
  24. package/lib/commonjs/components/RowndProvider.js.map +1 -0
  25. package/lib/commonjs/components/SignIn.js +622 -0
  26. package/lib/commonjs/components/SignIn.js.map +1 -0
  27. package/lib/commonjs/data/actions.js +26 -0
  28. package/lib/commonjs/data/actions.js.map +1 -0
  29. package/lib/commonjs/hooks/api.js +157 -0
  30. package/lib/commonjs/hooks/api.js.map +1 -0
  31. package/lib/commonjs/hooks/debounce.js +38 -0
  32. package/lib/commonjs/hooks/debounce.js.map +1 -0
  33. package/lib/commonjs/hooks/fingerprint.js +176 -0
  34. package/lib/commonjs/hooks/fingerprint.js.map +1 -0
  35. package/lib/commonjs/hooks/index.js +48 -0
  36. package/lib/commonjs/hooks/index.js.map +1 -0
  37. package/lib/commonjs/hooks/interval.js +31 -0
  38. package/lib/commonjs/hooks/interval.js.map +1 -0
  39. package/lib/commonjs/hooks/nav.js +39 -0
  40. package/lib/commonjs/hooks/nav.js.map +1 -0
  41. package/lib/commonjs/hooks/rownd.js +163 -0
  42. package/lib/commonjs/hooks/rownd.js.map +1 -0
  43. package/lib/commonjs/index.js +32 -0
  44. package/lib/commonjs/index.js.map +1 -0
  45. package/lib/commonjs/index.tsx.bak +26 -0
  46. package/lib/commonjs/types.js +2 -0
  47. package/lib/commonjs/types.js.map +1 -0
  48. package/lib/commonjs/utils/config.js +28 -0
  49. package/lib/commonjs/utils/config.js.map +1 -0
  50. package/lib/commonjs/utils/events.js +57 -0
  51. package/lib/commonjs/utils/events.js.map +1 -0
  52. package/lib/commonjs/utils/form.js +46 -0
  53. package/lib/commonjs/utils/form.js.map +1 -0
  54. package/lib/commonjs/utils/queue.js +117 -0
  55. package/lib/commonjs/utils/queue.js.map +1 -0
  56. package/lib/commonjs/utils/storage.js +15 -0
  57. package/lib/commonjs/utils/storage.js.map +1 -0
  58. package/lib/commonjs/utils/tailwind.js +17 -0
  59. package/lib/commonjs/utils/tailwind.js.map +1 -0
  60. package/lib/commonjs/utils/tokens.js +35 -0
  61. package/lib/commonjs/utils/tokens.js.map +1 -0
  62. package/lib/commonjs/utils/user-data.js +21 -0
  63. package/lib/commonjs/utils/user-data.js.map +1 -0
  64. package/lib/module/assets/images/checkmark--filled.svg +12 -0
  65. package/lib/module/assets/images/email-verify-waiting.svg +36 -0
  66. package/lib/module/assets/images/phone-verify-waiting.svg +26 -0
  67. package/lib/module/components/AuthenticatedComponent.js +24 -0
  68. package/lib/module/components/AuthenticatedComponent.js.map +1 -0
  69. package/lib/module/components/AutoSigninDialog.js +100 -0
  70. package/lib/module/components/AutoSigninDialog.js.map +1 -0
  71. package/lib/module/components/DefaultContext.js +244 -0
  72. package/lib/module/components/DefaultContext.js.map +1 -0
  73. package/lib/module/components/GlobalContext.js +318 -0
  74. package/lib/module/components/GlobalContext.js.map +1 -0
  75. package/lib/module/components/RowndComponents.js +14 -0
  76. package/lib/module/components/RowndComponents.js.map +1 -0
  77. package/lib/module/components/RowndProvider.js +39 -0
  78. package/lib/module/components/RowndProvider.js.map +1 -0
  79. package/lib/module/components/SignIn.js +593 -0
  80. package/lib/module/components/SignIn.js.map +1 -0
  81. package/lib/module/data/actions.js +19 -0
  82. package/lib/module/data/actions.js.map +1 -0
  83. package/lib/module/hooks/api.js +138 -0
  84. package/lib/module/hooks/api.js.map +1 -0
  85. package/lib/module/hooks/debounce.js +29 -0
  86. package/lib/module/hooks/debounce.js.map +1 -0
  87. package/lib/module/hooks/fingerprint.js +157 -0
  88. package/lib/module/hooks/fingerprint.js.map +1 -0
  89. package/lib/module/hooks/index.js +7 -0
  90. package/lib/module/hooks/index.js.map +1 -0
  91. package/lib/module/hooks/interval.js +23 -0
  92. package/lib/module/hooks/interval.js.map +1 -0
  93. package/lib/module/hooks/nav.js +30 -0
  94. package/lib/module/hooks/nav.js.map +1 -0
  95. package/lib/module/hooks/rownd.js +148 -0
  96. package/lib/module/hooks/rownd.js.map +1 -0
  97. package/lib/module/index.js +6 -0
  98. package/lib/module/index.js.map +1 -0
  99. package/lib/module/index.tsx.bak +26 -0
  100. package/lib/module/types.js +2 -0
  101. package/lib/module/types.js.map +1 -0
  102. package/lib/module/utils/config.js +17 -0
  103. package/lib/module/utils/config.js.map +1 -0
  104. package/lib/module/utils/events.js +45 -0
  105. package/lib/module/utils/events.js.map +1 -0
  106. package/lib/module/utils/form.js +34 -0
  107. package/lib/module/utils/form.js.map +1 -0
  108. package/lib/module/utils/queue.js +109 -0
  109. package/lib/module/utils/queue.js.map +1 -0
  110. package/lib/module/utils/storage.js +6 -0
  111. package/lib/module/utils/storage.js.map +1 -0
  112. package/lib/module/utils/tailwind.js +5 -0
  113. package/lib/module/utils/tailwind.js.map +1 -0
  114. package/lib/module/utils/tokens.js +24 -0
  115. package/lib/module/utils/tokens.js.map +1 -0
  116. package/lib/module/utils/user-data.js +14 -0
  117. package/lib/module/utils/user-data.js.map +1 -0
  118. package/lib/typescript/example2/App.d.ts +11 -0
  119. package/lib/typescript/src/components/AuthenticatedComponent.d.ts +7 -0
  120. package/lib/typescript/src/components/AutoSigninDialog.d.ts +1 -0
  121. package/lib/typescript/src/components/DefaultContext.d.ts +12 -0
  122. package/lib/typescript/src/components/GlobalContext.d.ts +111 -0
  123. package/lib/typescript/src/components/RowndComponents.d.ts +1 -0
  124. package/lib/typescript/src/components/RowndProvider.d.ts +8 -0
  125. package/lib/typescript/src/components/SignIn.d.ts +1 -0
  126. package/lib/typescript/src/data/actions.d.ts +20 -0
  127. package/lib/typescript/src/hooks/api.d.ts +12 -0
  128. package/lib/typescript/src/hooks/debounce.d.ts +5 -0
  129. package/lib/typescript/src/hooks/fingerprint.d.ts +12 -0
  130. package/lib/typescript/src/hooks/index.d.ts +6 -0
  131. package/lib/typescript/src/hooks/interval.d.ts +2 -0
  132. package/lib/typescript/src/hooks/nav.d.ts +6 -0
  133. package/lib/typescript/src/hooks/rownd.d.ts +37 -0
  134. package/lib/typescript/src/index.d.ts +4 -0
  135. package/lib/typescript/src/types.d.ts +26 -0
  136. package/lib/typescript/src/utils/config.d.ts +18 -0
  137. package/lib/typescript/src/utils/events.d.ts +22 -0
  138. package/lib/typescript/src/utils/form.d.ts +17 -0
  139. package/lib/typescript/src/utils/queue.d.ts +21 -0
  140. package/lib/typescript/src/utils/storage.d.ts +3 -0
  141. package/lib/typescript/src/utils/tailwind.d.ts +2 -0
  142. package/lib/typescript/src/utils/tokens.d.ts +4 -0
  143. package/lib/typescript/src/utils/user-data.d.ts +3 -0
  144. package/lib/typescript/tailwind.config.d.ts +10 -0
  145. package/package.json +177 -0
  146. package/react-native.podspec +19 -0
  147. package/src/assets/images/checkmark--filled.svg +12 -0
  148. package/src/assets/images/email-verify-waiting.svg +36 -0
  149. package/src/assets/images/phone-verify-waiting.svg +26 -0
  150. package/src/components/AuthenticatedComponent.tsx +30 -0
  151. package/src/components/AutoSigninDialog.tsx +125 -0
  152. package/src/components/DefaultContext.tsx +278 -0
  153. package/src/components/GlobalContext.tsx +485 -0
  154. package/src/components/RowndComponents.tsx +21 -0
  155. package/src/components/RowndProvider.tsx +56 -0
  156. package/src/components/SignIn.tsx +770 -0
  157. package/src/data/actions.ts +21 -0
  158. package/src/hooks/api.ts +163 -0
  159. package/src/hooks/debounce.ts +36 -0
  160. package/src/hooks/fingerprint.ts +217 -0
  161. package/src/hooks/index.ts +7 -0
  162. package/src/hooks/interval.ts +25 -0
  163. package/src/hooks/nav.tsx +29 -0
  164. package/src/hooks/rownd.ts +184 -0
  165. package/src/index.tsx +6 -0
  166. package/src/index.tsx.bak +26 -0
  167. package/src/types.ts +27 -0
  168. package/src/utils/config.ts +36 -0
  169. package/src/utils/events.ts +54 -0
  170. package/src/utils/form.tsx +64 -0
  171. package/src/utils/queue.ts +75 -0
  172. package/src/utils/storage.ts +7 -0
  173. package/src/utils/tailwind.ts +6 -0
  174. package/src/utils/tokens.ts +26 -0
  175. package/src/utils/user-data.ts +15 -0
@@ -0,0 +1,593 @@
1
+ function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
2
+
3
+ import * as Linking from 'expo-linking';
4
+ import React, { useCallback, useEffect, useMemo, useReducer, useRef, useState } from 'react';
5
+ import { differenceInMinutes } from 'date-fns';
6
+ import { View, Text, StyleSheet, Pressable, Image, ActivityIndicator } from 'react-native';
7
+ import { SvgCssUri } from 'react-native-svg';
8
+ import tw from '../utils/tailwind';
9
+ import phone from 'phone';
10
+ import jwt_decode from 'jwt-decode';
11
+ import { BottomSheetBackdrop, BottomSheetModal, BottomSheetTextInput } from '@gorhom/bottom-sheet';
12
+ import { useApi, useInterval, useNav, useDeviceFingerprint } from '../hooks';
13
+ import { useGlobalContext } from './GlobalContext';
14
+ import { ActionType } from '../data/actions';
15
+ import { renderField } from '../utils/form'; // Image imports
16
+
17
+ import ImageEmailVerifyWaiting from '../assets/images/email-verify-waiting.svg';
18
+ import ImagePhoneVerifyWaiting from '../assets/images/phone-verify-waiting.svg';
19
+ import ImageCheckmarkFilled from '../assets/images/checkmark--filled.svg';
20
+ var LoginStep;
21
+
22
+ (function (LoginStep) {
23
+ LoginStep["INIT"] = "init";
24
+ LoginStep["WAITING"] = "waiting";
25
+ LoginStep["SUCCESS"] = "success";
26
+ LoginStep["FAILURE"] = "failure";
27
+ LoginStep["ERROR"] = "error";
28
+ })(LoginStep || (LoginStep = {}));
29
+
30
+ var LoginVerificationStatus;
31
+
32
+ (function (LoginVerificationStatus) {
33
+ LoginVerificationStatus["PENDING"] = "pending";
34
+ LoginVerificationStatus["EXPIRED"] = "expired";
35
+ LoginVerificationStatus["VERIFIED"] = "verified";
36
+ })(LoginVerificationStatus || (LoginVerificationStatus = {}));
37
+
38
+ export function SignIn() {
39
+ var _decodedAccessToken, _nav$options, _app$config2, _app$config2$hub, _app$config2$hub$auth, _nav$options4, _nav$options5, _nav$options8, _state$config3, _nav$options10, _state$config5, _app$config5, _app$config6, _app$config6$hub, _app$config6$hub$auth, _app$config7, _app$config7$hub, _app$config7$hub$auth;
40
+
41
+ const navTo = useNav();
42
+ const {
43
+ getFingerprint,
44
+ getChallengeIfPresent,
45
+ clearFingerprint
46
+ } = useDeviceFingerprint();
47
+ const {
48
+ state,
49
+ dispatch
50
+ } = useGlobalContext();
51
+ const {
52
+ config,
53
+ nav,
54
+ app,
55
+ user
56
+ } = state;
57
+ let decodedAccessToken;
58
+
59
+ if (state.auth.access_token) {
60
+ decodedAccessToken = jwt_decode(state.auth.access_token);
61
+ }
62
+
63
+ const [userIdentifier, setUserIdentifier] = useState('');
64
+ const [fieldError, setFieldError] = useState(null);
65
+ const [step, setStep] = useState(state.auth.access_token && ((_decodedAccessToken = decodedAccessToken) === null || _decodedAccessToken === void 0 ? void 0 : _decodedAccessToken['https://auth.rownd.io/is_verified_user']) !== false ? LoginStep.SUCCESS : LoginStep.INIT);
66
+ const [error, setError] = useState('');
67
+ const allowedIdentifiers = useMemo(() => ['email', 'phone'], []);
68
+ const [requestId, setRequestId] = useState(null);
69
+ const [loginPollStart, setLoginPollStart] = useState(null);
70
+ const [isSubmitting, setIsSubmitting] = useState(false);
71
+ const [loginType, setLoginType] = useState(null); // eslint-disable-next-line @typescript-eslint/no-unused-vars
72
+
73
+ const [_phoneDetails, setPhoneDetails] = useState(null); // TODO: For parity with web, need to use `phoneDetails` to update the input visuals
74
+
75
+ const [isValidUserIdentifier, setIsValidUserIdentifier] = useState(false);
76
+ const [requiresAdditionalFields, setRequiresAdditionalFields] = useState(nav === null || nav === void 0 ? void 0 : (_nav$options = nav.options) === null || _nav$options === void 0 ? void 0 : _nav$options.init_data);
77
+ const bottomSheetModalRef = useRef(null);
78
+ useEffect(() => {
79
+ if (bottomSheetModalRef.current) {
80
+ bottomSheetModalRef.current.present();
81
+ }
82
+ }, []);
83
+ const addlFieldInit = useCallback(currentState => {
84
+ var _app$config, _app$config$hub, _app$config$hub$auth, _nav$options2, _nav$options3;
85
+
86
+ const addlFields = app === null || app === void 0 ? void 0 : (_app$config = app.config) === null || _app$config === void 0 ? void 0 : (_app$config$hub = _app$config.hub) === null || _app$config$hub === void 0 ? void 0 : (_app$config$hub$auth = _app$config$hub.auth) === null || _app$config$hub$auth === void 0 ? void 0 : _app$config$hub$auth.additional_fields;
87
+ const addlInputs = (nav === null || nav === void 0 ? void 0 : (_nav$options2 = nav.options) === null || _nav$options2 === void 0 ? void 0 : _nav$options2.init_data) || (nav === null || nav === void 0 ? void 0 : (_nav$options3 = nav.options) === null || _nav$options3 === void 0 ? void 0 : _nav$options3.default_values) || {};
88
+ const newState = {};
89
+
90
+ if (addlFields !== null && addlFields !== void 0 && addlFields.length) {
91
+ for (const field of addlFields) {
92
+ if (field !== null && field !== void 0 && field.options) {
93
+ newState[field.name] = (addlInputs === null || addlInputs === void 0 ? void 0 : addlInputs[field.name]) || field.options[0].value;
94
+ }
95
+ }
96
+ }
97
+
98
+ return { ...currentState,
99
+ ...newState
100
+ };
101
+ }, [app === null || app === void 0 ? void 0 : (_app$config2 = app.config) === null || _app$config2 === void 0 ? void 0 : (_app$config2$hub = _app$config2.hub) === null || _app$config2$hub === void 0 ? void 0 : (_app$config2$hub$auth = _app$config2$hub.auth) === null || _app$config2$hub$auth === void 0 ? void 0 : _app$config2$hub$auth.additional_fields, nav === null || nav === void 0 ? void 0 : (_nav$options4 = nav.options) === null || _nav$options4 === void 0 ? void 0 : _nav$options4.default_values, nav === null || nav === void 0 ? void 0 : (_nav$options5 = nav.options) === null || _nav$options5 === void 0 ? void 0 : _nav$options5.init_data]);
102
+ const fieldReducer = useCallback((currentState, action) => {
103
+ console.log('fieldReducer', action);
104
+
105
+ switch (action.type) {
106
+ case 'reset':
107
+ return addlFieldInit(currentState);
108
+
109
+ default:
110
+ return { ...currentState,
111
+ ...action.payload
112
+ };
113
+ }
114
+ }, [addlFieldInit]);
115
+ const [addlFieldValues, addlFieldDispatch] = useReducer(fieldReducer, {}, addlFieldInit);
116
+ const {
117
+ client: api
118
+ } = useApi();
119
+
120
+ function validateEmail(email) {
121
+ const re = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
122
+ const isValid = re.test(String(email).toLowerCase());
123
+
124
+ if (!isValid) {
125
+ setFieldError('Invalid email address');
126
+ return false;
127
+ }
128
+
129
+ setFieldError(null);
130
+ return true;
131
+ }
132
+
133
+ const isValidPhone = useCallback(() => {
134
+ const phoneResult = phone(userIdentifier);
135
+
136
+ if (!phoneResult.isValid) {
137
+ setLoginType(null);
138
+ setPhoneDetails(null);
139
+ return false;
140
+ }
141
+
142
+ setLoginType('phone');
143
+ setPhoneDetails(phoneResult);
144
+ setUserIdentifier(phoneResult.phoneNumber);
145
+ return true;
146
+ }, [userIdentifier]);
147
+ const isValidEmail = useCallback(() => {
148
+ const emailAtIdx = userIdentifier === null || userIdentifier === void 0 ? void 0 : userIdentifier.indexOf('@');
149
+ const emailSuffixIdx = userIdentifier === null || userIdentifier === void 0 ? void 0 : userIdentifier.substring(emailAtIdx).indexOf('.');
150
+
151
+ if (emailAtIdx > 0 && emailSuffixIdx > 0 && (userIdentifier === null || userIdentifier === void 0 ? void 0 : userIdentifier.substring(emailAtIdx + emailSuffixIdx).length) >= 3) {
152
+ return validateEmail(userIdentifier);
153
+ }
154
+
155
+ return false;
156
+ }, [userIdentifier]);
157
+ const validateInput = useCallback(() => {
158
+ const validations = [];
159
+
160
+ if (allowedIdentifiers.includes('phone')) {
161
+ validations.push(isValidPhone);
162
+ }
163
+
164
+ if (allowedIdentifiers.includes('email')) {
165
+ validations.push(isValidEmail);
166
+ }
167
+
168
+ if (!validations.some(fn => fn())) {
169
+ setIsValidUserIdentifier(false);
170
+ } else {
171
+ setIsValidUserIdentifier(true);
172
+ }
173
+ }, [allowedIdentifiers, isValidEmail, isValidPhone]); // Fire validation as data changes in field
174
+
175
+ useEffect(validateInput, [validateInput]);
176
+ const pollLoginStatus = useCallback(async () => {
177
+ try {
178
+ const resp = await api.post(`hub/auth/challenge_status`, {
179
+ headers: {
180
+ 'x-rownd-app-key': config === null || config === void 0 ? void 0 : config.appKey
181
+ },
182
+ json: {
183
+ challenge_id: requestId,
184
+ [loginType === 'phone' ? 'phone' : 'email']: userIdentifier
185
+ }
186
+ }).json();
187
+ let err;
188
+
189
+ switch (resp.status) {
190
+ case 'pending':
191
+ err = new Error('Login challenge is still pending');
192
+ err.code = LoginVerificationStatus.PENDING;
193
+ throw err;
194
+
195
+ case 'expired':
196
+ err = new Error('Login challenge is still pending');
197
+ err.code = LoginVerificationStatus.PENDING;
198
+ throw err;
199
+
200
+ case 'verified':
201
+ break;
202
+
203
+ default:
204
+ err = new Error('Unknown login challenge status');
205
+ throw err;
206
+ }
207
+
208
+ dispatch({
209
+ type: ActionType.LOGIN_SUCCESS,
210
+ payload: resp
211
+ });
212
+ setStep(LoginStep.SUCCESS);
213
+ } catch (err) {
214
+ // logger.log('login poll error', err);
215
+ // If network error, try again up to 1 minute, else fail
216
+ if (!err.code && differenceInMinutes(Date.now(), loginPollStart) > 0) {
217
+ setStep(LoginStep.ERROR);
218
+ setError('Network error. Please try again later.');
219
+ return;
220
+ } // If request expires, then fail (assume > 6 mins is a failure/expiration)
221
+
222
+
223
+ if ((err.status || err.code) && differenceInMinutes(Date.now(), loginPollStart) > 6) {
224
+ setStep(LoginStep.ERROR);
225
+ setError('The sign in request expired.');
226
+ return;
227
+ }
228
+
229
+ if (err.status && err.status >= 400) {
230
+ setStep(LoginStep.FAILURE);
231
+ setError('Sign in unsuccessful.');
232
+ }
233
+ }
234
+ }, [api, config === null || config === void 0 ? void 0 : config.appKey, dispatch, loginPollStart, loginType, requestId, userIdentifier]); // Polling when a login flow is in progress
235
+
236
+ useInterval(pollLoginStatus, step === LoginStep.WAITING ? 5000 : null); // login polling manager
237
+
238
+ useEffect(() => {
239
+ if (step === LoginStep.SUCCESS) {
240
+ var _nav$options6, _state$config;
241
+
242
+ if (nav !== null && nav !== void 0 && (_nav$options6 = nav.options) !== null && _nav$options6 !== void 0 && _nav$options6.post_login_redirect || (_state$config = state.config) !== null && _state$config !== void 0 && _state$config.postLoginUrl) {
243
+ var _nav$options7, _state$config2;
244
+
245
+ Linking.openURL((nav === null || nav === void 0 ? void 0 : (_nav$options7 = nav.options) === null || _nav$options7 === void 0 ? void 0 : _nav$options7.post_login_redirect) || ((_state$config2 = state.config) === null || _state$config2 === void 0 ? void 0 : _state$config2.postLoginUrl));
246
+ }
247
+
248
+ dispatch({
249
+ type: ActionType.CHANGE_ROUTE,
250
+ payload: {
251
+ route: '/'
252
+ }
253
+ }); // Reset modal state if this user is unverified, since we'll need to re-submit at some point
254
+
255
+ if (!state.auth.is_verified_user) {
256
+ setStep(LoginStep.INIT);
257
+ }
258
+ }
259
+ }, [dispatch, nav === null || nav === void 0 ? void 0 : (_nav$options8 = nav.options) === null || _nav$options8 === void 0 ? void 0 : _nav$options8.post_login_redirect, pollLoginStatus, state.auth.is_verified_user, (_state$config3 = state.config) === null || _state$config3 === void 0 ? void 0 : _state$config3.postLoginUrl, step]);
260
+ const initSignIn = useCallback(async () => {
261
+ var _nav$options9, _state$config4, _app$config3;
262
+
263
+ if (step === LoginStep.WAITING) {
264
+ return;
265
+ } // Validation
266
+
267
+
268
+ if (fieldError) {
269
+ return;
270
+ }
271
+
272
+ const payload = {
273
+ [loginType === 'phone' ? 'phone' : 'email']: userIdentifier,
274
+ return_url: (nav === null || nav === void 0 ? void 0 : (_nav$options9 = nav.options) === null || _nav$options9 === void 0 ? void 0 : _nav$options9.post_login_redirect) || ((_state$config4 = state.config) === null || _state$config4 === void 0 ? void 0 : _state$config4.postLoginUrl),
275
+ user_data: Object.values(user.data).some(f => f !== null && f !== undefined) ? user.data : {} // Include user.data if at least one field is defined
276
+
277
+ }; // Set the user_id to the application's default user id format if it is defined
278
+
279
+ if ((_app$config3 = app.config) !== null && _app$config3 !== void 0 && _app$config3.default_user_id_format) {
280
+ var _app$config4;
281
+
282
+ payload.user_id = (_app$config4 = app.config) === null || _app$config4 === void 0 ? void 0 : _app$config4.default_user_id_format;
283
+ }
284
+
285
+ if (requiresAdditionalFields) {
286
+ payload.user_data = { ...payload.user_data,
287
+ ...addlFieldValues
288
+ };
289
+ } // Submission
290
+
291
+
292
+ try {
293
+ var _payload$fingerprint;
294
+
295
+ setIsSubmitting(true); // Get the browser fingerprint for future sign-ins that don't require re-verification
296
+
297
+ const fingerprint = await getFingerprint();
298
+ const challengeEntry = await getChallengeIfPresent(app.id, [userIdentifier]);
299
+ payload.fingerprint = {
300
+ hash: fingerprint.visitorId,
301
+ challenge: challengeEntry === null || challengeEntry === void 0 ? void 0 : challengeEntry.value
302
+ };
303
+ const resp = await api.post('hub/auth/init', {
304
+ headers: {
305
+ 'x-rownd-app-key': config === null || config === void 0 ? void 0 : config.appKey
306
+ },
307
+ json: payload
308
+ }).json(); // This will only be true when a user is signing in for the very first time and
309
+ // the app allows unverified users OR the user was successfully fingerprinted.
310
+
311
+ if (resp.auth_tokens) {
312
+ dispatch({
313
+ type: ActionType.LOGIN_SUCCESS,
314
+ payload: { ...resp.auth_tokens,
315
+ app_id: app.id
316
+ }
317
+ });
318
+ setStep(LoginStep.SUCCESS);
319
+ return;
320
+ } else if (payload !== null && payload !== void 0 && (_payload$fingerprint = payload.fingerprint) !== null && _payload$fingerprint !== void 0 && _payload$fingerprint.challenge) {
321
+ // The fingerprint is probably expired, so delete the challenge for re-registration
322
+ try {
323
+ clearFingerprint(payload.fingerprint.challenge);
324
+ } catch (err) {// no-op, but not likely to throw anyway
325
+ }
326
+ }
327
+
328
+ setRequestId(resp.challenge_id);
329
+ setStep(LoginStep.WAITING);
330
+ setLoginPollStart(Date.now());
331
+ } catch (err) {
332
+ // logger.error(err);
333
+ if (err.response.status === 400) {
334
+ setStep(LoginStep.INIT);
335
+ setRequiresAdditionalFields(true);
336
+ return;
337
+ }
338
+
339
+ setStep(LoginStep.ERROR);
340
+ setError(err.message);
341
+ } finally {
342
+ setIsSubmitting(false);
343
+ }
344
+ }, [step, fieldError, loginType, userIdentifier, nav === null || nav === void 0 ? void 0 : (_nav$options10 = nav.options) === null || _nav$options10 === void 0 ? void 0 : _nav$options10.post_login_redirect, (_state$config5 = state.config) === null || _state$config5 === void 0 ? void 0 : _state$config5.postLoginUrl, user.data, (_app$config5 = app.config) === null || _app$config5 === void 0 ? void 0 : _app$config5.default_user_id_format, app.id, requiresAdditionalFields, addlFieldValues, getFingerprint, getChallengeIfPresent, api, config === null || config === void 0 ? void 0 : config.appKey, dispatch, clearFingerprint]);
345
+
346
+ const launchRowndWebsite = () => {
347
+ Linking.openURL('https://rownd.io');
348
+ };
349
+
350
+ const handleAddlFieldChange = evt => {
351
+ const target = evt.target;
352
+ const {
353
+ value,
354
+ name
355
+ } = target;
356
+ addlFieldDispatch({
357
+ type: 'default',
358
+ payload: {
359
+ [name]: value
360
+ }
361
+ });
362
+ };
363
+
364
+ const handleClose = useCallback(() => {
365
+ setTimeout(() => {
366
+ navTo({
367
+ hide: true
368
+ });
369
+ }, 150);
370
+ }, [navTo]);
371
+ const snapPoints = useMemo(() => ['25%', '70%'], []);
372
+ const renderBackdrop = useCallback(cbProps => /*#__PURE__*/React.createElement(BottomSheetBackdrop, _extends({}, cbProps, {
373
+ pressBehavior: "close"
374
+ })), []);
375
+ return /*#__PURE__*/React.createElement(BottomSheetModal, {
376
+ snapPoints: snapPoints,
377
+ index: 1,
378
+ backdropComponent: renderBackdrop,
379
+ keyboardBehavior: "fillParent",
380
+ android_keyboardInputMode: "adjustResize",
381
+ enablePanDownToClose: true,
382
+ onDismiss: handleClose,
383
+ style: styles.bottomSheet,
384
+ ref: bottomSheetModalRef
385
+ }, /*#__PURE__*/React.createElement(View, {
386
+ style: styles.innerContainer
387
+ }, step === LoginStep.INIT && /*#__PURE__*/React.createElement(React.Fragment, null, (app === null || app === void 0 ? void 0 : (_app$config6 = app.config) === null || _app$config6 === void 0 ? void 0 : (_app$config6$hub = _app$config6.hub) === null || _app$config6$hub === void 0 ? void 0 : (_app$config6$hub$auth = _app$config6$hub.auth) === null || _app$config6$hub$auth === void 0 ? void 0 : _app$config6$hub$auth.show_app_icon) && (app === null || app === void 0 ? void 0 : app.icon) && (app.icon_content_type === 'image/svg+xml' ? /*#__PURE__*/React.createElement(SvgCssUri, {
388
+ uri: app.icon,
389
+ style: styles.appLogo
390
+ }) : /*#__PURE__*/React.createElement(Image, {
391
+ style: styles.appLogo,
392
+ source: {
393
+ uri: app.icon
394
+ }
395
+ })), /*#__PURE__*/React.createElement(Text, {
396
+ style: styles.dialogHeading
397
+ }, "Sign in or sign up"), /*#__PURE__*/React.createElement(Text, {
398
+ style: styles.inputLabel
399
+ }, "Email or phone number"), /*#__PURE__*/React.createElement(BottomSheetTextInput, {
400
+ style: styles.identifierInput,
401
+ placeholder: "Enter here",
402
+ keyboardType: "email-address",
403
+ textContentType: "emailAddress",
404
+ returnKeyLabel: "Sign in",
405
+ returnKeyType: "go",
406
+ enablesReturnKeyAutomatically: true,
407
+ autoCapitalize: "none",
408
+ onChangeText: text => setUserIdentifier(text.trim()),
409
+ onBlur: validateInput,
410
+ value: userIdentifier,
411
+ onSubmitEditing: initSignIn
412
+ }), requiresAdditionalFields && (app === null || app === void 0 ? void 0 : (_app$config7 = app.config) === null || _app$config7 === void 0 ? void 0 : (_app$config7$hub = _app$config7.hub) === null || _app$config7$hub === void 0 ? void 0 : (_app$config7$hub$auth = _app$config7$hub.auth) === null || _app$config7$hub$auth === void 0 ? void 0 : _app$config7$hub$auth.additional_fields.map(field => {
413
+ return renderField({ ...field,
414
+ value: addlFieldValues[field.name] || '',
415
+ [['input', 'text', 'tel', 'email'].includes(field.type) ? 'onInput' : 'onChange']: handleAddlFieldChange
416
+ });
417
+ })), /*#__PURE__*/React.createElement(Pressable, {
418
+ style: _ref => {
419
+ let {
420
+ pressed
421
+ } = _ref;
422
+ return [styles.button, !isValidUserIdentifier && styles.buttonDisabled, pressed && styles.buttonPressed, isSubmitting && styles.buttonSubmitting];
423
+ },
424
+ disabled: !isValidUserIdentifier || isSubmitting,
425
+ onPress: initSignIn
426
+ }, /*#__PURE__*/React.createElement(Text, null, isSubmitting && /*#__PURE__*/React.createElement(ActivityIndicator, {
427
+ size: "small",
428
+ color: "#efefef"
429
+ }), /*#__PURE__*/React.createElement(View, {
430
+ style: styles.buttonText
431
+ }, /*#__PURE__*/React.createElement(Text, {
432
+ style: isValidUserIdentifier ? styles.buttonContent : { ...styles.buttonContent,
433
+ ...styles.buttonDisabledText
434
+ }
435
+ }, isSubmitting ? 'Just a sec...' : 'Continue')))), /*#__PURE__*/React.createElement(Text, {
436
+ style: styles.signInNoticeText
437
+ }, "By continuing, you're agreeing to the terms of service that govern this app and to receive email or text messages for verification purposes.")), step === LoginStep.WAITING && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Text, {
438
+ style: styles.dialogHeading
439
+ }, "Thanks! Verify your", ' ', loginType === 'phone' ? 'phone number' : 'email', " to finish"), /*#__PURE__*/React.createElement(Text, {
440
+ style: tw.style('py-6')
441
+ }, "Click the link in the message we just sent to", ' ', /*#__PURE__*/React.createElement(Text, {
442
+ style: tw.style('italic')
443
+ }, userIdentifier), " to verify and finish.", /*#__PURE__*/React.createElement(Text, {
444
+ style: [styles.link],
445
+ onPress: () => setStep(LoginStep.INIT)
446
+ }, "\xA0Re-send message")), /*#__PURE__*/React.createElement(View, {
447
+ style: styles.signInVerificationImage
448
+ }, loginType === 'phone' ? /*#__PURE__*/React.createElement(ImagePhoneVerifyWaiting, null) : /*#__PURE__*/React.createElement(ImageEmailVerifyWaiting, null)), /*#__PURE__*/React.createElement(Pressable, {
449
+ style: _ref2 => {
450
+ let {
451
+ pressed
452
+ } = _ref2;
453
+ return [styles.button, pressed && styles.buttonPressed];
454
+ },
455
+ onPress: () => setStep(LoginStep.INIT)
456
+ }, /*#__PURE__*/React.createElement(Text, {
457
+ style: styles.buttonContent
458
+ }, "Try a different", ' ', loginType === 'phone' ? 'phone number' : 'email'))), step === LoginStep.SUCCESS && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(View, {
459
+ style: styles.signInVerificationImage
460
+ }, /*#__PURE__*/React.createElement(ImageCheckmarkFilled, null))), step === LoginStep.FAILURE && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Text, {
461
+ style: tw.style('text-base')
462
+ }, "Whoops, that didn't work!"), /*#__PURE__*/React.createElement(Pressable, {
463
+ style: styles.button,
464
+ onPress: () => setStep(LoginStep.INIT)
465
+ }, /*#__PURE__*/React.createElement(Text, {
466
+ style: styles.buttonContent
467
+ }, "Try again"))), step === LoginStep.ERROR && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Text, {
468
+ style: tw.style('text-base')
469
+ }, "An error occurred while signing you in."), !!error && /*#__PURE__*/React.createElement(Text, {
470
+ style: tw.style('text-rose-800')
471
+ }, error), /*#__PURE__*/React.createElement(Pressable, {
472
+ style: styles.button,
473
+ onPress: () => setStep(LoginStep.INIT)
474
+ }, /*#__PURE__*/React.createElement(Text, {
475
+ style: styles.buttonContent
476
+ }, "Try again"))), /*#__PURE__*/React.createElement(Text, null, "Powered by", ' ', /*#__PURE__*/React.createElement(Text, {
477
+ style: styles.link,
478
+ onPress: launchRowndWebsite
479
+ }, "Rownd"))));
480
+ }
481
+ const styles = StyleSheet.create({
482
+ modal: {// flex: 1,
483
+ },
484
+ bottomSheet: {
485
+ shadowColor: '#000',
486
+ shadowOffset: {
487
+ width: 0,
488
+ height: 12
489
+ },
490
+ shadowOpacity: 0.58,
491
+ shadowRadius: 16.0,
492
+ elevation: 24
493
+ },
494
+ innerContainer: {
495
+ borderRadius: 20,
496
+ borderColor: 'transparent',
497
+ borderWidth: 0,
498
+ padding: 25
499
+ },
500
+ container: {
501
+ flex: 1,
502
+ padding: 24
503
+ },
504
+ header: {
505
+ alignItems: 'center',
506
+ backgroundColor: 'white',
507
+ paddingVertical: 20,
508
+ borderTopLeftRadius: 20,
509
+ borderTopRightRadius: 20
510
+ },
511
+ panelHandle: {
512
+ width: 40,
513
+ height: 2,
514
+ backgroundColor: 'rgba(0,0,0,0.3)',
515
+ borderRadius: 4
516
+ },
517
+ appLogo: {
518
+ padding: 50,
519
+ width: 75,
520
+ height: 75,
521
+ resizeMode: 'center',
522
+ textAlign: 'center',
523
+ marginLeft: 'auto',
524
+ marginRight: 'auto',
525
+ marginBottom: 20
526
+ },
527
+ dialogHeading: {
528
+ fontSize: 24
529
+ },
530
+ inputLabel: {
531
+ marginTop: 20,
532
+ marginBottom: 5
533
+ },
534
+ identifierInput: {
535
+ backgroundColor: '#eee',
536
+ borderRadius: 8,
537
+ padding: 10,
538
+ fontSize: 18
539
+ },
540
+ button: {
541
+ borderRadius: 10,
542
+ padding: 10,
543
+ marginTop: 20,
544
+ marginBottom: 30,
545
+ elevation: 0,
546
+ backgroundColor: '#5b0ae0',
547
+ display: 'flex',
548
+ alignItems: 'center',
549
+ justifyContent: 'center'
550
+ },
551
+ buttonDisabled: {
552
+ backgroundColor: '#eee'
553
+ },
554
+ buttonPressed: {
555
+ opacity: 0.5
556
+ },
557
+ buttonContent: {
558
+ textAlign: 'center',
559
+ fontSize: 18,
560
+ color: '#fff'
561
+ },
562
+ buttonText: {
563
+ marginLeft: 10,
564
+ paddingLeft: 10,
565
+ fontSize: 18
566
+ },
567
+ buttonTextInner: {
568
+ fontSize: 18
569
+ },
570
+ buttonDisabledText: {
571
+ color: '#8e8e8e'
572
+ },
573
+ buttonSubmitting: {
574
+ backgroundColor: '#2f0492',
575
+ color: '#c7c7c7'
576
+ },
577
+ loadingIndicator: {
578
+ textAlignVertical: 'center',
579
+ padding: 20,
580
+ margin: 20
581
+ },
582
+ signInNoticeText: {
583
+ fontSize: 12,
584
+ marginBottom: 20
585
+ },
586
+ signInVerificationImage: {
587
+ alignItems: 'center'
588
+ },
589
+ link: {
590
+ color: '#6114e1'
591
+ }
592
+ });
593
+ //# sourceMappingURL=SignIn.js.map