detail page updated , add subcategory zustand
This commit is contained in:
@@ -1,98 +1,134 @@
|
||||
"use client";
|
||||
|
||||
import { useCarDetail } from "@/components/lib_components/carDetailProvider";
|
||||
import Text from "@/components/lib_components/text";
|
||||
import Image from "next/image";
|
||||
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 { usePathname, useParams } from "next/navigation";
|
||||
import { logoImg } from "@/assets";
|
||||
import { useSubCategory } from "@/store/subCategory";
|
||||
import { minimumValues } from "@/data/minimimValues";
|
||||
import { LoadingSkeleton } from "@/components/loadingProduct";
|
||||
import { EmptyState } from "@/components/emptyState";
|
||||
import { ErrorState } from "@/components/errorState";
|
||||
|
||||
const baseUrl = "https://api.spes-texnika.uz/api/v1/products/";
|
||||
|
||||
type Lang = "uz" | "ru" | "en";
|
||||
const validLangs: Lang[] = ["uz", "ru", "en"];
|
||||
|
||||
function checkCategory(categoryName: string | undefined, lang: string) {
|
||||
if (!categoryName || !validLangs.includes(lang as Lang)) {
|
||||
return { isMinimum: false, text: "" };
|
||||
}
|
||||
const validLang = lang as Lang;
|
||||
const matched = minimumValues[validLang].find(
|
||||
(item: string) => item === categoryName,
|
||||
);
|
||||
if (matched)
|
||||
return { isMinimum: true, text: minimumValues.values[validLang] };
|
||||
return { isMinimum: false, text: "" };
|
||||
}
|
||||
|
||||
export default function CarDetailPage() {
|
||||
const [modalOpen, setModalOpen] = useState<boolean>(false);
|
||||
const { t } = useTranslation();
|
||||
|
||||
// tools of request
|
||||
const initialCar = useCarType((state) => state.initialCar);
|
||||
const initialSubCategory = useSubCategory(
|
||||
(state) => state.initialSubCategory,
|
||||
);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const pathname = usePathname();
|
||||
const params = useParams();
|
||||
const lang = pathname.split("/")[1];
|
||||
const carId = params.carDeatil as string;
|
||||
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) {
|
||||
const fetchProducts = async () => {
|
||||
if (!carId) {
|
||||
setLoading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
const fetchProducts = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
try {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
|
||||
const response = await fetch(`${baseUrl}${initialCar.id}/`, {
|
||||
headers: {
|
||||
"Accept-Language": lang,
|
||||
},
|
||||
});
|
||||
const response = await fetch(`${baseUrl}${carId}/`, {
|
||||
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);
|
||||
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);
|
||||
|
||||
if (result?.data) {
|
||||
if (Array.isArray(result.data)) {
|
||||
setCars(result.data);
|
||||
} else {
|
||||
setCars([result.data]);
|
||||
}
|
||||
} else {
|
||||
setCars([]);
|
||||
}
|
||||
} catch (err) {
|
||||
console.log("Xatolik: ", err);
|
||||
setError(err instanceof Error ? err.message : "Noma'lum xatolik");
|
||||
setCars([]);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchProducts();
|
||||
}, [lang]); // initialCar.id ham dependency ga qo'shildi
|
||||
}, [carId, lang]);
|
||||
|
||||
const firstData = cars ? cars[0] : undefined;
|
||||
if (loading) {
|
||||
return (
|
||||
<div className="my-10 max-w-[1200px] w-full mx-auto grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4 px-2">
|
||||
<LoadingSkeleton />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (error) {
|
||||
return (
|
||||
<div className="my-10 max-w-[1200px] w-full mx-auto px-2">
|
||||
<ErrorState message={error} onRetry={fetchProducts} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const firstData = cars[0];
|
||||
|
||||
if (!firstData) {
|
||||
return <>Maluot topilmadi</>;
|
||||
return (
|
||||
<div className="my-10 max-w-[1200px] w-full mx-auto px-2">
|
||||
<EmptyState />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const { isMinimum, text } = checkCategory(initialSubCategory.name, lang);
|
||||
|
||||
return (
|
||||
<div
|
||||
dir="ltr"
|
||||
className="my-10 max-w-[1200px] w-full mx-auto space-y-8 flex flex-col items-start justify-center px-2"
|
||||
>
|
||||
{/* 1️⃣ Mashina nomi */}
|
||||
{/* Mashina nomi */}
|
||||
<div className="text-2xl font-bold w-full text-center text-secondary mb-10">
|
||||
<Text txt={""} />
|
||||
</div>
|
||||
|
||||
{/* 2️⃣ Rasmi + asosiy narx ma’lumotlari */}
|
||||
{/* Rasmi + asosiy narx ma'lumotlari */}
|
||||
<div className="flex flex-col md:flex-row md:items-start items-center gap-6 justify-center w-full">
|
||||
{/* Mashina rasmi */}
|
||||
<div className="max-w-[600px] w-full h-auto">
|
||||
@@ -105,22 +141,24 @@ export default function CarDetailPage() {
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Asosiy ma’lumotlar */}
|
||||
{/* Asosiy ma'lumotlar */}
|
||||
<div className="lg:space-y-6 space-y-3 w-full">
|
||||
<div className="text-lg font-semibold flex gap-2">
|
||||
<Text txt="hour-price" />
|
||||
{isMinimum ? <p>{text}</p> : <Text txt="hour-price" />} :
|
||||
<span className="font-medium flex gap-2 text-gray-500">
|
||||
{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">
|
||||
{firstData.minimal_order}
|
||||
<Text txt="time" />
|
||||
</span>
|
||||
</div>
|
||||
{!isMinimum && (
|
||||
<div className="text-lg font-semibold flex gap-2">
|
||||
<Text txt="min-time" />
|
||||
<span className="font-medium flex gap-2 text-gray-500">
|
||||
{firstData.minimal_order}
|
||||
<Text txt="time" />
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Izoh */}
|
||||
<div className="space-y-2 text-gray-500 text-lg">
|
||||
@@ -141,7 +179,7 @@ export default function CarDetailPage() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 3️⃣ Texnik xususiyatlar (faqat mavjudlari) */}
|
||||
{/* Texnik xususiyatlar */}
|
||||
<div className="w-full border-t border-gray-300 pt-6">
|
||||
<h2 className="text-xl font-semibold mb-4 text-secondary">
|
||||
Texnik xususiyatlari
|
||||
@@ -159,7 +197,7 @@ export default function CarDetailPage() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 4️⃣ Ijara modal */}
|
||||
{/* Ijara modal */}
|
||||
<CarRentalModal
|
||||
car={firstData}
|
||||
isOpen={modalOpen}
|
||||
|
||||
Reference in New Issue
Block a user