slider component updated

This commit is contained in:
nabijonovdavronbek619@gmail.com
2026-04-28 11:29:06 +05:00
parent cfa84d04ab
commit 77c6baaa55
25 changed files with 1308 additions and 1770 deletions

View File

@@ -6,12 +6,22 @@ import Link from "next/link";
import Text from "../lib_components/text";
import { motion } from "framer-motion";
import { useParams } from "next/navigation";
import { useSubCategory } from "@/store/subCategory";
export default function SliderCard({ data }: { data: ProductTypes }) {
const router = useParams();
const setInitialSubcategory = useSubCategory(
(state) => state.setInitialSubCategory,
);
return (
<Link
href={`/${router.lang}/${data.path}`}
href={`/${router.lang}/${data.id}`}
onClick={() => {
setInitialSubcategory({
name:data.truck_name,
id: data.id,
});
}}
id="news_slider_card"
className="group hover:cursor-pointer block"
>

View File

@@ -3,7 +3,7 @@
import { innerCardTypes } from "@/types";
import React, { useState, useEffect } from "react";
import axios from "axios";
import { useTranslation } from "react-i18next";
import { useTranslations } from "next-intl";
interface CarRentalModalProps {
car: innerCardTypes;
@@ -16,7 +16,7 @@ export default function CarRentalModal({
isOpen,
onClose,
}: CarRentalModalProps) {
const { t } = useTranslation();
const t = useTranslations();
const [userName, setUserName] = useState("");
const [phone, setPhone] = useState("+998 ");
const [phoneError, setPhoneError] = useState("");
@@ -50,7 +50,6 @@ export default function CarRentalModal({
if (phoneError) setPhoneError("");
};
// 🧩 Telegramga yuboruvchi funksiya
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
@@ -65,13 +64,11 @@ export default function CarRentalModal({
}
try {
// ⚙️ Telegram bot ma'lumotlari
const token =
process.env.NEXT_PUBLIC_TELEGRAM_TOKEN ||
"7940057045:AAHRFPvgUCo_7pqpXD6uq4li7-_DYx2J96g";
const chatId = process.env.NEXT_PUBLIC_TELEGRAM_CHAT_ID || "6134458285";
// 🧾 Yuboriladigan xabar
const message = `
🚗 *Yangi buyurtma!*
@@ -82,14 +79,13 @@ export default function CarRentalModal({
💰 Umumiy summa: ${total?.toLocaleString("uz-UZ")} UZS
📦 Mashina: ${car.name}
⛽️ Yoqilgi turi: ${car.fuelType || "Nomalum"}
⛽️ Yoqilg'i turi: ${car.fuelType || "Noma'lum"}
⚙️ Dvigatel: ${car.enginePower_hp || "-"}
🚀 Maks tezlik: ${car.maxSpeed_kmh ? car.maxSpeed_kmh + " km/soat" : "-"}
📝 Qoshimcha malumot: ${car.path || "-"}
📝 Qo'shimcha ma'lumot: ${car.path || "-"}
`;
// 📤 Telegram API orqali yuborish
await axios.post(`https://api.telegram.org/bot${token}/sendMessage`, {
chat_id: chatId,
text: message,
@@ -112,7 +108,6 @@ export default function CarRentalModal({
return (
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/50 backdrop-blur-sm p-4">
<div className="bg-white rounded-xl shadow-xl max-w-lg w-full p-6 relative animate-fade-in">
{/* Close button */}
<button
className="absolute top-4 right-4 text-gray-500 hover:text-gray-900 text-2xl font-bold transition"
onClick={onClose}
@@ -120,7 +115,6 @@ export default function CarRentalModal({
×
</button>
{/* Header */}
<div className="flex flex-col md:flex-row gap-4">
<div className="flex-1">
<h2 className="text-2xl font-bold text-gray-800">{car.name}</h2>
@@ -129,14 +123,14 @@ export default function CarRentalModal({
{t("modal-hourly-price")}{" "}
<span className="text-red-600">
{car.price
? Math.round(Number(car.price)).toLocaleString("ru-RU")
: ""} UZS
? Math.round(Number(car.price)).toLocaleString("ru-RU")
: ""}{" "}
UZS
</span>
</p>
</div>
</div>
{/* Form */}
<form onSubmit={handleSubmit} className="mt-6 space-y-4">
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
@@ -186,9 +180,8 @@ export default function CarRentalModal({
<div className="text-lg font-semibold text-gray-800 mt-2">
{t("modal-total")}{" "}
<span className="text-green-600">
{total
? Math.round(Number(total)).toLocaleString("ru-RU")
: ""} UZS
{total ? Math.round(Number(total)).toLocaleString("ru-RU") : ""}{" "}
UZS
</span>
</div>

View File

@@ -1,8 +1,8 @@
'use client'
import { useTranslation } from "react-i18next";
import { useTranslations } from "next-intl";
export default function Text({txt}:{txt:string}) {
const { t } = useTranslation();
export default function Text({ txt }: { txt: string }) {
const t = useTranslations();
return <div>{t(txt)}</div>;
}

View File

@@ -1,10 +1,10 @@
'use client'
import React from 'react'
import { useTranslation } from 'react-i18next'
import { useTranslations } from 'next-intl'
export default function Time() {
const {t} = useTranslation();
const t = useTranslations();
return (
<div dir='ltr' className='icon_animation2 fixed bottom-10 right-20 z-40 rounded-[50%] bg-primary p-5 text-lg text-secondary flex flex-col items-center justify-center'>
<p>{t('work_day_title')}</p>

View File

@@ -1,11 +1,8 @@
"use client";
import { FaLocationDot } from "react-icons/fa6";
import Text from "../lib_components/text";
import { useTranslation } from "react-i18next";
export default function Header() {
const { t } = useTranslation();
return (
<div
dir="ltr"

View File

@@ -2,26 +2,25 @@
"use client";
import { useEffect, useState } from "react";
import i18n from "@/i18n";
import { animateScroll as scroll } from "react-scroll";
import Text from "../lib_components/text";
import "./navbar.css";
import { logoImg } from "@/assets";
import Image from "next/image";
import { usePathname, useRouter } from "next/navigation";
import { X } from "lucide-react"; // ❗ exit icon
import { X } from "lucide-react";
import { useLocale } from "next-intl";
import { useRouter, usePathname } from "@/i18n/navigation";
export default function Navbar() {
const router = useRouter();
const pathname = usePathname();
const locale = useLocale();
const [toggle, setToggle] = useState(false);
const [togglerIcon, setTogglerIcon] = useState("toggler");
const [lang, setLang] = useState<"uz" | "ru">("uz");
const handleChangeLang = (lng: "uz" | "ru") => {
setLang(lng);
i18n.changeLanguage(lng);
router.replace(pathname, { locale: lng });
};
const changeToggler = () => {
@@ -32,26 +31,23 @@ export default function Navbar() {
};
const scrollOrRoute = (id: string) => {
if (pathname !== `/${lang}`) {
// Agar user boshqa sahifada bo'lsa asosiy sahifaga yo'naltirish
router.push(`/${lang}#${id}`);
if (pathname !== "/") {
router.push(`/#${id}`);
} else {
// Agar main page-da bo'lsa scroll qilish
scroll.scrollTo(document.getElementById(id)!.offsetTop - 100);
}
changeToggler();
};
const goHome = () => {
router.push(`/${lang}`);
router.push("/");
};
// ❗ Scrollni bloklash uchun effect
useEffect(() => {
if (toggle) {
document.body.style.overflow = "hidden"; // orqa scrollni ochir
document.body.style.overflow = "hidden";
} else {
document.body.style.overflow = "auto"; // qayta yoq
document.body.style.overflow = "auto";
}
}, [toggle]);
@@ -69,9 +65,9 @@ export default function Navbar() {
<button
onClick={() => handleChangeLang("uz")}
className={`hover:cursor-pointer ${
lang === "uz" && "bg-secondary text-primary rounded-[8px]"
locale === "uz" && "bg-secondary text-primary rounded-[8px]"
} px-2 py-1 text-[20px] ${
lang !== "uz" && "border-l-2 border-b-2 border-primary"
locale !== "uz" && "border-l-2 border-b-2 border-primary"
} `}
>
UZ
@@ -79,9 +75,9 @@ export default function Navbar() {
<button
onClick={() => handleChangeLang("ru")}
className={`hover:cursor-pointer ${
lang === "ru" && "bg-secondary text-primary rounded-[8px]"
locale === "ru" && "bg-secondary text-primary rounded-[8px]"
} px-2 py-1 text-[20px] ${
lang !== "ru" && "border-r-2 border-b-2 border-primary"
locale !== "ru" && "border-r-2 border-b-2 border-primary"
}`}
>
RU

View File

@@ -1,7 +1,7 @@
"use client";
import { useState } from "react";
import { useTranslation } from "react-i18next";
import { useTranslations } from "next-intl";
import Text from "../lib_components/text";
import axios from "axios";
import { FormEvent } from "react";
@@ -42,7 +42,7 @@ const isValidPhone = (value: string) => {
};
export default function Contact() {
const { t } = useTranslation();
const t = useTranslations();
const [phone, setPhone] = useState("");
const handlePhoneChange = (value: string) => {
@@ -63,7 +63,7 @@ export default function Contact() {
: `+998${normalized}`;
try {
const token = "7940057045:AAHRFPvgUCo_7pqpXD6uq4li7-_DYx2J96g"; // Use environment variable
const token = "7940057045:AAHRFPvgUCo_7pqpXD6uq4li7-_DYx2J96g";
const chatId = 6134458285;
if (!token || !chatId) {
@@ -99,7 +99,6 @@ export default function Contact() {
<Text txt="contact-h2" />
</h2>
{/* Form */}
<form
className="flex max-sm:flex-col gap-5 w-full max-w-2xl px-4"
onSubmit={sendMessage}

View File

@@ -6,13 +6,89 @@ import "swiper/css";
import "swiper/css/navigation";
import Title from "../lib_components/title";
import SliderCard from "../cards/sliderCard";
import { sliderData } from "@/data";
import { useEffect, useState } from "react";
import { ProductTypes } from "@/types";
import { usePathname } from "next/navigation";
import Text from "../lib_components/text";
import { LoadingSkeleton } from "../loadingProduct";
import { baseUrl } from "@/data/url";
// The custom CSS selectors for navigation
const navigationPrevEl = ".custom-swiper-prev";
const navigationNextEl = ".custom-swiper-next";
function getRandomItems(arr: any[], count: number) {
const shuffled = [...arr];
for (let i = shuffled.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];
}
return shuffled.slice(0, count);
}
export default function CustomSlider() {
const [cars, setCars] = useState<ProductTypes[]>([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
const pathname = usePathname();
const lang = pathname.split("/")[1];
useEffect(() => {
const fetchProducts = async () => {
try {
setLoading(true);
setError(null);
const response = await fetch(baseUrl, {
headers: {
"Accept-Language": lang,
},
});
if (!response.ok) {
throw new Error("Server xatosi");
}
const data = await response.json();
console.log("backend Data slider: ", data?.data);
if (data?.data && data.data.length > 0) {
const dataSlider = getRandomItems(data.data, 6);
const formattedData = dataSlider.map((item) => ({
id: item.id,
truck_name: item.name,
desc: "news-title1",
image: item.image || "",
}));
setCars(formattedData);
} else {
setCars([]);
}
} catch (error) {
console.log("Xatolik: ", error);
setError(error instanceof Error ? error.message : "Noma'lum xatolik");
} finally {
setLoading(false);
}
};
fetchProducts();
}, [lang]);
if (error) {
return (
<div className="mb-4 p-4 bg-red-50 border border-red-200 rounded-lg">
<p className="text-red-600 text-center">
<Text txt="downloadError" /> : {error}
</p>
</div>
);
}
if (loading) {
return <LoadingSkeleton />;
}
return (
<div
dir="ltr"
@@ -29,7 +105,7 @@ export default function CustomSlider() {
<button
className={`${navigationPrevEl.replace(
".",
""
"",
)} w-10 h-10 p-0 bg-primary text-[30px] text-center text-white flex items-center justify-center hover:bg-secondary hover:cursor-pointer transition`}
>
@@ -37,7 +113,7 @@ export default function CustomSlider() {
<button
className={`${navigationNextEl.replace(
".",
""
"",
)} w-10 h-10 bg-primary text-[30px] text-center text-white flex items-center justify-center hover:bg-secondary hover:cursor-pointer transition `}
>
@@ -62,7 +138,7 @@ export default function CustomSlider() {
1024: { slidesPerView: 3 },
}}
>
{sliderData.map((item, index) => (
{cars.map((item, index) => (
<SwiperSlide key={index}>
<SliderCard data={item} />
</SwiperSlide>

View File

@@ -4,7 +4,6 @@ import React, { useEffect, useState } from "react";
import Title from "../../lib_components/title";
import Text from "../../lib_components/text";
import type { ProductTypes } from "@/types";
import { allProducts } from "@/data";
import ProductCard from "../../cards/productCard";
import { LoadingSkeleton } from "@/components/loadingProduct";
import { EmptyState } from "@/components/emptyState";
@@ -45,15 +44,13 @@ export default function Products() {
} catch (error) {
console.log("Xatolik: ", error);
setError(error instanceof Error ? error.message : "Noma'lum xatolik");
// Xatolik bo'lsa ham local data'ni ko'rsatish
setCars(allProducts);
} finally {
setLoading(false);
}
};
fetchProducts();
}, [lang]); // Bo'sh array - faqat bitta marta ishlaydi
}, [lang]);
return (
<div dir="ltr" className="max-w-[1200px] w-full mx-auto">