@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
@@ -3,6 +3,7 @@ import { useEffect, useState } from 'react';
3
3
  import { View, Text, StyleSheet, ActivityIndicator, ScrollView, TouchableOpacity, Image } from 'react-native';
4
4
  import type { BaseScreenProps } from '../navigation/types';
5
5
  import { useOxy } from '../context/OxyContext';
6
+ import { useThemeColors } from '../styles';
6
7
  import Avatar from '../components/Avatar';
7
8
  import { FollowButton } from '../components';
8
9
  import { useFollow } from '../hooks/useFollow';
@@ -39,10 +40,8 @@ const ProfileScreen: React.FC<ProfileScreenProps> = ({ userId, username, theme,
39
40
  setFollowingCount,
40
41
  } = useFollow(userId);
41
42
 
42
- const isDarkTheme = theme === 'dark';
43
- const backgroundColor = isDarkTheme ? '#121212' : '#FFFFFF';
44
- const textColor = isDarkTheme ? '#FFFFFF' : '#000000';
45
- const primaryColor = '#d169e5';
43
+ const colors = useThemeColors(theme);
44
+ const styles = createStyles(colors);
46
45
 
47
46
  // Check if current user is viewing their own profile
48
47
  const isOwnProfile = currentUser && currentUser.id === userId;
@@ -154,27 +153,27 @@ const ProfileScreen: React.FC<ProfileScreenProps> = ({ userId, username, theme,
154
153
 
155
154
  if (isLoading) {
156
155
  return (
157
- <View style={[styles.container, { backgroundColor, justifyContent: 'center' }]}>
158
- <ActivityIndicator size="large" color={primaryColor} />
156
+ <View style={[styles.container, { backgroundColor: colors.background, justifyContent: 'center' }]}>
157
+ <ActivityIndicator size="large" color={colors.primary} />
159
158
  </View>
160
159
  );
161
160
  }
162
161
 
163
162
  if (error) {
164
163
  return (
165
- <View style={[styles.container, { backgroundColor }]}>
164
+ <View style={[styles.container, { backgroundColor: colors.background }]}>
166
165
  <View style={styles.errorHeader}>
167
166
  {goBack && (
168
167
  <TouchableOpacity onPress={goBack} style={styles.backButton}>
169
- <Ionicons name="arrow-back" size={24} color={textColor} />
168
+ <Ionicons name="arrow-back" size={24} color={colors.text} />
170
169
  </TouchableOpacity>
171
170
  )}
172
- <Text style={[styles.errorTitle, { color: textColor }]}>Profile Error</Text>
171
+ <Text style={[styles.errorTitle, { color: colors.text }]}>Profile Error</Text>
173
172
  </View>
174
173
  <View style={styles.errorContent}>
175
- <Ionicons name="alert-circle" size={48} color="#D32F2F" style={styles.errorIcon} />
176
- <Text style={[styles.errorText, { color: '#D32F2F' }]}>{error}</Text>
177
- <Text style={[styles.errorSubtext, { color: textColor }]}>
174
+ <Ionicons name="alert-circle" size={48} color={colors.error} style={styles.errorIcon} />
175
+ <Text style={[styles.errorText, { color: colors.error }]}>{error}</Text>
176
+ <Text style={[styles.errorSubtext, { color: colors.secondaryText }]}>
178
177
  This could happen if the user doesn't exist or the profile service is unavailable.
179
178
  </Text>
180
179
  </View>
@@ -183,7 +182,7 @@ const ProfileScreen: React.FC<ProfileScreenProps> = ({ userId, username, theme,
183
182
  }
184
183
 
185
184
  return (
186
- <View style={[styles.container, { backgroundColor }]}>
185
+ <View style={[styles.container, { backgroundColor: colors.background }]}>
187
186
  <ScrollView contentContainerStyle={styles.scrollContainer}>
188
187
  {/* Banner Image */}
189
188
  <View style={styles.bannerContainer}>
@@ -222,55 +221,55 @@ const ProfileScreen: React.FC<ProfileScreenProps> = ({ userId, username, theme,
222
221
  </View>
223
222
  {/* Profile Info */}
224
223
  <View style={styles.header}>
225
- <Text style={[styles.displayName, { color: textColor }]}>{profile?.displayName || profile?.username || username || profile?.id}</Text>
224
+ <Text style={[styles.displayName, { color: colors.text }]}>{profile?.displayName || profile?.username || username || profile?.id}</Text>
226
225
  {profile?.username && (
227
- <Text style={[styles.subText, { color: isDarkTheme ? '#BBBBBB' : '#888888' }]}>@{profile.username}</Text>
226
+ <Text style={[styles.subText, { color: colors.secondaryText }]}>@{profile.username}</Text>
228
227
  )}
229
228
  {/* Bio placeholder */}
230
- <Text style={[styles.bio, { color: textColor }]}>{profile?.bio || 'This user has no bio yet.'}</Text>
229
+ <Text style={[styles.bio, { color: colors.text }]}>{profile?.bio || 'This user has no bio yet.'}</Text>
231
230
 
232
231
  {/* Info Grid Row */}
233
232
  <View style={styles.infoGrid}>
234
233
  {profile?.createdAt && (
235
234
  <View style={styles.infoGridItem}>
236
- <Ionicons name="calendar-outline" size={16} color={isDarkTheme ? '#BBBBBB' : '#888888'} style={{ marginRight: 6 }} />
237
- <Text style={[styles.infoGridText, { color: isDarkTheme ? '#BBBBBB' : '#888888' }]}>Joined {new Date(profile.createdAt).toLocaleDateString()}</Text>
235
+ <Ionicons name="calendar-outline" size={16} color={colors.secondaryText} style={{ marginRight: 6 }} />
236
+ <Text style={[styles.infoGridText, { color: colors.secondaryText }]}>Joined {new Date(profile.createdAt).toLocaleDateString()}</Text>
238
237
  </View>
239
238
  )}
240
239
  {profile?.location && (
241
240
  <View style={styles.infoGridItem}>
242
- <Ionicons name="location-outline" size={16} color={isDarkTheme ? '#BBBBBB' : '#888888'} style={{ marginRight: 6 }} />
243
- <Text style={[styles.infoGridText, { color: isDarkTheme ? '#BBBBBB' : '#888888' }]} numberOfLines={1}>{profile.location}</Text>
241
+ <Ionicons name="location-outline" size={16} color={colors.secondaryText} style={{ marginRight: 6 }} />
242
+ <Text style={[styles.infoGridText, { color: colors.secondaryText }]} numberOfLines={1}>{profile.location}</Text>
244
243
  </View>
245
244
  )}
246
245
  {profile?.website && (
247
246
  <View style={styles.infoGridItem}>
248
- <Ionicons name="globe-outline" size={16} color={isDarkTheme ? '#BBBBBB' : '#888888'} style={{ marginRight: 6 }} />
249
- <Text style={[styles.infoGridText, { color: isDarkTheme ? '#BBBBBB' : '#888888' }]} numberOfLines={1}>{profile.website}</Text>
247
+ <Ionicons name="globe-outline" size={16} color={colors.secondaryText} style={{ marginRight: 6 }} />
248
+ <Text style={[styles.infoGridText, { color: colors.secondaryText }]} numberOfLines={1}>{profile.website}</Text>
250
249
  </View>
251
250
  )}
252
251
  {profile?.company && (
253
252
  <View style={styles.infoGridItem}>
254
- <Ionicons name="business-outline" size={16} color={isDarkTheme ? '#BBBBBB' : '#888888'} style={{ marginRight: 6 }} />
255
- <Text style={[styles.infoGridText, { color: isDarkTheme ? '#BBBBBB' : '#888888' }]} numberOfLines={1}>{profile.company}</Text>
253
+ <Ionicons name="business-outline" size={16} color={colors.secondaryText} style={{ marginRight: 6 }} />
254
+ <Text style={[styles.infoGridText, { color: colors.secondaryText }]} numberOfLines={1}>{profile.company}</Text>
256
255
  </View>
257
256
  )}
258
257
  {profile?.jobTitle && (
259
258
  <View style={styles.infoGridItem}>
260
- <Ionicons name="briefcase-outline" size={16} color={isDarkTheme ? '#BBBBBB' : '#888888'} style={{ marginRight: 6 }} />
261
- <Text style={[styles.infoGridText, { color: isDarkTheme ? '#BBBBBB' : '#888888' }]} numberOfLines={1}>{profile.jobTitle}</Text>
259
+ <Ionicons name="briefcase-outline" size={16} color={colors.secondaryText} style={{ marginRight: 6 }} />
260
+ <Text style={[styles.infoGridText, { color: colors.secondaryText }]} numberOfLines={1}>{profile.jobTitle}</Text>
262
261
  </View>
263
262
  )}
264
263
  {profile?.education && (
265
264
  <View style={styles.infoGridItem}>
266
- <Ionicons name="school-outline" size={16} color={isDarkTheme ? '#BBBBBB' : '#888888'} style={{ marginRight: 6 }} />
267
- <Text style={[styles.infoGridText, { color: isDarkTheme ? '#BBBBBB' : '#888888' }]} numberOfLines={1}>{profile.education}</Text>
265
+ <Ionicons name="school-outline" size={16} color={colors.secondaryText} style={{ marginRight: 6 }} />
266
+ <Text style={[styles.infoGridText, { color: colors.secondaryText }]} numberOfLines={1}>{profile.education}</Text>
268
267
  </View>
269
268
  )}
270
269
  {profile?.birthday && (
271
270
  <View style={styles.infoGridItem}>
272
- <Ionicons name="gift-outline" size={16} color={isDarkTheme ? '#BBBBBB' : '#888888'} style={{ marginRight: 6 }} />
273
- <Text style={[styles.infoGridText, { color: isDarkTheme ? '#BBBBBB' : '#888888' }]}>Born {new Date(profile.birthday).toLocaleDateString()}</Text>
271
+ <Ionicons name="gift-outline" size={16} color={colors.secondaryText} style={{ marginRight: 6 }} />
272
+ <Text style={[styles.infoGridText, { color: colors.secondaryText }]}>Born {new Date(profile.birthday).toLocaleDateString()}</Text>
274
273
  </View>
275
274
  )}
276
275
  {links.length > 0 && (
@@ -278,12 +277,12 @@ const ProfileScreen: React.FC<ProfileScreenProps> = ({ userId, username, theme,
278
277
  style={styles.infoGridItem}
279
278
  onPress={() => navigate?.('UserLinks', { userId, links })}
280
279
  >
281
- <Ionicons name="link-outline" size={16} color={isDarkTheme ? '#BBBBBB' : '#888888'} style={{ marginRight: 6 }} />
282
- <Text style={[styles.infoGridText, { color: isDarkTheme ? '#BBBBBB' : '#888888' }]} numberOfLines={1}>
280
+ <Ionicons name="link-outline" size={16} color={colors.secondaryText} style={{ marginRight: 6 }} />
281
+ <Text style={[styles.infoGridText, { color: colors.secondaryText }]} numberOfLines={1}>
283
282
  {links[0].url}
284
283
  </Text>
285
284
  {links.length > 1 && (
286
- <Text style={[styles.linksMore, { color: isDarkTheme ? '#BBBBBB' : '#888888' }]}>
285
+ <Text style={[styles.linksMore, { color: colors.secondaryText }]}>
287
286
  + {links.length - 1} more
288
287
  </Text>
289
288
  )}
@@ -295,24 +294,24 @@ const ProfileScreen: React.FC<ProfileScreenProps> = ({ userId, username, theme,
295
294
  {/* All Stats in one row */}
296
295
  <View style={styles.statsRow}>
297
296
  <View style={styles.statItem}>
298
- <Text style={[styles.karmaAmount, { color: primaryColor }]}>{karmaTotal !== null && karmaTotal !== undefined ? karmaTotal : '--'}</Text>
299
- <Text style={[styles.karmaLabel, { color: isDarkTheme ? '#BBBBBB' : '#888888' }]}>Karma</Text>
297
+ <Text style={[styles.karmaAmount, { color: colors.primary }]}>{karmaTotal !== null && karmaTotal !== undefined ? karmaTotal : '--'}</Text>
298
+ <Text style={[styles.karmaLabel, { color: colors.secondaryText }]}>Karma</Text>
300
299
  </View>
301
300
  <View style={styles.statItem}>
302
301
  {isLoadingCounts ? (
303
- <ActivityIndicator size="small" color={textColor} />
302
+ <ActivityIndicator size="small" color={colors.text} />
304
303
  ) : (
305
- <Text style={[styles.karmaAmount, { color: textColor }]}>{followerCount !== null ? followerCount : '--'}</Text>
304
+ <Text style={[styles.karmaAmount, { color: colors.text }]}>{followerCount !== null ? followerCount : '--'}</Text>
306
305
  )}
307
- <Text style={[styles.karmaLabel, { color: isDarkTheme ? '#BBBBBB' : '#888888' }]}>Followers</Text>
306
+ <Text style={[styles.karmaLabel, { color: colors.secondaryText }]}>Followers</Text>
308
307
  </View>
309
308
  <View style={styles.statItem}>
310
309
  {isLoadingCounts ? (
311
- <ActivityIndicator size="small" color={textColor} />
310
+ <ActivityIndicator size="small" color={colors.text} />
312
311
  ) : (
313
- <Text style={[styles.karmaAmount, { color: textColor }]}>{followingCount !== null ? followingCount : '--'}</Text>
312
+ <Text style={[styles.karmaAmount, { color: colors.text }]}>{followingCount !== null ? followingCount : '--'}</Text>
314
313
  )}
315
- <Text style={[styles.karmaLabel, { color: isDarkTheme ? '#BBBBBB' : '#888888' }]}>Following</Text>
314
+ <Text style={[styles.karmaLabel, { color: colors.secondaryText }]}>Following</Text>
316
315
  </View>
317
316
  </View>
318
317
  </View>
@@ -321,37 +320,37 @@ const ProfileScreen: React.FC<ProfileScreenProps> = ({ userId, username, theme,
321
320
  );
322
321
  };
323
322
 
324
- const styles = StyleSheet.create({
323
+ const createStyles = (colors: any) => StyleSheet.create({
325
324
  container: { flex: 1 },
326
325
  scrollContainer: { alignItems: 'stretch', paddingBottom: 40 },
327
- bannerContainer: { height: 160, backgroundColor: '#e1bee7', position: 'relative', overflow: 'hidden' },
328
- bannerImage: { flex: 1, backgroundColor: '#d169e5' }, // Placeholder, replace with Image if available
326
+ bannerContainer: { height: 160, backgroundColor: colors.primary + '20', position: 'relative', overflow: 'hidden' },
327
+ bannerImage: { flex: 1, backgroundColor: colors.primary }, // Placeholder, replace with Image if available
329
328
  avatarRow: { flexDirection: 'row', alignItems: 'flex-end', marginTop: -56, paddingHorizontal: 20, justifyContent: 'space-between', zIndex: 2 },
330
- avatarWrapper: { borderWidth: 5, borderColor: '#fff', borderRadius: 64, overflow: 'hidden', backgroundColor: '#fff', },
329
+ avatarWrapper: { borderWidth: 5, borderColor: colors.background, borderRadius: 64, overflow: 'hidden', backgroundColor: colors.background },
331
330
  actionButtonWrapper: { flex: 1, alignItems: 'flex-end', justifyContent: 'flex-end' },
332
331
  actionButton: {
333
- backgroundColor: '#fff',
332
+ backgroundColor: colors.background,
334
333
  borderWidth: 1,
335
- borderColor: '#d169e5',
334
+ borderColor: colors.primary,
336
335
  borderRadius: 24,
337
336
  paddingVertical: 7,
338
337
  paddingHorizontal: 22,
339
338
  marginBottom: 8,
340
339
  elevation: 2,
341
- shadowColor: '#d169e5',
340
+ shadowColor: colors.primary,
342
341
  shadowOffset: { width: 0, height: 1 },
343
342
  shadowOpacity: 0.08,
344
343
  shadowRadius: 2
345
344
  },
346
345
  actionButtonText: {
347
- color: '#d169e5',
346
+ color: colors.primary,
348
347
  fontWeight: 'bold',
349
348
  fontSize: 16
350
349
  },
351
350
  header: { alignItems: 'flex-start', width: '100%', paddingHorizontal: 20 },
352
351
  displayName: { fontSize: 24, fontWeight: 'bold', marginTop: 10, marginBottom: 2, letterSpacing: 0.1 },
353
- subText: { fontSize: 16, marginBottom: 2, color: '#a0a0a0' },
354
- bio: { fontSize: 16, marginTop: 10, marginBottom: 10, color: '#666', lineHeight: 22 },
352
+ subText: { fontSize: 16, marginBottom: 2, color: colors.secondaryText },
353
+ bio: { fontSize: 16, marginTop: 10, marginBottom: 10, color: colors.text, lineHeight: 22 },
355
354
  infoGrid: {
356
355
  flexDirection: 'row',
357
356
  alignItems: 'center',
@@ -365,16 +364,17 @@ const styles = StyleSheet.create({
365
364
  marginBottom: 4
366
365
  },
367
366
  infoGridText: {
368
- fontSize: 15
367
+ fontSize: 15,
368
+ color: colors.text
369
369
  },
370
- divider: { height: 1, backgroundColor: '#e0e0e0', width: '100%', marginVertical: 14 },
370
+ divider: { height: 1, backgroundColor: colors.border, width: '100%', marginVertical: 14 },
371
371
  linksMore: {
372
372
  fontSize: 15,
373
373
  marginLeft: 4
374
374
  },
375
375
  statsRow: { width: '100%', flex: 1, flexDirection: 'row', alignItems: 'center', marginTop: 6, marginBottom: 2, justifyContent: 'space-between' },
376
376
  statItem: { flex: 1, alignItems: 'center', minWidth: 50, marginBottom: 12 },
377
- karmaLabel: { fontSize: 14, marginBottom: 2, textAlign: 'center', color: '#a0a0a0' },
377
+ karmaLabel: { fontSize: 14, marginBottom: 2, textAlign: 'center', color: colors.secondaryText },
378
378
  karmaAmount: { fontSize: 24, fontWeight: 'bold', textAlign: 'center', letterSpacing: 0.2 },
379
379
  // Error handling styles
380
380
  errorHeader: {
@@ -1,230 +1,117 @@
1
1
  import type React from 'react';
2
2
  import { useState, useRef, useCallback } from 'react';
3
- import { View, Text, Animated, KeyboardAvoidingView, Platform, ScrollView, StyleSheet, StatusBar, type TextInput } from 'react-native';
4
- import { Ionicons } from '@expo/vector-icons';
5
- import TextField from '../components/internal/TextField';
6
- import GroupedPillButtons from '../components/internal/GroupedPillButtons';
7
- import HighFive from '../../assets/illustrations/HighFive';
8
- import { useThemeColors, createAuthStyles } from '../styles';
9
- import PinInput from '../components/internal/PinInput';
10
-
11
- interface RecoverAccountScreenProps {
12
- navigate: (screen: string, props?: Record<string, any>) => void;
13
- goBack: () => void;
14
- theme: string;
15
- returnTo?: string;
16
- returnStep?: number;
17
- returnData?: Record<string, any>;
18
- }
3
+ import type { BaseScreenProps } from '../navigation/types';
4
+ import { useThemeColors } from '../styles';
5
+ import StepBasedScreen, { type StepConfig } from '../components/StepBasedScreen';
6
+ import RecoverRequestStep from './steps/RecoverRequestStep';
7
+ import RecoverVerifyStep from './steps/RecoverVerifyStep';
8
+ import RecoverSuccessStep from './steps/RecoverSuccessStep';
19
9
 
10
+ // Constants
20
11
  const PIN_LENGTH = 6;
21
12
 
22
- const RecoverAccountScreen: React.FC<RecoverAccountScreenProps> = ({ navigate, goBack, theme, returnTo, returnStep, returnData }) => {
13
+ // Main component
14
+ const RecoverAccountScreen: React.FC<BaseScreenProps> = ({
15
+ navigate,
16
+ goBack,
17
+ theme,
18
+ oxyServices,
19
+ }) => {
20
+ const colors = useThemeColors(theme);
21
+
22
+ // Form state
23
23
  const [identifier, setIdentifier] = useState('');
24
+ const [verificationCode, setVerificationCode] = useState('');
24
25
  const [isLoading, setIsLoading] = useState(false);
25
26
  const [errorMessage, setErrorMessage] = useState('');
26
27
  const [successMessage, setSuccessMessage] = useState('');
27
- const [step, setStep] = useState<'request' | 'code' | 'done'>('request');
28
- const [code, setCode] = useState('');
29
- const fadeAnim = useRef(new Animated.Value(1)).current;
30
- const slideAnim = useRef(new Animated.Value(0)).current;
31
- const colors = useThemeColors(theme as 'light' | 'dark');
32
- const styles = createAuthStyles(colors, theme);
33
- const identifierRef = useRef<TextInput>(null);
34
- const handleRequestWithFocus = () => {
35
- if (!identifier) {
36
- setTimeout(() => {
37
- identifierRef.current?.focus();
38
- }, 0);
39
- }
40
- handleRequest();
41
- };
42
28
 
43
- const handleRequest = async () => {
44
- setErrorMessage('');
45
- setSuccessMessage('');
46
- if (!identifier || identifier.length < 3) {
47
- setErrorMessage('Please enter your email or username.');
48
- return;
49
- }
50
- setIsLoading(true);
51
- setTimeout(() => {
52
- setIsLoading(false);
53
- setStep('code');
54
- setSuccessMessage('A 6-digit code has been sent to your email or phone.');
55
- }, 1200);
56
- };
29
+ // Handle back navigation
30
+ const handleBack = useCallback(() => {
31
+ navigate('SignIn');
32
+ }, [navigate]);
57
33
 
58
- const handleVerifyCode = async () => {
59
- setErrorMessage('');
60
- setSuccessMessage('');
61
- if (code.length !== PIN_LENGTH) {
62
- setErrorMessage('Please enter the 6-digit code.');
63
- return;
64
- }
65
- setIsLoading(true);
66
- setTimeout(() => {
67
- setIsLoading(false);
68
- if (code === '123456') { // Simulate correct code
69
- setStep('done');
34
+ // Step configurations
35
+ const steps: StepConfig[] = [
36
+ {
37
+ id: 'request',
38
+ component: RecoverRequestStep,
39
+ canProceed: () => identifier.trim().length >= 3,
40
+ onEnter: () => {
41
+ // Reset messages when entering request step
42
+ setErrorMessage('');
43
+ setSuccessMessage('');
44
+ },
45
+ },
46
+ {
47
+ id: 'verify',
48
+ component: RecoverVerifyStep,
49
+ canProceed: () => verificationCode.length === PIN_LENGTH,
50
+ onEnter: () => {
51
+ // Simulate sending verification code
52
+ setIsLoading(true);
53
+ setTimeout(() => {
54
+ setIsLoading(false);
55
+ setSuccessMessage('A 6-digit code has been sent to your email or phone.');
56
+ }, 1000);
57
+ },
58
+ },
59
+ {
60
+ id: 'success',
61
+ component: RecoverSuccessStep,
62
+ canProceed: () => true,
63
+ onEnter: () => {
70
64
  setSuccessMessage('Your account has been verified! You can now reset your password.');
71
- } else {
72
- setErrorMessage('Invalid code. Please try again.');
73
- }
74
- }, 1200);
75
- };
65
+ },
66
+ },
67
+ ];
76
68
 
77
- // Helper function to determine back action based on current step
78
- const handleBack = () => {
79
- console.log('RecoverAccount handleBack:', { step, returnTo, returnStep, returnData });
69
+ // Handle completion
70
+ const handleComplete = useCallback((stepData: any[]) => {
71
+ // Final step completed - could navigate to password reset
72
+ console.log('Account recovery completed');
73
+ }, []);
80
74
 
81
- if (step === 'code') {
82
- setStep('request');
83
- } else if (step === 'done') {
84
- // If we have return information, use it; otherwise go to SignIn
85
- if (returnTo && returnStep !== undefined) {
86
- console.log('Navigating back to', returnTo, 'with step', returnStep, 'and data', returnData);
87
- navigate(returnTo, {
88
- initialStep: returnStep,
89
- ...returnData
90
- });
91
- } else {
92
- navigate('SignIn');
93
- }
94
- } else {
95
- // For 'request' step, if we have return information, use it; otherwise go back
96
- if (returnTo && returnStep !== undefined) {
97
- console.log('Navigating back to', returnTo, 'with step', returnStep, 'and data', returnData);
98
- navigate(returnTo, {
99
- initialStep: returnStep,
100
- ...returnData
101
- });
102
- } else {
103
- goBack();
104
- }
105
- }
106
- };
75
+ // Step data for the reusable component
76
+ const stepData = [
77
+ // Request step
78
+ {
79
+ identifier,
80
+ setIdentifier,
81
+ errorMessage,
82
+ setErrorMessage,
83
+ isLoading,
84
+ setIsLoading,
85
+ },
86
+ // Verify step
87
+ {
88
+ verificationCode,
89
+ setVerificationCode,
90
+ errorMessage,
91
+ setErrorMessage,
92
+ successMessage,
93
+ setSuccessMessage,
94
+ isLoading,
95
+ setIsLoading,
96
+ },
97
+ // Success step
98
+ {
99
+ successMessage,
100
+ },
101
+ ];
107
102
 
108
103
  return (
109
- <KeyboardAvoidingView
110
- style={[styles.container, { backgroundColor: colors.background }]}
111
- behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
112
- >
113
- <StatusBar
114
- barStyle={theme === 'dark' ? 'light-content' : 'dark-content'}
115
- backgroundColor={colors.background}
116
- />
117
- <ScrollView
118
- contentContainerStyle={styles.scrollContent}
119
- showsVerticalScrollIndicator={false}
120
- keyboardShouldPersistTaps="handled"
121
- >
122
- <Animated.View style={[
123
- styles.stepContainer,
124
- { opacity: fadeAnim, transform: [{ translateX: slideAnim }] }
125
- ]}>
126
- <HighFive width={100} height={100} />
127
- <View style={styles.modernHeader}>
128
- <Text style={[styles.modernTitle, { color: colors.text }]}>Recover Account</Text>
129
- <Text style={[styles.modernSubtitle, { color: colors.secondaryText }]}>Enter your email or username to receive a 6-digit code.</Text>
130
- </View>
131
- {step === 'request' && (
132
- <>
133
- <TextField
134
- ref={identifierRef}
135
- label="Email or Username"
136
- leading={<Ionicons name="mail-outline" size={24} color={colors.secondaryText} />}
137
- value={identifier}
138
- onChangeText={setIdentifier}
139
- autoCapitalize="none"
140
- autoCorrect={false}
141
- variant="filled"
142
- error={errorMessage || undefined}
143
- editable={!isLoading}
144
- autoFocus
145
- testID="recover-identifier-input"
146
- onSubmitEditing={handleRequestWithFocus}
147
- />
148
- <GroupedPillButtons
149
- buttons={[
150
- {
151
- text: 'Back',
152
- onPress: handleBack,
153
- icon: 'arrow-back',
154
- variant: 'transparent',
155
- },
156
- {
157
- text: 'Send Code',
158
- onPress: handleRequest,
159
- icon: 'mail-open-outline',
160
- variant: 'primary',
161
- loading: isLoading,
162
- disabled: isLoading,
163
- },
164
- ]}
165
- colors={colors}
166
- />
167
- </>
168
- )}
169
- {step === 'code' && (
170
- <>
171
- <PinInput
172
- value={code}
173
- onChange={setCode}
174
- length={PIN_LENGTH}
175
- disabled={isLoading}
176
- autoFocus
177
- colors={colors}
178
- />
179
- {successMessage && (
180
- <View style={styles.belowInputMessage}>
181
- <Ionicons name="checkmark-circle" size={16} color={colors.success} />
182
- <Text style={[styles.belowInputText, { color: colors.success }]}>{successMessage}</Text>
183
- </View>
184
- )}
185
- {errorMessage ? (
186
- <Text style={[styles.successText, { color: colors.error, marginBottom: 12 }]}>{errorMessage}</Text>
187
- ) : null}
188
- <GroupedPillButtons
189
- buttons={[
190
- {
191
- text: 'Back',
192
- onPress: handleBack,
193
- icon: 'arrow-back',
194
- variant: 'transparent',
195
- },
196
- {
197
- text: 'Verify Code',
198
- onPress: handleVerifyCode,
199
- icon: 'checkmark-circle-outline',
200
- variant: 'primary',
201
- loading: isLoading,
202
- disabled: isLoading,
203
- },
204
- ]}
205
- colors={colors}
206
- />
207
- </>
208
- )}
209
- {step === 'done' && (
210
- <>
211
- <Text style={[styles.successText, { color: colors.success, marginBottom: 24 }]}>{successMessage}</Text>
212
- <GroupedPillButtons
213
- buttons={[
214
- {
215
- text: 'Back',
216
- onPress: handleBack,
217
- icon: 'arrow-back',
218
- variant: 'primary',
219
- },
220
- ]}
221
- colors={colors}
222
- />
223
- </>
224
- )}
225
- </Animated.View>
226
- </ScrollView>
227
- </KeyboardAvoidingView>
104
+ <StepBasedScreen
105
+ steps={steps}
106
+ stepData={stepData}
107
+ onComplete={handleComplete}
108
+ navigate={navigate}
109
+ goBack={handleBack}
110
+ theme={theme}
111
+ oxyServices={oxyServices}
112
+ showProgressIndicator={true}
113
+ enableAnimations={true}
114
+ />
228
115
  );
229
116
  };
230
117