NeoScan_Physician/app/modules/Auth/components/signup/NameStep.tsx
2025-08-20 20:42:33 +05:30

399 lines
11 KiB
TypeScript

/*
* File: NameStep.tsx
* Description: Name step component for signup flow
* Design & Developed by Tech4Biz Solutions
* Copyright (c) Spurrin Innovations. All rights reserved.
*/
import React, { useState } from 'react';
import {
View,
Text,
TextInput,
TouchableOpacity,
StyleSheet,
KeyboardAvoidingView,
Platform,
ScrollView,
} from 'react-native';
import { theme } from '../../../../theme/theme';
import { NameStepProps } from '../../types/signup';
import Icon from 'react-native-vector-icons/Feather';
// ============================================================================
// NAME STEP COMPONENT
// ============================================================================
/**
* NameStep Component
*
* Purpose: Third step of signup flow - personal information
*
* Features:
* - First name, last name, and username inputs
* - Real-time validation with error handling
* - Continue button with loading state
* - Back navigation with modern header
*/
const NameStep: React.FC<NameStepProps> = ({
onContinue,
onBack,
data,
isLoading,
}) => {
// ============================================================================
// STATE MANAGEMENT
// ============================================================================
const [firstName, setFirstName] = useState(data.first_name || '');
const [lastName, setLastName] = useState(data.last_name || '');
const [username, setUsername] = useState(data.username || '');
const [errors, setErrors] = useState({
firstName: '',
lastName: '',
username: '',
});
// ============================================================================
// VALIDATION FUNCTIONS
// ============================================================================
/**
* Validate Input Fields
*
* Purpose: Check if all fields are valid
*/
const validateFields = (): boolean => {
const newErrors = {
firstName: '',
lastName: '',
username: '',
};
if (!firstName.trim()) {
newErrors.firstName = 'First name is required';
}
if (!lastName.trim()) {
newErrors.lastName = 'Last name is required';
}
if (!username.trim()) {
newErrors.username = 'Username is required';
} else if (username.length < 3) {
newErrors.username = 'Username must be at least 3 characters';
}
setErrors(newErrors);
return !Object.values(newErrors).some(error => error !== '');
};
/**
* Handle Continue
*
* Purpose: Validate fields and proceed to next step
*/
const handleContinue = () => {
if (validateFields()) {
onContinue(firstName.trim(), lastName.trim(), username.trim());
}
};
// ============================================================================
// RENDER
// ============================================================================
return (
<KeyboardAvoidingView
style={styles.container}
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
>
<ScrollView
style={styles.scrollView}
contentContainerStyle={styles.scrollContent}
keyboardShouldPersistTaps="handled"
showsVerticalScrollIndicator={false}
>
{/* Header */}
<View style={styles.header}>
<TouchableOpacity onPress={onBack} style={styles.backButton}>
<Icon name="arrow-left" size={24} color={theme.colors.textPrimary} />
</TouchableOpacity>
<View style={styles.headerContent}>
<Text style={styles.title}>Create Account</Text>
<Text style={styles.subtitle}>Step 3 of 5</Text>
</View>
<View style={styles.headerSpacer} />
</View>
{/* Content */}
<View style={styles.content}>
<Text style={styles.sectionTitle}>Tell us about yourself</Text>
<Text style={styles.description}>
Please provide your name and choose a username for your account.
</Text>
{/* First Name Input */}
<View style={styles.inputContainer}>
<Text style={styles.inputLabel}>First Name</Text>
<TextInput
style={[
styles.input,
errors.firstName ? styles.inputError : null,
]}
placeholder="Enter your first name"
placeholderTextColor={theme.colors.textMuted}
value={firstName}
onChangeText={(text) => {
setFirstName(text);
setErrors(prev => ({ ...prev, firstName: '' }));
}}
autoCapitalize="words"
autoCorrect={false}
editable={!isLoading}
/>
{errors.firstName ? (
<Text style={styles.errorText}>{errors.firstName}</Text>
) : null}
</View>
{/* Last Name Input */}
<View style={styles.inputContainer}>
<Text style={styles.inputLabel}>Last Name</Text>
<TextInput
style={[
styles.input,
errors.lastName ? styles.inputError : null,
]}
placeholder="Enter your last name"
placeholderTextColor={theme.colors.textMuted}
value={lastName}
onChangeText={(text) => {
setLastName(text);
setErrors(prev => ({ ...prev, lastName: '' }));
}}
autoCapitalize="words"
autoCorrect={false}
editable={!isLoading}
/>
{errors.lastName ? (
<Text style={styles.errorText}>{errors.lastName}</Text>
) : null}
</View>
{/* Username Input */}
<View style={styles.inputContainer}>
<Text style={styles.inputLabel}>Username</Text>
<TextInput
style={[
styles.input,
errors.username ? styles.inputError : null,
]}
placeholder="Choose a username"
placeholderTextColor={theme.colors.textMuted}
value={username}
onChangeText={(text) => {
setUsername(text);
setErrors(prev => ({ ...prev, username: '' }));
}}
autoCapitalize="none"
autoCorrect={false}
editable={!isLoading}
/>
{errors.username ? (
<Text style={styles.errorText}>{errors.username}</Text>
) : null}
</View>
{/* Continue Button */}
<TouchableOpacity
style={[
styles.continueButton,
(!firstName.trim() || !lastName.trim() || !username.trim() || isLoading)
? styles.continueButtonDisabled
: null,
]}
onPress={handleContinue}
disabled={!firstName.trim() || !lastName.trim() || !username.trim() || isLoading}
>
<Text style={[
styles.continueButtonText,
(!firstName.trim() || !lastName.trim() || !username.trim() || isLoading)
? styles.continueButtonTextDisabled
: null,
]}>
{isLoading ? 'Validating...' : 'Continue'}
</Text>
</TouchableOpacity>
</View>
</ScrollView>
</KeyboardAvoidingView>
);
};
// ============================================================================
// STYLES
// ============================================================================
const styles = StyleSheet.create({
// Main container
container: {
flex: 1,
backgroundColor: theme.colors.background,
},
// Scroll view
scrollView: {
flex: 1,
},
// Scroll content
scrollContent: {
flexGrow: 1,
paddingHorizontal: theme.spacing.sm,
},
// Header section
header: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
paddingTop: theme.spacing.xl,
paddingBottom: theme.spacing.lg,
marginBottom: theme.spacing.lg,
},
// Back button
backButton: {
padding: theme.spacing.sm,
borderRadius: theme.borderRadius.medium,
backgroundColor: theme.colors.backgroundAlt,
},
// Header content
headerContent: {
flex: 1,
alignItems: 'center',
},
// Header spacer
headerSpacer: {
width: 40,
},
// Title
title: {
fontSize: theme.typography.fontSize.displaySmall,
fontFamily: theme.typography.fontFamily.bold,
color: theme.colors.textPrimary,
marginBottom: theme.spacing.xs,
},
// Subtitle
subtitle: {
fontSize: theme.typography.fontSize.bodyMedium,
fontFamily: theme.typography.fontFamily.regular,
color: theme.colors.textSecondary,
},
// Content section
content: {
flex: 1,
justifyContent: 'center',
paddingBottom: theme.spacing.xl,
},
// Section title
sectionTitle: {
fontSize: theme.typography.fontSize.displaySmall,
fontFamily: theme.typography.fontFamily.bold,
color: theme.colors.textPrimary,
marginBottom: theme.spacing.sm,
},
// Description
description: {
fontSize: theme.typography.fontSize.bodyMedium,
fontFamily: theme.typography.fontFamily.regular,
color: theme.colors.textSecondary,
marginBottom: theme.spacing.xl,
},
// Input container
inputContainer: {
marginBottom: theme.spacing.xl,
},
// Input label
inputLabel: {
fontSize: theme.typography.fontSize.bodyMedium,
fontFamily: theme.typography.fontFamily.medium,
color: theme.colors.textPrimary,
marginBottom: theme.spacing.sm,
},
// Input field
input: {
borderWidth: 1,
borderColor: theme.colors.border,
borderRadius: theme.borderRadius.medium,
paddingHorizontal: theme.spacing.md,
paddingVertical: theme.spacing.md,
fontSize: theme.typography.fontSize.bodyLarge,
fontFamily: theme.typography.fontFamily.regular,
color: theme.colors.textPrimary,
backgroundColor: theme.colors.background,
},
// Input error state
inputError: {
borderColor: theme.colors.error,
},
// Error text
errorText: {
fontSize: theme.typography.fontSize.bodySmall,
fontFamily: theme.typography.fontFamily.regular,
color: theme.colors.error,
marginTop: theme.spacing.xs,
},
// Continue button
continueButton: {
backgroundColor: theme.colors.primary,
borderRadius: theme.borderRadius.medium,
paddingVertical: theme.spacing.md,
paddingHorizontal: theme.spacing.lg,
alignItems: 'center',
marginBottom: theme.spacing.lg,
...theme.shadows.primary,
},
// Continue button disabled
continueButtonDisabled: {
backgroundColor: theme.colors.border,
opacity: 0.6,
},
// Continue button text
continueButtonText: {
fontSize: theme.typography.fontSize.bodyLarge,
fontFamily: theme.typography.fontFamily.bold,
color: theme.colors.background,
},
// Continue button text disabled
continueButtonTextDisabled: {
color: theme.colors.textMuted,
},
});
export default NameStep;
/*
* End of File: NameStep.tsx
* Design & Developed by Tech4Biz Solutions
* Copyright (c) Spurrin Innovations. All rights reserved.
*/