import {
View,
Text,
StyleSheet,
TouchableOpacity,
Image,
FlatList,
TextInput,
Modal,
} from "react-native";
import React, { useEffect, useState } from "react";
import { SafeAreaProvider, SafeAreaView } from "react-native-safe-area-context";
import Ionicons from "react-native-vector-icons/Ionicons";
export default function Home({ navigation }) {
const [data, setdata] = useState([]);
const [search, setsearch] = useState("");
const [backupdata, setbackupdata] = useState([]);
const [modal, setmodal] = useState(false);
const [sortOption, setSortOption] = useState("");
const [appliedSort, setAppliedSort] = useState("");
// ⭐ PAGINATION
const [currentPage, setCurrentPage] = useState(1);
const itemsPerPage = 6;
useEffect(() => {
fetch("https://dummyjson.com/products")
.then((res) => res.json())
.then((resp) => {
setdata(resp.products);
setbackupdata(resp.products);
})
.catch((err) => console.error("Error", err));
}, []);
const totalPages = Math.ceil(data.length / itemsPerPage);
const startIndex = (currentPage - 1) * itemsPerPage;
const paginatedData = data.slice(startIndex, startIndex + itemsPerPage);
const sortOptions = {
"A-Z": "Name (A-Z)",
"Z-A": "Name (Z-A)",
"Low-High": "Price: Low to High",
"High-Low": "Price: High to Low",
};
const resetSort = () => {
setdata(backupdata);
setAppliedSort("");
setSortOption("");
};
const renderProducts = ({ item }) => {
return (
<TouchableOpacity
style={styles.ProductCard}
onPress={() => navigation.navigate("ProductDetail", { item })}
>
<Image
source={{ uri: item.thumbnail }}
resizeMode="contain"
style={styles.ProfileImage}
/>
<Text style={styles.title}>{item.title}</Text>
<Text style={styles.price}>₹ {item.price}</Text>
<TouchableOpacity style={styles.AddBtn}>
<Text style={{ fontSize: 14, color: "white", fontWeight: "500" }}>
Add to Cart
</Text>
</TouchableOpacity>
</TouchableOpacity>
);
};
function handlesearch(text) {
setsearch(text);
if (text.trim() === "") {
setdata(backupdata);
setCurrentPage(1);
return;
}
const filter = backupdata.filter((item) =>
item.title.toLowerCase().includes(text.toLowerCase())
);
setdata(filter);
setCurrentPage(1);
}
const handleSort = (option) => {
let sorted = [...data];
if (option === "A-Z") {
sorted.sort((a, b) => a.title.localeCompare(b.title));
} else if (option === "Z-A") {
sorted.sort((a, b) => b.title.localeCompare(a.title));
} else if (option === "Low-High") {
sorted.sort((a, b) => a.price - b.price);
} else if (option === "High-Low") {
sorted.sort((a, b) => b.price - a.price);
}
setdata(sorted);
setAppliedSort(option);
setmodal(false);
setCurrentPage(1);
};
const clearSearch = () => {
setsearch("");
setdata(backupdata);
setCurrentPage(1);
};
return (
<SafeAreaProvider>
<SafeAreaView style={{ marginBottom: 5 }}>
{/* Search + Filter */}
<View style={styles.serachcontainer}>
<View style={styles.search}>
<TextInput
style={styles.searchInput}
value={search}
onChangeText={(text) => handlesearch(text)}
placeholder="Search..."
/>
{search.length > 0 && (
<TouchableOpacity
onPress={clearSearch}
style={{ position: "absolute", top: 5, right: 10 }}
>
<Ionicons name="close-circle" size={35} color="#666" />
</TouchableOpacity>
)}
</View>
<TouchableOpacity
style={styles.filterButton}
onPress={() => setmodal(true)}
>
<Ionicons name="filter-outline" size={28} color="#000" />
{appliedSort && <View style={styles.greenDot} />}
</TouchableOpacity>
</View>
{/* Current Sort Info */}
{appliedSort && (
<View style={styles.sortInfoContainer}>
<Text style={styles.sortInfoText}>
Sort by: <Text style={{ fontWeight: "bold" }}>{sortOptions[appliedSort]}</Text>
</Text>
<TouchableOpacity onPress={resetSort}>
<Text style={styles.resetText}>Reset</Text>
</TouchableOpacity>
</View>
)}
{/* ⭐ PRODUCT LIST WITH FOOTER PAGINATION */}
<FlatList
data={paginatedData}
renderItem={renderProducts}
keyExtractor={(item) => item.id}
numColumns={2}
contentContainerStyle={{ paddingBottom: 110 }}
ListFooterComponent={() => (
<View style={styles.pagination}>
<TouchableOpacity
style={[styles.pageBtn, currentPage === 1 && styles.disabledBtn]}
disabled={currentPage === 1}
onPress={() => setCurrentPage(currentPage - 1)}
>
<Text style={styles.pageBtnText}>Prev</Text>
</TouchableOpacity>
<Text style={styles.pageNumber}>
{currentPage} / {totalPages}
</Text>
<TouchableOpacity
style={[
styles.pageBtn,
currentPage === totalPages && styles.disabledBtn,
]}
disabled={currentPage === totalPages}
onPress={() => setCurrentPage(currentPage + 1)}
>
<Text style={styles.pageBtnText}>Next</Text>
</TouchableOpacity>
</View>
)}
/>
{/* Modal */}
<Modal visible={modal} animationType="fade" transparent>
<View style={styles.modalOverlay}>
<View style={styles.modalBox}>
<TouchableOpacity
style={styles.closeBtn}
onPress={() => setmodal(false)}
>
<Ionicons name="close" size={32} color="#333" />
</TouchableOpacity>
<Text style={styles.modalTitle}>Sort Products</Text>
<View style={{ width: "100%", marginTop: 20 }}>
{["A-Z", "Z-A", "Low-High", "High-Low"].map((item) => (
<TouchableOpacity
key={item}
style={styles.optionRow}
onPress={() => setSortOption(item)}
>
<View style={styles.outerCircle}>
{sortOption === item && <View style={styles.innerCircle} />}
</View>
<Text style={styles.optionText}>{item}</Text>
</TouchableOpacity>
))}
</View>
<View style={styles.bottomBtnRow}>
<TouchableOpacity
style={[styles.btn, styles.cancelBtn]}
onPress={() => setmodal(false)}
>
<Text style={styles.cancelText}>Cancel</Text>
</TouchableOpacity>
<TouchableOpacity
style={[styles.btn, styles.okBtn]}
onPress={() => handleSort(sortOption)}
>
<Text style={styles.okText}>Apply</Text>
</TouchableOpacity>
</View>
</View>
</View>
</Modal>
</SafeAreaView>
</SafeAreaProvider>
);
}
const styles = StyleSheet.create({
serachcontainer: {
width: "100%",
backgroundColor: "#fafafa",
height: 80,
alignItems: "center",
flexDirection: "row",
paddingHorizontal: 10,
justifyContent: "space-between",
},
search: {
width: "83%",
borderWidth: 1,
borderRadius: 50,
borderColor: "#ccc",
height: 50,
paddingHorizontal: 10,
justifyContent: "center",
},
searchInput: { width: "100%", height: 50 },
filterButton: { position: "relative" },
greenDot: {
width: 10,
height: 10,
backgroundColor: "green",
borderRadius: 50,
position: "absolute",
top: 0,
right: 0,
},
sortInfoContainer: {
width: "100%",
padding: 10,
flexDirection: "row",
justifyContent: "space-between",
backgroundColor: "#eee",
},
sortInfoText: { fontSize: 16 },
resetText: {
fontSize: 16,
color: "red",
fontWeight: "bold",
},
ProductCard: {
width: "50%",
height: 280,
backgroundColor: "#fff",
padding: 10,
borderColor: "#ddd",
borderWidth: 1,
justifyContent: "center",
alignItems: "center",
},
ProfileImage: { width: "100%", height: 120 },
title: {
width: "100%",
textAlign: "center",
marginVertical: 10,
fontWeight: "500",
color: "gray",
},
AddBtn: {
width: "90%",
height: 40,
borderRadius: 50,
backgroundColor: "purple",
justifyContent: "center",
alignItems: "center",
marginVertical: 15,
},
price: { fontSize: 18, color: "blue", textAlign: "center" },
// ⭐ Pagination Footer Style
pagination: {
flexDirection: "row",
justifyContent: "center",
alignItems: "center",
marginVertical: 35,
gap: 20,
},
pageBtn: {
backgroundColor: "purple",
paddingVertical: 10,
paddingHorizontal: 20,
borderRadius: 10,
},
disabledBtn: {
backgroundColor: "#ccc",
},
pageBtnText: { color: "white", fontWeight: "bold" },
pageNumber: { fontSize: 18, fontWeight: "600" },
modalOverlay: {
flex: 1,
backgroundColor: "rgba(0,0,0,0.5)",
justifyContent: "center",
alignItems: "center",
},
modalBox: {
width: "85%",
backgroundColor: "white",
borderRadius: 20,
padding: 20,
paddingTop: 35,
elevation: 20,
alignItems: "center",
},
closeBtn: { position: "absolute", right: 15, top: 15 },
modalTitle: {
fontSize: 24,
fontWeight: "700",
color: "#333",
},
optionRow: {
flexDirection: "row",
alignItems: "center",
paddingVertical: 12,
paddingHorizontal: 5,
},
outerCircle: {
width: 26,
height: 26,
borderRadius: 50,
borderWidth: 2,
borderColor: "purple",
justifyContent: "center",
alignItems: "center",
},
innerCircle: {
width: 14,
height: 14,
borderRadius: 50,
backgroundColor: "purple",
},
optionText: {
fontSize: 18,
marginLeft: 12,
color: "#333",
},
bottomBtnRow: {
width: "100%",
flexDirection: "row",
justifyContent: "space-between",
marginTop: 25,
},
btn: {
width: "45%",
height: 45,
borderRadius: 10,
justifyContent: "center",
alignItems: "center",
elevation: 5,
},
cancelBtn: { backgroundColor: "#f2f2f2" },
okBtn: { backgroundColor: "purple" },
cancelText: {
fontSize: 18,
color: "#000",
fontWeight: "600",
},
okText: {
fontSize: 18,
color: "white",
fontWeight: "600",
},
});