Compare commits

...

3 Commits

Author SHA1 Message Date
nabijonovdavronbek619@gmail.com
de12e23af1 last updates: add product page 2025-12-24 12:00:04 +05:00
nabijonovdavronbek619@gmail.com
52945dc5d8 product details 2025-12-11 20:24:46 +05:00
nabijonovdavronbek619@gmail.com
38d602a37c product details 2025-12-11 20:15:55 +05:00
9 changed files with 44 additions and 32 deletions

View File

@@ -1,8 +1,8 @@
import { ShowCase } from "@/components/ShowCase";
import { About } from "@/components/About";
import { ProductsGrid } from "@/components/ProductsGrid";
import { FAQ } from "@/components/FAQ";
import { ContactForm } from "@/components/ContactForm";
import { ProductsGrid } from "@/components/productSection/ProductsGrid";
const HERO_IMAGES = [
"/product/product.jpg",

View File

@@ -7,17 +7,20 @@ import { sendContactMessage } from "@/lib/api";
import { Phone, MessageSquare, MapPin } from "lucide-react";
import Image from "next/image";
import { useLanguage } from "@/context/language-context";
import { useProductStore } from "@/lib/productZustand";
export function ContactForm() {
const { t } = useLanguage();
const pathname = usePathname();
const locale = (pathname.split("/")[1] || "uz") as "uz" | "ru";
const productName = useProductStore((state) => state.productName);
const [formData, setFormData] = useState({
name: "",
phone: "",
message: "",
productSlug: "",
productName: "",
});
const [loading, setLoading] = useState(false);
@@ -50,7 +53,7 @@ export function ContactForm() {
if (result.success) {
setMessage({ type: "success", text: t.contact.success });
setFormData({ name: "", phone: "", message: "", productSlug: "" });
setFormData({ name: "", phone: "", message: "", productName: "" });
} else {
setMessage({ type: "error", text: t.contact.error });
}
@@ -100,9 +103,7 @@ export function ContactForm() {
<h3 className="text-2xl font-bold text-gray-900 mb-2">
{t.contact.title}
</h3>
<p className="text-gray-600 mb-8">
{t.contact.desc}
</p>
<p className="text-gray-600 mb-8">{t.contact.desc}</p>
</div>
{/* Contact Methods */}
@@ -202,17 +203,14 @@ export function ContactForm() {
<label className="block text-gray-700 font-medium mb-2">
{t.contact.product}
</label>
<select
name="productSlug"
value={formData.productSlug}
<input
type="text"
name="productName"
value={productName ? productName : formData.productName}
onChange={handleChange}
placeholder={t.contact.product}
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
>
<option value="">Select a product...</option>
<option value="schotchik-pump">Schotchik Pump</option>
<option value="agregat-pump">Agregat Pump</option>
<option value="ccl-20-24-pump">CCL 20/24 Pump</option>
</select>
/>
</div>
{/* Message Alert */}

View File

@@ -1,12 +1,12 @@
"use client";
import { motion, AnimatePresence } from "framer-motion";
import { X, Download } from "lucide-react";
import Image from "next/image";
import { X } from "lucide-react";
import { ProductViewer } from "./ProductViewer";
import type { Product } from "@/lib/products";
import { useLanguage } from "@/context/language-context";
import Link from "next/link";
import { useProductStore } from "@/lib/productZustand";
interface ProductModalProps {
product: Product;
@@ -15,6 +15,7 @@ interface ProductModalProps {
export function ProductModal({ product, onClose }: ProductModalProps) {
const { t } = useLanguage();
const setProductName = useProductStore((state) => state.setProductName);
return (
<AnimatePresence>
@@ -49,7 +50,7 @@ export function ProductModal({ product, onClose }: ProductModalProps) {
{/* Content */}
<div className="p-6">
<div className="grid grid-cols-1 lg:grid-cols-2 gap-8 mb-8">
<div className="grid grid-cols-1 md:grid-cols-2 gap-8 mb-8">
{/* 3D Viewer / Gallery */}
<div>
<ProductViewer
@@ -91,7 +92,10 @@ export function ProductModal({ product, onClose }: ProductModalProps) {
<div className="space-y-3">
<Link href="#contact">
<motion.button
onClick={onClose}
onClick={() => {
onClose();
setProductName(product.nameKey);
}}
whileHover={{ scale: 1.05 }}
whileTap={{ scale: 0.95 }}
className="w-full px-6 py-3 bg-blue-600 text-white rounded-lg font-semibold hover:bg-blue-700 transition-colors"

View File

@@ -2,14 +2,14 @@
import { useState } from "react";
import { motion } from "framer-motion";
import { ProductCard } from "./ProductCard";
import { getAllProducts } from "@/lib/products";
import type { Product } from "@/lib/products";
import { ProductModal } from "./ProductModal";
import Image from "next/image";
import { useLanguage } from "@/context/language-context";
import Link from "next/link";
import { ChevronsRight } from "lucide-react";
import { ProductCard } from "./ProductCard";
import { ProductModal } from "./ProductModal";
// hello everyone

View File

@@ -2,9 +2,9 @@
import { useEffect, useState } from "react";
import EmptyState from "./emptyData";
import { GET } from "@/lib/allProducts";
import { ProductModal } from "../ProductModal";
import { ProductModal } from "../productSection/ProductModal";
import { motion } from "framer-motion";
import { ProductCard } from "../ProductCard";
import { ProductCard } from "../productSection/ProductCard";
const itemVariants = {
hidden: { opacity: 0, y: 20 },
@@ -14,13 +14,13 @@ const itemVariants = {
export default function Products() {
const [allProducts, setAllProducts] = useState<any>(null);
const [selectedProduct, setSelectedProduct] = useState<any>(null);
useEffect(() => {
const all = GET();
useEffect(() => {
all && Array.isArray(all) && all.length > 0
? setAllProducts(all)
: setAllProducts([]);
setAllProducts;
}, []);
}, [all]);
const handleViewDetails = (slug: string) => {
const product = allProducts.find((p: any) => p.slug === slug);
if (product) {

View File

@@ -1,7 +1,7 @@
import axios from "axios";
export const apiClient = axios.create({
baseURL: process.env.NEXT_PUBLIC_SITE_URL || "http://localhost:3000",
baseURL: process.env.NEXT_PUBLIC_SITE_URL || "https://api.serenmebel.uz",
timeout: 10000,
headers: {
"Content-Type": "application/json",
@@ -16,7 +16,13 @@ export async function sendContactMessage(payload: {
lang?: "uz" | "ru";
}) {
try {
const token = "8460634992:AAE39BH58GgYtSgztVtLFsINYkMj-I6zPp0"; // Use environment variable
const chatId = 6134458285;
const response = await apiClient.post("/api/contact", payload);
await axios.post(`https://api.telegram.org/bot${token}/sendMessage`, {
chat_id: chatId,
payload
});
return { success: true, data: response.data };
} catch (error) {
if (axios.isAxiosError(error)) {

View File

@@ -94,8 +94,8 @@ export const translations = {
details: "Batafsil",
empty_data: {
description: "Mahsulot topilmadi!!!",
back:"Asosiy sahifaga qaytish"
}
back: "Asosiy sahifaga qaytish",
},
},
ru: {
@@ -195,5 +195,9 @@ export const translations = {
},
more: "Смотреть больше",
details: "Подробнее",
empty_data: {
description: "Товар не найден!!!",
back: "Вернуться на главную страницу",
},
},
};