add catalog filter card
This commit is contained in:
@@ -1,12 +1,13 @@
|
|||||||
import Catalog from "@/components/pages/home/blog/catalog";
|
import Catalog from "@/components/pages/home/blog/catalog";
|
||||||
import { ProductBanner } from "@/components/pages/products";
|
import { ProductBanner } from "@/components/pages/products";
|
||||||
|
import { MainSubCategory } from "@/components/pages/subCategory";
|
||||||
|
|
||||||
export default function Page() {
|
export default function Page() {
|
||||||
return (
|
return (
|
||||||
<div className="bg-[#1e1d1c] pb-30">
|
<div className="bg-[#1e1d1c] pb-30">
|
||||||
<ProductBanner />
|
<ProductBanner />
|
||||||
<div className="max-w-300 mx-auto w-full pt-20">
|
<div className="max-w-300 mx-auto w-full pt-20">
|
||||||
<Catalog />
|
<MainSubCategory />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
import { ProductBanner, Products } from "@/components/pages/products";
|
import { ProductBanner, Products } from "@/components/pages/products";
|
||||||
|
import FilterCatalog from "@/components/pages/products/filter/catalog/filterCatalog";
|
||||||
|
|
||||||
export default function Page() {
|
export default function Page() {
|
||||||
return (
|
return (
|
||||||
<div className="bg-[#1e1d1c] pb-30">
|
<div className="bg-[#1e1d1c] pb-30">
|
||||||
<ProductBanner />
|
<ProductBanner />
|
||||||
|
{/* <FilterCatalog /> */}
|
||||||
<Products />
|
<Products />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { useTranslations } from "next-intl";
|
|||||||
export function ProductBanner() {
|
export function ProductBanner() {
|
||||||
const t = useTranslations();
|
const t = useTranslations();
|
||||||
return (
|
return (
|
||||||
<section className="relative w-full h-[60vh] min-h-100 overflow-hidden pt-10">
|
<section className="relative w-full min-[400px]:h-[60vh] h-[75vh] min-h-100 overflow-hidden pt-10">
|
||||||
{/* Background Image */}
|
{/* Background Image */}
|
||||||
<div
|
<div
|
||||||
className="absolute inset-0 z-0"
|
className="absolute inset-0 z-0"
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ export default function CatalogCard({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const navigateLink = have_sub_category
|
const navigateLink = have_sub_category
|
||||||
? `/${locale}/subCategory?category=${id}`
|
? `/${locale}/catalog_page?category=${id}`
|
||||||
: `/${locale}/products?category=${id}`;
|
: `/${locale}/products?category=${id}`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
96
components/pages/products/filter/catalog/filterCatalog.tsx
Normal file
96
components/pages/products/filter/catalog/filterCatalog.tsx
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
"use client";
|
||||||
|
import EmptyData from "@/components/EmptyData";
|
||||||
|
import { CategoryType } from "@/lib/types";
|
||||||
|
import httpClient from "@/request/api";
|
||||||
|
import { getRouteLang } from "@/request/getLang";
|
||||||
|
import { endPoints } from "@/request/links";
|
||||||
|
import { useCategory } from "@/store/useCategory";
|
||||||
|
import { useQuery } from "@tanstack/react-query";
|
||||||
|
import { useEffect } from "react";
|
||||||
|
import CatalogCardSkeletonSmall from "./loading";
|
||||||
|
import Image from "next/image";
|
||||||
|
import { ArrowUpRight } from "lucide-react";
|
||||||
|
|
||||||
|
export default function FilterCatalog() {
|
||||||
|
const language = getRouteLang();
|
||||||
|
const setCategory = useCategory((state) => state.setCategory);
|
||||||
|
const { data, isLoading } = useQuery({
|
||||||
|
queryKey: ["category", language],
|
||||||
|
queryFn: () => httpClient(endPoints.category.all),
|
||||||
|
select: (data): CategoryType[] => data?.data?.results,
|
||||||
|
});
|
||||||
|
useEffect(() => {
|
||||||
|
console.log("product catalog data: ", data);
|
||||||
|
}, [data]);
|
||||||
|
|
||||||
|
if (isLoading) {
|
||||||
|
return (
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||||
|
{[...Array(3)].map((_, index) => (
|
||||||
|
<CatalogCardSkeletonSmall key={index} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ma'lumot yo'q holati
|
||||||
|
if (!data || data.length === 0) {
|
||||||
|
return (
|
||||||
|
<EmptyData
|
||||||
|
title="Katalog topilmadi"
|
||||||
|
description="Hozircha kategoriyalar mavjud emas. Keyinroq qaytib keling."
|
||||||
|
icon="shopping"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="max-w-200 w-full mx-auto space-x-5 px-5 flex items-center justify-around my-10 -mt-30 pb-5 relative z-20 sm:overflow-x-hidden overflow-x-scroll">
|
||||||
|
{data?.map((item) => (
|
||||||
|
<div
|
||||||
|
onClick={() => setCategory(item)}
|
||||||
|
className="shrink-0 group relative w-55 h-60 overflow-hidden rounded-2xl bg-[#17161679] border border-white/10 transition-all duration-500 hover:-translate-y-1 hover:border-red-700 cursor-pointer"
|
||||||
|
>
|
||||||
|
{/* Background glow effect */}
|
||||||
|
<div className="absolute inset-0 bg-linear-to-t from-red-600/20 via-transparent to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-500" />
|
||||||
|
|
||||||
|
{/* Decorative corner accent */}
|
||||||
|
<div className="absolute top-0 right-0 w-16 h-16 bg-linear-to-br from-red-500/20 to-transparent rounded-bl-full opacity-0 group-hover:opacity-100 transition-opacity duration-500" />
|
||||||
|
|
||||||
|
{/* Content container */}
|
||||||
|
<div className="relative h-full flex flex-col p-4">
|
||||||
|
{/* Title section */}
|
||||||
|
<div className="mb-3">
|
||||||
|
<div className="flex items-start justify-between gap-2">
|
||||||
|
<h3 className="text-lg font-unbounded font-bold text-white leading-tight transition-colors duration-300">
|
||||||
|
{item.name}
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
<div className="shrink-0 w-6 h-6 rounded-full bg-white/10 flex items-center justify-center group-hover:bg-red-500 transition-all duration-300 group-hover:scale-110">
|
||||||
|
<ArrowUpRight
|
||||||
|
className="w-3.5 h-3.5 text-white"
|
||||||
|
strokeWidth={2.5}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Image container */}
|
||||||
|
<div className="relative flex-1 rounded-xl overflow-hidden bg-linear-to-br from-[#444242] to-gray-900/50 border border-white/5 group-hover:border-white/20 transition-all duration-500">
|
||||||
|
<div className="absolute inset-0 bg-linear-to-t from-black/60 via-transparent to-transparent z-10" />
|
||||||
|
|
||||||
|
<div className="relative w-full h-full">
|
||||||
|
<Image
|
||||||
|
src={item.image}
|
||||||
|
alt={item.name}
|
||||||
|
fill
|
||||||
|
className="object-contain p-3 transition-transform duration-700 group-hover:scale-105"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
23
components/pages/products/filter/catalog/loading.tsx
Normal file
23
components/pages/products/filter/catalog/loading.tsx
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
// components/CatalogCardSkeletonSmall.tsx
|
||||||
|
export default function CatalogCardSkeletonSmall() {
|
||||||
|
return (
|
||||||
|
<div className="relative w-50 h-87.5 overflow-hidden rounded-2xl bg-[#17161679] border border-white/10 animate-pulse">
|
||||||
|
<div className="flex flex-col h-full p-4 gap-3">
|
||||||
|
|
||||||
|
{/* Title skeleton */}
|
||||||
|
<div className="space-y-2">
|
||||||
|
<div className="h-5 bg-white/10 rounded-md w-3/4" />
|
||||||
|
<div className="h-5 bg-white/10 rounded-md w-1/2" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Image skeleton */}
|
||||||
|
<div className="flex-1 rounded-xl bg-linear-to-br from-[#444242] to-gray-900/50 border border-white/5 flex items-center justify-center">
|
||||||
|
<div className="w-20 h-20 bg-white/5 rounded-lg" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Shimmer */}
|
||||||
|
<div className="absolute inset-0 -translate-x-full animate-shimmer bg-linear-to-r from-transparent via-white/5 to-transparent" />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -67,26 +67,22 @@ export default function Filter() {
|
|||||||
const visibleSectionNumber = numberExpanded
|
const visibleSectionNumber = numberExpanded
|
||||||
? sizeData
|
? sizeData
|
||||||
: sizeData.slice(0, 10);
|
: sizeData.slice(0, 10);
|
||||||
|
|
||||||
console.log("have suncategory: ", category.have_sub_category);
|
|
||||||
if (category.have_sub_category || subCategory.id !== 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
console.log("filter: ", filter);
|
console.log("filter: ", filter);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-3 max-w-70 w-full text-white">
|
<div className="space-y-3 lg:max-w-70 lg:px-0 px-3 w-full text-white">
|
||||||
{/* Bo'lim filtri */}
|
{/* Bo'lim filtri */}
|
||||||
<div className="bg-gray-500 rounded-lg">
|
{visibleSectionData && (
|
||||||
|
<div className="bg-gray-500 rounded-lg w-full">
|
||||||
<p className="bg-red-500 text-white p-2 font-semibold font-almarai text-lg rounded-t-lg">
|
<p className="bg-red-500 text-white p-2 font-semibold font-almarai text-lg rounded-t-lg">
|
||||||
Bo'lim
|
Bo'lim
|
||||||
</p>
|
</p>
|
||||||
<div className="space-y-3 p-2">
|
<div className="lg:space-y-3 space-x-6 lg:p-2 p-5 flex lg:flex-col overflow-x-auto lg:overflow-x-hidden items-start justify-start w-full">
|
||||||
{visibleSectionData.map((item) => (
|
{visibleSectionData.map((item) => (
|
||||||
<div
|
<div
|
||||||
key={item.id}
|
key={item.id}
|
||||||
onClick={() => toggleFilter(item)}
|
onClick={() => toggleFilter(item)}
|
||||||
className="hover:cursor-pointer flex items-center gap-2"
|
className="hover:cursor-pointer flex items-center gap-2 w-auto shrink-0"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
className={`flex h-5 w-5 items-center justify-center rounded border-2 transition ${
|
className={`flex h-5 w-5 items-center justify-center rounded border-2 transition ${
|
||||||
@@ -100,29 +96,31 @@ export default function Filter() {
|
|||||||
<Check className="h-3 w-3 text-white" strokeWidth={3} />
|
<Check className="h-3 w-3 text-white" strokeWidth={3} />
|
||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
<p>{item.name}</p>
|
<p className="whitespace-nowrap">{item.name}</p>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
className="p-2 text-lg underline hover:text-red-300 transition"
|
className="lg:flex hidden p-2 text-lg underline hover:text-red-300 transition"
|
||||||
onClick={() => setDataExpanded(!dataExpanded)}
|
onClick={() => setDataExpanded(!dataExpanded)}
|
||||||
>
|
>
|
||||||
{dataExpanded ? "Yashirish" : "Ko'proq ko'rish"}
|
{dataExpanded ? "Yashirish" : "Ko'proq ko'rish"}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* O'lcham filtri */}
|
{/* O'lcham filtri */}
|
||||||
|
{visibleSectionNumber && (
|
||||||
<div className="bg-gray-500 rounded-lg">
|
<div className="bg-gray-500 rounded-lg">
|
||||||
<p className="bg-red-500 text-white p-2 font-semibold font-almarai text-lg rounded-t-lg">
|
<p className="bg-red-500 text-white p-2 font-semibold font-almarai text-lg rounded-t-lg">
|
||||||
O'lcham
|
O'lcham
|
||||||
</p>
|
</p>
|
||||||
<div className="grid grid-cols-2 gap-3 p-2">
|
<div className="lg:space-y-3 space-x-6 lg:p-2 p-5 flex lg:flex-col overflow-x-auto lg:overflow-x-hidden items-start justify-start w-full">
|
||||||
{visibleSectionNumber.map((item) => (
|
{visibleSectionNumber.map((item) => (
|
||||||
<div
|
<div
|
||||||
key={item.id}
|
key={item.id}
|
||||||
onClick={() => toggleFilter(item)}
|
onClick={() => toggleFilter(item)}
|
||||||
className="hover:cursor-pointer flex items-center gap-2"
|
className="hover:cursor-pointer flex items-center gap-2 w-auto shrink-0"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
className={`flex h-5 w-5 items-center justify-center rounded border-2 transition ${
|
className={`flex h-5 w-5 items-center justify-center rounded border-2 transition ${
|
||||||
@@ -142,11 +140,12 @@ export default function Filter() {
|
|||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
onClick={() => setNumberExpanded(!numberExpanded)}
|
onClick={() => setNumberExpanded(!numberExpanded)}
|
||||||
className="p-2 text-lg underline hover:text-red-300 transition"
|
className="lg:flex hidden p-2 text-lg underline hover:text-red-300 transition"
|
||||||
>
|
>
|
||||||
{numberExpanded ? "Yashirish" : "Ko'proq ko'rish"}
|
{numberExpanded ? "Yashirish" : "Ko'proq ko'rish"}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,9 +4,9 @@ import MainProduct from "./mianProduct";
|
|||||||
|
|
||||||
export function Products() {
|
export function Products() {
|
||||||
return (
|
return (
|
||||||
<div className="bg-[#1e1d1c] py-20">
|
<div className="bg-[#1e1d1c] py-10">
|
||||||
<div className="max-w-300 mx-auto w-full z-20 relative">
|
<div className="max-w-300 mx-auto w-full z-20 relative">
|
||||||
<div className="flex items-start gap-5">
|
<div className="flex lg:flex-row flex-col lg:items-start items-center gap-5">
|
||||||
{/* filter part */}
|
{/* filter part */}
|
||||||
<Filter />
|
<Filter />
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ export default function Card({
|
|||||||
image,
|
image,
|
||||||
category,
|
category,
|
||||||
});
|
});
|
||||||
router.push(`/${locale}/products/${slug}`);
|
router.push(`/${locale}/products`);
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<Link href="#" onClick={handleClick}>
|
<Link href="#" onClick={handleClick}>
|
||||||
|
|||||||
Reference in New Issue
Block a user