186 lines
No EOL
6.1 KiB
TypeScript
186 lines
No EOL
6.1 KiB
TypeScript
import React, { useState } from "react";
|
|
import {
|
|
View,
|
|
Dimensions,
|
|
Image,
|
|
Platform,
|
|
Alert,
|
|
ScrollView,
|
|
} from "react-native";
|
|
import { LinearGradient } from "expo-linear-gradient";
|
|
import { useRouter } from "expo-router";
|
|
import {
|
|
theme,
|
|
tw,
|
|
useManualRefresh,
|
|
useMarkDataFetchers,
|
|
LoadingDialog,
|
|
AppContainer,
|
|
MyFlatList,
|
|
MyText,
|
|
} from "common-ui";
|
|
import MaterialIcons from "@expo/vector-icons/MaterialIcons";
|
|
import ProductCard from "@/components/ProductCard";
|
|
|
|
import { trpc } from "@/src/trpc-client";
|
|
import { useGetCart, useAddToCart } from '@/hooks/cart-query-hooks';
|
|
import { useProductSlotIdentifier } from '@/hooks/useProductSlotIdentifier';
|
|
import FloatingCartBar from "@/components/floating-cart-bar";
|
|
import TabLayoutWrapper from "@/components/TabLayoutWrapper";
|
|
|
|
const { width: screenWidth } = Dimensions.get("window");
|
|
const itemWidth = (screenWidth - 48) / 2; // 2 items per row with padding
|
|
|
|
export default function OrderAgain() {
|
|
const router = useRouter();
|
|
const [isLoadingDialogOpen, setIsLoadingDialogOpen] = useState(false);
|
|
|
|
const {
|
|
data: recentProductsData,
|
|
isLoading,
|
|
error,
|
|
refetch,
|
|
} = trpc.user.order.getRecentlyOrderedProducts.useQuery({
|
|
limit: 20,
|
|
});
|
|
|
|
|
|
|
|
const { data: cartData, refetch: refetchCart } = useGetCart();
|
|
const { addToCart = () => {} } = useAddToCart({ showSuccessAlert: false, showErrorAlert: false, refetchCart: true }) || {};
|
|
const { getQuickestSlot } = useProductSlotIdentifier();
|
|
|
|
const recentProducts = recentProductsData?.products || [];
|
|
|
|
useManualRefresh(() => {
|
|
refetch();
|
|
});
|
|
|
|
useMarkDataFetchers(() => {
|
|
refetch();
|
|
});
|
|
|
|
const handleAddToCart = (productId: number) => {
|
|
const slotId = getQuickestSlot(productId);
|
|
if (!slotId) {
|
|
Alert.alert("Error", "No available delivery slot for this product");
|
|
return;
|
|
}
|
|
|
|
setIsLoadingDialogOpen(true);
|
|
addToCart(productId, 1, slotId, () => setIsLoadingDialogOpen(false));
|
|
};
|
|
|
|
const handleBuyNow = (productId: number) => {
|
|
const slotId = getQuickestSlot(productId);
|
|
if (!slotId) {
|
|
Alert.alert("Error", "No available delivery slot for this product");
|
|
return;
|
|
}
|
|
|
|
setIsLoadingDialogOpen(true);
|
|
addToCart(productId, 1, slotId, () => {
|
|
setIsLoadingDialogOpen(false);
|
|
router.push(`/(drawer)/(tabs)/home/cart?select=${productId}`);
|
|
});
|
|
};
|
|
|
|
if (isLoading) {
|
|
return (
|
|
<AppContainer>
|
|
<View style={tw`flex-1 justify-center items-center bg-gray-50`}>
|
|
<MaterialIcons name="refresh" size={48} color="#3B82F6" />
|
|
<MyText style={tw`text-gray-500 font-medium mt-4`}>Loading your recent orders...</MyText>
|
|
</View>
|
|
</AppContainer>
|
|
);
|
|
}
|
|
|
|
if (error) {
|
|
return (
|
|
<AppContainer>
|
|
<View style={tw`flex-1 justify-center items-center bg-gray-50`}>
|
|
<MaterialIcons name="error-outline" size={48} color="#EF4444" />
|
|
<MyText style={tw`text-gray-900 text-lg font-bold mt-4`}>Oops!</MyText>
|
|
<MyText style={tw`text-gray-500 mt-2`}>Failed to load recent orders</MyText>
|
|
</View>
|
|
</AppContainer>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<TabLayoutWrapper>
|
|
<ScrollView style={tw`flex-1`} contentContainerStyle={tw`pb-20`}>
|
|
<LinearGradient
|
|
colors={['#194185', '#1570EF']} // brand900 to brand600
|
|
start={{ x: 0, y: 0 }}
|
|
end={{ x: 1, y: 1 }}
|
|
style={tw`pb-8 pt-6 px-5 rounded-b-[32px] shadow-lg mb-4`}
|
|
>
|
|
<View style={tw`flex-row justify-between items-start mb-6`}>
|
|
<View style={tw`flex-1 mr-4`}>
|
|
<View style={tw`flex-row items-center mb-1`}>
|
|
<View style={tw`bg-white/20 p-1 rounded-full mr-2`}>
|
|
<MaterialIcons name="refresh" size={14} color="#FFF" />
|
|
</View>
|
|
<MyText style={tw`text-brand100 text-xs font-bold uppercase tracking-widest`}>
|
|
Order Again
|
|
</MyText>
|
|
</View>
|
|
<MyText style={tw`text-white text-sm font-medium opacity-90 ml-1`} numberOfLines={1}>
|
|
Reorder your favorite items quickly
|
|
</MyText>
|
|
</View>
|
|
</View>
|
|
</LinearGradient>
|
|
|
|
{/* White Section */}
|
|
<View style={tw`bg-white`}>
|
|
{/* Section Title */}
|
|
<View style={tw`flex-row items-center mb-2 px-4 pt-4`}>
|
|
<MyText style={tw`text-lg font-bold text-gray-900`}>Recently Ordered</MyText>
|
|
</View>
|
|
|
|
{recentProducts.length === 0 ? (
|
|
<View style={tw`items-center justify-center py-12`}>
|
|
<View
|
|
style={tw`w-20 h-20 bg-gray-100 rounded-full items-center justify-center mb-4`}
|
|
>
|
|
<MaterialIcons name="shopping-bag" size={32} color="#9CA3AF" />
|
|
</View>
|
|
<MyText style={tw`text-lg font-bold text-gray-900`}>
|
|
No recent orders
|
|
</MyText>
|
|
<MyText style={tw`text-gray-500 mt-2 text-center px-8`}>
|
|
Items you've ordered recently will appear here
|
|
</MyText>
|
|
</View>
|
|
) : (
|
|
<View style={tw`px-4 pb-4`}>
|
|
<View style={tw`flex-row flex-wrap justify-between`}>
|
|
{recentProducts.map((item, index) => (
|
|
<View key={item.id} style={tw`mb-4 ${index % 2 === 0 ? 'mr-2' : ''}`}>
|
|
<ProductCard
|
|
item={item}
|
|
// handleAddToCart={handleAddToCart}
|
|
// handleBuyNow={handleBuyNow}
|
|
itemWidth={itemWidth}
|
|
onPress={() => router.push(`/(drawer)/(tabs)/order-again/product-detail/${item.id}`)}
|
|
showDeliveryInfo={false}
|
|
// iconType="flash"
|
|
/>
|
|
</View>
|
|
))}
|
|
</View>
|
|
</View>
|
|
)}
|
|
</View>
|
|
</ScrollView>
|
|
|
|
<LoadingDialog open={isLoadingDialogOpen} message="Adding to cart..." />
|
|
<View style={tw`absolute bottom-2 left-4 right-4`}>
|
|
<FloatingCartBar />
|
|
</View>
|
|
</TabLayoutWrapper>
|
|
);
|
|
} |