127 lines
3.9 KiB
TypeScript
127 lines
3.9 KiB
TypeScript
"use client";
|
|
import httpClient from "@/request/api";
|
|
import { endPoints } from "@/request/links";
|
|
import { useQuery } from "@tanstack/react-query";
|
|
import ProductCard from "./productCard";
|
|
import { useCategory } from "@/zustand/useCategory";
|
|
import { useFilter } from "@/lib/filter-zustand";
|
|
import { useMemo, useState } from "react";
|
|
import { useProductPageInfo } from "@/zustand/useProduct";
|
|
import { useSubCategory } from "@/zustand/useSubCategory";
|
|
import { useTranslations } from "next-intl";
|
|
import PaginationLite from "@/components/paginationUI";
|
|
import { useCatalog } from "@/zustand/useCatalog";
|
|
|
|
export default function MainProduct() {
|
|
const t = useTranslations();
|
|
const category = useCategory((s) => s.category);
|
|
const subCategory = useSubCategory((s) => s.subCategory);
|
|
const filter = useFilter((s) => s.filter);
|
|
const getFiltersByType = useFilter((s) => s.getFiltersByType);
|
|
const setProduct = useProductPageInfo((s) => s.setProducts);
|
|
const parentID = useCatalog((state) => state.parentID);
|
|
|
|
const [currentPage, setCurrentPage] = useState(1);
|
|
|
|
const queryParams = useMemo(() => {
|
|
const catalog = getFiltersByType("catalog");
|
|
const size = getFiltersByType("size");
|
|
const catalogParams = catalog.map((i) => `catalog=${i.id}`).join("&");
|
|
const sizeParams = size.map((i) => `size=${i.id}`).join("&");
|
|
const allParams = [catalogParams, sizeParams].filter(Boolean).join("&");
|
|
setCurrentPage(1);
|
|
return allParams ? `&${allParams}` : "";
|
|
}, [filter]);
|
|
|
|
const requestLink = useMemo(() => {
|
|
const baseLink = category.have_sub_category
|
|
? endPoints.product.bySubCategory({ id: subCategory.id, currentPage })
|
|
: parentID
|
|
? endPoints.product.byCatalogSection({ id: parentID, currentPage })
|
|
: endPoints.product.byCategory({ id: category.id, currentPage });
|
|
return `${baseLink}${queryParams}`;
|
|
}, [
|
|
category.id,
|
|
category.have_sub_category,
|
|
queryParams,
|
|
subCategory.id,
|
|
currentPage,
|
|
]);
|
|
|
|
const { data, isLoading, error } = useQuery({
|
|
queryKey: [
|
|
"products",
|
|
subCategory.id,
|
|
category.id,
|
|
queryParams,
|
|
currentPage,
|
|
],
|
|
queryFn: () => httpClient(requestLink),
|
|
placeholderData: (prev) => prev, // ✅ pagination da flicker yo'q
|
|
select: (res) => ({
|
|
results: res?.data?.data?.results ?? [],
|
|
totalPages: res?.data?.data?.total_pages ?? 1,
|
|
}),
|
|
});
|
|
|
|
// ✅ To'g'ridan select dan olamiz — useEffect + let emas
|
|
const results = useMemo(() => {
|
|
return data?.results ?? [];
|
|
}, [data]);
|
|
const totalPages = useMemo(() => {
|
|
return data?.totalPages ?? 1;
|
|
}, [data]);
|
|
|
|
if (isLoading && !data) {
|
|
// ✅ placeholderData bor — faqat birinchi yuklanishda
|
|
return (
|
|
<div className="grid lg:grid-cols-3 sm:grid-cols-2 grid-cols-1 gap-5">
|
|
{[1, 2, 3].map((i) => (
|
|
<div key={i} className="h-96 bg-gray-800 animate-pulse rounded-2xl" />
|
|
))}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
if (error) {
|
|
return (
|
|
<div className="text-center text-red-500 py-10">{t("loadingError")}</div>
|
|
);
|
|
}
|
|
|
|
if (!results.length) {
|
|
return (
|
|
<div className="text-center text-gray-400 py-10">
|
|
{t("productsNotFound")}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div className="space-y-4">
|
|
{/* ✅ isLoading da overlay — list o'rnini saqlab, ustidan opacity */}
|
|
<div
|
|
className={`grid lg:grid-cols-4 sm:grid-cols-2 grid-cols-1 gap-5 transition-opacity ${isLoading ? "opacity-50 pointer-events-none" : "opacity-100"}`}
|
|
>
|
|
{results.map((item: any) => (
|
|
<ProductCard
|
|
key={item.id}
|
|
getProduct={() => setProduct(item)}
|
|
title={item.name}
|
|
image={item?.images?.[0]?.image || ""}
|
|
slug="special_product"
|
|
/>
|
|
))}
|
|
</div>
|
|
|
|
{totalPages > 1 && (
|
|
<PaginationLite
|
|
currentPage={currentPage}
|
|
totalPages={totalPages}
|
|
onChange={(p) => setCurrentPage(p)}
|
|
/>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|