@oxyhq/services 5.4.1 → 5.4.3

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 (154) hide show
  1. package/lib/commonjs/assets/icons/OxyServices.js +1 -1
  2. package/lib/commonjs/core/index.js +84 -2
  3. package/lib/commonjs/core/index.js.map +1 -1
  4. package/lib/commonjs/index.js +22 -22
  5. package/lib/commonjs/index.js.map +1 -1
  6. package/lib/commonjs/node/index.js +6 -6
  7. package/lib/commonjs/node/index.js.map +1 -1
  8. package/lib/commonjs/ui/components/Avatar.js +3 -3
  9. package/lib/commonjs/ui/components/Avatar.js.map +1 -1
  10. package/lib/commonjs/ui/components/FollowButton.js +3 -3
  11. package/lib/commonjs/ui/components/GroupedSection.js +1 -1
  12. package/lib/commonjs/ui/components/OxyLogo.js +1 -1
  13. package/lib/commonjs/ui/components/OxyProvider.js +13 -13
  14. package/lib/commonjs/ui/components/OxyProvider.js.map +1 -1
  15. package/lib/commonjs/ui/components/OxySignInButton.js +2 -2
  16. package/lib/commonjs/ui/components/ProfileCard.js +2 -2
  17. package/lib/commonjs/ui/components/Section.js +1 -1
  18. package/lib/commonjs/ui/components/SectionTitle.js +1 -1
  19. package/lib/commonjs/ui/components/icon/index.js +1 -1
  20. package/lib/commonjs/ui/components/index.js +12 -12
  21. package/lib/commonjs/ui/context/OxyContext.js +20 -4
  22. package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
  23. package/lib/commonjs/ui/index.js +11 -11
  24. package/lib/commonjs/ui/index.js.map +1 -1
  25. package/lib/commonjs/ui/navigation/OxyRouter.js +18 -18
  26. package/lib/commonjs/ui/screens/AccountCenterScreen.js +18 -18
  27. package/lib/commonjs/ui/screens/AccountCenterScreen.js.map +1 -1
  28. package/lib/commonjs/ui/screens/AccountManagementDemo.js +3 -3
  29. package/lib/commonjs/ui/screens/AccountManagementDemo.js.map +1 -1
  30. package/lib/commonjs/ui/screens/AccountOverviewScreen.js +45 -27
  31. package/lib/commonjs/ui/screens/AccountOverviewScreen.js.map +1 -1
  32. package/lib/commonjs/ui/screens/AccountSettingsScreen.js +29 -22
  33. package/lib/commonjs/ui/screens/AccountSettingsScreen.js.map +1 -1
  34. package/lib/commonjs/ui/screens/AccountSwitcherScreen.js +3 -3
  35. package/lib/commonjs/ui/screens/AppInfoScreen.js +6 -6
  36. package/lib/commonjs/ui/screens/BillingManagementScreen.js +3 -3
  37. package/lib/commonjs/ui/screens/FileManagementScreen.js +324 -306
  38. package/lib/commonjs/ui/screens/FileManagementScreen.js.map +1 -1
  39. package/lib/commonjs/ui/screens/PremiumSubscriptionScreen.js +3 -3
  40. package/lib/commonjs/ui/screens/ProfileScreen.js +2 -2
  41. package/lib/commonjs/ui/screens/SessionManagementScreen.js +2 -2
  42. package/lib/commonjs/ui/screens/SignInScreen.js +358 -310
  43. package/lib/commonjs/ui/screens/SignInScreen.js.map +1 -1
  44. package/lib/commonjs/ui/screens/SignUpScreen.js +483 -308
  45. package/lib/commonjs/ui/screens/SignUpScreen.js.map +1 -1
  46. package/lib/commonjs/ui/screens/karma/KarmaCenterScreen.js +3 -3
  47. package/lib/commonjs/ui/screens/karma/KarmaFAQScreen.js +51 -26
  48. package/lib/commonjs/ui/screens/karma/KarmaFAQScreen.js.map +1 -1
  49. package/lib/commonjs/ui/screens/karma/KarmaLeaderboardScreen.js +2 -2
  50. package/lib/commonjs/ui/screens/karma/KarmaRulesScreen.js +1 -1
  51. package/lib/commonjs/ui/styles/index.js +2 -2
  52. package/lib/commonjs/ui/styles/theme.js +1 -1
  53. package/lib/commonjs/utils/index.js +1 -1
  54. package/lib/module/assets/icons/OxyServices.js +1 -1
  55. package/lib/module/assets/icons/OxyServices.js.map +1 -1
  56. package/lib/module/core/index.js +84 -2
  57. package/lib/module/core/index.js.map +1 -1
  58. package/lib/module/index.js +10 -10
  59. package/lib/module/index.js.map +1 -1
  60. package/lib/module/node/index.js +4 -4
  61. package/lib/module/node/index.js.map +1 -1
  62. package/lib/module/ui/components/Avatar.js +2 -2
  63. package/lib/module/ui/components/Avatar.js.map +1 -1
  64. package/lib/module/ui/components/FollowButton.js +3 -3
  65. package/lib/module/ui/components/FollowButton.js.map +1 -1
  66. package/lib/module/ui/components/GroupedSection.js +1 -1
  67. package/lib/module/ui/components/GroupedSection.js.map +1 -1
  68. package/lib/module/ui/components/OxyLogo.js +1 -1
  69. package/lib/module/ui/components/OxyLogo.js.map +1 -1
  70. package/lib/module/ui/components/OxyProvider.js +10 -10
  71. package/lib/module/ui/components/OxyProvider.js.map +1 -1
  72. package/lib/module/ui/components/OxySignInButton.js +2 -2
  73. package/lib/module/ui/components/OxySignInButton.js.map +1 -1
  74. package/lib/module/ui/components/ProfileCard.js +2 -2
  75. package/lib/module/ui/components/ProfileCard.js.map +1 -1
  76. package/lib/module/ui/components/Section.js +1 -1
  77. package/lib/module/ui/components/Section.js.map +1 -1
  78. package/lib/module/ui/components/SectionTitle.js +1 -1
  79. package/lib/module/ui/components/SectionTitle.js.map +1 -1
  80. package/lib/module/ui/components/icon/index.js +1 -1
  81. package/lib/module/ui/components/icon/index.js.map +1 -1
  82. package/lib/module/ui/components/index.js +12 -12
  83. package/lib/module/ui/components/index.js.map +1 -1
  84. package/lib/module/ui/context/OxyContext.js +20 -4
  85. package/lib/module/ui/context/OxyContext.js.map +1 -1
  86. package/lib/module/ui/index.js +10 -10
  87. package/lib/module/ui/index.js.map +1 -1
  88. package/lib/module/ui/navigation/OxyRouter.js +18 -18
  89. package/lib/module/ui/navigation/OxyRouter.js.map +1 -1
  90. package/lib/module/ui/screens/AccountCenterScreen.js +5 -5
  91. package/lib/module/ui/screens/AccountCenterScreen.js.map +1 -1
  92. package/lib/module/ui/screens/AccountManagementDemo.js +2 -2
  93. package/lib/module/ui/screens/AccountManagementDemo.js.map +1 -1
  94. package/lib/module/ui/screens/AccountOverviewScreen.js +46 -28
  95. package/lib/module/ui/screens/AccountOverviewScreen.js.map +1 -1
  96. package/lib/module/ui/screens/AccountSettingsScreen.js +30 -23
  97. package/lib/module/ui/screens/AccountSettingsScreen.js.map +1 -1
  98. package/lib/module/ui/screens/AccountSwitcherScreen.js +3 -3
  99. package/lib/module/ui/screens/AccountSwitcherScreen.js.map +1 -1
  100. package/lib/module/ui/screens/AppInfoScreen.js +6 -6
  101. package/lib/module/ui/screens/AppInfoScreen.js.map +1 -1
  102. package/lib/module/ui/screens/BillingManagementScreen.js +3 -3
  103. package/lib/module/ui/screens/BillingManagementScreen.js.map +1 -1
  104. package/lib/module/ui/screens/FileManagementScreen.js +325 -307
  105. package/lib/module/ui/screens/FileManagementScreen.js.map +1 -1
  106. package/lib/module/ui/screens/PremiumSubscriptionScreen.js +3 -3
  107. package/lib/module/ui/screens/PremiumSubscriptionScreen.js.map +1 -1
  108. package/lib/module/ui/screens/ProfileScreen.js +2 -2
  109. package/lib/module/ui/screens/ProfileScreen.js.map +1 -1
  110. package/lib/module/ui/screens/SessionManagementScreen.js +2 -2
  111. package/lib/module/ui/screens/SessionManagementScreen.js.map +1 -1
  112. package/lib/module/ui/screens/SignInScreen.js +358 -310
  113. package/lib/module/ui/screens/SignInScreen.js.map +1 -1
  114. package/lib/module/ui/screens/SignUpScreen.js +486 -309
  115. package/lib/module/ui/screens/SignUpScreen.js.map +1 -1
  116. package/lib/module/ui/screens/karma/KarmaCenterScreen.js +3 -3
  117. package/lib/module/ui/screens/karma/KarmaCenterScreen.js.map +1 -1
  118. package/lib/module/ui/screens/karma/KarmaFAQScreen.js +52 -27
  119. package/lib/module/ui/screens/karma/KarmaFAQScreen.js.map +1 -1
  120. package/lib/module/ui/screens/karma/KarmaLeaderboardScreen.js +2 -2
  121. package/lib/module/ui/screens/karma/KarmaLeaderboardScreen.js.map +1 -1
  122. package/lib/module/ui/screens/karma/KarmaRulesScreen.js +1 -1
  123. package/lib/module/ui/screens/karma/KarmaRulesScreen.js.map +1 -1
  124. package/lib/module/ui/styles/index.js +2 -2
  125. package/lib/module/ui/styles/index.js.map +1 -1
  126. package/lib/module/ui/styles/theme.js +1 -1
  127. package/lib/module/ui/styles/theme.js.map +1 -1
  128. package/lib/module/utils/index.js +1 -1
  129. package/lib/module/utils/index.js.map +1 -1
  130. package/lib/typescript/core/index.d.ts +24 -0
  131. package/lib/typescript/core/index.d.ts.map +1 -1
  132. package/lib/typescript/ui/components/OxyProvider.d.ts.map +1 -1
  133. package/lib/typescript/ui/context/OxyContext.d.ts.map +1 -1
  134. package/lib/typescript/ui/screens/AccountOverviewScreen.d.ts +2 -2
  135. package/lib/typescript/ui/screens/AccountOverviewScreen.d.ts.map +1 -1
  136. package/lib/typescript/ui/screens/AccountSettingsScreen.d.ts +2 -2
  137. package/lib/typescript/ui/screens/AccountSettingsScreen.d.ts.map +1 -1
  138. package/lib/typescript/ui/screens/FileManagementScreen.d.ts.map +1 -1
  139. package/lib/typescript/ui/screens/SignInScreen.d.ts.map +1 -1
  140. package/lib/typescript/ui/screens/SignUpScreen.d.ts.map +1 -1
  141. package/lib/typescript/ui/screens/karma/KarmaFAQScreen.d.ts +2 -2
  142. package/lib/typescript/ui/screens/karma/KarmaFAQScreen.d.ts.map +1 -1
  143. package/package.json +21 -5
  144. package/src/core/index.ts +68 -0
  145. package/src/ui/components/OxyProvider.tsx +5 -5
  146. package/src/ui/context/OxyContext.tsx +61 -41
  147. package/src/ui/screens/AccountOverviewScreen.tsx +44 -26
  148. package/src/ui/screens/AccountSettingsScreen.tsx +24 -18
  149. package/src/ui/screens/FileManagementScreen.tsx +246 -211
  150. package/src/ui/screens/SignInScreen.tsx +382 -326
  151. package/src/ui/screens/SignUpScreen.tsx +443 -273
  152. package/src/ui/screens/karma/KarmaFAQScreen.tsx +50 -29
  153. package/lib/commonjs/package.json +0 -1
  154. package/lib/module/package.json +0 -1
