feat(insurance): edit tenant insurance contracts

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
hamed
2026-06-23 20:32:34 +03:30
co-authored by Claude Opus 4.8
parent 2ef38f082d
commit d049e42ddc
@@ -1,6 +1,6 @@
import { useState } from 'react'; import { useState } from 'react';
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { TrashIcon, PlusIcon } from '@heroicons/react/24/outline'; import { TrashIcon, PlusIcon, PencilIcon } from '@heroicons/react/24/outline';
import { toast } from 'sonner'; import { toast } from 'sonner';
import { api } from '../lib/api'; import { api } from '../lib/api';
import { formatRial } from '../lib/utils'; import { formatRial } from '../lib/utils';
@@ -30,6 +30,7 @@ const KIND_LABEL: Record<string, string> = {
export default function TenantInsuranceContracts() { export default function TenantInsuranceContracts() {
const qc = useQueryClient(); const qc = useQueryClient();
const [addOpen, setAddOpen] = useState(false); const [addOpen, setAddOpen] = useState(false);
const [editUuid, setEditUuid] = useState<string | null>(null);
const [insuranceId, setInsuranceId] = useState(''); const [insuranceId, setInsuranceId] = useState('');
const [coverage, setCoverage] = useState(''); const [coverage, setCoverage] = useState('');
const [franchise, setFranchise] = useState(''); const [franchise, setFranchise] = useState('');
@@ -56,8 +57,33 @@ export default function TenantInsuranceContracts() {
setFranchise(''); setFranchise('');
setCeiling(''); setCeiling('');
setAddOpen(false); setAddOpen(false);
setEditUuid(null);
}; };
const openEdit = (c: Contract) => {
setEditUuid(c.uuid);
setAddOpen(false);
setInsuranceId(String(c.insurance_id));
setCoverage(String(c.coverage_percent ?? ''));
setFranchise(String(c.franchise_rials ?? ''));
setCeiling(c.annual_ceiling_rials != null ? String(c.annual_ceiling_rials) : '');
};
const editMut = useMutation({
mutationFn: () =>
api.patch(`/api/v1/billing/tenant-insurances/${editUuid}`, {
coverage_percent: Number(coverage) || 0,
franchise_rials: Number(franchise) || 0,
annual_ceiling_rials: ceiling === '' ? null : Number(ceiling),
}),
onSuccess: () => {
toast.success('قرارداد بیمه ویرایش شد');
resetForm();
qc.invalidateQueries({ queryKey: ['tenant-insurances'] });
},
onError: (e: Error) => toast.error(e.message),
});
const addMut = useMutation({ const addMut = useMutation({
mutationFn: () => mutationFn: () =>
api.post('/api/v1/billing/tenant-insurances', { api.post('/api/v1/billing/tenant-insurances', {
@@ -99,13 +125,13 @@ export default function TenantInsuranceContracts() {
)} )}
</div> </div>
{addOpen && ( {(addOpen || editUuid) && (
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 10, alignItems: 'flex-end', padding: 14, borderRadius: 10, border: '1px solid var(--border)', background: 'var(--surface)', marginBottom: 14 }}> <div style={{ display: 'flex', flexWrap: 'wrap', gap: 10, alignItems: 'flex-end', padding: 14, borderRadius: 10, border: '1px solid var(--border)', background: 'var(--surface)', marginBottom: 14 }}>
<div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}> <div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
<label style={{ fontSize: 11.5, fontWeight: 600 }}>بیمه</label> <label style={{ fontSize: 11.5, fontWeight: 600 }}>بیمه</label>
<select className="input" style={{ minWidth: 160 }} value={insuranceId} onChange={(e) => setInsuranceId(e.target.value)}> <select className="input" style={{ minWidth: 160 }} value={insuranceId} disabled={!!editUuid} onChange={(e) => setInsuranceId(e.target.value)}>
<option value="">انتخاب...</option> <option value="">انتخاب...</option>
{available.map((i) => ( {(editUuid ? allInsurances : available).map((i) => (
<option key={i.insurance_id} value={i.insurance_id}>{i.insurance_name} ({KIND_LABEL[i.type] ?? i.type})</option> <option key={i.insurance_id} value={i.insurance_id}>{i.insurance_name} ({KIND_LABEL[i.type] ?? i.type})</option>
))} ))}
</select> </select>
@@ -123,8 +149,12 @@ export default function TenantInsuranceContracts() {
<input type="number" min={0} dir="ltr" className="input" style={{ width: 130 }} placeholder="بی‌نهایت" value={ceiling} onChange={(e) => setCeiling(e.target.value)} /> <input type="number" min={0} dir="ltr" className="input" style={{ width: 130 }} placeholder="بی‌نهایت" value={ceiling} onChange={(e) => setCeiling(e.target.value)} />
</div> </div>
<div style={{ display: 'flex', gap: 6 }}> <div style={{ display: 'flex', gap: 6 }}>
<button className="btn primary sm" disabled={!insuranceId || addMut.isPending} onClick={() => addMut.mutate()}> <button
{addMut.isPending ? '...' : 'ذخیره'} className="btn primary sm"
disabled={!insuranceId || addMut.isPending || editMut.isPending}
onClick={() => (editUuid ? editMut.mutate() : addMut.mutate())}
>
{addMut.isPending || editMut.isPending ? '...' : 'ذخیره'}
</button> </button>
<button className="btn ghost sm" onClick={resetForm}>لغو</button> <button className="btn ghost sm" onClick={resetForm}>لغو</button>
</div> </div>
@@ -152,6 +182,9 @@ export default function TenantInsuranceContracts() {
{c.annual_ceiling_rials != null && ` · سقف ${formatRial(c.annual_ceiling_rials)}`} {c.annual_ceiling_rials != null && ` · سقف ${formatRial(c.annual_ceiling_rials)}`}
</div> </div>
</div> </div>
<button className="mini-btn" title="ویرایش" onClick={() => openEdit(c)}>
<PencilIcon style={{ width: 15 }} />
</button>
<button className="mini-btn danger" title="غیرفعال‌سازی" disabled={delMut.isPending} onClick={() => delMut.mutate(c.uuid)}> <button className="mini-btn danger" title="غیرفعال‌سازی" disabled={delMut.isPending} onClick={() => delMut.mutate(c.uuid)}>
<TrashIcon style={{ width: 15 }} /> <TrashIcon style={{ width: 15 }} />
</button> </button>