+ {/* پیام اعلان موفقیت */}
+ {successMessage && (
+
+
+ {successMessage}
+
+ )}
+
+ {/* پیام خطا در صورت وجود */}
+ {errorMessage && (
+
+
+
+ {errorMessage}
+
+
+
+ )}
+
+ {/* کارتهای آماری بالای صفحه */}
+
+
+
+
+
کل دستهبندیها
+
{toFa(categories.length)}
+
+
+
+
+
+
+
+
+
+
+
کل پرسش و پاسخها
+
{toFa(items.length)}
+
+
+
+
+
+
+
+
+
+
+
سوالات فعال در اپلیکیشن
+
+ {toFa(items.filter((i) => i.is_active).length)}
+
+
+
+
+
+
+
+
+
+
+
+
پوشش ۵ زبانه سامانه
+
۱۰۰٪
+
+
+
+
+
+
+
+
+ {/* کنترلر تبهای اصلی + دکمه افزودن + ابزار جستجو */}
+
+ {/* تبهای اصلی */}
+
+
+
+
+
+
+ {/* دکمههای اکشن */}
+
+
+
+ {activeMainTab === 'categories' ? (
+
+ ) : (
+
+ )}
+
+
+
+ {/* نوار جستجو و فیلتر */}
+
+
+
+ setSearchTerm(e.target.value)}
+ placeholder={
+ activeMainTab === 'categories'
+ ? 'جستجو بر اساس عنوان دستهبندی یا شناسه (Slug)...'
+ : 'جستجو در متن سوالات یا عنوان دستهبندی...'
+ }
+ className="pr-9 text-xs border-border/60 bg-card rounded-xl"
+ />
+
+
+ {activeMainTab === 'questions' && (
+
+ دستهبندی:
+
+
+ )}
+
+
+ {/* محتوای اصلی تبها */}
+ {isLoading ? (
+
+
+
+
+
+ ) : activeMainTab === 'categories' ? (
+ /* ═══════════════════════════════════════════════════════════════════════
+ فهرست دستهبندیهای موضوعی
+ ═══════════════════════════════════════════════════════════════════════ */
+ filteredCategories.length === 0 ? (
+
+
+
+
+
هیچ دستهبندیای یافت نشد
+
+ میتوانید با دکمه «دستهبندی جدید» اولین دستهبندی موضوعی سوالات متداول را تعریف کنید.
+
+
+ ) : (
+
+ {filteredCategories.map((cat) => (
+
+
+ {/* هدر کارت: آیکون، عنوان و تاگل فعال */}
+
+
+
+
+
+
+
{cat.title_fa}
+
+ {cat.slug}
+ • ترتیب: {toFa(cat.order)}
+
+
+
+
+ {/* تاگل وضعیت فعال */}
+
+ handleToggleCategoryActive(cat, e)}
+ />
+
+
+
+ {/* توضیحات زیر دستهبندی */}
+
+ {cat.translations?.fa?.description || 'بدون توضیحات کوتاه'}
+
+
+ {/* تگهای زبانها و تعداد سوالات */}
+
+
+ {SUPPORTED_LANGUAGES.map((lang) => {
+ const hasTrans = Boolean(cat.translations?.[lang.code]?.title)
+ return (
+
+ {lang.code.toUpperCase()}
+
+ )
+ })}
+
+
+
+
+
+ {/* دکمههای اکشن */}
+
+
+
+
+
+
+
+
+
+
+ ))}
+
+ )
+ ) : (
+ /* ═══════════════════════════════════════════════════════════════════════
+ فهرست پرسش و پاسخها
+ ═══════════════════════════════════════════════════════════════════════ */
+ filteredItems.length === 0 ? (
+
+
+
+
+
هیچ پرسش و پاسخی یافت نشد
+
+ میتوانید با دکمه «پرسش و پاسخ جدید» یک سوال جدید برای دستهبندی انتخابی ثبت نمایید.
+
+
+ ) : (
+
+ {filteredItems.map((item) => (
+
+
+
+
+
+
+ {item.category_title || 'دستهبندی'}
+
+
+ ترتیب: {toFa(item.order)}
+
+ {!item.is_active && (
+
+ غیرفعال در اپ
+
+ )}
+
+
+
+ {item.question_fa}
+
+
+
+ {/* تاگل وضعیت و اکشنها */}
+
+
+ handleToggleItemActive(item, e)}
+ />
+
+
+
+
+
+
+
+ {/* متن پاسخ (نمایش خلاصه) */}
+
+
+ {item.translations?.fa?.answer || 'بدون پاسخ فارسی'}
+
+
+
+ {/* وضعیت پوشش ۵ زبانه */}
+
+
ترجمهها:
+
+ {SUPPORTED_LANGUAGES.map((lang) => {
+ const hasTrans =
+ Boolean(item.translations?.[lang.code]?.question) &&
+ Boolean(item.translations?.[lang.code]?.answer)
+ return (
+
+ {lang.code.toUpperCase()}
+
+ )
+ })}
+
+
+
+
+ ))}
+
+ )
+ )}
+
+ {/* ═══════════════════════════════════════════════════════════════════════
+ دیالوگ ایجاد و ویرایش دستهبندی (با تبهای ۵ زبانه)
+ ═══════════════════════════════════════════════════════════════════════ */}
+
+
+ {/* ═══════════════════════════════════════════════════════════════════════
+ دیالوگ ایجاد و ویرایش سوال و پاسخ (با تبهای ۵ زبانه)
+ ═══════════════════════════════════════════════════════════════════════ */}
+
+
+ {/* ═══════════════════════════════════════════════════════════════════════
+ دیالوگ تأیید حذف
+ ═══════════════════════════════════════════════════════════════════════ */}
+
+
+ )
+}
diff --git a/src/features/services/components/ShrinesServiceView.tsx b/src/features/services/components/ShrinesServiceView.tsx
new file mode 100644
index 0000000..6707b77
--- /dev/null
+++ b/src/features/services/components/ShrinesServiceView.tsx
@@ -0,0 +1,614 @@
+import React, { useState, useEffect, useMemo } from 'react'
+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 { Shimmer } from '@/components/shared/Shimmer'
+import { toFa } from '@/lib/utils'
+import {
+ Dialog,
+ DialogContent,
+ DialogHeader,
+ DialogTitle,
+ DialogFooter,
+} from '@/components/ui/dialog'
+import type { ShrineItem, CreateShrineInput } from '../types/trip-etiquette'
+import {
+ fetchShrines,
+ createShrine,
+ updateShrine,
+ deleteShrine,
+} from '../services/trip-etiquette-api'
+import { fetchCityGuideCountries } from '../services/zayer-guide-api'
+import type { CityGuideCountry } from '../types/zayer-guide'
+
+export function ShrinesServiceView() {
+ const [shrines, setShrines] = useState