@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
@@ -6,6 +6,7 @@ import { Ionicons } from '@expo/vector-icons';
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 SignUpIdentityStepProps {
11
12
  // Common props from StepBasedScreen
@@ -55,6 +56,7 @@ const SignUpIdentityStep: React.FC<SignUpIdentityStepProps> = ({
55
56
  validateUsername,
56
57
  }) => {
57
58
  const usernameRef = useRef<any>(null);
59
+ const baseStyles = stepStyles;
58
60
  const { t } = useI18n();
59
61
  const validationTimeoutRef = useRef<NodeJS.Timeout | null>(null);
60
62
 
@@ -81,7 +83,9 @@ const SignUpIdentityStep: React.FC<SignUpIdentityStepProps> = ({
81
83
  }, []);
82
84
 
83
85
  const handleUsernameChange = (text: string) => {
84
- setUsername(text);
86
+ // Text is already filtered by formatValue prop, but ensure it's clean
87
+ const filteredText = text.replace(/[^a-zA-Z0-9]/g, '');
88
+ setUsername(filteredText);
85
89
  setErrorMessage('');
86
90
  // Reset validation state when user types
87
91
  if (validationState.status !== 'idle') {
@@ -89,7 +93,7 @@ const SignUpIdentityStep: React.FC<SignUpIdentityStepProps> = ({
89
93
  }
90
94
 
91
95
  // Trigger debounced validation
92
- debouncedValidateUsername(text);
96
+ debouncedValidateUsername(filteredText);
93
97
  };
94
98
 
95
99
  const handleEmailChange = (text: string) => {
@@ -99,24 +103,24 @@ const SignUpIdentityStep: React.FC<SignUpIdentityStepProps> = ({
99
103
 
100
104
  const handleNext = async () => {
101
105
  if (!username.trim()) {
102
- setErrorMessage('Please enter a username');
106
+ setErrorMessage(t('signup.username.required') || 'Please enter a username');
103
107
  setTimeout(() => usernameRef.current?.focus(), 0);
104
108
  return;
105
109
  }
106
110
 
107
111
  if (username.trim().length < 3) {
108
- setErrorMessage('Username must be at least 3 characters');
112
+ setErrorMessage(t('signup.username.minLength') || 'Username must be at least 3 characters');
109
113
  setTimeout(() => usernameRef.current?.focus(), 0);
110
114
  return;
111
115
  }
112
116
 
113
117
  if (!email.trim()) {
114
- setErrorMessage('Please enter an email address');
118
+ setErrorMessage(t('signup.email.required') || 'Please enter an email address');
115
119
  return;
116
120
  }
117
121
 
118
122
  if (!validateEmail(email)) {
119
- setErrorMessage('Please enter a valid email address');
123
+ setErrorMessage(t('signup.email.invalid') || 'Please enter a valid email address');
120
124
  return;
121
125
  }
122
126
 
@@ -130,22 +134,24 @@ const SignUpIdentityStep: React.FC<SignUpIdentityStepProps> = ({
130
134
  nextStep();
131
135
  };
132
136
 
133
- const emailError = email && !validateEmail(email) ? 'Please enter a valid email address' : undefined;
137
+ const emailError = email && !validateEmail(email) ? (t('signup.email.invalid') || 'Please enter a valid email address') : undefined;
134
138
 
135
139
  return (
136
140
  <>
137
- <View style={styles.modernHeader}>
138
- <Text style={[styles.modernTitle, { color: colors.text }]}>{t('signup.identity.title')}</Text>
139
- <Text style={[styles.modernSubtitle, { color: colors.secondaryText }]}>{t('signup.identity.subtitle')}</Text>
141
+ <View style={[baseStyles.container, baseStyles.sectionSpacing, baseStyles.header]}>
142
+ <Text style={[styles.modernTitle, baseStyles.title, { color: colors.text, marginBottom: 0, marginTop: 0 }]}>{t('signup.identity.title')}</Text>
143
+ <Text style={[styles.modernSubtitle, baseStyles.subtitle, { color: colors.secondaryText, marginBottom: 0, marginTop: 0 }]}>{t('signup.identity.subtitle')}</Text>
140
144
  </View>
141
145
 
142
- <View style={styles.modernInputContainer}>
146
+ <View style={[baseStyles.container, baseStyles.sectionSpacing, { gap: STEP_INNER_GAP }]}>
143
147
  <TextField
144
148
  ref={usernameRef}
145
149
  label={t('common.labels.username')}
146
150
  leading={<Ionicons name="person-outline" size={24} color={colors.secondaryText} />}
147
151
  value={username}
148
152
  onChangeText={handleUsernameChange}
153
+ formatValue={(text) => text.replace(/[^a-zA-Z0-9]/g, '')}
154
+ maxLength={30}
149
155
  autoCapitalize="none"
150
156
  autoCorrect={false}
151
157
  testID="signup-username-input"
@@ -153,8 +159,10 @@ const SignUpIdentityStep: React.FC<SignUpIdentityStepProps> = ({
153
159
  error={validationState.status === 'invalid' ? validationState.message : undefined}
154
160
  loading={validationState.status === 'validating'}
155
161
  success={validationState.status === 'valid'}
162
+ helperText={t('signup.username.helper') || '3-30 characters, letters and numbers only'}
156
163
  onSubmitEditing={handleNext}
157
164
  autoFocus
165
+ style={{ marginBottom: 0 }}
158
166
  />
159
167
 
160
168
  <TextField
@@ -168,34 +176,40 @@ const SignUpIdentityStep: React.FC<SignUpIdentityStepProps> = ({
168
176
  testID="signup-email-input"
169
177
  variant="filled"
170
178
  error={emailError}
179
+ helperText={t('signup.email.helper') || 'We\'ll never share your email'}
171
180
  onSubmitEditing={handleNext}
181
+ accessibilityLabel={t('common.labels.email')}
182
+ accessibilityHint={t('signup.email.helper') || 'Enter your email address'}
183
+ style={{ marginBottom: 0 }}
172
184
  />
173
185
  </View>
174
186
 
175
- <GroupedPillButtons
176
- buttons={[
177
- {
178
- text: t('common.actions.back'),
179
- onPress: prevStep,
180
- icon: 'arrow-back',
181
- variant: 'transparent',
182
- },
183
- {
184
- text: t('common.actions.next'),
185
- onPress: handleNext,
186
- icon: 'arrow-forward',
187
- variant: 'primary',
188
- loading: validationState.status === 'validating',
189
- disabled: !username.trim() ||
190
- username.trim().length < 3 ||
191
- !email.trim() ||
192
- !validateEmail(email) ||
193
- validationState.status === 'validating' ||
194
- validationState.status === 'invalid',
195
- },
196
- ]}
197
- colors={colors}
198
- />
187
+ <View style={[baseStyles.container, baseStyles.sectionSpacing, baseStyles.buttonContainer]}>
188
+ <GroupedPillButtons
189
+ buttons={[
190
+ {
191
+ text: t('common.actions.back'),
192
+ onPress: prevStep,
193
+ icon: 'arrow-back',
194
+ variant: 'transparent',
195
+ },
196
+ {
197
+ text: t('common.actions.next'),
198
+ onPress: handleNext,
199
+ icon: 'arrow-forward',
200
+ variant: 'primary',
201
+ loading: validationState.status === 'validating',
202
+ disabled: !username.trim() ||
203
+ username.trim().length < 3 ||
204
+ !email.trim() ||
205
+ !validateEmail(email) ||
206
+ validationState.status === 'validating' ||
207
+ validationState.status === 'invalid',
208
+ },
209
+ ]}
210
+ colors={colors}
211
+ />
212
+ </View>
199
213
  </>
200
214
  );
201
215
  };
@@ -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, StyleSheet } from 'react-native';
5
5
  import { Ionicons } from '@expo/vector-icons';
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 SignUpSecurityStepProps {
11
12
  // Common props from StepBasedScreen
@@ -57,6 +58,7 @@ const SignUpSecurityStep: React.FC<SignUpSecurityStepProps> = ({
57
58
  }) => {
58
59
  const passwordRef = useRef<any>(null);
59
60
  const { t } = useI18n();
61
+ const baseStyles = stepStyles;
60
62
 
61
63
  const handlePasswordChange = (text: string) => {
62
64
  setPassword(text);
@@ -70,40 +72,40 @@ const SignUpSecurityStep: React.FC<SignUpSecurityStepProps> = ({
70
72
 
71
73
  const handleNext = () => {
72
74
  if (!password) {
73
- setErrorMessage('Please enter a password');
75
+ setErrorMessage(t('signup.password.required') || 'Please enter a password');
74
76
  setTimeout(() => passwordRef.current?.focus(), 0);
75
77
  return;
76
78
  }
77
79
 
78
80
  if (!validatePassword(password)) {
79
- setErrorMessage('Password must be at least 8 characters long');
81
+ setErrorMessage(t('signup.password.minLength') || 'Password must be at least 8 characters long');
80
82
  return;
81
83
  }
82
84
 
83
85
  if (!confirmPassword) {
84
- setErrorMessage('Please confirm your password');
86
+ setErrorMessage(t('signup.password.confirmRequired') || 'Please confirm your password');
85
87
  return;
86
88
  }
87
89
 
88
90
  if (password !== confirmPassword) {
89
- setErrorMessage('Passwords do not match');
91
+ setErrorMessage(t('signup.password.mismatch') || 'Passwords do not match');
90
92
  return;
91
93
  }
92
94
 
93
95
  nextStep();
94
96
  };
95
97
 
96
- const passwordError = password && !validatePassword(password) ? 'Password must be at least 8 characters long' : undefined;
97
- const confirmPasswordError = confirmPassword && password !== confirmPassword ? 'Passwords do not match' : undefined;
98
+ const passwordError = password && !validatePassword(password) ? (t('signup.password.minLength') || 'Password must be at least 8 characters long') : undefined;
99
+ const confirmPasswordError = confirmPassword && password !== confirmPassword ? (t('signup.password.mismatch') || 'Passwords do not match') : undefined;
98
100
 
99
101
  return (
100
102
  <>
101
- <View style={styles.modernHeader}>
102
- <Text style={[styles.modernTitle, { color: colors.text }]}>{t('signup.security.title')}</Text>
103
- <Text style={[styles.modernSubtitle, { color: colors.secondaryText }]}>{t('signup.security.subtitle')}</Text>
103
+ <View style={[baseStyles.container, baseStyles.sectionSpacing, baseStyles.header]}>
104
+ <Text style={[styles.modernTitle, baseStyles.title, { color: colors.text, marginBottom: 0, marginTop: 0 }]}>{t('signup.security.title')}</Text>
105
+ <Text style={[styles.modernSubtitle, baseStyles.subtitle, { color: colors.secondaryText, marginBottom: 0, marginTop: 0 }]}>{t('signup.security.subtitle')}</Text>
104
106
  </View>
105
107
 
106
- <View style={styles.modernInputContainer}>
108
+ <View style={[baseStyles.container, baseStyles.sectionSpacing, { gap: STEP_INNER_GAP }]}>
107
109
  <TextField
108
110
  ref={passwordRef}
109
111
  label={t('common.labels.password')}
@@ -111,10 +113,10 @@ const SignUpSecurityStep: React.FC<SignUpSecurityStepProps> = ({
111
113
  trailing={
112
114
  <TouchableOpacity
113
115
  onPress={() => setShowPassword(!showPassword)}
114
- style={{ padding: 4 }}
116
+ style={stylesheet.iconButton}
115
117
  >
116
118
  <Ionicons
117
- name={showPassword ? "eye-off-outline" : "eye-outline"}
119
+ name={showPassword ? 'eye-off-outline' : 'eye-outline'}
118
120
  size={20}
119
121
  color={colors.secondaryText}
120
122
  />
@@ -123,13 +125,18 @@ const SignUpSecurityStep: React.FC<SignUpSecurityStepProps> = ({
123
125
  value={password}
124
126
  onChangeText={handlePasswordChange}
125
127
  secureTextEntry={!showPassword}
128
+ passwordStrength={true}
126
129
  autoCapitalize="none"
127
130
  autoCorrect={false}
128
131
  testID="signup-password-input"
129
132
  variant="filled"
130
133
  error={passwordError}
134
+ helperText={t('signup.password.helper') || 'At least 8 characters'}
131
135
  onSubmitEditing={handleNext}
132
136
  autoFocus
137
+ accessibilityLabel={t('common.labels.password')}
138
+ accessibilityHint={t('signup.password.helper') || 'Enter a password, at least 8 characters long'}
139
+ style={{ marginBottom: 0 }}
133
140
  />
134
141
 
135
142
  <TextField
@@ -138,10 +145,10 @@ const SignUpSecurityStep: React.FC<SignUpSecurityStepProps> = ({
138
145
  trailing={
139
146
  <TouchableOpacity
140
147
  onPress={() => setShowConfirmPassword(!showConfirmPassword)}
141
- style={{ padding: 4 }}
148
+ style={stylesheet.iconButton}
142
149
  >
143
150
  <Ionicons
144
- name={showConfirmPassword ? "eye-off-outline" : "eye-outline"}
151
+ name={showConfirmPassword ? 'eye-off-outline' : 'eye-outline'}
145
152
  size={20}
146
153
  color={colors.secondaryText}
147
154
  />
@@ -155,36 +162,46 @@ const SignUpSecurityStep: React.FC<SignUpSecurityStepProps> = ({
155
162
  testID="signup-confirm-password-input"
156
163
  variant="filled"
157
164
  error={confirmPasswordError}
165
+ helperText={confirmPassword && password !== confirmPassword ? (t('signup.password.mismatch') || 'Passwords do not match') : undefined}
158
166
  onSubmitEditing={handleNext}
167
+ accessibilityLabel={t('common.labels.confirmPassword')}
168
+ accessibilityHint={t('signup.password.confirmHint') || 'Re-enter your password to confirm'}
169
+ style={{ marginBottom: 0 }}
159
170
  />
160
-
161
- <View style={{ marginTop: 16 }}>
162
- <Text style={[styles.footerText, { color: colors.secondaryText, fontSize: 12 }]}>
163
- Password must be at least 8 characters long
164
- </Text>
165
- </View>
166
171
  </View>
167
172
 
168
- <GroupedPillButtons
169
- buttons={[
170
- {
171
- text: t('common.actions.back'),
172
- onPress: prevStep,
173
- icon: 'arrow-back',
174
- variant: 'transparent',
175
- },
176
- {
177
- text: t('common.actions.next'),
178
- onPress: handleNext,
179
- icon: 'arrow-forward',
180
- variant: 'primary',
181
- disabled: !password || !confirmPassword || password !== confirmPassword,
182
- },
183
- ]}
184
- colors={colors}
185
- />
173
+ <View style={[baseStyles.container, baseStyles.sectionSpacing, baseStyles.buttonContainer]}>
174
+ <GroupedPillButtons
175
+ buttons={[
176
+ {
177
+ text: t('common.actions.back'),
178
+ onPress: prevStep,
179
+ icon: 'arrow-back',
180
+ variant: 'transparent',
181
+ },
182
+ {
183
+ text: t('common.actions.next'),
184
+ onPress: handleNext,
185
+ icon: 'arrow-forward',
186
+ variant: 'primary',
187
+ disabled: !password || !confirmPassword || password !== confirmPassword,
188
+ },
189
+ ]}
190
+ colors={colors}
191
+ />
192
+ </View>
186
193
  </>
187
194
  );
188
195
  };
189
196
 
190
197
  export default SignUpSecurityStep;
198
+
199
+ const stylesheet = StyleSheet.create({
200
+ iconButton: {
201
+ padding: 4,
202
+ },
203
+ helperText: {
204
+ fontSize: 12,
205
+ marginTop: 0,
206
+ },
207
+ });
@@ -1,9 +1,10 @@
1
1
  import type React from 'react';
2
2
  import type { RouteName } from '../../navigation/routes';
3
3
  import { View, Text } from 'react-native';
4
- import { Ionicons } from '@expo/vector-icons';
5
4
  import GroupedPillButtons from '../../components/internal/GroupedPillButtons';
5
+ import { Section, GroupedSection } from '../../components';
6
6
  import { useI18n } from '../../hooks/useI18n';
7
+ import { stepStyles } from '../../styles/spacing';
7
8
 
8
9
  interface SignUpSummaryStepProps {
9
10
  // Common props from StepBasedScreen
@@ -28,12 +29,14 @@ interface SignUpSummaryStepProps {
28
29
  const SignUpSummaryStep: React.FC<SignUpSummaryStepProps> = ({
29
30
  colors,
30
31
  styles,
32
+ theme,
31
33
  nextStep,
32
34
  prevStep,
33
35
  allStepData,
34
36
  isLoading,
35
37
  }) => {
36
38
  const { t } = useI18n();
39
+ const baseStyles = stepStyles;
37
40
  // Extract data from previous steps
38
41
  const identityData = allStepData[1] || {}; // Step 2 (index 1)
39
42
  const securityData = allStepData[2] || {}; // Step 3 (index 2)
@@ -44,100 +47,107 @@ const SignUpSummaryStep: React.FC<SignUpSummaryStepProps> = ({
44
47
  // Check if all required data is available
45
48
  const hasValidData = username && email && password;
46
49
 
47
-
48
-
49
50
  return (
50
51
  <>
51
- <View style={styles.modernHeader}>
52
- <Text style={[styles.modernTitle, { color: colors.text }]}>{t('signup.summary.title')}</Text>
53
- <Text style={[styles.modernSubtitle, { color: colors.secondaryText }]}>{t('signup.summary.subtitle')}</Text>
52
+ <View style={[baseStyles.container, baseStyles.sectionSpacing, baseStyles.header]}>
53
+ <Text style={[styles.modernTitle, baseStyles.title, { color: colors.text, marginBottom: 0, marginTop: 0 }]}>
54
+ {t('signup.summary.title')}
55
+ </Text>
56
+ <Text style={[styles.modernSubtitle, baseStyles.subtitle, { color: colors.secondaryText, marginBottom: 0, marginTop: 0 }]}>
57
+ {t('signup.summary.subtitle')}
58
+ </Text>
54
59
  </View>
55
60
 
56
- <View style={[styles.modernInputContainer, { marginBottom: 32 }]}>
57
- <View style={{
58
- backgroundColor: colors.inputBackground,
59
- borderRadius: 16,
60
- padding: 20,
61
- borderWidth: 1,
62
- borderColor: colors.border,
63
- }}>
64
- <View style={{ flexDirection: 'row', alignItems: 'center', marginBottom: 16 }}>
65
- <Ionicons name="person-outline" size={20} color={colors.secondaryText} style={{ marginRight: 12 }} />
66
- <View style={{ flex: 1 }}>
67
- <Text style={[styles.footerText, { color: colors.secondaryText, fontSize: 12, marginBottom: 4 }]}>
68
- Username
69
- </Text>
70
- <Text style={[styles.modernInput, { color: colors.text, fontSize: 16 }]}>
71
- @{username || 'Not set'}
72
- </Text>
73
- </View>
74
- </View>
75
-
76
- <View style={{ flexDirection: 'row', alignItems: 'center' }}>
77
- <Ionicons name="mail-outline" size={20} color={colors.secondaryText} style={{ marginRight: 12 }} />
78
- <View style={{ flex: 1 }}>
79
- <Text style={[styles.footerText, { color: colors.secondaryText, fontSize: 12, marginBottom: 4 }]}>
80
- Email
81
- </Text>
82
- <Text style={[styles.modernInput, { color: colors.text, fontSize: 16 }]}>
83
- {email || 'Not set'}
84
- </Text>
85
- </View>
86
- </View>
87
- </View>
88
-
89
- <View style={{
90
- flexDirection: 'row',
91
- alignItems: 'center',
92
- marginTop: 16,
93
- padding: 12,
94
- backgroundColor: colors.warning + '10',
95
- borderRadius: 8,
96
- borderWidth: 1,
97
- borderColor: colors.warning + '30',
98
- }}>
99
- <Ionicons name="shield-checkmark" size={20} color={colors.warning} style={{ marginRight: 8 }} />
100
- <Text style={[styles.footerText, { color: colors.warning, fontSize: 14, flex: 1 }]}>
101
- For stronger security, we recommend enabling Two‑Factor Authentication (TOTP) from Account Settings after you create your account.
102
- </Text>
103
- </View>
104
-
105
- <View style={{
106
- flexDirection: 'row',
107
- alignItems: 'center',
108
- marginTop: 16,
109
- padding: 12,
110
- backgroundColor: colors.success + '10',
111
- borderRadius: 8,
112
- borderWidth: 1,
113
- borderColor: colors.success + '30',
114
- }}>
115
- <Ionicons name="checkmark-circle" size={20} color={colors.success} style={{ marginRight: 8 }} />
116
- <Text style={[styles.footerText, { color: colors.success, fontSize: 14, flex: 1 }]}>
117
- By creating an account, you agree to our Terms of Service and Privacy Policy
118
- </Text>
119
- </View>
61
+ <View style={[baseStyles.container, baseStyles.sectionSpacing]}>
62
+ <Section
63
+ title={t('signup.summary.sections.account') || t('signup.summary.sectionTitle') || 'Account Information'}
64
+ theme={theme as 'light' | 'dark'}
65
+ isFirst={true}
66
+ >
67
+ <GroupedSection
68
+ items={[
69
+ {
70
+ id: 'username',
71
+ icon: 'person-outline',
72
+ iconColor: colors.primary,
73
+ title: t('signup.summary.fields.username'),
74
+ subtitle: `@${username || t('signup.summary.notSet')}`,
75
+ showChevron: false,
76
+ },
77
+ {
78
+ id: 'email',
79
+ icon: 'mail-outline',
80
+ iconColor: colors.primary,
81
+ title: t('signup.summary.fields.email'),
82
+ subtitle: email || t('signup.summary.notSet'),
83
+ showChevron: false,
84
+ },
85
+ {
86
+ id: 'password',
87
+ icon: 'lock-closed-outline',
88
+ iconColor: colors.primary,
89
+ title: t('signup.summary.fields.password') || 'Password',
90
+ subtitle: password ? '••••••••' : t('signup.summary.notSet'),
91
+ showChevron: false,
92
+ },
93
+ ]}
94
+ theme={theme as 'light' | 'dark'}
95
+ />
96
+ </Section>
97
+
98
+ <Section
99
+ title={t('signup.summary.sections.next') || 'Next Steps'}
100
+ theme={theme as 'light' | 'dark'}
101
+ >
102
+ <GroupedSection
103
+ items={[
104
+ {
105
+ id: 'security-tip',
106
+ icon: 'shield-checkmark',
107
+ iconColor: colors.warning,
108
+ title: t('signup.summary.next.securityTitle') || 'Keep your account secure',
109
+ subtitle: t('signup.summary.securityTip'),
110
+ showChevron: false,
111
+ multiRow: true,
112
+ dense: true,
113
+ },
114
+ {
115
+ id: 'legal-reminder',
116
+ icon: 'checkmark-circle',
117
+ iconColor: colors.success,
118
+ title: t('signup.summary.next.legalTitle') || 'You’re all set',
119
+ subtitle: t('signup.summary.legalReminder'),
120
+ showChevron: false,
121
+ multiRow: true,
122
+ dense: true,
123
+ },
124
+ ]}
125
+ theme={theme as 'light' | 'dark'}
126
+ />
127
+ </Section>
120
128
  </View>
121
129
 
122
- <GroupedPillButtons
123
- buttons={[
124
- {
125
- text: t('common.actions.back'),
126
- onPress: prevStep,
127
- icon: 'arrow-back',
128
- variant: 'transparent',
129
- },
130
- {
131
- text: t('common.actions.createAccount'),
132
- onPress: nextStep,
133
- icon: 'checkmark-circle',
134
- variant: 'primary',
135
- loading: isLoading,
136
- disabled: !hasValidData,
137
- },
138
- ]}
139
- colors={colors}
140
- />
130
+ <View style={[baseStyles.container, baseStyles.sectionSpacing, baseStyles.buttonContainer]}>
131
+ <GroupedPillButtons
132
+ buttons={[
133
+ {
134
+ text: t('common.actions.back'),
135
+ onPress: prevStep,
136
+ icon: 'arrow-back',
137
+ variant: 'transparent',
138
+ },
139
+ {
140
+ text: t('common.actions.createAccount'),
141
+ onPress: nextStep,
142
+ icon: 'checkmark-circle',
143
+ variant: 'primary',
144
+ loading: isLoading,
145
+ disabled: !hasValidData,
146
+ },
147
+ ]}
148
+ colors={colors}
149
+ />
150
+ </View>
141
151
  </>
142
152
  );
143
153
  };