import React, { useState, useEffect } from 'react' import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, DialogClose, } from '@/components/ui/dialog' import { Button } from '@/components/ui/button' import { Input } from '@/components/ui/input' import { Ic } from '@/icons' import { ServiceTranslation, SERVICE_LANGUAGES, type ServiceLanguageCode, } from '@/components/shared/ServiceTranslation' import type { SimCardItem, CreateSimCardInput } from '../services/simcard-api' export type SupportedLanguage = ServiceLanguageCode interface SimcardFormDialogProps { open: boolean onOpenChange: (open: boolean) => void item?: SimCardItem | null onSave: (data: CreateSimCardInput, id?: number) => Promise onDelete?: (id: number) => Promise } const COUNTRIES = [ { id: 1, code: 'IR', name: 'ایران', flag: '🇮🇷' }, { id: 2, code: 'IQ', name: 'عراق', flag: '🇮🇶' }, { id: 4, code: 'SA', name: 'عربستان سعودی', flag: '🇸🇦' }, ] export const LANGUAGES = SERVICE_LANGUAGES const createEmptyTitles = (): Record => ({ ar: '', fa: '', en: '', ru: '', id: '', }) const createEmptyDetails = (): Record => ({ ar: [], fa: [], en: [], ru: [], id: [], }) export function SimcardFormDialog({ open, onOpenChange, item, onSave, onDelete, }: SimcardFormDialogProps) { const isEditing = Boolean(item && item.id) const [activeLangTab, setActiveLangTab] = useState('ar') const [countryId, setCountryId] = useState(1) const [price, setPrice] = useState('10.00') const [status, setStatus] = useState(1) // عناوین چندزبانه const [titles, setTitles] = useState>(createEmptyTitles) // ویژگی‌های چندزبانه const [details, setDetails] = useState>(createEmptyDetails) // افزودن ویژگی جدید در زبان فعال const [newDetailText, setNewDetailText] = useState('') // ویرایش درون‌خطی ویژگی در زبان فعال const [editingDetailIndex, setEditingDetailIndex] = useState(null) const [editingDetailText, setEditingDetailText] = useState('') const [isSubmitting, setIsSubmitting] = useState(false) const [isDeleting, setIsDeleting] = useState(false) const [showDeleteConfirm, setShowDeleteConfirm] = useState(false) const [errorMsg, setErrorMsg] = useState(null) useEffect(() => { if (!open) return setActiveLangTab('ar') if (item) { const cId = item.country?.id || 1 setCountryId(cId) setPrice(item.price ? String(item.price) : '10.00') setStatus(item.status ?? 1) // استخراج عناوین ۵ زبانه از دیتابیس const parsedTitles = createEmptyTitles() if (Array.isArray(item.raw_title)) { for (const t of item.raw_title) { if (t && typeof t === 'object' && t.language_code && t.title) { const lang = t.language_code as SupportedLanguage if (lang in parsedTitles) { parsedTitles[lang] = t.title } } } } else if (item.raw_title && typeof item.raw_title === 'object') { for (const lang of ['ar', 'fa', 'en', 'ru', 'id'] as SupportedLanguage[]) { if (item.raw_title[lang]) parsedTitles[lang] = String(item.raw_title[lang]) } } if (!parsedTitles.ar && !parsedTitles.fa && item.title) { parsedTitles.ar = item.title parsedTitles.fa = item.title } setTitles(parsedTitles) // استخراج ویژگی‌های ۵ زبانه از دیتابیس (آرایه‌های کاملاً مستقل جهت جلوگیری از Mutation) const parsedDetails = createEmptyDetails() if (Array.isArray(item.raw_detail)) { for (const d of item.raw_detail) { if (d && typeof d === 'object' && d.language_code && d.detail) { const lang = d.language_code as SupportedLanguage if (lang in parsedDetails) { const text = String(d.detail).trim() // جلوگیری از موارد تکراری ناشی از ثبت‌های قبلی if (text && !parsedDetails[lang].includes(text)) { parsedDetails[lang].push(text) } } } } } else if (item.raw_detail && typeof item.raw_detail === 'object') { for (const lang of ['ar', 'fa', 'en', 'ru', 'id'] as SupportedLanguage[]) { if (Array.isArray(item.raw_detail[lang])) { const uniqueList: string[] = [] for (const x of item.raw_detail[lang]) { const text = String(x || '').trim() if (text && !uniqueList.includes(text)) { uniqueList.push(text) } } parsedDetails[lang] = uniqueList } } } if (parsedDetails.ar.length === 0 && parsedDetails.fa.length === 0 && Array.isArray(item.simcard_detail)) { const uniqueList: string[] = [] for (const x of item.simcard_detail) { const text = String(x || '').trim() if (text && !uniqueList.includes(text)) { uniqueList.push(text) } } parsedDetails.ar = [...uniqueList] parsedDetails.fa = [...uniqueList] } setDetails(parsedDetails) } else { setCountryId(1) setPrice('10.00') setStatus(1) setTitles(createEmptyTitles()) setDetails(createEmptyDetails()) } setNewDetailText('') setEditingDetailIndex(null) setEditingDetailText('') setErrorMsg(null) setShowDeleteConfirm(false) }, [item, open]) // کار با ویژگی‌های زبان فعال const activeDetails = details[activeLangTab] || [] const handleTabChange = (langCode: SupportedLanguage) => { setActiveLangTab(langCode) } const handleTitleChange = (val: string) => { setTitles((prev) => ({ ...prev, [activeLangTab]: val, })) } const handleCountryChange = (cId: number) => { setCountryId(cId) } const handleAddDetail = () => { if (!newDetailText.trim()) return setDetails((prev) => ({ ...prev, [activeLangTab]: [...(prev[activeLangTab] || []), newDetailText.trim()], })) setNewDetailText('') } const handleRemoveDetail = (index: number) => { setDetails((prev) => ({ ...prev, [activeLangTab]: (prev[activeLangTab] || []).filter((_, i) => i !== index), })) if (editingDetailIndex === index) { setEditingDetailIndex(null) setEditingDetailText('') } } const handleStartEditDetail = (index: number, text: string) => { setEditingDetailIndex(index) setEditingDetailText(text) } const handleSaveEditDetail = (index: number) => { if (!editingDetailText.trim()) return setDetails((prev) => ({ ...prev, [activeLangTab]: (prev[activeLangTab] || []).map((d, i) => i === index ? editingDetailText.trim() : d ), })) setEditingDetailIndex(null) setEditingDetailText('') } const handleCancelEditDetail = () => { setEditingDetailIndex(null) setEditingDetailText('') } const handleSubmit = async (e: React.FormEvent) => { e.preventDefault() const mainTitle = titles.ar.trim() || titles.fa.trim() || titles[activeLangTab].trim() || titles.en.trim() || titles.ru.trim() || titles.id.trim() if (!mainTitle) { setErrorMsg('لطفاً عنوان بسته سیم‌کارت را وارد نمایید.') return } const numPrice = parseFloat(price) if (isNaN(numPrice) || numPrice <= 0) { setErrorMsg('لطفاً قیمت معتبری وارد نمایید.') return } // عناوین ۵ زبانه const finalTitles: Record = { ar: titles.ar.trim() || mainTitle, fa: titles.fa.trim() || mainTitle, en: titles.en.trim() || mainTitle, ru: titles.ru.trim() || mainTitle, id: titles.id.trim() || mainTitle, } // ویژگی‌های ۵ زبانه const finalDetails: Record = { ar: (details.ar || []).filter((d) => d.trim()), fa: (details.fa || []).filter((d) => d.trim()), en: (details.en || []).filter((d) => d.trim()), ru: (details.ru || []).filter((d) => d.trim()), id: (details.id || []).filter((d) => d.trim()), } // فال‌بک ویژگی‌ها در صورت خالی بودن const fallbackDetails = finalDetails.ar.length > 0 ? finalDetails.ar : finalDetails.fa.length > 0 ? finalDetails.fa : [] for (const lang of ['ar', 'fa', 'en', 'ru', 'id'] as SupportedLanguage[]) { if (finalDetails[lang].length === 0 && fallbackDetails.length > 0) { finalDetails[lang] = [...fallbackDetails] } } setErrorMsg(null) setIsSubmitting(true) try { await onSave( { title: finalTitles.fa || finalTitles.ar, titles: finalTitles, country_id: countryId, price: numPrice.toFixed(2), status, simcard_detail: finalDetails.fa.length > 0 ? finalDetails.fa : finalDetails.ar, details: finalDetails, }, item?.id ) onOpenChange(false) } catch (err: any) { setErrorMsg(err?.message || 'خطایی در ثبت اطلاعات رخ داد.') } finally { setIsSubmitting(false) } } const handleConfirmDelete = async () => { if (!item?.id || !onDelete) return setIsDeleting(true) try { await onDelete(item.id) setShowDeleteConfirm(false) onOpenChange(false) } catch (err: any) { setErrorMsg(err?.message || 'خطایی در حذف سیم‌کارت رخ داد.') } finally { setIsDeleting(false) } } const currentLang = LANGUAGES.find((l) => l.code === activeLangTab) || LANGUAGES[0] return ( <> {/* هدر ثابت در بالای مدال */} {isEditing ? 'ویرایش بسته سیم‌کارت' : 'افزودن سیم‌کارت جدید'} {isEditing ? 'تغییرات شما در تمام زبان‌ها در دیتابیس ثبت شده و در اپلیکیشن زائرین بر اساس زبان انتخابی کاربر نمایش داده می‌شود.' : 'سیم‌کارت جدید در دیتابیس ذخیره و در اپلیکیشن فعال خواهد شد.'} {/* فرم: بدنه اسکرول‌شونده و فوتر فیکس‌شده */}
{/* بدنه محتوا (تنها بخشی که اسکرول می‌شود) */}
{errorMsg && (
{errorMsg}
)} {/* ۱. انتخاب کشور مقصد */}
{COUNTRIES.map((c) => { const isSelected = countryId === c.id return ( ) })}
{/* ۲. تب‌های انتخاب ۵ زبان با کامپوننت مشترک ServiceTranslation */} handleTabChange(lang)} completedLangs={Object.fromEntries( Object.entries(titles).map(([k, v]) => [k, Boolean(v?.trim())]) )} primaryLang="ar" title="زبان ترجمه و محتوا" required variant="grid" /> {/* ۳. عنوان بسته سیم‌کارت به زبان فعال */}
{currentLang.dir === 'rtl' ? 'RTL' : 'LTR'}
handleTitleChange(e.target.value)} dir={currentLang.dir} placeholder={`عنوان بسته به زبان ${currentLang.name}...`} className="h-11 text-xs bg-surface-base rounded-xl border-border-soft" required={activeLangTab === 'fa'} />
{/* ۴. قیمت و وضعیت در اپلیکیشن */}
setPrice(e.target.value)} placeholder="10.00" className="h-11 text-xs bg-surface-base rounded-xl border-border-soft font-mono ps-8" required /> $
{/* ۵. ویژگی‌ها و جزئیات بسته به زبان فعال */}
{activeDetails.length} ویژگی ثبت‌شده برای {currentLang.name}
{/* ورودی افزودن ویژگی جدید */}
setNewDetailText(e.target.value)} onKeyDown={(e) => { if (e.key === 'Enter') { e.preventDefault() handleAddDetail() } }} dir={currentLang.dir} placeholder={`افزودن ویژگی به زبان ${currentLang.name} (مثلاً حجم اینترنت، دقایق مکالمه، فعال‌سازی)...`} className="h-10 text-xs bg-surface-base rounded-xl border-border-soft flex-1" />
{/* لیست ویژگی‌های ثبت‌شده در زبان فعال */} {activeDetails.length === 0 ? (
هنوز ویژگی خاصی به زبان {currentLang.name} اضافه نشده است. می‌توانید با فیلد بالا ویژگی جدید ثبت کنید.
) : (
{activeDetails.map((itemText, idx) => (
{editingDetailIndex === idx ? (
setEditingDetailText(e.target.value)} onKeyDown={(e) => { if (e.key === 'Enter') { e.preventDefault() handleSaveEditDetail(idx) } }} dir={currentLang.dir} className="h-9 text-xs bg-card rounded-lg flex-1" autoFocus />
) : (
{itemText}
)}
))}
)}
{/* فوتر فیکس‌شده در پایین */} {/* دکمه حذف در سمت راست (Start در RTL) */}
{isEditing && onDelete && ( )}
{/* دکمه‌های انصراف و ذخیره در سمت چپ (End در RTL) */}
{/* دیالوگ اعتبارسنجی و تایید حذف برای جلوگیری از حذف تصادفی */} {showDeleteConfirm && (
حذف بسته سیم‌کارت آیا از حذف بسته سیم‌کارت «{item?.title}» از پایگاه‌داده اطمینان دارید؟ با حذف این مورد، دیگر در اپلیکیشن زائرین نمایش داده نخواهد شد و این عملیات غیرقابل بازگشت است.
)} ) }