Compare commits
3 Commits
003fa5ccce
...
de12e23af1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
de12e23af1 | ||
|
|
52945dc5d8 | ||
|
|
38d602a37c |
@@ -1,8 +1,8 @@
|
|||||||
import { ShowCase } from "@/components/ShowCase";
|
import { ShowCase } from "@/components/ShowCase";
|
||||||
import { About } from "@/components/About";
|
import { About } from "@/components/About";
|
||||||
import { ProductsGrid } from "@/components/ProductsGrid";
|
|
||||||
import { FAQ } from "@/components/FAQ";
|
import { FAQ } from "@/components/FAQ";
|
||||||
import { ContactForm } from "@/components/ContactForm";
|
import { ContactForm } from "@/components/ContactForm";
|
||||||
|
import { ProductsGrid } from "@/components/productSection/ProductsGrid";
|
||||||
|
|
||||||
const HERO_IMAGES = [
|
const HERO_IMAGES = [
|
||||||
"/product/product.jpg",
|
"/product/product.jpg",
|
||||||
|
|||||||
@@ -7,17 +7,20 @@ import { sendContactMessage } from "@/lib/api";
|
|||||||
import { Phone, MessageSquare, MapPin } from "lucide-react";
|
import { Phone, MessageSquare, MapPin } from "lucide-react";
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import { useLanguage } from "@/context/language-context";
|
import { useLanguage } from "@/context/language-context";
|
||||||
|
import { useProductStore } from "@/lib/productZustand";
|
||||||
|
|
||||||
export function ContactForm() {
|
export function ContactForm() {
|
||||||
const {t} = useLanguage();
|
const { t } = useLanguage();
|
||||||
const pathname = usePathname();
|
const pathname = usePathname();
|
||||||
const locale = (pathname.split("/")[1] || "uz") as "uz" | "ru";
|
const locale = (pathname.split("/")[1] || "uz") as "uz" | "ru";
|
||||||
|
|
||||||
|
const productName = useProductStore((state) => state.productName);
|
||||||
|
|
||||||
const [formData, setFormData] = useState({
|
const [formData, setFormData] = useState({
|
||||||
name: "",
|
name: "",
|
||||||
phone: "",
|
phone: "",
|
||||||
message: "",
|
message: "",
|
||||||
productSlug: "",
|
productName: "",
|
||||||
});
|
});
|
||||||
|
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
@@ -50,7 +53,7 @@ export function ContactForm() {
|
|||||||
|
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
setMessage({ type: "success", text: t.contact.success });
|
setMessage({ type: "success", text: t.contact.success });
|
||||||
setFormData({ name: "", phone: "", message: "", productSlug: "" });
|
setFormData({ name: "", phone: "", message: "", productName: "" });
|
||||||
} else {
|
} else {
|
||||||
setMessage({ type: "error", text: t.contact.error });
|
setMessage({ type: "error", text: t.contact.error });
|
||||||
}
|
}
|
||||||
@@ -71,7 +74,7 @@ export function ContactForm() {
|
|||||||
className="object-cover"
|
className="object-cover"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="absolute w-full h-full top-0 left-0 bg-black opacity-25 -z-40"/>
|
<div className="absolute w-full h-full top-0 left-0 bg-black opacity-25 -z-40" />
|
||||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<motion.div
|
<motion.div
|
||||||
@@ -100,9 +103,7 @@ export function ContactForm() {
|
|||||||
<h3 className="text-2xl font-bold text-gray-900 mb-2">
|
<h3 className="text-2xl font-bold text-gray-900 mb-2">
|
||||||
{t.contact.title}
|
{t.contact.title}
|
||||||
</h3>
|
</h3>
|
||||||
<p className="text-gray-600 mb-8">
|
<p className="text-gray-600 mb-8">{t.contact.desc}</p>
|
||||||
{t.contact.desc}
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Contact Methods */}
|
{/* Contact Methods */}
|
||||||
@@ -202,17 +203,14 @@ export function ContactForm() {
|
|||||||
<label className="block text-gray-700 font-medium mb-2">
|
<label className="block text-gray-700 font-medium mb-2">
|
||||||
{t.contact.product}
|
{t.contact.product}
|
||||||
</label>
|
</label>
|
||||||
<select
|
<input
|
||||||
name="productSlug"
|
type="text"
|
||||||
value={formData.productSlug}
|
name="productName"
|
||||||
|
value={productName ? productName : formData.productName}
|
||||||
onChange={handleChange}
|
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"
|
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>
|
</div>
|
||||||
|
|
||||||
{/* Message Alert */}
|
{/* Message Alert */}
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { motion, AnimatePresence } from "framer-motion";
|
import { motion, AnimatePresence } from "framer-motion";
|
||||||
import { X, Download } from "lucide-react";
|
import { X } from "lucide-react";
|
||||||
import Image from "next/image";
|
|
||||||
import { ProductViewer } from "./ProductViewer";
|
import { ProductViewer } from "./ProductViewer";
|
||||||
import type { Product } from "@/lib/products";
|
import type { Product } from "@/lib/products";
|
||||||
import { useLanguage } from "@/context/language-context";
|
import { useLanguage } from "@/context/language-context";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
|
import { useProductStore } from "@/lib/productZustand";
|
||||||
|
|
||||||
interface ProductModalProps {
|
interface ProductModalProps {
|
||||||
product: Product;
|
product: Product;
|
||||||
@@ -15,6 +15,7 @@ interface ProductModalProps {
|
|||||||
|
|
||||||
export function ProductModal({ product, onClose }: ProductModalProps) {
|
export function ProductModal({ product, onClose }: ProductModalProps) {
|
||||||
const { t } = useLanguage();
|
const { t } = useLanguage();
|
||||||
|
const setProductName = useProductStore((state) => state.setProductName);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AnimatePresence>
|
<AnimatePresence>
|
||||||
@@ -49,7 +50,7 @@ export function ProductModal({ product, onClose }: ProductModalProps) {
|
|||||||
|
|
||||||
{/* Content */}
|
{/* Content */}
|
||||||
<div className="p-6">
|
<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 */}
|
{/* 3D Viewer / Gallery */}
|
||||||
<div>
|
<div>
|
||||||
<ProductViewer
|
<ProductViewer
|
||||||
@@ -91,7 +92,10 @@ export function ProductModal({ product, onClose }: ProductModalProps) {
|
|||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
<Link href="#contact">
|
<Link href="#contact">
|
||||||
<motion.button
|
<motion.button
|
||||||
onClick={onClose}
|
onClick={() => {
|
||||||
|
onClose();
|
||||||
|
setProductName(product.nameKey);
|
||||||
|
}}
|
||||||
whileHover={{ scale: 1.05 }}
|
whileHover={{ scale: 1.05 }}
|
||||||
whileTap={{ scale: 0.95 }}
|
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"
|
className="w-full px-6 py-3 bg-blue-600 text-white rounded-lg font-semibold hover:bg-blue-700 transition-colors"
|
||||||
@@ -2,14 +2,14 @@
|
|||||||
|
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { motion } from "framer-motion";
|
import { motion } from "framer-motion";
|
||||||
import { ProductCard } from "./ProductCard";
|
|
||||||
import { getAllProducts } from "@/lib/products";
|
import { getAllProducts } from "@/lib/products";
|
||||||
import type { Product } from "@/lib/products";
|
import type { Product } from "@/lib/products";
|
||||||
import { ProductModal } from "./ProductModal";
|
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import { useLanguage } from "@/context/language-context";
|
import { useLanguage } from "@/context/language-context";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { ChevronsRight } from "lucide-react";
|
import { ChevronsRight } from "lucide-react";
|
||||||
|
import { ProductCard } from "./ProductCard";
|
||||||
|
import { ProductModal } from "./ProductModal";
|
||||||
|
|
||||||
// hello everyone
|
// hello everyone
|
||||||
|
|
||||||
@@ -2,9 +2,9 @@
|
|||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import EmptyState from "./emptyData";
|
import EmptyState from "./emptyData";
|
||||||
import { GET } from "@/lib/allProducts";
|
import { GET } from "@/lib/allProducts";
|
||||||
import { ProductModal } from "../ProductModal";
|
import { ProductModal } from "../productSection/ProductModal";
|
||||||
import { motion } from "framer-motion";
|
import { motion } from "framer-motion";
|
||||||
import { ProductCard } from "../ProductCard";
|
import { ProductCard } from "../productSection/ProductCard";
|
||||||
|
|
||||||
const itemVariants = {
|
const itemVariants = {
|
||||||
hidden: { opacity: 0, y: 20 },
|
hidden: { opacity: 0, y: 20 },
|
||||||
@@ -14,13 +14,13 @@ const itemVariants = {
|
|||||||
export default function Products() {
|
export default function Products() {
|
||||||
const [allProducts, setAllProducts] = useState<any>(null);
|
const [allProducts, setAllProducts] = useState<any>(null);
|
||||||
const [selectedProduct, setSelectedProduct] = useState<any>(null);
|
const [selectedProduct, setSelectedProduct] = useState<any>(null);
|
||||||
|
const all = GET();
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const all = GET();
|
|
||||||
all && Array.isArray(all) && all.length > 0
|
all && Array.isArray(all) && all.length > 0
|
||||||
? setAllProducts(all)
|
? setAllProducts(all)
|
||||||
: setAllProducts([]);
|
: setAllProducts([]);
|
||||||
setAllProducts;
|
setAllProducts;
|
||||||
}, []);
|
}, [all]);
|
||||||
const handleViewDetails = (slug: string) => {
|
const handleViewDetails = (slug: string) => {
|
||||||
const product = allProducts.find((p: any) => p.slug === slug);
|
const product = allProducts.find((p: any) => p.slug === slug);
|
||||||
if (product) {
|
if (product) {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
|
|
||||||
export const apiClient = axios.create({
|
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,
|
timeout: 10000,
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
@@ -16,7 +16,13 @@ export async function sendContactMessage(payload: {
|
|||||||
lang?: "uz" | "ru";
|
lang?: "uz" | "ru";
|
||||||
}) {
|
}) {
|
||||||
try {
|
try {
|
||||||
|
const token = "8460634992:AAE39BH58GgYtSgztVtLFsINYkMj-I6zPp0"; // Use environment variable
|
||||||
|
const chatId = 6134458285;
|
||||||
const response = await apiClient.post("/api/contact", payload);
|
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 };
|
return { success: true, data: response.data };
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (axios.isAxiosError(error)) {
|
if (axios.isAxiosError(error)) {
|
||||||
|
|||||||
@@ -92,10 +92,10 @@ export const translations = {
|
|||||||
},
|
},
|
||||||
more: "Ko'proq ko'rish",
|
more: "Ko'proq ko'rish",
|
||||||
details: "Batafsil",
|
details: "Batafsil",
|
||||||
empty_data:{
|
empty_data: {
|
||||||
description:"Mahsulot topilmadi!!!",
|
description: "Mahsulot topilmadi!!!",
|
||||||
back:"Asosiy sahifaga qaytish"
|
back: "Asosiy sahifaga qaytish",
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
ru: {
|
ru: {
|
||||||
@@ -195,5 +195,9 @@ export const translations = {
|
|||||||
},
|
},
|
||||||
more: "Смотреть больше",
|
more: "Смотреть больше",
|
||||||
details: "Подробнее",
|
details: "Подробнее",
|
||||||
|
empty_data: {
|
||||||
|
description: "Товар не найден!!!",
|
||||||
|
back: "Вернуться на главную страницу",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user