@@ -1,4 +1,4 @@
1
- import React, { useState, useRef, useEffect } from 'react';
1
+ import React, { useState, useRef, useEffect, useMemo, useCallback } from 'react';
2
2
  import {
3
3
  View,
4
4
  Text,
@@ -12,13 +12,14 @@ import {
12
12
  TextStyle,
13
13
  Animated,
14
14
  Dimensions,
15
+ StatusBar,
15
16
  } from 'react-native';
16
17
  import { BaseScreenProps } from '../navigation/types';
17
18
  import { useOxy } from '../context/OxyContext';
18
- import { fontFamilies } from '../styles/fonts';
19
+ import { fontFamilies, useThemeColors, createCommonStyles } from '../styles';
19
20
  import OxyLogo from '../components/OxyLogo';
20
21
  import { BottomSheetScrollView, BottomSheetView } from '../components/bottomSheet';
21
- import { Ionicons } from '@expo/vector-icons'; // Add icon import
22
+ import { Ionicons } from '@expo/vector-icons';
22
23
  import Svg, { Path, Circle } from 'react-native-svg';
23
24
  import { toast } from '../../lib/sonner';
24
25
 
@@ -32,40 +33,152 @@ const SignUpScreen: React.FC<BaseScreenProps> = ({
32
33
  const [email, setEmail] = useState('');
33
34
  const [password, setPassword] = useState('');
34
35
  const [confirmPassword, setConfirmPassword] = useState('');
36
+ const [showPassword, setShowPassword] = useState(false);
37
+ const [showConfirmPassword, setShowConfirmPassword] = useState(false);
35
38
  const [errorMessage, setErrorMessage] = useState('');
36
39
 
37
40
  // Multi-step form states
38
41
  const [currentStep, setCurrentStep] = useState(0);
42
+ const [isInputFocused, setIsInputFocused] = useState(false);
43
+ const [isValidating, setIsValidating] = useState(false);
44
+ const [validationStatus, setValidationStatus] = useState<'idle' | 'validating' | 'valid' | 'invalid'>('idle');
45
+
46
+ // Cache for validation results
47
+ const validationCache = useRef<Map<string, { available: boolean; timestamp: number }>>(new Map());
48
+
39
49
  const fadeAnim = useRef(new Animated.Value(1)).current;
40
50
  const slideAnim = useRef(new Animated.Value(0)).current;
41
- const heightAnim = useRef(new Animated.Value(400)).current; // Initial height value
42
- const [containerHeight, setContainerHeight] = useState(400); // Default height
51
+ const heightAnim = useRef(new Animated.Value(400)).current;
52
+ const [containerHeight, setContainerHeight] = useState(400);
43
53
 
44
- const { signUp, isLoading, user, isAuthenticated } = useOxy();
54
+ const { signUp, isLoading, user, isAuthenticated, oxyServices } = useOxy();
45
55
 
46
- const isDarkTheme = theme === 'dark';
47
- const textColor = isDarkTheme ? '#FFFFFF' : '#000000';
48
- const backgroundColor = isDarkTheme ? '#121212' : '#FFFFFF';
49
- const inputBackgroundColor = isDarkTheme ? '#333333' : '#F5F5F5';
50
- const placeholderColor = isDarkTheme ? '#AAAAAA' : '#999999';
51
- const primaryColor = '#d169e5';
52
- const borderColor = isDarkTheme ? '#444444' : '#E0E0E0';
56
+ const colors = useThemeColors(theme);
57
+ const commonStyles = createCommonStyles(theme);
58
+
59
+ // Memoized styles to prevent rerenders
60
+ const styles = useMemo(() => createStyles(colors, theme), [colors, theme]);
61
+
62
+ // Input focus animations
63
+ const handleInputFocus = useCallback(() => {
64
+ setIsInputFocused(true);
65
+ }, []);
66
+
67
+ const handleInputBlur = useCallback(() => {
68
+ setIsInputFocused(false);
69
+ }, []);
70
+
71
+ // Memoized input change handlers
72
+ const handleUsernameChange = useCallback((text: string) => {
73
+ setUsername(text);
74
+ if (validationStatus === 'invalid') {
75
+ setErrorMessage('');
76
+ setValidationStatus('idle');
77
+ }
78
+ }, [validationStatus]);
79
+
80
+ const handleEmailChange = useCallback((text: string) => {
81
+ setEmail(text);
82
+ setErrorMessage('');
83
+ }, []);
84
+
85
+ const handlePasswordChange = useCallback((text: string) => {
86
+ setPassword(text);
87
+ setErrorMessage('');
88
+ }, []);
89
+
90
+ const handleConfirmPasswordChange = useCallback((text: string) => {
91
+ setConfirmPassword(text);
92
+ setErrorMessage('');
93
+ }, []);
94
+
95
+ // Username availability validation using core services
96
+ const validateUsername = useCallback(async (usernameToValidate: string) => {
97
+ if (!usernameToValidate || usernameToValidate.length < 3) {
98
+ setValidationStatus('invalid');
99
+ return false;
100
+ }
101
+
102
+ // Check cache first (cache valid for 5 minutes)
103
+ const cached = validationCache.current.get(usernameToValidate);
104
+ const now = Date.now();
105
+ if (cached && (now - cached.timestamp) < 5 * 60 * 1000) {
106
+ setValidationStatus(cached.available ? 'valid' : 'invalid');
107
+ setErrorMessage(cached.available ? '' : 'Username is already taken');
108
+ return cached.available;
109
+ }
110
+
111
+ setIsValidating(true);
112
+ setValidationStatus('validating');
113
+
114
+ try {
115
+ const result = await oxyServices.checkUsernameAvailability(usernameToValidate);
116
+
117
+ if (result.available) {
118
+ setValidationStatus('valid');
119
+ setErrorMessage('');
120
+
121
+ // Cache the result
122
+ validationCache.current.set(usernameToValidate, {
123
+ available: true,
124
+ timestamp: now
125
+ });
126
+
127
+ return true;
128
+ } else {
129
+ setValidationStatus('invalid');
130
+ setErrorMessage(result.message || 'Username is already taken');
131
+
132
+ // Cache the result
133
+ validationCache.current.set(usernameToValidate, {
134
+ available: false,
135
+ timestamp: now
136
+ });
137
+
138
+ return false;
139
+ }
140
+ } catch (error: any) {
141
+ console.error('Username validation error:', error);
142
+ setValidationStatus('invalid');
143
+ setErrorMessage('Unable to validate username. Please try again.');
144
+ return false;
145
+ } finally {
146
+ setIsValidating(false);
147
+ }
148
+ }, [oxyServices]);
149
+
150
+ // Debounced username validation
151
+ useEffect(() => {
152
+ if (!username || username.length < 3) {
153
+ setValidationStatus('idle');
154
+ setErrorMessage('');
155
+ return;
156
+ }
157
+
158
+ const timeoutId = setTimeout(() => {
159
+ validateUsername(username);
160
+ }, 800);
161
+
162
+ return () => clearTimeout(timeoutId);
163
+ }, [username, validateUsername]);
164
+
165
+ // Cleanup cache on unmount
166
+ useEffect(() => {
167
+ return () => {
168
+ validationCache.current.clear();
169
+ };
170
+ }, []);
53
171
 
54
- // If user is already authenticated, show user info and account center option
55
172
  // Animation functions
56
- const animateTransition = (nextStep: number) => {
57
- // Fade out
173
+ const animateTransition = useCallback((nextStep: number) => {
58
174
  Animated.timing(fadeAnim, {
59
175
  toValue: 0,
60
176
  duration: 250,
61
177
  useNativeDriver: true,
62
178
  }).start(() => {
63
179
  setCurrentStep(nextStep);
64
-
65
- // Reset slide position
66
180
  slideAnim.setValue(-100);
67
181
 
68
- // Fade in and slide
69
182
  Animated.parallel([
70
183
  Animated.timing(fadeAnim, {
71
184
  toValue: 1,
@@ -79,61 +192,26 @@ const SignUpScreen: React.FC<BaseScreenProps> = ({
79
192
  })
80
193
  ]).start();
81
194
  });
82
- };
195
+ }, [fadeAnim, slideAnim]);
83
196
 
84
- const nextStep = () => {
197
+ const nextStep = useCallback(() => {
85
198
  if (currentStep < 3) {
86
199
  animateTransition(currentStep + 1);
87
200
  }
88
- };
201
+ }, [currentStep, animateTransition]);
89
202
 
90
- const prevStep = () => {
203
+ const prevStep = useCallback(() => {
91
204
  if (currentStep > 0) {
92
205
  animateTransition(currentStep - 1);
93
206
  }
94
- };
95
-
96
- if (user && isAuthenticated) {
97
- return (
98
- <BottomSheetScrollView style={[styles.scrollContainer, { backgroundColor, padding: 20 }]}>
99
- <Text style={[
100
- styles.welcomeTitle,
101
- {
102
- color: textColor,
103
- textAlign: 'center'
104
- }
105
- ]}>Welcome, {user.username}!</Text>
106
-
107
- <View style={styles.userInfoContainer}>
108
- <Text style={[styles.userInfoText, { color: textColor }]}>
109
- You are already signed in.
110
- </Text>
111
- {user.email && (
112
- <Text style={[styles.userInfoText, { color: isDarkTheme ? '#BBBBBB' : '#666666' }]}>
113
- Email: {user.email}
114
- </Text>
115
- )}
116
- </View>
207
+ }, [currentStep, animateTransition]);
117
208
 
118
- <View style={styles.actionButtonsContainer}>
119
- <TouchableOpacity
120
- style={[styles.button, { backgroundColor: primaryColor }]}
121
- onPress={() => navigate('AccountCenter')}
122
- >
123
- <Text style={styles.buttonText}>Go to Account Center</Text>
124
- </TouchableOpacity>
125
- </View>
126
- </BottomSheetScrollView>
127
- );
128
- }
129
-
130
- const validateEmail = (email: string) => {
209
+ const validateEmail = useCallback((email: string) => {
131
210
  const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
132
211
  return emailRegex.test(email);
133
- };
212
+ }, []);
134
213
 
135
- const handleSignUp = async () => {
136
- // Validate inputs
214
+ const handleSignUp = useCallback(async () => {
137
215
  if (!username || !email || !password || !confirmPassword) {
138
216
  toast.error('Please fill in all fields');
139
217
  return;
@@ -144,6 +222,11 @@ const SignUpScreen: React.FC<BaseScreenProps> = ({
144
222
  return;
145
223
  }
146
224
 
225
+ if (validationStatus !== 'valid') {
226
+ toast.error('Please enter a valid username');
227
+ return;
228
+ }
229
+
147
230
  if (password !== confirmPassword) {
148
231
  toast.error('Passwords do not match');
149
232
  return;
@@ -158,14 +241,13 @@ const SignUpScreen: React.FC<BaseScreenProps> = ({
158
241
  setErrorMessage('');
159
242
  await signUp(username, email, password);
160
243
  toast.success('Account created successfully! Welcome to Oxy!');
161
- // The authentication state change will be handled through context
162
244
  } catch (error: any) {
163
245
  toast.error(error.message || 'Sign up failed');
164
246
  }
165
- };
247
+ }, [username, email, password, confirmPassword, validationStatus, validateEmail, signUp]);
166
248
 
167
249
  // Step components
168
- const renderWelcomeStep = () => (
250
+ const renderWelcomeStep = useMemo(() => (
169
251
  <Animated.View style={[
170
252
  styles.stepContainer,
171
253
  { opacity: fadeAnim, transform: [{ translateX: slideAnim }] }
@@ -176,20 +258,20 @@ const SignUpScreen: React.FC<BaseScreenProps> = ({
176
258
  {/* Example: Abstract friendly illustration */}
177
259
  <Path
178
260
  d="M30 100 Q60 20 110 60 Q160 100 190 40"
179
- stroke="#d169e5"
261
+ stroke={colors.primary}
180
262
  strokeWidth="8"
181
263
  fill="none"
182
264
  />
183
- <Circle cx="60" cy="60" r="18" fill="#d169e5" opacity="0.18" />
184
- <Circle cx="110" cy="60" r="24" fill="#d169e5" opacity="0.25" />
185
- <Circle cx="170" cy="50" r="14" fill="#d169e5" opacity="0.15" />
265
+ <Circle cx="60" cy="60" r="18" fill={colors.primary} opacity="0.18" />
266
+ <Circle cx="110" cy="60" r="24" fill={colors.primary} opacity="0.25" />
267
+ <Circle cx="170" cy="50" r="14" fill={colors.primary} opacity="0.15" />
186
268
  {/* Smiling face */}
187
269
  <Circle cx="110" cy="60" r="32" fill="#fff" opacity="0.7" />
188
- <Circle cx="100" cy="55" r="4" fill="#d169e5" />
189
- <Circle cx="120" cy="55" r="4" fill="#d169e5" />
270
+ <Circle cx="100" cy="55" r="4" fill={colors.primary} />
271
+ <Circle cx="120" cy="55" r="4" fill={colors.primary} />
190
272
  <Path
191
273
  d="M104 68 Q110 75 116 68"
192
- stroke="#d169e5"
274
+ stroke={colors.primary}
193
275
  strokeWidth="2"
194
276
  fill="none"
195
277
  strokeLinecap="round"
@@ -197,18 +279,12 @@ const SignUpScreen: React.FC<BaseScreenProps> = ({
197
279
  </Svg>
198
280
  </View>
199
281
 
200
- <View style={styles.header}>
201
- {/* Add a close/back icon for better navigation */}
202
- <Text style={[styles.welcomeTitle]}>Create a Oxy Account</Text>
203
- <View style={styles.placeholder} />
204
- </View>
205
-
206
- <Text style={[styles.welcomeText, { color: textColor }]}>
282
+ <Text style={[styles.welcomeText, { color: colors.text }]}>
207
283
  We're excited to have you join us. Let's get your account set up in just a few easy steps.
208
284
  </Text>
209
285
 
210
286
  <TouchableOpacity
211
- style={[styles.button, { backgroundColor: primaryColor }]}
287
+ style={[styles.button, { backgroundColor: colors.primary }]}
212
288
  onPress={nextStep}
213
289
  testID="welcome-next-button"
214
290
  >
@@ -216,50 +292,80 @@ const SignUpScreen: React.FC<BaseScreenProps> = ({
216
292
  </TouchableOpacity>
217
293
 
218
294
  <View style={styles.footerTextContainer}>
219
- <Text style={[styles.footerText, { color: textColor }]}>
295
+ <Text style={[styles.footerText, { color: colors.text }]}>
220
296
  Already have an account?{' '}
221
297
  </Text>
222
298
  <TouchableOpacity onPress={() => navigate('SignIn')}>
223
- <Text style={[styles.linkText, { color: primaryColor }]}>Sign In</Text>
299
+ <Text style={[styles.linkText, { color: colors.primary }]}>Sign In</Text>
224
300
  </TouchableOpacity>
225
301
  </View>
226
302
  </Animated.View>
227
- );
303
+ ), [fadeAnim, slideAnim, colors, nextStep, navigate, styles]);
228
304
 
229
- const renderIdentityStep = () => (
305
+ const renderIdentityStep = useMemo(() => (
230
306
  <Animated.View style={[
231
307
  styles.stepContainer,
232
308
  { opacity: fadeAnim, transform: [{ translateX: slideAnim }] }
233
309
  ]}>
234
- <Text style={[styles.stepTitle, { color: textColor }]}>Who are you?</Text>
310
+ <Text style={[styles.stepTitle, { color: colors.text }]}>Who are you?</Text>
235
311
 
236
312
  <View style={styles.inputContainer}>
237
- <Text style={[styles.label, { color: textColor }]}>Username</Text>
238
- <TextInput
239
- style={[
240
- styles.input,
241
- { backgroundColor: inputBackgroundColor, borderColor, color: textColor }
242
- ]}
243
- placeholder="Choose a username"
244
- placeholderTextColor={placeholderColor}
245
- value={username}
246
- onChangeText={setUsername}
247
- autoCapitalize="none"
248
- testID="username-input"
249
- />
313
+ <Text style={[styles.label, { color: colors.text }]}>Username</Text>
314
+ <View style={{ position: 'relative' }}>
315
+ <TextInput
316
+ style={[
317
+ styles.input,
318
+ { backgroundColor: colors.inputBackground, borderColor: colors.border, color: colors.text }
319
+ ]}
320
+ placeholder="Choose a username"
321
+ placeholderTextColor={colors.placeholder}
322
+ value={username}
323
+ onChangeText={handleUsernameChange}
324
+ autoCapitalize="none"
325
+ testID="username-input"
326
+ />
327
+ {validationStatus === 'validating' && (
328
+ <ActivityIndicator size="small" color={colors.primary} style={styles.validationIndicator} />
329
+ )}
330
+ {validationStatus === 'valid' && (
331
+ <Ionicons name="checkmark-circle" size={20} color={colors.success} style={styles.validationIndicator} />
332
+ )}
333
+ {validationStatus === 'invalid' && username.length >= 3 && (
334
+ <Ionicons name="close-circle" size={20} color={colors.error} style={styles.validationIndicator} />
335
+ )}
336
+ </View>
337
+
338
+ {/* Validation feedback */}
339
+ {validationStatus === 'valid' && (
340
+ <View style={[styles.validationSuccessCard, { backgroundColor: colors.success + '15' }]}>
341
+ <Ionicons name="checkmark-circle" size={16} color={colors.success} />
342
+ <Text style={[styles.validationText, { color: colors.success }]}>
343
+ Username is available
344
+ </Text>
345
+ </View>
346
+ )}
347
+
348
+ {validationStatus === 'invalid' && username.length >= 3 && (
349
+ <View style={[styles.validationErrorCard, { backgroundColor: colors.error + '15' }]}>
350
+ <Ionicons name="alert-circle" size={16} color={colors.error} />
351
+ <Text style={[styles.validationText, { color: colors.error }]}>
352
+ {errorMessage || 'Username is already taken'}
353
+ </Text>
354
+ </View>
355
+ )}
250
356
  </View>
251
357
 
252
358
  <View style={styles.inputContainer}>
253
- <Text style={[styles.label, { color: textColor }]}>Email</Text>
359
+ <Text style={[styles.label, { color: colors.text }]}>Email</Text>
254
360
  <TextInput
255
361
  style={[
256
362
  styles.input,
257
- { backgroundColor: inputBackgroundColor, borderColor, color: textColor }
363
+ { backgroundColor: colors.inputBackground, borderColor: colors.border, color: colors.text }
258
364
  ]}
259
365
  placeholder="Enter your email"
260
- placeholderTextColor={placeholderColor}
366
+ placeholderTextColor={colors.placeholder}
261
367
  value={email}
262
- onChangeText={setEmail}
368
+ onChangeText={handleEmailChange}
263
369
  autoCapitalize="none"
264
370
  keyboardType="email-address"
265
371
  testID="email-input"
@@ -268,135 +374,152 @@ const SignUpScreen: React.FC<BaseScreenProps> = ({
268
374
 
269
375
  <View style={styles.navigationButtons}>
270
376
  <TouchableOpacity
271
- style={[styles.navButton, styles.backButton]}
377
+ style={[styles.navButton, styles.backButton, { borderColor: colors.border }]}
272
378
  onPress={prevStep}
273
379
  >
274
- <Text style={[styles.navButtonText, { color: textColor }]}>Back</Text>
380
+ <Text style={[styles.navButtonText, { color: colors.text }]}>Back</Text>
275
381
  </TouchableOpacity>
276
382
 
277
383
  <TouchableOpacity
278
- style={[styles.navButton, styles.nextButton, { backgroundColor: primaryColor }]}
384
+ style={[styles.navButton, styles.nextButton, { backgroundColor: colors.primary }]}
279
385
  onPress={nextStep}
280
- disabled={!username || !email || !validateEmail(email)}
386
+ disabled={!username || !email || !validateEmail(email) || validationStatus !== 'valid'}
281
387
  >
282
- <Text style={styles.navButtonText}>Next</Text>
388
+ <Text style={[styles.navButtonText, { color: '#FFFFFF' }]}>Next</Text>
283
389
  </TouchableOpacity>
284
390
  </View>
285
391
  </Animated.View>
286
- );
392
+ ), [fadeAnim, slideAnim, colors, username, email, validationStatus, errorMessage, handleUsernameChange, handleEmailChange, validateEmail, prevStep, nextStep, styles]);
287
393
 
288
- const renderSecurityStep = () => (
394
+ const renderSecurityStep = useMemo(() => (
289
395
  <Animated.View style={[
290
396
  styles.stepContainer,
291
397
  { opacity: fadeAnim, transform: [{ translateX: slideAnim }] }
292
398
  ]}>
293
- <Text style={[styles.stepTitle, { color: textColor }]}>Secure your account</Text>
399
+ <Text style={[styles.stepTitle, { color: colors.text }]}>Secure your account</Text>
294
400
 
295
401
  <View style={styles.inputContainer}>
296
- <Text style={[styles.label, { color: textColor }]}>Password</Text>
297
- <TextInput
298
- style={[
299
- styles.input,
300
- { backgroundColor: inputBackgroundColor, borderColor, color: textColor }
301
- ]}
302
- placeholder="Create a password"
303
- placeholderTextColor={placeholderColor}
304
- value={password}
305
- onChangeText={setPassword}
306
- secureTextEntry
307
- testID="password-input"
308
- />
309
- <Text style={[styles.passwordHint, { color: isDarkTheme ? '#AAAAAA' : '#666666' }]}>
402
+ <Text style={[styles.label, { color: colors.text }]}>Password</Text>
403
+ <View style={{ position: 'relative' }}>
404
+ <TextInput
405
+ style={[
406
+ styles.input,
407
+ { backgroundColor: colors.inputBackground, borderColor: colors.border, color: colors.text }
408
+ ]}
409
+ placeholder="Create a password"
410
+ placeholderTextColor={colors.placeholder}
411
+ value={password}
412
+ onChangeText={handlePasswordChange}
413
+ secureTextEntry={!showPassword}
414
+ testID="password-input"
415
+ />
416
+ <TouchableOpacity
417
+ style={styles.passwordToggle}
418
+ onPress={() => setShowPassword(!showPassword)}
419
+ >
420
+ <Ionicons
421
+ name={showPassword ? 'eye-off' : 'eye'}
422
+ size={20}
423
+ color={colors.placeholder}
424
+ />
425
+ </TouchableOpacity>
426
+ </View>
427
+ <Text style={[styles.passwordHint, { color: colors.secondaryText }]}>
310
428
  Password must be at least 8 characters long
311
429
  </Text>
312
430
  </View>
313
431
 
314
432
  <View style={styles.inputContainer}>
315
- <Text style={[styles.label, { color: textColor }]}>Confirm Password</Text>
316
- <TextInput
317
- style={[
318
- styles.input,
319
- { backgroundColor: inputBackgroundColor, borderColor, color: textColor }
320
- ]}
321
- placeholder="Confirm your password"
322
- placeholderTextColor={placeholderColor}
323
- value={confirmPassword}
324
- onChangeText={setConfirmPassword}
325
- secureTextEntry
326
- testID="confirm-password-input"
327
- />
433
+ <Text style={[styles.label, { color: colors.text }]}>Confirm Password</Text>
434
+ <View style={{ position: 'relative' }}>
435
+ <TextInput
436
+ style={[
437
+ styles.input,
438
+ { backgroundColor: colors.inputBackground, borderColor: colors.border, color: colors.text }
439
+ ]}
440
+ placeholder="Confirm your password"
441
+ placeholderTextColor={colors.placeholder}
442
+ value={confirmPassword}
443
+ onChangeText={handleConfirmPasswordChange}
444
+ secureTextEntry={!showConfirmPassword}
445
+ testID="confirm-password-input"
446
+ />
447
+ <TouchableOpacity
448
+ style={styles.passwordToggle}
449
+ onPress={() => setShowConfirmPassword(!showConfirmPassword)}
450
+ >
451
+ <Ionicons
452
+ name={showConfirmPassword ? 'eye-off' : 'eye'}
453
+ size={20}
454
+ color={colors.placeholder}
455
+ />
456
+ </TouchableOpacity>
457
+ </View>
328
458
  </View>
329
459
 
330
460
  <View style={styles.navigationButtons}>
331
461
  <TouchableOpacity
332
- style={[styles.navButton, styles.backButton]}
462
+ style={[styles.navButton, styles.backButton, { borderColor: colors.border }]}
333
463
  onPress={prevStep}
334
464
  >
335
- <Text style={[styles.navButtonText, { color: textColor }]}>Back</Text>
465
+ <Text style={[styles.navButtonText, { color: colors.text }]}>Back</Text>
336
466
  </TouchableOpacity>
337
467
 
338
468
  <TouchableOpacity
339
- style={[styles.navButton, styles.nextButton, { backgroundColor: primaryColor }]}
469
+ style={[styles.navButton, styles.nextButton, { backgroundColor: colors.primary }]}
340
470
  onPress={nextStep}
341
471
  disabled={!password || password.length < 8 || password !== confirmPassword}
342
472
  >
343
- <Text style={styles.navButtonText}>Next</Text>
473
+ <Text style={[styles.navButtonText, { color: '#FFFFFF' }]}>Next</Text>
344
474
  </TouchableOpacity>
345
475
  </View>
346
476
  </Animated.View>
347
- );
477
+ ), [fadeAnim, slideAnim, colors, password, confirmPassword, showPassword, showConfirmPassword, handlePasswordChange, handleConfirmPasswordChange, prevStep, nextStep, styles]);
348
478
 
349
- const renderSummaryStep = () => (
479
+ const renderSummaryStep = useMemo(() => (
350
480
  <Animated.View style={[
351
481
  styles.stepContainer,
352
482
  { opacity: fadeAnim, transform: [{ translateX: slideAnim }] }
353
483
  ]}>
354
- <Text style={[styles.stepTitle, { color: textColor }]}>Ready to join</Text>
484
+ <Text style={[styles.stepTitle, { color: colors.text }]}>Ready to join</Text>
355
485
 
356
486
  <View style={styles.summaryContainer}>
357
487
  <View style={styles.summaryRow}>
358
- <Text style={[styles.summaryLabel, { color: isDarkTheme ? '#AAAAAA' : '#666666' }]}>Username:</Text>
359
- <Text style={[styles.summaryValue, { color: textColor }]}>{username}</Text>
488
+ <Text style={[styles.summaryLabel, { color: colors.secondaryText }]}>Username:</Text>
489
+ <Text style={[styles.summaryValue, { color: colors.text }]}>{username}</Text>
360
490
  </View>
361
491
 
362
492
  <View style={styles.summaryRow}>
363
- <Text style={[styles.summaryLabel, { color: isDarkTheme ? '#AAAAAA' : '#666666' }]}>Email:</Text>
364
- <Text style={[styles.summaryValue, { color: textColor }]}>{email}</Text>
493
+ <Text style={[styles.summaryLabel, { color: colors.secondaryText }]}>Email:</Text>
494
+ <Text style={[styles.summaryValue, { color: colors.text }]}>{email}</Text>
365
495
  </View>
366
496
  </View>
367
497
 
368
- {errorMessage ? (
369
- <View style={styles.errorContainer}>
370
- <Text style={styles.errorText}>{errorMessage}</Text>
371
- </View>
372
- ) : null}
498
+ <TouchableOpacity
499
+ style={[styles.button, { backgroundColor: colors.primary }]}
500
+ onPress={handleSignUp}
501
+ disabled={isLoading}
502
+ testID="signup-button"
503
+ >
504
+ {isLoading ? (
505
+ <ActivityIndicator color="#FFFFFF" size="small" />
506
+ ) : (
507
+ <Text style={styles.buttonText}>Create Account</Text>
508
+ )}
509
+ </TouchableOpacity>
373
510
 
374
511
  <View style={styles.navigationButtons}>
375
512
  <TouchableOpacity
376
- style={[styles.navButton, styles.backButton]}
513
+ style={[styles.navButton, styles.backButton, { borderColor: colors.border }]}
377
514
  onPress={prevStep}
378
515
  >
379
- <Text style={[styles.navButtonText, { color: textColor }]}>Back</Text>
380
- </TouchableOpacity>
381
-
382
- <TouchableOpacity
383
- style={[styles.button, { opacity: isLoading ? 0.8 : 1 }]}
384
- onPress={handleSignUp}
385
- disabled={isLoading}
386
- testID="signup-button"
387
- >
388
- {isLoading ? (
389
- <ActivityIndicator color="#FFFFFF" size="small" />
390
- ) : (
391
- <Text style={styles.buttonText}>Create Account</Text>
392
- )}
516
+ <Text style={[styles.navButtonText, { color: colors.text }]}>Back</Text>
393
517
  </TouchableOpacity>
394
518
  </View>
395
519
  </Animated.View>
396
- );
520
+ ), [fadeAnim, slideAnim, colors, username, email, isLoading, handleSignUp, prevStep, styles]);
397
521
 
398
- // Progress indicators
399
- const renderProgressIndicators = () => (
522
+ const renderProgressIndicators = useMemo(() => (
400
523
  <View style={styles.progressContainer}>
401
524
  {[0, 1, 2, 3].map((step) => (
402
525
  <View
@@ -404,74 +527,144 @@ const SignUpScreen: React.FC<BaseScreenProps> = ({
404
527
  style={[
405
528
  styles.progressDot,
406
529
  currentStep === step ?
407
- { backgroundColor: primaryColor, width: 24 } :
408
- { backgroundColor: isDarkTheme ? '#444444' : '#E0E0E0' }
530
+ { backgroundColor: colors.primary, width: 24 } :
531
+ { backgroundColor: colors.border }
409
532
  ]}
410
533
  />
411
534
  ))}
412
535
  </View>
413
- );
536
+ ), [currentStep, colors, styles]);
414
537
 
415
- // Render step based on current step value
416
- const renderCurrentStep = () => {
538
+ const renderCurrentStep = useCallback(() => {
417
539
  switch (currentStep) {
418
540
  case 0:
419
- return renderWelcomeStep();
541
+ return renderWelcomeStep;
420
542
  case 1:
421
- return renderIdentityStep();
543
+ return renderIdentityStep;
422
544
  case 2:
423
- return renderSecurityStep();
545
+ return renderSecurityStep;
424
546
  case 3:
425
- return renderSummaryStep();
547
+ return renderSummaryStep;
426
548
  default:
427
- return null;
549
+ return renderWelcomeStep;
428
550
  }
429
- };
551
+ }, [currentStep, renderWelcomeStep, renderIdentityStep, renderSecurityStep, renderSummaryStep]);
552
+
553
+ // If user is already authenticated, show user info and account center option
554
+ if (user && isAuthenticated) {
555
+ return (
556
+ <KeyboardAvoidingView
557
+ style={[styles.container, { backgroundColor: colors.background }]}
558
+ behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
559
+ >
560
+ <StatusBar
561
+ barStyle={theme === 'dark' ? 'light-content' : 'dark-content'}
562
+ backgroundColor={colors.background}
563
+ />
564
+
565
+ <ScrollView
566
+ contentContainerStyle={styles.scrollContent}
567
+ showsVerticalScrollIndicator={false}
568
+ >
569
+ <Text style={[styles.welcomeTitle, { color: colors.text }]}>
570
+ Welcome, {user.username}!
571
+ </Text>
572
+
573
+ <View style={[styles.userInfoContainer, { backgroundColor: colors.inputBackground }]}>
574
+ <Text style={[styles.userInfoText, { color: colors.text }]}>
575
+ You are already signed in.
576
+ </Text>
577
+ {user.email && (
578
+ <Text style={[styles.userInfoText, { color: colors.secondaryText }]}>
579
+ Email: {user.email}
580
+ </Text>
581
+ )}
582
+ </View>
583
+
584
+ <View style={styles.actionButtonsContainer}>
585
+ <TouchableOpacity
586
+ style={[styles.button, { backgroundColor: colors.primary }]}
587
+ onPress={() => navigate('AccountCenter')}
588
+ >
589
+ <Text style={styles.buttonText}>Go to Account Center</Text>
590
+ </TouchableOpacity>
591
+ </View>
592
+ </ScrollView>
593
+ </KeyboardAvoidingView>
594
+ );
595
+ }
430
596
 
431
597
  return (
432
- <BottomSheetScrollView
433
- contentContainerStyle={styles.scrollContainer}
434
- keyboardShouldPersistTaps="handled"
598
+ <KeyboardAvoidingView
599
+ style={[styles.container, { backgroundColor: colors.background }]}
600
+ behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
435
601
  >
436
- <OxyLogo
437
- style={{ marginBottom: 24 }}
438
- width={50}
439
- height={50}
602
+ <StatusBar
603
+ barStyle={theme === 'dark' ? 'light-content' : 'dark-content'}
604
+ backgroundColor={colors.background}
440
605
  />
441
606
 
442
- <View style={styles.formContainer}>
607
+ <ScrollView
608
+ contentContainerStyle={styles.scrollContent}
609
+ showsVerticalScrollIndicator={false}
610
+ keyboardShouldPersistTaps="handled"
611
+ >
612
+ {renderProgressIndicators}
443
613
  {renderCurrentStep()}
444
- </View>
445
-
446
- {currentStep > 0 && renderProgressIndicators()}
447
- </BottomSheetScrollView>
614
+ </ScrollView>
615
+ </KeyboardAvoidingView>
448
616
  );
449
617
  };
450
618
 
451
- const styles = StyleSheet.create({
452
- scrollContainer: {
453
- padding: 20,
619
+ // Memoized styles creation
620
+ const createStyles = (colors: any, theme: string) => StyleSheet.create({
621
+ container: {
622
+ flex: 1,
454
623
  },
455
- header: {
456
- flexDirection: 'row',
624
+ scrollContent: {
625
+ flexGrow: 1,
626
+ paddingHorizontal: 24,
627
+ paddingTop: 40,
628
+ paddingBottom: 40,
629
+ },
630
+ stepContainer: {
631
+ flex: 1,
632
+ justifyContent: 'center',
457
633
  alignItems: 'center',
458
- justifyContent: 'space-between',
634
+ minHeight: 500,
459
635
  },
460
- placeholder: {
461
- width: 40,
636
+ welcomeImageContainer: {
637
+ alignItems: 'center',
638
+ justifyContent: 'center',
639
+ marginVertical: 30,
462
640
  },
463
- formContainer: {
464
- width: '100%',
465
- marginTop: 8,
641
+ welcomeTitle: {
642
+ fontFamily: Platform.OS === 'web' ? 'Phudu' : 'Phudu-Bold',
643
+ fontWeight: Platform.OS === 'web' ? 'bold' : undefined,
644
+ fontSize: 42,
645
+ lineHeight: 48,
646
+ marginBottom: 24,
647
+ textAlign: 'left',
648
+ letterSpacing: -1,
466
649
  },
467
- stepContainer: {
468
- width: '100%',
469
- paddingVertical: 8,
470
- paddingHorizontal: 0,
471
- marginBottom: 8,
650
+ welcomeText: {
651
+ fontSize: 16,
652
+ textAlign: 'left',
653
+ marginBottom: 30,
654
+ lineHeight: 24,
655
+ },
656
+ stepTitle: {
657
+ fontFamily: Platform.OS === 'web' ? 'Phudu' : 'Phudu-Bold',
658
+ fontWeight: Platform.OS === 'web' ? 'bold' : undefined,
659
+ fontSize: 34,
660
+ marginBottom: 20,
661
+ color: colors.primary,
662
+ maxWidth: '90%',
663
+ textAlign: 'left',
472
664
  },
473
665
  inputContainer: {
474
666
  marginBottom: 18,
667
+ width: '100%',
475
668
  },
476
669
  label: {
477
670
  fontSize: 15,
@@ -485,22 +678,55 @@ const styles = StyleSheet.create({
485
678
  paddingHorizontal: 16,
486
679
  borderWidth: 1,
487
680
  fontSize: 16,
488
- backgroundColor: '#F5F5F5',
489
- borderColor: '#E0E0E0',
490
681
  marginBottom: 2,
491
682
  },
683
+ validationIndicator: {
684
+ position: 'absolute',
685
+ right: 16,
686
+ top: 14,
687
+ },
688
+ validationSuccessCard: {
689
+ flexDirection: 'row',
690
+ alignItems: 'center',
691
+ padding: 12,
692
+ borderRadius: 12,
693
+ marginTop: 8,
694
+ gap: 8,
695
+ },
696
+ validationErrorCard: {
697
+ flexDirection: 'row',
698
+ alignItems: 'center',
699
+ padding: 12,
700
+ borderRadius: 12,
701
+ marginTop: 8,
702
+ gap: 8,
703
+ },
704
+ validationText: {
705
+ fontSize: 12,
706
+ fontWeight: '500',
707
+ },
708
+ passwordToggle: {
709
+ position: 'absolute',
710
+ right: 16,
711
+ top: 14,
712
+ padding: 4,
713
+ },
714
+ passwordHint: {
715
+ fontSize: 12,
716
+ marginTop: 4,
717
+ },
492
718
  button: {
493
- backgroundColor: '#d169e5',
494
719
  height: 48,
495
720
  borderRadius: 24,
496
721
  alignItems: 'center',
497
722
  justifyContent: 'center',
498
723
  marginTop: 24,
499
- shadowColor: '#d169e5',
724
+ shadowColor: colors.primary,
500
725
  shadowOpacity: 0.12,
501
726
  shadowOffset: { width: 0, height: 2 },
502
727
  shadowRadius: 8,
503
728
  elevation: 2,
729
+ width: '100%',
504
730
  },
505
731
  buttonText: {
506
732
  color: '#FFFFFF',
@@ -515,30 +741,14 @@ const styles = StyleSheet.create({
515
741
  },
516
742
  footerText: {
517
743
  fontSize: 15,
518
- color: '#888',
519
744
  },
520
745
  linkText: {
521
746
  fontSize: 15,
522
747
  fontWeight: '700',
523
- color: '#d169e5',
524
- },
525
- errorContainer: {
526
- backgroundColor: '#FFE4EC',
527
- padding: 14,
528
- borderRadius: 18,
529
- marginBottom: 16,
530
- borderWidth: 1,
531
- borderColor: '#F8BBD0',
532
- },
533
- errorText: {
534
- color: '#D32F2F',
535
- fontSize: 15,
536
- fontWeight: '500',
537
748
  },
538
749
  userInfoContainer: {
539
750
  padding: 20,
540
751
  marginVertical: 20,
541
- backgroundColor: '#F5F5F5',
542
752
  borderRadius: 24,
543
753
  alignItems: 'center',
544
754
  shadowColor: '#000',
@@ -555,42 +765,12 @@ const styles = StyleSheet.create({
555
765
  actionButtonsContainer: {
556
766
  marginTop: 24,
557
767
  },
558
- // Multi-step form styles
559
- welcomeTitle: {
560
- fontFamily: Platform.OS === 'web'
561
- ? 'Phudu' // Use CSS font name directly for web
562
- : 'Phudu-Bold', // Use exact font name as registered with Font.loadAsync
563
- fontWeight: Platform.OS === 'web' ? 'bold' : undefined, // Only apply fontWeight on web
564
- fontSize: 54,
565
- marginBottom: 24,
566
- },
567
- welcomeText: {
568
- fontSize: 16,
569
- textAlign: 'left',
570
- marginBottom: 30,
571
- lineHeight: 24,
572
- color: '#444',
573
- },
574
- welcomeImageContainer: {
575
- alignItems: 'center',
576
- justifyContent: 'center',
577
- marginVertical: 30,
578
- },
579
- stepTitle: {
580
- fontFamily: Platform.OS === 'web'
581
- ? 'Phudu' // Use CSS font name directly for web
582
- : 'Phudu-Bold', // Use exact font name as registered with Font.loadAsync
583
- fontWeight: Platform.OS === 'web' ? 'bold' : undefined, // Only apply fontWeight on web
584
- fontSize: 34,
585
- marginBottom: 20,
586
- color: '#d169e5',
587
- maxWidth: '90%',
588
- },
589
768
  navigationButtons: {
590
769
  flexDirection: 'row',
591
770
  justifyContent: 'space-between',
592
771
  alignItems: 'center',
593
772
  marginTop: 28,
773
+ width: '100%',
594
774
  },
595
775
  navButton: {
596
776
  borderRadius: 24,
@@ -603,21 +783,13 @@ const styles = StyleSheet.create({
603
783
  backButton: {
604
784
  backgroundColor: 'transparent',
605
785
  borderWidth: 1,
606
- borderColor: '#E0E0E0',
607
786
  },
608
787
  nextButton: {
609
788
  minWidth: 100,
610
- backgroundColor: '#d169e5',
611
789
  },
612
790
  navButtonText: {
613
791
  fontSize: 16,
614
792
  fontWeight: '700',
615
- color: '#d169e5',
616
- },
617
- passwordHint: {
618
- fontSize: 12,
619
- marginTop: 4,
620
- color: '#888',
621
793
  },
622
794
  progressContainer: {
623
795
  flexDirection: 'row',
@@ -630,10 +802,9 @@ const styles = StyleSheet.create({
630
802
  width: 10,
631
803
  borderRadius: 5,
632
804
  marginHorizontal: 6,
633
- backgroundColor: '#E0E0E0',
634
805
  borderWidth: 2,
635
806
  borderColor: '#fff',
636
- shadowColor: '#d169e5',
807
+ shadowColor: colors.primary,
637
808
  shadowOpacity: 0.08,
638
809
  shadowOffset: { width: 0, height: 1 },
639
810
  shadowRadius: 2,
@@ -642,6 +813,7 @@ const styles = StyleSheet.create({
642
813
  summaryContainer: {
643
814
  padding: 0,
644
815
  marginBottom: 24,
816
+ width: '100%',
645
817
  },
646
818
  summaryRow: {
647
819
  flexDirection: 'row',
@@ -650,13 +822,11 @@ const styles = StyleSheet.create({
650
822
  summaryLabel: {
651
823
  fontSize: 15,
652
824
  width: 90,
653
- color: '#888',
654
825
  },
655
826
  summaryValue: {
656
827
  fontSize: 15,
657
828
  fontWeight: '600',
658
829
  flex: 1,
659
- color: '#222',
660
830
  },
661
831
  });
662
832