181 lines
5.5 KiB
TypeScript
181 lines
5.5 KiB
TypeScript
import React, { useState, useEffect } from 'react';
|
|
import {
|
|
Text,
|
|
View,
|
|
TextInput,
|
|
TouchableOpacity,
|
|
KeyboardAvoidingView,
|
|
Platform,
|
|
ScrollView,
|
|
} from 'react-native';
|
|
import { useNavigation } from '@react-navigation/native';
|
|
import Icon from 'react-native-vector-icons/Ionicons';
|
|
import { getStyles } from './login.styles';
|
|
import { useTheme } from '../../theme';
|
|
import { useAppDispatch, useAppSelector } from '../../store/store';
|
|
import { login } from '../../store/commonReducers/auth/thunk';
|
|
import { LoginRequest } from '@interfaces';
|
|
import { RootState } from '../../store/rootReducer';
|
|
|
|
export const LoginScreen = () => {
|
|
const dispatch = useAppDispatch();
|
|
const navigation = useNavigation<any>();
|
|
const { theme: colors } = useTheme();
|
|
const styles = getStyles(colors);
|
|
const [tenancy, setTenancy] = useState('');
|
|
const [email, setEmail] = useState('');
|
|
const [password, setPassword] = useState('');
|
|
const [localError, setLocalError] = useState('');
|
|
|
|
const { loginLoading, loginError, loginSuccess, token, user_data } =
|
|
useAppSelector((state: RootState) => state.auth);
|
|
|
|
const handleLogin = async () => {
|
|
setLocalError('');
|
|
if (!tenancy.trim()) {
|
|
setLocalError('Tenancy name is required');
|
|
return;
|
|
}
|
|
if (!email.trim()) {
|
|
setLocalError('Email address is required');
|
|
return;
|
|
}
|
|
if (!password.trim()) {
|
|
setLocalError('Password is required');
|
|
return;
|
|
}
|
|
|
|
const payload: LoginRequest = {
|
|
email,
|
|
password,
|
|
device_token: '',
|
|
};
|
|
|
|
await dispatch(login(payload));
|
|
};
|
|
|
|
useEffect(() => {
|
|
if (loginSuccess && token && user_data) {
|
|
navigation.reset({
|
|
index: 0,
|
|
routes: [{ name: 'DrawerStack' }],
|
|
});
|
|
}
|
|
}, [loginSuccess, token, user_data, navigation]);
|
|
|
|
return (
|
|
<KeyboardAvoidingView
|
|
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
|
|
style={styles.container}
|
|
>
|
|
<ScrollView
|
|
contentContainerStyle={styles.scrollContainer}
|
|
keyboardShouldPersistTaps="handled"
|
|
>
|
|
<View style={styles.headerContainer}>
|
|
<View style={styles.logoCircle}>
|
|
<Icon name="cube" size={40} color={colors.icon} />
|
|
</View>
|
|
<Text style={styles.title}>Convex CRM</Text>
|
|
<Text style={styles.subtitle}>
|
|
Enter details to access your workspace
|
|
</Text>
|
|
</View>
|
|
|
|
<View style={styles.formCard}>
|
|
{localError || loginError ? (
|
|
<View style={styles.errorBanner}>
|
|
<Icon name="alert-circle" size={20} color="#EF4444" />
|
|
<Text style={styles.errorText}>{localError || loginError}</Text>
|
|
</View>
|
|
) : null}
|
|
|
|
{/* Tenancy Field */}
|
|
<View style={styles.inputContainer}>
|
|
<Text style={styles.label}>Tenancy Name</Text>
|
|
<View style={styles.inputWrapper}>
|
|
<Icon
|
|
name="business-outline"
|
|
size={20}
|
|
color={colors.textSecondary}
|
|
style={styles.inputIcon}
|
|
/>
|
|
<TextInput
|
|
style={styles.input}
|
|
placeholder="company-name"
|
|
placeholderTextColor={colors.textMuted}
|
|
value={tenancy}
|
|
onChangeText={setTenancy}
|
|
autoCapitalize="none"
|
|
autoCorrect={false}
|
|
/>
|
|
</View>
|
|
</View>
|
|
|
|
{/* Email Field */}
|
|
<View style={styles.inputContainer}>
|
|
<Text style={styles.label}>Email Address</Text>
|
|
<View style={styles.inputWrapper}>
|
|
<Icon
|
|
name="mail-outline"
|
|
size={20}
|
|
color={colors.textSecondary}
|
|
style={styles.inputIcon}
|
|
/>
|
|
<TextInput
|
|
style={styles.input}
|
|
placeholder="name@company.com"
|
|
placeholderTextColor={colors.textMuted}
|
|
value={email}
|
|
onChangeText={setEmail}
|
|
keyboardType="email-address"
|
|
autoCapitalize="none"
|
|
autoCorrect={false}
|
|
/>
|
|
</View>
|
|
</View>
|
|
|
|
{/* Password Field */}
|
|
<View style={styles.inputContainer}>
|
|
<Text style={styles.label}>Password</Text>
|
|
<View style={styles.inputWrapper}>
|
|
<Icon
|
|
name="lock-closed-outline"
|
|
size={20}
|
|
color={colors.textSecondary}
|
|
style={styles.inputIcon}
|
|
/>
|
|
<TextInput
|
|
style={styles.input}
|
|
placeholder="••••••••"
|
|
placeholderTextColor={colors.textMuted}
|
|
value={password}
|
|
onChangeText={setPassword}
|
|
secureTextEntry
|
|
autoCapitalize="none"
|
|
autoCorrect={false}
|
|
/>
|
|
</View>
|
|
</View>
|
|
|
|
{/* Sign In Button */}
|
|
<TouchableOpacity
|
|
style={styles.button}
|
|
activeOpacity={0.8}
|
|
onPress={handleLogin}
|
|
disabled={loginLoading}
|
|
>
|
|
<Text style={styles.buttonText}>
|
|
{loginLoading ? 'Signing In...' : 'Sign In'}
|
|
</Text>
|
|
</TouchableOpacity>
|
|
</View>
|
|
|
|
<View style={styles.footer}>
|
|
<Text style={styles.footerText}>Secure SSL encrypted workspace</Text>
|
|
</View>
|
|
</ScrollView>
|
|
</KeyboardAvoidingView>
|
|
);
|
|
};
|