@oxyhq/services
Version:
Reusable OxyHQ module to handle authentication, user management, karma system, device-based session management and more 🚀
195 lines (190 loc) • 6.61 kB
JavaScript
"use strict";
import { useRef, useEffect, useCallback } from 'react';
import { View, Text } from 'react-native';
import { Ionicons } from '@expo/vector-icons';
import GroupedPillButtons from '../../components/internal/GroupedPillButtons';
import TextField from '../../components/internal/TextField';
import { useI18n } from '../../hooks/useI18n';
import { STEP_INNER_GAP, stepStyles } from '../../styles/spacing';
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
const SignUpIdentityStep = ({
colors,
styles,
navigate,
nextStep,
prevStep,
username,
email,
setUsername,
setEmail,
validationState,
setValidationState,
setErrorMessage,
validateEmail,
validateUsername
}) => {
const usernameRef = useRef(null);
const baseStyles = stepStyles;
const {
t
} = useI18n();
const validationTimeoutRef = useRef(null);
// Debounced username validation
const debouncedValidateUsername = useCallback(usernameToValidate => {
if (validationTimeoutRef.current) {
clearTimeout(validationTimeoutRef.current);
}
validationTimeoutRef.current = setTimeout(async () => {
if (usernameToValidate.trim().length >= 3) {
await validateUsername(usernameToValidate.trim());
}
}, 500);
}, [validateUsername]);
// Cleanup timeout on unmount
useEffect(() => {
return () => {
if (validationTimeoutRef.current) {
clearTimeout(validationTimeoutRef.current);
}
};
}, []);
const handleUsernameChange = text => {
// Text is already filtered by formatValue prop, but ensure it's clean
const filteredText = text.replace(/[^a-zA-Z0-9]/g, '');
setUsername(filteredText);
setErrorMessage('');
// Reset validation state when user types
if (validationState.status !== 'idle') {
setValidationState({
status: 'idle',
message: ''
});
}
// Trigger debounced validation
debouncedValidateUsername(filteredText);
};
const handleEmailChange = text => {
setEmail(text);
setErrorMessage('');
};
const handleNext = async () => {
if (!username.trim()) {
setErrorMessage(t('signup.username.required') || 'Please enter a username');
setTimeout(() => usernameRef.current?.focus(), 0);
return;
}
if (username.trim().length < 3) {
setErrorMessage(t('signup.username.minLength') || 'Username must be at least 3 characters');
setTimeout(() => usernameRef.current?.focus(), 0);
return;
}
if (!email.trim()) {
setErrorMessage(t('signup.email.required') || 'Please enter an email address');
return;
}
if (!validateEmail(email)) {
setErrorMessage(t('signup.email.invalid') || 'Please enter a valid email address');
return;
}
// Validate username availability
const isUsernameValid = await validateUsername(username.trim());
if (!isUsernameValid) {
setTimeout(() => usernameRef.current?.focus(), 0);
return;
}
nextStep();
};
const emailError = email && !validateEmail(email) ? t('signup.email.invalid') || 'Please enter a valid email address' : undefined;
return /*#__PURE__*/_jsxs(_Fragment, {
children: [/*#__PURE__*/_jsxs(View, {
style: [baseStyles.container, baseStyles.sectionSpacing, baseStyles.header],
children: [/*#__PURE__*/_jsx(Text, {
style: [styles.modernTitle, baseStyles.title, {
color: colors.text,
marginBottom: 0,
marginTop: 0
}],
children: t('signup.identity.title')
}), /*#__PURE__*/_jsx(Text, {
style: [styles.modernSubtitle, baseStyles.subtitle, {
color: colors.secondaryText,
marginBottom: 0,
marginTop: 0
}],
children: t('signup.identity.subtitle')
})]
}), /*#__PURE__*/_jsxs(View, {
style: [baseStyles.container, baseStyles.sectionSpacing, {
gap: STEP_INNER_GAP
}],
children: [/*#__PURE__*/_jsx(TextField, {
ref: usernameRef,
label: t('common.labels.username'),
leading: /*#__PURE__*/_jsx(Ionicons, {
name: "person-outline",
size: 24,
color: colors.secondaryText
}),
value: username,
onChangeText: handleUsernameChange,
formatValue: text => text.replace(/[^a-zA-Z0-9]/g, ''),
maxLength: 30,
autoCapitalize: "none",
autoCorrect: false,
testID: "signup-username-input",
variant: "filled",
error: validationState.status === 'invalid' ? validationState.message : undefined,
loading: validationState.status === 'validating',
success: validationState.status === 'valid',
helperText: t('signup.username.helper') || '3-30 characters, letters and numbers only',
onSubmitEditing: handleNext,
autoFocus: true,
style: {
marginBottom: 0
}
}), /*#__PURE__*/_jsx(TextField, {
label: t('common.labels.email'),
leading: /*#__PURE__*/_jsx(Ionicons, {
name: "mail-outline",
size: 24,
color: colors.secondaryText
}),
value: email,
onChangeText: handleEmailChange,
keyboardType: "email-address",
autoCapitalize: "none",
autoCorrect: false,
testID: "signup-email-input",
variant: "filled",
error: emailError,
helperText: t('signup.email.helper') || 'We\'ll never share your email',
onSubmitEditing: handleNext,
accessibilityLabel: t('common.labels.email'),
accessibilityHint: t('signup.email.helper') || 'Enter your email address',
style: {
marginBottom: 0
}
})]
}), /*#__PURE__*/_jsx(View, {
style: [baseStyles.container, baseStyles.sectionSpacing, baseStyles.buttonContainer],
children: /*#__PURE__*/_jsx(GroupedPillButtons, {
buttons: [{
text: t('common.actions.back'),
onPress: prevStep,
icon: 'arrow-back',
variant: 'transparent'
}, {
text: t('common.actions.next'),
onPress: handleNext,
icon: 'arrow-forward',
variant: 'primary',
loading: validationState.status === 'validating',
disabled: !username.trim() || username.trim().length < 3 || !email.trim() || !validateEmail(email) || validationState.status === 'validating' || validationState.status === 'invalid'
}],
colors: colors
})
})]
});
};
export default SignUpIdentityStep;
//# sourceMappingURL=SignUpIdentityStep.js.map