import React, { useState, useEffect, useMemo } from 'react' import { useNavigate } from 'react-router-dom' import { Ic } from '@/icons' import { Card, CardContent } from '@/components/ui/card' import { Button } from '@/components/ui/button' import { Input } from '@/components/ui/input' import { Badge } from '@/components/ui/badge' import { Skeleton } from '@/components/ui/skeleton' import { fetchTours, fetchTourItineraries } from './services/tour-api' import type { TourListItem, TourItineraryItem } from './types' import { TourStatusBadge, CountryFlagBadge } from './components/TourStatusBadge' import FilterSelect from '@/components/shared/FilterSelect' import { Shimmer } from '@/components/shared/Shimmer' import { toFa } from '@/lib/utils' interface TourWithItineraries { tour: TourListItem itineraries: TourItineraryItem[] isLoadingItinerary: boolean itineraryError: string | null hoursToStart: number isCurrentlyRunning: boolean isImminent: boolean currentStepIndex: number progressPercent: number timelineStatus: 'TRAVELING' | 'IMMINENT' | 'UPCOMING' | 'FINISHED' } export default function OngoingToursPage() { const navigate = useNavigate() const [tours, setTours] = useState([]) const [itinerariesMap, setItinerariesMap] = useState>({}) const [isLoading, setIsLoading] = useState(true) const [isRefreshing, setIsRefreshing] = useState(false) const [error, setError] = useState(null) // فیلترها و جستجو const [activeTab, setActiveTab] = useState<'ALL' | 'TRAVELING' | 'IMMINENT'>('ALL') const [searchTerm, setSearchTerm] = useState('') const [countryFilter, setCountryFilter] = useState('ALL') const [expandedTourIds, setExpandedTourIds] = useState>({}) // لود فهرست همه تورها const loadToursData = async (showRefresh = false) => { if (showRefresh) setIsRefreshing(true) else setIsLoading(true) setError(null) try { const res = await fetchTours({ limit: 100 }) const rawTours = res.results || [] setTours(rawTours) // باز کردن پیش‌فرض کارت اولین تورهای در حال اجرا const initialExpanded: Record = {} rawTours.forEach((t) => { initialExpanded[t.id] = true }) setExpandedTourIds(initialExpanded) } catch (err: any) { setError(err.message || 'خطا در برقراری ارتباط با وب‌سرویس تورها') } finally { setIsLoading(false) setIsRefreshing(false) } } useEffect(() => { loadToursData() }, []) // محاسبه وضعیت زمانی و تطبیق منطق ۲۴ تا ۴۸ ساعت مانده به شروع و تورهای در حال اجرا const processedTours: TourWithItineraries[] = useMemo(() => { const now = new Date() const nowMs = now.getTime() return tours .map((tour) => { // ساعت شروع: ابتدای روز؛ ساعت پایان: انتهای روز const startMs = new Date(tour.started_at).setHours(0, 0, 0, 0) const endMs = new Date(tour.ended_at).setHours(23, 59, 59, 999) const hoursToStart = Math.round((startMs - nowMs) / (1000 * 3600)) const isCurrentlyRunning = (nowMs >= startMs && nowMs <= endMs) || tour.trip_status === 'TRAVELING' // نزدیک به شروع: بین ۰ تا ۴۸ ساعت مانده به شروع const isImminent = !isCurrentlyRunning && hoursToStart > 0 && hoursToStart <= 48 let timelineStatus: 'TRAVELING' | 'IMMINENT' | 'UPCOMING' | 'FINISHED' = 'UPCOMING' if (isCurrentlyRunning) { timelineStatus = 'TRAVELING' } else if (isImminent) { timelineStatus = 'IMMINENT' } else if (nowMs > endMs) { timelineStatus = 'FINISHED' } const itState = itinerariesMap[tour.id] const itineraries = itState?.data || [] const isLoadingItinerary = itState?.loading || false const itineraryError = itState?.error || null // تعیین مرحله جاری سفر (Current Itinerary Step) let currentStepIndex = -1 if (itineraries.length > 0) { // بررسی اول: آیا مرحله‌ای صراحتاً وضعیت 'In Progress' یا ۲ دارد؟ const explicitCurrent = itineraries.findIndex( (it) => it.status === 'In Progress' || it.status === 2 || it.status === '2' ) if (explicitCurrent !== -1) { currentStepIndex = explicitCurrent } else { // بررسی دوم: محاسبه بر اساس زمان حال و تاریخ هر مرحله let foundByTime = -1 for (let i = 0; i < itineraries.length; i++) { const itStart = itineraries[i].started_at ? new Date(itineraries[i].started_at).getTime() : 0 const itEnd = itineraries[i].ended_at ? new Date(itineraries[i].ended_at!).getTime() : itStart + 24 * 3600 * 1000 if (nowMs >= itStart && nowMs <= itEnd) { foundByTime = i break } } if (foundByTime !== -1) { currentStepIndex = foundByTime } else if (isCurrentlyRunning) { // اگر در حال سفر است ولی زمان دقیق ثبت نشده، اولین مرحله در انتظار یا ابتدا را انتخاب کن const firstNotStarted = itineraries.findIndex( (it) => it.status === 'Not Started' || it.status === 3 || it.status === '3' ) currentStepIndex = firstNotStarted !== -1 ? firstNotStarted : 0 } else if (isImminent) { // تور به زودی شروع می‌شود، مرحله ۱ مرحله ورودی است currentStepIndex = 0 } } } // درصد پیشرفت تور let progressPercent = 0 if (itineraries.length > 0) { if (timelineStatus === 'FINISHED') { progressPercent = 100 } else if (currentStepIndex >= 0) { progressPercent = Math.round(((currentStepIndex + 1) / itineraries.length) * 100) } } else if (isCurrentlyRunning) { const totalDuration = Math.max(1, endMs - startMs) const elapsed = Math.max(0, nowMs - startMs) progressPercent = Math.min(100, Math.round((elapsed / totalDuration) * 100)) } return { tour, itineraries, isLoadingItinerary, itineraryError, hoursToStart, isCurrentlyRunning, isImminent, currentStepIndex, progressPercent, timelineStatus, } }) .filter((item) => { // معیار قرار گرفتن در این صفحه: // ۱. تور در حال حاضر TRAVELING باشد یا تاریخ امروز در بازه شروع و پایان باشد // ۲. یا زمان شروع آن در بازه نزدیک (۲۴ الی ۴۸ ساعت آینده) باشد return item.isCurrentlyRunning || item.isImminent || item.tour.trip_status === 'TRAVELING' }) }, [tours, itinerariesMap]) // لود خودکار Itineraryهای تورهای در حال برگزاری useEffect(() => { if (processedTours.length === 0) return processedTours.forEach((item) => { const tourId = item.tour.id if (!itinerariesMap[tourId]) { setItinerariesMap((prev) => ({ ...prev, [tourId]: { data: [], loading: true, error: null }, })) fetchTourItineraries(tourId) .then((res) => { setItinerariesMap((prev) => ({ ...prev, [tourId]: { data: res.results || [], loading: false, error: null }, })) }) .catch((err: any) => { setItinerariesMap((prev) => ({ ...prev, [tourId]: { data: [], loading: false, error: err.message || 'خطا در دریافت برنامه سفر', }, })) }) } }) }, [processedTours]) // فیلتر و جستجو const filteredList = useMemo(() => { return processedTours.filter((item) => { // فیلتر تب وضعیت زمانی if (activeTab === 'TRAVELING' && !item.isCurrentlyRunning) return false if (activeTab === 'IMMINENT' && !item.isImminent) return false // فیلتر کشور if (countryFilter !== 'ALL' && item.tour.destination_country !== countryFilter) return false // جستجو if (searchTerm.trim()) { const query = searchTerm.toLowerCase() const matchTitle = item.tour.title.toLowerCase().includes(query) const matchSlug = item.tour.slug.toLowerCase().includes(query) if (!matchTitle && !matchSlug) return false } return true }) }, [processedTours, activeTab, countryFilter, searchTerm]) // شاخص‌های آماری بالای صفحه const stats = useMemo(() => { const totalOngoing = processedTours.length const currentlyTraveling = processedTours.filter((t) => t.isCurrentlyRunning).length const startingSoon = processedTours.filter((t) => t.isImminent).length const distinctCountries = new Set(processedTours.map((t) => t.tour.destination_country).filter(Boolean)).size return { totalOngoing, currentlyTraveling, startingSoon, distinctCountries } }, [processedTours]) const toggleExpand = (tourId: number) => { setExpandedTourIds((prev) => ({ ...prev, [tourId]: !prev[tourId], })) } // قالب‌بندی زمان و تاریخ به فرمت خوانا const formatDateTime = (dateStr?: string | null) => { if (!dateStr) return '-' try { const d = new Date(dateStr) return d.toLocaleDateString('fa-IR', { month: 'long', day: 'numeric', weekday: 'short', }) } catch { return dateStr } } return (
{/* سربرگ صفحه تورهای در حال برگزاری */}

تورهای در حال برگزاری

{stats.totalOngoing} تور فعال و در جریان

پایش زنده وضعیت سفرهای جاری، زمان‌بندی روزانه (Itinerary)، موقعیت مرحله فعلی و وضعیت مسافران

{/* لینک سریع به لیست همه تورها */} {/* دکمه بروزرسانی زنده */}
{/* کارت‌های شاخص‌های کلیدی آماری (KPIs) */}

کل تورهای در جریان

{isLoading ? ( ) : (

{toFa(stats.totalOngoing)}

)}

هم‌اکنون در حال سفر

{isLoading ? ( ) : (

{toFa(stats.currentlyTraveling)}

)}

نزدیک به شروع (۲۴-۴۸ ساعت)

{isLoading ? ( ) : (

{toFa(stats.startingSoon)}

)}

مقاصد در حال میزبانی

{isLoading ? ( ) : (

{toFa(stats.distinctCountries)}

)}
{/* نوار فیلتر و تب‌های زمانی */}
{/* تب‌های وضعیت زمانی */}
{/* فیلتر مقصد و جستجو */}
setSearchTerm(e.target.value)} placeholder="جستجوی عنوان یا اسلاگ تور..." className="h-8 pr-8 text-xs bg-surface-base border-border-soft" />
{/* وضعیت لودینگ استاندارد Shimmer */} {isLoading ? ( ) : error ? ( /* وضعیت خطا */

خطا در بارگذاری تورهای در حال برگزاری

{error}

) : filteredList.length === 0 ? ( /* وضعیت خالی */

توری در حال برگزاری یا نزدیک به شروع یافت نشد

در بازه زمانی جاری (هم‌اکنون یا ۲۴ تا ۴۸ ساعت آینده)، هیچ توری مطابق با فیلترهای انتخابی شما در حال برگزاری نیست.

) : ( /* فهرست کارت‌های تورهای در حال برگزاری با برنامه‌های سفر گام‌به‌گام (Itinerary Stepper) */
{filteredList.map((item) => { const { tour, itineraries, isLoadingItinerary, itineraryError, isCurrentlyRunning, isImminent, hoursToStart, currentStepIndex, progressPercent, } = item const isExpanded = Boolean(expandedTourIds[tour.id]) const imgUrl = tour.image?.image_url?.md || tour.image?.image_url?.medium || tour.image?.image_url?.lg || tour.image?.image_url?.large || tour.image?.image_url?.original || '/placeholder.jpg' return (
{/* بخش ۱: سربرگ کارت تور و مشخصات کلیدی */}
{/* تصویر، عنوان و کشور */}
{tour.title} { ;(e.target as HTMLImageElement).src = 'data:image/svg+xml;utf8,Aqila' }} />
#{tour.id} {/* وضعیت زمانی زنده */} {isCurrentlyRunning ? ( هم‌اکنون در حال برگزاری ) : isImminent ? ( آماده‌سازی شروع ({toFa(Math.max(1, hoursToStart))} ساعت مانده) ) : ( )}

{tour.title}

{tour.started_at} ~ {tour.ended_at}
|
{tour.slug}
{/* دکمه‌ها و خلاصه پیشرفت مرحله */}
{/* نوار کوچک پیشرفت مرحله */} {itineraries.length > 0 && (
وضعیت اجرای برنامه: {toFa(progressPercent)}%
{currentStepIndex >= 0 ? ( <> مرحله فعلی: {toFa(currentStepIndex + 1)} از{' '} {toFa(itineraries.length)} ) : ( `${toFa(itineraries.length)} مرحله ثبت‌شده` )}
)} {/* دکمه باز/بسته کردن تایم‌لاین Itinerary */}
{/* بخش ۲: بدنه Itineraryها و تایم‌لاین زنده مراحل سفر */} {isExpanded && (
{/* اطلاعات مرحله جاری (Current Active Step Callout) */} {itineraries.length > 0 && currentStepIndex >= 0 && (
مرحله جاری تور (هم‌اکنون در حال برگزاری):

{toFa(currentStepIndex + 1)}. {itineraries[currentStepIndex]?.title}

{itineraries[currentStepIndex]?.summary}

{formatDateTime(itineraries[currentStepIndex]?.started_at)}
{itineraries[currentStepIndex]?.ended_at && (
تا {formatDateTime(itineraries[currentStepIndex]?.ended_at)}
)}
)} {/* وضعیت لودینگ Itinerary */} {isLoadingItinerary ? ( ) : itineraryError ? (
{itineraryError}
) : itineraries.length === 0 ? (

برنامه زمان‌بندی روزانه‌ای (Itinerary) برای این تور ثبت نشده است.

) : ( /* تایم‌لاین عمودی مراحل سفر (Vertical Stepper Timeline) */
{itineraries.map((step, idx) => { const isCurrent = idx === currentStepIndex const isPast = currentStepIndex >= 0 ? idx < currentStepIndex : false // وضعیت این مرحله: Completed / In Progress / Not Started const isCompleted = step.status === 'Completed' || step.status === 1 || step.status === '1' || isPast const isInProgress = step.status === 'In Progress' || step.status === 2 || step.status === '2' || isCurrent return (
{/* آیکون / نشانگر دایره‌ای تایم‌لاین */}
{isCompleted ? (
) : isInProgress ? (
{toFa(idx + 1)}
) : (
{toFa(idx + 1)}
)}
{/* کارت محتوای مرحله سفر */}
گام {toFa(idx + 1)} از {toFa(itineraries.length)} {/* برچسب وضعیت مرحله */} {isInProgress ? ( مرحله جاری (In Progress) ) : isCompleted ? ( تکمیل شده (Completed) ) : ( در انتظار شروع (Not Started) )}

{step.title}

{/* تاریخ و زمان مرحله */}
{formatDateTime(step.started_at)}
{step.ended_at && (
الی {formatDateTime(step.ended_at)}
)}
{/* خلاصه و توضیحات مرحله */} {step.summary && (

{step.summary}

)} {/* تصاویر مرحله */} {step.images && step.images.length > 0 && (
تصاویر این مرحله:
{step.images.map((img, imgIdx) => (
))}
)}
) })}
)}
)}
) })}
)}
) }