@oxyhq/services 5.11.8 → 5.11.10

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 (199) hide show
  1. package/lib/commonjs/core/OxyServices.js +104 -10
  2. package/lib/commonjs/core/OxyServices.js.map +1 -1
  3. package/lib/commonjs/ui/components/AnimationExample.js +213 -0
  4. package/lib/commonjs/ui/components/AnimationExample.js.map +1 -0
  5. package/lib/commonjs/ui/components/FollowButton.js +58 -47
  6. package/lib/commonjs/ui/components/FollowButton.js.map +1 -1
  7. package/lib/commonjs/ui/components/GroupedItem.js +2 -1
  8. package/lib/commonjs/ui/components/GroupedItem.js.map +1 -1
  9. package/lib/commonjs/ui/components/GroupedSection.js +3 -0
  10. package/lib/commonjs/ui/components/GroupedSection.js.map +1 -1
  11. package/lib/commonjs/ui/components/Header.js +25 -11
  12. package/lib/commonjs/ui/components/Header.js.map +1 -1
  13. package/lib/commonjs/ui/components/OxyProvider.js +69 -33
  14. package/lib/commonjs/ui/components/OxyProvider.js.map +1 -1
  15. package/lib/commonjs/ui/components/ProfileCard.js +5 -1
  16. package/lib/commonjs/ui/components/ProfileCard.js.map +1 -1
  17. package/lib/commonjs/ui/components/index.js +0 -7
  18. package/lib/commonjs/ui/components/index.js.map +1 -1
  19. package/lib/commonjs/ui/components/internal/TextField.js +8 -4
  20. package/lib/commonjs/ui/components/internal/TextField.js.map +1 -1
  21. package/lib/commonjs/ui/components/photogrid/JustifiedPhotoGrid.js +161 -0
  22. package/lib/commonjs/ui/components/photogrid/JustifiedPhotoGrid.js.map +1 -0
  23. package/lib/commonjs/ui/context/OxyContext.js +97 -38
  24. package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
  25. package/lib/commonjs/ui/hooks/useFollow.types.js +2 -0
  26. package/lib/commonjs/ui/hooks/useFollow.types.js.map +1 -0
  27. package/lib/commonjs/ui/navigation/OxyRouter.js +10 -0
  28. package/lib/commonjs/ui/navigation/OxyRouter.js.map +1 -1
  29. package/lib/commonjs/ui/screens/AccountCenterScreen.js +26 -14
  30. package/lib/commonjs/ui/screens/AccountCenterScreen.js.map +1 -1
  31. package/lib/commonjs/ui/screens/AccountOverviewScreen.js +3 -3
  32. package/lib/commonjs/ui/screens/AccountOverviewScreen.js.map +1 -1
  33. package/lib/commonjs/ui/screens/AccountSettingsScreen.js +64 -15
  34. package/lib/commonjs/ui/screens/AccountSettingsScreen.js.map +1 -1
  35. package/lib/commonjs/ui/screens/AccountSwitcherScreen.js +4 -4
  36. package/lib/commonjs/ui/screens/AccountSwitcherScreen.js.map +1 -1
  37. package/lib/commonjs/ui/screens/FeedbackScreen.js +72 -75
  38. package/lib/commonjs/ui/screens/FeedbackScreen.js.map +1 -1
  39. package/lib/commonjs/ui/screens/FileManagementScreen.js +286 -126
  40. package/lib/commonjs/ui/screens/FileManagementScreen.js.map +1 -1
  41. package/lib/commonjs/ui/screens/LanguageSelectorScreen.js +322 -0
  42. package/lib/commonjs/ui/screens/LanguageSelectorScreen.js.map +1 -0
  43. package/lib/commonjs/ui/screens/ProfileScreen.js +1 -1
  44. package/lib/commonjs/ui/screens/ProfileScreen.js.map +1 -1
  45. package/lib/commonjs/ui/screens/SessionManagementScreen.js +176 -174
  46. package/lib/commonjs/ui/screens/SessionManagementScreen.js.map +1 -1
  47. package/lib/commonjs/ui/screens/SignInScreen.js +43 -52
  48. package/lib/commonjs/ui/screens/SignInScreen.js.map +1 -1
  49. package/lib/commonjs/ui/screens/SignUpScreen.js +6 -4
  50. package/lib/commonjs/ui/screens/SignUpScreen.js.map +1 -1
  51. package/lib/commonjs/ui/screens/WelcomeNewUserScreen.js +386 -0
  52. package/lib/commonjs/ui/screens/WelcomeNewUserScreen.js.map +1 -0
  53. package/lib/commonjs/ui/screens/internal/SignInPasswordStep.js +25 -15
  54. package/lib/commonjs/ui/screens/internal/SignInPasswordStep.js.map +1 -1
  55. package/lib/commonjs/ui/screens/internal/SignInUsernameStep.js +16 -9
  56. package/lib/commonjs/ui/screens/internal/SignInUsernameStep.js.map +1 -1
  57. package/lib/commonjs/ui/screens/karma/KarmaCenterScreen.js +1 -1
  58. package/lib/commonjs/ui/screens/karma/KarmaCenterScreen.js.map +1 -1
  59. package/lib/commonjs/ui/styles/authStyles.js +1 -1
  60. package/lib/commonjs/ui/styles/authStyles.js.map +1 -1
  61. package/lib/module/core/OxyServices.js +103 -9
  62. package/lib/module/core/OxyServices.js.map +1 -1
  63. package/lib/module/ui/components/AnimationExample.js +209 -0
  64. package/lib/module/ui/components/AnimationExample.js.map +1 -0
  65. package/lib/module/ui/components/FollowButton.js +58 -47
  66. package/lib/module/ui/components/FollowButton.js.map +1 -1
  67. package/lib/module/ui/components/GroupedItem.js +2 -1
  68. package/lib/module/ui/components/GroupedItem.js.map +1 -1
  69. package/lib/module/ui/components/GroupedSection.js +3 -0
  70. package/lib/module/ui/components/GroupedSection.js.map +1 -1
  71. package/lib/module/ui/components/Header.js +25 -11
  72. package/lib/module/ui/components/Header.js.map +1 -1
  73. package/lib/module/ui/components/OxyProvider.js +70 -34
  74. package/lib/module/ui/components/OxyProvider.js.map +1 -1
  75. package/lib/module/ui/components/ProfileCard.js +5 -1
  76. package/lib/module/ui/components/ProfileCard.js.map +1 -1
  77. package/lib/module/ui/components/index.js +0 -1
  78. package/lib/module/ui/components/index.js.map +1 -1
  79. package/lib/module/ui/components/internal/TextField.js +8 -4
  80. package/lib/module/ui/components/internal/TextField.js.map +1 -1
  81. package/lib/module/ui/components/photogrid/JustifiedPhotoGrid.js +156 -0
  82. package/lib/module/ui/components/photogrid/JustifiedPhotoGrid.js.map +1 -0
  83. package/lib/module/ui/context/OxyContext.js +97 -39
  84. package/lib/module/ui/context/OxyContext.js.map +1 -1
  85. package/lib/module/ui/hooks/useFollow.types.js +2 -0
  86. package/lib/module/ui/hooks/useFollow.types.js.map +1 -0
  87. package/lib/module/ui/navigation/OxyRouter.js +10 -0
  88. package/lib/module/ui/navigation/OxyRouter.js.map +1 -1
  89. package/lib/module/ui/screens/AccountCenterScreen.js +12 -1
  90. package/lib/module/ui/screens/AccountCenterScreen.js.map +1 -1
  91. package/lib/module/ui/screens/AccountOverviewScreen.js +3 -3
  92. package/lib/module/ui/screens/AccountOverviewScreen.js.map +1 -1
  93. package/lib/module/ui/screens/AccountSettingsScreen.js +64 -15
  94. package/lib/module/ui/screens/AccountSettingsScreen.js.map +1 -1
  95. package/lib/module/ui/screens/AccountSwitcherScreen.js +4 -4
  96. package/lib/module/ui/screens/AccountSwitcherScreen.js.map +1 -1
  97. package/lib/module/ui/screens/FeedbackScreen.js +72 -75
  98. package/lib/module/ui/screens/FeedbackScreen.js.map +1 -1
  99. package/lib/module/ui/screens/FileManagementScreen.js +285 -125
  100. package/lib/module/ui/screens/FileManagementScreen.js.map +1 -1
  101. package/lib/module/ui/screens/LanguageSelectorScreen.js +319 -0
  102. package/lib/module/ui/screens/LanguageSelectorScreen.js.map +1 -0
  103. package/lib/module/ui/screens/ProfileScreen.js +1 -1
  104. package/lib/module/ui/screens/ProfileScreen.js.map +1 -1
  105. package/lib/module/ui/screens/SessionManagementScreen.js +177 -175
  106. package/lib/module/ui/screens/SessionManagementScreen.js.map +1 -1
  107. package/lib/module/ui/screens/SignInScreen.js +44 -53
  108. package/lib/module/ui/screens/SignInScreen.js.map +1 -1
  109. package/lib/module/ui/screens/SignUpScreen.js +6 -4
  110. package/lib/module/ui/screens/SignUpScreen.js.map +1 -1
  111. package/lib/module/ui/screens/WelcomeNewUserScreen.js +382 -0
  112. package/lib/module/ui/screens/WelcomeNewUserScreen.js.map +1 -0
  113. package/lib/module/ui/screens/internal/SignInPasswordStep.js +23 -14
  114. package/lib/module/ui/screens/internal/SignInPasswordStep.js.map +1 -1
  115. package/lib/module/ui/screens/internal/SignInUsernameStep.js +15 -9
  116. package/lib/module/ui/screens/internal/SignInUsernameStep.js.map +1 -1
  117. package/lib/module/ui/screens/karma/KarmaCenterScreen.js +1 -1
  118. package/lib/module/ui/screens/karma/KarmaCenterScreen.js.map +1 -1
  119. package/lib/module/ui/styles/authStyles.js +1 -1
  120. package/lib/module/ui/styles/authStyles.js.map +1 -1
  121. package/lib/typescript/core/OxyServices.d.ts +95 -4
  122. package/lib/typescript/core/OxyServices.d.ts.map +1 -1
  123. package/lib/typescript/models/interfaces.d.ts +1 -5
  124. package/lib/typescript/models/interfaces.d.ts.map +1 -1
  125. package/lib/typescript/models/session.d.ts +1 -4
  126. package/lib/typescript/models/session.d.ts.map +1 -1
  127. package/lib/typescript/ui/components/AnimationExample.d.ts +4 -0
  128. package/lib/typescript/ui/components/AnimationExample.d.ts.map +1 -0
  129. package/lib/typescript/ui/components/FollowButton.d.ts.map +1 -1
  130. package/lib/typescript/ui/components/GroupedItem.d.ts.map +1 -1
  131. package/lib/typescript/ui/components/Header.d.ts +9 -0
  132. package/lib/typescript/ui/components/Header.d.ts.map +1 -1
  133. package/lib/typescript/ui/components/OxyProvider.d.ts.map +1 -1
  134. package/lib/typescript/ui/components/ProfileCard.d.ts +1 -3
  135. package/lib/typescript/ui/components/ProfileCard.d.ts.map +1 -1
  136. package/lib/typescript/ui/components/index.d.ts +0 -1
  137. package/lib/typescript/ui/components/index.d.ts.map +1 -1
  138. package/lib/typescript/ui/components/internal/TextField.d.ts.map +1 -1
  139. package/lib/typescript/ui/components/photogrid/JustifiedPhotoGrid.d.ts +27 -0
  140. package/lib/typescript/ui/components/photogrid/JustifiedPhotoGrid.d.ts.map +1 -0
  141. package/lib/typescript/ui/context/OxyContext.d.ts +6 -2
  142. package/lib/typescript/ui/context/OxyContext.d.ts.map +1 -1
  143. package/lib/typescript/ui/hooks/useFollow.types.d.ts +33 -0
  144. package/lib/typescript/ui/hooks/useFollow.types.d.ts.map +1 -0
  145. package/lib/typescript/ui/navigation/OxyRouter.d.ts.map +1 -1
  146. package/lib/typescript/ui/navigation/types.d.ts +5 -0
  147. package/lib/typescript/ui/navigation/types.d.ts.map +1 -1
  148. package/lib/typescript/ui/screens/AccountCenterScreen.d.ts.map +1 -1
  149. package/lib/typescript/ui/screens/AccountSettingsScreen.d.ts.map +1 -1
  150. package/lib/typescript/ui/screens/FeedbackScreen.d.ts.map +1 -1
  151. package/lib/typescript/ui/screens/FileManagementScreen.d.ts +18 -1
  152. package/lib/typescript/ui/screens/FileManagementScreen.d.ts.map +1 -1
  153. package/lib/typescript/ui/screens/LanguageSelectorScreen.d.ts +7 -0
  154. package/lib/typescript/ui/screens/LanguageSelectorScreen.d.ts.map +1 -0
  155. package/lib/typescript/ui/screens/ProfileScreen.d.ts.map +1 -1
  156. package/lib/typescript/ui/screens/SessionManagementScreen.d.ts.map +1 -1
  157. package/lib/typescript/ui/screens/SignInScreen.d.ts.map +1 -1
  158. package/lib/typescript/ui/screens/SignUpScreen.d.ts.map +1 -1
  159. package/lib/typescript/ui/screens/WelcomeNewUserScreen.d.ts +13 -0
  160. package/lib/typescript/ui/screens/WelcomeNewUserScreen.d.ts.map +1 -0
  161. package/lib/typescript/ui/screens/internal/SignInPasswordStep.d.ts +5 -5
  162. package/lib/typescript/ui/screens/internal/SignInPasswordStep.d.ts.map +1 -1
  163. package/lib/typescript/ui/screens/internal/SignInUsernameStep.d.ts +4 -4
  164. package/lib/typescript/ui/screens/internal/SignInUsernameStep.d.ts.map +1 -1
  165. package/lib/typescript/ui/styles/authStyles.d.ts +1 -1
  166. package/package.json +10 -2
  167. package/src/core/OxyServices.ts +107 -13
  168. package/src/models/interfaces.ts +2 -5
  169. package/src/models/session.ts +1 -4
  170. package/src/ui/components/AnimationExample.tsx +194 -0
  171. package/src/ui/components/FollowButton.tsx +65 -45
  172. package/src/ui/components/GroupedItem.tsx +1 -0
  173. package/src/ui/components/GroupedSection.tsx +1 -1
  174. package/src/ui/components/Header.tsx +36 -12
  175. package/src/ui/components/OxyProvider.tsx +66 -32
  176. package/src/ui/components/ProfileCard.tsx +6 -8
  177. package/src/ui/components/index.ts +0 -1
  178. package/src/ui/components/internal/TextField.tsx +12 -6
  179. package/src/ui/components/photogrid/JustifiedPhotoGrid.tsx +158 -0
  180. package/src/ui/context/OxyContext.tsx +84 -54
  181. package/src/ui/hooks/useFollow.types.ts +33 -0
  182. package/src/ui/navigation/OxyRouter.tsx +10 -0
  183. package/src/ui/navigation/types.ts +6 -0
  184. package/src/ui/screens/AccountCenterScreen.tsx +13 -7
  185. package/src/ui/screens/AccountOverviewScreen.tsx +3 -3
  186. package/src/ui/screens/AccountSettingsScreen.tsx +65 -13
  187. package/src/ui/screens/AccountSwitcherScreen.tsx +4 -4
  188. package/src/ui/screens/FeedbackScreen.tsx +57 -80
  189. package/src/ui/screens/FileManagementScreen.tsx +278 -175
  190. package/src/ui/screens/LanguageSelectorScreen.tsx +322 -0
  191. package/src/ui/screens/ProfileScreen.tsx +6 -1
  192. package/src/ui/screens/SessionManagementScreen.tsx +148 -151
  193. package/src/ui/screens/SignInScreen.tsx +43 -62
  194. package/src/ui/screens/SignUpScreen.tsx +3 -5
  195. package/src/ui/screens/WelcomeNewUserScreen.tsx +272 -0
  196. package/src/ui/screens/internal/SignInPasswordStep.tsx +28 -13
  197. package/src/ui/screens/internal/SignInUsernameStep.tsx +21 -11
  198. package/src/ui/screens/karma/KarmaCenterScreen.tsx +1 -1
  199. package/src/ui/styles/authStyles.ts +1 -1
