@oxyhq/services 5.4.3 → 5.4.4

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 (189) hide show
  1. package/README.md +14 -0
  2. package/lib/commonjs/assets/assets/illustrations/HighFive.tsx +41 -0
  3. package/lib/commonjs/assets/icons/OxyServices.js +1 -1
  4. package/lib/commonjs/assets/illustrations/HighFive.js +61 -0
  5. package/lib/commonjs/assets/illustrations/HighFive.js.map +1 -0
  6. package/lib/commonjs/core/index.js +2 -2
  7. package/lib/commonjs/index.js +22 -22
  8. package/lib/commonjs/index.js.map +1 -1
  9. package/lib/commonjs/node/createAuth.js +95 -0
  10. package/lib/commonjs/node/createAuth.js.map +1 -0
  11. package/lib/commonjs/node/index.js +15 -6
  12. package/lib/commonjs/node/index.js.map +1 -1
  13. package/lib/commonjs/package.json +1 -0
  14. package/lib/commonjs/ui/components/Avatar.js +3 -3
  15. package/lib/commonjs/ui/components/Avatar.js.map +1 -1
  16. package/lib/commonjs/ui/components/FollowButton.js +3 -3
  17. package/lib/commonjs/ui/components/GroupedSection.js +1 -1
  18. package/lib/commonjs/ui/components/OxyLogo.js +1 -1
  19. package/lib/commonjs/ui/components/OxyProvider.js +146 -141
  20. package/lib/commonjs/ui/components/OxyProvider.js.map +1 -1
  21. package/lib/commonjs/ui/components/OxySignInButton.js +2 -2
  22. package/lib/commonjs/ui/components/ProfileCard.js +2 -2
  23. package/lib/commonjs/ui/components/Section.js +1 -1
  24. package/lib/commonjs/ui/components/SectionTitle.js +1 -1
  25. package/lib/commonjs/ui/components/icon/index.js +1 -1
  26. package/lib/commonjs/ui/components/index.js +12 -12
  27. package/lib/commonjs/ui/components/internal/GroupedPillButtons.js +213 -0
  28. package/lib/commonjs/ui/components/internal/GroupedPillButtons.js.map +1 -0
  29. package/lib/commonjs/ui/components/internal/TextField.js +576 -0
  30. package/lib/commonjs/ui/components/internal/TextField.js.map +1 -0
  31. package/lib/commonjs/ui/context/OxyContext.js +1 -1
  32. package/lib/commonjs/ui/index.js +19 -11
  33. package/lib/commonjs/ui/index.js.map +1 -1
  34. package/lib/commonjs/ui/navigation/OxyRouter.js +23 -18
  35. package/lib/commonjs/ui/navigation/OxyRouter.js.map +1 -1
  36. package/lib/commonjs/ui/screens/AccountCenterScreen.js +18 -18
  37. package/lib/commonjs/ui/screens/AccountCenterScreen.js.map +1 -1
  38. package/lib/commonjs/ui/screens/AccountManagementDemo.js +3 -3
  39. package/lib/commonjs/ui/screens/AccountManagementDemo.js.map +1 -1
  40. package/lib/commonjs/ui/screens/AccountOverviewScreen.js +4 -4
  41. package/lib/commonjs/ui/screens/AccountSettingsScreen.js +5 -5
  42. package/lib/commonjs/ui/screens/AccountSwitcherScreen.js +3 -3
  43. package/lib/commonjs/ui/screens/AppInfoScreen.js +6 -6
  44. package/lib/commonjs/ui/screens/BillingManagementScreen.js +3 -3
  45. package/lib/commonjs/ui/screens/FeedbackScreen.js +1169 -0
  46. package/lib/commonjs/ui/screens/FeedbackScreen.js.map +1 -0
  47. package/lib/commonjs/ui/screens/FileManagementScreen.js +3 -3
  48. package/lib/commonjs/ui/screens/PremiumSubscriptionScreen.js +3 -3
  49. package/lib/commonjs/ui/screens/ProfileScreen.js +2 -2
  50. package/lib/commonjs/ui/screens/SessionManagementScreen.js +2 -2
  51. package/lib/commonjs/ui/screens/SignInScreen.js +182 -304
  52. package/lib/commonjs/ui/screens/SignInScreen.js.map +1 -1
  53. package/lib/commonjs/ui/screens/SignUpScreen.js +811 -712
  54. package/lib/commonjs/ui/screens/SignUpScreen.js.map +1 -1
  55. package/lib/commonjs/ui/screens/karma/KarmaCenterScreen.js +3 -3
  56. package/lib/commonjs/ui/screens/karma/KarmaLeaderboardScreen.js +2 -2
  57. package/lib/commonjs/ui/screens/karma/KarmaRulesScreen.js +1 -1
  58. package/lib/commonjs/ui/store/index.js +52 -0
  59. package/lib/commonjs/ui/store/index.js.map +1 -0
  60. package/lib/commonjs/ui/styles/index.js +2 -2
  61. package/lib/commonjs/ui/styles/theme.js +1 -1
  62. package/lib/commonjs/utils/index.js +1 -1
  63. package/lib/module/assets/assets/illustrations/HighFive.tsx +41 -0
  64. package/lib/module/assets/icons/OxyServices.js +1 -1
  65. package/lib/module/assets/icons/OxyServices.js.map +1 -1
  66. package/lib/module/assets/illustrations/HighFive.js +55 -0
  67. package/lib/module/assets/illustrations/HighFive.js.map +1 -0
  68. package/lib/module/core/index.js +2 -2
  69. package/lib/module/core/index.js.map +1 -1
  70. package/lib/module/index.js +10 -10
  71. package/lib/module/index.js.map +1 -1
  72. package/lib/module/node/createAuth.js +90 -0
  73. package/lib/module/node/createAuth.js.map +1 -0
  74. package/lib/module/node/index.js +8 -4
  75. package/lib/module/node/index.js.map +1 -1
  76. package/lib/module/package.json +1 -0
  77. package/lib/module/ui/components/Avatar.js +2 -2
  78. package/lib/module/ui/components/Avatar.js.map +1 -1
  79. package/lib/module/ui/components/FollowButton.js +3 -3
  80. package/lib/module/ui/components/FollowButton.js.map +1 -1
  81. package/lib/module/ui/components/GroupedSection.js +1 -1
  82. package/lib/module/ui/components/GroupedSection.js.map +1 -1
  83. package/lib/module/ui/components/OxyLogo.js +1 -1
  84. package/lib/module/ui/components/OxyLogo.js.map +1 -1
  85. package/lib/module/ui/components/OxyProvider.js +143 -138
  86. package/lib/module/ui/components/OxyProvider.js.map +1 -1
  87. package/lib/module/ui/components/OxySignInButton.js +2 -2
  88. package/lib/module/ui/components/OxySignInButton.js.map +1 -1
  89. package/lib/module/ui/components/ProfileCard.js +2 -2
  90. package/lib/module/ui/components/ProfileCard.js.map +1 -1
  91. package/lib/module/ui/components/Section.js +1 -1
  92. package/lib/module/ui/components/Section.js.map +1 -1
  93. package/lib/module/ui/components/SectionTitle.js +1 -1
  94. package/lib/module/ui/components/SectionTitle.js.map +1 -1
  95. package/lib/module/ui/components/icon/index.js +1 -1
  96. package/lib/module/ui/components/icon/index.js.map +1 -1
  97. package/lib/module/ui/components/index.js +12 -12
  98. package/lib/module/ui/components/index.js.map +1 -1
  99. package/lib/module/ui/components/internal/GroupedPillButtons.js +208 -0
  100. package/lib/module/ui/components/internal/GroupedPillButtons.js.map +1 -0
  101. package/lib/module/ui/components/internal/TextField.js +571 -0
  102. package/lib/module/ui/components/internal/TextField.js.map +1 -0
  103. package/lib/module/ui/context/OxyContext.js +1 -1
  104. package/lib/module/ui/context/OxyContext.js.map +1 -1
  105. package/lib/module/ui/index.js +12 -10
  106. package/lib/module/ui/index.js.map +1 -1
  107. package/lib/module/ui/navigation/OxyRouter.js +23 -18
  108. package/lib/module/ui/navigation/OxyRouter.js.map +1 -1
  109. package/lib/module/ui/screens/AccountCenterScreen.js +5 -5
  110. package/lib/module/ui/screens/AccountCenterScreen.js.map +1 -1
  111. package/lib/module/ui/screens/AccountManagementDemo.js +2 -2
  112. package/lib/module/ui/screens/AccountManagementDemo.js.map +1 -1
  113. package/lib/module/ui/screens/AccountOverviewScreen.js +4 -4
  114. package/lib/module/ui/screens/AccountOverviewScreen.js.map +1 -1
  115. package/lib/module/ui/screens/AccountSettingsScreen.js +5 -5
  116. package/lib/module/ui/screens/AccountSettingsScreen.js.map +1 -1
  117. package/lib/module/ui/screens/AccountSwitcherScreen.js +3 -3
  118. package/lib/module/ui/screens/AccountSwitcherScreen.js.map +1 -1
  119. package/lib/module/ui/screens/AppInfoScreen.js +6 -6
  120. package/lib/module/ui/screens/AppInfoScreen.js.map +1 -1
  121. package/lib/module/ui/screens/BillingManagementScreen.js +3 -3
  122. package/lib/module/ui/screens/BillingManagementScreen.js.map +1 -1
  123. package/lib/module/ui/screens/FeedbackScreen.js +1164 -0
  124. package/lib/module/ui/screens/FeedbackScreen.js.map +1 -0
  125. package/lib/module/ui/screens/FileManagementScreen.js +3 -3
  126. package/lib/module/ui/screens/FileManagementScreen.js.map +1 -1
  127. package/lib/module/ui/screens/PremiumSubscriptionScreen.js +3 -3
  128. package/lib/module/ui/screens/PremiumSubscriptionScreen.js.map +1 -1
  129. package/lib/module/ui/screens/ProfileScreen.js +2 -2
  130. package/lib/module/ui/screens/ProfileScreen.js.map +1 -1
  131. package/lib/module/ui/screens/SessionManagementScreen.js +2 -2
  132. package/lib/module/ui/screens/SessionManagementScreen.js.map +1 -1
  133. package/lib/module/ui/screens/SignInScreen.js +182 -304
  134. package/lib/module/ui/screens/SignInScreen.js.map +1 -1
  135. package/lib/module/ui/screens/SignUpScreen.js +810 -712
  136. package/lib/module/ui/screens/SignUpScreen.js.map +1 -1
  137. package/lib/module/ui/screens/karma/KarmaCenterScreen.js +3 -3
  138. package/lib/module/ui/screens/karma/KarmaCenterScreen.js.map +1 -1
  139. package/lib/module/ui/screens/karma/KarmaLeaderboardScreen.js +2 -2
  140. package/lib/module/ui/screens/karma/KarmaLeaderboardScreen.js.map +1 -1
  141. package/lib/module/ui/screens/karma/KarmaRulesScreen.js +1 -1
  142. package/lib/module/ui/screens/karma/KarmaRulesScreen.js.map +1 -1
  143. package/lib/module/ui/store/index.js +44 -0
  144. package/lib/module/ui/store/index.js.map +1 -0
  145. package/lib/module/ui/styles/index.js +2 -2
  146. package/lib/module/ui/styles/index.js.map +1 -1
  147. package/lib/module/ui/styles/theme.js +1 -1
  148. package/lib/module/ui/styles/theme.js.map +1 -1
  149. package/lib/module/utils/index.js +1 -1
  150. package/lib/module/utils/index.js.map +1 -1
  151. package/lib/typescript/assets/illustrations/HighFive.d.ts +9 -0
  152. package/lib/typescript/assets/illustrations/HighFive.d.ts.map +1 -0
  153. package/lib/typescript/node/createAuth.d.ts +7 -0
  154. package/lib/typescript/node/createAuth.d.ts.map +1 -0
  155. package/lib/typescript/node/index.d.ts +2 -0
  156. package/lib/typescript/node/index.d.ts.map +1 -1
  157. package/lib/typescript/types/expo-vector-icons.d.ts +3 -0
  158. package/lib/typescript/types/express.d.ts +5 -0
  159. package/lib/typescript/types/react-redux.d.ts +5 -0
  160. package/lib/typescript/ui/components/OxyProvider.d.ts.map +1 -1
  161. package/lib/typescript/ui/components/internal/GroupedPillButtons.d.ts +18 -0
  162. package/lib/typescript/ui/components/internal/GroupedPillButtons.d.ts.map +1 -0
  163. package/lib/typescript/ui/components/internal/TextField.d.ts +25 -0
  164. package/lib/typescript/ui/components/internal/TextField.d.ts.map +1 -0
  165. package/lib/typescript/ui/index.d.ts +2 -0
  166. package/lib/typescript/ui/index.d.ts.map +1 -1
  167. package/lib/typescript/ui/navigation/OxyRouter.d.ts.map +1 -1
  168. package/lib/typescript/ui/screens/FeedbackScreen.d.ts +5 -0
  169. package/lib/typescript/ui/screens/FeedbackScreen.d.ts.map +1 -0
  170. package/lib/typescript/ui/screens/SignInScreen.d.ts.map +1 -1
  171. package/lib/typescript/ui/screens/SignUpScreen.d.ts.map +1 -1
  172. package/lib/typescript/ui/store/index.d.ts +19 -0
  173. package/lib/typescript/ui/store/index.d.ts.map +1 -0
  174. package/package.json +10 -25
  175. package/src/assets/illustrations/HighFive.tsx +41 -0
  176. package/src/node/createAuth.ts +116 -0
  177. package/src/node/index.ts +4 -0
  178. package/src/types/expo-vector-icons.d.ts +3 -0
  179. package/src/types/express.d.ts +5 -0
  180. package/src/types/react-redux.d.ts +5 -0
  181. package/src/ui/components/OxyProvider.tsx +136 -135
  182. package/src/ui/components/internal/GroupedPillButtons.tsx +253 -0
  183. package/src/ui/components/internal/TextField.tsx +694 -0
  184. package/src/ui/index.ts +6 -2
  185. package/src/ui/navigation/OxyRouter.tsx +8 -3
  186. package/src/ui/screens/FeedbackScreen.tsx +1042 -0
  187. package/src/ui/screens/SignInScreen.tsx +179 -222
  188. package/src/ui/screens/SignUpScreen.tsx +772 -608
  189. package/src/ui/store/index.ts +51 -0
