@oxyhq/services 5.11.10 → 5.11.11

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 (170) 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/Header.js +2 -2
  4. package/lib/commonjs/ui/components/Header.js.map +1 -1
  5. package/lib/commonjs/ui/components/OxyProvider.js.map +1 -1
  6. package/lib/commonjs/ui/components/StepBasedScreen.README.md +337 -0
  7. package/lib/commonjs/ui/components/StepBasedScreen.js +361 -0
  8. package/lib/commonjs/ui/components/StepBasedScreen.js.map +1 -0
  9. package/lib/commonjs/ui/components/icon/OxyIcon.js +3 -3
  10. package/lib/commonjs/ui/components/icon/OxyIcon.js.map +1 -1
  11. package/lib/commonjs/ui/components/internal/PinInput.js +1 -1
  12. package/lib/commonjs/ui/components/internal/PinInput.js.map +1 -1
  13. package/lib/commonjs/ui/components/photogrid/JustifiedPhotoGrid.js.map +1 -1
  14. package/lib/commonjs/ui/context/OxyContext.js +7 -7
  15. package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
  16. package/lib/commonjs/ui/screens/ProfileScreen.js +55 -55
  17. package/lib/commonjs/ui/screens/ProfileScreen.js.map +1 -1
  18. package/lib/commonjs/ui/screens/RecoverAccountScreen.js +87 -219
  19. package/lib/commonjs/ui/screens/RecoverAccountScreen.js.map +1 -1
  20. package/lib/commonjs/ui/screens/SignInScreen.js +138 -235
  21. package/lib/commonjs/ui/screens/SignInScreen.js.map +1 -1
  22. package/lib/commonjs/ui/screens/SignUpScreen.js +139 -742
  23. package/lib/commonjs/ui/screens/SignUpScreen.js.map +1 -1
  24. package/lib/commonjs/ui/screens/internal/SignInPasswordStep.js +3 -3
  25. package/lib/commonjs/ui/screens/internal/SignInPasswordStep.js.map +1 -1
  26. package/lib/commonjs/ui/screens/internal/SignInUsernameStep.js +2 -2
  27. package/lib/commonjs/ui/screens/internal/SignInUsernameStep.js.map +1 -1
  28. package/lib/commonjs/ui/screens/steps/RecoverRequestStep.js +110 -0
  29. package/lib/commonjs/ui/screens/steps/RecoverRequestStep.js.map +1 -0
  30. package/lib/commonjs/ui/screens/steps/RecoverSuccessStep.js +138 -0
  31. package/lib/commonjs/ui/screens/steps/RecoverSuccessStep.js.map +1 -0
  32. package/lib/commonjs/ui/screens/steps/RecoverVerifyStep.js +141 -0
  33. package/lib/commonjs/ui/screens/steps/RecoverVerifyStep.js.map +1 -0
  34. package/lib/commonjs/ui/screens/steps/SignInPasswordStep.js +165 -0
  35. package/lib/commonjs/ui/screens/steps/SignInPasswordStep.js.map +1 -0
  36. package/lib/commonjs/ui/screens/steps/SignInUsernameStep.js +150 -0
  37. package/lib/commonjs/ui/screens/steps/SignInUsernameStep.js.map +1 -0
  38. package/lib/commonjs/ui/screens/steps/SignUpIdentityStep.js +171 -0
  39. package/lib/commonjs/ui/screens/steps/SignUpIdentityStep.js.map +1 -0
  40. package/lib/commonjs/ui/screens/steps/SignUpSecurityStep.js +163 -0
  41. package/lib/commonjs/ui/screens/steps/SignUpSecurityStep.js.map +1 -0
  42. package/lib/commonjs/ui/screens/steps/SignUpSummaryStep.js +170 -0
  43. package/lib/commonjs/ui/screens/steps/SignUpSummaryStep.js.map +1 -0
  44. package/lib/commonjs/ui/screens/steps/SignUpWelcomeStep.js +72 -0
  45. package/lib/commonjs/ui/screens/steps/SignUpWelcomeStep.js.map +1 -0
  46. package/lib/module/ui/components/AnimationExample.js +1 -1
  47. package/lib/module/ui/components/AnimationExample.js.map +1 -1
  48. package/lib/module/ui/components/Header.js +2 -2
  49. package/lib/module/ui/components/Header.js.map +1 -1
  50. package/lib/module/ui/components/OxyProvider.js.map +1 -1
  51. package/lib/module/ui/components/Section.js.map +1 -1
  52. package/lib/module/ui/components/SectionTitle.js.map +1 -1
  53. package/lib/module/ui/components/StepBasedScreen.README.md +337 -0
  54. package/lib/module/ui/components/StepBasedScreen.js +356 -0
  55. package/lib/module/ui/components/StepBasedScreen.js.map +1 -0
  56. package/lib/module/ui/components/icon/FAIRWalletIcon.js.map +1 -1
  57. package/lib/module/ui/components/icon/OxyIcon.js +3 -3
  58. package/lib/module/ui/components/icon/OxyIcon.js.map +1 -1
  59. package/lib/module/ui/components/internal/PinInput.js +1 -1
  60. package/lib/module/ui/components/internal/PinInput.js.map +1 -1
  61. package/lib/module/ui/components/photogrid/JustifiedPhotoGrid.js.map +1 -1
  62. package/lib/module/ui/context/OxyContext.js +7 -7
  63. package/lib/module/ui/context/OxyContext.js.map +1 -1
  64. package/lib/module/ui/screens/ProfileScreen.js +55 -55
  65. package/lib/module/ui/screens/ProfileScreen.js.map +1 -1
  66. package/lib/module/ui/screens/RecoverAccountScreen.js +91 -222
  67. package/lib/module/ui/screens/RecoverAccountScreen.js.map +1 -1
  68. package/lib/module/ui/screens/SignInScreen.js +140 -237
  69. package/lib/module/ui/screens/SignInScreen.js.map +1 -1
  70. package/lib/module/ui/screens/SignUpScreen.js +141 -743
  71. package/lib/module/ui/screens/SignUpScreen.js.map +1 -1
  72. package/lib/module/ui/screens/internal/SignInPasswordStep.js +3 -3
  73. package/lib/module/ui/screens/internal/SignInPasswordStep.js.map +1 -1
  74. package/lib/module/ui/screens/internal/SignInUsernameStep.js +2 -2
  75. package/lib/module/ui/screens/internal/SignInUsernameStep.js.map +1 -1
  76. package/lib/module/ui/screens/steps/RecoverRequestStep.js +105 -0
  77. package/lib/module/ui/screens/steps/RecoverRequestStep.js.map +1 -0
  78. package/lib/module/ui/screens/steps/RecoverSuccessStep.js +133 -0
  79. package/lib/module/ui/screens/steps/RecoverSuccessStep.js.map +1 -0
  80. package/lib/module/ui/screens/steps/RecoverVerifyStep.js +136 -0
  81. package/lib/module/ui/screens/steps/RecoverVerifyStep.js.map +1 -0
  82. package/lib/module/ui/screens/steps/SignInPasswordStep.js +160 -0
  83. package/lib/module/ui/screens/steps/SignInPasswordStep.js.map +1 -0
  84. package/lib/module/ui/screens/steps/SignInUsernameStep.js +145 -0
  85. package/lib/module/ui/screens/steps/SignInUsernameStep.js.map +1 -0
  86. package/lib/module/ui/screens/steps/SignUpIdentityStep.js +166 -0
  87. package/lib/module/ui/screens/steps/SignUpIdentityStep.js.map +1 -0
  88. package/lib/module/ui/screens/steps/SignUpSecurityStep.js +158 -0
  89. package/lib/module/ui/screens/steps/SignUpSecurityStep.js.map +1 -0
  90. package/lib/module/ui/screens/steps/SignUpSummaryStep.js +165 -0
  91. package/lib/module/ui/screens/steps/SignUpSummaryStep.js.map +1 -0
  92. package/lib/module/ui/screens/steps/SignUpWelcomeStep.js +67 -0
  93. package/lib/module/ui/screens/steps/SignUpWelcomeStep.js.map +1 -0
  94. package/lib/typescript/models/interfaces.d.ts +4 -3
  95. package/lib/typescript/models/interfaces.d.ts.map +1 -1
  96. package/lib/typescript/ui/components/AnimationExample.d.ts +1 -1
  97. package/lib/typescript/ui/components/AnimationExample.d.ts.map +1 -1
  98. package/lib/typescript/ui/components/OxyPayButton.d.ts +2 -2
  99. package/lib/typescript/ui/components/OxyPayButton.d.ts.map +1 -1
  100. package/lib/typescript/ui/components/Section.d.ts +2 -1
  101. package/lib/typescript/ui/components/Section.d.ts.map +1 -1
  102. package/lib/typescript/ui/components/SectionTitle.d.ts +2 -1
  103. package/lib/typescript/ui/components/SectionTitle.d.ts.map +1 -1
  104. package/lib/typescript/ui/components/StepBasedScreen.d.ts +24 -0
  105. package/lib/typescript/ui/components/StepBasedScreen.d.ts.map +1 -0
  106. package/lib/typescript/ui/components/icon/FAIRWalletIcon.d.ts +2 -1
  107. package/lib/typescript/ui/components/icon/FAIRWalletIcon.d.ts.map +1 -1
  108. package/lib/typescript/ui/components/icon/OxyIcon.d.ts +1 -1
  109. package/lib/typescript/ui/components/icon/OxyIcon.d.ts.map +1 -1
  110. package/lib/typescript/ui/components/internal/PinInput.d.ts +9 -1
  111. package/lib/typescript/ui/components/internal/PinInput.d.ts.map +1 -1
  112. package/lib/typescript/ui/context/OxyContext.d.ts +2 -1
  113. package/lib/typescript/ui/context/OxyContext.d.ts.map +1 -1
  114. package/lib/typescript/ui/screens/PaymentGatewayScreen.d.ts +2 -2
  115. package/lib/typescript/ui/screens/PaymentGatewayScreen.d.ts.map +1 -1
  116. package/lib/typescript/ui/screens/ProfileScreen.d.ts.map +1 -1
  117. package/lib/typescript/ui/screens/RecoverAccountScreen.d.ts +2 -9
  118. package/lib/typescript/ui/screens/RecoverAccountScreen.d.ts.map +1 -1
  119. package/lib/typescript/ui/screens/SignInScreen.d.ts.map +1 -1
  120. package/lib/typescript/ui/screens/SignUpScreen.d.ts +1 -1
  121. package/lib/typescript/ui/screens/SignUpScreen.d.ts.map +1 -1
  122. package/lib/typescript/ui/screens/steps/RecoverRequestStep.d.ts +21 -0
  123. package/lib/typescript/ui/screens/steps/RecoverRequestStep.d.ts.map +1 -0
  124. package/lib/typescript/ui/screens/steps/RecoverSuccessStep.d.ts +18 -0
  125. package/lib/typescript/ui/screens/steps/RecoverSuccessStep.d.ts.map +1 -0
  126. package/lib/typescript/ui/screens/steps/RecoverVerifyStep.d.ts +24 -0
  127. package/lib/typescript/ui/screens/steps/RecoverVerifyStep.d.ts.map +1 -0
  128. package/lib/typescript/ui/screens/steps/SignInPasswordStep.d.ts +27 -0
  129. package/lib/typescript/ui/screens/steps/SignInPasswordStep.d.ts.map +1 -0
  130. package/lib/typescript/ui/screens/steps/SignInUsernameStep.d.ts +27 -0
  131. package/lib/typescript/ui/screens/steps/SignInUsernameStep.d.ts.map +1 -0
  132. package/lib/typescript/ui/screens/steps/SignUpIdentityStep.d.ts +25 -0
  133. package/lib/typescript/ui/screens/steps/SignUpIdentityStep.d.ts.map +1 -0
  134. package/lib/typescript/ui/screens/steps/SignUpSecurityStep.d.ts +26 -0
  135. package/lib/typescript/ui/screens/steps/SignUpSecurityStep.d.ts.map +1 -0
  136. package/lib/typescript/ui/screens/steps/SignUpSummaryStep.d.ts +16 -0
  137. package/lib/typescript/ui/screens/steps/SignUpSummaryStep.d.ts.map +1 -0
  138. package/lib/typescript/ui/screens/steps/SignUpWelcomeStep.d.ts +13 -0
  139. package/lib/typescript/ui/screens/steps/SignUpWelcomeStep.d.ts.map +1 -0
  140. package/package.json +2 -3
  141. package/src/models/interfaces.ts +5 -3
  142. package/src/ui/components/AnimationExample.tsx +9 -8
  143. package/src/ui/components/Header.tsx +2 -2
  144. package/src/ui/components/OxyPayButton.tsx +2 -2
  145. package/src/ui/components/OxyProvider.tsx +1 -1
  146. package/src/ui/components/Section.tsx +7 -7
  147. package/src/ui/components/SectionTitle.tsx +2 -2
  148. package/src/ui/components/StepBasedScreen.README.md +337 -0
  149. package/src/ui/components/StepBasedScreen.tsx +417 -0
  150. package/src/ui/components/icon/FAIRWalletIcon.tsx +2 -2
  151. package/src/ui/components/icon/OxyIcon.tsx +10 -11
  152. package/src/ui/components/internal/PinInput.tsx +13 -4
  153. package/src/ui/components/photogrid/JustifiedPhotoGrid.tsx +1 -1
  154. package/src/ui/context/OxyContext.tsx +12 -11
  155. package/src/ui/screens/PaymentGatewayScreen.tsx +2 -2
  156. package/src/ui/screens/ProfileScreen.tsx +54 -54
  157. package/src/ui/screens/RecoverAccountScreen.tsx +98 -211
  158. package/src/ui/screens/SignInScreen.tsx +148 -271
  159. package/src/ui/screens/SignUpScreen.tsx +146 -748
  160. package/src/ui/screens/internal/SignInPasswordStep.tsx +3 -3
  161. package/src/ui/screens/internal/SignInUsernameStep.tsx +2 -2
  162. package/src/ui/screens/steps/RecoverRequestStep.tsx +130 -0
  163. package/src/ui/screens/steps/RecoverSuccessStep.tsx +131 -0
  164. package/src/ui/screens/steps/RecoverVerifyStep.tsx +153 -0
  165. package/src/ui/screens/steps/SignInPasswordStep.tsx +172 -0
  166. package/src/ui/screens/steps/SignInUsernameStep.tsx +176 -0
  167. package/src/ui/screens/steps/SignUpIdentityStep.tsx +204 -0
  168. package/src/ui/screens/steps/SignUpSecurityStep.tsx +191 -0
  169. package/src/ui/screens/steps/SignUpSummaryStep.tsx +130 -0
  170. package/src/ui/screens/steps/SignUpWelcomeStep.tsx +65 -0
