import React, { useEffect, useMemo, useRef, useState } from 'react'; import { View, Text, ScrollView, TouchableOpacity, Image, TextInput, LayoutAnimation, Platform, UIManager, Animated, StatusBar, } from 'react-native'; import { useNavigation } from '@react-navigation/native'; import { StackNavigationProp } from '@react-navigation/stack'; import { getStyles } from './cartScreen.styles'; import { Header, QuantitySelector, PrimaryButton } from '@components'; import { useAppTheme } from '@theme'; import { selectCartTotal, getCartThunk, updateCartItemThunk, } from '../../../store/commonreducers/cart'; import { AppStackParamList } from '../../../navigation/appStack'; import { useAppDispatch, useAppSelector } from '@store'; import { getFullUrl } from '@utils'; if (Platform.OS === 'android' && UIManager.setLayoutAnimationEnabledExperimental) { UIManager.setLayoutAnimationEnabledExperimental(true); } type CartScreenNavProp = StackNavigationProp; const TIP_OPTIONS = [20, 30, 50, 100]; // ─── Skeleton shimmer ────────────────────────────────────────────────────────── const SkeletonBlock: React.FC<{ width?: number | string; height?: number; borderRadius?: number; colors: any }> = ({ width = '100%', height = 16, borderRadius = 8, colors, }) => { const shimmer = useRef(new Animated.Value(0)).current; useEffect(() => { const loop = Animated.loop( Animated.sequence([ Animated.timing(shimmer, { toValue: 1, duration: 900, useNativeDriver: true }), Animated.timing(shimmer, { toValue: 0, duration: 900, useNativeDriver: true }), ]), ); loop.start(); return () => loop.stop(); }, [shimmer]); const opacity = shimmer.interpolate({ inputRange: [0, 1], outputRange: [0.3, 0.7] }); return ( ); }; // ─── Savings pill ────────────────────────────────────────────────────────────── const SavingsPill: React.FC<{ label: string; styles: any }> = ({ label, styles }) => ( 🎉 {label} ); // ─── Section Header ──────────────────────────────────────────────────────────── const SectionTitle: React.FC<{ label: string; styles: any }> = ({ label, styles }) => ( {label} ); // ─── Main Component ──────────────────────────────────────────────────────────── export const CartScreen: React.FC = () => { const { colors, isDarkMode } = useAppTheme(); const styles = getStyles(colors); const dispatch = useAppDispatch(); const navigation = useNavigation(); const { items, isLoading } = useAppSelector(state => state.cart); const totals = useAppSelector(selectCartTotal); const [instructions, setInstructions] = useState(''); const [showInstructionsInput, setShowInstructionsInput] = useState(false); const [selectedTip, setSelectedTip] = useState(null); const [couponInput, setCouponInput] = useState(''); const [billExpanded, setBillExpanded] = useState(false); // Animated values const fadeAnim = useRef(new Animated.Value(0)).current; const slideAnim = useRef(new Animated.Value(30)).current; const bottomPanelAnim = useRef(new Animated.Value(100)).current; useEffect(() => { dispatch(getCartThunk()); }, [dispatch]); useEffect(() => { if (!isLoading) { Animated.parallel([ Animated.timing(fadeAnim, { toValue: 1, duration: 400, useNativeDriver: true }), Animated.spring(slideAnim, { toValue: 0, useNativeDriver: true, tension: 80, friction: 10 }), Animated.spring(bottomPanelAnim, { toValue: 0, useNativeDriver: true, tension: 80, friction: 12 }), ]).start(); } }, [isLoading, fadeAnim, slideAnim, bottomPanelAnim]); const itemCount = useMemo( () => items.reduce((sum, item) => sum + item.quantity, 0), [items], ); const tipAmount = selectedTip ?? 0; const grandTotal = (totals.total ?? 0) + tipAmount; const toggleBillExpanded = () => { LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut); setBillExpanded(prev => !prev); }; // ─── Empty state ────────────────────────────────────────────────────────────── if (!isLoading && items.length === 0) { return (
navigation.goBack()} /> 🛒 Your cart is empty Looks like you haven't added anything yet.{'\n'}Browse and find something you'll love! navigation.goBack()} > Browse Menu ); } // ─── Loading skeleton ───────────────────────────────────────────────────────── if (isLoading) { return (
navigation.goBack()} /> {[1, 2, 3].map(i => ( ))} ); } // ─── Main Cart View ─────────────────────────────────────────────────────────── return (
navigation.goBack()} /> {/* ── ETA Banner ─────────────────────────────────────────── */} 🛵 Delivery in 20–25 mins Order arrives fresh & hot 🔥 FASTEST {/* ── Items Card ─────────────────────────────────────────── */} {itemCount} {itemCount === 1 ? 'item' : 'items'} in your cart {items.map((item, index) => ( {/* Veg / Non-veg indicator */} {/* {typeof item.product === 'boolean' && ( )} */} {/* Thumbnail */} {/* Info */} {item.product.name} ₹{item.product.price} {/* {!!item.product.mrp && item.product.mrp > item.product.price && ( <> ₹{item.product.mrp} {Math.round(((item.product.mrp - item.product.price) / item.product.mrp) * 100)}% OFF )} */} {/* Quantity */} dispatch( updateCartItemThunk({ productId: item.productId, quantity: item.quantity + 1, }), ) } onDecrement={() => { if (item.quantity >= 1) { dispatch( updateCartItemThunk({ productId: item.productId, quantity: item.quantity - 1, }), ); } }} /> ))} {/* Add more items */} navigation.goBack()} > Add more items {/* ── Savings if any ─────────────────────────────────────── */} {totals.discount > 0 && ( )} {/* ── Coupons & Offers ───────────────────────────────────── */} {totals.discount > 0 ? ( 🏷️ Coupon Applied! You saved ₹{totals.discount} on this order Remove ) : ( 🎁 Apply navigation.navigate('MainTabs', { screen: 'OffersScreen' })}> 🔖 View all available offers )} {/* ── Order Instructions ─────────────────────────────────── */} {/* {showInstructionsInput ? ( setShowInstructionsInput(false)} /> ) : ( setShowInstructionsInput(true)} > 📝 {instructions || 'Add a note for the rider or restaurant'} )} */} {/* ── Tip Your Delivery Partner ──────────────────────────── */} {/* 100% of the tip goes directly to your delivery partner. They work hard so your food arrives hot! {TIP_OPTIONS.map(amount => ( setSelectedTip(prev => (prev === amount ? null : amount)) } > {selectedTip === amount && ( )} ₹{amount} ))} {selectedTip !== null && ( setSelectedTip(null)} > ✕ Remove tip )} */} {/* ── Bill Details ───────────────────────────────────────── */} Item Total ₹{totals.subtotal} Delivery Fee ₹{totals.deliveryFee} {billExpanded && ( Delivery fee helps cover your delivery partner's costs. GST as applicable is included in the item total. )} Platform Fee ₹{totals.platformFee} {tipAmount > 0 && ( Delivery Tip 💛 ₹{tipAmount} )} {totals.discount > 0 && ( Coupon Discount − ₹{totals.discount} )} To Pay {totals.discount > 0 && ( Saved ₹{totals.discount} )} ₹{grandTotal} {/* ── Cancellation Policy ────────────────────────────────── */} 🛈 Orders cannot be cancelled once packed for delivery. In case of unexpected delays, a refund will be provided, if applicable. {/* ── Bottom Panel ───────────────────────────────────────────── */} {itemCount} {itemCount === 1 ? 'item' : 'items'} ₹{grandTotal} {totals.discount > 0 && ( saved ₹{totals.discount} )} navigation.navigate('CheckoutAddressScreen')} style={styles.checkoutButton} /> ); };