@@ -13,6 +13,7 @@ import {
13
13
  Animated,
14
14
  Dimensions,
15
15
  StatusBar,
16
+ Alert,
16
17
  } from 'react-native';
17
18
  import { BaseScreenProps } from '../navigation/types';
18
19
  import { useOxy } from '../context/OxyContext';
@@ -21,12 +22,16 @@ import OxyLogo from '../components/OxyLogo';
21
22
  import Avatar from '../components/Avatar';
22
23
  import { BottomSheetScrollView } from '../components/bottomSheet';
23
24
  import { Ionicons } from '@expo/vector-icons';
24
- import Svg, { Path, Circle, Defs, LinearGradient, Stop } from 'react-native-svg';
25
+ import HighFive from '../../assets/illustrations/HighFive';
25
26
  import { toast } from '../../lib/sonner';
27
+ import Svg, { Path, Circle } from 'react-native-svg';
28
+ import GroupedPillButtons from '../components/internal/GroupedPillButtons';
29
+ import TextField from '../components/internal/TextField';
26
30
 
27
31
  const SignInScreen: React.FC<BaseScreenProps> = ({
28
32
  navigate,
29
33
  goBack,
34
+ onAuthenticated,
30
35
  theme,
31
36
  }) => {
32
37
  // Form data states
@@ -297,47 +302,39 @@ const SignInScreen: React.FC<BaseScreenProps> = ({
297
302
  }
298
303
  }, [currentStep, progressAnim, animateTransition]);