@@ -0,0 +1,272 @@
1
+ import React, { useCallback, useMemo, useRef, useState } from 'react';
2
+ import { View, Text, TouchableOpacity, StyleSheet, Platform, Animated, ScrollView } from 'react-native';
3
+ import type { BaseScreenProps } from '../navigation/types';
4
+ import { useOxy } from '../context/OxyContext';
5
+ import Avatar from '../components/Avatar';
6
+ import { Ionicons } from '@expo/vector-icons';
7
+ import { toast } from '../../lib/sonner';
8
+ import { useAuthStore } from '../stores/authStore';
9
+ import { useThemeColors } from '../styles';
10
+ import GroupedPillButtons from '../components/internal/GroupedPillButtons';
11
+
12
+ /**
13
+ * Post-signup welcome & onboarding screen.
14
+ * - Greets the newly registered user
15
+ * - Lets them immediately set / change their avatar using existing FileManagement picker
16
+ * - Only when the user presses "Continue" do we invoke onAuthenticated to finish flow & close sheet
17
+ */
18
+ const WelcomeNewUserScreen: React.FC<BaseScreenProps & { newUser?: any }> = ({
19
+ navigate,
20
+ onAuthenticated,
21
+ theme,
22
+ newUser,
23
+ }) => {
24
+ const { user, oxyServices } = useOxy();
25
+ const updateUser = useAuthStore(s => s.updateUser);
26
+ const currentUser = user || newUser; // fallback
27
+ const colors = useThemeColors(theme);
28
+ const styles = useMemo(() => createStyles(theme), [theme]);
29
+
30
+ // Animation state
31
+ const fadeAnim = useRef(new Animated.Value(1)).current;
32
+ const slideAnim = useRef(new Animated.Value(0)).current;
33
+ const [currentStep, setCurrentStep] = useState(0);
34
+
35
+ const avatarUri = currentUser?.avatar ? oxyServices.getFileDownloadUrl(currentUser.avatar as string, 'thumb') : undefined;
36
+
37
+ // Steps content
38
+ const steps: Array<{ key: string; title: string; bullets?: string[]; body?: string; showAvatar?: boolean; }> = [
39
+ { key: 'welcome', title: `Welcome${currentUser?.username ? `, ${currentUser.username}` : ''} 👋`, body: 'You just created an account in a calm, ethical space. A few quick things — then you\'re in.' },
40
+ { key: 'account', title: 'One Account. Simple.', bullets: ['One identity across everything', 'No re‑signing in all the time', 'Your preferences stay with you'] },
41
+ { key: 'principles', title: 'What We Stand For', bullets: ['Privacy by default', 'No manipulative feeds', 'You decide what to share', 'No selling your data'] },
42
+ { key: 'karma', title: 'Karma = Trust & Growth', body: 'Oxy Karma is a points system that reacts to what you do. Helpful, respectful, constructive actions earn it. Harmful or low‑effort stuff chips it away. More karma can unlock benefits; low karma can limit features. It keeps things fair and rewards real contribution.' },
43
+ { key: 'avatar', title: 'Make It Yours', body: 'Add an avatar so people recognize you. It will show anywhere you show up here. Skip if you want — you can add it later.', showAvatar: true },
44
+ { key: 'ready', title: 'You\'re Ready', body: 'Explore. Contribute. Earn karma. Stay in control.' }
45
+ ];
46
+ const totalSteps = steps.length;
47
+ const avatarStepIndex = steps.findIndex(s => s.showAvatar);
48
+
49
+ const animateToStep = (next: number) => {
50
+ Animated.timing(fadeAnim, { toValue: 0, duration: 180, useNativeDriver: Platform.OS !== 'web' }).start(() => {
51
+ setCurrentStep(next);
52
+ slideAnim.setValue(-40);
53
+ Animated.parallel([
54
+ Animated.timing(fadeAnim, { toValue: 1, duration: 220, useNativeDriver: Platform.OS !== 'web' }),
55
+ Animated.spring(slideAnim, { toValue: 0, useNativeDriver: Platform.OS !== 'web', friction: 9 })
56
+ ]).start();
57
+ });
58
+ };
59
+
60
+ const nextStep = useCallback(() => { if (currentStep < totalSteps - 1) animateToStep(currentStep + 1); }, [currentStep, totalSteps]);
61
+ const prevStep = useCallback(() => { if (currentStep > 0) animateToStep(currentStep - 1); }, [currentStep]);
62
+ const skipToAvatar = useCallback(() => { if (avatarStepIndex >= 0) animateToStep(avatarStepIndex); }, [avatarStepIndex]);
63
+ const finish = useCallback(() => { if (onAuthenticated && currentUser) onAuthenticated(currentUser); }, [onAuthenticated, currentUser]);
64
+ const openAvatarPicker = useCallback(() => {
65
+ navigate('FileManagement', {
66
+ selectMode: true,
67
+ multiSelect: false,
68
+ disabledMimeTypes: ['video/', 'audio/', 'application/pdf'],
69
+ afterSelect: 'back',
70
+ onSelect: async (file: any) => {
71
+ if (!file.contentType.startsWith('image/')) { toast.error('Please select an image file'); return; }
72
+ try { await updateUser({ avatar: file.id }, oxyServices); toast.success('Avatar updated'); } catch (e: any) { toast.error(e.message || 'Failed to update avatar'); }
73
+ }
74
+ });
75
+ }, [navigate, updateUser, oxyServices]);
76
+
77
+ const step = steps[currentStep];
78
+ const pillButtons = useMemo(() => {
79
+ if (currentStep === totalSteps - 1) {
80
+ return [
81
+ { text: 'Back', onPress: prevStep, icon: 'arrow-back', variant: 'transparent' },
82
+ { text: 'Enter', onPress: finish, icon: 'log-in-outline', variant: 'primary' },
83
+ ];
84
+ }
85
+ if (currentStep === 0) {
86
+ const arr: any[] = [];
87
+ if (avatarStepIndex > 0) arr.push({ text: 'Skip', onPress: skipToAvatar, icon: 'play-skip-forward', variant: 'transparent' });
88
+ arr.push({ text: 'Next', onPress: nextStep, icon: 'arrow-forward', variant: 'primary' });
89
+ return arr;
90
+ }
91
+ if (step.showAvatar) {
92
+ return [
93
+ { text: 'Back', onPress: prevStep, icon: 'arrow-back', variant: 'transparent' },
94
+ { text: avatarUri ? 'Continue' : 'Skip', onPress: nextStep, icon: 'arrow-forward', variant: 'primary' },
95
+ ];
96
+ }
97
+ return [
98
+ { text: 'Back', onPress: prevStep, icon: 'arrow-back', variant: 'transparent' },
99
+ { text: 'Next', onPress: nextStep, icon: 'arrow-forward', variant: 'primary' },
100
+ ];
101
+ }, [currentStep, totalSteps, prevStep, nextStep, finish, skipToAvatar, avatarStepIndex, step.showAvatar, avatarUri]);
102
+
103
+ return (
104
+ <View style={styles.container}>
105
+ <View style={styles.progressContainer}>
106
+ {steps.map((s, i) => (
107
+ <View key={s.key} style={[styles.progressDot, i === currentStep ? { backgroundColor: colors.primary, width: 22 } : { backgroundColor: colors.border }]} />
108
+ ))}
109
+ </View>
110
+ <Animated.View style={{ opacity: fadeAnim, transform: [{ translateX: slideAnim }] }}>
111
+ <ScrollView contentContainerStyle={styles.scrollInner} showsVerticalScrollIndicator={false}>
112
+ <Text style={styles.title}>{step.title}</Text>
113
+ {step.body && <Text style={styles.body}>{step.body}</Text>}
114
+ {Array.isArray(step.bullets) && step.bullets.length > 0 && (
115
+ <View style={styles.bulletContainer}>
116
+ {step.bullets.map(b => (
117
+ <View key={b} style={styles.bulletRow}>
118
+ <Ionicons name="ellipse" size={8} color={colors.primary} style={{ marginTop: 6 }} />
119
+ <Text style={styles.bulletText}>{b}</Text>
120
+ </View>
121
+ ))}
122
+ </View>
123
+ )}
124
+ {step.showAvatar && (
125
+ <View style={styles.avatarSection}>
126
+ <Avatar size={120} name={currentUser?.username} uri={avatarUri} theme={theme} style={styles.avatar} />
127
+ <TouchableOpacity style={styles.changeAvatarButton} onPress={openAvatarPicker}>
128
+ <Ionicons name="image-outline" size={18} color="#FFFFFF" />
129
+ <Text style={styles.changeAvatarText}>{avatarUri ? 'Change Avatar' : 'Add Avatar'}</Text>
130
+ </TouchableOpacity>
131
+ </View>
132
+ )}
133
+ <GroupedPillButtons buttons={pillButtons} colors={colors} />
134
+ </ScrollView>
135
+ </Animated.View>
136
+ </View>
137
+ );
138
+
139
+ };
140
+
141
+ const createStyles = (theme: string) => {
142
+ const isDark = theme === 'dark';
143
+ const textColor = isDark ? '#FFFFFF' : '#000000';
144
+ const secondary = isDark ? '#CCCCCC' : '#555555';
145
+ const cardBg = isDark ? '#1E1E1E' : '#FFFFFF';
146
+ const border = isDark ? '#333333' : '#E0E0E0';
147
+ const primary = '#007AFF';
148
+ return StyleSheet.create({
149
+ container: {
150
+ width: '100%',
151
+ paddingHorizontal: 20,
152
+ },
153
+ scrollInner: {
154
+ paddingBottom: 12,
155
+ },
156
+ title: {
157
+ fontSize: 42,
158
+ fontFamily: Platform.OS === 'web' ? 'Phudu' : 'Phudu-Bold',
159
+ fontWeight: Platform.OS === 'web' ? 'bold' : undefined,
160
+ letterSpacing: -1,
161
+ color: textColor,
162
+ marginBottom: 12,
163
+ },
164
+ body: {
165
+ fontSize: 16,
166
+ lineHeight: 22,
167
+ color: secondary,
168
+ marginBottom: 28,
169
+ maxWidth: 620,
170
+ },
171
+ bulletContainer: {
172
+ gap: 10,
173
+ marginBottom: 32,
174
+ },
175
+ bulletRow: {
176
+ flexDirection: 'row',
177
+ alignItems: 'flex-start',
178
+ gap: 10,
179
+ },
180
+ bulletText: {
181
+ flex: 1,
182
+ fontSize: 15,
183
+ lineHeight: 20,
184
+ color: secondary,
185
+ },
186
+ avatarSection: {
187
+ width: '100%',
188
+ alignItems: 'center',
189
+ marginBottom: 40,
190
+ },
191
+ avatar: {
192
+ marginBottom: 16,
193
+ borderWidth: 4,
194
+ borderColor: primary + '40',
195
+ },
196
+ changeAvatarButton: {
197
+ flexDirection: 'row',
198
+ alignItems: 'center',
199
+ backgroundColor: primary,
200
+ paddingHorizontal: 18,
201
+ paddingVertical: 10,
202
+ borderRadius: 35,
203
+ gap: 8,
204
+ },
205
+ changeAvatarText: {
206
+ color: '#FFFFFF',
207
+ fontSize: 15,
208
+ fontWeight: '600',
209
+ },
210
+ progressContainer: {
211
+ flexDirection: 'row',
212
+ width: '100%',
213
+ justifyContent: 'center',
214
+ marginBottom: 24,
215
+ marginTop: 4,
216
+ },
217
+ progressDot: {
218
+ height: 10,
219
+ width: 10,
220
+ borderRadius: 5,
221
+ marginHorizontal: 6,
222
+ backgroundColor: border,
223
+ },
224
+ navBar: {
225
+ flexDirection: 'row',
226
+ alignItems: 'center',
227
+ width: '100%',
228
+ gap: 12,
229
+ marginTop: 8,
230
+ },
231
+ navButton: {
232
+ flexDirection: 'row',
233
+ alignItems: 'center',
234
+ gap: 6,
235
+ paddingHorizontal: 14,
236
+ paddingVertical: 10,
237
+ borderRadius: 12,
238
+ },
239
+ backButton: {
240
+ backgroundColor: cardBg,
241
+ borderWidth: 1,
242
+ borderColor: border,
243
+ },
244
+ skipButton: {
245
+ marginLeft: 'auto',
246
+ backgroundColor: 'transparent',
247
+ paddingHorizontal: 4,
248
+ },
249
+ navText: {
250
+ fontSize: 14,
251
+ fontWeight: '500',
252
+ },
253
+ primaryButton: {
254
+ flexDirection: 'row',
255
+ alignItems: 'center',
256
+ justifyContent: 'center',
257
+ gap: 8,
258
+ backgroundColor: primary,
259
+ paddingVertical: 18,
260
+ borderRadius: 16,
261
+ width: '100%',
262
+ },
263
+ primaryButtonText: {
264
+ color: '#FFFFFF',
265
+ fontSize: 16,
266
+ fontWeight: '600',
267
+ letterSpacing: 0.5,
268
+ },
269
+ });
270
+ };
271
+
272
+ export default WelcomeNewUserScreen;
@@ -1,6 +1,10 @@
1
1
  import type React from 'react';
