diff --git a/assets/admin/components/ServiceInsuranceSection.tsx b/assets/admin/components/ServiceInsuranceModal.tsx
similarity index 77%
rename from assets/admin/components/ServiceInsuranceSection.tsx
rename to assets/admin/components/ServiceInsuranceModal.tsx
index 9bb7b4e5..c2fe241d 100644
--- a/assets/admin/components/ServiceInsuranceSection.tsx
+++ b/assets/admin/components/ServiceInsuranceModal.tsx
@@ -3,6 +3,7 @@ import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { ShieldCheckIcon, CheckIcon } from '@heroicons/react/24/outline';
import { toast } from 'sonner';
import { api } from '../lib/api';
+import Modal from './ui/Modal';
import PriceInput from './ui/PriceInput';
import type { ServiceItem } from '../types';
@@ -129,7 +130,7 @@ function ContractCard({ contract, item }: { contract: TenantInsurance; item: Ser
type="number" min={0} max={100} dir="ltr" className="input"
style={{ height: 40, textAlign: 'left' }}
value={draft.coverage_percent ?? ''}
- placeholder="ارثی"
+ placeholder="ارث"
onChange={(e) => setDraft((d) => ({ ...d, coverage_percent: e.target.value === '' ? null : Number(e.target.value) }))}
/>
@@ -158,7 +159,7 @@ function ContractCard({ contract, item }: { contract: TenantInsurance; item: Ser
مقدار خالی از قرارداد بیمه ارث میبرد
-
@@ -171,7 +172,7 @@ function ContractCard({ contract, item }: { contract: TenantInsurance; item: Ser
{!draft.covered && !isLoading && (
این خدمت تحت این بیمه پوشش ندارد
- saveMut.mutate()}>
+ saveMut.mutate()}>
{saveMut.isPending ? '...' : 'ذخیره'}
@@ -180,47 +181,41 @@ function ContractCard({ contract, item }: { contract: TenantInsurance; item: Ser
);
}
-/**
- * Per-insurer coverage editor for a single saved service item, rendered inline
- * inside the service edit modal (no dialog wrapper). Each contract saves on its
- * own; independent of the service item's own save button.
- */
-export default function ServiceInsuranceSection({ item }: { item: ServiceItem }) {
+export default function ServiceInsuranceModal({ item, onClose }: { item: ServiceItem | null; onClose: () => void }) {
const { data, isLoading } = useQuery<{ data: { data: TenantInsurance[] } }>({
queryKey: ['tenant-insurances'],
queryFn: () => api.get('/api/v1/billing/tenant-insurances'),
+ enabled: !!item,
});
const contracts = ((data as any)?.data?.data as TenantInsurance[] | undefined) ?? [];
return (
-
-
-
- پوشش بیمه
-
-
-
- درصد پوشش، فرانشیز و سقف هر بیمهگر برای این خدمت تعیین میشود. این تنظیمات مبنای محاسبهی سهم بیمار و ساخت مطالبات بیمه است.
-
-
- {isLoading ? (
-
در حال بارگذاری...
- ) : contracts.length === 0 ? (
+
+
-
-
قرارداد بیمهی فعالی ندارید
-
ابتدا از بخش بیمهها یک بیمه را فعال کنید.
+
+
درصد پوشش، فرانشیز و سقف هر بیمهگر برای این خدمت تعیین میشود. این تنظیمات مبنای محاسبهی سهم بیمار و ساخت مطالبات بیمه است.
- ) : (
- contracts.map((c) =>
)
- )}
-
+
+ {isLoading ? (
+ در حال بارگذاری...
+ ) : contracts.length === 0 ? (
+
+
+
قرارداد بیمهی فعالی ندارید
+
ابتدا از بخش بیمهها یک بیمه را فعال کنید.
+
+ ) : (
+ item && contracts.map((c) => )
+ )}
+
+
);
}
diff --git a/assets/admin/pages/ClinicServicesPage.test.tsx b/assets/admin/pages/ClinicServicesPage.test.tsx
index e716bc06..32b9765e 100644
--- a/assets/admin/pages/ClinicServicesPage.test.tsx
+++ b/assets/admin/pages/ClinicServicesPage.test.tsx
@@ -36,11 +36,6 @@ beforeEach(() => {
{ uuid: 'st1', full_name: 'مریم امینی', active: true },
{ uuid: 'st2', full_name: 'سحر رحمانی', active: true },
] });
- // coverage before tenant-insurances (coverage URL also contains "tenant-insurances")
- if (url.includes('/service-coverage')) return Promise.resolve({ success: true, data: { data: [] } });
- if (url.includes('/tenant-insurances')) return Promise.resolve({ success: true, data: { data: [
- { uuid: 'ins1', insurance_name: 'تأمین اجتماعی', insurance_kind: 'basic', coverage_percent: 70 },
- ] } });
return Promise.resolve({ success: true, data: [] });
});
});
@@ -64,15 +59,13 @@ describe('ClinicServicesPage (خدمات)', () => {
expect(screen.getByText('سرویس جدید')).toBeInTheDocument();
});
- it('embeds per-insurer coverage inline inside the service edit modal', async () => {
+ it('opens the ⋮ actions menu with insurance and tariff entries for a service', async () => {
renderWithProviders(, { route: '/admin/clinic-services' });
fireEvent.click(await screen.findByText('کندلا ۲۰۲۱'));
- // open the ⋮ actions menu, then ویرایش
fireEvent.click(await screen.findByTitle('عملیات'));
- fireEvent.click(await screen.findByText('ویرایش'));
- // insurance section + contract render inside the same (edit) modal
- expect(await screen.findByText('پوشش بیمه')).toBeInTheDocument();
- expect(await screen.findByText('تأمین اجتماعی')).toBeInTheDocument();
+ expect(await screen.findByText('ویرایش')).toBeInTheDocument();
+ expect(screen.getByText('تعرفههای سالانه')).toBeInTheDocument();
+ expect(screen.getByText('پوشش بیمه')).toBeInTheDocument();
});
});
diff --git a/assets/admin/pages/ClinicServicesPage.tsx b/assets/admin/pages/ClinicServicesPage.tsx
index 7f68aa37..61c6e13a 100644
--- a/assets/admin/pages/ClinicServicesPage.tsx
+++ b/assets/admin/pages/ClinicServicesPage.tsx
@@ -19,7 +19,7 @@ import Modal from '../components/ui/Modal';
import PriceInput from '../components/ui/PriceInput';
import ConfirmDialog from '../components/ui/ConfirmDialog';
import ServiceTariffModal from '../components/ServiceTariffModal';
-import ServiceInsuranceSection from '../components/ServiceInsuranceSection';
+import ServiceInsuranceModal from '../components/ServiceInsuranceModal';
import SearchableSelect from '../components/ui/SearchableSelect';
import FeatureGate from '../components/ui/FeatureGate';
@@ -78,6 +78,7 @@ function ClinicServicesPageInner() {
const [itemModal, setItemModal] = useState<'create' | ServiceItem | null>(null);
const [toggleItem, setToggleItem] = useState(null);
const [tariffItem, setTariffItem] = useState(null);
+ const [insuranceItem, setInsuranceItem] = useState(null);
const [search, setSearch] = useState('');
const [showInactive, setShowInactive] = useState(true);
const [menuOpen, setMenuOpen] = useState(null);
@@ -356,9 +357,10 @@ function ClinicServicesPageInner() {
{menuOpen === item.uuid && (
<>
setMenuOpen(null)} />
-
+
{ setMenuOpen(null); openEditItem(item); }}> ویرایش
{ setMenuOpen(null); setTariffItem(item); }}> تعرفههای سالانه
+
{ setMenuOpen(null); setInsuranceItem(item); }}> پوشش بیمه
{ setMenuOpen(null); setToggleItem(item); }}>{item.active ? : }{item.active ? ' غیرفعالکردن' : ' فعالکردن'}
>
@@ -572,25 +574,12 @@ function ClinicServicesPageInner() {
)}
-
- {/* پوشش بیمه — پیوسته داخل همان مودال، فقط برای سرویس ذخیرهشده */}
- {itemModal !== null && typeof itemModal === 'object' ? (
-
-
-
- ) : (
-
-
- برای تنظیم پوشش بیمه، ابتدا سرویس را ذخیره کنید و سپس آن را ویرایش کنید.
-
- )}
setTariffItem(null)} />
+ setInsuranceItem(null)} />
+
{/* Confirm حذف بخش */}