@oxyhq/services 5.12.11 → 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.
- package/lib/commonjs/core/OxyServices.js +86 -8
- package/lib/commonjs/core/OxyServices.js.map +1 -1
- package/lib/commonjs/i18n/index.js +37 -1
- package/lib/commonjs/i18n/index.js.map +1 -1
- package/lib/commonjs/i18n/locales/ar-SA.json +128 -0
- package/lib/commonjs/i18n/locales/ca-ES.json +128 -0
- package/lib/commonjs/i18n/locales/de-DE.json +128 -0
- package/lib/commonjs/i18n/locales/en-US.json +85 -12
- package/lib/commonjs/i18n/locales/es-ES.json +58 -6
- package/lib/commonjs/i18n/locales/fr-FR.json +128 -0
- package/lib/commonjs/i18n/locales/it-IT.json +128 -0
- package/lib/commonjs/i18n/locales/ja-JP.json +127 -0
- package/lib/commonjs/i18n/locales/ko-KR.json +128 -0
- package/lib/commonjs/i18n/locales/pt-PT.json +128 -0
- package/lib/commonjs/i18n/locales/zh-CN.json +128 -0
- package/lib/commonjs/ui/components/FontLoader.js +22 -42
- package/lib/commonjs/ui/components/FontLoader.js.map +1 -1
- package/lib/commonjs/ui/components/OxyProvider.js +5 -8
- package/lib/commonjs/ui/components/OxyProvider.js.map +1 -1
- package/lib/commonjs/ui/components/StepBasedScreen.js +64 -44
- package/lib/commonjs/ui/components/StepBasedScreen.js.map +1 -1
- package/lib/commonjs/ui/components/internal/GroupedPillButtons.js +14 -35
- package/lib/commonjs/ui/components/internal/GroupedPillButtons.js.map +1 -1
- package/lib/commonjs/ui/components/internal/PinInput.js +2 -2
- package/lib/commonjs/ui/components/internal/PinInput.js.map +1 -1
- package/lib/commonjs/ui/context/OxyContext.js +434 -321
- package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
- package/lib/commonjs/ui/screens/FileManagementScreen.js +56 -5
- package/lib/commonjs/ui/screens/FileManagementScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/SignInScreen.js +43 -39
- package/lib/commonjs/ui/screens/SignInScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/WelcomeNewUserScreen.js +139 -125
- package/lib/commonjs/ui/screens/WelcomeNewUserScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/internal/SignInUsernameStep.js +2 -4
- package/lib/commonjs/ui/screens/internal/SignInUsernameStep.js.map +1 -1
- package/lib/commonjs/ui/screens/steps/RecoverRequestStep.js +45 -25
- package/lib/commonjs/ui/screens/steps/RecoverRequestStep.js.map +1 -1
- package/lib/commonjs/ui/screens/steps/RecoverResetPasswordStep.js +88 -53
- package/lib/commonjs/ui/screens/steps/RecoverResetPasswordStep.js.map +1 -1
- package/lib/commonjs/ui/screens/steps/RecoverSuccessStep.js +79 -58
- package/lib/commonjs/ui/screens/steps/RecoverSuccessStep.js.map +1 -1
- package/lib/commonjs/ui/screens/steps/RecoverVerifyStep.js +61 -52
- package/lib/commonjs/ui/screens/steps/RecoverVerifyStep.js.map +1 -1
- package/lib/commonjs/ui/screens/steps/SignInPasswordStep.js +220 -31
- package/lib/commonjs/ui/screens/steps/SignInPasswordStep.js.map +1 -1
- package/lib/commonjs/ui/screens/steps/SignInTotpStep.js +77 -50
- package/lib/commonjs/ui/screens/steps/SignInTotpStep.js.map +1 -1
- package/lib/commonjs/ui/screens/steps/SignInUsernameStep.js +527 -66
- package/lib/commonjs/ui/screens/steps/SignInUsernameStep.js.map +1 -1
- package/lib/commonjs/ui/screens/steps/SignUpIdentityStep.js +55 -30
- package/lib/commonjs/ui/screens/steps/SignUpIdentityStep.js.map +1 -1
- package/lib/commonjs/ui/screens/steps/SignUpSecurityStep.js +64 -46
- package/lib/commonjs/ui/screens/steps/SignUpSecurityStep.js.map +1 -1
- package/lib/commonjs/ui/screens/steps/SignUpSummaryStep.js +84 -146
- package/lib/commonjs/ui/screens/steps/SignUpSummaryStep.js.map +1 -1
- package/lib/commonjs/ui/screens/steps/SignUpWelcomeStep.js +113 -34
- package/lib/commonjs/ui/screens/steps/SignUpWelcomeStep.js.map +1 -1
- package/lib/commonjs/ui/stores/authStore.js +16 -20
- package/lib/commonjs/ui/stores/authStore.js.map +1 -1
- package/lib/commonjs/ui/styles/authStyles.js +2 -1
- package/lib/commonjs/ui/styles/authStyles.js.map +1 -1
- package/lib/commonjs/ui/styles/index.js +11 -0
- package/lib/commonjs/ui/styles/index.js.map +1 -1
- package/lib/commonjs/ui/styles/spacing.js +51 -0
- package/lib/commonjs/ui/styles/spacing.js.map +1 -0
- package/lib/commonjs/utils/validationUtils.js +1 -1
- package/lib/module/core/OxyServices.js +86 -8
- package/lib/module/core/OxyServices.js.map +1 -1
- package/lib/module/i18n/index.js +37 -1
- package/lib/module/i18n/index.js.map +1 -1
- package/lib/module/i18n/locales/ar-SA.json +128 -0
- package/lib/module/i18n/locales/ca-ES.json +128 -0
- package/lib/module/i18n/locales/de-DE.json +128 -0
- package/lib/module/i18n/locales/en-US.json +85 -12
- package/lib/module/i18n/locales/es-ES.json +58 -6
- package/lib/module/i18n/locales/fr-FR.json +128 -0
- package/lib/module/i18n/locales/it-IT.json +128 -0
- package/lib/module/i18n/locales/ja-JP.json +127 -0
- package/lib/module/i18n/locales/ko-KR.json +128 -0
- package/lib/module/i18n/locales/pt-PT.json +128 -0
- package/lib/module/i18n/locales/zh-CN.json +128 -0
- package/lib/module/ui/components/FontLoader.js +23 -43
- package/lib/module/ui/components/FontLoader.js.map +1 -1
- package/lib/module/ui/components/OxyProvider.js +6 -8
- package/lib/module/ui/components/OxyProvider.js.map +1 -1
- package/lib/module/ui/components/StepBasedScreen.js +65 -45
- package/lib/module/ui/components/StepBasedScreen.js.map +1 -1
- package/lib/module/ui/components/internal/GroupedPillButtons.js +14 -35
- package/lib/module/ui/components/internal/GroupedPillButtons.js.map +1 -1
- package/lib/module/ui/components/internal/PinInput.js +2 -2
- package/lib/module/ui/components/internal/PinInput.js.map +1 -1
- package/lib/module/ui/context/OxyContext.js +434 -321
- package/lib/module/ui/context/OxyContext.js.map +1 -1
- package/lib/module/ui/screens/FileManagementScreen.js +56 -5
- package/lib/module/ui/screens/FileManagementScreen.js.map +1 -1
- package/lib/module/ui/screens/SignInScreen.js +44 -40
- package/lib/module/ui/screens/SignInScreen.js.map +1 -1
- package/lib/module/ui/screens/WelcomeNewUserScreen.js +138 -126
- package/lib/module/ui/screens/WelcomeNewUserScreen.js.map +1 -1
- package/lib/module/ui/screens/internal/SignInUsernameStep.js +2 -4
- package/lib/module/ui/screens/internal/SignInUsernameStep.js.map +1 -1
- package/lib/module/ui/screens/steps/RecoverRequestStep.js +45 -25
- package/lib/module/ui/screens/steps/RecoverRequestStep.js.map +1 -1
- package/lib/module/ui/screens/steps/RecoverResetPasswordStep.js +89 -54
- package/lib/module/ui/screens/steps/RecoverResetPasswordStep.js.map +1 -1
- package/lib/module/ui/screens/steps/RecoverSuccessStep.js +80 -59
- package/lib/module/ui/screens/steps/RecoverSuccessStep.js.map +1 -1
- package/lib/module/ui/screens/steps/RecoverVerifyStep.js +62 -53
- package/lib/module/ui/screens/steps/RecoverVerifyStep.js.map +1 -1
- package/lib/module/ui/screens/steps/SignInPasswordStep.js +221 -32
- package/lib/module/ui/screens/steps/SignInPasswordStep.js.map +1 -1
- package/lib/module/ui/screens/steps/SignInTotpStep.js +78 -51
- package/lib/module/ui/screens/steps/SignInTotpStep.js.map +1 -1
- package/lib/module/ui/screens/steps/SignInUsernameStep.js +530 -68
- package/lib/module/ui/screens/steps/SignInUsernameStep.js.map +1 -1
- package/lib/module/ui/screens/steps/SignUpIdentityStep.js +55 -30
- package/lib/module/ui/screens/steps/SignUpIdentityStep.js.map +1 -1
- package/lib/module/ui/screens/steps/SignUpSecurityStep.js +65 -47
- package/lib/module/ui/screens/steps/SignUpSecurityStep.js.map +1 -1
- package/lib/module/ui/screens/steps/SignUpSummaryStep.js +84 -146
- package/lib/module/ui/screens/steps/SignUpSummaryStep.js.map +1 -1
- package/lib/module/ui/screens/steps/SignUpWelcomeStep.js +114 -35
- package/lib/module/ui/screens/steps/SignUpWelcomeStep.js.map +1 -1
- package/lib/module/ui/stores/authStore.js +16 -20
- package/lib/module/ui/stores/authStore.js.map +1 -1
- package/lib/module/ui/styles/authStyles.js +2 -1
- package/lib/module/ui/styles/authStyles.js.map +1 -1
- package/lib/module/ui/styles/index.js +1 -0
- package/lib/module/ui/styles/index.js.map +1 -1
- package/lib/module/ui/styles/spacing.js +48 -0
- package/lib/module/ui/styles/spacing.js.map +1 -0
- package/lib/module/utils/validationUtils.js +1 -1
- package/lib/typescript/core/OxyServices.d.ts +38 -2
- package/lib/typescript/core/OxyServices.d.ts.map +1 -1
- package/lib/typescript/i18n/index.d.ts.map +1 -1
- package/lib/typescript/ui/components/FontLoader.d.ts +3 -3
- package/lib/typescript/ui/components/FontLoader.d.ts.map +1 -1
- package/lib/typescript/ui/components/OxyProvider.d.ts +2 -2
- package/lib/typescript/ui/components/OxyProvider.d.ts.map +1 -1
- package/lib/typescript/ui/components/StepBasedScreen.d.ts.map +1 -1
- package/lib/typescript/ui/components/internal/GroupedPillButtons.d.ts.map +1 -1
- package/lib/typescript/ui/context/OxyContext.d.ts +1 -0
- package/lib/typescript/ui/context/OxyContext.d.ts.map +1 -1
- package/lib/typescript/ui/screens/FileManagementScreen.d.ts +10 -0
- package/lib/typescript/ui/screens/FileManagementScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/SignInScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/WelcomeNewUserScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/steps/RecoverRequestStep.d.ts.map +1 -1
- package/lib/typescript/ui/screens/steps/RecoverResetPasswordStep.d.ts.map +1 -1
- package/lib/typescript/ui/screens/steps/RecoverSuccessStep.d.ts.map +1 -1
- package/lib/typescript/ui/screens/steps/RecoverVerifyStep.d.ts.map +1 -1
- package/lib/typescript/ui/screens/steps/SignInPasswordStep.d.ts +2 -0
- package/lib/typescript/ui/screens/steps/SignInPasswordStep.d.ts.map +1 -1
- package/lib/typescript/ui/screens/steps/SignInTotpStep.d.ts.map +1 -1
- package/lib/typescript/ui/screens/steps/SignInUsernameStep.d.ts.map +1 -1
- package/lib/typescript/ui/screens/steps/SignUpIdentityStep.d.ts.map +1 -1
- package/lib/typescript/ui/screens/steps/SignUpSecurityStep.d.ts.map +1 -1
- package/lib/typescript/ui/screens/steps/SignUpSummaryStep.d.ts.map +1 -1
- package/lib/typescript/ui/screens/steps/SignUpWelcomeStep.d.ts.map +1 -1
- package/lib/typescript/ui/stores/authStore.d.ts +7 -3
- package/lib/typescript/ui/stores/authStore.d.ts.map +1 -1
- package/lib/typescript/ui/styles/authStyles.d.ts +1 -0
- package/lib/typescript/ui/styles/authStyles.d.ts.map +1 -1
- package/lib/typescript/ui/styles/index.d.ts +1 -0
- package/lib/typescript/ui/styles/index.d.ts.map +1 -1
- package/lib/typescript/ui/styles/spacing.d.ts +43 -0
- package/lib/typescript/ui/styles/spacing.d.ts.map +1 -0
- package/lib/typescript/utils/validationUtils.d.ts +1 -1
- package/package.json +1 -1
- package/src/core/OxyServices.ts +96 -10
- package/src/i18n/index.ts +36 -0
- package/src/i18n/locales/ar-SA.json +128 -0
- package/src/i18n/locales/ca-ES.json +128 -0
- package/src/i18n/locales/de-DE.json +128 -0
- package/src/i18n/locales/en-US.json +85 -12
- package/src/i18n/locales/es-ES.json +58 -6
- package/src/i18n/locales/fr-FR.json +128 -0
- package/src/i18n/locales/it-IT.json +128 -0
- package/src/i18n/locales/ja-JP.json +127 -0
- package/src/i18n/locales/ko-KR.json +128 -0
- package/src/i18n/locales/pt-PT.json +128 -0
- package/src/i18n/locales/zh-CN.json +128 -0
- package/src/ui/components/FontLoader.tsx +17 -37
- package/src/ui/components/OxyProvider.tsx +14 -13
- package/src/ui/components/StepBasedScreen.tsx +66 -43
- package/src/ui/components/internal/GroupedPillButtons.tsx +15 -31
- package/src/ui/components/internal/PinInput.tsx +2 -2
- package/src/ui/context/OxyContext.tsx +404 -285
- package/src/ui/screens/FileManagementScreen.tsx +81 -4
- package/src/ui/screens/SignInScreen.tsx +59 -36
- package/src/ui/screens/WelcomeNewUserScreen.tsx +102 -91
- package/src/ui/screens/internal/SignInUsernameStep.tsx +1 -1
- package/src/ui/screens/steps/RecoverRequestStep.tsx +34 -24
- package/src/ui/screens/steps/RecoverResetPasswordStep.tsx +65 -36
- package/src/ui/screens/steps/RecoverSuccessStep.tsx +71 -47
- package/src/ui/screens/steps/RecoverVerifyStep.tsx +60 -50
- package/src/ui/screens/steps/SignInPasswordStep.tsx +191 -29
- package/src/ui/screens/steps/SignInTotpStep.tsx +68 -34
- package/src/ui/screens/steps/SignInUsernameStep.tsx +586 -57
- package/src/ui/screens/steps/SignUpIdentityStep.tsx +49 -35
- package/src/ui/screens/steps/SignUpSecurityStep.tsx +56 -39
- package/src/ui/screens/steps/SignUpSummaryStep.tsx +99 -89
- package/src/ui/screens/steps/SignUpWelcomeStep.tsx +88 -20
- package/src/ui/stores/authStore.ts +15 -19
- package/src/ui/styles/authStyles.ts +2 -1
- package/src/ui/styles/index.ts +1 -0
- package/src/ui/styles/spacing.ts +46 -0
- 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
|
-
|
|
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(
|
|
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={
|
|
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={
|
|
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
|
-
<
|
|
176
|
-
|
|
177
|
-
{
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
username.trim()
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
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={
|
|
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={
|
|
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={
|
|
116
|
+
style={stylesheet.iconButton}
|
|
115
117
|
>
|
|
116
118
|
<Ionicons
|
|
117
|
-
name={showPassword ?
|
|
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={
|
|
148
|
+
style={stylesheet.iconButton}
|
|
142
149
|
>
|
|
143
150
|
<Ionicons
|
|
144
|
-
name={showConfirmPassword ?
|
|
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
|
-
<
|
|
169
|
-
|
|
170
|
-
{
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
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={
|
|
52
|
-
<Text style={[styles.modernTitle, { color: colors.text }]}>
|
|
53
|
-
|
|
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={[
|
|
57
|
-
<
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
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
|
-
<
|
|
123
|
-
|
|
124
|
-
{
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
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
|
};
|