2
2
  import { useRef, useCallback, useEffect } from 'react';
3
- import { View, Text, Animated, TouchableOpacity, type TextInput, StatusBar } from 'react-native';
3
+ import { View, Text, TouchableOpacity, type TextInput, StatusBar } from 'react-native';
4
+ import Animated, {
5
+ useAnimatedStyle,
6
+ SharedValue,
7
+ } from 'react-native-reanimated';
4
8
  import { Ionicons } from '@expo/vector-icons';
5
9
  import Avatar from '../../components/Avatar';
6
10
  import GroupedPillButtons from '../../components/internal/GroupedPillButtons';
@@ -8,14 +12,14 @@ import TextField from '../../components/internal/TextField';
8
12
 
9
13
  interface SignInPasswordStepProps {
10
14
  styles: any;
11
- fadeAnim: Animated.Value;
12
- slideAnim: Animated.Value;
13
- scaleAnim: Animated.Value;
15
+ fadeAnim: SharedValue<number>;
16
+ slideAnim: SharedValue<number>;
17
+ scaleAnim: SharedValue<number>;
14
18
  colors: any;
15
19
  userProfile: any;
16
20
  username: string;
17
21
  theme: string;
18
- logoAnim: Animated.Value;
22
+ logoAnim: SharedValue<number>;
19
23
  errorMessage: string;
20
24
  isInputFocused: boolean;
21
25
  password: string;
@@ -53,6 +57,23 @@ const SignInPasswordStep: React.FC<SignInPasswordStepProps> = ({
53
57
  }) => {
54
58
  const inputRef = useRef<TextInput>(null);
55
59
 
60
+ // Animated styles
61
+ const containerAnimatedStyle = useAnimatedStyle(() => {
62
+ return {
63
+ opacity: fadeAnim.value,
64
+ transform: [
65
+ { translateX: slideAnim.value },
66
+ { scale: scaleAnim.value }
67
+ ]
68
+ };
69
+ }, [fadeAnim, slideAnim, scaleAnim]);
70
+
71
+ const logoAnimatedStyle = useAnimatedStyle(() => {
72
+ return {
73
+ transform: [{ scale: logoAnim.value }]
74
+ };
75
+ }, [logoAnim]);
76
+
56
77
  // Focus password input on error or when step becomes active
57
78
  useEffect(() => {
58
79
  if (errorMessage) {
@@ -74,18 +95,12 @@ const SignInPasswordStep: React.FC<SignInPasswordStepProps> = ({
74
95
  return (
75
96
  <Animated.View style={[
76
97
  styles.stepContainer,
77
- {
78
- opacity: fadeAnim,
79
- transform: [
80
- { translateX: slideAnim },
81
- { scale: scaleAnim }
82
- ]
83
- }
98
+ containerAnimatedStyle
84
99
  ]}>
85
100
  <View style={styles.modernUserProfileContainer}>
86
101
  <Animated.View style={[
87
102
  styles.avatarContainer,
88
- { transform: [{ scale: logoAnim }] }
103
+ logoAnimatedStyle
89
104
  ]}>
90
105
  <Avatar
91
106
  name={userProfile?.displayName || userProfile?.name || username}
@@ -1,6 +1,10 @@
1
1
  import type React from 'react';
2
2
  import { useRef } from 'react';
3
- import { type TextInput, View, Text, Animated } from 'react-native';
3
+ import { type TextInput, View, Text } from 'react-native';
4
+ import Animated, {
5
+ useAnimatedStyle,
6
+ SharedValue,
7
+ } from 'react-native-reanimated';
4
8
  import { Ionicons } from '@expo/vector-icons';
5
9
  import HighFive from '../../../assets/illustrations/HighFive';
6
10
  import GroupedPillButtons from '../../components/internal/GroupedPillButtons';
@@ -8,9 +12,9 @@ import TextField from '../../components/internal/TextField';
8
12
 
9
13
  interface SignInUsernameStepProps {
10
14
  styles: any;
11
- fadeAnim: Animated.Value;
12
- slideAnim: Animated.Value;
13
- scaleAnim: Animated.Value;
15
+ fadeAnim: SharedValue<number>;
16
+ slideAnim: SharedValue<number>;
17
+ scaleAnim: SharedValue<number>;
14
18
  colors: any;
15
19
  isAddAccountMode: boolean;
16
20
  user: any;
@@ -48,6 +52,18 @@ const SignInUsernameStep: React.FC<SignInUsernameStepProps> = ({
48
52
  navigate,
49
53
  }) => {
50
54
  const inputRef = useRef<TextInput>(null);
55
+
56
+ // Animated styles
57
+ const animatedStyle = useAnimatedStyle(() => {
58
+ return {
59
+ opacity: fadeAnim.value,
60
+ transform: [
61
+ { translateX: slideAnim.value },
62
+ { scale: scaleAnim.value }
63
+ ]
64
+ };
65
+ }, [fadeAnim, slideAnim, scaleAnim]);
66
+
51
67
  const handleUsernameContinue = () => {
52
68
  if (!username || validationStatus === 'invalid') {
53
69
  setTimeout(() => {
@@ -59,13 +75,7 @@ const SignInUsernameStep: React.FC<SignInUsernameStepProps> = ({
59
75
  return (
60
76
  <Animated.View style={[
61
77
  styles.stepContainer,
62
- {
63
- opacity: fadeAnim,
64
- transform: [
65
- { translateX: slideAnim },
66
- { scale: scaleAnim }
67
- ]
68
- }
78
+ animatedStyle
69
79
  ]}>
70
80
  <HighFive width={100} height={100} />
71
81
  <View style={styles.modernHeader}>
@@ -73,7 +73,7 @@ const KarmaCenterScreen: React.FC<BaseScreenProps> = ({
73
73
  <ScrollView style={styles.scrollView} contentContainerStyle={styles.scrollContainer}>
74
74
  <View style={styles.walletHeader}>
75
75
  <Avatar
76
- uri={user?.avatar?.url}
76
+ uri={user?.avatar ? oxyServices.getFileDownloadUrl(user.avatar as string, 'thumb') : undefined}
77
77
  name={user?.username}
78
78
  size={60}
79
79
  theme={theme}
@@ -260,7 +260,7 @@ export const createAuthStyles = (colors: AuthThemeColors, theme: string) => Styl
260
260
  fontWeight: Platform.OS === 'web' ? 'bold' : undefined,
261
261
  fontSize: 42,
262
262
  marginBottom: 4,
263
- textAlign: 'center',
263
+ textAlign: 'left',
264
264
  letterSpacing: -0.5,
265
265
  },
266
266
  modernUsernameSubtext: {