UI Updates and Bug Fixes
This commit is contained in:
@@ -0,0 +1,229 @@
|
||||
import React, { useState } from 'react';
|
||||
import { View, StyleSheet, KeyboardAvoidingView, Platform, ScrollView, TouchableOpacity } from 'react-native';
|
||||
import { NativeStackNavigationProp } from '@react-navigation/native-stack';
|
||||
import { RootStackParamList } from '../navigation/AppNavigator';
|
||||
import { Typography } from '../components/ui/Typography';
|
||||
import { Input } from '../components/ui/Input';
|
||||
import { Button } from '../components/ui/Button';
|
||||
import { authService } from '../services/authService';
|
||||
import AsyncStorage from '@react-native-async-storage/async-storage';
|
||||
import { HeartHandshake } from 'lucide-react-native';
|
||||
|
||||
type LoginScreenNavigationProp = NativeStackNavigationProp<RootStackParamList, 'Login'>;
|
||||
|
||||
interface LoginScreenProps {
|
||||
navigation: LoginScreenNavigationProp;
|
||||
}
|
||||
|
||||
export const LoginScreen: React.FC<LoginScreenProps> = ({ navigation }) => {
|
||||
const [phone, setPhone] = useState('+91');
|
||||
const [otp, setOtp] = useState('');
|
||||
const [step, setStep] = useState<'PHONE' | 'OTP'>('PHONE');
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [error, setError] = useState('');
|
||||
|
||||
const handleLogin = async () => {
|
||||
if (step === 'PHONE') {
|
||||
if (!phone || phone.length < 10) {
|
||||
setError('Please enter a valid phone number');
|
||||
return;
|
||||
}
|
||||
setIsLoading(true);
|
||||
setError('');
|
||||
try {
|
||||
const response = await authService.login(phone);
|
||||
console.log('OTP sent:', response);
|
||||
setStep('OTP');
|
||||
} catch (err: any) {
|
||||
console.error('Login failed:', err);
|
||||
setError('Failed to send OTP. Please check your number and try again.');
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
} else {
|
||||
if (!otp || otp.length < 4) {
|
||||
setError('Please enter a valid OTP');
|
||||
return;
|
||||
}
|
||||
setIsLoading(true);
|
||||
setError('');
|
||||
try {
|
||||
const response = await authService.verifyOtp(phone, otp);
|
||||
console.log('OTP verified successfully:', response);
|
||||
// Save the token
|
||||
if (response.data && response.data.accessToken) {
|
||||
await AsyncStorage.setItem('token', response.data.accessToken);
|
||||
} else if (response.token) {
|
||||
await AsyncStorage.setItem('token', response.token);
|
||||
}
|
||||
navigation.replace('MainTabs');
|
||||
} catch (err: any) {
|
||||
console.error('OTP verification failed:', err);
|
||||
setError('Invalid OTP. Please try again.');
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<KeyboardAvoidingView
|
||||
style={styles.container}
|
||||
behavior={Platform.OS === 'ios' ? 'padding' : undefined}
|
||||
>
|
||||
<ScrollView contentContainerStyle={styles.scrollContent} keyboardShouldPersistTaps="handled">
|
||||
|
||||
<View style={styles.formContainer}>
|
||||
<View style={styles.card}>
|
||||
<View style={styles.logoContainer}>
|
||||
<View style={styles.iconWrapper}>
|
||||
<HeartHandshake color="#4F46E5" size={40} />
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<View style={styles.header}>
|
||||
<Typography variant="h1" weight="bold" style={styles.title}>
|
||||
Caregiver Portal
|
||||
</Typography>
|
||||
<Typography variant="body" style={styles.subtitle}>
|
||||
Sign in to view your schedule, manage patient care, and stay connected.
|
||||
</Typography>
|
||||
</View>
|
||||
|
||||
<View style={styles.form}>
|
||||
{error ? (
|
||||
<Typography variant="caption" style={styles.errorText}>
|
||||
{error}
|
||||
</Typography>
|
||||
) : null}
|
||||
|
||||
{step === 'PHONE' ? (
|
||||
<Input
|
||||
label="Phone Number"
|
||||
labelStyle={{ fontWeight: 'bold', fontSize: 16 }}
|
||||
placeholder="+917540032060"
|
||||
keyboardType="phone-pad"
|
||||
autoCapitalize="none"
|
||||
value={phone}
|
||||
onChangeText={setPhone}
|
||||
/>
|
||||
) : (
|
||||
<Input
|
||||
label="Enter OTP"
|
||||
labelStyle={{ fontWeight: 'bold', fontSize: 16 }}
|
||||
placeholder="e.g. 881433"
|
||||
keyboardType="numeric"
|
||||
autoCapitalize="none"
|
||||
value={otp}
|
||||
onChangeText={setOtp}
|
||||
/>
|
||||
)}
|
||||
|
||||
<Button
|
||||
title={step === 'PHONE' ? "Get OTP" : "Verify & Log In"}
|
||||
onPress={handleLogin}
|
||||
loading={isLoading}
|
||||
style={styles.loginButton}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<View style={styles.footer}>
|
||||
<Typography variant="body" style={styles.footerText}>
|
||||
Don't have an account?{' '}
|
||||
</Typography>
|
||||
<TouchableOpacity>
|
||||
<Typography variant="body" weight="bold" style={styles.signupText}>
|
||||
Sign Up
|
||||
</Typography>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
</ScrollView>
|
||||
</KeyboardAvoidingView>
|
||||
);
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: '#EEF2FF', // Beautiful light indigo background
|
||||
},
|
||||
scrollContent: {
|
||||
flexGrow: 1,
|
||||
paddingHorizontal: 24,
|
||||
justifyContent: 'center',
|
||||
},
|
||||
formContainer: {
|
||||
width: '100%',
|
||||
maxWidth: 480,
|
||||
alignSelf: 'center',
|
||||
paddingVertical: 40,
|
||||
},
|
||||
card: {
|
||||
backgroundColor: '#FFFFFF',
|
||||
borderRadius: 32,
|
||||
padding: 32,
|
||||
shadowColor: '#4F46E5',
|
||||
shadowOffset: { width: 0, height: 12 },
|
||||
shadowOpacity: 0.1,
|
||||
shadowRadius: 32,
|
||||
elevation: 8,
|
||||
borderWidth: 1,
|
||||
borderColor: '#E0E7FF',
|
||||
marginBottom: 32,
|
||||
},
|
||||
logoContainer: {
|
||||
alignItems: 'center',
|
||||
marginBottom: 24,
|
||||
},
|
||||
iconWrapper: {
|
||||
width: 80,
|
||||
height: 80,
|
||||
borderRadius: 40,
|
||||
backgroundColor: '#EEF2FF',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
borderWidth: 2,
|
||||
borderColor: '#C7D2FE',
|
||||
},
|
||||
header: {
|
||||
marginBottom: 32,
|
||||
alignItems: 'center',
|
||||
},
|
||||
title: {
|
||||
marginBottom: 8,
|
||||
color: '#111827',
|
||||
textAlign: 'center',
|
||||
},
|
||||
subtitle: {
|
||||
color: '#6B7280',
|
||||
lineHeight: 24,
|
||||
textAlign: 'center',
|
||||
},
|
||||
form: {
|
||||
marginBottom: 8,
|
||||
},
|
||||
errorText: {
|
||||
color: '#DC2626', // Red
|
||||
marginBottom: 16,
|
||||
textAlign: 'center',
|
||||
},
|
||||
loginButton: {
|
||||
width: '100%',
|
||||
backgroundColor: '#1E3A8A', // Navy blue
|
||||
},
|
||||
footer: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
marginBottom: 40,
|
||||
},
|
||||
footerText: {
|
||||
color: '#6B7280',
|
||||
},
|
||||
signupText: {
|
||||
color: '#1E3A8A', // Navy blue
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user