feat(admin): session edit form, payment edit/delete UI, and audit history modal

- SessionServiceCard menu gains «ویرایش» and «تاریخچه تغییرات» items.
- SessionAuditModal shows the session's change history (field, op badge,
  old->new, actor, time) from /session/{uuid}/audit-log.
- PaymentStep payment rows get edit (modal) + delete (confirm) controls for
  non-wallet payments, calling the new PATCH/DELETE payment endpoints.
- CreateStep accepts an editSession prop (prefill + PATCH); EditSessionPage
  reuses it at /patients/:recordUuid/session/:sessionUuid/edit.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
hamed
2026-07-17 15:23:02 +03:30
co-authored by Claude Fable 5
parent 48579dc06f
commit f2ea2ff262
8 changed files with 287 additions and 12 deletions
+4 -1
View File
@@ -26,6 +26,7 @@ import { useIssueInvoice } from '../hooks/useIssueInvoice';
import AppointmentTurnCard, { type AppointmentCardData } from '../components/AppointmentTurnCard';
import SessionPaymentAccordion, { type SessionPaymentData } from '../components/SessionPaymentAccordion';
import InvoiceSummaryModal from '../components/InvoiceSummaryModal';
import SessionAuditModal from '../components/session/SessionAuditModal';
import SearchableSelect from '../components/ui/SearchableSelect';
import { TurnsFilter, AddTurn } from '../components/icons/FilesToolbarIcons';
import {
@@ -81,6 +82,7 @@ export default function PatientDetailPage() {
const qc = useQueryClient();
const nav = useNavigate();
const [invoiceUuid, setInvoiceUuid] = useState<string | null>(null);
const [auditSessionUuid, setAuditSessionUuid] = useState<string | null>(null);
const [sessionFilter, setSessionFilter] = useState<'active' | 'all' | 'archived'>('active');
// «مشاهده فاکتور»: اگر session هنوز فاکتور ندارد، اول صادر می‌شود (idempotent).
@@ -241,7 +243,7 @@ export default function PatientDetailPage() {
) : (
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(240px, 1fr))', columnGap: 6, rowGap: 10, alignItems: 'stretch' }}>
{sessions.map((s) => (
<SessionServiceCard key={s.uuid} session={s} onSettle={(u) => nav(`/admin/patients/${uuid}/session/${u}/pay`)} onViewInvoice={viewInvoice} onArchive={(sess, archived) => archiveMut.mutate({ sessionUuid: sess.uuid, archived })} issuing={issueInvoiceMut.isPending} />
<SessionServiceCard key={s.uuid} session={s} onSettle={(u) => nav(`/admin/patients/${uuid}/session/${u}/pay`)} onViewInvoice={viewInvoice} onEdit={(sess) => nav(`/admin/patients/${uuid}/session/${sess.uuid}/edit`)} onViewAudit={(sess) => setAuditSessionUuid(sess.uuid)} onArchive={(sess, archived) => archiveMut.mutate({ sessionUuid: sess.uuid, archived })} issuing={issueInvoiceMut.isPending} />
))}
</div>
)}
@@ -265,6 +267,7 @@ export default function PatientDetailPage() {
)}
<InvoiceSummaryModal invoiceUuid={invoiceUuid} onClose={() => setInvoiceUuid(null)} />
<SessionAuditModal sessionUuid={auditSessionUuid} onClose={() => setAuditSessionUuid(null)} />
</div>
);
}