"use client"; import { createHotel, editHotel, getHotel, hotelFeature, hotelFeatureType, hotelType, } from "@/pages/tours/lib/api"; import { useTicketStore } from "@/pages/tours/lib/store"; import type { GetOneTours, HotelFeatures, HotelFeaturesType, Type, } from "@/pages/tours/lib/type"; import { Form, FormControl, FormField, FormItem, FormMessage, } from "@/shared/ui/form"; import { Input } from "@/shared/ui/input"; import { Label } from "@/shared/ui/label"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/shared/ui/select"; import { zodResolver } from "@hookform/resolvers/zod"; import { useMutation, useQuery } from "@tanstack/react-query"; import { X } from "lucide-react"; import { useEffect, useState } from "react"; import { useForm } from "react-hook-form"; import { useTranslation } from "react-i18next"; import { useNavigate } from "react-router-dom"; import { toast } from "sonner"; import z from "zod"; const formSchema = z.object({ title: z.string().min(2, { message: "Sarlavha kamida 2 ta belgidan iborat bo'lishi kerak", }), rating: z.string().min(1).max(5), mealPlan: z.string().min(1, { message: "Taom rejasi tanlanishi majburiy" }), hotelType: z.array(z.string()).optional(), hotelFeatures: z.array(z.string()).optional(), hotelFeaturesType: z.array(z.string()).optional(), }); const StepTwo = ({ data, isEditMode, }: { data: GetOneTours | undefined; isEditMode: boolean; }) => { const { amenities, id: ticketId } = useTicketStore(); const navigate = useNavigate(); const { t } = useTranslation(); // 🧩 Query - Hotel detail const { data: hotelDetail } = useQuery({ queryKey: ["hotel_detail", data?.data.id], queryFn: () => getHotel(data?.data.id!), select: (res) => res.data.data.results, enabled: !!data?.data.id, }); // 🧩 React Hook Form const form = useForm>({ resolver: zodResolver(formSchema), defaultValues: { title: "", rating: "3.0", mealPlan: "", hotelType: [], hotelFeatures: [], hotelFeaturesType: [], }, }); // 🧩 Edit holati uchun formni to‘ldirish useEffect(() => { if (isEditMode && hotelDetail?.[0]) { const hotel = hotelDetail[0]; form.setValue("title", hotel.name); form.setValue("rating", String(hotel.rating)); const mealPlan = hotel.meal_plan === "breakfast" ? "Breakfast Only" : hotel.meal_plan === "all_inclusive" ? "All Inclusive" : hotel.meal_plan === "half_board" ? "Half Board" : hotel.meal_plan === "full_board" ? "Full Board" : "All Inclusive"; form.setValue("mealPlan", mealPlan); form.setValue( "hotelType", hotel.hotel_type?.map((t) => String(t.id)) ?? [], ); form.setValue( "hotelFeatures", hotel.hotel_features?.map((f) => String(f.feature_type.id)) ?? [], ); form.setValue("hotelFeaturesType", [ ...new Set(hotel.hotel_features?.map((f) => String(f.id)) ?? []), ]); } }, [isEditMode, hotelDetail, form, data]); // 🧩 Select ma'lumotlari const [allHotelTypes, setAllHotelTypes] = useState([]); const [allHotelFeature, setAllHotelFeature] = useState([]); const [allHotelFeatureType, setAllHotelFeatureType] = useState< HotelFeaturesType[] >([]); const [featureTypeMapping, setFeatureTypeMapping] = useState< Record >({}); const selectedHotelFeatures = form.watch("hotelFeatures"); // 🔹 Hotel Types yuklash useEffect(() => { const loadHotelTypes = async () => { let page = 1; let results: Type[] = []; let hasNext = true; while (hasNext) { const res = await hotelType({ page, page_size: 50 }); const data = res.data.data; results = [...results, ...data.results]; hasNext = !!data.links.next; page++; } setAllHotelTypes(results); }; loadHotelTypes(); }, []); // 🔹 Hotel Features yuklash useEffect(() => { const loadHotelFeatures = async () => { let page = 1; let results: HotelFeatures[] = []; let hasNext = true; while (hasNext) { const res = await hotelFeature({ page, page_size: 50 }); const data = res.data.data; results = [...results, ...data.results]; hasNext = !!data.links.next; page++; } setAllHotelFeature(results); }; loadHotelFeatures(); }, []); // 🔹 Feature type'larni yuklash (tanlangan feature bo‘yicha) useEffect(() => { if (selectedHotelFeatures && selectedHotelFeatures.length === 0) { setAllHotelFeatureType([]); setFeatureTypeMapping({}); return; } const loadFeatureTypes = async () => { const selectedIds = selectedHotelFeatures && selectedHotelFeatures.map(Number).filter(Boolean); let allResults: HotelFeaturesType[] = []; const mapping: Record = {}; for (const id of selectedIds!) { let page = 1; let hasNext = true; const featureTypes: string[] = []; while (hasNext) { const res = await hotelFeatureType({ page, page_size: 50, feature_type: id, }); const data = res.data.data; allResults = [...allResults, ...data.results]; data.results.forEach((ft: HotelFeaturesType) => featureTypes.push(String(ft.id)), ); hasNext = !!data.links.next; page++; } mapping[String(id)] = featureTypes; } const uniqueResults = allResults.filter( (v, i, a) => a.findIndex((t) => t.id === v.id) === i, ); setAllHotelFeatureType(uniqueResults); setFeatureTypeMapping(mapping); }; loadFeatureTypes(); }, [selectedHotelFeatures]); const { mutate, isPending } = useMutation({ mutationFn: (body: FormData) => createHotel({ body }), onSuccess: () => { toast.success(t("Muvaffaqiyatli saqlandi")); navigate("/tours"); }, onError: () => toast.error(t("Xatolik yuz berdi"), { richColors: true, position: "top-center", }), }); const { mutate: edit, isPending: editPending } = useMutation({ mutationFn: ({ body, id }: { id: number; body: FormData }) => editHotel({ body, id }), onSuccess: () => { toast.success(t("Muvaffaqiyatli saqlandi")); navigate("/tours"); }, onError: () => toast.error(t("Xatolik yuz berdi"), { richColors: true, position: "top-center", }), }); const removeHotelType = (id: string) => form.setValue( "hotelType", (form.getValues("hotelType") ?? []).filter((v) => v !== id), ); const removeHotelFeature = (id: string) => { const current = form.getValues("hotelFeatures") ?? []; const types = form.getValues("hotelFeaturesType") ?? []; const toRemove = featureTypeMapping[id] || []; form.setValue( "hotelFeatures", current.filter((v) => v !== id), ); form.setValue( "hotelFeaturesType", types.filter((v) => !toRemove.includes(v)), ); }; const removeFeatureType = (id: string) => form.setValue( "hotelFeaturesType", (form.getValues("hotelFeaturesType") ?? []).filter((v) => v !== id), ); // 🧩 Submit const onSubmit = (data: z.infer) => { const formData = new FormData(); formData.append("ticket", ticketId ? String(ticketId) : ""); formData.append("name", data.title); formData.append("rating", data.rating); amenities.forEach((e, i) => { formData.append(`hotel_amenities[${i}]`, String(e)); }); const mealPlan = data.mealPlan === "Breakfast Only" ? "breakfast" : data.mealPlan === "Half Board" ? "half_board" : data.mealPlan === "Full Board" ? "full_board" : "all_inclusive"; formData.append("meal_plan", mealPlan); data.hotelType && data.hotelType.forEach((id) => formData.append("hotel_type", id)); data.hotelFeatures && data.hotelFeatures.forEach((id) => formData.append("hotel_features", id)); if (isEditMode && hotelDetail) { edit({ body: formData, id: Number(hotelDetail[0].id), }); } else { mutate(formData); } }; const mealPlans = [ "Breakfast Only", "Half Board", "Full Board", "All Inclusive", ]; return (
{/* Mehmonxona nomi */} ( )} /> {/* Rating */} ( { const val = e.target.value; // Faqat raqam va nuqta kiritishga ruxsat berish if (/^\d*\.?\d*$/.test(val) || val === "") { field.onChange(val); } }} onBlur={(e) => { const val = e.target.value; if (val && !isNaN(parseFloat(val))) { // Agar 1 xonali bo'lsa, .0 qo'shish const num = parseFloat(val); if (val.indexOf(".") === -1) { field.onChange(num.toFixed(1)); } } }} /> )} /> {/* Meal Plan */} ( )} /> {/* Hotel Type */} (
{field.value && field.value.length > 0 && (
{field.value.map((selectedValue) => { const selectedItem = allHotelTypes.find( (item) => String(item.id) === selectedValue, ); return (
{selectedItem?.name}
); })}
)}
)} /> {/* Hotel Features */} (
{field.value && field.value.length > 0 && (
{field.value.map((selectedValue) => { const selectedItem = allHotelFeature.find( (item) => String(item.id) === selectedValue, ); console.log(allHotelFeature); return (
{selectedItem?.hotel_feature_type_name}
); })}
)}
)} /> {/* Hotel Feature Type */} (
{field.value && field.value.length > 0 && (
{field.value.map((selectedValue) => { const selectedItem = allHotelFeatureType.find( (item) => String(item.id) === selectedValue, ); return (
{selectedItem?.feature_name}
); })}
)}
)} />
); }; export default StepTwo;