@@ -1,42 +1,12 @@
1
1
  import type React from 'react';
2
2
  import { useState, useRef, useEffect, useMemo, useCallback } from 'react';
3
- import {
4
- View,
5
- Text,
6
- TextInput,
7
- TouchableOpacity,
8
- StyleSheet,
9
- ActivityIndicator,
10
- Platform,
11
- KeyboardAvoidingView,
12
- ScrollView,
13
- TextStyle,
14
- Dimensions,
15
- StatusBar,
16
- Alert,
17
- } from 'react-native';
18
- import Animated, {
19
- useSharedValue,
20
- useAnimatedStyle,
21
- withSpring,
22
- withTiming,
23
- interpolate,
24
- runOnJS,
25
- Easing,
26
- } from 'react-native-reanimated';
27
3
  import type { BaseScreenProps } from '../navigation/types';
28
4
  import { useOxy } from '../context/OxyContext';
29
- import { fontFamilies, useThemeColors, createCommonStyles, createAuthStyles } from '../styles';
30
- import OxyLogo from '../components/OxyLogo';
31
- import Avatar from '../components/Avatar';
32
- import { Ionicons } from '@expo/vector-icons';
33
- import HighFive from '../../assets/illustrations/HighFive';
5
+ import { useThemeColors } from '../styles';
34
6
  import { toast } from '../../lib/sonner';
