catalog part connected to backend , added empty data and loading component

This commit is contained in:
nabijonovdavronbek619@gmail.com
2026-02-05 19:56:23 +05:00
parent 3cf5e0efcf
commit 34cb524626
12 changed files with 249 additions and 19 deletions

48
components/EmptyData.tsx Normal file
View File

@@ -0,0 +1,48 @@
// components/EmptyData.tsx
import { PackageOpen, ShoppingBag } from "lucide-react";
import { useTranslations } from "next-intl";
interface EmptyDataProps {
title?: string;
description?: string;
icon?: "package" | "shopping";
}
export default function EmptyData({
title,
description,
icon = "package",
}: EmptyDataProps) {
const t = useTranslations();
const Icon = icon === "package" ? PackageOpen : ShoppingBag;
return (
<div className="flex flex-col items-center justify-center min-h-100 py-12 px-4">
{/* Animated background circles */}
<div className="relative flex items-center justify-center ">
{/* Icon */}
<div className="relative z-10 w-20 h-20 mx-auto mb-6 rounded-full bg-linear-to-br from-[#444242] to-gray-900 border border-white/10 flex items-center justify-center">
<Icon className="w-10 h-10 text-white/40" strokeWidth={1.5} />
</div>
</div>
{/* Text content */}
<div className="text-center space-y-3 max-w-md">
<h3 className="text-2xl font-unbounded font-bold text-white">
{title || t("no_data_title")}
</h3>
<p className="text-white/50 font-almarai">
{description || t("no_data_description")}
</p>
</div>
{/* Decorative elements */}
<div className="mt-8 flex gap-2">
<div className="w-2 h-2 rounded-full bg-red-500/30 animate-pulse" />
<div className="w-2 h-2 rounded-full bg-red-500/30 animate-pulse delay-150" />
<div className="w-2 h-2 rounded-full bg-red-500/30 animate-pulse delay-300" />
</div>
</div>
);
}

View File

@@ -0,0 +1,41 @@
// components/CatalogCardSkeleton.tsx
export default function CatalogCardSkeleton() {
return (
<div className="relative h-112.5 w-full overflow-hidden rounded-2xl bg-[#17161679] border border-white/10 animate-pulse">
{/* Content container */}
<div className="relative h-full flex flex-col p-6">
{/* Title section */}
<div className="mb-4">
<div className="flex items-start justify-between mb-2">
{/* Title skeleton */}
<div className="flex-1 space-y-2">
<div className="h-7 bg-white/10 rounded-md w-3/4" />
<div className="h-7 bg-white/10 rounded-md w-1/2" />
</div>
{/* Icon skeleton */}
<div className="shrink-0 w-8 h-8 rounded-full bg-white/10" />
</div>
{/* Description skeleton */}
<div className="space-y-2 mt-3">
<div className="h-4 bg-white/10 rounded w-full" />
<div className="h-4 bg-white/10 rounded w-4/5" />
</div>
</div>
{/* Image container skeleton */}
<div className="relative flex-1 rounded-xl overflow-hidden bg-linear-to-br from-[#444242] to-gray-900/50 border border-white/5">
<div className="absolute inset-0 flex items-center justify-center">
<div className="w-32 h-32 bg-white/5 rounded-lg" />
</div>
</div>
{/* Bottom accent bar skeleton */}
<div className="mt-4 h-1 w-1/3 bg-white/10 rounded-full" />
</div>
{/* Shimmer effect */}
<div className="absolute inset-0 -translate-x-full animate-shimmer bg-linear-to-r from-transparent via-white/5 to-transparent" />
</div>
);
}

View File

@@ -1,7 +1,6 @@
import DotAnimatsiya from "@/components/dot/DotAnimatsiya";
import { useTranslations } from "next-intl";
import { ProductCatalog } from "@/lib/demoData";
import CatalogCard from "../products/catalog";
import Catalog from "./catalog";
export function Blog() {
const t = useTranslations();
@@ -26,17 +25,7 @@ export function Blog() {
</div>
{/* Blog Cards Grid */}
<div className="grid gap-8 md:grid-cols-2 lg:grid-cols-3 place-items-center">
{ProductCatalog.map((item, index) => (
<CatalogCard
key={index}
id={item.id}
title={item.title}
description={item.description}
image={item.image}
/>
))}
</div>
<Catalog />
</div>
</section>
);

View File

@@ -0,0 +1,57 @@
"use client";
import { useQuery } from "@tanstack/react-query";
import httpClient from "@/request/api";
import { endPoints } from "@/request/links";
import { useEffect } from "react";
import CatalogCard from "../../products/catalog";
import CatalogCardSkeleton from "@/components/loadingSkleton";
import EmptyData from "@/components/EmptyData";
import { getRouteLang } from "@/request/getLang";
import { CategoryType } from "@/lib/types";
export default function Catalog() {
const language = getRouteLang();
const { data, isLoading } = useQuery({
queryKey: ["categorycasd", 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) => (
<CatalogCardSkeleton 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="grid gap-8 md:grid-cols-2 lg:grid-cols-3 place-items-center">
{data.map((item, index) => (
<CatalogCard
key={index}
id={item.id}
title={item.name}
description={item.description}
image={item.image}
/>
))}
</div>
);
}

View File

@@ -5,4 +5,4 @@ export { Video } from "./video";
export { OurService } from "./ourService";
export { Testimonial } from "./testimonal";
export { Line } from "./line";
export { Blog } from "./blog";
export { Blog } from "./blog/blog";

View File

@@ -50,7 +50,7 @@ import Link from "next/link";
import { ArrowUpRight } from "lucide-react";
interface CatalogProps {
id: string;
id: number;
image: string;
title: string;
description: string;