ceo optimization

This commit is contained in:
nabijonovdavronbek619@gmail.com
2026-01-09 17:38:01 +05:00
parent a700fdddc6
commit c2c39d44a0
11 changed files with 117 additions and 50 deletions

View File

@@ -1,14 +0,0 @@
import { ContactForm } from "@/components/ContactForm";
import DetailInfo from "@/components/detailPage/detailInfo";
import React from "react";
export default function Page() {
return (
<div>
<DetailInfo />
<section id="contact">
<ContactForm />
</section>
</div>
);
}

View File

@@ -0,0 +1,38 @@
import { ContactForm } from "@/components/ContactForm";
import DetailInfo from "@/components/detailPage/detailInfo";
import { Product } from "@/lib/products";
import { generateSlug } from "@/lib/slug";
import { getAllProducts } from "@/lib/api";
import { notFound } from "next/navigation";
export async function generateStaticParams() {
const products = await getAllProducts();
return products.map((product) => ({
slug: generateSlug(product.name_uz),
}));
}
async function getProduct(slug: string): Promise<Product | undefined> {
const products = await getAllProducts();
return products.find((product) => generateSlug(product.name_uz) === slug);
}
export default async function Page({ params }: { params: any }) {
const { slug } = await params;
const product = await getProduct(slug);
if (!product) {
notFound();
}
return (
<div>
<DetailInfo product={product} />
<section id="contact">
<ContactForm />
</section>
</div>
);
}

View File