35
- import Svg, { Path, Circle } from 'react-native-svg';
36
- import GroupedPillButtons from '../components/internal/GroupedPillButtons';
37
- import TextField from '../components/internal/TextField';
38
- import SignInUsernameStep from './internal/SignInUsernameStep';
39
- import SignInPasswordStep from './internal/SignInPasswordStep';
7
+ import StepBasedScreen, { type StepConfig } from '../components/StepBasedScreen';
8
+ import SignInUsernameStep from './steps/SignInUsernameStep';
9
+ import SignInPasswordStep from './steps/SignInPasswordStep';
40
10
 
41
11
  const SignInScreen: React.FC<BaseScreenProps> = ({
42
12
  navigate,
@@ -47,39 +17,35 @@ const SignInScreen: React.FC<BaseScreenProps> = ({
47
17
  username: initialUsername,
48
18
  userProfile: initialUserProfile,
49
19
  }) => {
50
- // Only log props in development mode to reduce console noise
51
- if (__DEV__) {
52
- console.log('SignInScreen props:', { initialStep, initialUsername, initialUserProfile });
53
- }
54
20
  // Form data states
55
21
  const [username, setUsername] = useState(initialUsername || '');
56
22
  const [password, setPassword] = useState('');
57
23
  const [errorMessage, setErrorMessage] = useState('');
58
24
  const [userProfile, setUserProfile] = useState<any>(initialUserProfile || null);
59
25
  const [showPassword, setShowPassword] = useState(false);
60
-
61
- // Multi-step form states
62
- const [currentStep, setCurrentStep] = useState(initialStep || 0);
63
26
  const [isInputFocused, setIsInputFocused] = useState(false);
64
27
  const [isValidating, setIsValidating] = useState(false);
65
28
  const [validationStatus, setValidationStatus] = useState<'idle' | 'validating' | 'valid' | 'invalid'>(
66
29
  initialUserProfile ? 'valid' : 'idle'
67
30
  );
68
31
 
69
- // Cache for validation results to prevent repeated API calls
70
- const validationCache = useRef<Map<string, { profile: any; timestamp: number }>>(new Map());
32
+ // Monitor username state changes
33
+ useEffect(() => {
34
+ console.log('👀 SignInScreen username state changed:', username);
35
+ }, [username]);
71
36
 
72
- // Reanimated shared values
73
- const fadeAnim = useSharedValue(1);
74
- const slideAnim = useSharedValue(0);
75
- const scaleAnim = useSharedValue(1);
76
- const logoAnim = useSharedValue(0);
77
- const progressAnim = useSharedValue(initialStep ? 1.0 : 0.5);
37
+ // Cache for validation results to prevent repeated API calls
38
+ const validationCache = useRef<Map<string, { profile: any }>>(new Map());
78
39
 
79
40
  const { login, isLoading, user, isAuthenticated, sessions, oxyServices } = useOxy();
80
41
 
42
+ // Only log props in development mode to reduce console noise
43
+ if (__DEV__) {
44
+ console.log('SignInScreen props:', { initialStep, initialUsername, initialUserProfile });
45
+ console.log('🔧 oxyServices available:', !!oxyServices);
46
+ console.log('🔧 getProfileByUsername available:', typeof oxyServices?.getProfileByUsername);
47
+ }
81
48
  const colors = useThemeColors(theme);
82
- const commonStyles = createCommonStyles(theme);
83
49
 
84
50
  // Check if this should be treated as "Add Account" mode
85
51
  const isAddAccountMode = useMemo(() =>
@@ -87,66 +53,45 @@ const SignInScreen: React.FC<BaseScreenProps> = ({
87
53
  [isAuthenticated, sessions]
88
54
  );
89
55
 
90
- // Memoized styles to prevent rerenders
91
- const styles = useMemo(() => createAuthStyles(colors, theme), [colors, theme]);
92
-
93
- // Initialize logo animation
94
- useEffect(() => {
95
- logoAnim.value = withSpring(1, {
96
- damping: 15,
97
- stiffness: 150,
98
- });
99
- }, [logoAnim]);
100
-
101
- // Input focus handlers (no animation)
102
- const handleInputFocus = useCallback(() => {
103
- setIsInputFocused(true);
104
- }, []);
105
-
106
- const handleInputBlur = useCallback(() => {
107
- setIsInputFocused(false);
108
- }, []);
109
-
110
- // Memoized input change handlers to prevent re-renders
111
- const handleUsernameChange = useCallback((text: string) => {
112
- setUsername(text);
113
- // Clear error as soon as user edits username
114
- if (errorMessage) setErrorMessage('');
115
- setValidationStatus('idle');
116
- }, [errorMessage]);
117
-
118
- const handlePasswordChange = useCallback((text: string) => {
119
- setPassword(text);
120
- // Clear error as soon as user edits password
121
- if (errorMessage) setErrorMessage('');
122
- }, [errorMessage]);
123
-
124
56
  // Username validation using core services with caching
125
57
  const validateUsername = useCallback(async (usernameToValidate: string) => {
58
+ console.log('🔍 Validating username:', usernameToValidate);
59
+
126
60
  if (!usernameToValidate || usernameToValidate.length < 3) {
61
+ console.log('❌ Username too short');
62
+ setValidationStatus('invalid');
63
+ setErrorMessage('Username must be at least 3 characters.');
64
+ return false;
65
+ }
66
+
67
+ // Safety check for oxyServices
68
+ if (!oxyServices || typeof oxyServices.getProfileByUsername !== 'function') {
69
+ console.error('🚨 oxyServices not available or getProfileByUsername not found');
127
70
  setValidationStatus('invalid');
128
- setErrorMessage('Please enter a valid username.');
71
+ setErrorMessage('Service unavailable. Please try again.');
129
72
  return false;
130
73
  }
131
74
 
132
- // Check cache first (cache valid for 5 minutes)
75
+ // Check cache first
133
76
  const cached = validationCache.current.get(usernameToValidate);
134
- const now = Date.now();
135
- if (cached && (now - cached.timestamp) < 5 * 60 * 1000) {
77
+ if (cached) {
78
+ console.log('✅ Username found in cache:', cached.profile);
136
79
  setUserProfile(cached.profile);
137
80
  setValidationStatus('valid');
138
81
  setErrorMessage('');
139
82
  return true;
140
83
  }
141
84
 
85
+ console.log('🔄 Validating username with API...');
142
86
  setIsValidating(true);
143
87
  setValidationStatus('validating');
144
88
 
145
89
  try {
146
- // First check if username exists by trying to get profile
90
+ // Check if username exists
147
91
  const profile = await oxyServices.getProfileByUsername(usernameToValidate);
92
+ console.log('📋 Profile response:', profile);
148
93
 
149
- if (profile) {
94
+ if (profile && profile.username) {
150
95
  const profileData = {
151
96
  displayName: profile.name?.full || profile.name?.first || profile.username,
152
97
  name: profile.username,
@@ -154,30 +99,42 @@ const SignInScreen: React.FC<BaseScreenProps> = ({
154
99
  id: profile.id
155
100
  };
156
101
 
102
+ console.log('✅ Username is valid:', profileData);
157
103
  setUserProfile(profileData);
158
104
  setValidationStatus('valid');
159
- setErrorMessage(''); // Clear any previous errors
105
+ setErrorMessage('');
160
106
 
161
107
  // Cache the result
162
108
  validationCache.current.set(usernameToValidate, {
163
- profile: profileData,
164
- timestamp: now
109
+ profile: profileData
165
110
  });
166
111
 
167
112
  return true;
168
113
  } else {
114
+ console.log('❌ Username not found');
169
115
  setValidationStatus('invalid');
170
116
  setErrorMessage('Username not found.');
171
117
  return false;
172
118
  }
173
119
  } catch (error: any) {
120
+ console.log('🚨 Validation error:', error);
121
+
174
122
  // If user not found (404), username doesn't exist
175
123
  if (error.status === 404 || error.code === 'USER_NOT_FOUND') {
124
+ console.log('❌ Username not found (404)');
176
125
  setValidationStatus('invalid');
177
126
  setErrorMessage('Username not found.');
178
127
  return false;
179
128
  }
180
129
 
130
+ // For development/testing: if API fails, allow any 3+ character username
131
+ if (__DEV__) {
132
+ console.log('⚠️ Development mode: allowing username due to API error');
133
+ setValidationStatus('valid');
134
+ setErrorMessage('');
135
+ return true;
136
+ }
137
+
181
138
  // For other errors, show generic message
182
139
  console.error('Username validation error:', error);
183
140
  setValidationStatus('invalid');
@@ -188,113 +145,39 @@ const SignInScreen: React.FC<BaseScreenProps> = ({
188
145
  }
189
146
  }, [oxyServices]);
190
147
 
191
- // Debounced username validation - only run on explicit continue, not on every keystroke
192
- useEffect(() => {
193
- if (!username || username.length < 3) {
194
- setValidationStatus('idle');
195
- setUserProfile(null);
196
- setErrorMessage('');
197
- return;
198
- }
199
- // Only validate if we haven't already validated this exact username
200
- if (validationStatus === 'valid' && userProfile?.name === username) {
201
- return;
202
- }
203
- // Remove debounce, only validate on continue
204
- }, [username, validationStatus, userProfile?.name]);
205
-
206
- // Cleanup cache on unmount and limit cache size
207
- useEffect(() => {
208
- return () => {
209
- // Clear cache on unmount
210
- validationCache.current.clear();
211
- };
212
- }, []);
213
-
214
- // Clean up old cache entries periodically (older than 10 minutes)
215
- useEffect(() => {
216
- const cleanupInterval = setInterval(() => {
217
- const now = Date.now();
218
- const maxAge = 10 * 60 * 1000; // 10 minutes
219
-
220
- for (const [key, value] of validationCache.current.entries()) {
221
- if (now - value.timestamp > maxAge) {
222
- validationCache.current.delete(key);
223
- }
224
- }
148
+ // Input change handlers
149
+ const handleUsernameChange = useCallback((text: string) => {
150
+ console.log('🔄 SignInScreen handleUsernameChange called:', text);
151
+ setUsername(text);
152
+ if (errorMessage) setErrorMessage('');
153
+ setValidationStatus('idle');
154
+ }, [errorMessage]);
225
155
 
226
- // Limit cache size to 50 entries
227
- if (validationCache.current.size > 50) {
228
- const entries = Array.from(validationCache.current.entries());
229
- entries.sort((a, b) => a[1].timestamp - b[1].timestamp);
230
- const toDelete = entries.slice(0, entries.length - 50);
231
- toDelete.forEach(([key]) => validationCache.current.delete(key));
232
- }
233
- }, 5 * 60 * 1000); // Clean up every 5 minutes
156
+ const handlePasswordChange = useCallback((text: string) => {
157
+ setPassword(text);
158
+ if (errorMessage) setErrorMessage('');
159
+ }, [errorMessage]);
234
160
 
235
- return () => clearInterval(cleanupInterval);
161
+ const handleInputFocus = useCallback(() => {
162
+ setIsInputFocused(true);
236
163
  }, []);
237
164
 
238
- // Animation functions
239
- const animateTransition = useCallback((nextStep: number) => {
240
- // Scale down current content
241
- scaleAnim.value = withTiming(0.95, { duration: 150 });
242
-
243
- // Fade out and then animate in new content
244
- fadeAnim.value = withTiming(0, { duration: 200 }, (finished) => {
245
- if (finished) {
246
- runOnJS(setCurrentStep)(nextStep);
247
-
248
- // Reset animations
249
- slideAnim.value = -50;
250
- scaleAnim.value = 0.95;
251
-
252
- // Animate in new content
253
- fadeAnim.value = withTiming(1, { duration: 300 });
254
- slideAnim.value = withSpring(0, {
255
- damping: 15,
256
- stiffness: 200,
257
- });
258
- scaleAnim.value = withSpring(1, {
259
- damping: 15,
260
- stiffness: 200,
261
- });
262
- }
263
- });
264
- }, [fadeAnim, slideAnim, scaleAnim]);
265
-
266
- const nextStep = useCallback(() => {
267
- if (currentStep < 1) {
268
- // Animate progress bar
269
- progressAnim.value = withTiming(1.0, { duration: 300 });
270
- animateTransition(currentStep + 1);
271
- }
272
- }, [currentStep, progressAnim, animateTransition]);
273
-
274
- const prevStep = useCallback(() => {
275
- if (currentStep > 0) {
276
- // Animate progress bar
277
- progressAnim.value = withTiming(0.5, { duration: 300 });
278
- animateTransition(currentStep - 1);
279
- }
280
- }, [currentStep, progressAnim, animateTransition]);
165
+ const handleInputBlur = useCallback(() => {
166
+ setIsInputFocused(false);
167
+ }, []);
281
168
 
282
- // Custom next handlers for validation
283
- const handleUsernameContinue = useCallback(async () => {
169
+ // Step validation and handlers
170
+ const validateUsernameStep = useCallback(async () => {
284
171
  if (!username) {
285
172
  setErrorMessage('Please enter your username.');
286
- return;
173
+ return false;
287
174
  }
288
175
  setErrorMessage('');
289
176
  setIsValidating(true);
290
177
  const valid = await validateUsername(username);
291
178
  setIsValidating(false);
292
- if (!valid) {
293
- // Error message is set in validateUsername
294
- return;
295
- }
296
- nextStep();
297
- }, [username, validateUsername, nextStep]);
179
+ return valid;
180
+ }, [username, validateUsername]);
298
181
 
299
182
  const handleSignIn = useCallback(async () => {
300
183
  if (!password) {
@@ -316,93 +199,87 @@ const SignInScreen: React.FC<BaseScreenProps> = ({
316
199
  }
317
200
  }, [username, password, login, onAuthenticated, userProfile]);
318
201
 
319
- // Memoized step components
320
- const renderUsernameStep = useMemo(() => (
321
- <SignInUsernameStep
322
- styles={styles}
323
- fadeAnim={fadeAnim}
324
- slideAnim={slideAnim}
325
- scaleAnim={scaleAnim}
326
- colors={colors}
327
- isAddAccountMode={isAddAccountMode}
328
- user={user}
329
- errorMessage={errorMessage}
330
- isInputFocused={isInputFocused}
331
- username={username}
332
- validationStatus={validationStatus}
333
- userProfile={userProfile}
334
- isValidating={isValidating}
335
- handleInputFocus={handleInputFocus}
336
- handleInputBlur={handleInputBlur}
337
- handleUsernameChange={handleUsernameChange}
338
- handleUsernameContinue={handleUsernameContinue}
339
- navigate={navigate}
340
- />
341
- ), [
342
- fadeAnim, slideAnim, scaleAnim, colors, isAddAccountMode, user?.username,
343
- errorMessage, isInputFocused, username, validationStatus,
344
- userProfile, isValidating, handleInputFocus, handleInputBlur, handleUsernameChange,
345
- handleUsernameContinue, navigate, styles
346
- ]);
202
+ // Simple cleanup on unmount - that's all we need for username validation
203
+ useEffect(() => {
204
+ return () => {
205
+ validationCache.current.clear();
206
+ };
207
+ }, []);
347
208
 
348
- const renderPasswordStep = useMemo(() => (
349
- <SignInPasswordStep
350
- styles={styles}
351
- fadeAnim={fadeAnim}
352
- slideAnim={slideAnim}
353
- scaleAnim={scaleAnim}
354
- colors={colors}
355
- userProfile={userProfile}
356
- username={username}
357
- theme={theme}
358
- logoAnim={logoAnim}
359
- errorMessage={errorMessage}
360
- isInputFocused={isInputFocused}
361
- password={password}
362
- showPassword={showPassword}
363
- handleInputFocus={handleInputFocus}
364
- handleInputBlur={handleInputBlur}
365
- handlePasswordChange={handlePasswordChange}
366
- handleSignIn={handleSignIn}
367
- isLoading={isLoading}
368
- prevStep={prevStep}
369
- navigate={navigate}
370
- />
371
- ), [
372
- fadeAnim, slideAnim, scaleAnim, colors, userProfile, username, theme, logoAnim,
373
- errorMessage, isInputFocused, password, showPassword,
374
- handleInputFocus, handleInputBlur, handlePasswordChange, handleSignIn, isLoading, prevStep, styles, navigate
375
- ]);
209
+ // Step configurations
210
+ const steps: StepConfig[] = useMemo(() => [
211
+ {
212
+ id: 'username',
213
+ component: SignInUsernameStep,
214
+ canProceed: () => true, // Let the component handle validation internally
215
+ },
216
+ {
217
+ id: 'password',
218
+ component: SignInPasswordStep,
219
+ canProceed: () => true, // Let the component handle validation internally
220
+ },
221
+ ], [username, password, validationStatus, validateUsername, handleSignIn]);
222
+
223
+ // Handle step completion (final step)
224
+ const handleComplete = useCallback(async (stepData: any[]) => {
225
+ // The sign-in is handled by the password step component
226
+ // This callback is here for interface compatibility
227
+ console.log('Sign-in flow completed');
228
+ }, []);
376
229
 
377
- const renderCurrentStep = useCallback(() => {
378
- switch (currentStep) {
379
- case 0:
380
- return renderUsernameStep;
381
- case 1:
382
- return renderPasswordStep;
383
- default:
384
- return renderUsernameStep;
385
- }
386
- }, [currentStep, renderUsernameStep, renderPasswordStep]);
230
+ // Step data for the reusable component
231
+ const stepData = useMemo(() => [
232
+ {
233
+ username,
234
+ setUsername: handleUsernameChange,
235
+ errorMessage,
236
+ setErrorMessage,
237
+ validationStatus,
238
+ userProfile,
239
+ isValidating,
240
+ isInputFocused,
241
+ isAddAccountMode,
242
+ user,
243
+ handleInputFocus,
244
+ handleInputBlur,
245
+ validateUsername, // Add validation function
246
+ },
247
+ {
248
+ password,
249
+ setPassword: handlePasswordChange,
250
+ showPassword,
251
+ setShowPassword,
252
+ errorMessage,
253
+ setErrorMessage,
254
+ isLoading,
255
+ isInputFocused,
256
+ userProfile,
257
+ username,
258
+ handleInputFocus,
259
+ handleInputBlur,
260
+ handleSignIn, // Add sign-in function for password step
261
+ },
262
+ ], [
263
+ username, password, errorMessage, validationStatus, userProfile,
264
+ isValidating, isInputFocused, isAddAccountMode, user, showPassword,
265
+ isLoading, handleUsernameChange, handlePasswordChange, handleInputFocus, handleInputBlur,
266
+ validateUsername, handleSignIn
267
+ ]);
387
268
 
388
269
  return (
389
- <KeyboardAvoidingView
390
- style={[styles.container, { backgroundColor: colors.background }]}
391
- behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
392
- >
393
- <StatusBar
394
- barStyle={theme === 'dark' ? 'light-content' : 'dark-content'}
395
- backgroundColor={colors.background}
396
- />
397
-
398
- <ScrollView
399
- contentContainerStyle={styles.scrollContent}
400
- showsVerticalScrollIndicator={false}
401
- keyboardShouldPersistTaps="handled"
402
- >
403
- {renderCurrentStep()}
404
- </ScrollView>
405
- </KeyboardAvoidingView>
270
+ <StepBasedScreen
271
+ steps={steps}
272
+ initialStep={initialStep}
273
+ stepData={stepData}
274
+ onComplete={handleComplete}
275
+ navigate={navigate}
276
+ goBack={goBack}
277
+ onAuthenticated={onAuthenticated}
278
+ theme={theme}
279
+ showProgressIndicator={true}
280
+ enableAnimations={true}
281
+ oxyServices={oxyServices}
282
+ />
406
283
  );
407
284
  };
408
285