first commit
This commit is contained in:
@@ -0,0 +1,306 @@
|
||||
import React, { useState } from 'react';
|
||||
import { View, Text, Dimensions, TextInput, TouchableOpacity, StyleSheet, StatusBar, KeyboardAvoidingView, Platform, ScrollView } from 'react-native';
|
||||
import LinearGradient from 'react-native-linear-gradient';
|
||||
import { Formik } from 'formik';
|
||||
import * as Yup from 'yup';
|
||||
import Animated, { FadeInUp, FadeInDown } from 'react-native-reanimated';
|
||||
import { Mail, Lock, Eye, EyeOff, ArrowRight } from 'lucide-react-native';
|
||||
import colors from '../../Constant/Color';
|
||||
import ImagePath from '../../Constant/ImagePath';
|
||||
import { useLogin } from '../../Services/BBPS/Hooks';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { setToken } from '../../Redux/Slices/Token';
|
||||
import { showErrorAlert } from '../../Constant/ShowDailog';
|
||||
import { useNavigation, CommonActions } from '@react-navigation/native';
|
||||
import NavigationString from '../../Constant/NavigationString';
|
||||
import ReactNativeHapticFeedback from "react-native-haptic-feedback";
|
||||
import { Loader } from '../../Component/Index';
|
||||
const hapticOptions = {
|
||||
enableVibrateFallback: true,
|
||||
ignoreAndroidSystemSettings: false
|
||||
};
|
||||
const { height, width } = Dimensions.get('window');
|
||||
|
||||
const LoginSchema = Yup.object().shape({
|
||||
email: Yup.string().email('Invalid email address').required('Email is required'),
|
||||
password: Yup.string().min(6, 'Minimum 6 characters').required('Password is required'),
|
||||
});
|
||||
|
||||
const Login = () => {
|
||||
const Navigation: any = useNavigation()
|
||||
const Dispatch = useDispatch()
|
||||
const [passwordVisible, setPasswordVisible] = React.useState(false);
|
||||
const [loading, setLoading] = useState(false)
|
||||
const { mutate, isPending } = useLogin()
|
||||
|
||||
const HandleLogin = async (values: any) => {
|
||||
setLoading(true)
|
||||
mutate({ password: values.password, emailAdd: values.email }, {
|
||||
onSuccess: (res) => {
|
||||
if (res.statusCode == 200) {
|
||||
Dispatch(setToken({ ...res.data, token: res.token }))
|
||||
Navigation.dispatch(
|
||||
CommonActions.reset({
|
||||
index: 0,
|
||||
routes: [
|
||||
{ name: NavigationString.Home },
|
||||
],
|
||||
})
|
||||
);
|
||||
}
|
||||
setLoading(false)
|
||||
},
|
||||
onError: (err) => {
|
||||
showErrorAlert(err.message)
|
||||
setLoading(false)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<KeyboardAvoidingView
|
||||
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
|
||||
style={{ flex: 1 }}
|
||||
>
|
||||
<ScrollView contentContainerStyle={{ flexGrow: 1 }} bounces={false}>
|
||||
|
||||
{/* Header */}
|
||||
<View style={styles.header}>
|
||||
<LinearGradient
|
||||
colors={[colors.primary, colors.primaryLight || '#4c669f']}
|
||||
style={styles.gradient}
|
||||
>
|
||||
<Animated.Image
|
||||
entering={FadeInDown.delay(200).duration(800)}
|
||||
source={ImagePath.Icon.Logo}
|
||||
resizeMode="contain"
|
||||
style={styles.logo}
|
||||
/>
|
||||
</LinearGradient>
|
||||
</View>
|
||||
|
||||
<Animated.View
|
||||
entering={FadeInUp.springify().damping(15)}
|
||||
style={styles.formContainer}
|
||||
>
|
||||
<View style={styles.sheetHandle} />
|
||||
|
||||
<Text style={styles.title}>Welcome Back</Text>
|
||||
<Text style={styles.subtitle}>Enter your details to access your account</Text>
|
||||
|
||||
<Formik
|
||||
initialValues={{ email: '', password: '' }}
|
||||
validationSchema={LoginSchema}
|
||||
onSubmit={(values) => {
|
||||
HandleLogin(values)
|
||||
}}
|
||||
>
|
||||
{({ handleChange, handleBlur, handleSubmit, values, errors, touched }) => (
|
||||
<View style={{}}>
|
||||
<Text style={styles.label}>Email Address</Text>
|
||||
<View style={[styles.inputWrapper, touched.email && errors.email && styles.inputError]}>
|
||||
<Mail size={20} color={touched.email && !errors.email ? colors.primary : colors.grayText} />
|
||||
<TextInput
|
||||
placeholder="name@example.com"
|
||||
placeholderTextColor="#A0A0A0"
|
||||
style={styles.input}
|
||||
keyboardType="email-address"
|
||||
autoCapitalize="none"
|
||||
onChangeText={handleChange('email')}
|
||||
onBlur={handleBlur('email')}
|
||||
value={values.email}
|
||||
/>
|
||||
</View>
|
||||
{errors.email && touched.email && <Text style={styles.errorText}>{errors.email}</Text>}
|
||||
|
||||
<Text style={[styles.label, { marginTop: 16 }]}>Password</Text>
|
||||
<View style={[styles.inputWrapper, touched.password && errors.password && styles.inputError]}>
|
||||
<Lock size={20} color={touched.password && !errors.password ? colors.primary : colors.grayText} />
|
||||
<TextInput
|
||||
placeholder="••••••••"
|
||||
placeholderTextColor="#A0A0A0"
|
||||
style={styles.input}
|
||||
secureTextEntry={!passwordVisible}
|
||||
onChangeText={handleChange('password')}
|
||||
onBlur={handleBlur('password')}
|
||||
value={values.password}
|
||||
/>
|
||||
<TouchableOpacity onPress={() => setPasswordVisible(!passwordVisible)}>
|
||||
{passwordVisible ? <EyeOff size={20} color={colors.grayText} /> : <Eye size={20} color={colors.grayText} />}
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
{errors.password && touched.password && <Text style={styles.errorText}>{errors.password}</Text>}
|
||||
|
||||
<TouchableOpacity style={styles.forgotPass}>
|
||||
<Text style={styles.forgotPassText}>Forgot Password?</Text>
|
||||
</TouchableOpacity>
|
||||
|
||||
<TouchableOpacity
|
||||
activeOpacity={0.8}
|
||||
onPress={() => {
|
||||
ReactNativeHapticFeedback.trigger("impactLight", hapticOptions);
|
||||
handleSubmit();
|
||||
}}
|
||||
|
||||
style={styles.buttonShadow}
|
||||
>
|
||||
<LinearGradient
|
||||
colors={[colors.primary, colors.primaryLight || '#4c669f']}
|
||||
start={{ x: 0, y: 0 }}
|
||||
end={{ x: 1, y: 0 }}
|
||||
style={styles.button}
|
||||
>
|
||||
{
|
||||
loading ? <Loader color={colors.white} size='small'/> : <>
|
||||
<Text style={styles.buttonText}>Sign In</Text>
|
||||
<ArrowRight size={20} color={colors.white} style={{ marginLeft: 8, marginTop: 5 }} /></>
|
||||
}
|
||||
</LinearGradient>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
)}
|
||||
</Formik>
|
||||
</Animated.View>
|
||||
</ScrollView>
|
||||
</KeyboardAvoidingView>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: colors.white,
|
||||
},
|
||||
header: {
|
||||
height: height * 0.35,
|
||||
},
|
||||
gradient: {
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
borderBottomLeftRadius: 0,
|
||||
},
|
||||
logo: {
|
||||
height: 200,
|
||||
width: 200,
|
||||
},
|
||||
formContainer: {
|
||||
flex: 1,
|
||||
backgroundColor: colors.white,
|
||||
marginTop: -40,
|
||||
borderTopLeftRadius: 35,
|
||||
borderTopRightRadius: 35,
|
||||
paddingHorizontal: 28,
|
||||
paddingTop: 10,
|
||||
// Shadow for iOS
|
||||
shadowColor: '#000',
|
||||
shadowOffset: { width: 0, height: -10 },
|
||||
shadowOpacity: 0.1,
|
||||
shadowRadius: 10,
|
||||
// Elevation for Android
|
||||
elevation: 20,
|
||||
},
|
||||
sheetHandle: {
|
||||
width: 40,
|
||||
height: 5,
|
||||
backgroundColor: '#E0E0E0',
|
||||
borderRadius: 10,
|
||||
alignSelf: 'center',
|
||||
marginBottom: 20,
|
||||
},
|
||||
title: {
|
||||
fontSize: 28,
|
||||
fontWeight: '800',
|
||||
color: '#1A1A1A',
|
||||
letterSpacing: -0.5,
|
||||
},
|
||||
subtitle: {
|
||||
fontSize: 15,
|
||||
color: '#7C7C7C',
|
||||
marginTop: 6,
|
||||
marginBottom: 30,
|
||||
},
|
||||
label: {
|
||||
fontSize: 14,
|
||||
fontWeight: '600',
|
||||
color: '#444',
|
||||
marginBottom: 8,
|
||||
marginLeft: 4,
|
||||
},
|
||||
inputWrapper: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
backgroundColor: '#F8F9FB',
|
||||
borderRadius: 16,
|
||||
borderWidth: 1.5,
|
||||
borderColor: '#F0F0F0',
|
||||
paddingHorizontal: 16,
|
||||
height: 58,
|
||||
},
|
||||
inputError: {
|
||||
borderColor: '#FF5252',
|
||||
backgroundColor: '#FFF8F8',
|
||||
},
|
||||
input: {
|
||||
flex: 1,
|
||||
marginLeft: 12,
|
||||
fontSize: 16,
|
||||
color: '#1A1A1A',
|
||||
fontWeight: '500',
|
||||
},
|
||||
errorText: {
|
||||
color: '#FF5252',
|
||||
fontSize: 12,
|
||||
marginTop: 5,
|
||||
marginLeft: 12,
|
||||
fontWeight: '500',
|
||||
},
|
||||
forgotPass: {
|
||||
alignSelf: 'flex-end',
|
||||
marginTop: 12,
|
||||
marginBottom: 24,
|
||||
},
|
||||
forgotPassText: {
|
||||
color: colors.primary,
|
||||
fontWeight: '600',
|
||||
fontSize: 14,
|
||||
},
|
||||
buttonShadow: {
|
||||
shadowColor: colors.primary,
|
||||
shadowOffset: { width: 0, height: 8 },
|
||||
shadowOpacity: 0.3,
|
||||
shadowRadius: 12,
|
||||
elevation: 8,
|
||||
},
|
||||
button: {
|
||||
height: 58,
|
||||
borderRadius: 18,
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
buttonText: {
|
||||
color: colors.white,
|
||||
fontSize: 18,
|
||||
fontWeight: '700',
|
||||
},
|
||||
footer: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'center',
|
||||
marginTop: 30,
|
||||
paddingBottom: 20,
|
||||
},
|
||||
footerText: {
|
||||
color: '#7C7C7C',
|
||||
fontSize: 15,
|
||||
},
|
||||
signUpText: {
|
||||
color: colors.primary,
|
||||
fontWeight: '700',
|
||||
fontSize: 15,
|
||||
},
|
||||
});
|
||||
|
||||
export default Login;
|
||||
Reference in New Issue
Block a user