import React, { useState, useEffect, useMemo } from 'react' import { useParams, useNavigate, useSearchParams, Link } from 'react-router-dom' import { Input } from '@/components/ui/input' import { Button } from '@/components/ui/button' import { Badge } from '@/components/ui/badge' import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, } from '@/components/ui/dialog' import DeleteConfirmDialog from '@/components/shared/DeleteConfirmDialog' import { Ic } from '@/icons' import { toFa } from '@/lib/utils' import { useTranslation } from '@/i18n' import { Shimmer } from '@/components/shared/shimmer_frontend' import type { CustomTripDestinationItem, CustomTripHotelItem, CustomTripTransportRelationItem, CustomTripOriginItem, } from './types' import { fetchCustomTripDestinations, fetchCustomTripOrigins, fetchCustomTripHotels, fetchCustomTripTransportRelations, saveCustomTripDestination, deleteCustomTripDestination, saveCustomTripHotel, deleteCustomTripHotel, saveCustomTripTransportRelation, deleteCustomTripTransportRelation, } from './services/custom-trip-api' const PRESET_DEST_COUNTRIES = [ { name: 'عراق', flag: '🇮🇶' }, { name: 'ایران', flag: '🇮🇷' }, { name: 'عربستان سعودی', flag: '🇸🇦' }, { name: 'سوریه', flag: '🇸🇾' }, ] const COMMON_AMENITIES = [ { id: 'wifi', name: 'اینترنت وای‌فای رایگان' }, { id: 'restaurant', name: 'رستوران ایرانی و بوفه باز' }, { id: 'shrine_transfer', name: 'ترانسفر حرم مطهر رایگان' }, { id: 'airport_transfer', name: 'ترانسفر فرودگاهی اختصاصی' }, { id: 'laundry', name: 'لاندری و خدمات خشکشویی' }, { id: 'wheelchair', name: 'خدمات ویژه ویلچر و توان‌یابان' }, { id: 'doctor', name: 'پزشک و خدمات درمانی مقیم' }, { id: 'safety_box', name: 'صندوق امانات دیجیتال در اتاق' }, ] export default function CustomTripDestinationDetailPage() { const { t } = useTranslation() const { id } = useParams<{ id: string }>() const navigate = useNavigate() const [searchParams, setSearchParams] = useSearchParams() // Default active tab is 'info' (مشخصات و اطلاعات شهر) const currentTab = searchParams.get('tab') || 'info' const [isLoading, setIsLoading] = useState(true) const [destination, setDestination] = useState(null) const [allOrigins, setAllOrigins] = useState([]) const [allHotels, setAllHotels] = useState([]) const [allRelations, setAllRelations] = useState([]) // --- TAB 1: DESTINATION INFO FORM STATE --- const [destName, setDestName] = useState('') const [destNameEn, setDestNameEn] = useState('') const [destCountry, setDestCountry] = useState('عراق') const [destFlag, setDestFlag] = useState('🇮🇶') const [destDescription, setDestDescription] = useState('') const [destHolyPlaces, setDestHolyPlaces] = useState('') const [destIsActive, setDestIsActive] = useState(true) const [isDestSavedSuccess, setIsDestSavedSuccess] = useState(false) const [isDestDeleteOpen, setIsDestDeleteOpen] = useState(false) // --- TAB 2: HOTELS STATE --- const [hotelSearch, setHotelSearch] = useState('') const [hotelStarsFilter, setHotelStarsFilter] = useState<'all' | '5' | '4' | '3'>('all') const [hotelViewMode, setHotelViewMode] = useState<'cards' | 'table'>('cards') const [isHotelFormOpen, setIsHotelFormOpen] = useState(false) const [editingHotel, setEditingHotel] = useState(null) const [hotelToDelete, setHotelToDelete] = useState(null) // Hotel form fields const [hotelFormName, setHotelFormName] = useState('') const [hotelFormStars, setHotelFormStars] = useState(5) const [hotelFormDistance, setHotelFormDistance] = useState('') const [hotelFormScore, setHotelFormScore] = useState(4.8) const [hotelFormDescription, setHotelFormDescription] = useState('') const [hotelFormGuideNote, setHotelFormGuideNote] = useState('') const [hotelFormAmenities, setHotelFormAmenities] = useState([]) const [hotelFormCustomAmenity, setHotelFormCustomAmenity] = useState('') const [hotelFormPriceAdult, setHotelFormPriceAdult] = useState(100) const [hotelFormPriceChild, setHotelFormPriceChild] = useState(50) const [hotelFormIsActive, setHotelFormIsActive] = useState(true) // --- TAB 3: TRANSPORTS STATE --- const [transportSearch, setTransportSearch] = useState('') const [transportMethodFilter, setTransportMethodFilter] = useState<'all' | 'flight' | 'train' | 'road'>('all') const [transportViewMode, setTransportViewMode] = useState<'cards' | 'table'>('cards') const [isTransportFormOpen, setIsTransportFormOpen] = useState(false) const [editingTransport, setEditingTransport] = useState(null) const [transportToDelete, setTransportToDelete] = useState(null) // Transport form fields const [transportFormFromCity, setTransportFormFromCity] = useState('') const [transportFormFromCountry, setTransportFormFromCountry] = useState('') const [transportFormHasAirplane, setTransportFormHasAirplane] = useState(true) const [transportFormAirplaneDetails, setTransportFormAirplaneDetails] = useState('') const [transportFormHasTrain, setTransportFormHasTrain] = useState(false) const [transportFormTrainDetails, setTransportFormTrainDetails] = useState('') const [transportFormHasRoad, setTransportFormHasRoad] = useState(false) const [transportFormRoadDetails, setTransportFormRoadDetails] = useState('') const [transportFormGuideNote, setTransportFormGuideNote] = useState('') const [transportFormIsActive, setTransportFormIsActive] = useState(true) // Load all initial data useEffect(() => { let isMounted = true async function load() { setIsLoading(true) try { const [dests, origs, hotels, rels] = await Promise.all([ fetchCustomTripDestinations(), fetchCustomTripOrigins(), fetchCustomTripHotels(), fetchCustomTripTransportRelations(), ]) if (isMounted) { setAllOrigins(origs) setAllHotels(hotels) setAllRelations(rels) const target = dests.find( (d) => String(d.id) === String(id) || d.name === String(id) || (d.nameEn && d.nameEn.toLowerCase() === String(id).toLowerCase()) ) if (target) { setDestination(target) // Init Tab 1 Form setDestName(target.name) setDestNameEn(target.nameEn || '') setDestCountry(target.country) setDestFlag(target.flag || '📍') setDestDescription(target.description || '') setDestHolyPlaces((target.holyPlaces || []).join('، ')) setDestIsActive(target.isActive) } else if (dests.length > 0) { const fallback = dests[0] setDestination(fallback) setDestName(fallback.name) setDestNameEn(fallback.nameEn || '') setDestCountry(fallback.country) setDestFlag(fallback.flag || '📍') setDestDescription(fallback.description || '') setDestHolyPlaces((fallback.holyPlaces || []).join('، ')) setDestIsActive(fallback.isActive) } } } finally { if (isMounted) setIsLoading(false) } } load() return () => { isMounted = false } }, [id]) // Destination-specific hotels const destHotels = useMemo(() => { if (!destination) return [] return allHotels.filter( (h) => h.cityName === destination.name || destination.name.includes(h.cityName) || h.cityName.includes(destination.name) ) }, [allHotels, destination]) // Filtered hotels const filteredHotels = useMemo(() => { return destHotels.filter((h) => { const matchStars = hotelStarsFilter === 'all' || String(h.stars) === hotelStarsFilter const term = hotelSearch.trim().toLowerCase() const matchSearch = !term || h.name.toLowerCase().includes(term) || (h.distanceToShrine && h.distanceToShrine.toLowerCase().includes(term)) || (h.description && h.description.toLowerCase().includes(term)) || (h.guideNote && h.guideNote.toLowerCase().includes(term)) || h.amenities.some((a) => a.toLowerCase().includes(term)) return matchStars && matchSearch }) }, [destHotels, hotelStarsFilter, hotelSearch]) // Destination-specific transport relations const destRelations = useMemo(() => { if (!destination) return [] return allRelations.filter( (r) => r.toCity === destination.name || destination.name.includes(r.toCity) || r.toCity.includes(destination.name) ) }, [allRelations, destination]) // Filtered relations const filteredRelations = useMemo(() => { return destRelations.filter((rel) => { const matchMethod = transportMethodFilter === 'all' || (transportMethodFilter === 'flight' && rel.hasAirplane) || (transportMethodFilter === 'train' && rel.hasTrain) || (transportMethodFilter === 'road' && rel.hasRoad) const term = transportSearch.trim().toLowerCase() const matchSearch = !term || rel.fromCity.toLowerCase().includes(term) || rel.fromCountry.toLowerCase().includes(term) || (rel.airplaneDetails && rel.airplaneDetails.toLowerCase().includes(term)) || (rel.trainDetails && rel.trainDetails.toLowerCase().includes(term)) || (rel.roadDetails && rel.roadDetails.toLowerCase().includes(term)) || (rel.guideNote && rel.guideNote.toLowerCase().includes(term)) return matchMethod && matchSearch }) }, [destRelations, transportMethodFilter, transportSearch]) const handleTabChange = (tabKey: string) => { setSearchParams({ tab: tabKey }) } // --- TAB 1: SAVE DESTINATION HANDLER --- const handleSaveDestinationInfo = async (e: React.FormEvent) => { e.preventDefault() if (!destination || !destName.trim()) return const places = destHolyPlaces .split(/[،,]/) .map((s) => s.trim()) .filter(Boolean) const updated: CustomTripDestinationItem = { ...destination, name: destName.trim(), nameEn: destNameEn.trim() || undefined, country: destCountry.trim(), flag: destFlag, description: destDescription.trim() || undefined, holyPlaces: places.length ? places : undefined, isActive: destIsActive, } await saveCustomTripDestination(updated) setDestination(updated) setIsDestSavedSuccess(true) setTimeout(() => setIsDestSavedSuccess(false), 3000) } const handleDeleteDestinationConfirm = async () => { if (!destination) return await deleteCustomTripDestination(destination.id) navigate('/custom-trip/destinations') } // --- TAB 2: HOTEL HANDLERS --- const handleOpenAddHotel = () => { setEditingHotel(null) setHotelFormName('') setHotelFormStars(5) setHotelFormDistance('') setHotelFormScore(4.8) setHotelFormDescription('') setHotelFormGuideNote('') setHotelFormAmenities(['اینترنت وای‌فای رایگان', 'رستوران ایرانی و بوفه باز']) setHotelFormCustomAmenity('') setHotelFormPriceAdult(110) setHotelFormPriceChild(55) setHotelFormIsActive(true) setIsHotelFormOpen(true) } const handleOpenEditHotel = (hotel: CustomTripHotelItem) => { setEditingHotel(hotel) setHotelFormName(hotel.name) setHotelFormStars(hotel.stars) setHotelFormDistance(hotel.distanceToShrine || '') setHotelFormScore(hotel.score || 4.8) setHotelFormDescription(hotel.description || '') setHotelFormGuideNote(hotel.guideNote || '') setHotelFormAmenities(hotel.amenities || []) setHotelFormCustomAmenity('') setHotelFormPriceAdult(hotel.pricePerDayAdult || 100) setHotelFormPriceChild(hotel.pricePerDayChild || 50) setHotelFormIsActive(hotel.isActive) setIsHotelFormOpen(true) } const handleToggleHotelAmenity = (name: string) => { setHotelFormAmenities((prev) => prev.includes(name) ? prev.filter((a) => a !== name) : [...prev, name] ) } const handleAddCustomHotelAmenity = () => { const val = hotelFormCustomAmenity.trim() if (!val) return if (!hotelFormAmenities.includes(val)) { setHotelFormAmenities((prev) => [...prev, val]) } setHotelFormCustomAmenity('') } const handleSaveHotel = async (e: React.FormEvent) => { e.preventDefault() if (!destination || !hotelFormName.trim()) return const item: CustomTripHotelItem = { id: editingHotel ? editingHotel.id : `hotel_${Date.now()}`, name: hotelFormName.trim(), cityName: destination.name, stars: hotelFormStars, score: hotelFormScore, distanceToShrine: hotelFormDistance.trim() || 'فاصله استاندارد تا حرم مطهر', amenities: hotelFormAmenities, description: hotelFormDescription.trim() || 'هتل درجه یک و مجهز جهت اقامت زائرین گرامی.', guideNote: hotelFormGuideNote.trim() || undefined, pricePerDayAdult: hotelFormPriceAdult, pricePerDayChild: hotelFormPriceChild, isActive: hotelFormIsActive, } await saveCustomTripHotel(item) setAllHotels((prev) => { const exists = prev.some((h) => h.id === item.id) return exists ? prev.map((h) => (h.id === item.id ? item : h)) : [item, ...prev] }) setIsHotelFormOpen(false) } const handleConfirmDeleteHotel = async () => { if (!hotelToDelete) return await deleteCustomTripHotel(hotelToDelete.id) setAllHotels((prev) => prev.filter((h) => h.id !== hotelToDelete.id)) setHotelToDelete(null) } // --- TAB 3: TRANSPORT HANDLERS --- const handleOpenAddTransport = () => { setEditingTransport(null) setTransportFormFromCity(allOrigins.length > 0 ? allOrigins[0].name : 'تهران') setTransportFormFromCountry(allOrigins.length > 0 ? allOrigins[0].country : 'ایران') setTransportFormHasAirplane(true) setTransportFormAirplaneDetails(`پرواز مستقیم به فرودگاه نجف / بغداد`) setTransportFormHasTrain(false) setTransportFormTrainDetails('') setTransportFormHasRoad(false) setTransportFormRoadDetails('') setTransportFormGuideNote(`معمولاً پروازهای این مسیر به صورت روزانه یا چارتر هفتگی انجام می‌شود.`) setTransportFormIsActive(true) setIsTransportFormOpen(true) } const handleOpenEditTransport = (rel: CustomTripTransportRelationItem) => { setEditingTransport(rel) setTransportFormFromCity(rel.fromCity) setTransportFormFromCountry(rel.fromCountry) setTransportFormHasAirplane(rel.hasAirplane) setTransportFormAirplaneDetails(rel.airplaneDetails || '') setTransportFormHasTrain(rel.hasTrain) setTransportFormTrainDetails(rel.trainDetails || '') setTransportFormHasRoad(rel.hasRoad) setTransportFormRoadDetails(rel.roadDetails || '') setTransportFormGuideNote(rel.guideNote || '') setTransportFormIsActive(rel.isActive) setIsTransportFormOpen(true) } const handleSaveTransport = async (e: React.FormEvent) => { e.preventDefault() if (!destination || !transportFormFromCity.trim()) return const item: CustomTripTransportRelationItem = { id: editingTransport ? editingTransport.id : `rel_${Date.now()}`, fromCity: transportFormFromCity.trim(), fromCountry: transportFormFromCountry.trim() || 'نامشخص', toCity: destination.name, toCountry: destination.country, hasAirplane: transportFormHasAirplane, airplaneDetails: transportFormHasAirplane ? transportFormAirplaneDetails.trim() || undefined : undefined, hasTrain: transportFormHasTrain, trainDetails: transportFormHasTrain ? transportFormTrainDetails.trim() || undefined : undefined, hasRoad: transportFormHasRoad, roadDetails: transportFormHasRoad ? transportFormRoadDetails.trim() || undefined : undefined, guideNote: transportFormGuideNote.trim() || undefined, isActive: transportFormIsActive, } await saveCustomTripTransportRelation(item) setAllRelations((prev) => { const exists = prev.some((r) => r.id === item.id) return exists ? prev.map((r) => (r.id === item.id ? item : r)) : [item, ...prev] }) setIsTransportFormOpen(false) } const handleConfirmDeleteTransport = async () => { if (!transportToDelete) return await deleteCustomTripTransportRelation(transportToDelete.id) setAllRelations((prev) => prev.filter((r) => r.id !== transportToDelete.id)) setTransportToDelete(null) } if (isLoading) { return (
) } if (!destination) { return (

شهر مقصد مورد نظر یافت نشد!

) } return (
{/* Top Breadcrumb Navigation */}
شهرهای مقصد / {destination.flag || '📍'} {destination.name}
{destination.isActive ? 'مقصد فعال و قابل رزرو' : 'مقصد غیرفعال'}
{/* Tabs Navigation Header: 1. Info & Description | 2. Hotels | 3. Transportation */}
{/* Tab 1: City Info & Custom Trip Description */} {/* Tab 2: Hotels */} {/* Tab 3: Transportation */}
{/* ========================================================================= */} {/* TAB 1: DESTINATION INFO & DESCRIPTION (صفحه اول: مشخصات و توضیحات شهر) */} {/* ========================================================================= */} {currentTab === 'info' && (

{destFlag || '📍'} اطلاعات و شناسنامه شهر {destination.name}

ویرایش مشخصات اصلی، موقعیت کشور، اماکن مقدسه و توضیحات شهر برای ماژول سفر اختصاصی (Custom Trip).

{isDestSavedSuccess && (
تغییرات با موفقیت ذخیره شد
)}
{/* Form Grid */}
{/* 1. Country */}
{/* 2. City Name FA */}
setDestName(e.target.value)} placeholder="مثال: کربلای معلی، نجف اشرف، مشهد مقدس..." className="h-11 rounded-xl text-xs sm:text-sm" required />
{/* 3. City Name EN */}
setDestNameEn(e.target.value)} placeholder="e.g. Karbala, Najaf, Mashhad..." className="h-11 rounded-xl text-xs sm:text-sm font-mono" />
{/* 4. Active Status Toggle */}
{/* 5. Holy Places */}
setDestHolyPlaces(e.target.value)} placeholder="مثال: حرم مطهر امام حسین (ع)، حرم حضرت ابوالفضل العباس (ع)، تل زینبیه، مقام علی‌اکبر (ع)..." className="h-11 rounded-xl text-xs sm:text-sm" />
{/* 6. City Description for Custom Trip (توضیح برای آن شهر که در Custom Trip در توضیحات شهر قرار داده می‌شود) */}
این متن در اپلیکیشن هنگام انتخاب این مقصد به زائر نمایش داده می‌شود.