BrixCafe/app/screens/auth/SignUpScreen.tsx

586 lines
18 KiB
TypeScript

import React, { useState } from 'react';
import {View,Text,TextInput,TouchableOpacity,ScrollView,StyleSheet,SafeAreaView,Image,Pressable,Modal} from 'react-native';
import { StatusBar } from 'expo-status-bar';
import { ArrowLeft, Eye, EyeOff, MapPin,Check } from 'lucide-react-native';
import { doc, setDoc } from 'firebase/firestore';
import { db } from '../../../firebase/config';
import { signUp } from '../../../firebase/auth';
import { Alert } from 'react-native';
import { router } from "expo-router";
const cities = [
'Ariana', 'Ben Arous', 'Bizerte', 'Béja', 'El Kef', 'Ettadhamen', 'Gabes',
'Gafsa', 'Jendouba', 'Kairouan', 'Kasserine', 'Kebili', 'Mahdia', 'Medenine',
'Monastir', 'Nabeul', 'Sfax', 'Siliana', 'Sidi Bouzid', 'Sousse', 'Tataouine',
'Tozeur', 'Tunis', 'Zaghouan'
];
const delegationsByGouvernorat: Record<string, string[]> = {
Ariana: ['Ariana Medina', 'Ettadhamen', 'Kalaat El Andalous', 'Mnihla', 'Raoued', 'Sidi Thabet', 'Soukra'],
Béja: ['Amdoun', 'Beja North', 'Beja South', 'Goubellat', 'Mejez El Bab', 'Nefza', 'Teboursouk', 'Testour', 'Thibar'],
'Ben Arous': ['Ben Arous', 'Boumhel', 'El Mourouj', 'Ezzahra', 'Fouchana', 'Hammam Chott', 'Hammam Lif', 'M\'Hamdia', 'Medina Jedida', 'Mégrine', 'Mornag', 'Rades'],
Bizerte: ['Bizerte Nord', 'Bizerte Sud', 'Joumine', 'El Alia', 'Ghar El Melh', 'Mateur', 'Menzel Bourguiba', 'Menzel Jemil', 'Ras Jebel', 'Sejnane', 'Tinja', 'Utique', 'Zarzouna','Manzel Abderrahmen','El Alia','Ghezala'],
Gabès: ['Gabès', 'El Hamma', 'Matmata', 'Mareth', 'Nouvelle Matmata', 'Chouchet'],
Gafsa: ['Gafsa', 'El Guettar', 'Mdhila', 'Redeyef', 'Metlaoui', 'Sidi Aich', 'Belkhir', 'Om Larayes'],
Jendouba: ['Jendouba', 'Ain Draham', 'Fernana', 'Ghardimaou', 'Tabarka', 'Balta Bou Aouane', 'Oued Meliz'],
Kairouan: ['Kairouan', 'Bou Hajla', 'Chebika', 'El Alaa', 'El Fahs', 'Haffouz', 'Nasrallah', 'Oueslatia', 'Sbiba', 'Sidi Alouane', 'Soliman', 'Thala'],
Kasserine: ['Kasserine', 'Foussana', 'Hassi El Ferid', 'Haidra', 'Sbeitla', 'Thala', 'Tounine', 'Sidi Bouali'],
Kébili: ['Kébili', 'Douz', 'Souk Lahad', 'El Faouar', 'Chbika'],
Kef: ['Kef', 'Dahmani', 'El Ksour', 'Kalaa Khasba', 'Nebeur', 'Sers', 'Tajerouine', 'Zouila'],
Mahdia: ['Mahdia', 'Bou Merdes', 'Chorbane', 'El Jem', 'Ksour Essef', 'Melloulèche', 'Rejiche', 'Sahline', 'Sidi Alouane'],
Manouba: ['Manouba', 'Borj El Amri', 'El Battan', 'Jedaida', 'Mornaguia', 'Tebourba'],
Medenine: ['Medenine', 'Ben Guerdane', 'Beni Khedache', 'Djerba', 'Zarzis', 'Ajim', 'Houmt Souk'],
Monastir: ['Monastir', 'Bekalta', 'Ksibet El Mediouni', 'Ksar Hellal', 'Menzel Harb', 'Sahline', 'Sayada', 'Téboulba'],
Nabeul: ['Nabeul', 'Hammamet', 'Kelibia', 'Korba', 'Menzel Temime', 'Takelsa', 'Soliman', 'Dar Chaâbane El Fehri', 'Bou Argoub'],
Sfax: ['Sfax', 'El Amra', 'El Hencha', 'El Ouardia', 'Kerkennah', 'Menzel Chaker', 'Skhira', 'Thyna'],
'Sidi Bouzid': ['Sidi Bouzid', 'Bir El Hafey', 'Menzel Bouzelfa', 'Meknassy', 'Regueb', 'Sidi Ali Ben Aoun', 'Sbiba'],
Siliana: ['Siliana', 'Bou Arada', 'Gaafour', 'Kesra', 'Makthar', 'Rouhia', 'Sidi Bou Rouis'],
Sousse: ['Sousse', 'Akouda', 'Enfidha', 'Hergla', 'Kalaa Sghira', 'Khezama', 'Msaken', 'Sidi Bou Ali', 'Sidi El Hani'],
Tataouine: ['Tataouine', 'Beni Khedache', 'Dhehiba', 'Ghomrassen', 'Ksar Ouled Soltane', 'Remada'],
Tozeur: ['Tozeur', 'Nefta', 'Degache', 'Chbika'],
Tunis: ['Tunis', 'Carthage', 'Le Bardo', 'La Goulette', 'La Marsa', 'Medina', 'El Omrane', 'El Menzah', 'Ettadhamen', 'El Kabaria', 'El Kram', 'Ezzahra', 'Fouchana', 'Hammam Chott', 'Hammam Linf', 'Mornag', 'Raoued', 'Sidi Thabet', 'Soukra','Boumhel', 'El Mourouj', 'Fouchana', 'Hammam Chott', 'Hammam Lif', 'M\'Hamdia', 'Medina Jedida', 'Mégrine'],
Zaghouan: ['Bir Mcherga', 'El Fahs', 'Nadhour', 'Saouaf', 'Zriba', 'Zaghouan']
};
export default function App() {
const [step, setStep] = useState(1);
const [showPassword, setShowPassword] = useState(false);
const [showConfirmPassword, setShowConfirmPassword] = useState(false);
const handlePress=() =>{
router.replace("/screens/auth/SignIn-Screen");
}
const [formData, setFormData] = useState({
fullName: '',
email: '',
phone: '',
password: '',
confirmPassword: '',
cafeName: '',
cafeAddress: '',
city: '',
delegation: '',
fiscalId: '',
acceptTerms: false,
});
const [showCityPicker, setShowCityPicker] = useState(false);
const [showDelegationPicker, setShowDelegationPicker] = useState(false);
const handleCitySelect = (city: string) => {
setFormData(prev => ({ ...prev, city, delegation: '' }));
setShowCityPicker(false);
};
const handleDelegationSelect = (delegation: string) => {
setFormData(prev => ({ ...prev, delegation }));
setShowDelegationPicker(false);
};
const handleInputChange = (name: string, value: string | boolean) => {
setFormData(prev => ({
...prev,
[name]: value
}));
};
const formatPhoneNumber = (phone: string) => {
const cleaned = phone.replace(/\D/g, "").slice(0, 8); // Garde que les chiffres (max 8)
const part1 = cleaned.slice(0, 2);
const part2 = cleaned.slice(2, 5);
const part3 = cleaned.slice(5, 8);
return [part1, part2, part3].filter(Boolean).join(" ");
};
const handlePhoneChange = (value: string) => {
const cleaned = value.replace(/\D/g, "").slice(0, 8); // que les chiffres, max 8
setFormData({ ...formData, phone: cleaned });
};
const handleNext = () => {
setStep(2);
};
const handleSubmit = async () => {
if (!formData.acceptTerms) {
Alert.alert("Erreur", "Vous devez accepter les conditions.");
return;
}
if (formData.password !== formData.confirmPassword) {
Alert.alert("Erreur", "Les mots de passe ne correspondent pas.");
return;
}
try {
const user = await signUp(formData.email, formData.password);
await setDoc(doc(db, 'users', user.uid), {
fullName: formData.fullName,
email: formData.email,
phone: formData.phone,
cafeName: formData.cafeName,
cafeAddress: formData.cafeAddress,
city: formData.city,
delegation: formData.delegation,
fiscalId: formData.fiscalId,
role: 'user',
createdAt: new Date(),
});
Alert.alert("Succès", "Compte créé avec succès !");
router.replace("/screens/user/UserHomeScreen");
} catch (error: any) {
Alert.alert("Erreur", error.message);
console.log(error);
}
};
const renderStep1 = () => (
<View>
<View style={styles.inputGroup}>
<Text style={styles.label}>Nom et Prénom</Text>
<TextInput
style={styles.input}
placeholder="Nom et prénom"
value={formData.fullName}
onChangeText={(value) => handleInputChange('fullName', value)}
/>
</View>
<View style={styles.inputGroup}>
<Text style={styles.label}>E-mail</Text>
<TextInput
style={styles.input}
placeholder="E-mail"
keyboardType="email-address"
autoCapitalize="none"
value={formData.email}
onChangeText={(value) => handleInputChange('email', value)}
/>
</View>
<View style={styles.inputGroup}>
<Text style={styles.label}>Numéro de téléphone</Text>
<View style={styles.phoneContainer}>
<Image
source={require('../../../assets/images/Flag_Tunisia.png')} // Remplace par le chemin de ton image de drapeau
style={styles.flag}
/>
<Text style={styles.prefix}>+216</Text>
<TextInput
style={styles.phoneNum}
placeholder="00 000 000"
keyboardType="phone-pad"
value={formatPhoneNumber(formData.phone)}
onChangeText={(value) => handlePhoneChange(value)}
maxLength={11}
/>
</View>
</View>
<View style={styles.inputGroup}>
<Text style={styles.label}>Mot de passe</Text>
<View style={styles.passwordContainer}>
<TextInput
style={styles.passwordInput}
placeholder="Entrez votre mot de passe"
secureTextEntry={!showPassword}
value={formData.password}
onChangeText={(value) => handleInputChange('password', value)}
/>
<TouchableOpacity
style={styles.eyeIcon}
onPress={() => setShowPassword(!showPassword)}
>
{showPassword ? <EyeOff size={20} color="#666" /> : <Eye size={20} color="#666" />}
</TouchableOpacity>
</View>
</View>
<View style={styles.inputGroup}>
<Text style={styles.label}>Confirmer votre mot de passe</Text>
<View style={styles.passwordContainer}>
<TextInput
style={styles.passwordInput}
placeholder="Confirmez votre mot de passe"
secureTextEntry={!showConfirmPassword}
value={formData.confirmPassword}
onChangeText={(value) => handleInputChange('confirmPassword', value)}
/>
<TouchableOpacity
style={styles.eyeIcon}
onPress={() => setShowConfirmPassword(!showConfirmPassword)}
>
{showConfirmPassword ? <EyeOff size={20} color="#666" /> : <Eye size={20} color="#666" />}
</TouchableOpacity>
</View>
</View>
<TouchableOpacity style={styles.button} onPress={handleNext}>
<Text style={styles.buttonText}>Suivant</Text>
</TouchableOpacity>
<View style={styles.loginContainer}>
<Text style={styles.loginText}>Vous avez déjà un compte? </Text>
<TouchableOpacity onPress={handlePress}>
<Text style={styles.loginLink}>Connexion</Text>
</TouchableOpacity>
</View>
</View>
);
const renderStep2 = () => (
<View>
<View style={styles.inputGroup}>
<Text style={styles.label}>Nom de Café</Text>
<TextInput
style={styles.input}
placeholder="Nom de café"
value={formData.cafeName}
onChangeText={(value) => handleInputChange('cafeName', value)}
/>
</View>
<View style={styles.inputGroup}>
<Text style={styles.label}>Adresse de Café</Text>
<TextInput
style={styles.input}
placeholder="Adresse de Café"
value={formData.cafeAddress}
onChangeText={(value) => handleInputChange('cafeAddress', value)}
/>
</View>
<View style={styles.inputGroup}>
<Text style={styles.label}>Ville</Text>
<View style={styles.selectContainer}>
<Pressable
style={styles.select}
onPress={() => setShowCityPicker(true)}
>
<Text style={styles.selectText}>
{formData.city || 'Sélectionner une ville'}
</Text>
<MapPin size={20} color="#666" />
</Pressable>
</View>
</View>
<Modal
visible={showCityPicker}
transparent={true}
animationType="slide"
onRequestClose={() => setShowCityPicker(false)}
>
<View style={styles.modalOverlay}>
<View style={styles.modalContainer}>
<Text style={styles.modalTitle}>Sélectionner une Ville</Text>
<ScrollView>
{cities.map((city, index) => (
<TouchableOpacity key={index} onPress={() => handleCitySelect(city)}>
<Text style={styles.cityItem}>{city}</Text>
</TouchableOpacity>
))}
</ScrollView>
<TouchableOpacity
style={styles.closeButton}
onPress={() => setShowCityPicker(false)}
>
<Text style={styles.buttonText}>Fermer</Text>
</TouchableOpacity>
</View>
</View>
</Modal>
<Modal
visible={showDelegationPicker}
transparent={true}
animationType="slide"
onRequestClose={() => setShowDelegationPicker(false)}
>
<View style={styles.modalOverlay}>
<View style={styles.modalContainer}>
<Text style={styles.modalTitle}>Sélectionner une Délégation</Text>
<ScrollView>
{availableDelegations.map((del, index) => (
<TouchableOpacity key={index} onPress={() => handleDelegationSelect(del)}>
<Text style={styles.cityItem}>{del}</Text>
</TouchableOpacity>
))}
</ScrollView>
<TouchableOpacity style={styles.closeButton} onPress={() => setShowDelegationPicker(false)} >
<Text style={styles.buttonText}>Fermer</Text>
</TouchableOpacity>
</View>
</View>
</Modal>
<View style={styles.inputGroup}>
<Text style={styles.label}>Délégation</Text>
<View style={styles.selectContainer}>
<Pressable
style={styles.select}
onPress={() => setShowDelegationPicker(true)}
>
<Text style={styles.selectText}>
{formData.delegation || 'Sélectionner une délégation'}
</Text>
<MapPin size={20} color="#666" />
</Pressable>
</View>
</View>
<View style={styles.inputGroup}>
<Text style={styles.label}>Matricule Fiscale</Text>
<TextInput
style={styles.input}
placeholder="Matricule Fiscale"
value={formData.fiscalId}
onChangeText={(value) => handleInputChange('fiscalId', value)}
/>
</View>
<View style={styles.checkboxContainer}>
<Pressable
style={[styles.checkbox, formData.acceptTerms && styles.checkboxChecked]}
onPress={() => handleInputChange('acceptTerms', !formData.acceptTerms)}
>
{formData.acceptTerms && <Check size={16} color="white" />}
</Pressable>
<Text style={styles.checkboxLabel}>
J'accepte les conditions générales et la politique de confidentialité.
</Text>
</View>
<TouchableOpacity style={styles.button} onPress={handleSubmit}>
<Text style={styles.buttonText}>Valider</Text>
</TouchableOpacity>
</View>
);
const availableDelegations = delegationsByGouvernorat[formData.city] || [];
return (
<SafeAreaView style={styles.container}>
<StatusBar style="dark" />
<ScrollView contentContainerStyle={styles.scrollContainer}>
{step > 1 && (
<TouchableOpacity
style={styles.backButton}
onPress={() => setStep(1)}
>
<ArrowLeft size={24} color="#666" />
</TouchableOpacity>
)}
<View style={styles.header}>
<View style={styles.logoContainer}>
<Image source={require('../../../assets/images/logo.png')} style={styles.logo}/>
<Text style={styles.title}>Création de compte</Text>
</View>
</View>
{step === 1 ? renderStep1() : renderStep2()}
</ScrollView>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
padding: 10,
},
scrollContainer: {
flexGrow: 1,
padding: 16,
},
header: {
flexDirection: 'row',
alignItems: 'center',
marginBottom: 25,
},
backButton: {
marginTop:10,
},
logoContainer: {
flex: 1,
alignItems: 'center',
},
logo: {
width: 80,
height: 80,
alignItems: 'center',
justifyContent: 'center',
verticalAlign:'middle',
marginTop:20,
marginBottom: 16,
},
title: {
fontSize: 24,
fontWeight: '600',
color: '#1f2937',
},
inputGroup: {
marginBottom: 16,
},
label: {
fontSize: 14,
fontWeight: '500',
color: '#374151',
marginBottom: 4,
},
input: {
borderWidth: 1,
borderColor: '#d1d5db',
borderRadius: 8,
padding: 12,
fontSize: 16,
color: '#1f2937',
},
passwordContainer: {
flexDirection: 'row',
alignItems: 'center',
borderWidth: 1,
borderColor: '#d1d5db',
borderRadius: 8,
},
passwordInput: {
flex: 1,
padding: 12,
fontSize: 16,
color: '#1f2937',
},
eyeIcon: {
padding: 12,
},
selectContainer: {
borderWidth: 1,
borderColor: '#d1d5db',
borderRadius: 8,
},
select: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
padding: 12,
},
selectText: {
fontSize: 16,
color: '#000',
},
checkboxContainer: {
flexDirection: 'row',
alignItems: 'flex-start',
marginBottom: 16,
},
checkbox: {
width: 20,
height: 20,
borderWidth: 2,
borderColor: "#B17741",
borderRadius: 4,
marginRight: 8,
marginTop: 2,
},
checkboxChecked: {
backgroundColor: '#B17741',
borderColor: "#B17741",
},
checkboxLabel: {
flex: 1,
fontSize: 14,
color: '#4b5563',
},
button: {
backgroundColor: '#B77729',
borderRadius: 8,
padding: 16,
alignItems: 'center',
marginBottom: 16,
},
buttonText: {
color: 'white',
fontSize: 16,
fontWeight: '500',
},
loginContainer: {
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
},
loginText: {
fontSize: 14,
color: '#4b5563',
},
loginLink: {
fontSize: 14,
color: '#B77729',
},
modalOverlay: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'rgba(0, 0, 0, 0.5)',
},
modalContainer: {
backgroundColor: 'white',
padding: 20,
borderRadius: 10,
width: '90%',
height: '80%'
},
modalTitle: {
fontSize: 18,
fontWeight: '600',
marginBottom: 12,
},
cityItem: {
fontSize: 16,
paddingVertical: 8,
paddingHorizontal: 10,
borderBottomWidth: 1,
borderBottomColor: '#d1d5db',
},
closeButton: {
backgroundColor: '#B77729',
borderRadius: 8,
padding: 10,
alignItems: 'center',
marginTop: 12,
},
phoneContainer: {
flexDirection: 'row',
alignItems: 'center',
borderRadius: 8,
padding: 3,
borderWidth: 1,
borderColor: '#ddd',
},
flag: {
width: 18,
height: 12,
borderRadius: 2,
marginRight: 8,
marginLeft: 8,
},
prefix: {
fontSize: 16,
color: '#B77729',
marginRight: 5,
},
phoneNum:{
color: '#000',
fontSize: 16,
width: '100%',
}
});