+
+ {/* اعلان موفقیت ذخیره در صورت وجود */}
+ {isDestSavedSuccess && (
+
+
+ کشور مقصد
+
+ {destFlag || destination.flag || '📍'}
+ {destCountry || destination.country}
+
+
+
handleTabChange('hotels')}
+ className="p-3.5 rounded-xl bg-muted/30 border border-border/60 cursor-pointer hover:border-primary/50 transition-colors"
+ title="مشاهده هتلها"
+ >
+ هتلهای فعال
+
+
+ {toFa(destHotels.length)} هتل
+
+
+
handleTabChange('transports')}
+ className="p-3.5 rounded-xl bg-muted/30 border border-border/60 cursor-pointer hover:border-primary/50 transition-colors"
+ title="مشاهده مسیرهای حملونقل"
+ >
+ مسیرهای متصل
+
+
+ {toFa(destRelations.length)} مسیر
+
+
+
+
وضعیت در سامانه
+
+
+ {destIsActive ? 'فعال' : 'غیرفعال'}
+
+
+
+
+
+ {/* ماژول نمایش مشخصات چندزبانه با ServiceTranslation در حالت Readonly */}
+
+
+ setActiveLangTab(lang)}
+ completedLangs={{
+ ar: Boolean(names.ar?.trim()),
+ fa: Boolean(names.fa?.trim()),
+ en: Boolean(names.en?.trim()),
+ ru: Boolean(names.ru?.trim()),
+ id: Boolean(names.id?.trim()),
+ }}
+ primaryLang="ar"
+ title="شناسنامه و متون چندزبانه مقصد"
+ variant="pills"
+ />
+
+
+ {/* محتوای زبان انتخابشده */}
+
+
+
+ نام شهر مقصد ({currentLang.name}):
+
+
+ {names[activeLangTab] || destination.name || '---'}
+
+
- {/* فیلدهای ترجمهپذیر متناسب با زبان تب فعال */}
-
- {/* نام شهر مقصد به زبان انتخابشده */}
+ {holyPlacesMap[activeLangTab] && (
-
-
-
- {currentLang.dir.toUpperCase()}
-
+
+ اماکن مقدسه و زیارتگاهها ({currentLang.name}):
+
+
+ {holyPlacesMap[activeLangTab]
+ .split(/[،,]/)
+ .map((p) => p.trim())
+ .filter(Boolean)
+ .map((place, idx) => (
+
+ 🕌
+ {place}
+
+ ))}
-
- setNames((prev) => ({ ...prev, [activeLangTab]: e.target.value }))
- }
- dir={currentLang.dir}
- placeholder={`نام شهر به زبان ${currentLang.name}...`}
- className="h-10 rounded-xl text-xs bg-card border-border/70 focus-visible:border-primary focus-visible:ring-1 focus-visible:ring-primary shadow-2xs"
- required={activeLangTab === 'fa' || activeLangTab === 'ar'}
- />
+ )}
- {/* توضیحات و راهنمای شهر به زبان انتخابشده */}
-
-
-
+
+
- {/* Save Footer Bar */}
-
-
+ {/* ========================================================================= */}
+ {/* MODAL: EDIT DESTINATION INFO (طبق مدل popup.tsx / dialog.tsx) */}
+ {/* ========================================================================= */}
+
+
+ {/* ماژول چندزبانه ترجمه */}
+
+
+ setActiveLangTab(lang)}
+ completedLangs={{
+ ar: Boolean(names.ar?.trim()),
+ fa: Boolean(names.fa?.trim()),
+ en: Boolean(names.en?.trim()),
+ ru: Boolean(names.ru?.trim()),
+ id: Boolean(names.id?.trim()),
+ }}
+ primaryLang="ar"
+ title="اطلاعات متنی و چندزبانه مقصد"
+ required
+ variant="pills"
+ />
+
+
+ {/* فیلدهای ترجمهپذیر متناسب با زبان فعال */}
+
+
+
+
+
+ {currentLang.dir.toUpperCase()}
+
+
+
+ setNames((prev) => ({ ...prev, [activeLangTab]: e.target.value }))
+ }
+ dir={currentLang.dir}
+ placeholder={`نام شهر به زبان ${currentLang.name}...`}
+ className="h-10 rounded-xl text-xs bg-card border-border/70 focus-visible:border-primary focus-visible:ring-1 focus-visible:ring-primary shadow-2xs"
+ required={activeLangTab === 'fa' || activeLangTab === 'ar'}
+ />
+
+
+
+
+
+ setHolyPlacesMap((prev) => ({ ...prev, [activeLangTab]: e.target.value }))
+ }
+ dir={currentLang.dir}
+ placeholder={`اماکن متبرکه به زبان ${currentLang.name}...`}
+ className="h-10 rounded-xl text-xs bg-card border-border/70 focus-visible:border-primary focus-visible:ring-1 focus-visible:ring-primary shadow-2xs"
+ />
+
+
+
+
+
+
+
+
+
+ {/* فوتر فیکسشده در پایین مدال */}
+
+
+
+
+
+
+
{/* Delete Destination Dialog */}
{
setDestinations((prev) => [item, ...prev])
+ saveCustomTripDestination(item).catch(() => {})
}
const handleUpdateDestination = (item: CustomTripDestinationItem) => {
setDestinations((prev) => prev.map((d) => (d.id === item.id ? item : d)))
+ saveCustomTripDestination(item).catch(() => {})
}
const handleDeleteDestination = (id: string | number) => {
setDestinations((prev) => prev.filter((d) => d.id !== id))
+ deleteCustomTripDestination(id).catch(() => {})
}
// Relations CRUD
diff --git a/src/features/custom-trip/components/CustomTripDestinationsTab.tsx b/src/features/custom-trip/components/CustomTripDestinationsTab.tsx
index 0bbb874..eba1b55 100644
--- a/src/features/custom-trip/components/CustomTripDestinationsTab.tsx
+++ b/src/features/custom-trip/components/CustomTripDestinationsTab.tsx
@@ -689,34 +689,67 @@ export function CustomTripDestinationsTab({
- {
+ e.stopPropagation()
+ if (onUpdateDestination) {
+ onUpdateDestination({ ...item, isActive: !item.isActive })
+ }
+ }}
+ className={`inline-flex items-center gap-1.5 text-xs font-semibold px-2.5 py-1 rounded-full transition-all cursor-pointer ${
item.isActive
- ? 'bg-emerald-500/10 text-emerald-600'
- : 'bg-muted text-muted-foreground'
+ ? 'bg-emerald-500/10 text-emerald-600 hover:bg-emerald-500/20'
+ : 'bg-muted text-muted-foreground hover:bg-muted/80'
}`}
+ title="تغییر وضعیت فعال/غیرفعال"
>
- {item.isActive ? t('customTrip.active') : t('customTrip.inactive')}
-
+ {item.isActive ? t('customTrip.active') : t('customTrip.inactive')}
+
|
-
+
+
+
|
diff --git a/src/features/custom-trip/services/custom-trip-api.ts b/src/features/custom-trip/services/custom-trip-api.ts
index bf7f81a..74f6956 100644
--- a/src/features/custom-trip/services/custom-trip-api.ts
+++ b/src/features/custom-trip/services/custom-trip-api.ts
@@ -129,35 +129,709 @@ const MOCK_ORDERS: CustomTripOrderItem[] = [
// Mock Origins organized by core countries
const MOCK_ORIGINS: CustomTripOriginItem[] = [
- // عمان (Oman)
- { id: 'muscat', name: 'مسقط', nameEn: 'Muscat', country: 'عُمان', countryCode: 'OM', flag: '🇴🇲', isInternational: true, isActive: true },
- { id: 'salalah', name: 'صلاله', nameEn: 'Salalah', country: 'عُمان', countryCode: 'OM', flag: '🇴🇲', isInternational: true, isActive: true },
-
- // بحرین (Bahrain)
- { id: 'manama', name: 'منامه', nameEn: 'Manama', country: 'بحرین', countryCode: 'BH', flag: '🇧🇭', isInternational: true, isActive: true },
- { id: 'muharraq', name: 'المحرق', nameEn: 'Muharraq', country: 'بحرین', countryCode: 'BH', flag: '🇧🇭', isInternational: true, isActive: true },
-
- // کویت (Kuwait)
- { id: 'kuwait_city', name: 'کویت', nameEn: 'Kuwait City', country: 'کویت', countryCode: 'KW', flag: '🇰🇼', isInternational: true, isActive: true },
- { id: 'al_ahmadi', name: 'الاحمدی', nameEn: 'Al Ahmadi', country: 'کویت', countryCode: 'KW', flag: '🇰🇼', isInternational: true, isActive: true },
-
- // عربستان سعودی (Saudi Arabia)
- { id: 'riyadh', name: 'ریاض', nameEn: 'Riyadh', country: 'عربستان سعودی', countryCode: 'SA', flag: '🇸🇦', isInternational: true, isActive: true },
- { id: 'jeddah', name: 'جده', nameEn: 'Jeddah', country: 'عربستان سعودی', countryCode: 'SA', flag: '🇸🇦', isInternational: true, isActive: true },
- { id: 'dammam', name: 'دمام', nameEn: 'Dammam', country: 'عربستان سعودی', countryCode: 'SA', flag: '🇸🇦', isInternational: true, isActive: true },
- { id: 'qatif', name: 'قطیف', nameEn: 'Qatif', country: 'عربستان سعودی', countryCode: 'SA', flag: '🇸🇦', isInternational: true, isActive: true },
-
- // ایران (Iran)
- { id: 'tehran', name: 'تهران', nameEn: 'Tehran', country: 'ایران', countryCode: 'IR', flag: '🇮🇷', isInternational: false, isActive: true },
- { id: 'mashhad', name: 'مشهد', nameEn: 'Mashhad', country: 'ایران', countryCode: 'IR', flag: '🇮🇷', isInternational: false, isActive: true },
- { id: 'qom', name: 'قم', nameEn: 'Qom', country: 'ایران', countryCode: 'IR', flag: '🇮🇷', isInternational: false, isActive: true },
- { id: 'isfahan', name: 'اصفهان', nameEn: 'Isfahan', country: 'ایران', countryCode: 'IR', flag: '🇮🇷', isInternational: false, isActive: true },
- { id: 'shiraz', name: 'شیراز', nameEn: 'Shiraz', country: 'ایران', countryCode: 'IR', flag: '🇮🇷', isInternational: false, isActive: true },
- { id: 'ahvaz', name: 'اهواز', nameEn: 'Ahvaz', country: 'ایران', countryCode: 'IR', flag: '🇮🇷', isInternational: false, isActive: true },
-
- // عراق (Iraq)
- { id: 'baghdad', name: 'بغداد', nameEn: 'Baghdad', country: 'عراق', countryCode: 'IQ', flag: '🇮🇶', isInternational: true, isActive: true },
- { id: 'basra', name: 'بصره', nameEn: 'Basra', country: 'عراق', countryCode: 'IQ', flag: '🇮🇶', isInternational: true, isActive: true },
+ // ۱. عربستان سعودی (Saudi Arabia)
+ {
+ id: 'riyadh',
+ name: 'الرياض',
+ nameEn: 'Riyadh',
+ country: 'عربستان سعودی',
+ countryCode: 'SA',
+ flag: '🇸🇦',
+ isInternational: true,
+ isActive: true,
+ translations: {
+ ar: { name: 'الرياض' },
+ fa: { name: 'ریاض' },
+ en: { name: 'Riyadh' },
+ ru: { name: 'Эр-Рияд' },
+ id: { name: 'Riyadh' },
+ },
+ },
+ {
+ id: 'qatif',
+ name: 'القطيف',
+ nameEn: 'Qatif',
+ country: 'عربستان سعودی',
+ countryCode: 'SA',
+ flag: '🇸🇦',
+ isInternational: true,
+ isActive: true,
+ translations: {
+ ar: { name: 'القطيف' },
+ fa: { name: 'قطیف' },
+ en: { name: 'Qatif' },
+ ru: { name: 'Катиф' },
+ id: { name: 'Qatif' },
+ },
+ },
+ {
+ id: 'dammam',
+ name: 'الدمام',
+ nameEn: 'Dammam',
+ country: 'عربستان سعودی',
+ countryCode: 'SA',
+ flag: '🇸🇦',
+ isInternational: true,
+ isActive: true,
+ translations: {
+ ar: { name: 'الدمام' },
+ fa: { name: 'دمام' },
+ en: { name: 'Dammam' },
+ ru: { name: 'Даммам' },
+ id: { name: 'Dammam' },
+ },
+ },
+ {
+ id: 'al_ahsa',
+ name: 'الأحساء',
+ nameEn: 'Al-Ahsa',
+ country: 'عربستان سعودی',
+ countryCode: 'SA',
+ flag: '🇸🇦',
+ isInternational: true,
+ isActive: true,
+ translations: {
+ ar: { name: 'الأحساء' },
+ fa: { name: 'احساء' },
+ en: { name: 'Al-Ahsa' },
+ ru: { name: 'Эль-Ахса' },
+ id: { name: 'Al-Ahsa' },
+ },
+ },
+ {
+ id: 'jeddah',
+ name: 'جدة',
+ nameEn: 'Jeddah',
+ country: 'عربستان سعودی',
+ countryCode: 'SA',
+ flag: '🇸🇦',
+ isInternational: true,
+ isActive: true,
+ translations: {
+ ar: { name: 'جدة' },
+ fa: { name: 'جده' },
+ en: { name: 'Jeddah' },
+ ru: { name: 'Джидда' },
+ id: { name: 'Jeddah' },
+ },
+ },
+ {
+ id: 'medina',
+ name: 'المدينة المنورة',
+ nameEn: 'Medina',
+ country: 'عربستان سعودی',
+ countryCode: 'SA',
+ flag: '🇸🇦',
+ isInternational: true,
+ isActive: true,
+ translations: {
+ ar: { name: 'المدينة المنورة' },
+ fa: { name: 'مدینه منوره' },
+ en: { name: 'Medina' },
+ ru: { name: 'Медина' },
+ id: { name: 'Madinah' },
+ },
+ },
+ {
+ id: 'mecca',
+ name: 'مكة المكرمة',
+ nameEn: 'Mecca',
+ country: 'عربستان سعودی',
+ countryCode: 'SA',
+ flag: '🇸🇦',
+ isInternational: true,
+ isActive: true,
+ translations: {
+ ar: { name: 'مكة المكرمة' },
+ fa: { name: 'مکه مکرمه' },
+ en: { name: 'Mecca' },
+ ru: { name: 'Мекка' },
+ id: { name: 'Makkah' },
+ },
+ },
+
+ // ۲. امارات متحده عربی (United Arab Emirates)
+ {
+ id: 'dubai',
+ name: 'دبي',
+ nameEn: 'Dubai',
+ country: 'امارات متحده عربی',
+ countryCode: 'AE',
+ flag: '🇦🇪',
+ isInternational: true,
+ isActive: true,
+ translations: {
+ ar: { name: 'دبي' },
+ fa: { name: 'دبی' },
+ en: { name: 'Dubai' },
+ ru: { name: 'Дубай' },
+ id: { name: 'Dubai' },
+ },
+ },
+ {
+ id: 'abu_dhabi',
+ name: 'أبوظبي',
+ nameEn: 'Abu Dhabi',
+ country: 'امارات متحده عربی',
+ countryCode: 'AE',
+ flag: '🇦🇪',
+ isInternational: true,
+ isActive: true,
+ translations: {
+ ar: { name: 'أبوظبي' },
+ fa: { name: 'ابوظبی' },
+ en: { name: 'Abu Dhabi' },
+ ru: { name: 'Абу-Даби' },
+ id: { name: 'Abu Dhabi' },
+ },
+ },
+ {
+ id: 'sharjah',
+ name: 'الشارقة',
+ nameEn: 'Sharjah',
+ country: 'امارات متحده عربی',
+ countryCode: 'AE',
+ flag: '🇦🇪',
+ isInternational: true,
+ isActive: true,
+ translations: {
+ ar: { name: 'الشارقة' },
+ fa: { name: 'شارجه' },
+ en: { name: 'Sharjah' },
+ ru: { name: 'Шарджа' },
+ id: { name: 'Sharjah' },
+ },
+ },
+
+ // ۳. قطر (Qatar)
+ {
+ id: 'doha',
+ name: 'الدوحة',
+ nameEn: 'Doha',
+ country: 'قطر',
+ countryCode: 'QA',
+ flag: '🇶🇦',
+ isInternational: true,
+ isActive: true,
+ translations: {
+ ar: { name: 'الدوحة' },
+ fa: { name: 'دوحه' },
+ en: { name: 'Doha' },
+ ru: { name: 'Доха' },
+ id: { name: 'Doha' },
+ },
+ },
+ {
+ id: 'al_rayyan',
+ name: 'الريان',
+ nameEn: 'Al Rayyan',
+ country: 'قطر',
+ countryCode: 'QA',
+ flag: '🇶🇦',
+ isInternational: true,
+ isActive: true,
+ translations: {
+ ar: { name: 'الريان' },
+ fa: { name: 'الریان' },
+ en: { name: 'Al Rayyan' },
+ ru: { name: 'Эр-Райян' },
+ id: { name: 'Al Rayyan' },
+ },
+ },
+
+ // ۴. کویت (Kuwait)
+ {
+ id: 'kuwait_city',
+ name: 'مدينة الكويت',
+ nameEn: 'Kuwait City',
+ country: 'کویت',
+ countryCode: 'KW',
+ flag: '🇰🇼',
+ isInternational: true,
+ isActive: true,
+ translations: {
+ ar: { name: 'مدينة الكويت' },
+ fa: { name: 'شهر کویت' },
+ en: { name: 'Kuwait City' },
+ ru: { name: 'Эль-Кувейт' },
+ id: { name: 'Kota Kuwait' },
+ },
+ },
+ {
+ id: 'al_ahmadi',
+ name: 'الأحمدي',
+ nameEn: 'Al Ahmadi',
+ country: 'کویت',
+ countryCode: 'KW',
+ flag: '🇰🇼',
+ isInternational: true,
+ isActive: true,
+ translations: {
+ ar: { name: 'الأحمدي' },
+ fa: { name: 'الاحمدی' },
+ en: { name: 'Al Ahmadi' },
+ ru: { name: 'Аль-Ахмади' },
+ id: { name: 'Al Ahmadi' },
+ },
+ },
+ {
+ id: 'hawally',
+ name: 'حولي',
+ nameEn: 'Hawally',
+ country: 'کویت',
+ countryCode: 'KW',
+ flag: '🇰🇼',
+ isInternational: true,
+ isActive: true,
+ translations: {
+ ar: { name: 'حولي' },
+ fa: { name: 'حولی' },
+ en: { name: 'Hawally' },
+ ru: { name: 'Хавалли' },
+ id: { name: 'Hawally' },
+ },
+ },
+
+ // ۵. بحرین (Bahrain)
+ {
+ id: 'manama',
+ name: 'المنامة',
+ nameEn: 'Manama',
+ country: 'بحرین',
+ countryCode: 'BH',
+ flag: '🇧🇭',
+ isInternational: true,
+ isActive: true,
+ translations: {
+ ar: { name: 'المنامة' },
+ fa: { name: 'منامه' },
+ en: { name: 'Manama' },
+ ru: { name: 'Манама' },
+ id: { name: 'Manama' },
+ },
+ },
+ {
+ id: 'muharraq',
+ name: 'المحرق',
+ nameEn: 'Muharraq',
+ country: 'بحرین',
+ countryCode: 'BH',
+ flag: '🇧🇭',
+ isInternational: true,
+ isActive: true,
+ translations: {
+ ar: { name: 'المحرق' },
+ fa: { name: 'المحرق' },
+ en: { name: 'Muharraq' },
+ ru: { name: 'Мухаррак' },
+ id: { name: 'Muharraq' },
+ },
+ },
+ {
+ id: 'sitra',
+ name: 'سترة',
+ nameEn: 'Sitra',
+ country: 'بحرین',
+ countryCode: 'BH',
+ flag: '🇧🇭',
+ isInternational: true,
+ isActive: true,
+ translations: {
+ ar: { name: 'سترة' },
+ fa: { name: 'ستره' },
+ en: { name: 'Sitra' },
+ ru: { name: 'Ситра' },
+ id: { name: 'Sitra' },
+ },
+ },
+ {
+ id: 'riffa',
+ name: 'الرفاع',
+ nameEn: 'Riffa',
+ country: 'بحرین',
+ countryCode: 'BH',
+ flag: '🇧🇭',
+ isInternational: true,
+ isActive: true,
+ translations: {
+ ar: { name: 'الرفاع' },
+ fa: { name: 'الرفاع' },
+ en: { name: 'Riffa' },
+ ru: { name: 'Эр-Рифа' },
+ id: { name: 'Riffa' },
+ },
+ },
+
+ // ۶. عُمان (Oman)
+ {
+ id: 'muscat',
+ name: 'مسقط',
+ nameEn: 'Muscat',
+ country: 'عُمان',
+ countryCode: 'OM',
+ flag: '🇴🇲',
+ isInternational: true,
+ isActive: true,
+ translations: {
+ ar: { name: 'مسقط' },
+ fa: { name: 'مسقط' },
+ en: { name: 'Muscat' },
+ ru: { name: 'Маскат' },
+ id: { name: 'Muskat' },
+ },
+ },
+ {
+ id: 'salalah',
+ name: 'صلالة',
+ nameEn: 'Salalah',
+ country: 'عُمان',
+ countryCode: 'OM',
+ flag: '🇴🇲',
+ isInternational: true,
+ isActive: true,
+ translations: {
+ ar: { name: 'صلالة' },
+ fa: { name: 'صلاله' },
+ en: { name: 'Salalah' },
+ ru: { name: 'Салала' },
+ id: { name: 'Salalah' },
+ },
+ },
+ {
+ id: 'sohar',
+ name: 'صحار',
+ nameEn: 'Sohar',
+ country: 'عُمان',
+ countryCode: 'OM',
+ flag: '🇴🇲',
+ isInternational: true,
+ isActive: true,
+ translations: {
+ ar: { name: 'صحار' },
+ fa: { name: 'صحار' },
+ en: { name: 'Sohar' },
+ ru: { name: 'Сохар' },
+ id: { name: 'Sohar' },
+ },
+ },
+ {
+ id: 'nizwa',
+ name: 'نزوى',
+ nameEn: 'Nizwa',
+ country: 'عُمان',
+ countryCode: 'OM',
+ flag: '🇴🇲',
+ isInternational: true,
+ isActive: true,
+ translations: {
+ ar: { name: 'نزوى' },
+ fa: { name: 'نزوی' },
+ en: { name: 'Nizwa' },
+ ru: { name: 'Низва' },
+ id: { name: 'Nizwa' },
+ },
+ },
+
+ // ۷. عراق (Iraq)
+ {
+ id: 'baghdad',
+ name: 'بغداد',
+ nameEn: 'Baghdad',
+ country: 'عراق',
+ countryCode: 'IQ',
+ flag: '🇮🇶',
+ isInternational: true,
+ isActive: true,
+ translations: {
+ ar: { name: 'بغداد' },
+ fa: { name: 'بغداد' },
+ en: { name: 'Baghdad' },
+ ru: { name: 'Багдад' },
+ id: { name: 'Bagdad' },
+ },
+ },
+ {
+ id: 'basra',
+ name: 'البصرة',
+ nameEn: 'Basra',
+ country: 'عراق',
+ countryCode: 'IQ',
+ flag: '🇮🇶',
+ isInternational: true,
+ isActive: true,
+ translations: {
+ ar: { name: 'البصرة' },
+ fa: { name: 'بصره' },
+ en: { name: 'Basra' },
+ ru: { name: 'Басра' },
+ id: { name: 'Basra' },
+ },
+ },
+ {
+ id: 'erbil',
+ name: 'أربيل',
+ nameEn: 'Erbil',
+ country: 'عراق',
+ countryCode: 'IQ',
+ flag: '🇮🇶',
+ isInternational: true,
+ isActive: true,
+ translations: {
+ ar: { name: 'أربيل' },
+ fa: { name: 'اربیل' },
+ en: { name: 'Erbil' },
+ ru: { name: 'Эрбиль' },
+ id: { name: 'Erbil' },
+ },
+ },
+ {
+ id: 'najaf',
+ name: 'النجف الأشرف',
+ nameEn: 'Najaf',
+ country: 'عراق',
+ countryCode: 'IQ',
+ flag: '🇮🇶',
+ isInternational: true,
+ isActive: true,
+ translations: {
+ ar: { name: 'النجف الأشرف' },
+ fa: { name: 'نجف اشرف' },
+ en: { name: 'Najaf' },
+ ru: { name: 'Эн-Наджаф' },
+ id: { name: 'Najaf' },
+ },
+ },
+ {
+ id: 'karbala',
+ name: 'كربلاء المقدسة',
+ nameEn: 'Karbala',
+ country: 'عراق',
+ countryCode: 'IQ',
+ flag: '🇮🇶',
+ isInternational: true,
+ isActive: true,
+ translations: {
+ ar: { name: 'كربلاء المقدسة' },
+ fa: { name: 'کربلای معلی' },
+ en: { name: 'Karbala' },
+ ru: { name: 'Кербела' },
+ id: { name: 'Karbala' },
+ },
+ },
+
+ // ۸. لبنان (Lebanon)
+ {
+ id: 'beirut',
+ name: 'بيروت',
+ nameEn: 'Beirut',
+ country: 'لبنان',
+ countryCode: 'LB',
+ flag: '🇱🇧',
+ isInternational: true,
+ isActive: true,
+ translations: {
+ ar: { name: 'بيروت' },
+ fa: { name: 'بیروت' },
+ en: { name: 'Beirut' },
+ ru: { name: 'Бейрут' },
+ id: { name: 'Beirut' },
+ },
+ },
+ {
+ id: 'sidon',
+ name: 'صيدا',
+ nameEn: 'Sidon',
+ country: 'لبنان',
+ countryCode: 'LB',
+ flag: '🇱🇧',
+ isInternational: true,
+ isActive: true,
+ translations: {
+ ar: { name: 'صيدا' },
+ fa: { name: 'صیدا' },
+ en: { name: 'Sidon' },
+ ru: { name: 'Сайда' },
+ id: { name: 'Sidon' },
+ },
+ },
+
+ // ۹. سوریه (Syria)
+ {
+ id: 'damascus',
+ name: 'دمشق',
+ nameEn: 'Damascus',
+ country: 'سوریه',
+ countryCode: 'SY',
+ flag: '🇸🇾',
+ isInternational: true,
+ isActive: true,
+ translations: {
+ ar: { name: 'دمشق' },
+ fa: { name: 'دمشق' },
+ en: { name: 'Damascus' },
+ ru: { name: 'Дамаск' },
+ id: { name: 'Damaskus' },
+ },
+ },
+
+ // ۱۰. اردن (Jordan)
+ {
+ id: 'amman',
+ name: 'عمّان',
+ nameEn: 'Amman',
+ country: 'اردن',
+ countryCode: 'JO',
+ flag: '🇯🇴',
+ isInternational: true,
+ isActive: true,
+ translations: {
+ ar: { name: 'عمّان' },
+ fa: { name: 'امان' },
+ en: { name: 'Amman' },
+ ru: { name: 'Амман' },
+ id: { name: 'Amman' },
+ },
+ },
+
+ // ۱۱. مصر (Egypt)
+ {
+ id: 'cairo',
+ name: 'القاهرة',
+ nameEn: 'Cairo',
+ country: 'مصر',
+ countryCode: 'EG',
+ flag: '🇪🇬',
+ isInternational: true,
+ isActive: true,
+ translations: {
+ ar: { name: 'القاهرة' },
+ fa: { name: 'قاهره' },
+ en: { name: 'Cairo' },
+ ru: { name: 'Каир' },
+ id: { name: 'Kairo' },
+ },
+ },
+ {
+ id: 'alexandria',
+ name: 'الإسكندرية',
+ nameEn: 'Alexandria',
+ country: 'مصر',
+ countryCode: 'EG',
+ flag: '🇪🇬',
+ isInternational: true,
+ isActive: true,
+ translations: {
+ ar: { name: 'الإسكندرية' },
+ fa: { name: 'اسکندریه' },
+ en: { name: 'Alexandria' },
+ ru: { name: 'Александрия' },
+ id: { name: 'Aleksandria' },
+ },
+ },
+
+ // ۱۲. ایران (Iran)
+ {
+ id: 'tehran',
+ name: 'تهران',
+ nameEn: 'Tehran',
+ country: 'ایران',
+ countryCode: 'IR',
+ flag: '🇮🇷',
+ isInternational: false,
+ isActive: true,
+ translations: {
+ ar: { name: 'طهران' },
+ fa: { name: 'تهران' },
+ en: { name: 'Tehran' },
+ ru: { name: 'Тегеран' },
+ id: { name: 'Teheran' },
+ },
+ },
+ {
+ id: 'mashhad',
+ name: 'مشهد',
+ nameEn: 'Mashhad',
+ country: 'ایران',
+ countryCode: 'IR',
+ flag: '🇮🇷',
+ isInternational: false,
+ isActive: true,
+ translations: {
+ ar: { name: 'مشهد' },
+ fa: { name: 'مشهد' },
+ en: { name: 'Mashhad' },
+ ru: { name: 'Мешхед' },
+ id: { name: 'Masyhad' },
+ },
+ },
+ {
+ id: 'qom',
+ name: 'قم',
+ nameEn: 'Qom',
+ country: 'ایران',
+ countryCode: 'IR',
+ flag: '🇮🇷',
+ isInternational: false,
+ isActive: true,
+ translations: {
+ ar: { name: 'قم' },
+ fa: { name: 'قم' },
+ en: { name: 'Qom' },
+ ru: { name: 'Кум' },
+ id: { name: 'Qom' },
+ },
+ },
+ {
+ id: 'isfahan',
+ name: 'اصفهان',
+ nameEn: 'Isfahan',
+ country: 'ایران',
+ countryCode: 'IR',
+ flag: '🇮🇷',
+ isInternational: false,
+ isActive: true,
+ translations: {
+ ar: { name: 'أصفهان' },
+ fa: { name: 'اصفهان' },
+ en: { name: 'Isfahan' },
+ ru: { name: 'Исфахан' },
+ id: { name: 'Isfahan' },
+ },
+ },
+ {
+ id: 'shiraz',
+ name: 'شیراز',
+ nameEn: 'Shiraz',
+ country: 'ایران',
+ countryCode: 'IR',
+ flag: '🇮🇷',
+ isInternational: false,
+ isActive: true,
+ translations: {
+ ar: { name: 'شيراز' },
+ fa: { name: 'شیراز' },
+ en: { name: 'Shiraz' },
+ ru: { name: 'Шираз' },
+ id: { name: 'Syiraz' },
+ },
+ },
+ {
+ id: 'ahvaz',
+ name: 'اهواز',
+ nameEn: 'Ahvaz',
+ country: 'ایران',
+ countryCode: 'IR',
+ flag: '🇮🇷',
+ isInternational: false,
+ isActive: true,
+ translations: {
+ ar: { name: 'الأهواز' },
+ fa: { name: 'اهواز' },
+ en: { name: 'Ahvaz' },
+ ru: { name: 'Ахваз' },
+ id: { name: 'Ahvaz' },
+ },
+ },
]
// Mock Destinations
@@ -847,7 +1521,7 @@ const STORAGE_KEYS = {
DESTINATIONS: 'aqila_custom_destinations_v2',
HOTELS: 'aqila_custom_hotels_v2',
RELATIONS: 'aqila_custom_relations_v2',
- ORIGINS: 'aqila_custom_origins_v2',
+ ORIGINS: 'aqila_custom_origins_v3',
}
function getStored(key: string, fallback: T): T {
@@ -869,7 +1543,12 @@ function setStored(key: string, value: T): void {
}
export async function fetchCustomTripOrigins(): Promise {
- return getStored(STORAGE_KEYS.ORIGINS, MOCK_ORIGINS)
+ const stored = getStored(STORAGE_KEYS.ORIGINS, null)
+ if (!stored || !Array.isArray(stored) || stored.length < 25) {
+ setStored(STORAGE_KEYS.ORIGINS, MOCK_ORIGINS)
+ return MOCK_ORIGINS
+ }
+ return stored
}
export async function saveCustomTripOrigin(item: CustomTripOriginItem): Promise {
@@ -886,6 +1565,30 @@ export async function deleteCustomTripOrigin(id: string | number): Promise
}
export async function fetchCustomTripDestinations(): Promise {
+ try {
+ const remote = await apiFetch('trip/custom/v2/catalog/destinations/?include_inactive=true')
+ if (remote && Array.isArray(remote) && remote.length > 0) {
+ // If local storage has user-modified values (such as added 1s or custom test names), sync them
+ const stored = getStored(STORAGE_KEYS.DESTINATIONS, null)
+ if (stored && Array.isArray(stored)) {
+ for (const localItem of stored) {
+ const match = remote.find((r) => String(r.id) === String(localItem.id) || r.name === localItem.name)
+ if (match && localItem.name && localItem.name !== match.name) {
+ match.name = localItem.name
+ apiFetch(`trip/custom/v2/catalog/destinations/${match.id}/`, {
+ method: 'PATCH',
+ body: JSON.stringify({ name: localItem.name }),
+ }).catch(() => {})
+ }
+ }
+ }
+ setStored(STORAGE_KEYS.DESTINATIONS, remote)
+ return remote
+ }
+ } catch (err) {
+ console.warn('[CustomTrip API] Could not fetch destinations from backend, falling back to cache:', err)
+ }
+
const stored = getStored(STORAGE_KEYS.DESTINATIONS, null)
if (
!stored ||
@@ -912,16 +1615,60 @@ export async function fetchCustomTripDestinationById(id: string | number): Promi
}
export async function saveCustomTripDestination(item: CustomTripDestinationItem): Promise {
- const list = await fetchCustomTripDestinations()
- const exists = list.some((d) => d.id === item.id)
- const updated = exists ? list.map((d) => (d.id === item.id ? item : d)) : [item, ...list]
+ let savedItem = item
+ try {
+ const payload = {
+ id: String(item.id),
+ city_key: String(item.id),
+ name: item.name,
+ nameEn: item.nameEn,
+ name_en: item.nameEn,
+ country: item.country,
+ flag: item.flag,
+ description: item.description,
+ holyPlaces: item.holyPlaces,
+ holy_places: item.holyPlaces,
+ hotelsCount: item.hotelsCount,
+ hotels_count: item.hotelsCount,
+ transportsCount: item.transportsCount,
+ transports_count: item.transportsCount,
+ isActive: item.isActive,
+ is_active: item.isActive,
+ translations: item.translations,
+ }
+ const res = await apiFetch(`trip/custom/v2/catalog/destinations/${item.id}/`, {
+ method: 'PUT',
+ body: JSON.stringify(payload),
+ }).catch(async () => {
+ return await apiFetch('trip/custom/v2/catalog/destinations/', {
+ method: 'POST',
+ body: JSON.stringify(payload),
+ })
+ })
+ if (res && res.id) {
+ savedItem = { ...item, ...res }
+ }
+ } catch (err) {
+ console.warn('[CustomTrip API] Could not save destination to backend, cached locally:', err)
+ }
+
+ const list = getStored(STORAGE_KEYS.DESTINATIONS, MOCK_DESTINATIONS)
+ const exists = list.some((d) => String(d.id) === String(savedItem.id))
+ const updated = exists ? list.map((d) => (String(d.id) === String(savedItem.id) ? savedItem : d)) : [savedItem, ...list]
setStored(STORAGE_KEYS.DESTINATIONS, updated)
- return item
+ return savedItem
}
export async function deleteCustomTripDestination(id: string | number): Promise {
- const list = await fetchCustomTripDestinations()
- setStored(STORAGE_KEYS.DESTINATIONS, list.filter((d) => d.id !== id))
+ try {
+ await apiFetch(`trip/custom/v2/catalog/destinations/${id}/`, {
+ method: 'DELETE',
+ })
+ } catch (err) {
+ console.warn('[CustomTrip API] Could not delete destination on backend:', err)
+ }
+ const list = getStored(STORAGE_KEYS.DESTINATIONS, MOCK_DESTINATIONS)
+ setStored(STORAGE_KEYS.DESTINATIONS, list.filter((d) => String(d.id) !== String(id)))
}
export async function fetchCustomTripTransportRelations(): Promise {