From 6fbe23109c537dc12adc1f0be172c298cce7c268 Mon Sep 17 00:00:00 2001 From: "nabijonovdavronbek619@gmail.com" Date: Tue, 10 Feb 2026 16:41:40 +0500 Subject: [PATCH] vreadCrumb added --- app/[locale]/catalog_page/page.tsx | 2 + .../products/[slug]/page.tsx | 13 +- .../{ => catalog_page}/products/page.tsx | 7 + .../{ => catalog_page}/subCategory/page.tsx | 6 +- components/breadCrumb.tsx | 195 ++++++++++++++++++ components/pages/home/blog/catalog.tsx | 3 +- components/pages/products/catalog.tsx | 4 +- .../pages/products/product/productCard.tsx | 2 +- components/pages/subCategory/card.tsx | 2 +- messages/en.json | 22 +- messages/ru.json | 17 +- messages/uz.json | 16 +- 12 files changed, 270 insertions(+), 19 deletions(-) rename app/[locale]/{ => catalog_page}/products/[slug]/page.tsx (84%) rename app/[locale]/{ => catalog_page}/products/page.tsx (50%) rename app/[locale]/{ => catalog_page}/subCategory/page.tsx (62%) create mode 100644 components/breadCrumb.tsx diff --git a/app/[locale]/catalog_page/page.tsx b/app/[locale]/catalog_page/page.tsx index ebf489c..bcb1ae6 100644 --- a/app/[locale]/catalog_page/page.tsx +++ b/app/[locale]/catalog_page/page.tsx @@ -1,3 +1,4 @@ +import { Breadcrumb } from "@/components/breadCrumb"; import Catalog from "@/components/pages/home/blog/catalog"; import { ProductBanner } from "@/components/pages/products"; import { MainSubCategory } from "@/components/pages/subCategory"; @@ -7,6 +8,7 @@ export default function Page() {
+
diff --git a/app/[locale]/products/[slug]/page.tsx b/app/[locale]/catalog_page/products/[slug]/page.tsx similarity index 84% rename from app/[locale]/products/[slug]/page.tsx rename to app/[locale]/catalog_page/products/[slug]/page.tsx index da1e77a..a48308a 100644 --- a/app/[locale]/products/[slug]/page.tsx +++ b/app/[locale]/catalog_page/products/[slug]/page.tsx @@ -9,6 +9,7 @@ import { AlertCircle } from "lucide-react"; import { LoadingSkeleton } from "@/components/pages/products/slug/loading"; import { EmptyState } from "@/components/pages/products/slug/empty"; import { useEffect } from "react"; +import { Breadcrumb } from "@/components/breadCrumb"; // Types interface ProductImage { @@ -41,7 +42,7 @@ export default function SlugPage() { enabled: !!productZustand.id, }); - useEffect(()=>console.log("product detail: ",product)) + useEffect(() => console.log("product detail: ", product)); // Loading State if (isLoading) { @@ -55,12 +56,16 @@ export default function SlugPage() { // Extract images const productImages = product.images?.map((img) => img.image) || []; - const mainImage = product.images?.find((img) => img.is_main)?.image || productImages[0] || ""; - const features = product.features.map((item:any)=>item.name) + const mainImage = + product.images?.find((img) => img.is_main)?.image || productImages[0] || ""; + const features = product.features.map((item: any) => item.name); return ( -
+
+
+ +
{/* Main Product Section */}
{/* Left - Image Slider */} diff --git a/app/[locale]/products/page.tsx b/app/[locale]/catalog_page/products/page.tsx similarity index 50% rename from app/[locale]/products/page.tsx rename to app/[locale]/catalog_page/products/page.tsx index 977f133..d8e41a1 100644 --- a/app/[locale]/products/page.tsx +++ b/app/[locale]/catalog_page/products/page.tsx @@ -1,11 +1,18 @@ +"use client"; +import { Breadcrumb } from "@/components/breadCrumb"; import { ProductBanner, Products } from "@/components/pages/products"; import FilterCatalog from "@/components/pages/products/filter/catalog/filterCatalog"; +import { useSubCategory } from "@/store/useSubCategory"; export default function Page() { + const subCategory = useSubCategory((state) => state.subCategory); return (
{/* */} +
+ +
); diff --git a/app/[locale]/subCategory/page.tsx b/app/[locale]/catalog_page/subCategory/page.tsx similarity index 62% rename from app/[locale]/subCategory/page.tsx rename to app/[locale]/catalog_page/subCategory/page.tsx index 344aefd..2582ad5 100644 --- a/app/[locale]/subCategory/page.tsx +++ b/app/[locale]/catalog_page/subCategory/page.tsx @@ -1,3 +1,4 @@ +import { Breadcrumb } from "@/components/breadCrumb"; import { ProductBanner } from "@/components/pages/products"; import { MainSubCategory } from "@/components/pages/subCategory"; @@ -5,7 +6,10 @@ export default function Page() { return (
-
+
+
+ +
diff --git a/components/breadCrumb.tsx b/components/breadCrumb.tsx new file mode 100644 index 0000000..d486092 --- /dev/null +++ b/components/breadCrumb.tsx @@ -0,0 +1,195 @@ +"use client"; +import Link from "next/link"; +import { usePathname } from "next/navigation"; +import { ChevronRight, Home } from "lucide-react"; +import { useTranslations } from "next-intl"; +import { useCategory } from "@/store/useCategory"; +import { useSubCategory } from "@/store/useSubCategory"; +import { useProductPageInfo } from "@/store/useProduct"; + +interface BreadcrumbProps { + customLabels?: Record; + className?: string; +} + +export function Breadcrumb({ + customLabels = {}, + className = "", +}: BreadcrumbProps) { + const pathname = usePathname(); + const t = useTranslations(); + const category = useCategory((state) => state.category); + const subCategory = useSubCategory((state) => state.subCategory); + const product = useProductPageInfo((state) => state.product); + console.log("sub category: ", subCategory); + + // Pathdan segments olish + const segments = pathname.split("/").filter((segment) => segment !== ""); + + // Agar locale bo'lsa, uni olib tashlash (uz, en, ru) + const locales = ["uz", "en", "ru"]; + const filteredSegments = segments.filter( + (segment) => !locales.includes(segment), + ); + + // Agar faqat home page bo'lsa, breadcrumb ko'rsatmaslik + if (filteredSegments.length === 0) { + return null; + } + + // Breadcrumb items yaratish + const breadcrumbItems: Array<{ + label: string; + href: string; + isLast: boolean; + }> = []; + + // Home qo'shish (har doim birinchi) + breadcrumbItems.push({ + label: t("breadcrumb.home") || "Home", + href: "/", + isLast: false, + }); + + // Locale olish + const locale = segments.find((seg) => locales.includes(seg)) || ""; + const localePrefix = locale ? `/${locale}` : ""; + + // Segmentlarni tahlil qilish + filteredSegments.forEach((segment, index) => { + const isLast = index === filteredSegments.length - 1; + + if (segment === "catalog_page") { + // Catalog_page - asosiy kategoriyalar sahifasi + breadcrumbItems.push({ + label: t("breadcrumb.catalog_page") || "Katalog", + href: `${localePrefix}/catalog_page`, + isLast: isLast, + }); + } else if (segment === "subCategory") { + // SubCategory - kategoriya nomi ko'rsatiladi + if (category?.name) { + breadcrumbItems.push({ + label: category.name, + href: `${localePrefix}/catalog_page/subCategory`, + isLast: isLast, + }); + } + } else if (segment === "products") { + if (subCategory?.name) { + // Agar subCategory orqali kelgan bo'lsa + // 1. Kategoriya + if (category?.name) { + const categoryInBreadcrumb = breadcrumbItems.find( + (item) => item.label === category.name, + ); + if (!categoryInBreadcrumb) { + breadcrumbItems.push({ + label: category.name, + href: `${localePrefix}/catalog_page/subCategory`, + isLast: false, + }); + } + } + + // 2. SubKategoriya + breadcrumbItems.push({ + label: subCategory.name, + href: `${localePrefix}/catalog_page/subCategory`, + isLast: false, + }); + } else if (category?.name) { + // To'g'ridan-to'g'ri kategoriyadan products ga kelgan + breadcrumbItems.push({ + label: category.name, + href: `${localePrefix}/catalog_page`, + isLast: false, + }); + } + } else if (segment.startsWith("[") && segment.endsWith("]")) { + // Dynamic route (masalan, [slug]) + // Custom label yoki default + const slugValue = segment.replace(/\[|\]/g, ""); + const label = customLabels[slugValue] || slugValue; + + breadcrumbItems.push({ + label: label, + href: `${localePrefix}/${filteredSegments.slice(0, index + 1).join("/")}`, + isLast: isLast, + }); + } else { + // Boshqa segmentlar + const label = getLabel(segment); + breadcrumbItems.push({ + label: label, + href: `${localePrefix}/${filteredSegments.slice(0, index + 1).join("/")}`, + isLast: isLast, + }); + } + }); + + // Default label translator + function getLabel(segment: string): string { + // Agar custom label berilgan bo'lsa + if (customLabels[segment]) { + return customLabels[segment]; + } + + // Agar translation mavjud bo'lsa + try { + if (segment === "special_product") { + return product.name; + } + return t(`breadcrumb.${segment}`); + } catch { + // Aks holda, segment nomini formatlash + return segment + .replace(/-/g, " ") + .replace(/_/g, " ") + .split(" ") + .map((word) => word.charAt(0).toUpperCase() + word.slice(1)) + .join(" "); + } + } + + return ( + + ); +} diff --git a/components/pages/home/blog/catalog.tsx b/components/pages/home/blog/catalog.tsx index 7f01503..857b94d 100644 --- a/components/pages/home/blog/catalog.tsx +++ b/components/pages/home/blog/catalog.tsx @@ -2,14 +2,13 @@ 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() { +export default function Catalog() { const language = getRouteLang(); const { data, isLoading } = useQuery({ queryKey: ["category", language], diff --git a/components/pages/products/catalog.tsx b/components/pages/products/catalog.tsx index f718644..30818ec 100644 --- a/components/pages/products/catalog.tsx +++ b/components/pages/products/catalog.tsx @@ -84,8 +84,8 @@ export default function CatalogCard({ }; const navigateLink = have_sub_category - ? `/${locale}/subCategory?category=${id}` - : `/${locale}/products?category=${id}`; + ? `/${locale}/catalog_page/subCategory?category=${id}` + : `/${locale}/catalog_page/products?category=${id}`; return ( +
{/* Image Container */}
diff --git a/components/pages/subCategory/card.tsx b/components/pages/subCategory/card.tsx index 0730a18..a4530cc 100644 --- a/components/pages/subCategory/card.tsx +++ b/components/pages/subCategory/card.tsx @@ -32,7 +32,7 @@ export default function Card({ image, category, }); - router.push(`/${locale}/products`); + router.push(`/${locale}/catalog_page/products`); }; return ( diff --git a/messages/en.json b/messages/en.json index 34c0c91..2e144e3 100644 --- a/messages/en.json +++ b/messages/en.json @@ -222,9 +222,8 @@ "contact": "Contact", "help": "Help" }, - "address":"Tashkent city, Yunusabad district, 3rd dead-end of Niyozbek Yoli street, house 39", - "create":"Created by {name}" - + "address": "Tashkent city, Yunusabad district, 3rd dead-end of Niyozbek Yoli street, house 39", + "create": "Created by {name}" }, "rasmlar": "Images", "fotogalereya": "Photo Gallery", @@ -232,8 +231,8 @@ "contactSubTitle": "Our staff will contact you", "enterPhone": "Enter your phone number", "send": "Sent", - "error":"Error!", - "succes":"sent!", + "error": "Error!", + "succes": "sent!", "priceModal": { "title": "Get Price", "product": { @@ -257,5 +256,18 @@ }, "success": "Your request has been sent successfully!", "error": "An error occurred. Please try again." + }, + "breadcrumb": { + "home": "Home", + "about": "About Us", + "services": "Services", + "products": "Products", + "contact": "Contact", + "blog": "Blog", + "fire-safety": "Fire Safety", + "fire-alarm": "Fire Alarm", + "fire-suppression": "Fire Suppression", + "installation": "Installation", + "maintenance": "Maintenance" } } diff --git a/messages/ru.json b/messages/ru.json index db42476..1d98b25 100644 --- a/messages/ru.json +++ b/messages/ru.json @@ -222,8 +222,8 @@ "contact": "Контакты", "help": "Помощь" }, - "address":"г. Ташкент, Юнусабадский район, 3-й тупик улицы Ниязбек йўли, дом 39", - "create":"Разработано {name}" + "address": "г. Ташкент, Юнусабадский район, 3-й тупик улицы Ниязбек йўли, дом 39", + "create": "Разработано {name}" }, "rasmlar": "Изображения", "fotogalereya": "Фотогалерея", @@ -256,5 +256,18 @@ }, "success": "Ваш запрос успешно отправлен!", "error": "Произошла ошибка. Попробуйте снова." + }, + "breadcrumb": { + "home": "Главная", + "about": "О нас", + "services": "Услуги", + "products": "Продукция", + "contact": "Контакты", + "blog": "Блог", + "fire-safety": "Пожарная безопасность", + "fire-alarm": "Пожарная сигнализация", + "fire-suppression": "Пожаротушение", + "installation": "Монтаж", + "maintenance": "Техническое обслуживание" } } diff --git a/messages/uz.json b/messages/uz.json index eb2ef74..1708c56 100644 --- a/messages/uz.json +++ b/messages/uz.json @@ -223,7 +223,7 @@ "help": "Yordam" }, "address": "Toshkent shahri , Yunusabod tumani , Niyozbek yo'li 3 tor ko'chasi , 39 uy", - "create":"{name} - Jamoasi tomonidan ishlab chiqilgan" + "create": "{name} - Jamoasi tomonidan ishlab chiqilgan" }, "rasmlar": "Rasmlar", "fotogalereya": "Fotogalereya", @@ -256,5 +256,19 @@ }, "success": "So‘rovingiz muvaffaqiyatli yuborildi!", "error": "Xatolik yuz berdi. Iltimos, qayta urinib ko‘ring." + }, + "breadcrumb": { + "home": "Bosh sahifa", + "about": "Biz haqimizda", + "services": "Xizmatlar", + "catalog_page": "Mahsulotlar", + "subCategory":"{subCategory}", + "contact": "Bog'lanish", + "blog": "Blog", + "fire-safety": "Yong'in xavfsizligi", + "fire-alarm": "Yong'in signalizatsiyasi", + "fire-suppression": "Yong'in o'chirish", + "installation": "O'rnatish", + "maintenance": "Texnik xizmat" } }