Skip to content

Postwires

Primary Menu
  • Home
  • CSS
  • Documentation
  • HTML
  • Java
  • Javascript
  • Questions
  • React js
  • React Native
Watch Video
  • Home
  • React Native
  • home.jsx
  • React Native

home.jsx

john November 28, 2025
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",
  },
});

About the Author

john

Administrator

Visit Website View All Posts

Continue Reading

Previous: How To Fix Gradle Error In React Native
Next: splash.jsx

Related Stories

  • React Native

splash.jsx

john November 28, 2025
  • Uncategorized
  • React Native

How To Fix Gradle Error In React Native

john November 2, 2025
  • React Native

storeapp using react native

john October 27, 2025

Recent Posts

  • splash.jsx
  • home.jsx
  • How To Fix Gradle Error In React Native
  • jdagj
  • global map system

Categories

  • CSS
  • Documentation
  • HTML
  • Java
  • Javascript
  • Questions
  • React js
  • React Native
  • Uncategorized

You may have missed

  • React Native

splash.jsx

john November 28, 2025
  • React Native

home.jsx

john November 28, 2025
  • Uncategorized
  • React Native

How To Fix Gradle Error In React Native

john November 2, 2025
  • Uncategorized

jdagj

john October 31, 2025
  • About Author
  • About Us
  • Contact Us
  • Disclaimer
  • Privacy Policy
Copyright © All rights reserved. | MoreNews by AF themes.