@oxyhq/services 5.11.10 → 5.11.12

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 (181) hide show
  1. package/lib/commonjs/ui/components/AnimationExample.js +1 -1
  2. package/lib/commonjs/ui/components/AnimationExample.js.map +1 -1
  3. package/lib/commonjs/ui/components/FollowButton.js +1 -1
  4. package/lib/commonjs/ui/components/FollowButton.js.map +1 -1
  5. package/lib/commonjs/ui/components/Header.js +2 -2
  6. package/lib/commonjs/ui/components/Header.js.map +1 -1
  7. package/lib/commonjs/ui/components/OxyProvider.js +3 -3
  8. package/lib/commonjs/ui/components/OxyProvider.js.map +1 -1
  9. package/lib/commonjs/ui/components/StepBasedScreen.README.md +337 -0
  10. package/lib/commonjs/ui/components/StepBasedScreen.js +361 -0
  11. package/lib/commonjs/ui/components/StepBasedScreen.js.map +1 -0
  12. package/lib/commonjs/ui/components/icon/OxyIcon.js +3 -3
  13. package/lib/commonjs/ui/components/icon/OxyIcon.js.map +1 -1
  14. package/lib/commonjs/ui/components/internal/PinInput.js +1 -1
  15. package/lib/commonjs/ui/components/internal/PinInput.js.map +1 -1
  16. package/lib/commonjs/ui/components/photogrid/JustifiedPhotoGrid.js.map +1 -1
  17. package/lib/commonjs/ui/context/OxyContext.js +7 -7
  18. package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
  19. package/lib/commonjs/ui/screens/PaymentGatewayScreen.js +1 -1
  20. package/lib/commonjs/ui/screens/PaymentGatewayScreen.js.map +1 -1
  21. package/lib/commonjs/ui/screens/ProfileScreen.js +55 -55
  22. package/lib/commonjs/ui/screens/ProfileScreen.js.map +1 -1
  23. package/lib/commonjs/ui/screens/RecoverAccountScreen.js +87 -219
  24. package/lib/commonjs/ui/screens/RecoverAccountScreen.js.map +1 -1
  25. package/lib/commonjs/ui/screens/SignInScreen.js +138 -235
  26. package/lib/commonjs/ui/screens/SignInScreen.js.map +1 -1
  27. package/lib/commonjs/ui/screens/SignUpScreen.js +139 -742
  28. package/lib/commonjs/ui/screens/SignUpScreen.js.map +1 -1
  29. package/lib/commonjs/ui/screens/internal/SignInPasswordStep.js +3 -3
  30. package/lib/commonjs/ui/screens/internal/SignInPasswordStep.js.map +1 -1
  31. package/lib/commonjs/ui/screens/internal/SignInUsernameStep.js +2 -2
  32. package/lib/commonjs/ui/screens/internal/SignInUsernameStep.js.map +1 -1
  33. package/lib/commonjs/ui/screens/steps/RecoverRequestStep.js +110 -0
  34. package/lib/commonjs/ui/screens/steps/RecoverRequestStep.js.map +1 -0
  35. package/lib/commonjs/ui/screens/steps/RecoverSuccessStep.js +138 -0
  36. package/lib/commonjs/ui/screens/steps/RecoverSuccessStep.js.map +1 -0
  37. package/lib/commonjs/ui/screens/steps/RecoverVerifyStep.js +141 -0
  38. package/lib/commonjs/ui/screens/steps/RecoverVerifyStep.js.map +1 -0
  39. package/lib/commonjs/ui/screens/steps/SignInPasswordStep.js +165 -0
  40. package/lib/commonjs/ui/screens/steps/SignInPasswordStep.js.map +1 -0
  41. package/lib/commonjs/ui/screens/steps/SignInUsernameStep.js +150 -0
  42. package/lib/commonjs/ui/screens/steps/SignInUsernameStep.js.map +1 -0
  43. package/lib/commonjs/ui/screens/steps/SignUpIdentityStep.js +171 -0
  44. package/lib/commonjs/ui/screens/steps/SignUpIdentityStep.js.map +1 -0
  45. package/lib/commonjs/ui/screens/steps/SignUpSecurityStep.js +163 -0
  46. package/lib/commonjs/ui/screens/steps/SignUpSecurityStep.js.map +1 -0
  47. package/lib/commonjs/ui/screens/steps/SignUpSummaryStep.js +170 -0
  48. package/lib/commonjs/ui/screens/steps/SignUpSummaryStep.js.map +1 -0
  49. package/lib/commonjs/ui/screens/steps/SignUpWelcomeStep.js +72 -0
  50. package/lib/commonjs/ui/screens/steps/SignUpWelcomeStep.js.map +1 -0
  51. package/lib/module/ui/components/AnimationExample.js +1 -1
  52. package/lib/module/ui/components/AnimationExample.js.map +1 -1
  53. package/lib/module/ui/components/FollowButton.js +1 -1
  54. package/lib/module/ui/components/FollowButton.js.map +1 -1
  55. package/lib/module/ui/components/Header.js +2 -2
  56. package/lib/module/ui/components/Header.js.map +1 -1
  57. package/lib/module/ui/components/OxyProvider.js +3 -3
  58. package/lib/module/ui/components/OxyProvider.js.map +1 -1
  59. package/lib/module/ui/components/Section.js.map +1 -1
  60. package/lib/module/ui/components/SectionTitle.js.map +1 -1
  61. package/lib/module/ui/components/StepBasedScreen.README.md +337 -0
  62. package/lib/module/ui/components/StepBasedScreen.js +356 -0
  63. package/lib/module/ui/components/StepBasedScreen.js.map +1 -0
  64. package/lib/module/ui/components/icon/FAIRWalletIcon.js.map +1 -1
  65. package/lib/module/ui/components/icon/OxyIcon.js +3 -3
  66. package/lib/module/ui/components/icon/OxyIcon.js.map +1 -1
  67. package/lib/module/ui/components/internal/PinInput.js +1 -1
  68. package/lib/module/ui/components/internal/PinInput.js.map +1 -1
  69. package/lib/module/ui/components/photogrid/JustifiedPhotoGrid.js.map +1 -1
  70. package/lib/module/ui/context/OxyContext.js +7 -7
  71. package/lib/module/ui/context/OxyContext.js.map +1 -1
  72. package/lib/module/ui/screens/PaymentGatewayScreen.js +1 -1
  73. package/lib/module/ui/screens/PaymentGatewayScreen.js.map +1 -1
  74. package/lib/module/ui/screens/ProfileScreen.js +55 -55
  75. package/lib/module/ui/screens/ProfileScreen.js.map +1 -1
  76. package/lib/module/ui/screens/RecoverAccountScreen.js +91 -222
  77. package/lib/module/ui/screens/RecoverAccountScreen.js.map +1 -1
  78. package/lib/module/ui/screens/SignInScreen.js +140 -237
  79. package/lib/module/ui/screens/SignInScreen.js.map +1 -1
  80. package/lib/module/ui/screens/SignUpScreen.js +141 -743
  81. package/lib/module/ui/screens/SignUpScreen.js.map +1 -1
  82. package/lib/module/ui/screens/internal/SignInPasswordStep.js +3 -3
  83. package/lib/module/ui/screens/internal/SignInPasswordStep.js.map +1 -1
  84. package/lib/module/ui/screens/internal/SignInUsernameStep.js +2 -2
  85. package/lib/module/ui/screens/internal/SignInUsernameStep.js.map +1 -1
  86. package/lib/module/ui/screens/steps/RecoverRequestStep.js +105 -0
  87. package/lib/module/ui/screens/steps/RecoverRequestStep.js.map +1 -0
  88. package/lib/module/ui/screens/steps/RecoverSuccessStep.js +133 -0
  89. package/lib/module/ui/screens/steps/RecoverSuccessStep.js.map +1 -0
  90. package/lib/module/ui/screens/steps/RecoverVerifyStep.js +136 -0
  91. package/lib/module/ui/screens/steps/RecoverVerifyStep.js.map +1 -0
  92. package/lib/module/ui/screens/steps/SignInPasswordStep.js +160 -0
  93. package/lib/module/ui/screens/steps/SignInPasswordStep.js.map +1 -0
  94. package/lib/module/ui/screens/steps/SignInUsernameStep.js +145 -0
  95. package/lib/module/ui/screens/steps/SignInUsernameStep.js.map +1 -0
  96. package/lib/module/ui/screens/steps/SignUpIdentityStep.js +166 -0
  97. package/lib/module/ui/screens/steps/SignUpIdentityStep.js.map +1 -0
  98. package/lib/module/ui/screens/steps/SignUpSecurityStep.js +158 -0
  99. package/lib/module/ui/screens/steps/SignUpSecurityStep.js.map +1 -0
  100. package/lib/module/ui/screens/steps/SignUpSummaryStep.js +165 -0
  101. package/lib/module/ui/screens/steps/SignUpSummaryStep.js.map +1 -0
  102. package/lib/module/ui/screens/steps/SignUpWelcomeStep.js +67 -0
  103. package/lib/module/ui/screens/steps/SignUpWelcomeStep.js.map +1 -0
  104. package/lib/typescript/models/interfaces.d.ts +4 -3
  105. package/lib/typescript/models/interfaces.d.ts.map +1 -1
  106. package/lib/typescript/ui/components/AnimationExample.d.ts +1 -1
  107. package/lib/typescript/ui/components/AnimationExample.d.ts.map +1 -1
  108. package/lib/typescript/ui/components/OxyPayButton.d.ts +2 -2
  109. package/lib/typescript/ui/components/OxyPayButton.d.ts.map +1 -1
  110. package/lib/typescript/ui/components/Section.d.ts +2 -1
  111. package/lib/typescript/ui/components/Section.d.ts.map +1 -1
  112. package/lib/typescript/ui/components/SectionTitle.d.ts +2 -1
  113. package/lib/typescript/ui/components/SectionTitle.d.ts.map +1 -1
  114. package/lib/typescript/ui/components/StepBasedScreen.d.ts +24 -0
  115. package/lib/typescript/ui/components/StepBasedScreen.d.ts.map +1 -0
  116. package/lib/typescript/ui/components/icon/FAIRWalletIcon.d.ts +2 -1
  117. package/lib/typescript/ui/components/icon/FAIRWalletIcon.d.ts.map +1 -1
  118. package/lib/typescript/ui/components/icon/OxyIcon.d.ts +1 -1
  119. package/lib/typescript/ui/components/icon/OxyIcon.d.ts.map +1 -1
  120. package/lib/typescript/ui/components/internal/PinInput.d.ts +9 -1
  121. package/lib/typescript/ui/components/internal/PinInput.d.ts.map +1 -1
  122. package/lib/typescript/ui/context/OxyContext.d.ts +2 -1
  123. package/lib/typescript/ui/context/OxyContext.d.ts.map +1 -1
  124. package/lib/typescript/ui/screens/PaymentGatewayScreen.d.ts +2 -2
  125. package/lib/typescript/ui/screens/PaymentGatewayScreen.d.ts.map +1 -1
  126. package/lib/typescript/ui/screens/ProfileScreen.d.ts.map +1 -1
  127. package/lib/typescript/ui/screens/RecoverAccountScreen.d.ts +2 -9
  128. package/lib/typescript/ui/screens/RecoverAccountScreen.d.ts.map +1 -1
  129. package/lib/typescript/ui/screens/SignInScreen.d.ts.map +1 -1
  130. package/lib/typescript/ui/screens/SignUpScreen.d.ts +1 -1
  131. package/lib/typescript/ui/screens/SignUpScreen.d.ts.map +1 -1
  132. package/lib/typescript/ui/screens/steps/RecoverRequestStep.d.ts +21 -0
  133. package/lib/typescript/ui/screens/steps/RecoverRequestStep.d.ts.map +1 -0
  134. package/lib/typescript/ui/screens/steps/RecoverSuccessStep.d.ts +18 -0
  135. package/lib/typescript/ui/screens/steps/RecoverSuccessStep.d.ts.map +1 -0
  136. package/lib/typescript/ui/screens/steps/RecoverVerifyStep.d.ts +24 -0
  137. package/lib/typescript/ui/screens/steps/RecoverVerifyStep.d.ts.map +1 -0
  138. package/lib/typescript/ui/screens/steps/SignInPasswordStep.d.ts +27 -0
  139. package/lib/typescript/ui/screens/steps/SignInPasswordStep.d.ts.map +1 -0
  140. package/lib/typescript/ui/screens/steps/SignInUsernameStep.d.ts +27 -0
  141. package/lib/typescript/ui/screens/steps/SignInUsernameStep.d.ts.map +1 -0
  142. package/lib/typescript/ui/screens/steps/SignUpIdentityStep.d.ts +25 -0
  143. package/lib/typescript/ui/screens/steps/SignUpIdentityStep.d.ts.map +1 -0
  144. package/lib/typescript/ui/screens/steps/SignUpSecurityStep.d.ts +26 -0
  145. package/lib/typescript/ui/screens/steps/SignUpSecurityStep.d.ts.map +1 -0
  146. package/lib/typescript/ui/screens/steps/SignUpSummaryStep.d.ts +16 -0
  147. package/lib/typescript/ui/screens/steps/SignUpSummaryStep.d.ts.map +1 -0
  148. package/lib/typescript/ui/screens/steps/SignUpWelcomeStep.d.ts +13 -0
  149. package/lib/typescript/ui/screens/steps/SignUpWelcomeStep.d.ts.map +1 -0
  150. package/package.json +2 -3
  151. package/src/models/interfaces.ts +5 -3
  152. package/src/ui/components/AnimationExample.tsx +9 -8
  153. package/src/ui/components/FollowButton.tsx +2 -2
  154. package/src/ui/components/Header.tsx +2 -2
  155. package/src/ui/components/OxyPayButton.tsx +2 -2
  156. package/src/ui/components/OxyProvider.tsx +4 -4
  157. package/src/ui/components/Section.tsx +7 -7
  158. package/src/ui/components/SectionTitle.tsx +2 -2
  159. package/src/ui/components/StepBasedScreen.README.md +337 -0
  160. package/src/ui/components/StepBasedScreen.tsx +417 -0
  161. package/src/ui/components/icon/FAIRWalletIcon.tsx +2 -2
  162. package/src/ui/components/icon/OxyIcon.tsx +10 -11
  163. package/src/ui/components/internal/PinInput.tsx +13 -4
  164. package/src/ui/components/photogrid/JustifiedPhotoGrid.tsx +1 -1
  165. package/src/ui/context/OxyContext.tsx +12 -11
  166. package/src/ui/screens/PaymentGatewayScreen.tsx +3 -3
  167. package/src/ui/screens/ProfileScreen.tsx +54 -54
  168. package/src/ui/screens/RecoverAccountScreen.tsx +98 -211
  169. package/src/ui/screens/SignInScreen.tsx +148 -271
  170. package/src/ui/screens/SignUpScreen.tsx +146 -748
  171. package/src/ui/screens/internal/SignInPasswordStep.tsx +3 -3
  172. package/src/ui/screens/internal/SignInUsernameStep.tsx +2 -2
  173. package/src/ui/screens/steps/RecoverRequestStep.tsx +130 -0
  174. package/src/ui/screens/steps/RecoverSuccessStep.tsx +131 -0
  175. package/src/ui/screens/steps/RecoverVerifyStep.tsx +153 -0
  176. package/src/ui/screens/steps/SignInPasswordStep.tsx +172 -0
  177. package/src/ui/screens/steps/SignInUsernameStep.tsx +176 -0
  178. package/src/ui/screens/steps/SignUpIdentityStep.tsx +204 -0
  179. package/src/ui/screens/steps/SignUpSecurityStep.tsx +191 -0
  180. package/src/ui/screens/steps/SignUpSummaryStep.tsx +130 -0
  181. package/src/ui/screens/steps/SignUpWelcomeStep.tsx +65 -0
