import React, { useState, useCallback, useEffect } from 'react'; import { View, FlatList, Alert, ActivityIndicator } from 'react-native'; import { Image } from 'expo-image'; import { MaterialIcons, Ionicons } from '@expo/vector-icons'; import { useRouter } from 'expo-router'; import { tw, useManualRefresh, MyText, MyFlatList, useMarkDataFetchers, REFUND_STATUS, MyTouchableOpacity, theme } from 'common-ui'; import { trpc } from '@/src/trpc-client'; // import RazorpayCheckout from 'react-native-razorpay'; import OrderMenu from '@/components/OrderMenu'; import dayjs from 'dayjs'; // Type definitions interface OrderItem { productName: string; quantity: number; price: number; amount: number; image: string | null; } interface Order { id: number; orderId: string; orderDate: string; deliveryStatus: string; deliveryDate?: string; orderStatus: string; cancelReason: string | null; totalAmount: number; deliveryCharge: number; paymentMode: string; paymentStatus: string; refundStatus: string; refundAmount: number | null; userNotes: string | null; items: OrderItem[]; discountAmount?: number; isFlashDelivery: boolean; createdAt: string; } interface OrderFooterProps { isLoadingMore: boolean; loadMoreError: string | null; hasNextPage: boolean; allOrders: Order[]; onRetryLoadMore: () => void; } const OrderFooter: React.FC = ({ isLoadingMore, loadMoreError, hasNextPage, allOrders, onRetryLoadMore }) => { if (isLoadingMore) { return ( Loading more orders... ); } if (loadMoreError) { return ( {loadMoreError} Retry ); } if (!hasNextPage && allOrders.length > 0) { return ( End of list ); } return null; }; interface OrderItemProps { item: Order; index: number; getStatusColor: (status: string) => any; getRefundStatusColor: (status: string) => any; onPress: (orderId: number) => void; onRetryPayment: (orderId: number) => void; onViewMoreItems: (orderId: number) => void; isPaymentPending: boolean; } const OrderItem: React.FC = ({ item, index, getStatusColor, getRefundStatusColor, onPress, onRetryPayment, onViewMoreItems, isPaymentPending }) => { const mainStatus = getStatusColor(item.orderStatus); const deliveryStatus = getStatusColor(item.deliveryStatus); const totalAmount = item.totalAmount; return ( onPress(item.id)} activeOpacity={0.95} > {/* Top Header: Order ID and Status */} Order Reference #{item.orderId} {item.orderStatus.toLowerCase() === 'cancelled' && ( {mainStatus.label} )} {item.isFlashDelivery && ( FLASH )} {/* Order Date & Quick Stats */} {(item.deliveryDate || item.isFlashDelivery) && ( {item.isFlashDelivery ? ( ) : ( )} {item.isFlashDelivery ? "Flash Delivery" : "Delivery Time"} {item.isFlashDelivery ? dayjs(item.createdAt || item.orderDate).add(30, 'minutes').format("DD MMM, hh:mm A") : dayjs(item.deliveryDate).format("DD MMM, hh:mm A") } {item.isFlashDelivery && ( ⚡ 30-Min Delivery )} )} Placed On {dayjs(item.orderDate).format("DD MMM YYYY, hh:mm A")} { // refetch will be handled by parent }} /> {/* Items Section */} Items Summary {item.items.length} {item.items.length === 1 ? 'Item' : 'Items'} {item.items.slice(0, 2).map((product, index) => ( {product.quantity} {product.productName} Unit Price: ₹{product.price} ₹{product.amount} ))} {item.items.length > 2 && ( onViewMoreItems(item.id)} > + {item.items.length - 2} more {item.items.length - 2 === 1 ? 'item' : 'items'} in this order )} {/* Delivery Status - Single Line */} {item.isFlashDelivery ? ( ) : ( )} {item.isFlashDelivery ? "Flash Delivery:" : "Shipping Status:"} {item.deliveryStatus} {item.isFlashDelivery && ( ⚡ FAST )} {/* User Notes or Delivery Time if present */} {item.userNotes && ( Your Instructions {item.userNotes} )} {/* Cancellation Info */} {item.cancelReason && ( Cancellation Details {item.cancelReason} {item.refundStatus && item.refundStatus !== REFUND_STATUS.NOT_APPLICABLE && ( Refund Status {item.refundStatus} )} )} {/* Footer: Price and CTA */} Amount to Pay ₹{totalAmount} {item.discountAmount ? ( Saved ₹{item.discountAmount} ) : null} {item.deliveryCharge > 0 && ( Delivery: ₹{item.deliveryCharge} )} {(item.paymentMode === 'Online' && (item.paymentStatus === 'pending' || item.paymentStatus === 'failed')) ? ( { e.stopPropagation(); onRetryPayment(item.id); }} disabled={isPaymentPending} style={tw`bg-rose-600 px-6 py-3 rounded-2xl shadow-lg shadow-rose-200 flex-row items-center`} > {isPaymentPending ? ( ) : ( <> Retry Payment )} ) : ( View Details )} ); }; export default function MyOrders() { const router = useRouter(); // Infinite scroll state const [allOrders, setAllOrders] = useState([]); const [currentPage, setCurrentPage] = useState(1); const [isLoadingMore, setIsLoadingMore] = useState(false); const [hasNextPage, setHasNextPage] = useState(true); const [loadMoreError, setLoadMoreError] = useState(null); const pageSize = 10; const { data: ordersData, isLoading, error, refetch } = trpc.user.order.getOrders.useQuery({ page: currentPage, pageSize: pageSize, }); const createRazorpayOrderMutation = trpc.user.payment.createRazorpayOrder.useMutation({ onSuccess: (paymentData) => { const order = allOrders.find(o => o.id === retryOrderId); if (order) { const totalAmount = order.items.reduce((sum, p) => sum + p.amount, 0); // initiateRazorpayPayment(paymentData.razorpayOrderId, paymentData.key, totalAmount); } }, onError: (error: any) => { Alert.alert('Error', error.message || 'Failed to create payment order'); }, }); const verifyPaymentMutation = trpc.user.payment.verifyPayment.useMutation({ onSuccess: () => { refetch(); Alert.alert('Success', 'Payment completed successfully'); }, onError: (error: any) => { Alert.alert('Error', error.message || 'Payment verification failed'); refetch(); }, }); // Handle data accumulation for infinite scroll useEffect(() => { if (ordersData?.data) { if (currentPage === 1) { // First page - replace all orders setAllOrders(ordersData.data); } else { // Subsequent pages - append to existing orders setAllOrders(prev => [...prev, ...ordersData.data]); } // Check if there are more pages const totalPages = ordersData.pagination?.totalPages || 1; setHasNextPage(currentPage < totalPages); setIsLoadingMore(false); setLoadMoreError(null); // Clear any previous errors } }, [ordersData, currentPage]); // Handle errors during infinite scroll loading useEffect(() => { if (error && currentPage > 1) { // If there's an error loading more pages, show error state setIsLoadingMore(false); setLoadMoreError('Failed to load more orders. Please try again.'); } }, [error, currentPage]); // Reset to first page on manual refresh useManualRefresh(() => { setCurrentPage(1); setAllOrders([]); setHasNextPage(true); setIsLoadingMore(false); setLoadMoreError(null); refetch(); }); useMarkDataFetchers(() => { setCurrentPage(1); setAllOrders([]); setHasNextPage(true); setIsLoadingMore(false); setLoadMoreError(null); refetch(); }); const [dialogOpen, setDialogOpen] = useState(false); const [dialogItems, setDialogItems] = useState([]); const [retryOrderId, setRetryOrderId] = useState(0); const openDialog = useCallback((items: OrderItem[]) => { setDialogItems(items); setDialogOpen(true); }, []); // Infinite scroll functions const loadMoreOrders = useCallback(() => { if (!isLoadingMore && hasNextPage && !isLoading) { setIsLoadingMore(true); setCurrentPage(prev => prev + 1); } }, [isLoadingMore, hasNextPage, isLoading]); const getStatusColor = (status: string) => { const s = status.toLowerCase(); switch (s) { case 'delivered': case 'success': case 'completed': return { bg: 'bg-emerald-50', text: 'text-emerald-700', icon: 'check-circle', color: '#059669', border: 'border-emerald-100', label: 'Delivered' }; case 'cancelled': case 'failed': return { bg: 'bg-rose-50', text: 'text-rose-700', icon: 'cancel', color: '#E11D48', border: 'border-rose-100', label: 'Cancelled' }; case 'pending': case 'payment_pending': return { bg: 'bg-amber-50', text: 'text-amber-700', icon: 'schedule', color: '#D97706', border: 'border-amber-100', label: 'Pending' }; case 'packaged': return { bg: 'bg-brand50', text: 'text-brand700', icon: 'inventory', color: '#1570EF', border: 'border-brand100', label: 'Packaged' }; case 'processing': case 'confirmed': case 'shipped': return { bg: 'bg-brand50', text: 'text-brand700', icon: 'local-shipping', color: '#1570EF', border: 'border-brand100', label: status.charAt(0).toUpperCase() + status.slice(1) }; default: return { bg: 'bg-slate-50', text: 'text-slate-700', icon: 'info', color: '#64748B', border: 'border-slate-100', label: status }; } }; const getRefundStatusColor = (status: string) => { switch (status) { case REFUND_STATUS.SUCCESS: return { bg: 'bg-emerald-50', text: 'text-emerald-700', icon: 'check-circle', color: '#059669', border: 'border-emerald-100' }; case REFUND_STATUS.PROCESSING: return { bg: 'bg-brand50', text: 'text-brand700', icon: 'refresh', color: '#1570EF', border: 'border-brand100' }; case REFUND_STATUS.PENDING: return { bg: 'bg-amber-50', text: 'text-amber-700', icon: 'schedule', color: '#D97706', border: 'border-amber-100' }; case REFUND_STATUS.NOT_APPLICABLE: return { bg: 'bg-slate-50', text: 'text-slate-700', icon: 'info', color: '#64748B', border: 'border-slate-100' }; default: return { bg: 'bg-slate-50', text: 'text-slate-700', icon: 'info', color: '#64748B', border: 'border-slate-100' }; } }; const handleRetryPayment = (orderId: number) => { setRetryOrderId(orderId); createRazorpayOrderMutation.mutate({ orderId: orderId.toString() }); }; // const initiateRazorpayPayment = (razorpayOrderId: string, key: string, amount: number) => { // const options = { // key, // amount: amount * 100, // in paisa // currency: 'INR', // order_id: razorpayOrderId, // name: 'Meat Farmer', // description: 'Order Payment Retry', // prefill: { // // Add user details if available // }, // }; // RazorpayCheckout.open(options) // .then((data: any) => { // // Payment success // verifyPaymentMutation.mutate({ // razorpay_payment_id: data.razorpay_payment_id, // razorpay_order_id: data.razorpay_order_id, // razorpay_signature: data.razorpay_signature, // }); // }) // .catch((error: any) => { // Alert.alert('Payment Failed', 'Payment failed. Please try again.'); // refetch(); // }); // }; if (isLoading && currentPage === 1) { return ( Loading your orders... ); } if (error) { return ( Unable to load orders Please check your connection and try again refetch()} style={tw`bg-blue-600 px-8 py-3 rounded-full shadow-md`} > Retry ); } return ( ( router.push(`/(drawer)/(tabs)/me/my-orders/${orderId}`)} onRetryPayment={handleRetryPayment} onViewMoreItems={(orderId) => router.push(`/(drawer)/(tabs)/me/my-orders/${orderId}`)} isPaymentPending={createRazorpayOrderMutation.isPending} /> )} keyExtractor={(item) => item.orderId} showsVerticalScrollIndicator={false} onEndReached={loadMoreOrders} onEndReachedThreshold={0.5} ListFooterComponent={ { setLoadMoreError(null); loadMoreOrders(); }} /> } ListEmptyComponent={ No orders yet Your order history will appear here router.push('/(drawer)/(tabs)/home')} > Start Shopping } /> ); }