diff --git a/assets/admin/components/ServiceInsuranceModal.tsx b/assets/admin/components/ServiceInsuranceSection.tsx similarity index 77% rename from assets/admin/components/ServiceInsuranceModal.tsx rename to assets/admin/components/ServiceInsuranceSection.tsx index 10a9ae98..9bb7b4e5 100644 --- a/assets/admin/components/ServiceInsuranceModal.tsx +++ b/assets/admin/components/ServiceInsuranceSection.tsx @@ -3,7 +3,6 @@ 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'; @@ -85,7 +84,7 @@ function ContractCard({ contract, item }: { contract: TenantInsurance; item: Ser }}>
@@ -130,7 +129,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) }))} /> @@ -159,7 +158,7 @@ function ContractCard({ contract, item }: { contract: TenantInsurance; item: Ser
مقدار خالی از قرارداد بیمه ارث می‌برد -
@@ -172,7 +171,7 @@ function ContractCard({ contract, item }: { contract: TenantInsurance; item: Ser {!draft.covered && !isLoading && (
این خدمت تحت این بیمه پوشش ندارد -
@@ -181,41 +180,47 @@ function ContractCard({ contract, item }: { contract: TenantInsurance; item: Ser ); } -export default function ServiceInsuranceModal({ item, onClose }: { item: ServiceItem | null; onClose: () => void }) { +/** + * 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 }) { 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 ? ( -
- -
قرارداد بیمه‌ی فعالی ندارید
-
ابتدا از بخش بیمه‌ها یک بیمه را فعال کنید.
-
- ) : ( - item && contracts.map((c) => ) - )} +
+
+ + پوشش بیمه
- +
+ + درصد پوشش، فرانشیز و سقف هر بیمه‌گر برای این خدمت تعیین می‌شود. این تنظیمات مبنای محاسبه‌ی سهم بیمار و ساخت مطالبات بیمه است. +
+ + {isLoading ? ( +
در حال بارگذاری...
+ ) : contracts.length === 0 ? ( +
+ +
قرارداد بیمه‌ی فعالی ندارید
+
ابتدا از بخش بیمه‌ها یک بیمه را فعال کنید.
+
+ ) : ( + contracts.map((c) => ) + )} +
); } diff --git a/assets/admin/pages/ClinicServicesPage.test.tsx b/assets/admin/pages/ClinicServicesPage.test.tsx index c94d3748..e716bc06 100644 --- a/assets/admin/pages/ClinicServicesPage.test.tsx +++ b/assets/admin/pages/ClinicServicesPage.test.tsx @@ -36,6 +36,11 @@ 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: [] }); }); }); @@ -58,4 +63,16 @@ describe('ClinicServicesPage (خدمات)', () => { expect(screen.getByText('سحر رحمانی')).toBeInTheDocument(); expect(screen.getByText('سرویس جدید')).toBeInTheDocument(); }); + + it('embeds per-insurer coverage inline inside the service edit modal', 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(); + }); }); diff --git a/assets/admin/pages/ClinicServicesPage.tsx b/assets/admin/pages/ClinicServicesPage.tsx index 7f34c386..7f68aa37 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 ServiceInsuranceModal from '../components/ServiceInsuranceModal'; +import ServiceInsuranceSection from '../components/ServiceInsuranceSection'; import SearchableSelect from '../components/ui/SearchableSelect'; import FeatureGate from '../components/ui/FeatureGate'; @@ -78,7 +78,6 @@ 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); @@ -360,7 +359,6 @@ function ClinicServicesPageInner() {
-
@@ -574,12 +572,25 @@ function ClinicServicesPageInner() { )}
+ + {/* پوشش بیمه — پیوسته داخل همان مودال، فقط برای سرویس ذخیره‌شده */} + {itemModal !== null && typeof itemModal === 'object' ? ( +
+ +
+ ) : ( +
+ + برای تنظیم پوشش بیمه، ابتدا سرویس را ذخیره کنید و سپس آن را ویرایش کنید. +
+ )}
setTariffItem(null)} /> - setInsuranceItem(null)} /> - {/* Confirm حذف بخش */}