Compare commits
14 Commits
4fa3a6d89c
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
18b2bfdfc4 | ||
|
|
d12c0797a4 | ||
|
|
d089551d0f | ||
|
|
e7b838e3fe | ||
|
|
1d0698573f | ||
|
|
71a21fc084 | ||
|
|
61d41fd7c9 | ||
|
|
e2e9cbccbe | ||
|
|
24f2b78adf | ||
|
|
e15dc486ae | ||
|
|
0146ed43e8 | ||
|
|
c7ee0e3292 | ||
|
|
c9ae02bdd1 | ||
|
|
d5896378db |
@@ -3,45 +3,85 @@
|
||||
import { useCarDetail } from "@/components/lib_components/carDetailProvider";
|
||||
import Text from "@/components/lib_components/text";
|
||||
import Image from "next/image";
|
||||
import React, { useState } from "react";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import CarRentalModal from "@/components/lib_components/carRentalModal";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useCarType } from "@/store/carType";
|
||||
import { usePathname } from "next/navigation";
|
||||
import { logoImg } from "@/assets";
|
||||
|
||||
const baseUrl = "https://api.spes-texnika.uz/api/v1/products/";
|
||||
|
||||
export default function CarDetailPage() {
|
||||
const { detail } = useCarDetail();
|
||||
const [modalOpen, setModalOpen] = useState<boolean>(false);
|
||||
const { t } = useTranslation();
|
||||
|
||||
if (!detail) {
|
||||
return (
|
||||
<div className="my-20 text-center text-gray-500">
|
||||
<Text txt="Mahsulot topilmadi yoki hali tanlanmagan." />
|
||||
</div>
|
||||
);
|
||||
// tools of request
|
||||
const initialCar = useCarType((state) => state.initialCar);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const pathname = usePathname();
|
||||
const lang = pathname.split("/")[1];
|
||||
const [cars, setCars] = useState<any[]>([]);
|
||||
|
||||
console.log("car type id: ", initialCar.id);
|
||||
console.log("request URL: ", `${baseUrl}${initialCar.id}/`);
|
||||
|
||||
useEffect(() => {
|
||||
// Agar ID bo'lmasa, fetchni ishga tushirma
|
||||
if (!initialCar.id) {
|
||||
setLoading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
const {t} = useTranslation();
|
||||
const fetchProducts = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
|
||||
const techSpecs: Record<string, string | number | undefined> = {
|
||||
[t("weight_kg")]: detail.weight_kg && `${detail.weight_kg.toLocaleString("uz-UZ")} kg`,
|
||||
[t("maxLength_m")]: detail.maxLength_m && `${detail.maxLength_m} m`,
|
||||
[t("maxHeight_m")]: detail.maxHeight_m && `${detail.maxHeight_m} m`,
|
||||
[t("capacity_tons")]: detail.capacity_tons && `${detail.capacity_tons} t`,
|
||||
[t("capacity_kg")]: detail.capacity_kg && `${detail.capacity_kg} kg`,
|
||||
[t("fuelType")]: detail.fuelType,
|
||||
[t("tankVolume_m3")]: detail.tankVolume_m3 && `${detail.tankVolume_m3} m³`,
|
||||
[t("maxSpeed_kmh")]: detail.maxSpeed_kmh && `${detail.maxSpeed_kmh} km/soat`,
|
||||
[t("intercooler")]: detail.intercooler,
|
||||
[t("enginePower_hp")]: detail.enginePower_hp,
|
||||
[t("transmission")]: detail.transmission,
|
||||
[t("bom")]: detail.bom && `${detail.bom} m`,
|
||||
[t("qazish")]: detail.qazish && `${detail.qazish} m`,
|
||||
[t("pichoq")]: detail.pichoq && `${detail.pichoq} m`,
|
||||
[t("zichlash")]: detail.zichlash && `${detail.zichlash} m`,
|
||||
[t("siqish")]: detail.siqish && `${detail.siqish} bar`,
|
||||
[t("havo")]: detail.havo && `${detail.havo} l`,
|
||||
[t("kompressor_sig")]: detail.kompressor_sig && `${detail.kompressor_sig} l`
|
||||
const response = await fetch(`${baseUrl}${initialCar.id}/`, {
|
||||
headers: {
|
||||
"Accept-Language": lang,
|
||||
},
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error("Server xatosi");
|
||||
}
|
||||
|
||||
const result = await response.json();
|
||||
console.log("backend full response: ", result);
|
||||
console.log("backend Data: ", result?.data);
|
||||
|
||||
// Data array ekanligini tekshirish
|
||||
if (result?.data) {
|
||||
if (Array.isArray(result.data)) {
|
||||
setCars(result.data);
|
||||
} else {
|
||||
// Agar object bo'lsa, uni array ichiga o'rab qo'yamiz
|
||||
setCars([result.data]);
|
||||
}
|
||||
} else {
|
||||
setCars([]);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("Xatolik: ", error);
|
||||
setError(error instanceof Error ? error.message : "Noma'lum xatolik");
|
||||
setCars([]);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
fetchProducts();
|
||||
}, [lang]); // initialCar.id ham dependency ga qo'shildi
|
||||
|
||||
const firstData = cars ? cars[0] : undefined;
|
||||
|
||||
if (!firstData) {
|
||||
return <>Maluot topilmadi</>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
dir="ltr"
|
||||
@@ -49,7 +89,7 @@ export default function CarDetailPage() {
|
||||
>
|
||||
{/* 1️⃣ Mashina nomi */}
|
||||
<div className="text-2xl font-bold w-full text-center text-secondary mb-10">
|
||||
<Text txt={detail.name} />
|
||||
<Text txt={""} />
|
||||
</div>
|
||||
|
||||
{/* 2️⃣ Rasmi + asosiy narx ma’lumotlari */}
|
||||
@@ -57,8 +97,8 @@ export default function CarDetailPage() {
|
||||
{/* Mashina rasmi */}
|
||||
<div className="max-w-[600px] w-full h-auto">
|
||||
<Image
|
||||
src={detail.image}
|
||||
alt={detail.name}
|
||||
src={firstData?.image ? firstData?.image : logoImg}
|
||||
alt={firstData?.name ? firstData?.name : "image"}
|
||||
width={600}
|
||||
height={200}
|
||||
className="rounded-lg object-cover border border-gray-200 w-full"
|
||||
@@ -70,24 +110,17 @@ export default function CarDetailPage() {
|
||||
<div className="text-lg font-semibold flex gap-2">
|
||||
<Text txt="hour-price" />
|
||||
<span className="font-medium flex gap-2 text-gray-500">
|
||||
{detail.price?.toLocaleString("uz-UZ")}
|
||||
{firstData.price?.toLocaleString("uz-UZ")}
|
||||
<Text txt="wallet" />
|
||||
</span>
|
||||
</div>
|
||||
<div className="text-lg font-semibold flex gap-2">
|
||||
<Text txt="min-time" />
|
||||
<span className="font-medium flex gap-2 text-gray-500">
|
||||
{detail.min_order_time}
|
||||
{firstData.minimal_order}
|
||||
<Text txt="time" />
|
||||
</span>
|
||||
</div>
|
||||
<div className="text-lg font-semibold flex gap-2">
|
||||
<Text txt="day-price" />
|
||||
<span className="font-medium flex gap-2 text-gray-500">
|
||||
{detail.price && (detail.price * 8).toLocaleString("uz-UZ")}
|
||||
<Text txt="wallet" />
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/* Izoh */}
|
||||
<div className="space-y-2 text-gray-500 text-lg">
|
||||
@@ -110,17 +143,17 @@ export default function CarDetailPage() {
|
||||
|
||||
{/* 3️⃣ Texnik xususiyatlar (faqat mavjudlari) */}
|
||||
<div className="w-full border-t border-gray-300 pt-6">
|
||||
<h2 className="text-xl font-semibold mb-4 text-secondary">Texnik xususiyatlari</h2>
|
||||
<h2 className="text-xl font-semibold mb-4 text-secondary">
|
||||
Texnik xususiyatlari
|
||||
</h2>
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4 text-gray-700">
|
||||
{Object.entries(techSpecs)
|
||||
.filter(([_, value]) => value !== undefined)
|
||||
.map(([key, value]) => (
|
||||
{firstData?.features.map((item: any) => (
|
||||
<div
|
||||
key={key}
|
||||
key={item.id}
|
||||
className="p-3 rounded-md bg-gray-50 border border-gray-200 hover:bg-gray-100 transition"
|
||||
>
|
||||
<p className="font-medium">{key}:</p>
|
||||
<p className="text-gray-600">{value}</p>
|
||||
<p className="font-medium">{item?.name}:</p>
|
||||
<p className="text-gray-600">{item?.value}</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
@@ -128,7 +161,7 @@ export default function CarDetailPage() {
|
||||
|
||||
{/* 4️⃣ Ijara modal */}
|
||||
<CarRentalModal
|
||||
car={detail}
|
||||
car={firstData}
|
||||
isOpen={modalOpen}
|
||||
onClose={() => setModalOpen(false)}
|
||||
/>
|
||||
|
||||
@@ -1,180 +1,100 @@
|
||||
"use client";
|
||||
|
||||
import InnerProductcard from "@/components/cards/innerProductcard";
|
||||
import { EmptyState } from "@/components/emptyState";
|
||||
import Text from "@/components/lib_components/text";
|
||||
import Title from "@/components/lib_components/title";
|
||||
import {
|
||||
asfalt,
|
||||
assenizator,
|
||||
avtogreyderlar,
|
||||
avtokran,
|
||||
avtominora,
|
||||
betonNasoslar,
|
||||
buldozerlar,
|
||||
cement_trucks,
|
||||
dumb_trucks,
|
||||
eks_yuklagichlar,
|
||||
evakuatorDemo,
|
||||
forkliftlar,
|
||||
gildirakli_eks,
|
||||
katkalar,
|
||||
manipulyator,
|
||||
mini_eks,
|
||||
minora,
|
||||
old_yuklagichlar,
|
||||
paletli_eks,
|
||||
shalandaTraller,
|
||||
teleskop_yuklagichlar,
|
||||
trailers,
|
||||
vodovoz,
|
||||
} from "@/data";
|
||||
import { useParams } from "next/navigation";
|
||||
import { LoadingSkeleton } from "@/components/loadingProduct";
|
||||
import { useCarType } from "@/store/carType";
|
||||
import { usePathname } from "next/navigation";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
const baseUrl = "https://api.spes-texnika.uz/api/v1/subcategory/?category=";
|
||||
|
||||
export default function CartType() {
|
||||
const router = useParams();
|
||||
const carType = router.carType;
|
||||
const initialCar = useCarType((state) => state.initialCar);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const pathname = usePathname();
|
||||
const lang = pathname.split("/")[1];
|
||||
const [cars, setCars] = useState<any[]>([]);
|
||||
|
||||
console.log("car type id: ", initialCar.id);
|
||||
console.log("request URL: ", `${baseUrl}${initialCar.id}`);
|
||||
|
||||
useEffect(() => {
|
||||
// Agar ID bo'lmasa, fetchni ishga tushirma for gitea
|
||||
if (!initialCar.id) {
|
||||
setLoading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
const fetchProducts = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
|
||||
const response = await fetch(`${baseUrl}${initialCar.id}`, {
|
||||
headers: {
|
||||
"Accept-Language": lang,
|
||||
},
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error("Server xatosi");
|
||||
}
|
||||
|
||||
const result = await response.json();
|
||||
console.log("backend full response: ", result);
|
||||
console.log("backend Data: ", result?.data);
|
||||
|
||||
// Data array ekanligini tekshirish
|
||||
if (result?.data) {
|
||||
if (Array.isArray(result.data)) {
|
||||
setCars(result.data);
|
||||
} else {
|
||||
// Agar object bo'lsa, uni array ichiga o'rab qo'yamiz
|
||||
setCars([result.data]);
|
||||
}
|
||||
} else {
|
||||
setCars([]);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("Xatolik: ", error);
|
||||
setError(error instanceof Error ? error.message : "Noma'lum xatolik");
|
||||
setCars([]);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
fetchProducts();
|
||||
}, [lang]); // initialCar.id ham dependency ga qo'shildi
|
||||
|
||||
return (
|
||||
<div dir="ltr" className="my-20">
|
||||
<Title text="tex-rent" />
|
||||
|
||||
{/* Error message */}
|
||||
{error && (
|
||||
<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>
|
||||
)}
|
||||
|
||||
{/* car type groups */}
|
||||
<div className="mt-10 grid lg:grid-cols-3 sm:grid-cols-2 grid-cols-1 gap-5 max-w-[1200px] w-full mx-auto">
|
||||
{/* Avtosementavoz */}
|
||||
{carType === "cement-truck" &&
|
||||
cement_trucks.map((item) => {
|
||||
return <InnerProductcard data={item} key={item.id} />;
|
||||
})}
|
||||
|
||||
{/* Samasvallar */}
|
||||
{carType === "dumb-truck" &&
|
||||
dumb_trucks.map((item) => {
|
||||
return <InnerProductcard data={item} key={item.id} />;
|
||||
})}
|
||||
|
||||
{/* Traylerlar */}
|
||||
{carType === "trailers" &&
|
||||
trailers.map((item) => {
|
||||
return <InnerProductcard data={item} key={item.id} />;
|
||||
})}
|
||||
|
||||
{/* Avtominora */}
|
||||
{carType === "avtotowers" &&
|
||||
avtominora.map((item) => {
|
||||
return <InnerProductcard data={item} key={item.id} />;
|
||||
})}
|
||||
|
||||
{/* Avtokran */}
|
||||
{carType === "avtocranes" &&
|
||||
avtokran.map((item) => {
|
||||
return <InnerProductcard data={item} key={item.id} />;
|
||||
})}
|
||||
|
||||
{/* Minora kranlar */}
|
||||
{carType === "tower-cranes" &&
|
||||
minora.map((item) => {
|
||||
return <InnerProductcard data={item} key={item.id} />;
|
||||
})}
|
||||
|
||||
{/* old yuklagichlar */}
|
||||
{carType === "front-loaders" &&
|
||||
old_yuklagichlar.map((item) => {
|
||||
return <InnerProductcard data={item} key={item.id} />;
|
||||
})}
|
||||
|
||||
{/* Teleskopik yuklagichlar */}
|
||||
{carType === "tele-loaders" &&
|
||||
teleskop_yuklagichlar.map((item) => {
|
||||
return <InnerProductcard data={item} key={item.id} />;
|
||||
})}
|
||||
|
||||
{/* forkliftlar */}
|
||||
{carType === "forklift-trucks" &&
|
||||
forkliftlar.map((item) => {
|
||||
return <InnerProductcard data={item} key={item.id} />;
|
||||
})}
|
||||
|
||||
{/* Paletli ekskavatorlar */}
|
||||
{carType === "crawler-excavators" &&
|
||||
paletli_eks.map((item) => {
|
||||
return <InnerProductcard data={item} key={item.id} />;
|
||||
})}
|
||||
|
||||
{/* G'ildirakli ekskavatorlar */}
|
||||
{carType === "wheel-excavators" &&
|
||||
gildirakli_eks.map((item) => {
|
||||
return <InnerProductcard data={item} key={item.id} />;
|
||||
})}
|
||||
|
||||
{/* Mini-ekskavatorlar */}
|
||||
{carType === "mini-excavators" &&
|
||||
mini_eks.map((item) => {
|
||||
return <InnerProductcard data={item} key={item.id} />;
|
||||
})}
|
||||
|
||||
{/* ekskavator yuklagichlar */}
|
||||
{carType === "excavator-loaders" &&
|
||||
eks_yuklagichlar.map((item) => {
|
||||
return <InnerProductcard data={item} key={item.id} />;
|
||||
})}
|
||||
|
||||
{/* avtogreyderlar */}
|
||||
{carType === "avtograders" &&
|
||||
avtogreyderlar.map((item) => {
|
||||
return <InnerProductcard data={item} key={item.id} />;
|
||||
})}
|
||||
|
||||
{/* Buldozerlar */}
|
||||
{carType === "buldozers" &&
|
||||
buldozerlar.map((item) => {
|
||||
return <InnerProductcard data={item} key={item.id} />;
|
||||
})}
|
||||
|
||||
{/* Katkalar */}
|
||||
{carType === "katkas" &&
|
||||
katkalar.map((item) => {
|
||||
return <InnerProductcard data={item} key={item.id} />;
|
||||
})}
|
||||
|
||||
{/* Evakuatorlar */}
|
||||
{carType === "evakuator" &&
|
||||
evakuatorDemo.map((item) => {
|
||||
return <InnerProductcard data={item} key={item.id} />;
|
||||
})}
|
||||
|
||||
{/* shalanda */}
|
||||
{carType === "shalanda_traller" &&
|
||||
shalandaTraller.map((item) => {
|
||||
return <InnerProductcard data={item} key={item.id} />;
|
||||
})}
|
||||
|
||||
{/* asfalt yotqizuvchi */}
|
||||
{carType === "asfalt_frez" &&
|
||||
asfalt.map((item) => {
|
||||
return <InnerProductcard data={item} key={item.id} />;
|
||||
})}
|
||||
|
||||
{/* asfalt ko'chiruvchi */}
|
||||
{carType === "beton_nasos" &&
|
||||
betonNasoslar.map((item) => {
|
||||
return <InnerProductcard data={item} key={item.id} />;
|
||||
})}
|
||||
|
||||
{/* manipulyator */}
|
||||
{carType === "manipulyator" &&
|
||||
manipulyator.map((item) => {
|
||||
return <InnerProductcard data={item} key={item.id} />;
|
||||
})}
|
||||
|
||||
{/* vodovoz */}
|
||||
{carType === "vodovoz" &&
|
||||
vodovoz.map((item) => {
|
||||
return <InnerProductcard data={item} key={item.id} />;
|
||||
})}
|
||||
|
||||
{/* assertizator */}
|
||||
{carType === "assenizator" &&
|
||||
assenizator.map((item) => {
|
||||
return <InnerProductcard data={item} key={item.id} />;
|
||||
})}
|
||||
<div className="mt-10 grid lg:grid-cols-3 sm:grid-cols-2 grid-cols-1 gap-5 max-w-[1200px] w-full mx-auto px-4">
|
||||
{loading ? (
|
||||
<LoadingSkeleton />
|
||||
) : cars.length > 0 ? (
|
||||
// MUHIM: Array ustidan map qilish kerak!
|
||||
cars.map((car, index) => (
|
||||
<InnerProductcard key={car.id || index} data={car} />
|
||||
))
|
||||
) : (
|
||||
<EmptyState />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import Products from "@/components/pageParts/products";
|
||||
import Products from "@/components/pageParts/products/products";
|
||||
import Texnika from "@/components/pageParts/texnika";
|
||||
import Offer from "@/components/pageParts/offer";
|
||||
import Faq from "@/components/pageParts/faq";
|
||||
@@ -27,4 +27,3 @@ export default function Home() {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
BIN
app/favicon.ico
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 15 KiB |
BIN
assets/cranes/kran_card_image.jpg
Normal file
|
After Width: | Height: | Size: 74 KiB |
BIN
assets/cranes/manipulyator_card_image.jpg
Normal file
|
After Width: | Height: | Size: 80 KiB |
BIN
assets/details/cranes/avtolift_card_image.jpg
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
assets/details/cranes/avtovishka_card_image.jpg
Normal file
|
After Width: | Height: | Size: 36 KiB |
BIN
assets/details/excavators/ekskavator_yuklagich_card_image.jpg
Normal file
|
After Width: | Height: | Size: 55 KiB |
BIN
assets/details/excavators/excavator_card_image.jpg
Normal file
|
After Width: | Height: | Size: 70 KiB |
BIN
assets/details/excavators/gusinichnik_card_image.jpg
Normal file
|
After Width: | Height: | Size: 139 KiB |
BIN
assets/details/loaders/mini_yuklagich_card_image.jpg
Normal file
|
After Width: | Height: | Size: 42 KiB |
BIN
assets/details/loaders/old_yuklagich_card_image.jpg
Normal file
|
After Width: | Height: | Size: 176 KiB |
BIN
assets/details/roaders/katok_card_image.jpg
Normal file
|
After Width: | Height: | Size: 217 KiB |
BIN
assets/evakuator/evakuator_card_image.jpg
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
assets/favicon_io/android-chrome-192x192.png
Normal file
|
After Width: | Height: | Size: 34 KiB |
BIN
assets/favicon_io/android-chrome-512x512.png
Normal file
|
After Width: | Height: | Size: 180 KiB |
BIN
assets/favicon_io/apple-touch-icon.png
Normal file
|
After Width: | Height: | Size: 30 KiB |
BIN
assets/favicon_io/favicon-16x16.png
Normal file
|
After Width: | Height: | Size: 661 B |
BIN
assets/favicon_io/favicon-32x32.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
1
assets/favicon_io/site.webmanifest
Normal file
@@ -0,0 +1 @@
|
||||
{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"}
|
||||
@@ -64,6 +64,8 @@ export {default as Gazel5} from './details/trucks/4-5.png';
|
||||
export {default as Gazel6} from './details/trucks/4-6.png';
|
||||
|
||||
// products kran
|
||||
export {default as Manipulyator_card} from './cranes/manipulyator_card_image.jpg';
|
||||
export {default as Kran_card} from './cranes/kran_card_image.jpg'
|
||||
export {default as Kran1} from './cranes/avtocrane.png';
|
||||
export {default as Kran2} from './cranes/avtokran.png';
|
||||
export {default as Kran3} from './cranes/dizel.png';
|
||||
@@ -83,6 +85,8 @@ export {default as Avtovishka36} from './details/cranes/avtovishka36.jpg';
|
||||
export {default as Avtovishka45} from './details/cranes/avtovishka45.jpg';
|
||||
export {default as Avtovishka60} from './details/cranes/avtovishka60.jpg';
|
||||
export {default as Avtovishka75} from './details/cranes/avtovishka75.jpg';
|
||||
export {default as Avtovishka_card} from './details/cranes/avtovishka_card_image.jpg';
|
||||
export {default as Avtolift_card} from './details/cranes/avtolift_card_image.jpg';
|
||||
|
||||
// products avtokranlar images
|
||||
export {default as Kran30} from './cranes/kran30.jpg';
|
||||
@@ -111,6 +115,7 @@ export {default as Dizel3} from './details/cranes/5-4.png';
|
||||
export {default as Old} from './loaders/loader.png';
|
||||
export {default as Teleskop} from './loaders/loader2.png';
|
||||
export {default as Forkliftlar} from './loaders/loader3.png';
|
||||
export { default as Old_card} from './details/loaders/old_yuklagich_card_image.jpg';
|
||||
|
||||
// products forkflit loaders images
|
||||
export {default as Old1} from './details/loaders/1-1.png';
|
||||
@@ -139,10 +144,13 @@ export {default as Fork8} from './details/loaders/3-8.jpg';
|
||||
export {default as Fork9} from './details/loaders/3-9.png';
|
||||
|
||||
// product ekskavators images
|
||||
export {default as Paletli} from './excavators/excavator.png';
|
||||
export {default as Paletli} from './details/excavators/gusinichnik_card_image.jpg';
|
||||
export {default as Balon} from './excavators/excavator2.png';
|
||||
export {default as Mini} from './excavators/mini.png';
|
||||
export {default as Digger} from './excavators/digger.png';
|
||||
export {default as Balon_card} from './details/excavators/excavator_card_image.jpg'
|
||||
export {default as Eks_yuk_card} from './details/excavators/ekskavator_yuklagich_card_image.jpg';
|
||||
export {default as Mini_yuk_card} from './details/loaders/mini_yuklagich_card_image.jpg';
|
||||
|
||||
// products Paletli of ekskavator images
|
||||
export {default as Paletli1} from './details/excavators/1-1.png';
|
||||
@@ -160,6 +168,8 @@ export {default as Grayder} from './roders/avtogreyder.png';
|
||||
export {default as Buldozer} from './roders/buldozer.png';
|
||||
export {default as Kat} from './roders/kat.png';
|
||||
export {default as Evakuator} from './evakuator/evakuator_fura.jpg';
|
||||
export {default as Evakuator_card} from'./evakuator/evakuator_card_image.jpg'
|
||||
export {default as Katok_card} from './details/roaders/katok_card_image.jpg'
|
||||
|
||||
// avtograyder , buldozer , katka , kampressor
|
||||
export {default as Grayder1} from './details/loaders/avtogreyder.jpg';
|
||||
|
||||
@@ -5,16 +5,18 @@ import Image from "next/image";
|
||||
import { useParams } from "next/navigation";
|
||||
import Text from "../lib_components/text";
|
||||
import Link from "next/link";
|
||||
import { useCarType } from "@/store/carType";
|
||||
|
||||
export default function CarType_Header() {
|
||||
const params = useParams();
|
||||
const initialCar = useCarType((state) => state.initialCar);
|
||||
console.log(params);
|
||||
return (
|
||||
<div
|
||||
dir="ltr"
|
||||
className="w-full h-[300px] relative flex items-center justify-center max-sm:px-2"
|
||||
>
|
||||
{/* back image */}
|
||||
{/* back image for gitea */}
|
||||
<Image
|
||||
alt="CarTypeImage"
|
||||
src={backOne}
|
||||
@@ -47,12 +49,20 @@ export default function CarType_Header() {
|
||||
<Text txt="home" />
|
||||
</Link>
|
||||
/
|
||||
<Link href={`/${params.lang}/${params.carType}`} className={params.carDeatil ? "hover:text-secondary hover:cursor-pointer":"text-secondary"}>
|
||||
<Text txt={`${params.carType}`} />
|
||||
<Link
|
||||
href={`/${params.lang}/${params.carType}`}
|
||||
className={
|
||||
params.carDeatil
|
||||
? "hover:text-secondary hover:cursor-pointer"
|
||||
: "text-secondary"
|
||||
}
|
||||
>
|
||||
{initialCar.name}
|
||||
</Link>
|
||||
{params.carDeatil && '/'}
|
||||
{params.carDeatil && <div className="text-secondary">
|
||||
<Text txt={`${params.carType}`} /></div>}
|
||||
{params.carDeatil && "/"}
|
||||
{params.carDeatil && (
|
||||
<div className="text-secondary">{initialCar.name}</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
"use client";
|
||||
|
||||
import { innerCardTypes } from "@/types";
|
||||
import Link from "next/link";
|
||||
import { useParams } from "next/navigation";
|
||||
@@ -8,74 +7,132 @@ import Image from "next/image";
|
||||
import Text from "../lib_components/text";
|
||||
import { useCarDetail } from "../lib_components/carDetailProvider";
|
||||
import { motion } from "framer-motion";
|
||||
import { useCarType } from "@/store/carType";
|
||||
|
||||
export default function InnerProductcard({ data }: { data: innerCardTypes }) {
|
||||
export default function InnerProductcard({ data }: { data: any }) {
|
||||
const route = useParams();
|
||||
const { setDetail } = useCarDetail();
|
||||
const setInitialCar = useCarType((state) => state.setInitialCar);
|
||||
|
||||
const carInfo = {
|
||||
id: data?.id,
|
||||
name: data?.name,
|
||||
};
|
||||
|
||||
return (
|
||||
<Link
|
||||
href={`/${route.lang}/${route.carType}/${data.name}`}
|
||||
onClick={() => {
|
||||
setDetail(data);
|
||||
setInitialCar(carInfo);
|
||||
}}
|
||||
className="block h-full"
|
||||
>
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 40 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true, amount: 0.2 }}
|
||||
transition={{ duration: 0.5, ease: "easeOut" }}
|
||||
whileHover={{
|
||||
scale: 1.05,
|
||||
boxShadow: "0px 0px 15px rgba(0,0,0,0.1)",
|
||||
}}
|
||||
whileTap={{ scale: 0.97 }}
|
||||
className="h-[420px] rounded-lg overflow-hidden bg-white transition-all"
|
||||
className="h-full group"
|
||||
>
|
||||
<Link
|
||||
href={`/${route.lang}/${route.carType}/${data.name}`}
|
||||
onClick={() => setDetail(data)}
|
||||
className="h-full flex flex-col items-center justify-between rounded-lg hover:cursor-pointer"
|
||||
<div
|
||||
className="h-full bg-white rounded-2xl overflow-hidden border-2 border-gray-100
|
||||
hover:border-[#f2a01c] transition-all duration-300
|
||||
shadow-sm hover:shadow-xl flex flex-col"
|
||||
>
|
||||
{/* Rasm container - katta va responsive */}
|
||||
<div
|
||||
className="relative w-full aspect-[4/3] bg-gradient-to-br from-gray-50 via-white to-gray-50
|
||||
overflow-hidden group-hover:bg-gradient-to-br group-hover:from-orange-50
|
||||
group-hover:via-white group-hover:to-orange-50 transition-all duration-500"
|
||||
>
|
||||
{/* Rasm */}
|
||||
<div className="absolute inset-0 p-6 flex items-center justify-center">
|
||||
<motion.div
|
||||
whileHover={{ scale: 1.05 }}
|
||||
transition={{ duration: 0.4 }}
|
||||
className="relative w-full h-full"
|
||||
>
|
||||
{/* Rasm qismi */}
|
||||
<div className="rounded-t-lg bg-white">
|
||||
<Image
|
||||
src={data.image}
|
||||
alt={data.name}
|
||||
width={0}
|
||||
height={200}
|
||||
className="object-fill w-full max-h-[200px] h-full rounded-t-sm"
|
||||
fill
|
||||
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
|
||||
className="object-contain"
|
||||
priority
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Pastki qism */}
|
||||
<div className="bg-[#fafafa] w-full p-2 px-4 rounded-b-lg flex flex-col items-start justify-start gap-2">
|
||||
<div className="text-xl font-semibold">
|
||||
<Text txt={data.name} />
|
||||
</div>
|
||||
|
||||
<div className="flex gap-2">
|
||||
<Text txt="hour-price" />
|
||||
{data.price?.toLocaleString("uz-UZ")}
|
||||
<Text txt="wallet" />
|
||||
</div>
|
||||
|
||||
<div className="flex gap-2">
|
||||
<Text txt="min-time" />
|
||||
{data.min_order_time}
|
||||
<Text txt="time" />
|
||||
</div>
|
||||
|
||||
{/* Tugma animatsiyasi */}
|
||||
<motion.button
|
||||
whileHover={{
|
||||
scale: 1.05,
|
||||
backgroundColor: "#ffffff",
|
||||
color: "#dc2626", // hoverda text-secondary (agar sizda secondary = red)
|
||||
borderColor: "#dc2626",
|
||||
}}
|
||||
whileTap={{ scale: 0.95 }}
|
||||
transition={{ duration: 0.3 }}
|
||||
className="w-full p-3 bg-secondary rounded-lg text-white border-2 border-secondary"
|
||||
>
|
||||
<Text txt="more" />
|
||||
</motion.button>
|
||||
</div>
|
||||
</Link>
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
{/* Dekorativ element */}
|
||||
<div
|
||||
className="absolute top-4 right-4 w-12 h-12 bg-[#f2a01c]/10 rounded-full
|
||||
flex items-center justify-center opacity-0 group-hover:opacity-100
|
||||
transition-opacity duration-300"
|
||||
>
|
||||
<svg
|
||||
className="w-6 h-6 text-[#f2a01c]"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M9 5l7 7-7 7"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Content qismi */}
|
||||
<div className="flex-1 p-6 flex flex-col justify-between bg-white">
|
||||
{/* Nomi va tavsif */}
|
||||
<div className="mb-4">
|
||||
<h3
|
||||
className="text-xl font-bold text-[#0c1239] mb-2 line-clamp-2
|
||||
group-hover:text-[#f2a01c] transition-colors duration-300"
|
||||
>
|
||||
<Text txt={data.name} />
|
||||
</h3>
|
||||
|
||||
{/* Agar qo'shimcha ma'lumot bo'lsa */}
|
||||
{data.description && (
|
||||
<p className="text-sm text-gray-600 line-clamp-2">
|
||||
<Text txt={data.description} />
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Tugma - past qismda */}
|
||||
<div className="pt-4 border-t border-gray-100">
|
||||
<motion.div
|
||||
whileHover={{ x: 4 }}
|
||||
transition={{ duration: 0.2 }}
|
||||
className="flex items-center justify-between text-[#f2a01c] font-semibold"
|
||||
>
|
||||
<span>
|
||||
<Text txt="more" />
|
||||
</span>
|
||||
<svg
|
||||
className="w-5 h-5"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M9 5l7 7-7 7"
|
||||
/>
|
||||
</svg>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,15 +1,23 @@
|
||||
"use client";
|
||||
|
||||
import { ProductTypes } from "@/types";
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
import Text from "../lib_components/text";
|
||||
import { useParams } from "next/navigation";
|
||||
import { motion } from "framer-motion";
|
||||
import { useCarType } from "@/store/carType";
|
||||
|
||||
export default function ProductCard({ data }: { data: ProductTypes }) {
|
||||
export default function ProductCard({ data }: { data: any }) {
|
||||
const { lang } = useParams();
|
||||
|
||||
const setInitialCar = useCarType((state) => state.setInitialCar);
|
||||
const carData = {
|
||||
name: data?.name,
|
||||
id: data?.id,
|
||||
};
|
||||
|
||||
console.log("data: ", data);
|
||||
|
||||
return (
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 50 }}
|
||||
@@ -23,14 +31,15 @@ export default function ProductCard({ data }: { data: ProductTypes }) {
|
||||
className="rounded-xl border-2 border-primary h-[430px]"
|
||||
>
|
||||
<Link
|
||||
href={`/${lang}/${data.path}`}
|
||||
href={`/${lang}/${data.name}`}
|
||||
onClick={() => setInitialCar(carData)}
|
||||
className="h-full flex flex-col items-center justify-between rounded-lg bg-white transition-transform"
|
||||
>
|
||||
{/* Yuqori qism - rasm */}
|
||||
<div className="rounded-t-lg bg-white py-10 px-2 flex justify-center items-center">
|
||||
<Image
|
||||
src={data.image}
|
||||
alt={data.truck_name}
|
||||
alt={data.name}
|
||||
width={260}
|
||||
height={200}
|
||||
className="object-contain max-h-[200px] h-full rounded-xl"
|
||||
@@ -40,10 +49,10 @@ export default function ProductCard({ data }: { data: ProductTypes }) {
|
||||
{/* Pastki qism - matn */}
|
||||
<div className="bg-[#fafafa] w-full py-5 rounded-b-lg flex flex-col items-center justify-center space-y-1">
|
||||
<div className="font-medium text-primary text-xl text-center">
|
||||
<Text txt={data.truck_name} />
|
||||
<Text txt={data.name} />
|
||||
</div>
|
||||
<div className="text-secondary text-md font-extrabold text-center">
|
||||
<Text txt={data.desc} />
|
||||
<Text txt="agreement" />
|
||||
</div>
|
||||
<div className="text-center text-secondary bg-primary max-w-[200px] w-full rounded-xl text-lg py-2 hover:cursor-pointer">
|
||||
<Text txt="more" />
|
||||
|
||||
30
components/emptyState.tsx
Normal file
@@ -0,0 +1,30 @@
|
||||
import Text from "./lib_components/text";
|
||||
|
||||
// Empty State Component
|
||||
export const EmptyState = () => {
|
||||
return (
|
||||
<div className="col-span-full flex flex-col items-center justify-center py-20 px-4">
|
||||
<div className="w-24 h-24 mb-6 rounded-full bg-[#f2a01c]/10 flex items-center justify-center">
|
||||
<svg
|
||||
className="w-12 h-12 text-[#f2a01c]"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M20 13V6a2 2 0 00-2-2H6a2 2 0 00-2 2v7m16 0v5a2 2 0 01-2 2H6a2 2 0 01-2-2v-5m16 0h-2.586a1 1 0 00-.707.293l-2.414 2.414a1 1 0 01-.707.293h-3.172a1 1 0 01-.707-.293l-2.414-2.414A1 1 0 006.586 13H4"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<h3 className="text-2xl font-bold text-[#0c1239] mb-2">
|
||||
<Text txt="noData" />
|
||||
</h3>
|
||||
<p className="text-gray-600 text-center max-w-md">
|
||||
<Text txt="noDataDesc" />
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -6,7 +6,7 @@ import { useTranslation } from 'react-i18next'
|
||||
export default function Time() {
|
||||
const {t} = useTranslation();
|
||||
return (
|
||||
<div dir='ltr' className='icon_animation2 fixed bottom-10 right-20 z-10 rounded-[50%] bg-primary p-5 text-lg text-secondary flex flex-col items-center justify-center'>
|
||||
<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>
|
||||
<p>24/7</p>
|
||||
</div>
|
||||
|
||||
@@ -37,7 +37,7 @@ export default function UpScrollIcon() {
|
||||
{showButton && (
|
||||
<span
|
||||
onClick={scrollToTop}
|
||||
className="fixed bottom-6 right-6 bg-secondary hover:bg-primary text-white p-3 rounded-full cursor-pointer shadow-lg transition"
|
||||
className="fixed z-40 bottom-6 right-6 bg-secondary hover:bg-primary text-white p-3 rounded-full cursor-pointer shadow-lg transition"
|
||||
>
|
||||
<FaArrowUp size={20} />
|
||||
</span>
|
||||
|
||||
19
components/loadingProduct.tsx
Normal file
@@ -0,0 +1,19 @@
|
||||
// Loading Skeleton Component
|
||||
export const LoadingSkeleton = () => {
|
||||
return (
|
||||
<>
|
||||
{[1, 2, 3, 4].map((item) => (
|
||||
<div
|
||||
key={item}
|
||||
className="bg-white rounded-lg shadow-md overflow-hidden animate-pulse"
|
||||
>
|
||||
<div className="w-full h-48 bg-gray-200"></div>
|
||||
<div className="p-4">
|
||||
<div className="h-4 bg-gray-200 rounded w-3/4 mb-2"></div>
|
||||
<div className="h-4 bg-gray-200 rounded w-1/2"></div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -12,6 +12,8 @@ import {
|
||||
import { Ekxkavator_vektor, logoImg } from "@/assets";
|
||||
import { FaLocationDot } from "react-icons/fa6";
|
||||
|
||||
// for gitea
|
||||
|
||||
export default function Footer() {
|
||||
return (
|
||||
<div dir="ltr" className="bg-primary relative">
|
||||
|
||||
@@ -48,7 +48,7 @@ export default function HeroSection() {
|
||||
className={`${navigationPrevEl.replace(
|
||||
".",
|
||||
""
|
||||
)} w-10 h-10 absolute z-10 left-[10%] top-50 p-0 bg-primary text-[30px] text-center text-white flex items-center justify-center hover:bg-secondary hover:cursor-pointer transition`}
|
||||
)} w-10 h-10 absolute z-10 left-[10%] top-50 p-0 bg-primary text-[30px] text-center text-white lg:flex hidden items-center justify-center hover:bg-secondary hover:cursor-pointer transition`}
|
||||
>
|
||||
<ArrowLeft />
|
||||
</button>
|
||||
@@ -56,7 +56,7 @@ export default function HeroSection() {
|
||||
className={`${navigationNextEl.replace(
|
||||
".",
|
||||
""
|
||||
)} w-10 h-10 absolute z-10 right-[10%] top-50 bg-primary text-[30px] text-center text-white flex items-center justify-center hover:bg-secondary hover:cursor-pointer transition `}
|
||||
)} w-10 h-10 absolute z-10 right-[10%] top-50 bg-primary text-[30px] text-center text-white lg:flex hidden items-center justify-center hover:bg-secondary hover:cursor-pointer transition `}
|
||||
>
|
||||
<ArrowRight />
|
||||
</button>
|
||||
|
||||
@@ -14,7 +14,7 @@ export default function Map() {
|
||||
</div>
|
||||
|
||||
{/* contact information */}
|
||||
<div className="absolute flex flex-col gap-3 sm:top-20 top-5 sm:right-20 z-50 bg-white rounded-[15px] p-5 px-10 max-w-[400px] w-full text-left ">
|
||||
<div className="absolute flex flex-col gap-3 sm:top-20 top-5 sm:right-20 z-30 bg-white rounded-[15px] p-5 px-10 max-w-[400px] w-full text-left ">
|
||||
<div className="text-left flex w-full justify-start">
|
||||
<Title text="contacts" />
|
||||
</div>
|
||||
|
||||
@@ -1,95 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import React, { useEffect, useState } from "react";
|
||||
import Title from "../lib_components/title";
|
||||
import Text from "../lib_components/text";
|
||||
import { Asphalt, Ekskavator, Forklift, Kran, Truck } from "@/assets";
|
||||
import Image from "next/image";
|
||||
import type { productFilterTypes, ProductTypes } from "@/types";
|
||||
import {
|
||||
allProducts,
|
||||
cranes,
|
||||
excavators,
|
||||
forklift,
|
||||
road_repairs,
|
||||
trucks,
|
||||
} from "@/data";
|
||||
import ProductCard from "../cards/productCard";
|
||||
|
||||
const productFilterTypesMainPage: productFilterTypes[] = [
|
||||
{ name: "trucks", image: Truck },
|
||||
{ name: "cranes", image: Kran },
|
||||
{ name: "forklift-trucks", image: Ekskavator },
|
||||
{ name: "excavators", image: Forklift },
|
||||
{ name: "road-repairs", image: Asphalt },
|
||||
{ name: "all", image: "" },
|
||||
];
|
||||
|
||||
export default function Products() {
|
||||
//const [productFilter, setProductFilter] = useState<string | null>(null);
|
||||
|
||||
const [cars, setCars] = useState(allProducts);
|
||||
|
||||
// execute filetr function
|
||||
// useEffect(() => {
|
||||
// if (productFilter === "trucks") {
|
||||
// setCars(trucks);
|
||||
// } else if (productFilter === "cranes") {
|
||||
// setCars(cranes);
|
||||
// } else if (productFilter === "forklift-trucks") {
|
||||
// setCars(forklift);
|
||||
// } else if (productFilter === "excavators") {
|
||||
// setCars(excavators);
|
||||
// } else if (productFilter === "road-repairs") {
|
||||
// setCars(road_repairs);
|
||||
// } else {
|
||||
// setCars(allProducts);
|
||||
// }
|
||||
// }, [productFilter]);
|
||||
return (
|
||||
<div dir="ltr" className="max-w-[1200px] w-full mx-auto">
|
||||
{/* title part */}
|
||||
<div className="flex flex-col mb-10">
|
||||
<div className="flex items-center justify-center w-full ">
|
||||
<div className="text-secondary px-2 text-[18px] font-semibold ">
|
||||
<Text txt="katalog" />
|
||||
</div>
|
||||
</div>
|
||||
<Title text="pricing-h2" />
|
||||
</div>
|
||||
|
||||
{/* product filters */}
|
||||
{/* <div className="flex flex-wrap gap-1 gap-y-4 items-center justify-center mb-10 ">
|
||||
{productFilterTypesMainPage.map((item, index) => (
|
||||
<button
|
||||
key={index}
|
||||
onClick={() => setProductFilter(item.name)}
|
||||
className={`${
|
||||
productFilter === item.name ? "bg-secondary" : ""
|
||||
} flex items-center gap-2 h-[58px] hover:bg-secondary border-gray-300 hover:border-secondary border-[1px] px-7 text-2xl rounded-tr-full rounded-bl-full `}
|
||||
>
|
||||
<Text txt={item.name} />
|
||||
{item.image && (
|
||||
<Image
|
||||
src={item.image}
|
||||
alt="Truck images"
|
||||
width={50}
|
||||
height={50}
|
||||
className="object-cover"
|
||||
/>
|
||||
)}
|
||||
</button>
|
||||
))}
|
||||
</div> */}
|
||||
|
||||
{/* products */}
|
||||
<div className="px-4 grid gap-5 grid-cols-1 place-content-center min-[500px]:grid-cols-2 min-lg:grid-cols-4 min-[1210px]:grid-cols-4">
|
||||
{cars.map((item: ProductTypes, index: number) => (
|
||||
<div key={index}>
|
||||
<ProductCard data={item} />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
95
components/pageParts/products/products.tsx
Normal file
@@ -0,0 +1,95 @@
|
||||
"use client";
|
||||
|
||||
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";
|
||||
import { usePathname } from "next/navigation";
|
||||
import { baseUrl } from "@/data/url";
|
||||
|
||||
export default function Products() {
|
||||
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: ", data?.data);
|
||||
|
||||
if (data?.data && data.data.length > 0) {
|
||||
setCars(data.data);
|
||||
} else {
|
||||
setCars([]);
|
||||
}
|
||||
} 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
|
||||
|
||||
return (
|
||||
<div dir="ltr" className="max-w-[1200px] w-full mx-auto">
|
||||
{/* title part */}
|
||||
<div className="flex flex-col mb-10">
|
||||
<div className="flex items-center justify-center w-full">
|
||||
<div className="text-[#f2a01c] px-2 text-[18px] font-semibold">
|
||||
<Text txt="katalog" />
|
||||
</div>
|
||||
</div>
|
||||
<Title text="pricing-h2" />
|
||||
</div>
|
||||
|
||||
{/* Error message */}
|
||||
{error && (
|
||||
<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>
|
||||
)}
|
||||
|
||||
{/* products */}
|
||||
<div className="px-4 grid gap-5 grid-cols-1 place-content-center min-[500px]:grid-cols-2 min-lg:grid-cols-4 min-[1210px]:grid-cols-4">
|
||||
{loading ? (
|
||||
<LoadingSkeleton />
|
||||
) : cars.length > 0 ? (
|
||||
cars.map((item: ProductTypes, index: number) => (
|
||||
<div key={item.id || index}>
|
||||
<ProductCard data={item} />
|
||||
</div>
|
||||
))
|
||||
) : (
|
||||
<EmptyState />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
500
data/index.ts
@@ -7,67 +7,61 @@ import {
|
||||
AvtokranSlider,
|
||||
Avtolift28,
|
||||
Avtolift53,
|
||||
Avtolift_card,
|
||||
Avtovishka28,
|
||||
Avtovishka36,
|
||||
Avtovishka45,
|
||||
Avtovishka60,
|
||||
Avtovishka75,
|
||||
Balon,
|
||||
Avtovishka_card,
|
||||
Balon1,
|
||||
Balon2,
|
||||
Balon_card,
|
||||
Beton_nasos,
|
||||
Buldozer,
|
||||
Buldozer1,
|
||||
Buldozer2,
|
||||
Chakman2,
|
||||
Digger,
|
||||
Digger1,
|
||||
Digger2,
|
||||
Eks_yuk_card,
|
||||
ekskavatorSlider,
|
||||
Evakuator,
|
||||
Evakuator20,
|
||||
Evakuator5,
|
||||
Evakuator_card,
|
||||
EvakuatorGruzavoy,
|
||||
Fork1,
|
||||
Fork2,
|
||||
Fork3,
|
||||
Forkliftlar,
|
||||
Gazel2,
|
||||
Gazel5,
|
||||
Grayder,
|
||||
Grayder1,
|
||||
Howo1,
|
||||
Howo2_1,
|
||||
Howo3_1,
|
||||
Isuzu2,
|
||||
Kaimei1,
|
||||
Kat,
|
||||
Katok10,
|
||||
Katok20,
|
||||
Katok3,
|
||||
Katok4,
|
||||
Katok6,
|
||||
Katok_card,
|
||||
kompressorSlider,
|
||||
Kran1,
|
||||
Kran130,
|
||||
Kran2,
|
||||
Kran30,
|
||||
Kran4,
|
||||
Kran50,
|
||||
Kran75,
|
||||
Kranmexanik1,
|
||||
Kranminora1,
|
||||
Kran_card,
|
||||
Manipulyator,
|
||||
Manipulyator_card,
|
||||
Mikser,
|
||||
Mini,
|
||||
Mini1,
|
||||
Mini2,
|
||||
Minora1,
|
||||
Minora4,
|
||||
Old,
|
||||
Old1,
|
||||
Old2,
|
||||
Old3,
|
||||
Mini_yuk_card,
|
||||
Old_card,
|
||||
Old_yuklagich_3,
|
||||
Old_yuklagich_biru8,
|
||||
Old_yuklagich_mini1,
|
||||
@@ -86,7 +80,6 @@ import {
|
||||
Tel4,
|
||||
Teleskop,
|
||||
Traller,
|
||||
Treyler,
|
||||
Treyler1,
|
||||
Treyler2,
|
||||
Treyler6,
|
||||
@@ -98,34 +91,146 @@ import { innerCardTypes, ProductTypes } from "@/types";
|
||||
export const trucks: ProductTypes[] = [
|
||||
{
|
||||
id: 1,
|
||||
truck_name: "cement-truck",
|
||||
truck_name: "avtocranes",
|
||||
desc: "agreement",
|
||||
path: "cement-truck",
|
||||
image: Mikser,
|
||||
path: "avtocranes",
|
||||
image: Kran_card,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
truck_name: "manipulyator",
|
||||
desc: "agreement",
|
||||
path: "manipulyator",
|
||||
image: Manipulyator_card,
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
truck_name: "Avtovishka",
|
||||
desc: "agreement",
|
||||
path: "Avtovishka",
|
||||
image: Avtovishka_card,
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
truck_name: "Avtolift",
|
||||
desc: "agreement",
|
||||
path: "Avtolift",
|
||||
image: Avtolift_card,
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
truck_name: "crawler-excavators",
|
||||
desc: "agreement",
|
||||
path: "crawler-excavators",
|
||||
image: Paletli,
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
truck_name: "wheel-excavators",
|
||||
desc: "agreement",
|
||||
path: "wheel-excavators",
|
||||
image: Balon_card,
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
truck_name: "mini-excavators",
|
||||
desc: "agreement",
|
||||
path: "mini-excavators",
|
||||
image: Mini,
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
truck_name: "excavator-loaders",
|
||||
desc: "agreement",
|
||||
path: "excavator-loaders",
|
||||
image: Eks_yuk_card,
|
||||
},
|
||||
{
|
||||
id: 24,
|
||||
truck_name: "mini-loaders",
|
||||
desc: "agreement",
|
||||
path: "mini-loaders",
|
||||
image: Mini_yuk_card,
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
truck_name: "katkas",
|
||||
desc: "agreement",
|
||||
path: "katkas",
|
||||
image: Katok_card,
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
truck_name: "buldozers",
|
||||
desc: "agreement",
|
||||
path: "buldozers",
|
||||
image: Buldozer,
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
truck_name: "avtograders",
|
||||
desc: "agreement",
|
||||
path: "avtograders",
|
||||
image: Grayder1,
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
truck_name: "asfalt_yotqizuvchi",
|
||||
desc: "agreement",
|
||||
path: "asfalt_frez",
|
||||
image: Aspal_800,
|
||||
},
|
||||
{
|
||||
id: 13,
|
||||
truck_name: "dumb-truck",
|
||||
desc: "agreement",
|
||||
path: "dumb-truck",
|
||||
image: Samasval,
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
truck_name: "trailers",
|
||||
id: 14,
|
||||
truck_name: "cement-truck",
|
||||
desc: "agreement",
|
||||
path: "trailers",
|
||||
image: Treyler,
|
||||
path: "cement-truck",
|
||||
image: Mikser,
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
id: 15,
|
||||
truck_name: "vodovoz",
|
||||
desc: "agreement",
|
||||
path: "vodovoz",
|
||||
image: Vodovoz,
|
||||
},
|
||||
{
|
||||
id: 16,
|
||||
truck_name: "evakuator",
|
||||
desc: "agreement",
|
||||
path: "evakuator",
|
||||
image: Evakuator_card,
|
||||
},
|
||||
{
|
||||
id: 17,
|
||||
truck_name: "avtocranes",
|
||||
desc: "agreement",
|
||||
path: "avtocranes",
|
||||
image: Kran2,
|
||||
},
|
||||
// {
|
||||
// id: 3,
|
||||
// truck_name: "trailers",
|
||||
// desc: "agreement",
|
||||
// path: "trailers",
|
||||
// image: Treyler,
|
||||
// },
|
||||
{
|
||||
id: 18,
|
||||
truck_name: "shalanda_traller",
|
||||
desc: "agreement",
|
||||
path: "shalanda_traller",
|
||||
image: Traller,
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
id: 19,
|
||||
truck_name: "beton_nasos",
|
||||
desc: "agreement",
|
||||
path: "beton_nasos",
|
||||
@@ -135,135 +240,41 @@ export const trucks: ProductTypes[] = [
|
||||
|
||||
export const cranes: ProductTypes[] = [
|
||||
{
|
||||
id: 1,
|
||||
truck_name: "avtotowers",
|
||||
desc: "agreement",
|
||||
path: "avtotowers",
|
||||
image: Kran1,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
truck_name: "avtocranes",
|
||||
desc: "agreement",
|
||||
path: "avtocranes",
|
||||
image: Kran2,
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
id: 20,
|
||||
truck_name: "tower-cranes",
|
||||
desc: "agreement",
|
||||
path: "tower-cranes",
|
||||
image: All_cranes,
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
truck_name: "manipulyator",
|
||||
desc: "agreement",
|
||||
path: "manipulyator",
|
||||
image: Manipulyator,
|
||||
},
|
||||
];
|
||||
|
||||
export const forklift: ProductTypes[] = [
|
||||
{
|
||||
id: 1,
|
||||
id: 21,
|
||||
truck_name: "front-loaders",
|
||||
desc: "agreement",
|
||||
path: "front-loaders",
|
||||
image: Old,
|
||||
image: Old_card,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
id: 22,
|
||||
truck_name: "tele-loaders",
|
||||
desc: "agreement",
|
||||
path: "tele-loaders",
|
||||
image: Teleskop,
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
truck_name: "forklift-trucks",
|
||||
desc: "agreement",
|
||||
path: "forklift-trucks",
|
||||
image: Forkliftlar,
|
||||
},
|
||||
];
|
||||
|
||||
export const excavators: ProductTypes[] = [
|
||||
{
|
||||
id: 1,
|
||||
truck_name: "crawler-excavators",
|
||||
desc: "agreement",
|
||||
path: "crawler-excavators",
|
||||
image: Paletli,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
truck_name: "wheel-excavators",
|
||||
desc: "agreement",
|
||||
path: "wheel-excavators",
|
||||
image: Balon,
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
truck_name: "mini-excavators",
|
||||
desc: "agreement",
|
||||
path: "mini-excavators",
|
||||
image: Mini,
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
truck_name: "excavator-loaders",
|
||||
desc: "agreement",
|
||||
path: "excavator-loaders",
|
||||
image: Digger,
|
||||
},
|
||||
// {
|
||||
// id: 3,
|
||||
// truck_name: "forklift-trucks",
|
||||
// desc: "agreement",
|
||||
// path: "forklift-trucks",
|
||||
// image: Forkliftlar,
|
||||
// },
|
||||
];
|
||||
|
||||
export const road_repairs: ProductTypes[] = [
|
||||
{
|
||||
id: 1,
|
||||
truck_name: "avtograders",
|
||||
desc: "agreement",
|
||||
path: "avtograders",
|
||||
image: Grayder1,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
truck_name: "buldozers",
|
||||
desc: "agreement",
|
||||
path: "buldozers",
|
||||
image: Buldozer,
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
truck_name: "katkas",
|
||||
desc: "agreement",
|
||||
path: "katkas",
|
||||
image: Kat,
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
truck_name: "evakuator",
|
||||
desc: "agreement",
|
||||
path: "evakuator",
|
||||
image: Evakuator,
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
truck_name: "asfalt_yotqizuvchi",
|
||||
desc: "agreement",
|
||||
path: "asfalt_frez",
|
||||
image: Aspal_800,
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
truck_name: "vodovoz",
|
||||
desc: "agreement",
|
||||
path: "vodovoz",
|
||||
image: Vodovoz,
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
id: 23,
|
||||
truck_name: "assenizator",
|
||||
desc: "agreement",
|
||||
path: "assenizator",
|
||||
@@ -275,11 +286,74 @@ export const allProducts: ProductTypes[] = [
|
||||
...trucks,
|
||||
...cranes,
|
||||
...forklift,
|
||||
...excavators,
|
||||
...road_repairs,
|
||||
];
|
||||
|
||||
// inner car information by types of trucks
|
||||
// inner car information by types of trucks salomlar
|
||||
|
||||
// mini loaders
|
||||
export const mini_loaders: innerCardTypes[] = [
|
||||
{
|
||||
id: 1,
|
||||
image: Old_yuklagich_mini1,
|
||||
name: "Old Yuklagich",
|
||||
min_order_time: 3,
|
||||
price: 370000,
|
||||
path: "",
|
||||
maxLength_m: 7, // Maksimum uzunligi (metr)
|
||||
capacity_tons: 500, // Yuk ko'tarish qobiliyati (tonna)
|
||||
fuelType: "Dizel/Gaz", // Yoqilg'i turi
|
||||
maxSpeed_kmh: 130, // Maksimum tezligi (km/soat)
|
||||
intercooler: "Bor", // Interkuler (Bor/Yoq)
|
||||
enginePower_hp: "360-400", // Dvigatel quvvati (ot kuchi) — diapazon sifatida
|
||||
transmission: "Mexanik/Robot", // O'tkazmalar qutisi
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
image: Old_yuklagich_mini2,
|
||||
name: "Old Yuklagich",
|
||||
min_order_time: 3,
|
||||
price: 370000,
|
||||
path: "",
|
||||
maxLength_m: 7, // Maksimum uzunligi (metr)
|
||||
capacity_tons: 500, // Yuk ko'tarish qobiliyati (tonna)
|
||||
fuelType: "Dizel/Gaz", // Yoqilg'i turi
|
||||
maxSpeed_kmh: 130, // Maksimum tezligi (km/soat)
|
||||
intercooler: "Bor", // Interkuler (Bor/Yoq)
|
||||
enginePower_hp: "360-400", // Dvigatel quvvati (ot kuchi) — diapazon sifatida
|
||||
transmission: "Mexanik/Robot", // O'tkazmalar qutisi
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
image: Tel1,
|
||||
name: "Teleskopik Yuklagich JCB",
|
||||
min_order_time: 3,
|
||||
price: 400000,
|
||||
path: "",
|
||||
maxLength_m: 7, // Maksimum uzunligi (metr)
|
||||
capacity_tons: 1, // Yuk ko'tarish qobiliyati (tonna)
|
||||
fuelType: "Dizel", // Yoqilg'i turi
|
||||
maxSpeed_kmh: 50, // Maksimum tezligi (km/soat)
|
||||
intercooler: "Bor", // Interkuler (Bor/Yoq)
|
||||
enginePower_hp: "60-150", // Dvigatel quvvati (ot kuchi) — diapazon sifatida
|
||||
transmission: "Mexanik", // O'tkazmalar qutisi
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
image: Tel2,
|
||||
name: "Teleskopik Yuklagich Bobkat",
|
||||
min_order_time: 3,
|
||||
price: 420000,
|
||||
path: "",
|
||||
maxLength_m: 7, // Maksimum uzunligi (metr)
|
||||
capacity_tons: 0.5, // Yuk ko'tarish qobiliyati (tonna)
|
||||
fuelType: "Dizel", // Yoqilg'i turi
|
||||
maxSpeed_kmh: 50, // Maksimum tezligi (km/soat)
|
||||
intercooler: "Bor", // Interkuler (Bor/Yoq)
|
||||
enginePower_hp: "60-150", // Dvigatel quvvati (ot kuchi) — diapazon sifatida
|
||||
transmission: "Mexanik", // O'tkazmalar qutisi
|
||||
},
|
||||
];
|
||||
|
||||
//yuk mashinalari
|
||||
export const cement_trucks: innerCardTypes[] = [
|
||||
@@ -501,52 +575,7 @@ export const betonNasoslar: innerCardTypes[] = [
|
||||
];
|
||||
|
||||
//kranlar
|
||||
export const avtominora: innerCardTypes[] = [
|
||||
{
|
||||
id: 1,
|
||||
image: Avtolift28,
|
||||
name: "Avtolift",
|
||||
min_order_time: 5,
|
||||
price: 600000,
|
||||
path: "",
|
||||
weight_kg: 12000,
|
||||
maxHeight_m: 28,
|
||||
capacity_kg: 500,
|
||||
fuelType: "Dizel",
|
||||
maxSpeed_kmh: 70,
|
||||
enginePower_hp: "200-400",
|
||||
transmission: "Mexanik/Avtomatik",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
image: Avtolift53,
|
||||
name: "Avtolift",
|
||||
min_order_time: 5,
|
||||
price: 600000,
|
||||
path: "",
|
||||
weight_kg: 12000,
|
||||
maxHeight_m: 53,
|
||||
capacity_kg: 500,
|
||||
fuelType: "Dizel",
|
||||
maxSpeed_kmh: 70,
|
||||
enginePower_hp: "200-400",
|
||||
transmission: "Mexanik/Avtomatik",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
image: Avtolift53,
|
||||
name: "Avtolift",
|
||||
min_order_time: 5,
|
||||
price: 600000,
|
||||
path: "",
|
||||
weight_kg: 12000,
|
||||
maxHeight_m: 63,
|
||||
capacity_kg: 500,
|
||||
fuelType: "Dizel",
|
||||
maxSpeed_kmh: 70,
|
||||
enginePower_hp: "200-400",
|
||||
transmission: "Mexanik/Avtomatik",
|
||||
},
|
||||
export const avtovishka: innerCardTypes[] = [
|
||||
{
|
||||
id: 4,
|
||||
image: Avtovishka28,
|
||||
@@ -624,6 +653,54 @@ export const avtominora: innerCardTypes[] = [
|
||||
},
|
||||
];
|
||||
|
||||
export const avtolift: innerCardTypes[] = [
|
||||
{
|
||||
id: 1,
|
||||
image: Avtolift28,
|
||||
name: "Avtolift",
|
||||
min_order_time: 5,
|
||||
price: 600000,
|
||||
path: "",
|
||||
weight_kg: 12000,
|
||||
maxHeight_m: 28,
|
||||
capacity_kg: 500,
|
||||
fuelType: "Dizel",
|
||||
maxSpeed_kmh: 70,
|
||||
enginePower_hp: "200-400",
|
||||
transmission: "Mexanik/Avtomatik",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
image: Avtolift53,
|
||||
name: "Avtolift",
|
||||
min_order_time: 5,
|
||||
price: 600000,
|
||||
path: "",
|
||||
weight_kg: 12000,
|
||||
maxHeight_m: 53,
|
||||
capacity_kg: 500,
|
||||
fuelType: "Dizel",
|
||||
maxSpeed_kmh: 70,
|
||||
enginePower_hp: "200-400",
|
||||
transmission: "Mexanik/Avtomatik",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
image: Avtolift53,
|
||||
name: "Avtolift",
|
||||
min_order_time: 5,
|
||||
price: 600000,
|
||||
path: "",
|
||||
weight_kg: 12000,
|
||||
maxHeight_m: 63,
|
||||
capacity_kg: 500,
|
||||
fuelType: "Dizel",
|
||||
maxSpeed_kmh: 70,
|
||||
enginePower_hp: "200-400",
|
||||
transmission: "Mexanik/Avtomatik",
|
||||
},
|
||||
];
|
||||
|
||||
export const avtokran: innerCardTypes[] = [
|
||||
{
|
||||
id: 1,
|
||||
@@ -733,69 +810,9 @@ export const old_yuklagichlar: innerCardTypes[] = [
|
||||
enginePower_hp: "360-400", // Dvigatel quvvati (ot kuchi) — diapazon sifatida
|
||||
transmission: "Mexanik/Robot", // O'tkazmalar qutisi
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
image: Old_yuklagich_mini1,
|
||||
name: "Old Yuklagich",
|
||||
min_order_time: 3,
|
||||
price: 370000,
|
||||
path: "",
|
||||
maxLength_m: 7, // Maksimum uzunligi (metr)
|
||||
capacity_tons: 500, // Yuk ko'tarish qobiliyati (tonna)
|
||||
fuelType: "Dizel/Gaz", // Yoqilg'i turi
|
||||
maxSpeed_kmh: 130, // Maksimum tezligi (km/soat)
|
||||
intercooler: "Bor", // Interkuler (Bor/Yoq)
|
||||
enginePower_hp: "360-400", // Dvigatel quvvati (ot kuchi) — diapazon sifatida
|
||||
transmission: "Mexanik/Robot", // O'tkazmalar qutisi
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
image: Old_yuklagich_mini2,
|
||||
name: "Old Yuklagich",
|
||||
min_order_time: 3,
|
||||
price: 370000,
|
||||
path: "",
|
||||
maxLength_m: 7, // Maksimum uzunligi (metr)
|
||||
capacity_tons: 500, // Yuk ko'tarish qobiliyati (tonna)
|
||||
fuelType: "Dizel/Gaz", // Yoqilg'i turi
|
||||
maxSpeed_kmh: 130, // Maksimum tezligi (km/soat)
|
||||
intercooler: "Bor", // Interkuler (Bor/Yoq)
|
||||
enginePower_hp: "360-400", // Dvigatel quvvati (ot kuchi) — diapazon sifatida
|
||||
transmission: "Mexanik/Robot", // O'tkazmalar qutisi
|
||||
},
|
||||
];
|
||||
|
||||
export const teleskop_yuklagichlar: innerCardTypes[] = [
|
||||
{
|
||||
id: 1,
|
||||
image: Tel1,
|
||||
name: "Teleskopik Yuklagich JCB",
|
||||
min_order_time: 3,
|
||||
price: 400000,
|
||||
path: "",
|
||||
maxLength_m: 7, // Maksimum uzunligi (metr)
|
||||
capacity_tons: 1, // Yuk ko'tarish qobiliyati (tonna)
|
||||
fuelType: "Dizel", // Yoqilg'i turi
|
||||
maxSpeed_kmh: 50, // Maksimum tezligi (km/soat)
|
||||
intercooler: "Bor", // Interkuler (Bor/Yoq)
|
||||
enginePower_hp: "60-150", // Dvigatel quvvati (ot kuchi) — diapazon sifatida
|
||||
transmission: "Mexanik", // O'tkazmalar qutisi
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
image: Tel2,
|
||||
name: "Teleskopik Yuklagich Bobkat",
|
||||
min_order_time: 3,
|
||||
price: 420000,
|
||||
path: "",
|
||||
maxLength_m: 7, // Maksimum uzunligi (metr)
|
||||
capacity_tons: 0.5, // Yuk ko'tarish qobiliyati (tonna)
|
||||
fuelType: "Dizel", // Yoqilg'i turi
|
||||
maxSpeed_kmh: 50, // Maksimum tezligi (km/soat)
|
||||
intercooler: "Bor", // Interkuler (Bor/Yoq)
|
||||
enginePower_hp: "60-150", // Dvigatel quvvati (ot kuchi) — diapazon sifatida
|
||||
transmission: "Mexanik", // O'tkazmalar qutisi
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
image: Tel3,
|
||||
@@ -1381,10 +1398,9 @@ export const manipulyator: innerCardTypes[] = [
|
||||
maxSpeed_kmh: 75,
|
||||
enginePower_hp: "180-240",
|
||||
transmission: "Mexanik/Avtomatik",
|
||||
}
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
// slider data
|
||||
export const sliderData: ProductTypes[] = [
|
||||
{
|
||||
|
||||
1
data/url.ts
Normal file
@@ -0,0 +1 @@
|
||||
export const baseUrl = "https://api.spes-texnika.uz/api/v1/category/";
|
||||
@@ -1,6 +1,22 @@
|
||||
// next.config.ts
|
||||
const nextConfig = {
|
||||
reactStrictMode: true,
|
||||
import type { NextConfig } from "next";
|
||||
|
||||
const nextConfig: NextConfig = {
|
||||
images: {
|
||||
remotePatterns: [
|
||||
{
|
||||
protocol: 'http',
|
||||
hostname: 'api.spes-texnika.uz',
|
||||
port: '',
|
||||
pathname: '/resources/media/**',
|
||||
},
|
||||
{
|
||||
protocol: 'https',
|
||||
hostname: 'api.spes-texnika.uz',
|
||||
port: '',
|
||||
pathname: '/resources/media/**',
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
export default nextConfig;
|
||||
112
package-lock.json
generated
@@ -17,7 +17,7 @@
|
||||
"i18next-resources-to-backend": "^1.2.1",
|
||||
"leaflet": "^1.9.4",
|
||||
"lucide-react": "^0.553.0",
|
||||
"next": "15.5.4",
|
||||
"next": "15.5.9",
|
||||
"next-i18next": "^15.4.2",
|
||||
"react": "19.1.0",
|
||||
"react-dom": "19.1.0",
|
||||
@@ -25,7 +25,8 @@
|
||||
"react-icons": "^5.5.0",
|
||||
"react-leaflet": "^5.0.0",
|
||||
"react-scroll": "^1.9.3",
|
||||
"swiper": "^12.0.3"
|
||||
"swiper": "^12.0.3",
|
||||
"zustand": "^5.0.11"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tailwindcss/postcss": "^4.1.14",
|
||||
@@ -674,15 +675,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/env": {
|
||||
"version": "15.5.4",
|
||||
"resolved": "https://registry.npmjs.org/@next/env/-/env-15.5.4.tgz",
|
||||
"integrity": "sha512-27SQhYp5QryzIT5uO8hq99C69eLQ7qkzkDPsk3N+GuS2XgOgoYEeOav7Pf8Tn4drECOVDsDg8oj+/DVy8qQL2A==",
|
||||
"version": "15.5.9",
|
||||
"resolved": "https://registry.npmjs.org/@next/env/-/env-15.5.9.tgz",
|
||||
"integrity": "sha512-4GlTZ+EJM7WaW2HEZcyU317tIQDjkQIyENDLxYJfSWlfqguN+dHkZgyQTV/7ykvobU7yEH5gKvreNrH4B6QgIg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@next/swc-darwin-arm64": {
|
||||
"version": "15.5.4",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.5.4.tgz",
|
||||
"integrity": "sha512-nopqz+Ov6uvorej8ndRX6HlxCYWCO3AHLfKK2TYvxoSB2scETOcfm/HSS3piPqc3A+MUgyHoqE6je4wnkjfrOA==",
|
||||
"version": "15.5.7",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.5.7.tgz",
|
||||
"integrity": "sha512-IZwtxCEpI91HVU/rAUOOobWSZv4P2DeTtNaCdHqLcTJU4wdNXgAySvKa/qJCgR5m6KI8UsKDXtO2B31jcaw1Yw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -696,9 +697,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-darwin-x64": {
|
||||
"version": "15.5.4",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.5.4.tgz",
|
||||
"integrity": "sha512-QOTCFq8b09ghfjRJKfb68kU9k2K+2wsC4A67psOiMn849K9ZXgCSRQr0oVHfmKnoqCbEmQWG1f2h1T2vtJJ9mA==",
|
||||
"version": "15.5.7",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.5.7.tgz",
|
||||
"integrity": "sha512-UP6CaDBcqaCBuiq/gfCEJw7sPEoX1aIjZHnBWN9v9qYHQdMKvCKcAVs4OX1vIjeE+tC5EIuwDTVIoXpUes29lg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -712,9 +713,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-linux-arm64-gnu": {
|
||||
"version": "15.5.4",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.5.4.tgz",
|
||||
"integrity": "sha512-eRD5zkts6jS3VfE/J0Kt1VxdFqTnMc3QgO5lFE5GKN3KDI/uUpSyK3CjQHmfEkYR4wCOl0R0XrsjpxfWEA++XA==",
|
||||
"version": "15.5.7",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.5.7.tgz",
|
||||
"integrity": "sha512-NCslw3GrNIw7OgmRBxHtdWFQYhexoUCq+0oS2ccjyYLtcn1SzGzeM54jpTFonIMUjNbHmpKpziXnpxhSWLcmBA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -728,9 +729,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-linux-arm64-musl": {
|
||||
"version": "15.5.4",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.5.4.tgz",
|
||||
"integrity": "sha512-TOK7iTxmXFc45UrtKqWdZ1shfxuL4tnVAOuuJK4S88rX3oyVV4ZkLjtMT85wQkfBrOOvU55aLty+MV8xmcJR8A==",
|
||||
"version": "15.5.7",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.5.7.tgz",
|
||||
"integrity": "sha512-nfymt+SE5cvtTrG9u1wdoxBr9bVB7mtKTcj0ltRn6gkP/2Nu1zM5ei8rwP9qKQP0Y//umK+TtkKgNtfboBxRrw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -744,9 +745,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-linux-x64-gnu": {
|
||||
"version": "15.5.4",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.5.4.tgz",
|
||||
"integrity": "sha512-7HKolaj+481FSW/5lL0BcTkA4Ueam9SPYWyN/ib/WGAFZf0DGAN8frNpNZYFHtM4ZstrHZS3LY3vrwlIQfsiMA==",
|
||||
"version": "15.5.7",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.5.7.tgz",
|
||||
"integrity": "sha512-hvXcZvCaaEbCZcVzcY7E1uXN9xWZfFvkNHwbe/n4OkRhFWrs1J1QV+4U1BN06tXLdaS4DazEGXwgqnu/VMcmqw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -760,9 +761,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-linux-x64-musl": {
|
||||
"version": "15.5.4",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.5.4.tgz",
|
||||
"integrity": "sha512-nlQQ6nfgN0nCO/KuyEUwwOdwQIGjOs4WNMjEUtpIQJPR2NUfmGpW2wkJln1d4nJ7oUzd1g4GivH5GoEPBgfsdw==",
|
||||
"version": "15.5.7",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.5.7.tgz",
|
||||
"integrity": "sha512-4IUO539b8FmF0odY6/SqANJdgwn1xs1GkPO5doZugwZ3ETF6JUdckk7RGmsfSf7ws8Qb2YB5It33mvNL/0acqA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -776,9 +777,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-win32-arm64-msvc": {
|
||||
"version": "15.5.4",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.5.4.tgz",
|
||||
"integrity": "sha512-PcR2bN7FlM32XM6eumklmyWLLbu2vs+D7nJX8OAIoWy69Kef8mfiN4e8TUv2KohprwifdpFKPzIP1njuCjD0YA==",
|
||||
"version": "15.5.7",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.5.7.tgz",
|
||||
"integrity": "sha512-CpJVTkYI3ZajQkC5vajM7/ApKJUOlm6uP4BknM3XKvJ7VXAvCqSjSLmM0LKdYzn6nBJVSjdclx8nYJSa3xlTgQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -792,9 +793,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-win32-x64-msvc": {
|
||||
"version": "15.5.4",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.5.4.tgz",
|
||||
"integrity": "sha512-1ur2tSHZj8Px/KMAthmuI9FMp/YFusMMGoRNJaRZMOlSkgvLjzosSdQI0cJAKogdHl3qXUQKL9MGaYvKwA7DXg==",
|
||||
"version": "15.5.7",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.5.7.tgz",
|
||||
"integrity": "sha512-gMzgBX164I6DN+9/PGA+9dQiwmTkE4TloBNx8Kv9UiGARsr9Nba7IpcBRA1iTV9vwlYnrE3Uy6I7Aj6qLjQuqw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -2370,12 +2371,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/next": {
|
||||
"version": "15.5.4",
|
||||
"resolved": "https://registry.npmjs.org/next/-/next-15.5.4.tgz",
|
||||
"integrity": "sha512-xH4Yjhb82sFYQfY3vbkJfgSDgXvBB6a8xPs9i35k6oZJRoQRihZH+4s9Yo2qsWpzBmZ3lPXaJ2KPXLfkvW4LnA==",
|
||||
"version": "15.5.9",
|
||||
"resolved": "https://registry.npmjs.org/next/-/next-15.5.9.tgz",
|
||||
"integrity": "sha512-agNLK89seZEtC5zUHwtut0+tNrc0Xw4FT/Dg+B/VLEo9pAcS9rtTKpek3V6kVcVwsB2YlqMaHdfZL4eLEVYuCg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@next/env": "15.5.4",
|
||||
"@next/env": "15.5.9",
|
||||
"@swc/helpers": "0.5.15",
|
||||
"caniuse-lite": "^1.0.30001579",
|
||||
"postcss": "8.4.31",
|
||||
@@ -2388,14 +2389,14 @@
|
||||
"node": "^18.18.0 || ^19.8.0 || >= 20.0.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@next/swc-darwin-arm64": "15.5.4",
|
||||
"@next/swc-darwin-x64": "15.5.4",
|
||||
"@next/swc-linux-arm64-gnu": "15.5.4",
|
||||
"@next/swc-linux-arm64-musl": "15.5.4",
|
||||
"@next/swc-linux-x64-gnu": "15.5.4",
|
||||
"@next/swc-linux-x64-musl": "15.5.4",
|
||||
"@next/swc-win32-arm64-msvc": "15.5.4",
|
||||
"@next/swc-win32-x64-msvc": "15.5.4",
|
||||
"@next/swc-darwin-arm64": "15.5.7",
|
||||
"@next/swc-darwin-x64": "15.5.7",
|
||||
"@next/swc-linux-arm64-gnu": "15.5.7",
|
||||
"@next/swc-linux-arm64-musl": "15.5.7",
|
||||
"@next/swc-linux-x64-gnu": "15.5.7",
|
||||
"@next/swc-linux-x64-musl": "15.5.7",
|
||||
"@next/swc-win32-arm64-msvc": "15.5.7",
|
||||
"@next/swc-win32-x64-msvc": "15.5.7",
|
||||
"sharp": "^0.34.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
@@ -3583,6 +3584,35 @@
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/zustand": {
|
||||
"version": "5.0.11",
|
||||
"resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.11.tgz",
|
||||
"integrity": "sha512-fdZY+dk7zn/vbWNCYmzZULHRrss0jx5pPFiOuMZ/5HJN6Yv3u+1Wswy/4MpZEkEGhtNH+pwxZB8OKgUBPzYAGg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12.20.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": ">=18.0.0",
|
||||
"immer": ">=9.0.6",
|
||||
"react": ">=18.0.0",
|
||||
"use-sync-external-store": ">=1.2.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"immer": {
|
||||
"optional": true
|
||||
},
|
||||
"react": {
|
||||
"optional": true
|
||||
},
|
||||
"use-sync-external-store": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
"i18next-resources-to-backend": "^1.2.1",
|
||||
"leaflet": "^1.9.4",
|
||||
"lucide-react": "^0.553.0",
|
||||
"next": "15.5.4",
|
||||
"next": "15.5.9",
|
||||
"next-i18next": "^15.4.2",
|
||||
"react": "19.1.0",
|
||||
"react-dom": "19.1.0",
|
||||
@@ -25,7 +25,8 @@
|
||||
"react-icons": "^5.5.0",
|
||||
"react-leaflet": "^5.0.0",
|
||||
"react-scroll": "^1.9.3",
|
||||
"swiper": "^12.0.3"
|
||||
"swiper": "^12.0.3",
|
||||
"zustand": "^5.0.11"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tailwindcss/postcss": "^4.1.14",
|
||||
|
||||
@@ -30,13 +30,13 @@
|
||||
"tower-crane": "Башенный кран",
|
||||
"lifters": "Дизельные подъемники",
|
||||
"lifter": "Дизельный подъемник",
|
||||
"front-loaders": "Фронтальные погрузчики",
|
||||
"front-loaders": "Фронталный погрузчик",
|
||||
"front-loader": "Фронтальный погрузчик",
|
||||
"tele-loaders": "Телескопические погрузчики",
|
||||
"tele-loader": "Телескопические погрузчики",
|
||||
"crawler-excavators": "Гусеничные экскаваторы",
|
||||
"crawler-excavator": "Гусеничный экскаватор",
|
||||
"wheel-excavators": "Колесные экскаваторы",
|
||||
"wheel-excavators": "Eкскаватор",
|
||||
"wheel-excavator": "Колесный экскаватор",
|
||||
"mini-excavators": "Мини-экскаваторы",
|
||||
"excavator-loaders": "Экскаватор-погрузчики",
|
||||
@@ -45,7 +45,8 @@
|
||||
"avtograder": "Автогрейдер",
|
||||
"buldozers": "Бульдозеры",
|
||||
"buldozer": "Бульдозер",
|
||||
"katkas": "Катки",
|
||||
"katkas": "Bыброкаток",
|
||||
"mini-loaders": "Мини погрузчик",
|
||||
"katka": "Катка",
|
||||
"compressors": "Компрессоры",
|
||||
"testimonials": "Отзывы",
|
||||
@@ -179,5 +180,10 @@
|
||||
"beton_nasos": "Бетононасосы",
|
||||
"vodovoz": "Водовоз",
|
||||
"assenizator": "Ассенизатор",
|
||||
"manipulyator": "Манипулятор"
|
||||
"manipulyator": "Манипулятор",
|
||||
"Avtovishka": "Автовышка",
|
||||
"Avtolift": "Автолифт",
|
||||
"downloadError": "Ошибка при загрузке данных",
|
||||
"noData": "Специальная техника не найдена",
|
||||
"noDataDesc": "На данный момент товары отсутствуют. Пожалуйста, попробуйте позже."
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
"tele-loader": "Teleskopik yuklagich",
|
||||
"crawler-excavators": "Paletli ekskavatorlar",
|
||||
"crawler-excavator": "Paletli ekskavator",
|
||||
"wheel-excavators": "G'ildirakli ekskavatorlar",
|
||||
"wheel-excavators": "Ekskavatorlar",
|
||||
"wheel-excavator": "G'ildirakli ekskavator",
|
||||
"mini-excavators": "Mini-ekskavatorlar",
|
||||
"excavator-loaders": "Ekskavator yuklagichlari",
|
||||
@@ -47,6 +47,7 @@
|
||||
"buldozer": "Buldozer",
|
||||
"katkas": "Katkalar",
|
||||
"katka": "Katka",
|
||||
"mini-loaders": "Kichik yuklagichlar",
|
||||
"compressors": "Kompressorlar",
|
||||
"testimonials": "Sharhlar",
|
||||
"clients'": "Mijozlar",
|
||||
@@ -141,7 +142,7 @@
|
||||
"bom-length": "Bomning uzunligi",
|
||||
"header-location": "O'zbekiston, Toshkent",
|
||||
"phone": "Telefon nomer",
|
||||
"news-title1": "Keyingi loyihangiz uchun eng yaxshi texnikalar ijarasi",
|
||||
"news-title1": "Keyingi loyihangiz uchun eng yaxshi texnikalar ijarasi",
|
||||
"news-title2": "Yangi yuklagich siz uchun eng yaxshi texnika!",
|
||||
"news-title3": "Yangi kompressorlar to'plami aynan siz uchun",
|
||||
"news-title4": "Bizning kuchli kranlarimiz bilan ishingiz yanada osonlashadi.",
|
||||
@@ -177,7 +178,12 @@
|
||||
"asfalt_yotqizuvchi": "Asfalt yotqizuvchi mashina",
|
||||
"asfalt_kochiruvchi": "Asfalt ko‘chiruvchi mashina",
|
||||
"beton_nasos": "Beton nasos mashinalari",
|
||||
"vodovoz":"Vodovoz",
|
||||
"assenizator":"Assenizator",
|
||||
"manipulyator":"Manipulyator"
|
||||
"vodovoz": "Vodovoz",
|
||||
"assenizator": "Assenizator",
|
||||
"manipulyator": "Manipulyator",
|
||||
"Avtovishka": "Avtovishka",
|
||||
"Avtolift": "Avtolift",
|
||||
"downloadError": "Ma'lumotlarni yuklashda xatolik",
|
||||
"noData": "Mahsus texnikalar topilmadi",
|
||||
"noDataDesc": "Hozircha mahsulotlar mavjud emas. Iltimos, keyinroq qayta urinib ko'ring."
|
||||
}
|
||||
|
||||
27
store/carType.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { create } from "zustand";
|
||||
|
||||
// Type definition
|
||||
interface CarType {
|
||||
name: string;
|
||||
id: number;
|
||||
}
|
||||
|
||||
interface CarStore {
|
||||
initialCar: CarType;
|
||||
setInitialCar: (data: CarType) => void;
|
||||
clearCar: () => void; // Tozalash uchun
|
||||
}
|
||||
|
||||
export const useCarType = create<CarStore>((set) => ({
|
||||
initialCar: {
|
||||
name: "",
|
||||
id: 0,
|
||||
},
|
||||
|
||||
setInitialCar: (data) => set({ initialCar: data }),
|
||||
|
||||
clearCar: () =>
|
||||
set({
|
||||
initialCar: { name: "", id: 0 },
|
||||
}),
|
||||
}));
|
||||