@oxyhq/services 5.13.0 → 5.13.1

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 (204) hide show
  1. package/lib/commonjs/core/OxyServices.js +7 -7
  2. package/lib/commonjs/core/OxyServices.js.map +1 -1
  3. package/lib/commonjs/i18n/index.js +37 -1
  4. package/lib/commonjs/i18n/index.js.map +1 -1
  5. package/lib/commonjs/i18n/locales/ar-SA.json +128 -0
  6. package/lib/commonjs/i18n/locales/ca-ES.json +128 -0
  7. package/lib/commonjs/i18n/locales/de-DE.json +128 -0
  8. package/lib/commonjs/i18n/locales/en-US.json +85 -12
  9. package/lib/commonjs/i18n/locales/es-ES.json +58 -6
  10. package/lib/commonjs/i18n/locales/fr-FR.json +128 -0
  11. package/lib/commonjs/i18n/locales/it-IT.json +128 -0
  12. package/lib/commonjs/i18n/locales/ja-JP.json +127 -0
  13. package/lib/commonjs/i18n/locales/ko-KR.json +128 -0
  14. package/lib/commonjs/i18n/locales/pt-PT.json +128 -0
  15. package/lib/commonjs/i18n/locales/zh-CN.json +128 -0
  16. package/lib/commonjs/ui/components/FontLoader.js +22 -42
  17. package/lib/commonjs/ui/components/FontLoader.js.map +1 -1
  18. package/lib/commonjs/ui/components/OxyProvider.js +5 -8
  19. package/lib/commonjs/ui/components/OxyProvider.js.map +1 -1
  20. package/lib/commonjs/ui/components/StepBasedScreen.js +64 -44
  21. package/lib/commonjs/ui/components/StepBasedScreen.js.map +1 -1
  22. package/lib/commonjs/ui/components/internal/GroupedPillButtons.js +14 -35
  23. package/lib/commonjs/ui/components/internal/GroupedPillButtons.js.map +1 -1
  24. package/lib/commonjs/ui/components/internal/PinInput.js +2 -2
  25. package/lib/commonjs/ui/components/internal/PinInput.js.map +1 -1
  26. package/lib/commonjs/ui/context/OxyContext.js +434 -321
  27. package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
  28. package/lib/commonjs/ui/screens/FileManagementScreen.js.map +1 -1
  29. package/lib/commonjs/ui/screens/SignInScreen.js +43 -39
  30. package/lib/commonjs/ui/screens/SignInScreen.js.map +1 -1
  31. package/lib/commonjs/ui/screens/WelcomeNewUserScreen.js +139 -125
  32. package/lib/commonjs/ui/screens/WelcomeNewUserScreen.js.map +1 -1
  33. package/lib/commonjs/ui/screens/internal/SignInUsernameStep.js +2 -4
  34. package/lib/commonjs/ui/screens/internal/SignInUsernameStep.js.map +1 -1
  35. package/lib/commonjs/ui/screens/steps/RecoverRequestStep.js +45 -25
  36. package/lib/commonjs/ui/screens/steps/RecoverRequestStep.js.map +1 -1
  37. package/lib/commonjs/ui/screens/steps/RecoverResetPasswordStep.js +88 -53
  38. package/lib/commonjs/ui/screens/steps/RecoverResetPasswordStep.js.map +1 -1
  39. package/lib/commonjs/ui/screens/steps/RecoverSuccessStep.js +79 -58
  40. package/lib/commonjs/ui/screens/steps/RecoverSuccessStep.js.map +1 -1
  41. package/lib/commonjs/ui/screens/steps/RecoverVerifyStep.js +61 -52
  42. package/lib/commonjs/ui/screens/steps/RecoverVerifyStep.js.map +1 -1
  43. package/lib/commonjs/ui/screens/steps/SignInPasswordStep.js +220 -31
  44. package/lib/commonjs/ui/screens/steps/SignInPasswordStep.js.map +1 -1
  45. package/lib/commonjs/ui/screens/steps/SignInTotpStep.js +77 -50
  46. package/lib/commonjs/ui/screens/steps/SignInTotpStep.js.map +1 -1
  47. package/lib/commonjs/ui/screens/steps/SignInUsernameStep.js +527 -66
  48. package/lib/commonjs/ui/screens/steps/SignInUsernameStep.js.map +1 -1
  49. package/lib/commonjs/ui/screens/steps/SignUpIdentityStep.js +55 -30
  50. package/lib/commonjs/ui/screens/steps/SignUpIdentityStep.js.map +1 -1
  51. package/lib/commonjs/ui/screens/steps/SignUpSecurityStep.js +64 -46
  52. package/lib/commonjs/ui/screens/steps/SignUpSecurityStep.js.map +1 -1
  53. package/lib/commonjs/ui/screens/steps/SignUpSummaryStep.js +84 -146
  54. package/lib/commonjs/ui/screens/steps/SignUpSummaryStep.js.map +1 -1
  55. package/lib/commonjs/ui/screens/steps/SignUpWelcomeStep.js +113 -34
  56. package/lib/commonjs/ui/screens/steps/SignUpWelcomeStep.js.map +1 -1
  57. package/lib/commonjs/ui/stores/authStore.js +16 -20
  58. package/lib/commonjs/ui/stores/authStore.js.map +1 -1
  59. package/lib/commonjs/ui/styles/authStyles.js +2 -1
  60. package/lib/commonjs/ui/styles/authStyles.js.map +1 -1
  61. package/lib/commonjs/ui/styles/index.js +11 -0
  62. package/lib/commonjs/ui/styles/index.js.map +1 -1
  63. package/lib/commonjs/ui/styles/spacing.js +51 -0
  64. package/lib/commonjs/ui/styles/spacing.js.map +1 -0
  65. package/lib/commonjs/utils/validationUtils.js +1 -1
  66. package/lib/module/core/OxyServices.js +7 -7
  67. package/lib/module/core/OxyServices.js.map +1 -1
  68. package/lib/module/i18n/index.js +37 -1
  69. package/lib/module/i18n/index.js.map +1 -1
  70. package/lib/module/i18n/locales/ar-SA.json +128 -0
  71. package/lib/module/i18n/locales/ca-ES.json +128 -0
  72. package/lib/module/i18n/locales/de-DE.json +128 -0
  73. package/lib/module/i18n/locales/en-US.json +85 -12
  74. package/lib/module/i18n/locales/es-ES.json +58 -6
  75. package/lib/module/i18n/locales/fr-FR.json +128 -0
  76. package/lib/module/i18n/locales/it-IT.json +128 -0
  77. package/lib/module/i18n/locales/ja-JP.json +127 -0
  78. package/lib/module/i18n/locales/ko-KR.json +128 -0
  79. package/lib/module/i18n/locales/pt-PT.json +128 -0
  80. package/lib/module/i18n/locales/zh-CN.json +128 -0
  81. package/lib/module/ui/components/FontLoader.js +23 -43
  82. package/lib/module/ui/components/FontLoader.js.map +1 -1
  83. package/lib/module/ui/components/OxyProvider.js +6 -8
  84. package/lib/module/ui/components/OxyProvider.js.map +1 -1
  85. package/lib/module/ui/components/StepBasedScreen.js +65 -45
  86. package/lib/module/ui/components/StepBasedScreen.js.map +1 -1
  87. package/lib/module/ui/components/internal/GroupedPillButtons.js +14 -35
  88. package/lib/module/ui/components/internal/GroupedPillButtons.js.map +1 -1
  89. package/lib/module/ui/components/internal/PinInput.js +2 -2
  90. package/lib/module/ui/components/internal/PinInput.js.map +1 -1
  91. package/lib/module/ui/context/OxyContext.js +434 -321
  92. package/lib/module/ui/context/OxyContext.js.map +1 -1
  93. package/lib/module/ui/screens/FileManagementScreen.js.map +1 -1
  94. package/lib/module/ui/screens/SignInScreen.js +44 -40
  95. package/lib/module/ui/screens/SignInScreen.js.map +1 -1
  96. package/lib/module/ui/screens/WelcomeNewUserScreen.js +138 -126
  97. package/lib/module/ui/screens/WelcomeNewUserScreen.js.map +1 -1
  98. package/lib/module/ui/screens/internal/SignInUsernameStep.js +2 -4
  99. package/lib/module/ui/screens/internal/SignInUsernameStep.js.map +1 -1
  100. package/lib/module/ui/screens/steps/RecoverRequestStep.js +45 -25
  101. package/lib/module/ui/screens/steps/RecoverRequestStep.js.map +1 -1
  102. package/lib/module/ui/screens/steps/RecoverResetPasswordStep.js +89 -54
  103. package/lib/module/ui/screens/steps/RecoverResetPasswordStep.js.map +1 -1
  104. package/lib/module/ui/screens/steps/RecoverSuccessStep.js +80 -59
  105. package/lib/module/ui/screens/steps/RecoverSuccessStep.js.map +1 -1
  106. package/lib/module/ui/screens/steps/RecoverVerifyStep.js +62 -53
  107. package/lib/module/ui/screens/steps/RecoverVerifyStep.js.map +1 -1
  108. package/lib/module/ui/screens/steps/SignInPasswordStep.js +221 -32
  109. package/lib/module/ui/screens/steps/SignInPasswordStep.js.map +1 -1
  110. package/lib/module/ui/screens/steps/SignInTotpStep.js +78 -51
  111. package/lib/module/ui/screens/steps/SignInTotpStep.js.map +1 -1
  112. package/lib/module/ui/screens/steps/SignInUsernameStep.js +530 -68
  113. package/lib/module/ui/screens/steps/SignInUsernameStep.js.map +1 -1
  114. package/lib/module/ui/screens/steps/SignUpIdentityStep.js +55 -30
  115. package/lib/module/ui/screens/steps/SignUpIdentityStep.js.map +1 -1
  116. package/lib/module/ui/screens/steps/SignUpSecurityStep.js +65 -47
  117. package/lib/module/ui/screens/steps/SignUpSecurityStep.js.map +1 -1
  118. package/lib/module/ui/screens/steps/SignUpSummaryStep.js +84 -146
  119. package/lib/module/ui/screens/steps/SignUpSummaryStep.js.map +1 -1
  120. package/lib/module/ui/screens/steps/SignUpWelcomeStep.js +114 -35
  121. package/lib/module/ui/screens/steps/SignUpWelcomeStep.js.map +1 -1
  122. package/lib/module/ui/stores/authStore.js +16 -20
  123. package/lib/module/ui/stores/authStore.js.map +1 -1
  124. package/lib/module/ui/styles/authStyles.js +2 -1
  125. package/lib/module/ui/styles/authStyles.js.map +1 -1
  126. package/lib/module/ui/styles/index.js +1 -0
  127. package/lib/module/ui/styles/index.js.map +1 -1
  128. package/lib/module/ui/styles/spacing.js +48 -0
  129. package/lib/module/ui/styles/spacing.js.map +1 -0
  130. package/lib/module/utils/validationUtils.js +1 -1
  131. package/lib/typescript/core/OxyServices.d.ts +4 -2
  132. package/lib/typescript/core/OxyServices.d.ts.map +1 -1
  133. package/lib/typescript/i18n/index.d.ts.map +1 -1
  134. package/lib/typescript/ui/components/FontLoader.d.ts +3 -3
  135. package/lib/typescript/ui/components/FontLoader.d.ts.map +1 -1
  136. package/lib/typescript/ui/components/OxyProvider.d.ts +2 -2
  137. package/lib/typescript/ui/components/OxyProvider.d.ts.map +1 -1
  138. package/lib/typescript/ui/components/StepBasedScreen.d.ts.map +1 -1
  139. package/lib/typescript/ui/components/internal/GroupedPillButtons.d.ts.map +1 -1
  140. package/lib/typescript/ui/context/OxyContext.d.ts +1 -0
  141. package/lib/typescript/ui/context/OxyContext.d.ts.map +1 -1
  142. package/lib/typescript/ui/screens/SignInScreen.d.ts.map +1 -1
  143. package/lib/typescript/ui/screens/WelcomeNewUserScreen.d.ts.map +1 -1
  144. package/lib/typescript/ui/screens/steps/RecoverRequestStep.d.ts.map +1 -1
  145. package/lib/typescript/ui/screens/steps/RecoverResetPasswordStep.d.ts.map +1 -1
  146. package/lib/typescript/ui/screens/steps/RecoverSuccessStep.d.ts.map +1 -1
  147. package/lib/typescript/ui/screens/steps/RecoverVerifyStep.d.ts.map +1 -1
  148. package/lib/typescript/ui/screens/steps/SignInPasswordStep.d.ts +2 -0
  149. package/lib/typescript/ui/screens/steps/SignInPasswordStep.d.ts.map +1 -1
  150. package/lib/typescript/ui/screens/steps/SignInTotpStep.d.ts.map +1 -1
  151. package/lib/typescript/ui/screens/steps/SignInUsernameStep.d.ts.map +1 -1
  152. package/lib/typescript/ui/screens/steps/SignUpIdentityStep.d.ts.map +1 -1
  153. package/lib/typescript/ui/screens/steps/SignUpSecurityStep.d.ts.map +1 -1
  154. package/lib/typescript/ui/screens/steps/SignUpSummaryStep.d.ts.map +1 -1
  155. package/lib/typescript/ui/screens/steps/SignUpWelcomeStep.d.ts.map +1 -1
  156. package/lib/typescript/ui/stores/authStore.d.ts +7 -3
  157. package/lib/typescript/ui/stores/authStore.d.ts.map +1 -1
  158. package/lib/typescript/ui/styles/authStyles.d.ts +1 -0
  159. package/lib/typescript/ui/styles/authStyles.d.ts.map +1 -1
  160. package/lib/typescript/ui/styles/index.d.ts +1 -0
  161. package/lib/typescript/ui/styles/index.d.ts.map +1 -1
  162. package/lib/typescript/ui/styles/spacing.d.ts +43 -0
  163. package/lib/typescript/ui/styles/spacing.d.ts.map +1 -0
  164. package/lib/typescript/utils/validationUtils.d.ts +1 -1
  165. package/package.json +1 -1
  166. package/src/core/OxyServices.ts +10 -8
  167. package/src/i18n/index.ts +36 -0
  168. package/src/i18n/locales/ar-SA.json +128 -0
  169. package/src/i18n/locales/ca-ES.json +128 -0
  170. package/src/i18n/locales/de-DE.json +128 -0
  171. package/src/i18n/locales/en-US.json +85 -12
  172. package/src/i18n/locales/es-ES.json +58 -6
  173. package/src/i18n/locales/fr-FR.json +128 -0
  174. package/src/i18n/locales/it-IT.json +128 -0
  175. package/src/i18n/locales/ja-JP.json +127 -0
  176. package/src/i18n/locales/ko-KR.json +128 -0
  177. package/src/i18n/locales/pt-PT.json +128 -0
  178. package/src/i18n/locales/zh-CN.json +128 -0
  179. package/src/ui/components/FontLoader.tsx +17 -37
  180. package/src/ui/components/OxyProvider.tsx +14 -13
  181. package/src/ui/components/StepBasedScreen.tsx +66 -43
  182. package/src/ui/components/internal/GroupedPillButtons.tsx +15 -31
  183. package/src/ui/components/internal/PinInput.tsx +2 -2
  184. package/src/ui/context/OxyContext.tsx +404 -285
  185. package/src/ui/screens/FileManagementScreen.tsx +15 -15
  186. package/src/ui/screens/SignInScreen.tsx +59 -36
  187. package/src/ui/screens/WelcomeNewUserScreen.tsx +102 -91
  188. package/src/ui/screens/internal/SignInUsernameStep.tsx +1 -1
  189. package/src/ui/screens/steps/RecoverRequestStep.tsx +34 -24
  190. package/src/ui/screens/steps/RecoverResetPasswordStep.tsx +65 -36
  191. package/src/ui/screens/steps/RecoverSuccessStep.tsx +71 -47
  192. package/src/ui/screens/steps/RecoverVerifyStep.tsx +60 -50
  193. package/src/ui/screens/steps/SignInPasswordStep.tsx +191 -29
  194. package/src/ui/screens/steps/SignInTotpStep.tsx +68 -34
  195. package/src/ui/screens/steps/SignInUsernameStep.tsx +586 -57
  196. package/src/ui/screens/steps/SignUpIdentityStep.tsx +49 -35
  197. package/src/ui/screens/steps/SignUpSecurityStep.tsx +56 -39
  198. package/src/ui/screens/steps/SignUpSummaryStep.tsx +99 -89
  199. package/src/ui/screens/steps/SignUpWelcomeStep.tsx +88 -20
  200. package/src/ui/stores/authStore.ts +15 -19
  201. package/src/ui/styles/authStyles.ts +2 -1
  202. package/src/ui/styles/index.ts +1 -0
  203. package/src/ui/styles/spacing.ts +46 -0
  204. package/src/utils/validationUtils.ts +1 -1
