diff --git a/app/_layout.tsx b/app/_layout.tsx
index e40127a..cb68712 100644
--- a/app/_layout.tsx
+++ b/app/_layout.tsx
@@ -3,7 +3,7 @@ import { Stack } from 'expo-router';
import { GestureHandlerRootView } from 'react-native-gesture-handler';
import { SafeAreaProvider } from 'react-native-safe-area-context';
import React from 'react';
-import { CartProvider } from './context/cartContext'
+import { CartProvider } from '../context/cartContext'
export default function Layout() {
return (
diff --git a/app/index.tsx b/app/index.tsx
index e413290..3b61465 100644
--- a/app/index.tsx
+++ b/app/index.tsx
@@ -1,90 +1,38 @@
-import React from 'react';
-import { View, Text, Image, StyleSheet, TouchableOpacity } from 'react-native';
+import React, { useEffect, useState } from 'react';
+import { View, ActivityIndicator } from 'react-native';
+import { getAuth, onAuthStateChanged } from 'firebase/auth';
import { router } from 'expo-router';
-import COLORS from './constants/colors';
-import { StatusBar } from 'expo-status-bar';
+import OpeningScreen from './screens/auth/OpeningScreen'; // ajuste le chemin si besoin
+const Index = () => {
+ const [checkingAuth, setCheckingAuth] = useState(true);
+ const [isLoggedIn, setIsLoggedIn] = useState(false);
-const OpeningScreen = () => {
+ useEffect(() => {
+ const auth = getAuth();
- return (
-
-
-
- Bienvenue chez Brix Café
-
-
- Depuis 2024, Brix Café vous fait vivre une expérience café unique,
- inspirée du savoir-faire italien et portée par une passion authentique.
- Des grains d’exception, une qualité incomparable.
-
+ const unsubscribe = onAuthStateChanged(auth, (user) => {
+ if (user) {
+ setIsLoggedIn(true);
+ router.replace('/screens/user/UserHomeScreen'); // redirige vers Home
+ } else {
+ setIsLoggedIn(false); // utilisateur non connecté
+ }
+ setCheckingAuth(false); // vérification terminée
+ });
- router.push('/screens/auth/SignIn-Screen')}>
- Se connecter
-
+ return () => unsubscribe();
+ }, []);
- router.push('/screens/auth/SignUpScreen')}>
- Créer un compte
-
-
- );
+ if (checkingAuth) {
+ return (
+
+
+
+ );
+ }
+
+ return !isLoggedIn ? : null;
};
-// Styles
-const styles = StyleSheet.create({
- container: {
- flex: 1,
- backgroundColor: '#000000',
- alignItems: 'center',
- justifyContent: 'center',
- paddingHorizontal: 20,
- },
- logo: {
- width: 120,
- height: 120,
- marginBottom: 20,
- },
- welcomeText: {
- fontSize: 26,
- fontWeight: 'bold',
- color: COLORS.text,
- marginBottom: 20,
- },
- coffeeImage: {
- width: '120%',
- height: 150,
- marginTop:40,
- marginBottom: 30,
- },
- descriptionText: {
- fontSize: 14,
- color: COLORS.text,
- textAlign: 'center',
- marginBottom: 40,
- },
- signInButton: {
- backgroundColor: COLORS.primary,
- paddingVertical: 15,
- paddingHorizontal: 40,
- borderRadius: 10,
- marginBottom: 20,
- width: '80%',
- alignItems: 'center',
- },
- signUpButton: {
- borderWidth: 1,
- borderColor: COLORS.primary,
- paddingVertical: 15,
- paddingHorizontal: 40,
- borderRadius: 10,
- width: '80%',
- alignItems: 'center',
- },
- buttonText: {
- fontSize: 16,
- color: COLORS.text,
- fontWeight: 'bold',
- },
-});
-
-export default OpeningScreen;
+export default Index;
diff --git a/app/screens/auth/OpeningScreen.tsx b/app/screens/auth/OpeningScreen.tsx
new file mode 100644
index 0000000..f7bfde7
--- /dev/null
+++ b/app/screens/auth/OpeningScreen.tsx
@@ -0,0 +1,90 @@
+import React from 'react';
+import { View, Text, Image, StyleSheet, TouchableOpacity } from 'react-native';
+import { router } from 'expo-router';
+import COLORS from '@/constants/colors';
+import { StatusBar } from 'expo-status-bar';
+
+
+const OpeningScreen = () => {
+
+ return (
+
+
+
+ Bienvenue chez Brix Café
+
+
+ Depuis 2024, Brix Café vous fait vivre une expérience café unique,
+ inspirée du savoir-faire italien et portée par une passion authentique.
+ Des grains d’exception, une qualité incomparable.
+
+
+ router.push('/screens/auth/SignIn-Screen')}>
+ Se connecter
+
+
+ router.push('/screens/auth/SignUpScreen')}>
+ Créer un compte
+
+
+ );
+};
+
+// Styles
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ backgroundColor: '#000000',
+ alignItems: 'center',
+ justifyContent: 'center',
+ paddingHorizontal: 20,
+ },
+ logo: {
+ width: 120,
+ height: 120,
+ marginBottom: 20,
+ },
+ welcomeText: {
+ fontSize: 26,
+ fontWeight: 'bold',
+ color: COLORS.text,
+ marginBottom: 20,
+ },
+ coffeeImage: {
+ width: '120%',
+ height: 150,
+ marginTop:40,
+ marginBottom: 30,
+ },
+ descriptionText: {
+ fontSize: 14,
+ color: COLORS.text,
+ textAlign: 'center',
+ marginBottom: 40,
+ },
+ signInButton: {
+ backgroundColor: COLORS.primary,
+ paddingVertical: 15,
+ paddingHorizontal: 40,
+ borderRadius: 10,
+ marginBottom: 20,
+ width: '80%',
+ alignItems: 'center',
+ },
+ signUpButton: {
+ borderWidth: 1,
+ borderColor: COLORS.primary,
+ paddingVertical: 15,
+ paddingHorizontal: 40,
+ borderRadius: 10,
+ width: '80%',
+ alignItems: 'center',
+ },
+ buttonText: {
+ fontSize: 16,
+ color: COLORS.text,
+ fontWeight: 'bold',
+ },
+});
+
+export default OpeningScreen;
diff --git a/app/screens/auth/SignIn-Screen.tsx b/app/screens/auth/SignIn-Screen.tsx
index c0d09b7..60542a4 100644
--- a/app/screens/auth/SignIn-Screen.tsx
+++ b/app/screens/auth/SignIn-Screen.tsx
@@ -5,8 +5,8 @@ import { router } from "expo-router";
import { signIn } from "../../../firebase/auth"; // Assure-toi que le chemin est correct
import { Link } from "expo-router";
import { KeyboardAwareScrollView } from "react-native-keyboard-aware-scroll-view"; // Import the library
-import COLORS from "@/app/constants/colors";
-
+import COLORS from "@/constants/colors";
+import AsyncStorage from "@react-native-async-storage/async-storage";
const SignInScreen = () => {
@@ -43,13 +43,21 @@ const SignInScreen = () => {
const handleLogin = async () => {
if (!validateForm()) return;
-
+
try {
- const { user } = await signIn(form.email, form.password); // Destructure to get user
- console.log("Connexion réussie :", user.email); // Access the email directly
+ const { user } = await signIn(form.email, form.password);
+
+ console.log("Connexion réussie :", user.email);
+
+ if (form.rememberMe) {
+ await AsyncStorage.setItem("rememberMe", "true");
+ } else {
+ await AsyncStorage.removeItem("rememberMe");
+ }
+
router.replace("/screens/user/UserHomeScreen");
} catch (error: any) {
- Alert.alert("Erreur", error.message); // Display the error message
+ Alert.alert("Erreur", error.message);
}
};
@@ -67,7 +75,7 @@ const SignInScreen = () => {
>
-
+
Se connecter
@@ -117,9 +125,9 @@ const SignInScreen = () => {
style={styles.eyeIcon}
>
{showPassword ? (
-
- ) : (
+ ) : (
+
)}
diff --git a/app/screens/user/CartScreen.tsx b/app/screens/user/CartScreen.tsx
index c3b0544..40a8d12 100644
--- a/app/screens/user/CartScreen.tsx
+++ b/app/screens/user/CartScreen.tsx
@@ -1,131 +1,238 @@
-import React, { useEffect, useState } from 'react';
-import { useRouter } from 'expo-router';
-import { View, Text, Button, Alert, StyleSheet } from 'react-native';
+import React, { useEffect, useState, useCallback } from 'react';
+import {
+ View,
+ Text,
+ Alert,
+ StyleSheet,
+ FlatList,
+ Platform,
+ TouchableOpacity,
+ Button,
+} from 'react-native';
+import { SafeAreaView } from 'react-native-safe-area-context';
+import { useCart } from '@/context/cartContext';
import { getAuth } from 'firebase/auth';
-import { collection, addDoc } from 'firebase/firestore'; // Make sure these are imported
-import { db } from '@/firebase/config'; // Ensure this path is correct
-import { useCart } from '@/app/context/cartContext';
+import { collection, addDoc } from 'firebase/firestore';
+import { db } from '@/firebase/config';
+import CartItem from '@/components/CartItem';
+import { ArrowLeft } from 'lucide-react-native';
+import Animated, {
+ useAnimatedStyle,
+ useSharedValue,
+ withSequence,
+ withTiming,
+} from 'react-native-reanimated';
+import * as Haptics from 'expo-haptics';
+import { useRouter } from 'expo-router';
+import COLORS from '@/constants/colors';
+import { CartItem as CartItemType } from '@/context/cartContext';
-const CartScreen = () => {
- const { cart, clearCart } = useCart();
+export default function CartScreen() {
+ const { cart, clearCart, updateQuantity } = useCart();
+ const totalAmount = cart.total;
+ const [isProcessingOrder, setIsProcessingOrder] = useState(false);
const auth = getAuth();
- const [isAuthenticated, setIsAuthenticated] = useState(false);
const router = useRouter();
- // Check if the user is logged in when the component mounts
- useEffect(() => {
- const user = auth.currentUser;
- if (user) {
- setIsAuthenticated(true);
- } else {
- setIsAuthenticated(false);
- router.push('../screens/auth/SignInScreen'); // Redirect to sign-in screen if not logged in
- }
- }, [auth, router]);
+ const totalValue = useSharedValue(1);
+ const buttonScale = useSharedValue(1);
- const handleConfirmOrder = async () => {
- if (!isAuthenticated) {
- Alert.alert('Erreur', 'Utilisateur non connecté.');
- return;
- }
+
- if (cart.total <= 0) {
+ const totalAnimatedStyle = useAnimatedStyle(() => ({
+ transform: [{ scale: totalValue.value }],
+ }));
+
+ const handleConfirmOrder = useCallback(async () => {
+
+
+ if (totalAmount <= 0) {
Alert.alert('Panier vide', 'Veuillez ajouter des produits à votre panier');
return;
}
- try {
- const userId = auth.currentUser?.uid;
- if (!userId) {
- Alert.alert('Erreur', 'Utilisateur non connecté.');
- return;
- }
+ setIsProcessingOrder(true);
+ buttonScale.value = withSequence(
+ withTiming(0.95, { duration: 100 }),
+ withTiming(1, { duration: 150 })
+ );
+ if (Platform.OS !== 'web') {
+ Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success);
+ }
+
+ try {
const orderData: any = {
- userId,
status: 'En attente',
+ createdAt: new Date().toISOString(),
+ totalAmount: totalAmount
};
cart.items.forEach((item, index) => {
- orderData[`item${index + 1}`] = [item.quantity, item.productName];
+ orderData[`item${index + 1}`] = {
+ name: item.name,
+ quantity: item.quantity,
+ };
});
await addDoc(collection(db, 'orders'), orderData);
-
- Alert.alert('Commande confirmée', 'Votre commande a été enregistrée.');
+ Alert.alert('Commande confirmée', `Montant Total : ${totalAmount}DT`);
clearCart();
} catch (error) {
- console.error('Erreur de commande', error);
+ console.error('Erreur commande :', error);
Alert.alert('Erreur', "Impossible d'enregistrer la commande.");
+ } finally {
+ setIsProcessingOrder(false);
}
- };
+ }, [cart, totalAmount]);
- if (!isAuthenticated) {
- return Chargement...; // Loading state while checking authentication
- }
+ const renderItem = useCallback(({ item }: { item: CartItemType }) => (
+ {
+ updateQuantity(id, newQty);
+ totalValue.value = withSequence(
+ withTiming(1.05, { duration: 100 }),
+ withTiming(1, { duration: 100 })
+ );
+ }}
+ />
+ ), []);
+
+ const keyExtractor = useCallback((item: CartItemType) => item.id, []);
return (
-
- Votre Panier
+
+
+ router.back()}>
+
+
+ Mon Panier
+
- {cart.items.length === 0 ? (
- Votre panier est vide.
- ) : (
- cart.items.map((item, index) => (
-
-
- {item.productName} - Quantité : {item.quantity}
-
-
- ))
- )}
+
+
+ Votre panier est vide
+
+ }
+ />
+
- {cart.items.length > 0 && (
-
-
-
-
-
+
+
+ Total :
+
+ {totalAmount}DT
+
- )}
-
+
+
+ Ajouter au panier
+
+
+ {
+ Alert.alert(
+ 'Vider le panier',
+ 'Êtes-vous sûr de vouloir supprimer tous les articles du panier ?',
+ [
+ { text: 'Annuler', style: 'cancel' },
+ { text: 'Confirmer', style: 'destructive', onPress: clearCart },
+ ]
+ );
+ }}
+ disabled={cart.items.length === 0}>
+ Vider le panier
+
+
+
);
-};
+}
const styles = StyleSheet.create({
- container: {
- padding: 20,
- backgroundColor: '#FFF',
- flexGrow: 1,
+ container: { flex: 1, backgroundColor: '#fff' },
+ header: {
+ height: 60,
+ justifyContent: 'center',
+ alignItems: 'center',
+ position: 'relative',
+ backgroundColor: '#fff',
+ borderBottomWidth: 1,
+ borderBottomColor: '#eee',
+ marginTop: 5,
},
- title: {
- fontSize: 22,
- fontWeight: 'bold',
- marginBottom: 15,
- textAlign: 'center',
- color: '#5A3E36',
+ backButton: {
+ position: 'absolute',
+ left: 20,
+ top: '50%',
+ transform: [{ translateY: -12 }],
},
- empty: {
- fontSize: 16,
- color: '#777',
- textAlign: 'center',
- marginTop: 50,
- },
- itemContainer: {
- backgroundColor: '#F5F5DC',
- padding: 15,
- marginBottom: 10,
- borderRadius: 10,
- borderColor: '#DDD',
- borderWidth: 1,
- },
- itemText: {
- fontSize: 16,
+ headerTitle: {
+ fontSize: 20,
+ fontWeight: '600',
color: '#333',
},
- buttonContainer: {
- marginTop: 30,
+ content: {
+ flex: 1,
+ padding: 5,
+ },
+ footer: {
+ paddingHorizontal: 20,
+ paddingVertical: 10,
+ backgroundColor: COLORS.background_user,
+ borderTopWidth: 1,
+ borderTopColor: COLORS.secondary,
+ },
+ totalContainer: {
+ flexDirection: 'row',
+ justifyContent: 'center',
+ alignItems: 'center',
+ marginBottom: 10,
+ },
+ totalLabel: {
+ fontSize: 20,
+ },
+ totalAmount: {
+ fontSize: 20,
+ color: COLORS.primary
+ },
+ ConfirmButton: {
+ backgroundColor: '#B07B4F',
+ borderRadius: 12,
+ padding: 16,
+ alignItems: 'center',
+ },
+ ConfirmButtonText: {
+ color: '#fff',
+ fontSize: 16,
+ fontWeight: '600',
+ },
+ clearCartButton: {
+ backgroundColor: '#D9534F',
+ borderRadius: 12,
+ padding: 16,
+ alignItems: 'center',
+ marginTop: 10, // Adding some space above the button
+ },
+ clearCartButtonText: {
+ color: '#fff',
+ fontSize: 16,
+ fontWeight: '600',
+ },
+
+ emptyContainer: {
+ flex: 1,
+ justifyContent: 'center',
+ alignItems: 'center',
+ paddingVertical: 10,
+ },
+ emptyText: {
+ fontSize: 18,
},
});
-
-export default CartScreen;
diff --git a/app/screens/user/GrainsScreen.tsx b/app/screens/user/GrainsScreen.tsx
index d9cd123..df70fbd 100644
--- a/app/screens/user/GrainsScreen.tsx
+++ b/app/screens/user/GrainsScreen.tsx
@@ -2,12 +2,12 @@ import { View, Text, StyleSheet, ScrollView, TouchableOpacity } from 'react-nati
import { SafeAreaView } from 'react-native-safe-area-context';
import { ArrowLeft } from 'lucide-react-native';
import { router } from "expo-router";
-import ProductCard from '../../components/ProductCard';
-import COLORS from '@/app/constants/colors';
+import ProductCard from '@/components/ProductCard';
+import COLORS from '@/constants/colors';
import { collection, getDocs } from 'firebase/firestore';
import { useEffect, useState } from 'react';
import { db } from '@/firebase/config';
-import { Product } from '@/app/constants/types';
+import { Product } from '@/constants/types';
export default function GrainsScreen() {
const [products, setProducts] = useState([]);
@@ -74,7 +74,7 @@ const styles = StyleSheet.create({
},
content: {
flex: 1,
- padding: 28,
+ padding: 30,
backgroundColor: COLORS.background_user,
},
});
diff --git a/app/screens/user/ProductDetailsScreen.tsx b/app/screens/user/ProductDetailsScreen.tsx
index df4fba5..29650f1 100644
--- a/app/screens/user/ProductDetailsScreen.tsx
+++ b/app/screens/user/ProductDetailsScreen.tsx
@@ -5,8 +5,8 @@ import { useLocalSearchParams, useRouter } from 'expo-router';
import { ChevronLeft, Minus, Plus } from 'lucide-react-native';
import { doc, getDoc } from 'firebase/firestore';
import { db } from '@/firebase/config';
-import { useCart } from '@/app/context/cartContext';
-import { Product } from '@/app/constants/types';
+import { useCart } from '@/context/cartContext';
+import { Product } from '@/constants/types';
export default function ProductScreen() {
const { productId } = useLocalSearchParams();
@@ -55,12 +55,18 @@ export default function ProductScreen() {
const { addItem } = useCart();
const handleAddToCart = () => {
- if (!product) return;
+ if (!product) return;
- addItem({
- productName: product?.productName,
- quantity: quantity,
- });
+ addItem({
+ id: product.id,
+ name: product.productName,
+ quantity: quantity,
+ price: parseFloat(product.price), // Assure-toi que price est bien un number
+ image: product.image,
+ });
+
+
+
Alert.alert('Ajouté', `${quantity} ${product.productName} ajouté au panier`);
};
@@ -70,7 +76,7 @@ const handleAddToCart = () => {
{/* Header */}
- router.back()}>
+ router.push('/screens/user/GrainsScreen')}>
{product?.productName || 'Détails du produit'}
diff --git a/app/screens/user/ProfileScreen.tsx b/app/screens/user/ProfileScreen.tsx
index 92a8016..786f741 100644
--- a/app/screens/user/ProfileScreen.tsx
+++ b/app/screens/user/ProfileScreen.tsx
@@ -1,18 +1,48 @@
-import { View, Text, StyleSheet, ScrollView,TouchableOpacity } from 'react-native';
+import { View, Text, StyleSheet, ScrollView, TouchableOpacity, Alert } from 'react-native';
import { SafeAreaView } from 'react-native-safe-area-context';
import { ArrowLeft } from 'lucide-react-native';
import { router } from "expo-router";
-
+import { getAuth, signOut } from "firebase/auth";
export default function ProfileScreen() {
+ const handleSignOut = () => {
+ Alert.alert(
+ "Déconnexion",
+ "Êtes-vous sûr de vouloir vous déconnecter ?",
+ [
+ { text: "Annuler", style: "cancel" },
+ {
+ text: "Se déconnecter",
+ style: "destructive",
+ onPress: async () => {
+ try {
+ const auth = getAuth();
+ await signOut(auth);
+ router.replace('/'); // Replace with your actual sign-in screen route
+ } catch (error) {
+ Alert.alert("Erreur", "Impossible de se déconnecter.");
+ console.error("Sign out error:", error);
+ }
+ }
+ }
+ ]
+ );
+ };
+
return (
router.back()}>
- Espace Personel
-
+ Espace Personnel
+
+
+
+
+ Se déconnecter
+
+
);
}
@@ -30,7 +60,7 @@ const styles = StyleSheet.create({
backgroundColor: '#fff',
borderBottomWidth: 1,
borderBottomColor: '#eee',
- marginTop:5,
+ marginTop: 5,
},
backButton: {
position: 'absolute',
@@ -43,4 +73,20 @@ const styles = StyleSheet.create({
fontWeight: '600',
color: '#333',
},
-});
\ No newline at end of file
+ body: {
+ flex: 1,
+ justifyContent: 'center',
+ alignItems: 'center',
+ },
+ signOutButton: {
+ backgroundColor: '#B07B4F',
+ paddingVertical: 12,
+ paddingHorizontal: 24,
+ borderRadius: 10,
+ },
+ signOutButtonText: {
+ color: '#fff',
+ fontSize: 16,
+ fontWeight: '600',
+ },
+});
diff --git a/app/screens/user/UserHomeScreen.tsx b/app/screens/user/UserHomeScreen.tsx
index d096fde..731ce7c 100644
--- a/app/screens/user/UserHomeScreen.tsx
+++ b/app/screens/user/UserHomeScreen.tsx
@@ -1,12 +1,23 @@
-import { View, Text, StyleSheet, Image, } from 'react-native';
+import React, { useCallback } from 'react';
+import { View, Text, StyleSheet, Image,BackHandler } from 'react-native';
import { TouchableOpacity } from 'react-native-gesture-handler';
import { useRouter } from 'expo-router';
import { BellRing } from 'lucide-react-native';
-import COLORS from '@/app/constants/colors';
+import COLORS from '@/constants/colors';
+import { useFocusEffect } from '@react-navigation/native';
+
const UserHomeScreen = () => {
const router = useRouter();
+// Empêcher retour arrière
+useFocusEffect(
+ useCallback(() => {
+ const onBackPress = () => true;
+ BackHandler.addEventListener('hardwareBackPress', onBackPress);
+ return () => BackHandler.removeEventListener('hardwareBackPress', onBackPress);
+ }, [])
+);
return (
@@ -130,11 +141,3 @@ const styles = StyleSheet.create({
export default UserHomeScreen;
-/*
-
-
@@ -70,15 +67,23 @@ const styles = StyleSheet.create({
flexDirection: 'row',
backgroundColor: COLORS.secondary,
borderRadius: 12,
- marginBottom: 5,
- padding: 4,
+ marginBottom: 16,
+ padding: 16,
+ shadowColor: '#000',
+ shadowOffset: {
+ width: 0,
+ height: 2,
+ },
+ shadowOpacity: 0.2,
+ shadowRadius: 4,
+ elevation: 5,
},
imageContainer: {
width: 80,
height: 80,
borderRadius: 8,
overflow: 'hidden',
- marginRight: 2,
+ marginRight: 16,
},
image: {
width: '100%',
@@ -90,8 +95,9 @@ const styles = StyleSheet.create({
},
name: {
fontSize: 16,
- color: COLORS.text,
- marginBottom: 5,
+ fontWeight: 700,
+ color: '#000',
+ marginBottom: 8,
},
controlRow: {
flexDirection: 'row',
@@ -100,7 +106,7 @@ const styles = StyleSheet.create({
},
price: {
fontSize: 14,
- color: COLORS.secondary,
+ color: COLORS.primary,
},
});
diff --git a/app/components/ProductCard.tsx b/components/ProductCard.tsx
similarity index 98%
rename from app/components/ProductCard.tsx
rename to components/ProductCard.tsx
index f1469b1..9b4406a 100644
--- a/app/components/ProductCard.tsx
+++ b/components/ProductCard.tsx
@@ -1,7 +1,7 @@
import { View, Text, Image, StyleSheet, TouchableOpacity } from 'react-native';
import { useRouter } from 'expo-router';
import { ChevronRight } from 'lucide-react-native';
-import COLORS from '@/app/constants/colors';
+import COLORS from '@/constants/colors';
import { Product } from '../constants/types';
interface ProductCardProps {
diff --git a/app/components/QuantityControl.tsx b/components/QuantityControl.tsx
similarity index 83%
rename from app/components/QuantityControl.tsx
rename to components/QuantityControl.tsx
index 3e42cf7..b32402d 100644
--- a/app/components/QuantityControl.tsx
+++ b/components/QuantityControl.tsx
@@ -1,8 +1,7 @@
import React from 'react';
import { View, Text, TouchableOpacity, StyleSheet, Platform } from 'react-native';
-import COLORS from "@/app/constants/colors";
import { Minus, Plus } from 'lucide-react-native';
-import Animated, { useAnimatedStyle, withTiming } from 'react-native-reanimated';
+import Animated, { useAnimatedStyle, withTiming, withSequence } from 'react-native-reanimated';
import * as Haptics from 'expo-haptics';
interface QuantityControlProps {
@@ -45,7 +44,7 @@ const QuantityControl: React.FC = ({
onPress={handleDecrease}
disabled={quantity <= 0}
>
-
+
@@ -53,7 +52,7 @@ const QuantityControl: React.FC = ({
-
+
);
@@ -69,18 +68,18 @@ const styles = StyleSheet.create({
button: {
width: 36,
height: 36,
- backgroundColor: COLORS.secondary,
+ backgroundColor: '#E6D0B3',
justifyContent: 'center',
alignItems: 'center',
borderRadius: 6,
},
quantity: {
fontSize: 14,
- color: COLORS.text,
- paddingHorizontal: 6,
+ color: '#333333',
+ paddingHorizontal: 16,
minWidth: 40,
textAlign: 'center',
},
});
-export default QuantityControl;
+export default QuantityControl;
\ No newline at end of file
diff --git a/app/constants/colors.ts b/constants/colors.ts
similarity index 100%
rename from app/constants/colors.ts
rename to constants/colors.ts
diff --git a/app/constants/types.ts b/constants/types.ts
similarity index 94%
rename from app/constants/types.ts
rename to constants/types.ts
index 2c9ddb1..10974ce 100644
--- a/app/constants/types.ts
+++ b/constants/types.ts
@@ -10,7 +10,6 @@ export interface Product {
id: string;
name: string;
price: number;
- priceUnit: string;
quantity: number;
image: string;
}
diff --git a/app/context/cartContext.tsx b/context/cartContext.tsx
similarity index 53%
rename from app/context/cartContext.tsx
rename to context/cartContext.tsx
index 704f06f..093da5f 100644
--- a/app/context/cartContext.tsx
+++ b/context/cartContext.tsx
@@ -1,9 +1,11 @@
-// context/CartContext.tsx
import React, { createContext, useState, useContext, ReactNode } from 'react';
-type CartItem = {
- productName: string;
+export type CartItem = {
+ id: string;
+ name: string;
quantity: number;
+ price: number;
+ image: string;
};
type CartState = {
@@ -15,6 +17,7 @@ type CartContextType = {
cart: CartState;
addItem: (item: CartItem) => void;
clearCart: () => void;
+ updateQuantity: (id: string, quantity: number) => void;
};
const CartContext = createContext(undefined);
@@ -24,36 +27,45 @@ export const CartProvider = ({ children }: { children: ReactNode }) => {
const addItem = (item: CartItem) => {
setCart(prev => {
- const existing = prev.items.find(i => i.productName === item.productName);
+ const existing = prev.items.find(i => i.id === item.id);
let updatedItems;
+
if (existing) {
updatedItems = prev.items.map(i =>
- i.productName === item.productName
- ? { ...i, quantity: i.quantity + item.quantity }
- : i
+ i.id === item.id ? { ...i, quantity: i.quantity + item.quantity } : i
);
} else {
updatedItems = [...prev.items, item];
}
- const updatedTotal = updatedItems.reduce((sum, i) => sum + i.quantity, 0);
+
+ const updatedTotal = updatedItems.reduce((sum, i) => sum + i.quantity * i.price, 0);
return { items: updatedItems, total: updatedTotal };
});
};
const clearCart = () => setCart({ items: [], total: 0 });
+ const updateQuantity = (id: string, quantity: number) => {
+ setCart(prev => {
+ const updatedItems = prev.items.map(item =>
+ item.id === id ? { ...item, quantity } : item
+ );
+ const updatedTotal = updatedItems.reduce((sum, i) => sum + i.quantity * i.price, 0);
+ return { items: updatedItems, total: updatedTotal };
+ });
+ };
+
return (
-
+
{children}
);
};
export const useCart = () => {
- const context = useContext(CartContext);
- if (!context) {
- throw new Error('useCart must be used within a CartProvider');
- }
- return context;
- };
-
+ const context = useContext(CartContext);
+ if (!context) {
+ throw new Error('useCart must be used within a CartProvider');
+ }
+ return context;
+};
diff --git a/firebase/auth.ts b/firebase/auth.ts
index a475b57..6cdfbbb 100644
--- a/firebase/auth.ts
+++ b/firebase/auth.ts
@@ -1,9 +1,6 @@
-import { getAuth, signInWithEmailAndPassword, createUserWithEmailAndPassword } from "firebase/auth";
-import { app } from "./config"; // ton fichier config Firebase
-
-
-
-const auth = getAuth(app);
+// auth.ts
+import { signInWithEmailAndPassword, createUserWithEmailAndPassword } from "firebase/auth";
+import { auth } from "./config";
export const signIn = async (email: string, password: string) => {
try {
@@ -14,7 +11,6 @@ export const signIn = async (email: string, password: string) => {
}
};
-
export const signUp = async (email: string, password: string) => {
try {
const userCredential = await createUserWithEmailAndPassword(auth, email, password);
diff --git a/firebase/config.ts b/firebase/config.ts
index dc66a1d..658e810 100644
--- a/firebase/config.ts
+++ b/firebase/config.ts
@@ -1,8 +1,11 @@
-// firebase/config.ts
import { FirebaseApp, initializeApp } from 'firebase/app';
import { getFirestore } from 'firebase/firestore';
+import { getAuth, initializeAuth } from 'firebase/auth';
+import AsyncStorage from '@react-native-async-storage/async-storage';
+import * as firebaseAuth from 'firebase/auth';
+const reactNativePersistence = (firebaseAuth as any).getReactNativePersistence;
-
+// Configuration Firebase
const firebaseConfig = {
apiKey: 'AIzaSyDHoF8Eahk60s3APh7WxohL1bya_44v39k',
authDomain: 'brix-cafe-2ddf1.firebaseapp.com',
@@ -15,5 +18,13 @@ const firebaseConfig = {
const app: FirebaseApp = initializeApp(firebaseConfig);
-export const db = getFirestore(app);
-export { app };
+// Initialiser Auth avec persistance
+const auth = initializeAuth(app, {
+ persistence: reactNativePersistence(AsyncStorage),
+});
+
+
+// Initialiser Firestore
+const db = getFirestore(app);
+
+export { app, db, auth };
diff --git a/firebase/session.ts b/firebase/session.ts
index e092980..b5b10ff 100644
--- a/firebase/session.ts
+++ b/firebase/session.ts
@@ -1,9 +1,6 @@
-// firebase/session.ts
-import { getAuth, onAuthStateChanged, User } from "firebase/auth";
+import { onAuthStateChanged, User } from "firebase/auth";
import AsyncStorage from "@react-native-async-storage/async-storage";
-import { app } from "./config";
-
-const auth = getAuth(app);
+import { auth } from "./config";
export const monitorAuthState = (onUserChange: (user: User | null) => void) => {
onAuthStateChanged(auth, async (user) => {
@@ -16,8 +13,3 @@ export const monitorAuthState = (onUserChange: (user: User | null) => void) => {
}
});
};
-
-export const getStoredUser = async (): Promise => {
- const json = await AsyncStorage.getItem("user");
- return json ? JSON.parse(json) : null;
-};
diff --git a/package-lock.json b/package-lock.json
index 1a07850..ca16a53 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9,7 +9,7 @@
"version": "1.0.0",
"dependencies": {
"@expo/vector-icons": "^14.0.2",
- "@react-native-async-storage/async-storage": "1.23.1",
+ "@react-native-async-storage/async-storage": "^1.23.1",
"@react-navigation/bottom-tabs": "^7.2.0",
"@react-navigation/native": "^7.0.14",
"expo": "~52.0.46",
diff --git a/package.json b/package.json
index 37d5bd7..9fa54c4 100644
--- a/package.json
+++ b/package.json
@@ -16,7 +16,7 @@
},
"dependencies": {
"@expo/vector-icons": "^14.0.2",
- "@react-native-async-storage/async-storage": "1.23.1",
+ "@react-native-async-storage/async-storage": "^1.23.1",
"@react-navigation/bottom-tabs": "^7.2.0",
"@react-navigation/native": "^7.0.14",
"expo": "~52.0.46",
diff --git a/app/utils/cartUtils.tsx b/utils/cartUtils.ts
similarity index 90%
rename from app/utils/cartUtils.tsx
rename to utils/cartUtils.ts
index 3dd6435..b6ee563 100644
--- a/app/utils/cartUtils.tsx
+++ b/utils/cartUtils.ts
@@ -1,4 +1,4 @@
-import { CartItem } from '@/app/constants/types';
+import { CartItem } from '@/constants/types';
export const calculateTotal = (items: CartItem[]): number => {
return items.reduce((total, item) => {