freshyo/apps/user-ui/app/(drawer)/(tabs)/stores/index.tsx
2026-01-24 00:13:15 +05:30

235 lines
No EOL
8.7 KiB
TypeScript

import React, { useState } from "react";
import {
View,
FlatList,
} from "react-native";
import { Image } from 'expo-image';
import { useRouter } from "expo-router";
import {
theme,
tw,
useManualRefresh,
useMarkDataFetchers,
MyFlatList,
MyText,
MyTouchableOpacity,
} from "common-ui";
import MaterialIcons from "@expo/vector-icons/MaterialIcons";
import { Ionicons } from "@expo/vector-icons";
import { trpc } from "@/src/trpc-client";
import { LinearGradient } from "expo-linear-gradient";
import TabLayoutWrapper from "@/components/TabLayoutWrapper";
import FloatingCartBar from "@/components/floating-cart-bar";
import { useFocusEffect } from "expo-router";
import { useNavigationStore } from "@/src/store/navigationStore";
const StoreCard = ({
item,
router,
}: {
item: any;
router: any;
}) => {
const sampleProducts = item.sampleProducts || [];
const remainingCount = item.productCount - sampleProducts.length;
const navigateToStore = () => router.push(`/(drawer)/(tabs)/stores/store-detail/${item.id}`);
return (
<View
style={tw`bg-white rounded-[24px] mb-4 shadow-lg shadow-slate-200 border border-slate-200 overflow-hidden`}
>
{/* Top Header Section - Touchable */}
<MyTouchableOpacity
onPress={navigateToStore}
activeOpacity={0.7}
style={tw`p-4 pb-0`}
>
<View style={tw`flex-row items-center mb-4`}>
<View style={tw`w-12 h-12 rounded-xl bg-slate-50 border border-slate-200 p-0.5 shadow-sm`}>
<Image
source={{ uri: item.signedImageUrl || undefined }}
style={tw`w-full h-full rounded-[10px]`}
contentFit="cover"
/>
{!item.signedImageUrl && (
<View style={tw`absolute inset-0 items-center justify-center`}>
<MaterialIcons name="storefront" size={20} color="#94A3B8" />
</View>
)}
</View>
<View style={tw`flex-1 ml-3`}>
<MyText style={tw`text-slate-900 font-extrabold text-lg`} numberOfLines={1}>
{item.name}
</MyText>
</View>
<View style={tw`bg-brand50 px-2.5 py-1.5 rounded-xl border border-brand100 items-center justify-center`}>
<MyText style={tw`text-brand700 text-sm font-black`}>{item.productCount}</MyText>
<MyText style={tw`text-brand600 text-[8px] font-black uppercase tracking-tighter`}>Items</MyText>
</View>
</View>
</MyTouchableOpacity>
{/* Horizontal Scrollable Product Collection */}
<View style={tw`mb-5`}>
<FlatList
data={sampleProducts}
horizontal
showsHorizontalScrollIndicator={false}
contentContainerStyle={tw`px-4`}
keyExtractor={(product) => product.id.toString()}
renderItem={({ item: product }) => (
<MyTouchableOpacity
onPress={navigateToStore}
activeOpacity={0.85}
style={tw`mr-3 items-center w-24`}
>
<View style={tw`bg-slate-50 rounded-2xl p-1 border border-slate-200 w-24 h-24 mb-2 shadow-sm`}>
<Image
source={{ uri: product.signedImageUrl || undefined }}
style={tw`w-full h-full rounded-xl`}
contentFit="cover"
transition={200}
/>
</View>
<MyText style={tw`text-slate-900 text-[10px] font-black leading-tight text-center`} numberOfLines={2}>
{product.name}
</MyText>
</MyTouchableOpacity>
)}
ListFooterComponent={remainingCount > 0 ? (
<View style={tw`items-center justify-center`}>
<MyTouchableOpacity
onPress={navigateToStore}
style={tw`bg-slate-900 w-24 h-24 rounded-2xl items-center justify-center shadow-md`}
>
<MyText style={tw`text-white text-base font-black`}>+{remainingCount}</MyText>
<MyText style={tw`text-white/60 text-[8px] font-black uppercase tracking-widest`}>Discover</MyText>
<MaterialIcons name="arrow-forward" size={16} color="white" style={tw`mt-1`} />
</MyTouchableOpacity>
<View style={tw`h-8`} />
</View>
) : null}
/>
</View>
<View style={tw`px-4 pb-4`}>
<MyTouchableOpacity
onPress={navigateToStore}
activeOpacity={0.9}
style={tw`bg-brand600 py-3 rounded-[18px] flex-row items-center justify-center shadow-lg shadow-brand200`}
>
<MyText style={tw`text-white text-sm font-black uppercase tracking-wider mr-2`}>Explore Store</MyText>
<Ionicons name="arrow-forward" size={18} color="white" />
</MyTouchableOpacity>
</View>
</View>
);
};
export default function Stores() {
const router = useRouter();
const {
data: storesData,
isLoading,
error,
refetch,
} = trpc.user.stores.getStores.useQuery();
const stores = storesData?.stores || [];
useManualRefresh(refetch);
useMarkDataFetchers(() => refetch());
const { isNavigatedFromHome, setNavigatedFromHome, selectedStoreId, setSelectedStoreId } = useNavigationStore();
useFocusEffect(() => {
if (isNavigatedFromHome && selectedStoreId) {
setNavigatedFromHome(false);
setSelectedStoreId(null);
router.push(`/(drawer)/(tabs)/stores/store-detail/${selectedStoreId}`);
}
});
if (isLoading) {
return (
<View style={tw`flex-1 justify-center items-center bg-slate-50`}>
<View style={tw`w-20 h-20 items-center justify-center`}>
<MaterialIcons name="storefront" size={48} color={theme.colors.brand200} />
</View>
<MyText style={tw`text-slate-400 font-black uppercase tracking-widest text-[10px] mt-4`}>Opening Marketplace...</MyText>
</View>
);
}
if (error) {
return (
<View style={tw`flex-1 justify-center items-center bg-slate-50 p-10`}>
<View style={tw`w-20 h-20 bg-rose-50 rounded-full items-center justify-center mb-6`}>
<MaterialIcons name="error-outline" size={32} color={theme.colors.red1} />
</View>
<MyText style={tw`text-slate-900 text-xl font-black text-center mb-2`}>Store Fetch Failed</MyText>
<MyText style={tw`text-slate-500 text-center font-medium mb-8 leading-5`}>
We couldn't reach our vendor network.
</MyText>
<MyTouchableOpacity
onPress={() => refetch()}
style={tw`bg-brand600 px-8 py-3 rounded-2xl shadow-lg shadow-brand200`}
>
<MyText style={tw`text-white font-black uppercase tracking-widest text-xs`}>Retry</MyText>
</MyTouchableOpacity>
</View>
);
}
return (
<TabLayoutWrapper>
<View style={tw`flex-1 bg-slate-50 relative`}>
<MyFlatList
data={stores}
renderItem={({ item }) => <StoreCard item={item} router={router} />}
keyExtractor={(item) => item.id.toString()}
contentContainerStyle={tw`pb-32 px-3`}
showsVerticalScrollIndicator={false}
ListHeaderComponent={
<View style={tw`pt-6 pb-4`}>
<View style={tw`flex-row items-center mb-2`}>
<LinearGradient
colors={[theme.colors.brand500, theme.colors.brand700]}
start={{ x: 0, y: 0 }}
end={{ x: 1, y: 1 }}
style={tw`w-1 h-6 rounded-full mr-3`}
/>
<View>
<MyText style={tw`text-slate-400 text-[10px] font-black uppercase tracking-[0.2em]`}>
Our Outlets
</MyText>
<MyText style={tw`text-slate-900 text-3xl font-black tracking-tight`}>
Our Stores
</MyText>
</View>
</View>
<MyText style={tw`text-slate-500 text-sm font-medium leading-5 pr-4`}>
Experience the finest selection of premium meat, poultry, fresh fruits, vegetables, and dairy directly from our own stores.
</MyText>
</View>
}
ListEmptyComponent={
<View style={tw`flex-1 justify-center items-center py-20`}>
<View style={tw`w-24 h-24 bg-white rounded-full items-center justify-center mb-6 shadow-sm`}>
<Ionicons name="storefront-outline" size={48} color="#94A3B8" />
</View>
<MyText style={tw`text-slate-900 text-xl font-black tracking-tight`}>No Stores Available</MyText>
</View>
}
/>
<View style={tw`absolute bottom-2 left-4 right-4`}>
<FloatingCartBar />
</View>
</View>
</TabLayoutWrapper>
);
}