@@ -1,11 +1,12 @@
1
1
  import type React from 'react';
2
2
  import { useRef, useEffect } from 'react';
3
- import { View, Text, TouchableOpacity } from 'react-native';
3
+ import { View, Text, TouchableOpacity, Platform, StyleSheet, type ViewStyle, type TextStyle } from 'react-native';
4
4
  import { Ionicons } from '@expo/vector-icons';
5
5
  import Avatar from '../../components/Avatar';
6
6
  import GroupedPillButtons from '../../components/internal/GroupedPillButtons';
7
7
  import TextField from '../../components/internal/TextField';
8
8
  import { useI18n } from '../../hooks/useI18n';
9
+ import { STEP_GAP, STEP_INNER_GAP, stepStyles } from '../../styles/spacing';
9
10
 
10
11
  interface SignInPasswordStepProps {
11
12
  // Common props from StepBasedScreen
@@ -41,6 +42,8 @@ interface SignInPasswordStepProps {
41
42
  // Sign-in function
42
43
  handleSignIn: () => Promise<void>;
43
44
  mfaToken?: string | null;
45
+ existingSession?: any;
46
+ handleContinueWithExistingAccount?: () => Promise<void>;
44
47
  }
45
48
 
46
49
  const SignInPasswordStep: React.FC<SignInPasswordStepProps> = ({
@@ -61,9 +64,13 @@ const SignInPasswordStep: React.FC<SignInPasswordStepProps> = ({
61
64
  username,
62
65
  handleSignIn,
63
66
  mfaToken,
67
+ existingSession,
68
+ handleContinueWithExistingAccount,
64
69
  }) => {
65
70
  const inputRef = useRef<any>(null);
66
71
  const { t } = useI18n();
72
+ const baseStyles = stepStyles;
73
+ const webShadowReset = Platform.OS === 'web' ? ({ boxShadow: 'none' } as any) : null;
67
74
 
68
75
  const handlePasswordChange = (text: string) => {
69
76
  setPassword(text);
@@ -72,7 +79,7 @@ const SignInPasswordStep: React.FC<SignInPasswordStepProps> = ({
72
79
 
73
80
  const handleSignInSubmit = async () => {
74
81
  if (!password) {
75
- setErrorMessage('Please enter your password.');
82
+ setErrorMessage(t('signin.password.required') || 'Please enter your password.');
76
83
  setTimeout(() => inputRef.current?.focus(), 0);
77
84
  return;
78
85
  }
@@ -102,10 +109,84 @@ const SignInPasswordStep: React.FC<SignInPasswordStepProps> = ({
102
109
  }
103
110
  }, [mfaToken, nextStep]);
104
111
 
112
+ // If account is already signed in, show "continue" UI instead of password
113
+ if (existingSession && handleContinueWithExistingAccount) {
114
+ return (
115
+ <>
116
+ <View style={[baseStyles.container, baseStyles.sectionSpacing, stylesheet.userProfileContainer]}>
117
+ <View style={stylesheet.avatarContainer}>
118
+ <Avatar
119
+ name={userProfile?.displayName || userProfile?.name || username}
120
+ size={100}
121
+ theme={theme as 'light' | 'dark'}
122
+ style={styles.modernUserAvatar}
123
+ backgroundColor={colors.primary + '20'}
124
+ />
125
+ <View style={[styles.statusIndicator, { backgroundColor: colors.primary }]} />
126
+ </View>
127
+ <Text style={[styles.modernUserDisplayName, stylesheet.displayName, { color: colors.text, marginBottom: 0, marginTop: 0 }]}>
128
+ {userProfile?.displayName || userProfile?.name || username}
129
+ </Text>
130
+ <Text style={[styles.modernUsernameSubtext, stylesheet.usernameSubtext, { color: colors.secondaryText, marginBottom: 0, marginTop: 0 }]}>
131
+ @{username}
132
+ </Text>
133
+ </View>
134
+
135
+ <View style={[baseStyles.container, baseStyles.sectionSpacing, stylesheet.alreadySignedInContainer]}>
136
+ <View style={[stylesheet.alreadySignedInCard, { backgroundColor: `${colors.primary}08`, borderColor: `${colors.primary}25` }]}>
137
+ <View style={stylesheet.alreadySignedInContent}>
138
+ <View style={[stylesheet.alreadySignedInIconWrapper, { backgroundColor: `${colors.primary}20` }]}>
139
+ <Ionicons name="checkmark-circle" size={28} color={colors.primary} />
140
+ </View>
141
+ <View style={stylesheet.alreadySignedInTextWrapper}>
142
+ <Text style={[stylesheet.alreadySignedInTitle, { color: colors.text }]}>
143
+ {t('signin.alreadySignedIn') || 'Already signed in'}
144
+ </Text>
145
+ <Text style={[stylesheet.alreadySignedInMessage, { color: colors.secondaryText }]}>
146
+ {t('signin.alreadySignedInMessage') || 'This account is already signed in. Tap continue to use it.'}
147
+ </Text>
148
+ </View>
149
+ </View>
150
+ </View>
151
+ </View>
152
+
153
+ {errorMessage && (
154
+ <View style={[baseStyles.container, baseStyles.sectionSpacing]}>
155
+ <Text style={[stylesheet.errorText, { color: colors.error }]}>
156
+ {errorMessage}
157
+ </Text>
158
+ </View>
159
+ )}
160
+
161
+ <View style={[baseStyles.container, baseStyles.sectionSpacing, baseStyles.buttonContainer]}>
162
+ <GroupedPillButtons
163
+ buttons={[
164
+ {
165
+ text: t('common.actions.back') || 'Back',
166
+ onPress: prevStep,
167
+ icon: 'arrow-back',
168
+ variant: 'transparent',
169
+ },
170
+ {
171
+ text: t('signin.continueWithAccount') || 'Continue',
172
+ onPress: handleContinueWithExistingAccount,
173
+ icon: 'log-in',
174
+ variant: 'primary',
175
+ loading: isLoading,
176
+ testID: 'continue-button',
177
+ },
178
+ ]}
179
+ colors={colors}
180
+ />
181
+ </View>
182
+ </>
183
+ );
184
+ }
185
+
105
186
  return (
106
187
  <>
107
- <View style={styles.modernUserProfileContainer}>
108
- <View style={styles.avatarContainer}>
188
+ <View style={[baseStyles.container, baseStyles.sectionSpacing, stylesheet.userProfileContainer]}>
189
+ <View style={stylesheet.avatarContainer}>
109
190
  <Avatar
110
191
  name={userProfile?.displayName || userProfile?.name || username}
111
192
  size={100}
@@ -115,15 +196,15 @@ const SignInPasswordStep: React.FC<SignInPasswordStepProps> = ({
115
196
  />
116
197
  <View style={[styles.statusIndicator, { backgroundColor: colors.primary }]} />
117
198
  </View>
118
- <Text style={[styles.modernUserDisplayName, { color: colors.text }]}>
199
+ <Text style={[styles.modernUserDisplayName, stylesheet.displayName, { color: colors.text, marginBottom: 0, marginTop: 0 }]}>
119
200
  {userProfile?.displayName || userProfile?.name || username}
120
201
  </Text>
121
- <Text style={[styles.modernUsernameSubtext, { color: colors.secondaryText }]}>
202
+ <Text style={[styles.modernUsernameSubtext, stylesheet.usernameSubtext, { color: colors.secondaryText, marginBottom: 0, marginTop: 0 }]}>
122
203
  @{username}
123
204
  </Text>
124
205
  </View>
125
206
 
126
- <View style={styles.modernInputContainer}>
207
+ <View style={[baseStyles.container, baseStyles.sectionSpacing, stylesheet.inputSection]}>
127
208
  <TextField
128
209
  ref={inputRef}
129
210
  label={t('common.labels.password')}
@@ -138,9 +219,12 @@ const SignInPasswordStep: React.FC<SignInPasswordStepProps> = ({
138
219
  error={errorMessage || undefined}
139
220
  onSubmitEditing={handleSignInSubmit}
140
221
  autoFocus
222
+ accessibilityLabel={t('common.labels.password')}
223
+ accessibilityHint={t('signin.password.hint') || 'Enter your password to sign in'}
224
+ style={{ marginBottom: 0 }}
141
225
  />
142
226
 
143
- <View style={{ flexDirection: 'row', alignItems: 'center', marginBottom: 16 }}>
227
+ <View style={[stylesheet.forgotPasswordContainer]}>
144
228
  <Text style={[styles.footerText, { color: colors.text }]}>{t('signin.forgotPrompt') || 'Forgot your password?'} </Text>
145
229
  <TouchableOpacity onPress={() => navigate('RecoverAccount', {
146
230
  returnTo: 'SignIn',
@@ -152,27 +236,29 @@ const SignInPasswordStep: React.FC<SignInPasswordStepProps> = ({
152
236
  </View>
153
237
  </View>
154
238
 
155
- <GroupedPillButtons
156
- buttons={[
157
- {
158
- text: t('common.actions.back') || 'Back',
159
- onPress: prevStep,
160
- icon: 'arrow-back',
161
- variant: 'transparent',
162
- },
163
- {
164
- text: t('common.actions.signIn') || 'Sign In',
165
- onPress: handleSignInSubmit,
166
- icon: 'log-in',
167
- variant: 'primary',
168
- loading: isLoading,
169
- testID: 'login-button',
170
- },
171
- ]}
172
- colors={colors}
173
- />
174
-
175
- <View style={styles.securityNotice}>
239
+ <View style={[baseStyles.container, baseStyles.sectionSpacing, baseStyles.buttonContainer]}>
240
+ <GroupedPillButtons
241
+ buttons={[
242
+ {
243
+ text: t('common.actions.back') || 'Back',
244
+ onPress: prevStep,
245
+ icon: 'arrow-back',
246
+ variant: 'transparent',
247
+ },
248
+ {
249
+ text: t('common.actions.signIn') || 'Sign In',
250
+ onPress: handleSignInSubmit,
251
+ icon: 'log-in',
252
+ variant: 'primary',
253
+ loading: isLoading,
254
+ testID: 'login-button',
255
+ },
256
+ ]}
257
+ colors={colors}
258
+ />
259
+ </View>
260
+
261
+ <View style={[baseStyles.container, baseStyles.sectionSpacing, stylesheet.securityNotice, { marginTop: 0 }]}>
176
262
  <Ionicons name="shield-checkmark" size={14} color={colors.secondaryText} />
177
263
  <Text style={[styles.securityText, { color: colors.secondaryText }]}>
178
264
  {t('signin.security.dataSecure') || 'Your data is encrypted and secure'}
@@ -183,3 +269,79 @@ const SignInPasswordStep: React.FC<SignInPasswordStepProps> = ({
183
269
  };
184
270
 
185
271
  export default SignInPasswordStep;
272
+
273
+ const stylesheet = StyleSheet.create({
274
+ userProfileContainer: {
275
+ alignItems: 'flex-start',
276
+ paddingVertical: 0,
277
+ gap: STEP_INNER_GAP,
278
+ },
279
+ avatarContainer: {
280
+ position: 'relative',
281
+ marginBottom: 0,
282
+ marginTop: 0,
283
+ },
284
+ displayName: {
285
+ marginBottom: 0,
286
+ marginTop: 0,
287
+ },
288
+ usernameSubtext: {
289
+ marginBottom: 0,
290
+ marginTop: 0,
291
+ },
292
+ inputSection: {
293
+ gap: STEP_INNER_GAP,
294
+ },
295
+ forgotPasswordContainer: {
296
+ flexDirection: 'row',
297
+ alignItems: 'center',
298
+ marginTop: 0,
299
+ },
300
+ securityNotice: {
301
+ flexDirection: 'row',
302
+ alignItems: 'center',
303
+ gap: STEP_INNER_GAP,
304
+ },
305
+ alreadySignedInContainer: {
306
+ width: '100%',
307
+ },
308
+ alreadySignedInCard: {
309
+ borderRadius: 20,
310
+ borderWidth: 1.5,
311
+ padding: 20,
312
+ width: '100%',
313
+ },
314
+ alreadySignedInContent: {
315
+ flexDirection: 'row',
316
+ alignItems: 'flex-start',
317
+ gap: 16,
318
+ },
319
+ alreadySignedInIconWrapper: {
320
+ width: 52,
321
+ height: 52,
322
+ borderRadius: 26,
323
+ alignItems: 'center',
324
+ justifyContent: 'center',
325
+ flexShrink: 0,
326
+ },
327
+ alreadySignedInTextWrapper: {
328
+ flex: 1,
329
+ gap: 8,
330
+ paddingTop: 2,
331
+ },
332
+ alreadySignedInTitle: {
333
+ fontSize: 18,
334
+ fontWeight: '600',
335
+ lineHeight: 24,
336
+ letterSpacing: -0.2,
337
+ },
338
+ alreadySignedInMessage: {
339
+ fontSize: 15,
340
+ lineHeight: 22,
341
+ letterSpacing: -0.1,
342
+ },
343
+ errorText: {
344
+ fontSize: 14,
345
+ textAlign: 'center',
346
+ },
347
+ });
@@ -1,11 +1,12 @@
1
1
  import type React from 'react';
2
2
  import type { RouteName } from '../../navigation/routes';
3
3
  import { useRef, useState } from 'react';
4
- import { View, Text, TouchableOpacity } from 'react-native';
4
+ import { View, Text, TouchableOpacity, Platform, StyleSheet, type ViewStyle, type TextStyle } from 'react-native';
5
5
  import { Ionicons } from '@expo/vector-icons';
6
6
  import GroupedPillButtons from '../../components/internal/GroupedPillButtons';
7
7
  import PinInput, { type PinInputHandle } from '../../components/internal/PinInput';
8
8
  import { useI18n } from '../../hooks/useI18n';
9
+ import { STEP_GAP, STEP_INNER_GAP, stepStyles } from '../../styles/spacing';
9
10
 
10
11
  interface SignInTotpStepProps {
11
12
  // Common props
@@ -47,6 +48,8 @@ const SignInTotpStep: React.FC<SignInTotpStepProps> = ({
47
48
  const [code, setCode] = useState('');
48
49
  const inputRef = useRef<PinInputHandle | null>(null);
49
50
  const { t } = useI18n();
51
+ const baseStyles = stepStyles;
52
+ const webShadowReset = Platform.OS === 'web' ? ({ boxShadow: 'none' } as any) : null;
50
53
 
51
54
  const handleVerify = async () => {
52
55
  if (!code || code.length !== 6) {
@@ -65,36 +68,36 @@ const SignInTotpStep: React.FC<SignInTotpStepProps> = ({
65
68
 
66
69
  return (
67
70
  <>
68
- <View style={styles.modernHeader}>
69
- <Text style={[styles.modernTitle, { color: colors.text }]}>{t('signin.totp.title') || 'Two‑Factor Code'}</Text>
70
- <Text style={[styles.modernSubtitle, { color: colors.secondaryText }]}>
71
+ <View style={[baseStyles.container, baseStyles.sectionSpacing, baseStyles.header]}>
72
+ <Text style={[styles.modernTitle, baseStyles.title, { color: colors.text, marginBottom: 0, marginTop: 0 }]}>{t('signin.totp.title') || 'Two‑Factor Code'}</Text>
73
+ <Text style={[styles.modernSubtitle, baseStyles.subtitle, { color: colors.secondaryText, marginBottom: 0, marginTop: 0 }]}>
71
74
  {t('signin.totp.subtitle', { username }) || `Enter the 6‑digit code from your authenticator app for @${username}`}
72
75
  </Text>
73
76
  </View>
74
77
 
75
- <View style={styles.modernInputContainer}>
76
- <PinInput
77
- ref={inputRef}
78
- value={code}
79
- onChange={setCode}
80
- length={6}
81
- disabled={isLoading}
82
- autoFocus
83
- colors={colors}
84
- />
78
+ <View style={[baseStyles.container, baseStyles.sectionSpacing, stylesheet.inputSection]}>
79
+ <View style={stylesheet.pinInputWrapper}>
80
+ <PinInput
81
+ ref={inputRef}
82
+ value={code}
83
+ onChange={setCode}
84
+ length={6}
85
+ disabled={isLoading}
86
+ autoFocus
87
+ colors={colors}
88
+ />
89
+ </View>
85
90
 
86
91
  {errorMessage ? (
87
- <View style={{
88
- flexDirection: 'row',
89
- alignItems: 'center',
90
- marginTop: 16,
91
- padding: 12,
92
- backgroundColor: colors.error + '10',
93
- borderRadius: 8,
94
- borderWidth: 1,
95
- borderColor: colors.error + '30',
96
- }}>
97
- <Ionicons name="alert-circle" size={20} color={colors.error} style={{ marginRight: 8 }} />
92
+ <View style={[
93
+ stylesheet.errorContainer,
94
+ {
95
+ backgroundColor: colors.error + '10',
96
+ borderColor: colors.error + '30',
97
+ },
98
+ webShadowReset,
99
+ ]}>
100
+ <Ionicons name="alert-circle" size={20} color={colors.error} />
98
101
  <Text style={[styles.footerText, { color: colors.error, fontSize: 14 }]}>
99
102
  {errorMessage}
100
103
  </Text>
@@ -102,17 +105,19 @@ const SignInTotpStep: React.FC<SignInTotpStepProps> = ({
102
105
  ) : null}
103
106
  </View>
104
107
 
105
- <GroupedPillButtons
106
- buttons={[
107
- { text: t('common.actions.back'), onPress: prevStep, icon: 'arrow-back', variant: 'transparent' },
108
- { text: t('signin.actions.verify'), onPress: handleVerify, icon: 'shield-checkmark', variant: 'primary', loading: isLoading, disabled: isLoading || code.length !== 6 },
109
- ]}
110
- colors={colors}
111
- />
108
+ <View style={[baseStyles.container, baseStyles.sectionSpacing, baseStyles.buttonContainer]}>
109
+ <GroupedPillButtons
110
+ buttons={[
111
+ { text: t('common.actions.back'), onPress: prevStep, icon: 'arrow-back', variant: 'transparent' },
112
+ { text: t('signin.actions.verify'), onPress: handleVerify, icon: 'shield-checkmark', variant: 'primary', loading: isLoading, disabled: isLoading || code.length !== 6 },
113
+ ]}
114
+ colors={colors}
115
+ />
116
+ </View>
112
117
 
113
- <View style={{ marginTop: 12, alignItems: 'center' }}>
118
+ <View style={[baseStyles.container, baseStyles.sectionSpacing, stylesheet.footerContainer]}>
114
119
  <Text style={[styles.footerText, { color: colors.secondaryText }]}>{t('signin.totp.noAccess') || 'No access to your authenticator?'}</Text>
115
- <View style={{ flexDirection: 'row', gap: 12, marginTop: 6 }}>
120
+ <View style={stylesheet.footerLinks}>
116
121
  <TouchableOpacity onPress={() => navigate('RecoverAccount', { prefillUsername: username })}>
117
122
  <Text style={[styles.linkText, { color: colors.primary }]}>{t('signin.totp.useBackupCode') || 'Use backup code'}</Text>
118
123
  </TouchableOpacity>
@@ -127,3 +132,32 @@ const SignInTotpStep: React.FC<SignInTotpStepProps> = ({
127
132
  };
128
133
 
129
134
  export default SignInTotpStep;
135
+
136
+ const stylesheet = StyleSheet.create({
137
+ inputSection: {
138
+ gap: STEP_INNER_GAP,
139
+ },
140
+ pinInputWrapper: {
141
+ marginBottom: 0,
142
+ marginTop: 0,
143
+ },
144
+ errorContainer: {
145
+ flexDirection: 'row',
146
+ alignItems: 'center',
147
+ marginTop: 0,
148
+ padding: STEP_INNER_GAP,
149
+ borderRadius: 8,
150
+ borderWidth: 1,
151
+ shadowColor: 'transparent',
152
+ gap: STEP_INNER_GAP,
153
+ },
154
+ footerContainer: {
155
+ alignItems: 'center',
156
+ gap: STEP_INNER_GAP,
157
+ },
158
+ footerLinks: {
159
+ flexDirection: 'row',
160
+ gap: STEP_INNER_GAP,
161
+ marginTop: 0,
162
+ },
163
+ });