b24544f115
Generated by create-expo-app 3.2.0.
146 lines
3.7 KiB
TypeScript
146 lines
3.7 KiB
TypeScript
import ProductCard from "@/components/ProductCart";
|
|
import { fetchProducts, getCategories, Product } from "@/utils/api";
|
|
import { COLORS } from "@/utils/colors";
|
|
import { FlashList } from "@shopify/flash-list";
|
|
import { useQuery } from "@tanstack/react-query";
|
|
import { Stack } from "expo-router";
|
|
import React, { useCallback, useMemo } from "react";
|
|
import {
|
|
Pressable,
|
|
ScrollView,
|
|
StyleSheet,
|
|
View,
|
|
Text,
|
|
Platform,
|
|
} from "react-native";
|
|
import { useHeaderHeight } from "@react-navigation/elements";
|
|
import { ProductShimmerGrid } from "@/components/ProductListShimmer";
|
|
|
|
export default function Index() {
|
|
const [selectedCategory, setSelectedCategory] = React.useState("all");
|
|
const [searchQuery, setSearchQuery] = React.useState("");
|
|
const headerHeight = useHeaderHeight();
|
|
|
|
const {
|
|
data: products,
|
|
refetch,
|
|
isLoading,
|
|
isRefetching,
|
|
} = useQuery({
|
|
queryKey: ["products"],
|
|
queryFn: fetchProducts,
|
|
});
|
|
|
|
const { data: categories = [] } = useQuery({
|
|
queryKey: ["categories"],
|
|
queryFn: getCategories,
|
|
});
|
|
|
|
const renderProduct = useCallback(
|
|
({ item }: { item: Product }) => <ProductCard product={item} />,
|
|
[]
|
|
);
|
|
|
|
const allCategories = ["all", ...categories];
|
|
|
|
const filteredProducts = useMemo(() => {
|
|
return products?.filter((product) => {
|
|
if (selectedCategory !== "all") {
|
|
return product.category === selectedCategory;
|
|
}
|
|
return product.title.toLowerCase().includes(searchQuery.toLowerCase());
|
|
});
|
|
}, [products, selectedCategory, searchQuery]);
|
|
|
|
return (
|
|
<View
|
|
style={[
|
|
styles.container,
|
|
{ marginTop: Platform.select({ ios: headerHeight, android: 0 }) },
|
|
]}
|
|
>
|
|
<Stack.Screen
|
|
options={{
|
|
headerSearchBarOptions: {
|
|
onChangeText: (e) => setSearchQuery(e.nativeEvent.text),
|
|
},
|
|
}}
|
|
/>
|
|
<View style={styles.categoryContainer}>
|
|
<ScrollView
|
|
style={styles.categoryScrollView}
|
|
horizontal
|
|
showsHorizontalScrollIndicator={false}
|
|
>
|
|
{allCategories.map((category) => (
|
|
<Pressable
|
|
key={category}
|
|
onPress={() => setSelectedCategory(category)}
|
|
style={[
|
|
styles.categoryButton,
|
|
selectedCategory === category && styles.selectedCategoryButton,
|
|
]}
|
|
>
|
|
<Text
|
|
style={[
|
|
styles.categoryText,
|
|
selectedCategory === category && styles.selectedCategoryText,
|
|
]}
|
|
>
|
|
{category.charAt(0).toUpperCase() + category.slice(1)}
|
|
</Text>
|
|
</Pressable>
|
|
))}
|
|
</ScrollView>
|
|
</View>
|
|
|
|
{isLoading ? (
|
|
<ProductShimmerGrid />
|
|
) : (
|
|
<FlashList
|
|
data={filteredProducts}
|
|
renderItem={renderProduct}
|
|
estimatedItemSize={200}
|
|
numColumns={2}
|
|
contentContainerStyle={{ padding: 8 }}
|
|
keyExtractor={(item) => item.id.toString()}
|
|
onRefresh={refetch}
|
|
refreshing={isRefetching}
|
|
/>
|
|
)}
|
|
</View>
|
|
);
|
|
}
|
|
const styles = StyleSheet.create({
|
|
container: {
|
|
flex: 1,
|
|
backgroundColor: "#fff",
|
|
},
|
|
categoryContainer: {
|
|
height: 60,
|
|
zIndex: 1,
|
|
boxShadow: "0 0 10px rgba(0, 0, 0, 0.1)",
|
|
},
|
|
categoryScrollView: {
|
|
padding: 12,
|
|
},
|
|
categoryButton: {
|
|
paddingHorizontal: 16,
|
|
paddingVertical: 8,
|
|
borderRadius: 20,
|
|
marginHorizontal: 4,
|
|
backgroundColor: COLORS.lightGray,
|
|
alignSelf: "center",
|
|
},
|
|
categoryText: {
|
|
fontSize: 14,
|
|
color: COLORS.white,
|
|
},
|
|
selectedCategoryButton: {
|
|
backgroundColor: COLORS.primary,
|
|
},
|
|
selectedCategoryText: {
|
|
color: COLORS.white,
|
|
},
|
|
});
|