@@ -3,14 +3,16 @@
import { motion } from "framer-motion";
import { useLanguage } from "@/context/language-context";
import Link from "next/link";
import { useProduct, useProductStore } from "@/lib/productZustand";
import Image from "next/image";
import { Product } from "@/lib/products";
export default function DetailInfo() {
interface DetailInfoProps {
product: Product;
}
export default function DetailInfo({ product }: DetailInfoProps) {
const { t, language } = useLanguage();
const languageIndex = language === "uz" ? true : false;
const product = useProduct((state) => state.product);
if (product === null) return null;
const handleScroll = (href: string) => {
const element = document.querySelector(href);
@@ -74,7 +76,7 @@ export default function DetailInfo() {
{t.features}
</h3>
<div className="space-y-3 flex items-start justify-start gap-4 flex-wrap ">
{product.features.map((spec, idx) => (
{product.features?.map((spec, idx) => (
<div
key={idx}
className="flex flex-col justify-between py-2 border border-gray-100 rounded-lg p-2"

View File

@@ -19,7 +19,7 @@ export function ProductCard({ product }: ProductCardProps) {
const setProducts = useProduct((state) => state.setProducts);
return (
<Link
href={`/detail?${languageIndex ? product.name_uz : product.name_ru}`}
href={`/product/${product.slug}`}
onClick={() => {
setProductName(languageIndex ? product.name_uz : product.name_ru);
setProducts(product);
@@ -63,14 +63,14 @@ export function ProductCard({ product }: ProductCardProps) {
</p>
{/* CTA Button - Always at Bottom */}
<motion.button
<motion.div
whileHover={{ scale: 1.02 }}
whileTap={{ scale: 0.98 }}
className="w-full flex items-center justify-center gap-2 px-6 py-3 bg-primary text-white rounded-xl font-semibold shadow-lg shadow-blue-500/30 hover:shadow-xl hover:shadow-primary/40 transition-all duration-300 group/button"
>
<span>{t.details}</span>
<ExternalLink className="w-4 h-4 group-hover/button:translate-x-1 transition-transform duration-300" />
</motion.button>
</motion.div>
</div>
{/* Decorative Corner */}

View File

@@ -11,6 +11,8 @@ import { ProductCard } from "./ProductCard";
import axios from "axios";
import EmptyState from "../productsPage/emptyData";
import Loading from "../loading";
import { getAllProducts } from "@/lib/api";
import { generateSlug } from "@/lib/slug";
// hello everyone
@@ -22,14 +24,14 @@ export function ProductsGrid() {
useEffect(() => {
async function getData() {
setLoading(true);
await axios
.get("https://admin.promtechno.uz/api/products/")
.then((res) => {
console.log("all data main page: ", res?.data);
const allData = res?.data || [];
setAllProducts(allData.slice(0, 3));
setLoading(false);
});
const products = await getAllProducts();
setAllProducts(
products.map((product: any) => ({
...product,
slug: generateSlug(product.name_uz),
})).slice(0, 3)
);
setLoading(false);
}
getData();
}, []);

View File

@@ -5,6 +5,8 @@ import { motion } from "framer-motion";
import { ProductCard } from "../productSection/ProductCard";
import axios from "axios";
import Loading from "../loading";
import { generateSlug } from "@/lib/slug";
import { getAllProducts } from "@/lib/api";
const itemVariants = {
hidden: { opacity: 0, y: 20 },
@@ -18,14 +20,14 @@ export default function Products() {
useEffect(() => {
async function getData() {
setLoading(true);
await axios
.get("https://admin.promtechno.uz/api/products/")
.then((res) => {
console.log("all data: ", res?.data);
const allData = res?.data || [];
setAllProducts(allData);
setLoading(false);
});
const products = await getAllProducts();
setAllProducts(
products.map((product: any) => ({
...product,
slug: generateSlug(product.name_uz),
}))
);
setLoading(false);
}
getData();
}, []);

14
lib/api.ts Normal file
View File

@@ -0,0 +1,14 @@
import { Product } from "@/lib/products";
export async function getAllProducts(): Promise<Product[]> {
const res = await fetch("https://admin.promtechno.uz/api/products/", {
cache: "force-cache", // build time uchun
});
if (!res.ok) {
console.log("Failed to fetch products");
return [];
}
return res.json();
}

View File

@@ -0,0 +1,17 @@
import axios from "axios";
import { generateSlug } from "./slug";
export async function generateStaticParams() {
try {
await axios.get("https://admin.promtechno.uz/api/products/").then((res) => {
console.log("all data: ", res?.data);
const allData = res?.data || [];
return allData.map((product: any) => ({
slug: generateSlug(product.name_uz),
}));
});
} catch (error) {
console.error("Error in generateStaticParams:", error);
return []; // Xato bo'lsa bo'sh array qaytarish
}
}

View File

@@ -9,18 +9,11 @@ interface ProductStore {
}
export const useProductStore = create<ProductStore>()(
devtools(
persist(
(set) => ({
productName: "",
setProductName: (name: string) => set({ productName: name }),
resetProductName: () => set({ productName: "" }),
}),
{
name: "product-storage",
}
)
)
devtools((set) => ({
productName: "",
setProductName: (name: string) => set({ productName: name }),
resetProductName: () => set({ productName: "" }),
}))
);
interface ProductDetail {

View File

@@ -13,4 +13,5 @@ export interface Product {
description_ru: string;
features:features[];
image:string;
slug?: string;
}

12
lib/slug.ts Normal file
View File

@@ -0,0 +1,12 @@
export function generateSlug(productName: string): string {
return productName
.toLowerCase()
.replace(/\s+/g, "-") // Bo'shliqlarni tire bilan almashtirish
.replace(/[()]/g, "") // Qavslarni olib tashlash
.replace(/[–—]/g, "-") // Maxsus tire'larni oddiy tire bilan
.replace(/%/g, "foiz") // % ni foiz deb yozish
.replace(/,/g, "-") // Vergullarni tire bilan
.replace(/\.+/g, "-") // Nuqtalarni tire bilan
.replace(/-+/g, "-") // Bir nechta tire'ni bitta tire bilan
.replace(/^-|-$/g, ""); // Boshi va oxiridagi tire'larni olib tashlash
}