diff --git a/app/globals.css b/app/globals.css index cda3071..22e2cd9 100644 --- a/app/globals.css +++ b/app/globals.css @@ -14,7 +14,7 @@ --font-mono: var(--font-geist-mono); --font-roboto: "Roboto", sans-serif; --font-almarai: "Almarai", sans-serif; - --font-unbounded:"Unbounded",sans-serif; + --font-unbounded: "Unbounded", sans-serif; --color-sidebar-ring: var(--sidebar-ring); --color-sidebar-border: var(--sidebar-border); --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); @@ -135,6 +135,25 @@ body { background: #1e1d1c; } -.loio{ - color:#8b1515, #c91d1d +.loio { + color: #8b1515, #c91d1d; +} + +/* globals.css ga qo'shing */ +@keyframes shimmer { + 100% { + transform: translateX(100%); + } +} + +.animate-shimmer { + animation: shimmer 2s infinite; +} + +.delay-150 { + animation-delay: 150ms; +} + +.delay-300 { + animation-delay: 300ms; } diff --git a/components/EmptyData.tsx b/components/EmptyData.tsx new file mode 100644 index 0000000..114680d --- /dev/null +++ b/components/EmptyData.tsx @@ -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 ( +
+ {/* Animated background circles */} +
+ {/* Icon */} +
+ +
+
+ + {/* Text content */} +
+

+ {title || t("no_data_title")} +

+

+ {description || t("no_data_description")} +

+
+ + {/* Decorative elements */} +
+
+
+
+
+
+ ); +} diff --git a/components/loadingSkleton.tsx b/components/loadingSkleton.tsx new file mode 100644 index 0000000..796e31c --- /dev/null +++ b/components/loadingSkleton.tsx @@ -0,0 +1,41 @@ +// components/CatalogCardSkeleton.tsx +export default function CatalogCardSkeleton() { + return ( +
+ {/* Content container */} +
+ {/* Title section */} +
+
+ {/* Title skeleton */} +
+
+
+
+ {/* Icon skeleton */} +
+
+ + {/* Description skeleton */} +
+
+
+
+
+ + {/* Image container skeleton */} +
+
+
+
+
+ + {/* Bottom accent bar skeleton */} +
+
+ + {/* Shimmer effect */} +
+
+ ); +} \ No newline at end of file diff --git a/components/pages/home/blog.tsx b/components/pages/home/blog/blog.tsx similarity index 67% rename from components/pages/home/blog.tsx rename to components/pages/home/blog/blog.tsx index 190d1b9..9f2273f 100644 --- a/components/pages/home/blog.tsx +++ b/components/pages/home/blog/blog.tsx @@ -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() {
{/* Blog Cards Grid */} -
- {ProductCatalog.map((item, index) => ( - - ))} -
+
); diff --git a/components/pages/home/blog/catalog.tsx b/components/pages/home/blog/catalog.tsx new file mode 100644 index 0000000..d64ae7b --- /dev/null +++ b/components/pages/home/blog/catalog.tsx @@ -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 ( +
+ {[...Array(3)].map((_, index) => ( + + ))} +
+ ); + } + + // Ma'lumot yo'q holati + if (!data || data.length === 0) { + return ( + + ); + } + + return ( +
+ {data.map((item, index) => ( + + ))} +
+ ); +} diff --git a/components/pages/home/index.ts b/components/pages/home/index.ts index 167d23a..082d0bd 100644 --- a/components/pages/home/index.ts +++ b/components/pages/home/index.ts @@ -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"; diff --git a/components/pages/products/catalog.tsx b/components/pages/products/catalog.tsx index 5ed6b99..c825d7b 100644 --- a/components/pages/products/catalog.tsx +++ b/components/pages/products/catalog.tsx @@ -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; diff --git a/lib/types.ts b/lib/types.ts new file mode 100644 index 0000000..5b1de65 --- /dev/null +++ b/lib/types.ts @@ -0,0 +1,39 @@ +export interface CategoryType { + id: number; + name: string; + image: string; + description: string; +} + +export interface SubCategoryType { + id: number; + name: string; + category: number; + image: string; +} + +export interface ProductsPageTypes { + id: number; + name: string; + image: string; +} + +export interface ProductImage { + id: number; + product: number; + image: string; + is_main: boolean; + order: number; +} + +export interface ProductDetail { + id: number; + name: string; + articular: string; + status: string; + description: string; + size: number; + price: string; + features: string[]; + images: ProductImage[]; +} diff --git a/request/links.ts b/request/links.ts index bc13c6c..d6abfc6 100644 --- a/request/links.ts +++ b/request/links.ts @@ -12,7 +12,7 @@ export const endPoints = { detail: (id: number) => `product/${id}/`, }, faq: "faq/", - gallery: "gallery/", + gallery: "gallery/?page_size=500", contact: "contact/", statistics: "statistics/", filter: { diff --git a/store/useCategory.ts b/store/useCategory.ts new file mode 100644 index 0000000..af27552 --- /dev/null +++ b/store/useCategory.ts @@ -0,0 +1,19 @@ +import { CategoryType } from "@/lib/types"; +import { create } from "zustand"; + +interface CategoryZustandType { + category: CategoryType; + setCategory: (category: CategoryType) => void; +} + +const demoCategory: CategoryType = { + id: 0, + name: "", + description: "", + image: "", +}; + +export const useCategory = create((set) => ({ + category: demoCategory, + setCategory: (data) => set({ category: data }), +})); diff --git a/store/useProduct.ts b/store/useProduct.ts new file mode 100644 index 0000000..e69de29 diff --git a/store/useSubCategory.ts b/store/useSubCategory.ts new file mode 100644 index 0000000..ce229dc --- /dev/null +++ b/store/useSubCategory.ts @@ -0,0 +1,18 @@ +import { SubCategoryType } from "@/lib/types"; +import { create } from "zustand"; + +interface SubCategoryZustandType { + subCategory: SubCategoryType; + setSubCategory: (subCategory: SubCategoryType) => void; +} + +const demoSubCategory = { + id: 0, + name: "", + category: 0, + image: "", +}; +export const useSubCategory = create((set) => ({ + subCategory: demoSubCategory, + setSubCategory: (data) => set({}), +}));