feat(admin): show visit datetime and itemized cost breakdown in session details

DetailsStep now renders the appointment's visit date/time first (from
session_at, falling back to created_at) and an itemized cost table (visit +
each service line with its line total) plus the grand total. Extend
SessionCardData with session_at, services_total_rials, and per-line price
fields already returned by the session API.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
hamed
2026-07-17 11:40:42 +03:30
co-authored by Claude Fable 5
parent 8c39d720b5
commit db7b0aca1a
2 changed files with 41 additions and 3 deletions
@@ -12,8 +12,10 @@ export interface SessionPaymentEntry {
export interface SessionCardData {
uuid: string;
services?: Array<{ service_name?: string; name?: string }>;
services?: Array<{ service_name?: string; name?: string; line_total_rials?: number; price_rials?: number; quantity?: number }>;
visit_price_rials?: number;
services_total_rials?: number;
session_at?: number | null;
doctor_name?: string | null;
final_price_rials?: number;
patient_debt_rials?: number;
@@ -1,5 +1,5 @@
import { toast } from 'sonner';
import { formatRial } from '../../lib/utils';
import { formatRial, formatDateTime } from '../../lib/utils';
import type { SessionCardData } from '../SessionServiceCard';
import { METHOD_LABELS } from './PaymentStep';
import { useIssueInvoice } from '../../hooks/useIssueInvoice';
@@ -34,13 +34,34 @@ export default function DetailsStep({ session, recordUuid, onBack, onFinish }: P
const discountRials = session.discount_rials ?? 0;
const debt = session.patient_debt_rials ?? 0;
const payments = session.payments ?? [];
const visitPrice = session.visit_price_rials ?? 0;
const serviceNames = (session.services ?? []).map((s) => s.service_name || s.name).filter(Boolean) as string[];
if ((session.visit_price_rials ?? 0) > 0) serviceNames.unshift('ویزیت');
if (visitPrice > 0) serviceNames.unshift('ویزیت');
// زمان مراجعه: زمان واقعی نوبت؛ در نبود آن، زمان ثبت پرونده.
const visitAt = session.session_at ?? session.created_at ?? null;
// آیتم‌های هزینه‌ی تفکیک‌شده: ویزیت + هر سرویس، با جمع کل.
const costItems: Array<{ label: string; rials: number }> = [];
if (visitPrice > 0) costItems.push({ label: 'ویزیت', rials: visitPrice });
(session.services ?? []).forEach((s) => {
costItems.push({
label: (s.service_name || s.name) ?? 'سرویس',
rials: s.line_total_rials ?? (s.price_rials ?? 0) * (s.quantity ?? 1),
});
});
return (
<>
{/* گام جزییات — پورت tauri Step3Final با دیتای واقعی */}
<div dir="rtl" className="dark:border-[#404040] dark:bg-[#222433]" style={{ padding: 16, border: '1px dashed #A7A7E0' }}>
{visitAt && (
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 8, marginBottom: 16 }}>
<span className="dark:text-[#A1A1A1]" style={{ fontSize: 13, color: '#616161' }}>تاریخ و ساعت مراجعه:</span>
<span className="dark:text-[#D7D8ED]" style={{ fontSize: 14, fontWeight: 600, color: '#2f2f2f' }}>{formatDateTime(visitAt)}</span>
</div>
)}
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 32, marginBottom: 16 }}>
<span className="dark:text-[#D7D8ED]" style={{ fontSize: 14, fontWeight: 500, color: '#2f2f2f' }}>
{serviceNames.length ? serviceNames.join(' - ') : 'ویزیت'}
@@ -49,6 +70,21 @@ export default function DetailsStep({ session, recordUuid, onBack, onFinish }: P
<span className="dark:text-[#D7D8ED]" style={{ fontSize: 14, fontWeight: 500, color: '#525252' }}>{session.doctor_name || '—'}</span>
</div>
{costItems.length > 0 && (
<div className="dark:border-[#404040]" style={{ marginBottom: 16, borderTop: '1px solid #EEE', borderBottom: '1px solid #EEE', padding: '4px 0' }}>
{costItems.map((it, i) => (
<div key={i} style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', padding: '6px 0' }}>
<span className="dark:text-[#A1A1A1]" style={{ fontSize: 13, color: '#616161' }}>{it.label}</span>
<span className="dark:text-[#D7D8ED]" style={{ fontSize: 14, fontWeight: 500, color: '#525252' }}>{formatRial(it.rials)}</span>
</div>
))}
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', padding: '8px 0 4px', borderTop: '1px dashed #E0E0E0' }}>
<span className="dark:text-[#D7D8ED]" style={{ fontSize: 13, fontWeight: 700, color: '#2f2f2f' }}>جمع کل</span>
<span className="dark:text-[#D7D8ED]" style={{ fontSize: 14, fontWeight: 700, color: '#2f2f2f' }}>{formatRial(finalPrice)}</span>
</div>
</div>
)}
<div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', gap: 72, marginBottom: 16 }}>
<span style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
<span className="dark:text-[#D7D8ED]" style={{ fontSize: 14, fontWeight: 500, color: '#525252' }}>هزینه سرویس:</span>