299
304
 
300
- const handleUsernameNext = useCallback(() => {
305
+ // Custom next handlers for validation
306
+ const handleUsernameContinue = useCallback(() => {
301
307
  if (!username) {
302
- toast.error('Please enter your username');
308
+ toast.error('Please enter your username.');
303
309
  return;
304
310
  }
305
-
306
- if (validationStatus === 'invalid') {
307
- // Don't show toast if we already have an error message displayed
308
- if (!errorMessage) {
309
- toast.error('Please enter a valid username');
310
- }
311
+ if (validationStatus !== 'valid' || !userProfile) {
312
+ toast.error('Please enter a valid username.');
311
313
  return;
312
314
  }
315
+ setErrorMessage('');
316
+ nextStep();
317
+ }, [username, validationStatus, userProfile, setErrorMessage, nextStep]);
313
318
 
314
- if (validationStatus === 'validating') {
315
- toast.error('Please wait while we validate your username');
319
+ const handleSignIn = useCallback(async () => {
320
+ if (!password) {
321
+ toast.error('Please enter your password.');
316
322
  return;
317
323
  }
318
-
319
- if (validationStatus === 'valid' && userProfile) {
320
- setErrorMessage('');
321
- nextStep();
322
- } else {
323
- toast.error('Please enter a valid username');
324
- }
325
- }, [username, validationStatus, userProfile, errorMessage, nextStep]);
326
-
327
- const handleLogin = useCallback(async () => {
328
- if (!username || !password) {
329
- toast.error('Please enter both username and password');
324
+ if (!username || !userProfile) {
325
+ toast.error('Please enter a valid username first.');
330
326
  return;
331
327
  }
332
-
333
328
  try {
334
329
  setErrorMessage('');
335
- await login(username, password);
336
- // The authentication state change will be handled through context
330
+ const user = await login(username, password);
331
+ if (onAuthenticated) {
332
+ onAuthenticated(user);
333
+ }
337
334
  } catch (error: any) {
338
335
  toast.error(error.message || 'Login failed');
339
336
  }
340
- }, [username, password, login]);
337
+ }, [username, password, login, onAuthenticated, setErrorMessage, userProfile]);
341
338
 
342
339
  // Memoized step components
343
340
  const renderUsernameStep = useMemo(() => (
@@ -351,52 +348,11 @@ const SignInScreen: React.FC<BaseScreenProps> = ({
351
348
  ]
352
349
  }
353
350
  ]}>
354
- <View style={styles.modernImageContainer}>
355
- <Svg width={280} height={160} viewBox="0 0 280 160">
356
- <Defs>
357
- <LinearGradient id="primaryGradient" x1="0%" y1="0%" x2="100%" y2="100%">
358
- <Stop offset="0%" stopColor={colors.primary} stopOpacity="0.8" />
359
- <Stop offset="100%" stopColor={colors.primary} stopOpacity="0.2" />
360
- </LinearGradient>
361
- <LinearGradient id="secondaryGradient" x1="0%" y1="0%" x2="100%" y2="100%">
362
- <Stop offset="0%" stopColor={colors.primary} stopOpacity="0.1" />
363
- <Stop offset="100%" stopColor={colors.primary} stopOpacity="0.3" />
364
- </LinearGradient>
365
- </Defs>
366
-
367
- {/* Modern abstract shapes */}
368
- <Circle cx="80" cy="80" r="45" fill="url(#primaryGradient)" />
369
- <Circle cx="200" cy="80" r="35" fill="url(#secondaryGradient)" />
370
- <Path
371
- d="M40 120 Q80 40 140 80 Q200 120 240 60"
372
- stroke={colors.primary}
373
- strokeWidth="4"
374
- fill="none"
375
- strokeLinecap="round"
376
- />
377
-
378
- {/* Floating elements */}
379
- <Circle cx="60" cy="50" r="8" fill={colors.primary} opacity="0.6" />
380
- <Circle cx="220" cy="120" r="6" fill={colors.primary} opacity="0.4" />
381
- <Circle cx="250" cy="40" r="4" fill={colors.primary} opacity="0.8" />
382
-
383
- {/* Central focus element */}
384
- <Circle cx="140" cy="80" r="25" fill={colors.background} opacity="0.9" />
385
- <Circle cx="135" cy="75" r="3" fill={colors.primary} />
386
- <Circle cx="145" cy="75" r="3" fill={colors.primary} />
387
- <Path
388
- d="M132 85 Q140 92 148 85"
389
- stroke={colors.primary}
390
- strokeWidth="2"
391
- fill="none"
392
- strokeLinecap="round"
393
- />
394
- </Svg>
395
- </View>
351
+ <HighFive width={100} height={100} />
396
352
 
397
353
  <View style={styles.modernHeader}>
398
354
  <Text style={[styles.modernTitle, { color: colors.text }]}>
399
- {isAddAccountMode ? 'Add Account' : 'Welcome Back'}
355
+ {isAddAccountMode ? 'Add Another Account' : 'Sign In'}
400
356
  </Text>
401
357
  <Text style={[styles.modernSubtitle, { color: colors.secondaryText }]}>
402
358
  {isAddAccountMode
@@ -426,99 +382,124 @@ const SignInScreen: React.FC<BaseScreenProps> = ({
426
382
  styles.modernInputContainer,
427
383
  { transform: [{ scale: inputScaleAnim }] }
428
384
  ]}>
429
- <View style={[
430
- styles.inputWrapper,
431
- {
432
- borderColor: validationStatus === 'valid' ? colors.success :
433
- validationStatus === 'invalid' ? colors.error :
434
- isInputFocused ? colors.primary : colors.border
435
- }
436
- ]}>
437
- <Ionicons
438
- name="person-outline"
439
- size={20}
440
- color={isInputFocused ? colors.primary : colors.secondaryText}
441
- style={styles.inputIcon}
442
- />
443
- <TextInput
444
- style={[styles.modernInput, { color: colors.text }]}
445
- placeholder="Enter your username"
446
- placeholderTextColor={colors.placeholder}
447
- value={username}
448
- onChangeText={handleUsernameChange}
449
- onFocus={handleInputFocus}
450
- onBlur={handleInputBlur}
451
- autoCapitalize="none"
452
- testID="username-input"
453
- />
454
- {validationStatus === 'validating' && (
455
- <ActivityIndicator size="small" color={colors.primary} style={styles.validationIndicator} />
456
- )}
457
- {validationStatus === 'valid' && (
458
- <Ionicons name="checkmark-circle" size={20} color={colors.success} style={styles.validationIndicator} />
459
- )}
460
- {validationStatus === 'invalid' && username.length >= 3 && (
461
- <Ionicons name="close-circle" size={20} color={colors.error} style={styles.validationIndicator} />
462
- )}
463
- </View>
385
+ <TextField
386
+ label="Username"
387
+ icon="person-outline"
388
+ value={username}
389
+ onChangeText={handleUsernameChange}
390
+ onFocus={handleInputFocus}
391
+ onBlur={handleInputBlur}
392
+ autoCapitalize="none"
393
+ autoCorrect={false}
394
+ testID="username-input"
395
+ colors={colors}
396
+ variant="filled"
397
+ error={validationStatus === 'invalid' && username.length >= 3 ? 'Username not found' : undefined}
398
+ loading={validationStatus === 'validating'}
399
+ success={validationStatus === 'valid'}
400
+ />
401
+ </Animated.View>
464
402
 
465
- {/* Validation feedback */}
466
- {validationStatus === 'valid' && userProfile && (
467
- <View style={[styles.validationSuccessCard, { backgroundColor: colors.success + '15' }]}>
403
+ {/* Enhanced Validation feedback */}
404
+ {validationStatus === 'valid' && userProfile && (
405
+ <View style={[styles.validationSuccessCard, {
406
+ backgroundColor: colors.success + '10',
407
+ borderWidth: 1,
408
+ borderColor: colors.success + '30',
409
+ padding: 16,
410
+ }]}>
411
+ <View style={{
412
+ width: 32,
413
+ height: 32,
414
+ borderRadius: 16,
415
+ backgroundColor: colors.success + '20',
416
+ justifyContent: 'center',
417
+ alignItems: 'center',
418
+ marginRight: 12,
419
+ }}>
468
420
  <Ionicons name="checkmark-circle" size={16} color={colors.success} />
469
- <Text style={[styles.validationText, { color: colors.success }]}>
470
- Found user: {userProfile.displayName}
421
+ </View>
422
+ <View style={{ flex: 1 }}>
423
+ <Text style={[styles.validationText, {
424
+ color: colors.success,
425
+ fontWeight: '600',
426
+ marginBottom: 2,
427
+ }]}>
428
+ Welcome back, {userProfile?.displayName || userProfile?.name || username}!
429
+ </Text>
430
+ <Text style={[styles.validationText, {
431
+ color: colors.secondaryText,
432
+ fontSize: 11,
433
+ opacity: 0.8,
434
+ }]}>
435
+ Ready to continue where you left off
471
436
  </Text>
472
437
  </View>
473
- )}
438
+ </View>
439
+ )}
474
440
 
475
- {validationStatus === 'invalid' && username.length >= 3 && !errorMessage && (
476
- <View style={[styles.validationErrorCard, { backgroundColor: colors.error + '15' }]}>
441
+ {validationStatus === 'invalid' && username.length >= 3 && (
442
+ <View style={[styles.validationErrorCard, {
443
+ backgroundColor: colors.error + '10',
444
+ borderWidth: 1,
445
+ borderColor: colors.error + '30',
446
+ padding: 16,
447
+ }]}>
448
+ <View style={{
449
+ width: 32,
450
+ height: 32,
451
+ borderRadius: 16,
452
+ backgroundColor: colors.error + '20',
453
+ justifyContent: 'center',
454
+ alignItems: 'center',
455
+ marginRight: 12,
456
+ }}>
477
457
  <Ionicons name="alert-circle" size={16} color={colors.error} />
478
- <Text style={[styles.validationText, { color: colors.error }]}>
458
+ </View>
459
+ <View style={{ flex: 1 }}>
460
+ <Text style={[styles.validationText, {
461
+ color: colors.error,
462
+ fontWeight: '600',
463
+ marginBottom: 2,
464
+ }]}>
479
465
  Username not found
480
466
  </Text>
467
+ <Text style={[styles.validationText, {
468
+ color: colors.secondaryText,
469
+ fontSize: 11,
470
+ opacity: 0.8,
471
+ }]}>
472
+ Check spelling or sign up
473
+ </Text>
481
474
  </View>
482
- )}
483
- </Animated.View>
475
+ </View>
476
+ )}
484
477
 
485
- <TouchableOpacity
486
- style={[
487
- styles.modernButton,
478
+ <GroupedPillButtons
479
+ buttons={[
488
480
  {
489
- backgroundColor: colors.primary,
490
- opacity: (!username || validationStatus !== 'valid') ? 0.5 : 1,
491
- shadowColor: colors.primary,
492
- }
481
+ text: 'Sign Up',
482
+ onPress: () => navigate('SignUp'),
483
+ icon: 'person-add',
484
+ variant: 'transparent',
485
+ },
486
+ {
487
+ text: 'Continue',
488
+ onPress: handleUsernameContinue,
489
+ icon: 'arrow-forward',
490
+ variant: 'primary',
491
+ loading: isValidating,
492
+ testID: 'username-next-button',
493
+ },
493
494
  ]}
494
- onPress={handleUsernameNext}
495
- disabled={!username || validationStatus !== 'valid' || isValidating}
496
- testID="username-next-button"
497
- >
498
- {isValidating ? (
499
- <ActivityIndicator color="#FFFFFF" size="small" />
500
- ) : (
501
- <>
502
- <Text style={styles.modernButtonText}>Continue</Text>
503
- <Ionicons name="arrow-forward" size={20} color="#FFFFFF" style={styles.buttonIcon} />
504
- </>
505
- )}
506
- </TouchableOpacity>
507
-
508
- <View style={styles.footerTextContainer}>
509
- <Text style={[styles.footerText, { color: colors.secondaryText }]}>
510
- Don't have an account?{' '}
511
- </Text>
512
- <TouchableOpacity onPress={() => navigate('SignUp')}>
513
- <Text style={[styles.modernLinkText, { color: colors.primary }]}>Sign Up</Text>
514
- </TouchableOpacity>
515
- </View>
495
+ colors={colors}
496
+ />
516
497
  </Animated.View>
517
498
  ), [
518
499
  fadeAnim, slideAnim, scaleAnim, colors, isAddAccountMode, user?.username,
519
500
  errorMessage, inputScaleAnim, isInputFocused, username, validationStatus,
520
501
  userProfile, isValidating, handleInputFocus, handleInputBlur, handleUsernameChange,
521
- handleUsernameNext, navigate, styles
502
+ handleUsernameContinue, navigate, styles
522
503
  ]);
523
504
 
524
505
  const renderPasswordStep = useMemo(() => (
@@ -573,70 +554,42 @@ const SignInScreen: React.FC<BaseScreenProps> = ({
573
554
  styles.modernInputContainer,
574
555
  { transform: [{ scale: inputScaleAnim }] }
575
556
  ]}>
576
- <View style={[styles.inputWrapper, { borderColor: isInputFocused ? colors.primary : colors.border }]}>
577
- <Ionicons
578
- name="lock-closed-outline"
579
- size={20}
580
- color={isInputFocused ? colors.primary : colors.secondaryText}
581
- style={styles.inputIcon}
582
- />
583
- <TextInput
584
- style={[styles.modernInput, { color: colors.text }]}
585
- placeholder="Enter your password"
586
- placeholderTextColor={colors.placeholder}
587
- value={password}
588
- onChangeText={handlePasswordChange}
589
- onFocus={handleInputFocus}
590
- onBlur={handleInputBlur}
591
- secureTextEntry={!showPassword}
592
- autoCapitalize="none"
593
- testID="password-input"
594
- />
595
- <TouchableOpacity
596
- style={styles.passwordToggle}
597
- onPress={() => setShowPassword(!showPassword)}
598
- >
599
- <Ionicons
600
- name={showPassword ? "eye-off" : "eye"}
601
- size={20}
602
- color={colors.secondaryText}
603
- />
604
- </TouchableOpacity>
605
- </View>
557
+ <TextField
558
+ label="Password"
559
+ icon="lock-closed-outline"
560
+ value={password}
561
+ onChangeText={handlePasswordChange}
562
+ onFocus={handleInputFocus}
563
+ onBlur={handleInputBlur}
564
+ secureTextEntry={!showPassword}
565
+ autoCapitalize="none"
566
+ autoCorrect={false}
567
+ testID="password-input"
568
+ colors={colors}
569
+ variant="filled"
570
+ error={errorMessage}
571
+ />
606
572
  </Animated.View>
607
573
 
608
- <TouchableOpacity
609
- style={[
610
- styles.modernButton,
574
+ <GroupedPillButtons
575
+ buttons={[
611
576
  {
612
- backgroundColor: colors.primary,
613
- opacity: !password ? 0.5 : 1,
614
- shadowColor: colors.primary,
615
- }
577
+ text: 'Back',
578
+ onPress: prevStep,
579
+ icon: 'arrow-back',
580
+ variant: 'transparent',
581
+ },
582
+ {
583
+ text: 'Sign In',
584
+ onPress: handleSignIn,
585
+ icon: 'log-in',
586
+ variant: 'primary',
587
+ loading: isLoading,
588
+ testID: 'login-button',
589
+ },
616
590
  ]}
617
- onPress={handleLogin}
618
- disabled={!password || isLoading}
619
- testID="login-button"
620
- >
621
- {isLoading ? (
622
- <ActivityIndicator color="#FFFFFF" size="small" />
623
- ) : (
624
- <>
625
- <Text style={styles.modernButtonText}>Sign In</Text>
626
- <Ionicons name="log-in" size={20} color="#FFFFFF" style={styles.buttonIcon} />
627
- </>
628
- )}
629
- </TouchableOpacity>
630
-
631
- <View style={styles.modernNavigationButtons}>
632
- <TouchableOpacity
633
- style={[styles.modernBackButton, { borderColor: colors.border }]}
634
- onPress={prevStep}
635
- >
636
- <Ionicons name="arrow-back" size={18} color={colors.text} />
637
- <Text style={[styles.modernBackButtonText, { color: colors.text }]}>Back</Text>
638
- </TouchableOpacity>
639
- </View>
591
+ colors={colors}
592
+ />
640
593
 
641
594
  <View style={styles.securityNotice}>
642
595
  <Ionicons name="shield-checkmark" size={14} color={colors.secondaryText} />
@@ -648,7 +601,7 @@ const SignInScreen: React.FC<BaseScreenProps> = ({
648
601
  ), [
649
602
  fadeAnim, slideAnim, scaleAnim, colors, userProfile, username, theme, logoAnim,
650
603
  errorMessage, inputScaleAnim, isInputFocused, password, showPassword,
651
- handleInputFocus, handleInputBlur, handlePasswordChange, handleLogin, isLoading, prevStep, styles
604
+ handleInputFocus, handleInputBlur, handlePasswordChange, handleSignIn, isLoading, prevStep, styles
652
605
  ]);
653
606
 
654
607
  const renderCurrentStep = useCallback(() => {
@@ -691,30 +644,25 @@ const createStyles = (colors: any, theme: string) => StyleSheet.create({
691
644
  scrollContent: {
692
645
  flexGrow: 1,
693
646
  paddingHorizontal: 24,
694
- paddingTop: 40,
695
- paddingBottom: 40,
647
+ paddingTop: 4,
648
+ paddingBottom: 20,
696
649
  },
697
650
  stepContainer: {
698
651
  flex: 1,
699
- justifyContent: 'center',
700
- alignItems: 'center',
701
- minHeight: 600,
702
- },
703
- modernImageContainer: {
704
- alignItems: 'center',
705
- marginBottom: 40,
652
+ justifyContent: 'flex-start',
653
+ alignItems: 'flex-start',
706
654
  },
707
655
  modernHeader: {
708
656
  alignItems: 'flex-start',
709
657
  width: '100%',
710
- marginBottom: 32,
658
+ marginBottom: 24,
711
659
  },
712
660
  modernTitle: {
713
661
  fontFamily: Platform.OS === 'web' ? 'Phudu' : 'Phudu-Bold',
714
662
  fontWeight: Platform.OS === 'web' ? 'bold' : undefined,
715
- fontSize: 42,
663
+ fontSize: 62,
716
664
  lineHeight: 48,
717
- marginBottom: 12,
665
+ marginBottom: 18,
718
666
  textAlign: 'left',
719
667
  letterSpacing: -1,
720
668
  },
@@ -825,6 +773,13 @@ const createStyles = (colors: any, theme: string) => StyleSheet.create({
825
773
  buttonIcon: {
826
774
  marginLeft: 4,
827
775
  },
776
+
777
+ // Enhanced Label Styles
778
+ modernLabel: {
779
+ fontSize: 12,
780
+ fontWeight: '500',
781
+ marginBottom: 2,
782
+ },
828
783
  modernLinkText: {
829
784
  fontSize: 14,
830
785
  lineHeight: 20,
@@ -834,7 +789,7 @@ const createStyles = (colors: any, theme: string) => StyleSheet.create({
834
789
  footerTextContainer: {
835
790
  flexDirection: 'row',
836
791
  justifyContent: 'center',
837
- marginTop: 28,
792
+ marginTop: 16,
838
793
  },
839
794
  footerText: {
840
795
  fontSize: 15,
@@ -896,8 +851,10 @@ const createStyles = (colors: any, theme: string) => StyleSheet.create({
896
851
  modernNavigationButtons: {
897
852
  flexDirection: 'row',
898
853
  justifyContent: 'center',
899
- marginTop: 24,
900
- marginBottom: 16,
854
+ marginTop: 16,
855
+ marginBottom: 8,
856
+ width: '100%',
857
+ gap: 8,
901
858
  },
902
859
  modernBackButton: {
903
860
  flexDirection: 'row',