@@ -0,0 +1,176 @@
1
+ import type React from 'react';
2
+ import { useRef, useEffect } from 'react';
3
+ import { View, Text } from 'react-native';
4
+ import { Ionicons } from '@expo/vector-icons';
5
+ import HighFive from '../../../assets/illustrations/HighFive';
6
+ import GroupedPillButtons from '../../components/internal/GroupedPillButtons';
7
+ import TextField from '../../components/internal/TextField';
8
+
9
+ interface SignInUsernameStepProps {
10
+ // Common props from StepBasedScreen
11
+ colors: any;
12
+ styles: any;
13
+ theme: string;
14
+ navigate: (screen: string, props?: Record<string, any>) => void;
15
+
16
+ // Step navigation
17
+ nextStep: () => void;
18
+ prevStep: () => void;
19
+ currentStep: number;
20
+ totalSteps: number;
21
+
22
+ // Data management
23
+ stepData?: any;
24
+ updateStepData: (data: any) => void;
25
+ allStepData: any[];
26
+
27
+ // Form state
28
+ username: string;
29
+ setUsername: (username: string) => void;
30
+ errorMessage: string;
31
+ setErrorMessage: (message: string) => void;
32
+ validationStatus: 'idle' | 'validating' | 'valid' | 'invalid';
33
+ userProfile: any;
34
+ isValidating: boolean;
35
+
36
+ // Add account mode
37
+ isAddAccountMode?: boolean;
38
+ user?: any;
39
+
40
+ // Validation function
41
+ validateUsername: (username: string) => Promise<boolean>;
42
+ }
43
+
44
+ const SignInUsernameStep: React.FC<SignInUsernameStepProps> = ({
45
+ colors,
46
+ styles,
47
+ navigate,
48
+ nextStep,
49
+ username,
50
+ setUsername,
51
+ errorMessage,
52
+ setErrorMessage,
53
+ validationStatus,
54
+ userProfile,
55
+ isValidating,
56
+ isAddAccountMode,
57
+ user,
58
+ validateUsername,
59
+ }) => {
60
+ const inputRef = useRef<any>(null);
61
+
62
+ // Monitor username prop changes
63
+ useEffect(() => {
64
+ console.log('👀 SignInUsernameStep username prop changed:', username);
65
+ }, [username]);
66
+
67
+ const handleUsernameChange = (text: string) => {
68
+ console.log('📝 Username input changed:', text);
69
+ setUsername(text);
70
+ if (errorMessage) setErrorMessage('');
71
+ };
72
+
73
+ const handleContinue = async () => {
74
+ console.log('🚀 Continue button pressed, username:', username);
75
+
76
+ const trimmedUsername = username?.trim() || '';
77
+
78
+ if (!trimmedUsername) {
79
+ console.log('❌ Username is empty');
80
+ setErrorMessage('Please enter your username.');
81
+ setTimeout(() => inputRef.current?.focus(), 0);
82
+ return;
83
+ }
84
+
85
+ if (trimmedUsername.length < 2) {
86
+ console.log('❌ Username too short');
87
+ setErrorMessage('Username must be at least 3 characters.');
88
+ return;
89
+ }
90
+
91
+ console.log('🔍 Starting username validation...');
92
+ try {
93
+ // Validate the username before proceeding
94
+ const isValid = await validateUsername(trimmedUsername);
95
+ console.log('📊 Validation result:', isValid);
96
+
97
+ if (isValid) {
98
+ console.log('✅ Validation passed, proceeding to next step');
99
+ nextStep();
100
+ } else {
101
+ console.log('❌ Validation failed, staying on current step');
102
+ }
103
+ } catch (error) {
104
+ console.error('🚨 Error during validation:', error);
105
+ setErrorMessage('Unable to validate username. Please try again.');
106
+ }
107
+ };
108
+
109
+ return (
110
+ <>
111
+ <HighFive width={100} height={100} />
112
+ <View style={styles.modernHeader}>
113
+ <Text style={[styles.modernTitle, { color: colors.text }]}>
114
+ {isAddAccountMode ? 'Add Another Account' : 'Sign In'}
115
+ </Text>
116
+ <Text style={[styles.modernSubtitle, { color: colors.secondaryText }]}>
117
+ {isAddAccountMode
118
+ ? 'Sign in with another account'
119
+ : 'Sign in to continue your journey'
120
+ }
121
+ </Text>
122
+ </View>
123
+
124
+ {isAddAccountMode && user && (
125
+ <View style={[styles.modernInfoCard, { backgroundColor: colors.inputBackground }]}>
126
+ <Ionicons name="information-circle" size={20} color={colors.primary} />
127
+ <Text style={[styles.modernInfoText, { color: colors.text }]}>
128
+ Currently signed in as <Text style={{ fontWeight: 'bold' }}>{user.username}</Text>
129
+ </Text>
130
+ </View>
131
+ )}
132
+
133
+ <View style={styles.modernInputContainer}>
134
+ <TextField
135
+ ref={inputRef}
136
+ label="Username"
137
+ leading={<Ionicons name="person-outline" size={24} color={colors.secondaryText} />}
138
+ value={username}
139
+ onChangeText={handleUsernameChange}
140
+ autoCapitalize="none"
141
+ autoCorrect={false}
142
+ testID="username-input"
143
+ variant="filled"
144
+ error={validationStatus === 'invalid' ? errorMessage : undefined}
145
+ loading={validationStatus === 'validating'}
146
+ success={validationStatus === 'valid'}
147
+ onSubmitEditing={() => handleContinue()}
148
+ autoFocus
149
+ />
150
+ </View>
151
+
152
+ <GroupedPillButtons
153
+ buttons={[
154
+ {
155
+ text: 'Sign Up',
156
+ onPress: () => navigate('SignUp'),
157
+ icon: 'person-add',
158
+ variant: 'transparent',
159
+ },
160
+ {
161
+ text: 'Continue',
162
+ onPress: handleContinue,
163
+ icon: 'arrow-forward',
164
+ variant: 'primary',
165
+ loading: isValidating,
166
+ disabled: !username || username.trim().length < 2 || isValidating,
167
+ testID: 'username-next-button',
168
+ },
169
+ ]}
170
+ colors={colors}
171
+ />
172
+ </>
173
+ );
174
+ };
175
+
176
+ export default SignInUsernameStep;
@@ -0,0 +1,204 @@
1
+ import type React from 'react';
2
+ import { useRef, useState, useEffect, useCallback } from 'react';
3
+ import { View, Text } from 'react-native';
4
+ import { Ionicons } from '@expo/vector-icons';
5
+ import GroupedPillButtons from '../../components/internal/GroupedPillButtons';
6
+ import TextField from '../../components/internal/TextField';
7
+
8
+ interface SignUpIdentityStepProps {
9
+ // Common props from StepBasedScreen
10
+ colors: any;
11
+ styles: any;
12
+ theme: string;
13
+ navigate: (screen: string, props?: Record<string, any>) => void;
14
+
15
+ // Step navigation
16
+ nextStep: () => void;
17
+ prevStep: () => void;
18
+ currentStep: number;
19
+ totalSteps: number;
20
+
21
+ // Data management
22
+ stepData?: any;
23
+ updateStepData: (data: any) => void;
24
+
25
+ // Form state
26
+ username: string;
27
+ email: string;
28
+ setUsername: (username: string) => void;
29
+ setEmail: (email: string) => void;
30
+ validationState: any;
31
+ setValidationState: (state: any) => void;
32
+ setErrorMessage: (message: string) => void;
33
+
34
+ // Validation
35
+ validateEmail: (email: string) => boolean;
36
+ validateUsername: (username: string) => Promise<boolean>;
37
+ }
38
+
39
+ const SignUpIdentityStep: React.FC<SignUpIdentityStepProps> = ({
40
+ colors,
41
+ styles,
42
+ navigate,
43
+ nextStep,
44
+ prevStep,
45
+ username,
46
+ email,
47
+ setUsername,
48
+ setEmail,
49
+ validationState,
50
+ setValidationState,
51
+ setErrorMessage,
52
+ validateEmail,
53
+ validateUsername,
54
+ }) => {
55
+ const usernameRef = useRef<any>(null);
56
+ const validationTimeoutRef = useRef<NodeJS.Timeout | null>(null);
57
+
58
+ // Debounced username validation
59
+ const debouncedValidateUsername = useCallback((usernameToValidate: string) => {
60
+ if (validationTimeoutRef.current) {
61
+ clearTimeout(validationTimeoutRef.current);
62
+ }
63
+
64
+ validationTimeoutRef.current = setTimeout(async () => {
65
+ if (usernameToValidate.trim().length >= 3) {
66
+ await validateUsername(usernameToValidate.trim());
67
+ }
68
+ }, 500);
69
+ }, [validateUsername]);
70
+
71
+ // Cleanup timeout on unmount
72
+ useEffect(() => {
73
+ return () => {
74
+ if (validationTimeoutRef.current) {
75
+ clearTimeout(validationTimeoutRef.current);
76
+ }
77
+ };
78
+ }, []);
79
+
80
+ const handleUsernameChange = (text: string) => {
81
+ setUsername(text);
82
+ setErrorMessage('');
83
+ // Reset validation state when user types
84
+ if (validationState.status !== 'idle') {
85
+ setValidationState({ status: 'idle', message: '' });
86
+ }
87
+
88
+ // Trigger debounced validation
89
+ debouncedValidateUsername(text);
90
+ };
91
+
92
+ const handleEmailChange = (text: string) => {
93
+ setEmail(text);
94
+ setErrorMessage('');
95
+ };
96
+
97
+ const handleNext = async () => {
98
+ if (!username.trim()) {
99
+ setErrorMessage('Please enter a username');
100
+ setTimeout(() => usernameRef.current?.focus(), 0);
101
+ return;
102
+ }
103
+
104
+ if (username.trim().length < 3) {
105
+ setErrorMessage('Username must be at least 3 characters');
106
+ setTimeout(() => usernameRef.current?.focus(), 0);
107
+ return;
108
+ }
109
+
110
+ if (!email.trim()) {
111
+ setErrorMessage('Please enter an email address');
112
+ return;
113
+ }
114
+
115
+ if (!validateEmail(email)) {
116
+ setErrorMessage('Please enter a valid email address');
117
+ return;
118
+ }
119
+
120
+ // Validate username availability
121
+ const isUsernameValid = await validateUsername(username.trim());
122
+ if (!isUsernameValid) {
123
+ setTimeout(() => usernameRef.current?.focus(), 0);
124
+ return;
125
+ }
126
+
127
+ nextStep();
128
+ };
129
+
130
+ const emailError = email && !validateEmail(email) ? 'Please enter a valid email address' : undefined;
131
+
132
+ return (
133
+ <>
134
+ <View style={styles.modernHeader}>
135
+ <Text style={[styles.modernTitle, { color: colors.text }]}>
136
+ Who are you?
137
+ </Text>
138
+ <Text style={[styles.modernSubtitle, { color: colors.secondaryText }]}>
139
+ Choose your username and enter your email
140
+ </Text>
141
+ </View>
142
+
143
+ <View style={styles.modernInputContainer}>
144
+ <TextField
145
+ ref={usernameRef}
146
+ label="Username"
147
+ leading={<Ionicons name="person-outline" size={24} color={colors.secondaryText} />}
148
+ value={username}
149
+ onChangeText={handleUsernameChange}
150
+ autoCapitalize="none"
151
+ autoCorrect={false}
152
+ testID="signup-username-input"
153
+ variant="filled"
154
+ error={validationState.status === 'invalid' ? validationState.message : undefined}
155
+ loading={validationState.status === 'validating'}
156
+ success={validationState.status === 'valid'}
157
+ onSubmitEditing={handleNext}
158
+ autoFocus
159
+ />
160
+
161
+ <TextField
162
+ label="Email"
163
+ leading={<Ionicons name="mail-outline" size={24} color={colors.secondaryText} />}
164
+ value={email}
165
+ onChangeText={handleEmailChange}
166
+ keyboardType="email-address"
167
+ autoCapitalize="none"
168
+ autoCorrect={false}
169
+ testID="signup-email-input"
170
+ variant="filled"
171
+ error={emailError}
172
+ onSubmitEditing={handleNext}
173
+ />
174
+ </View>
175
+
176
+ <GroupedPillButtons
177
+ buttons={[
178
+ {
179
+ text: 'Back',
180
+ onPress: prevStep,
181
+ icon: 'arrow-back',
182
+ variant: 'transparent',
183
+ },
184
+ {
185
+ text: 'Next',
186
+ onPress: handleNext,
187
+ icon: 'arrow-forward',
188
+ variant: 'primary',
189
+ loading: validationState.status === 'validating',
190
+ disabled: !username.trim() ||
191
+ username.trim().length < 3 ||
192
+ !email.trim() ||
193
+ !validateEmail(email) ||
194
+ validationState.status === 'validating' ||
195
+ validationState.status === 'invalid',
196
+ },
197
+ ]}
198
+ colors={colors}
199
+ />
200
+ </>
201
+ );
202
+ };
203
+
204
+ export default SignUpIdentityStep;
@@ -0,0 +1,191 @@
1
+ import type React from 'react';
2
+ import { useRef, useState } from 'react';
3
+ import { View, Text, TouchableOpacity } from 'react-native';
4
+ import { Ionicons } from '@expo/vector-icons';
5
+ import GroupedPillButtons from '../../components/internal/GroupedPillButtons';
6
+ import TextField from '../../components/internal/TextField';
7
+
8
+ interface SignUpSecurityStepProps {
9
+ // Common props from StepBasedScreen
10
+ colors: any;
11
+ styles: any;
12
+ theme: string;
13
+ navigate: (screen: string, props?: Record<string, any>) => void;
14
+
15
+ // Step navigation
16
+ nextStep: () => void;
17
+ prevStep: () => void;
18
+ currentStep: number;
19
+ totalSteps: number;
20
+
21
+ // Data management
22
+ stepData?: any;
23
+ updateStepData: (data: any) => void;
24
+
25
+ // Form state
26
+ password: string;
27
+ confirmPassword: string;
28
+ setPassword: (password: string) => void;
29
+ setConfirmPassword: (confirmPassword: string) => void;
30
+ showPassword: boolean;
31
+ showConfirmPassword: boolean;
32
+ setShowPassword: (show: boolean) => void;
33
+ setShowConfirmPassword: (show: boolean) => void;
34
+ setErrorMessage: (message: string) => void;
35
+
36
+ // Validation
37
+ validatePassword: (password: string) => boolean;
38
+ }
39
+
40
+ const SignUpSecurityStep: React.FC<SignUpSecurityStepProps> = ({
41
+ colors,
42
+ styles,
43
+ nextStep,
44
+ prevStep,
45
+ password,
46
+ confirmPassword,
47
+ setPassword,
48
+ setConfirmPassword,
49
+ showPassword,
50
+ showConfirmPassword,
51
+ setShowPassword,
52
+ setShowConfirmPassword,
53
+ setErrorMessage,
54
+ validatePassword,
55
+ }) => {
56
+ const passwordRef = useRef<any>(null);
57
+
58
+ const handlePasswordChange = (text: string) => {
59
+ setPassword(text);
60
+ setErrorMessage('');
61
+ };
62
+
63
+ const handleConfirmPasswordChange = (text: string) => {
64
+ setConfirmPassword(text);
65
+ setErrorMessage('');
66
+ };
67
+
68
+ const handleNext = () => {
69
+ if (!password) {
70
+ setErrorMessage('Please enter a password');
71
+ setTimeout(() => passwordRef.current?.focus(), 0);
72
+ return;
73
+ }
74
+
75
+ if (!validatePassword(password)) {
76
+ setErrorMessage('Password must be at least 8 characters long');
77
+ return;
78
+ }
79
+
80
+ if (!confirmPassword) {
81
+ setErrorMessage('Please confirm your password');
82
+ return;
83
+ }
84
+
85
+ if (password !== confirmPassword) {
86
+ setErrorMessage('Passwords do not match');
87
+ return;
88
+ }
89
+
90
+ nextStep();
91
+ };
92
+
93
+ const passwordError = password && !validatePassword(password) ? 'Password must be at least 8 characters long' : undefined;
94
+ const confirmPasswordError = confirmPassword && password !== confirmPassword ? 'Passwords do not match' : undefined;
95
+
96
+ return (
97
+ <>
98
+ <View style={styles.modernHeader}>
99
+ <Text style={[styles.modernTitle, { color: colors.text }]}>
100
+ Secure Your Account
101
+ </Text>
102
+ <Text style={[styles.modernSubtitle, { color: colors.secondaryText }]}>
103
+ Create a strong password to protect your account
104
+ </Text>
105
+ </View>
106
+
107
+ <View style={styles.modernInputContainer}>
108
+ <TextField
109
+ ref={passwordRef}
110
+ label="Password"
111
+ leading={<Ionicons name="lock-closed-outline" size={24} color={colors.secondaryText} />}
112
+ trailing={
113
+ <TouchableOpacity
114
+ onPress={() => setShowPassword(!showPassword)}
115
+ style={{ padding: 4 }}
116
+ >
117
+ <Ionicons
118
+ name={showPassword ? "eye-off-outline" : "eye-outline"}
119
+ size={20}
120
+ color={colors.secondaryText}
121
+ />
122
+ </TouchableOpacity>
123
+ }
124
+ value={password}
125
+ onChangeText={handlePasswordChange}
126
+ secureTextEntry={!showPassword}
127
+ autoCapitalize="none"
128
+ autoCorrect={false}
129
+ testID="signup-password-input"
130
+ variant="filled"
131
+ error={passwordError}
132
+ onSubmitEditing={handleNext}
133
+ autoFocus
134
+ />
135
+
136
+ <TextField
137
+ label="Confirm Password"
138
+ leading={<Ionicons name="lock-closed-outline" size={24} color={colors.secondaryText} />}
139
+ trailing={
140
+ <TouchableOpacity
141
+ onPress={() => setShowConfirmPassword(!showConfirmPassword)}
142
+ style={{ padding: 4 }}
143
+ >
144
+ <Ionicons
145
+ name={showConfirmPassword ? "eye-off-outline" : "eye-outline"}
146
+ size={20}
147
+ color={colors.secondaryText}
148
+ />
149
+ </TouchableOpacity>
150
+ }
151
+ value={confirmPassword}
152
+ onChangeText={handleConfirmPasswordChange}
153
+ secureTextEntry={!showConfirmPassword}
154
+ autoCapitalize="none"
155
+ autoCorrect={false}
156
+ testID="signup-confirm-password-input"
157
+ variant="filled"
158
+ error={confirmPasswordError}
159
+ onSubmitEditing={handleNext}
160
+ />
161
+
162
+ <View style={{ marginTop: 16 }}>
163
+ <Text style={[styles.footerText, { color: colors.secondaryText, fontSize: 12 }]}>
164
+ Password must be at least 8 characters long
165
+ </Text>
166
+ </View>
167
+ </View>
168
+
169
+ <GroupedPillButtons
170
+ buttons={[
171
+ {
172
+ text: 'Back',
173
+ onPress: prevStep,
174
+ icon: 'arrow-back',
175
+ variant: 'transparent',
176
+ },
177
+ {
178
+ text: 'Next',
179
+ onPress: handleNext,
180
+ icon: 'arrow-forward',
181
+ variant: 'primary',
182
+ disabled: !password || !confirmPassword || password !== confirmPassword,
183
+ },
184
+ ]}
185
+ colors={colors}
186
+ />
187
+ </>
188
+ );
189
+ };
190
+
191
+ export default SignUpSecurityStep;
@@ -0,0 +1,130 @@
1
+ import type React from 'react';
2
+ import { View, Text } from 'react-native';
3
+ import { Ionicons } from '@expo/vector-icons';
4
+ import GroupedPillButtons from '../../components/internal/GroupedPillButtons';
5
+
6
+ interface SignUpSummaryStepProps {
7
+ // Common props from StepBasedScreen
8
+ colors: any;
9
+ styles: any;
10
+ theme: string;
11
+ navigate: (screen: string, props?: Record<string, any>) => void;
12
+
13
+ // Step navigation
14
+ nextStep: () => void;
15
+ prevStep: () => void;
16
+ currentStep: number;
17
+ totalSteps: number;
18
+
19
+ // Data management
20
+ allStepData: any[];
21
+
22
+ // Form state
23
+ isLoading: boolean;
24
+ }
25
+
26
+ const SignUpSummaryStep: React.FC<SignUpSummaryStepProps> = ({
27
+ colors,
28
+ styles,
29
+ nextStep,
30
+ prevStep,
31
+ allStepData,
32
+ isLoading,
33
+ }) => {
34
+ // Extract data from previous steps
35
+ const identityData = allStepData[1] || {}; // Step 2 (index 1)
36
+ const securityData = allStepData[2] || {}; // Step 3 (index 2)
37
+
38
+ const { username = '', email = '' } = identityData;
39
+ const { password = '' } = securityData;
40
+
41
+ // Check if all required data is available
42
+ const hasValidData = username && email && password;
43
+
44
+
45
+
46
+ return (
47
+ <>
48
+ <View style={styles.modernHeader}>
49
+ <Text style={[styles.modernTitle, { color: colors.text }]}>
50
+ Almost There!
51
+ </Text>
52
+ <Text style={[styles.modernSubtitle, { color: colors.secondaryText }]}>
53
+ Review your information and create your account
54
+ </Text>
55
+ </View>
56
+
57
+ <View style={[styles.modernInputContainer, { marginBottom: 32 }]}>
58
+ <View style={{
59
+ backgroundColor: colors.inputBackground,
60
+ borderRadius: 16,
61
+ padding: 20,
62
+ borderWidth: 1,
63
+ borderColor: colors.border,
64
+ }}>
65
+ <View style={{ flexDirection: 'row', alignItems: 'center', marginBottom: 16 }}>
66
+ <Ionicons name="person-outline" size={20} color={colors.secondaryText} style={{ marginRight: 12 }} />
67
+ <View style={{ flex: 1 }}>
68
+ <Text style={[styles.footerText, { color: colors.secondaryText, fontSize: 12, marginBottom: 4 }]}>
69
+ Username
70
+ </Text>
71
+ <Text style={[styles.modernInput, { color: colors.text, fontSize: 16 }]}>
72
+ @{username || 'Not set'}
73
+ </Text>
74
+ </View>
75
+ </View>
76
+
77
+ <View style={{ flexDirection: 'row', alignItems: 'center' }}>
78
+ <Ionicons name="mail-outline" size={20} color={colors.secondaryText} style={{ marginRight: 12 }} />
79
+ <View style={{ flex: 1 }}>
80
+ <Text style={[styles.footerText, { color: colors.secondaryText, fontSize: 12, marginBottom: 4 }]}>
81
+ Email
82
+ </Text>
83
+ <Text style={[styles.modernInput, { color: colors.text, fontSize: 16 }]}>
84
+ {email || 'Not set'}
85
+ </Text>
86
+ </View>
87
+ </View>
88
+ </View>
89
+
90
+ <View style={{
91
+ flexDirection: 'row',
92
+ alignItems: 'center',
93
+ marginTop: 16,
94
+ padding: 12,
95
+ backgroundColor: colors.success + '10',
96
+ borderRadius: 8,
97
+ borderWidth: 1,
98
+ borderColor: colors.success + '30',
99
+ }}>
100
+ <Ionicons name="checkmark-circle" size={20} color={colors.success} style={{ marginRight: 8 }} />
101
+ <Text style={[styles.footerText, { color: colors.success, fontSize: 14, flex: 1 }]}>
102
+ By creating an account, you agree to our Terms of Service and Privacy Policy
103
+ </Text>
104
+ </View>
105
+ </View>
106
+
107
+ <GroupedPillButtons
108
+ buttons={[
109
+ {
110
+ text: 'Back',
111
+ onPress: prevStep,
112
+ icon: 'arrow-back',
113
+ variant: 'transparent',
114
+ },
115
+ {
116
+ text: 'Create Account',
117
+ onPress: nextStep,
118
+ icon: 'checkmark-circle',
119
+ variant: 'primary',
120
+ loading: isLoading,
121
+ disabled: !hasValidData,
122
+ },
123
+ ]}
124
+ colors={colors}
125
+ />
126
+ </>
127
+ );
128
+ };
129
+
130
+ export default SignUpSummaryStep;