Implement comprehensive dark/light mode overhaul for admin panel
- Refactor color palette in `ui-design-spec.md` to utilize CSS variables exclusively, eliminating fixed hex values and Tailwind utility classes. - Complete dark mode implementation in `uiStore.ts`, ensuring proper theme application via `applyTheme()` and `applyBrand()`. - Create `admin-theme-dark-light-audit.md` to document the transition process, outlining issues with inline styles and fixed colors. - Introduce `theme-tokens.test.ts` to enforce rules against fixed hex colors and ensure compliance with the design system. - Update various components and styles to replace inline styles and fixed colors with CSS variables, ensuring consistent theming across light and dark modes. - Ensure all changes maintain visual integrity in both light and dark modes, with a focus on accessibility and contrast standards.
This commit is contained in:
@@ -38,9 +38,9 @@ const nowHHMM = () => {
|
||||
const toSessionAt = (iso: string, time: string) => Math.floor(new Date(`${iso}T${time || '12:00'}:00`).getTime() / 1000);
|
||||
|
||||
// برچسب فیلد — tauri Step1Details Typography (fontWeight 500, 0.875rem, #6B7280)
|
||||
const fieldLabel: React.CSSProperties = { fontWeight: 500, lineHeight: '130%', fontSize: '0.875rem', marginBottom: 8, color: '#6B7280', display: 'block' };
|
||||
const primaryBtn: React.CSSProperties = { background: '#5559CE', color: '#fff', border: 'none', borderRadius: 4, height: 46, fontSize: 14, fontWeight: 500, cursor: 'pointer' };
|
||||
const ghostBtn: React.CSSProperties = { background: 'transparent', color: '#5559CE', border: '1px solid #5559CE', borderRadius: 4, height: 46, fontSize: 14, fontWeight: 500, cursor: 'pointer' };
|
||||
const fieldLabel: React.CSSProperties = { fontWeight: 500, lineHeight: '130%', fontSize: '0.875rem', marginBottom: 8, color: 'var(--text-2)', display: 'block' };
|
||||
const primaryBtn: React.CSSProperties = { background: 'var(--primary)', color: 'var(--on-primary)', border: 'none', borderRadius: 4, height: 46, fontSize: 14, fontWeight: 500, cursor: 'pointer' };
|
||||
const ghostBtn: React.CSSProperties = { background: 'transparent', color: 'var(--primary)', border: '1px solid var(--primary)', borderRadius: 4, height: 46, fontSize: 14, fontWeight: 500, cursor: 'pointer' };
|
||||
|
||||
interface Props {
|
||||
recordUuid: string;
|
||||
@@ -338,13 +338,13 @@ export default function CreateStep({ recordUuid, profile, onCreated, onCancel, e
|
||||
|
||||
/** ردیف شمارندهی tauri (باکس ۷۴px، +/− نارنجی #FF7A45، سطل روی تعداد ۱) */
|
||||
const counter = (qty: number, set: (q: number) => void) => (
|
||||
<div className="dark:border-[#404040]" style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', width: 74, height: 27, border: '1px solid #d1d1d1', borderRadius: 8, padding: '0 4px', gap: 4 }}>
|
||||
<button type="button" aria-label="افزایش" onClick={() => set(qty + 1)} style={{ border: 'none', background: 'transparent', color: '#FF7A45', cursor: 'pointer', display: 'flex' }}>
|
||||
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', width: 74, height: 27, border: '1px solid var(--border-2)', borderRadius: 8, padding: '0 4px', gap: 4 }}>
|
||||
<button type="button" aria-label="افزایش" onClick={() => set(qty + 1)} style={{ border: 'none', background: 'transparent', color: 'var(--accent)', cursor: 'pointer', display: 'flex' }}>
|
||||
<PlusIcon style={{ width: 16 }} />
|
||||
</button>
|
||||
<span className="dark:text-[#D7D8ED]" style={{ fontSize: 13, color: '#525252', minWidth: 20, textAlign: 'center' }}>{qty}</span>
|
||||
<button type="button" aria-label="کاهش" onClick={() => set(qty - 1)} style={{ border: 'none', background: 'transparent', color: '#FF7A45', cursor: 'pointer', display: 'flex' }}>
|
||||
{qty > 1 ? <MinusIcon style={{ width: 16 }} /> : <TrashRed size={16} color="#f17732" />}
|
||||
<span style={{ fontSize: 13, color: 'var(--text)', minWidth: 20, textAlign: 'center' }}>{qty}</span>
|
||||
<button type="button" aria-label="کاهش" onClick={() => set(qty - 1)} style={{ border: 'none', background: 'transparent', color: 'var(--accent)', cursor: 'pointer', display: 'flex' }}>
|
||||
{qty > 1 ? <MinusIcon style={{ width: 16 }} /> : <TrashRed size={16} color="var(--accent)" />}
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
@@ -353,8 +353,8 @@ export default function CreateStep({ recordUuid, profile, onCreated, onCancel, e
|
||||
<div style={{ marginTop: 16 }}>
|
||||
{/* پذیرش کننده — tauri UserTick + کاربر لاگینشده */}
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 4, marginBottom: 28 }}>
|
||||
<UserTick color="#6B7280" size={18} />
|
||||
<span className="dark:text-[#D7D8ED]" style={{ fontSize: 14, color: '#616161' }}>پذیرش کننده: {userName || '—'}</span>
|
||||
<UserTick color="var(--text-2)" size={18} />
|
||||
<span style={{ fontSize: 14, color: 'var(--text-2)' }}>پذیرش کننده: {userName || '—'}</span>
|
||||
</div>
|
||||
|
||||
{/* تاریخ و ساعت پذیرش */}
|
||||
@@ -365,8 +365,8 @@ export default function CreateStep({ recordUuid, profile, onCreated, onCancel, e
|
||||
</div>
|
||||
<div>
|
||||
<span style={fieldLabel}>ساعت پذیرش</span>
|
||||
<div className="bg-white dark:bg-[#222433] dark:border-[#404040]" style={{ display: 'flex', alignItems: 'center', gap: 8, height: 48, border: '1px solid #e1e1e1', borderRadius: 4, padding: '0 8px' }}>
|
||||
<ClockP color="#6B7280" size={18} />
|
||||
<div className="bg-[var(--surface)]" style={{ display: 'flex', alignItems: 'center', gap: 8, height: 48, border: '1px solid var(--border-2)', borderRadius: 4, padding: '0 8px' }}>
|
||||
<ClockP color="var(--text-2)" size={18} />
|
||||
<input
|
||||
type="time"
|
||||
className="time-input-plain"
|
||||
@@ -392,28 +392,28 @@ export default function CreateStep({ recordUuid, profile, onCreated, onCancel, e
|
||||
<SearchableSelect inputId="service-select" options={itemOptions} value={itemUuid} onChange={v => setItemUuid(v ? String(v) : '')} placeholder="جستجو و انتخاب سرویس..." />
|
||||
</div>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 4, marginTop: 20, flexShrink: 0 }}>
|
||||
<FilesServiceAddCard color="#6B7280" />
|
||||
<span className="dark:text-[#D7D8ED]" style={{ fontSize: 13, color: '#3b3b3b' }}>
|
||||
<FilesServiceAddCard color="var(--text-2)" />
|
||||
<span style={{ fontSize: 13, color: 'var(--text)' }}>
|
||||
قیمت: {currentItem ? formatRial(currentItem.price_rials) : '—'}
|
||||
</span>
|
||||
</div>
|
||||
<button type="button" aria-label="افزودن سرویس" onClick={addService} disabled={!itemUuid} style={{ minWidth: 40, height: 40, borderRadius: 8, background: '#5559CE', border: 'none', cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center', marginTop: 20 }}>
|
||||
<PlusIcon style={{ width: 18, color: '#fff' }} />
|
||||
<button type="button" aria-label="افزودن سرویس" onClick={addService} disabled={!itemUuid} style={{ minWidth: 40, height: 40, borderRadius: 8, background: 'var(--primary)', border: 'none', cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center', marginTop: 20 }}>
|
||||
<PlusIcon style={{ width: 18, color: 'var(--on-primary)' }} />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* خدمات انتخاب شده */}
|
||||
{selectedServices.length > 0 && (
|
||||
<div style={{ border: '1px dashed #C7C9F4', borderRadius: 8, padding: 16, marginBottom: 16 }}>
|
||||
<span className="dark:text-[#D7D8ED]" style={{ fontSize: 13, fontWeight: 600, color: '#525252', display: 'block', marginBottom: 16 }}>خدمات انتخاب شده</span>
|
||||
<div style={{ border: '1px dashed var(--primary-soft2)', borderRadius: 8, padding: 16, marginBottom: 16 }}>
|
||||
<span style={{ fontSize: 13, fontWeight: 600, color: 'var(--text)', display: 'block', marginBottom: 16 }}>خدمات انتخاب شده</span>
|
||||
{selectedServices.map(item => (
|
||||
<div key={item.uuid} style={{ display: 'flex', alignItems: 'center', gap: 24, padding: '8px 0' }}>
|
||||
<span className="dark:text-[#D7D8ED]" style={{ fontSize: 14, color: '#525252', minWidth: 120 }}>{item.name}</span>
|
||||
<span style={{ fontSize: 14, color: 'var(--text)', minWidth: 120 }}>{item.name}</span>
|
||||
{counter(item.qty, (q) => setServiceQty(item.uuid, q))}
|
||||
<span className="dark:text-[#A1A1A1]" style={{ fontSize: 12, fontWeight: 500, color: '#3b3b3b' }}>قیمت: {formatRial(item.price * item.qty)}</span>
|
||||
<span style={{ fontSize: 12, fontWeight: 500, color: 'var(--text)' }}>قیمت: {formatRial(item.price * item.qty)}</span>
|
||||
</div>
|
||||
))}
|
||||
<span className="dark:text-[#D7D8ED]" style={{ fontSize: 13, fontWeight: 600, color: '#525252', display: 'block', marginTop: 16 }}>مجموع قیمت خدمات: {formatRial(servicesTotal)}</span>
|
||||
<span style={{ fontSize: 13, fontWeight: 600, color: 'var(--text)', display: 'block', marginTop: 16 }}>مجموع قیمت خدمات: {formatRial(servicesTotal)}</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -425,36 +425,36 @@ export default function CreateStep({ recordUuid, profile, onCreated, onCancel, e
|
||||
|
||||
{/* انتخاب کالای مصرفی */}
|
||||
<div style={{ marginBottom: 16 }}>
|
||||
<span className="dark:text-[#D7D8ED]" style={{ fontSize: 14, color: '#525252', display: 'block', marginBottom: 8 }}>انتخاب کالای مصرفی</span>
|
||||
<span style={{ fontSize: 14, color: 'var(--text)', display: 'block', marginBottom: 8 }}>انتخاب کالای مصرفی</span>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
|
||||
<div style={{ width: 313, maxWidth: '60%' }}>
|
||||
<SearchableSelect inputId="consumable-select" options={consumableOptions} value={consumableUuid} onChange={v => setConsumableUuid(v ? String(v) : '')} placeholder="انتخاب کنید..." />
|
||||
</div>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 4, flexShrink: 0 }}>
|
||||
<FilesServiceAddCard color="#6B7280" />
|
||||
<span className="dark:text-[#A1A1A1]" style={{ fontSize: 13, color: '#6B7280' }}>
|
||||
<FilesServiceAddCard color="var(--text-2)" />
|
||||
<span style={{ fontSize: 13, color: 'var(--text-2)' }}>
|
||||
قیمت: {currentConsumable ? formatRial(currentConsumable.price) : '—'}
|
||||
</span>
|
||||
</div>
|
||||
<button type="button" aria-label="افزودن کالا" onClick={addConsumable} disabled={!consumableUuid} style={{ minWidth: 40, height: 40, borderRadius: 8, background: '#5559CE', border: 'none', cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
|
||||
<PlusIcon style={{ width: 18, color: '#fff' }} />
|
||||
<button type="button" aria-label="افزودن کالا" onClick={addConsumable} disabled={!consumableUuid} style={{ minWidth: 40, height: 40, borderRadius: 8, background: 'var(--primary)', border: 'none', cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
|
||||
<PlusIcon style={{ width: 18, color: 'var(--on-primary)' }} />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* کالاهای انتخاب شده — باکس خطچین tauri */}
|
||||
<div style={{ border: '1px dashed #C7C9F4', borderRadius: 8, padding: 16, marginBottom: 16 }}>
|
||||
<span className="dark:text-[#D7D8ED]" style={{ fontSize: 13, fontWeight: 600, color: '#525252', display: 'block', marginBottom: 16 }}>کالاهای انتخاب شده</span>
|
||||
<div style={{ border: '1px dashed var(--primary-soft2)', borderRadius: 8, padding: 16, marginBottom: 16 }}>
|
||||
<span style={{ fontSize: 13, fontWeight: 600, color: 'var(--text)', display: 'block', marginBottom: 16 }}>کالاهای انتخاب شده</span>
|
||||
{selectedConsumables.length === 0 ? (
|
||||
<span className="dark:text-[#A1A1A1]" style={{ fontSize: 13, color: '#6B7280' }}>کالایی انتخاب نشده است</span>
|
||||
<span style={{ fontSize: 13, color: 'var(--text-2)' }}>کالایی انتخاب نشده است</span>
|
||||
) : selectedConsumables.map(item => (
|
||||
<div key={item.uuid} style={{ display: 'flex', alignItems: 'center', gap: 24, padding: '8px 0' }}>
|
||||
<span className="dark:text-[#D7D8ED]" style={{ fontSize: 14, color: '#525252', minWidth: 120 }}>{item.name}</span>
|
||||
<span style={{ fontSize: 14, color: 'var(--text)', minWidth: 120 }}>{item.name}</span>
|
||||
{counter(item.qty, (q) => setConsumableQty(item.uuid, q))}
|
||||
<span className="dark:text-[#A1A1A1]" style={{ fontSize: 12, fontWeight: 500, color: '#3b3b3b' }}>قیمت: {formatRial(item.price * item.qty)}</span>
|
||||
<span style={{ fontSize: 12, fontWeight: 500, color: 'var(--text)' }}>قیمت: {formatRial(item.price * item.qty)}</span>
|
||||
</div>
|
||||
))}
|
||||
<span className="dark:text-[#D7D8ED]" style={{ fontSize: 13, fontWeight: 600, color: '#525252', display: 'block', marginTop: 16 }}>مجموع قیمت کالاها: {formatRial(consumablesTotal)}</span>
|
||||
<span style={{ fontSize: 13, fontWeight: 600, color: 'var(--text)', display: 'block', marginTop: 16 }}>مجموع قیمت کالاها: {formatRial(consumablesTotal)}</span>
|
||||
</div>
|
||||
|
||||
{/* انتخاب پکیج */}
|
||||
@@ -527,7 +527,7 @@ export default function CreateStep({ recordUuid, profile, onCreated, onCancel, e
|
||||
</div>
|
||||
|
||||
{/* خلاصه مبلغ */}
|
||||
<div className="dark:border-[#404040]" style={{ borderTop: '1px solid var(--border)', paddingTop: 12, marginBottom: 16, display: 'flex', flexDirection: 'column', gap: 6 }}>
|
||||
<div style={{ borderTop: '1px solid var(--border)', paddingTop: 12, marginBottom: 16, display: 'flex', flexDirection: 'column', gap: 6 }}>
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 13, color: 'var(--text-3)' }}><span>ویزیت</span><span>{formatRial(afterSupp)}</span></div>
|
||||
{servicesTotal > 0 && <div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 13, color: 'var(--text-3)' }}><span>سهم بیمار خدمات</span><span>{formatRial(servicesPatient)}</span></div>}
|
||||
{consumablesTotal > 0 && <div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 13, color: 'var(--text-3)' }}><span>کالاهای مصرفی</span><span>{formatRial(consumablesTotal)}</span></div>}
|
||||
|
||||
@@ -4,8 +4,8 @@ import type { SessionCardData } from '../SessionServiceCard';
|
||||
import { METHOD_LABELS } from './PaymentStep';
|
||||
import { useIssueInvoice } from '../../hooks/useIssueInvoice';
|
||||
|
||||
const primaryBtn: React.CSSProperties = { background: '#5559CE', color: '#fff', border: 'none', borderRadius: 4, height: 46, fontSize: 14, fontWeight: 500, cursor: 'pointer' };
|
||||
const ghostBtn: React.CSSProperties = { background: 'transparent', color: '#5559CE', border: '1px solid #5559CE', borderRadius: 4, height: 46, fontSize: 14, fontWeight: 500, cursor: 'pointer' };
|
||||
const primaryBtn: React.CSSProperties = { background: 'var(--primary)', color: 'var(--on-primary)', border: 'none', borderRadius: 4, height: 46, fontSize: 14, fontWeight: 500, cursor: 'pointer' };
|
||||
const ghostBtn: React.CSSProperties = { background: 'transparent', color: 'var(--primary)', border: '1px solid var(--primary)', borderRadius: 4, height: 46, fontSize: 14, fontWeight: 500, cursor: 'pointer' };
|
||||
|
||||
interface Props {
|
||||
session: SessionCardData;
|
||||
@@ -69,82 +69,82 @@ export default function DetailsStep({ session, recordUuid, onBack, onFinish }: P
|
||||
return (
|
||||
<>
|
||||
{/* گام جزییات — پورت tauri Step3Final با دیتای واقعی */}
|
||||
<div dir="rtl" className="dark:border-[#404040] dark:bg-[#222433]" style={{ padding: 16, border: '1px dashed #A7A7E0' }}>
|
||||
<div dir="rtl" className="dark:bg-[var(--surface)]" style={{ padding: 16, border: '1px dashed var(--primary-soft2)' }}>
|
||||
{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>
|
||||
<span style={{ fontSize: 13, color: 'var(--text-2)' }}>تاریخ و ساعت مراجعه:</span>
|
||||
<span style={{ fontSize: 14, fontWeight: 600, color: 'var(--text)' }}>{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' }}>
|
||||
<span style={{ fontSize: 14, fontWeight: 500, color: 'var(--text)' }}>
|
||||
{serviceNames.length ? serviceNames.join(' - ') : 'ویزیت'}
|
||||
</span>
|
||||
<span className="dark:bg-[#404040]" style={{ width: 1, height: 38, background: '#E0E0E0' }} />
|
||||
<span className="dark:text-[#D7D8ED]" style={{ fontSize: 14, fontWeight: 500, color: '#525252' }}>{session.doctor_name || '—'}</span>
|
||||
<span style={{ width: 1, height: 38, background: 'var(--border-2)' }} />
|
||||
<span style={{ fontSize: 14, fontWeight: 500, color: 'var(--text)' }}>{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' }}>
|
||||
<div style={{ marginBottom: 16, borderTop: '1px solid var(--border)', borderBottom: '1px solid var(--border)', 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>
|
||||
<span style={{ fontSize: 13, color: 'var(--text-2)' }}>{it.label}</span>
|
||||
<span style={{ fontSize: 14, fontWeight: 500, color: 'var(--text)' }}>{formatRial(it.rials)}</span>
|
||||
</div>
|
||||
))}
|
||||
{hasInsurance && (
|
||||
<>
|
||||
<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(grossTotal)}</span>
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', padding: '8px 0 4px', borderTop: '1px dashed var(--border-2)' }}>
|
||||
<span style={{ fontSize: 13, fontWeight: 700, color: 'var(--text)' }}>جمع کل خدمات</span>
|
||||
<span style={{ fontSize: 14, fontWeight: 700, color: 'var(--text)' }}>{formatRial(grossTotal)}</span>
|
||||
</div>
|
||||
{baseInsurance > 0 && (
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', padding: '6px 0' }}>
|
||||
<span className="dark:text-[#A1A1A1]" style={{ fontSize: 13, color: '#616161' }}>سهم بیمه پایه</span>
|
||||
<span style={{ fontSize: 14, fontWeight: 500, color: '#2E7D32' }}>{formatRial(baseInsurance)}</span>
|
||||
<span style={{ fontSize: 13, color: 'var(--text-2)' }}>سهم بیمه پایه</span>
|
||||
<span style={{ fontSize: 14, fontWeight: 500, color: 'var(--success)' }}>{formatRial(baseInsurance)}</span>
|
||||
</div>
|
||||
)}
|
||||
{suppInsurance > 0 && (
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', padding: '6px 0' }}>
|
||||
<span className="dark:text-[#A1A1A1]" style={{ fontSize: 13, color: '#616161' }}>سهم بیمه تکمیلی</span>
|
||||
<span style={{ fontSize: 14, fontWeight: 500, color: '#2E7D32' }}>{formatRial(suppInsurance)}</span>
|
||||
<span style={{ fontSize: 13, color: 'var(--text-2)' }}>سهم بیمه تکمیلی</span>
|
||||
<span style={{ fontSize: 14, fontWeight: 500, color: 'var(--success)' }}>{formatRial(suppInsurance)}</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' }}>{hasInsurance ? 'سهم بیمار' : 'جمع کل'}</span>
|
||||
<span className="dark:text-[#D7D8ED]" style={{ fontSize: 14, fontWeight: 700, color: '#2f2f2f' }}>{formatRial(finalPrice)}</span>
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', padding: '8px 0 4px', borderTop: '1px dashed var(--border-2)' }}>
|
||||
<span style={{ fontSize: 13, fontWeight: 700, color: 'var(--text)' }}>{hasInsurance ? 'سهم بیمار' : 'جمع کل'}</span>
|
||||
<span style={{ fontSize: 14, fontWeight: 700, color: 'var(--text)' }}>{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>
|
||||
<span className="dark:text-[#D7D8ED]" style={{ fontSize: 14, fontWeight: 500, color: '#525252' }}>{formatRial(finalPrice)}</span>
|
||||
<span style={{ fontSize: 14, fontWeight: 500, color: 'var(--text)' }}>هزینه سرویس:</span>
|
||||
<span style={{ fontSize: 14, fontWeight: 500, color: 'var(--text)' }}>{formatRial(finalPrice)}</span>
|
||||
</span>
|
||||
<span className="dark:bg-[#404040]" style={{ width: 1, height: 38, background: '#E0E0E0' }} />
|
||||
<span style={{ width: 1, height: 38, background: 'var(--border-2)' }} />
|
||||
<span style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
|
||||
<span className="dark:text-[#D7D8ED]" style={{ fontSize: 14, fontWeight: 500, color: '#525252' }}>تخفیف:</span>
|
||||
<span className="dark:text-[#D7D8ED]" style={{ fontSize: 14, fontWeight: 500, color: '#525252' }}>{formatRial(discountRials)}</span>
|
||||
<span style={{ fontSize: 14, fontWeight: 500, color: 'var(--text)' }}>تخفیف:</span>
|
||||
<span style={{ fontSize: 14, fontWeight: 500, color: 'var(--text)' }}>{formatRial(discountRials)}</span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<span className="dark:text-[#6A6AD9]" style={{ fontSize: 13, fontWeight: 600, color: '#5559CE', display: 'block', marginBottom: 12 }}>پرداخت شده ها:</span>
|
||||
<span style={{ fontSize: 13, fontWeight: 600, color: 'var(--primary)', display: 'block', marginBottom: 12 }}>پرداخت شده ها:</span>
|
||||
{payments.length === 0 ? (
|
||||
<span className="dark:text-[#A1A1A1]" style={{ fontSize: 13, color: '#6B7280' }}>پرداختی ثبت نشده است</span>
|
||||
<span style={{ fontSize: 13, color: 'var(--text-2)' }}>پرداختی ثبت نشده است</span>
|
||||
) : payments.map((p) => (
|
||||
<div key={p.uuid} className="dark:border-[#404040]" style={{ padding: '8px 0', borderBottom: '1px solid #EEE' }}>
|
||||
<div key={p.uuid} style={{ padding: '8px 0', borderBottom: '1px solid var(--border)' }}>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 56 }}>
|
||||
<span style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
|
||||
<span className="dark:bg-[#6A6AD9]" style={{ width: 6, height: 6, borderRadius: '50%', background: '#5559CE', flexShrink: 0 }} />
|
||||
<span className="dark:text-[#D7D8ED]" style={{ fontSize: 14, fontWeight: 600, color: '#525252' }}>{METHOD_LABELS[p.method] ?? p.method}</span>
|
||||
<span style={{ width: 6, height: 6, borderRadius: '50%', background: 'var(--primary)', flexShrink: 0 }} />
|
||||
<span style={{ fontSize: 14, fontWeight: 600, color: 'var(--text)' }}>{METHOD_LABELS[p.method] ?? p.method}</span>
|
||||
</span>
|
||||
<span className="dark:text-[#D7D8ED]" style={{ fontSize: 14, fontWeight: 600, color: '#111827' }}>مبلغ: {formatRial(p.amount_rials)}</span>
|
||||
<span style={{ fontSize: 14, fontWeight: 600, color: 'var(--text)' }}>مبلغ: {formatRial(p.amount_rials)}</span>
|
||||
</div>
|
||||
<div className="dark:text-[#A1A1A1]" style={{ display: 'flex', gap: 12, marginTop: 4, fontSize: 12, color: '#9CA3AF', flexWrap: 'wrap' }}>
|
||||
<div style={{ display: 'flex', gap: 12, marginTop: 4, fontSize: 12, color: 'var(--text-3)', flexWrap: 'wrap' }}>
|
||||
{(p.paid_at ?? p.created_at) && <span>{formatDateTime(p.paid_at ?? p.created_at!)}</span>}
|
||||
{p.created_by_name && <span>ثبت: {p.created_by_name}</span>}
|
||||
</div>
|
||||
@@ -153,8 +153,8 @@ export default function DetailsStep({ session, recordUuid, onBack, onFinish }: P
|
||||
|
||||
<div style={{ display: 'flex', width: '100%', justifyContent: 'flex-end', alignItems: 'center' }}>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 8, marginTop: 16 }}>
|
||||
<span className="dark:text-[#D7D8ED]" style={{ fontSize: 14, fontWeight: 600, color: '#525252' }}>مبلغ باقی مانده:</span>
|
||||
<span className="dark:text-[#FF5252]" style={{ fontSize: 14, fontWeight: 600, color: '#d32f2f' }}>{formatRial(debt)}</span>
|
||||
<span style={{ fontSize: 14, fontWeight: 600, color: 'var(--text)' }}>مبلغ باقی مانده:</span>
|
||||
<span style={{ fontSize: 14, fontWeight: 600, color: 'var(--danger)' }}>{formatRial(debt)}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -30,9 +30,9 @@ const todayISO = () => new Date().toISOString().slice(0, 10);
|
||||
/** YYYY-MM-DD → unix (ظهر همان روز تا با هر timezone یک روز بماند) */
|
||||
const isoToUnix = (iso: string) => Math.floor(new Date(`${iso}T12:00:00`).getTime() / 1000);
|
||||
|
||||
const fieldLabel: React.CSSProperties = { fontSize: 14, color: '#6B7280', marginBottom: 8, display: 'block' };
|
||||
const primaryBtn: React.CSSProperties = { background: '#5559CE', color: '#fff', border: 'none', borderRadius: 4, height: 46, fontSize: 14, fontWeight: 500, cursor: 'pointer' };
|
||||
const ghostBtn: React.CSSProperties = { background: 'transparent', color: '#5559CE', border: '1px solid #5559CE', borderRadius: 4, height: 46, fontSize: 14, fontWeight: 500, cursor: 'pointer' };
|
||||
const fieldLabel: React.CSSProperties = { fontSize: 14, color: 'var(--text-2)', marginBottom: 8, display: 'block' };
|
||||
const primaryBtn: React.CSSProperties = { background: 'var(--primary)', color: 'var(--on-primary)', border: 'none', borderRadius: 4, height: 46, fontSize: 14, fontWeight: 500, cursor: 'pointer' };
|
||||
const ghostBtn: React.CSSProperties = { background: 'transparent', color: 'var(--primary)', border: '1px solid var(--primary)', borderRadius: 4, height: 46, fontSize: 14, fontWeight: 500, cursor: 'pointer' };
|
||||
|
||||
interface Props {
|
||||
recordUuid: string;
|
||||
@@ -146,26 +146,26 @@ export default function PaymentStep({ recordUuid, session, walletBalance, onCont
|
||||
{/* هزینه سرویس */}
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 12, margin: '12px 0 16px' }}>
|
||||
<Step2PaymentCard />
|
||||
<span style={{ fontSize: 14, color: '#F97316', fontWeight: 700 }}>هزینه سرویس:</span>
|
||||
<span className="dark:text-[#D7D8ED]" style={{ fontSize: 14, fontWeight: 700, color: '#525252' }}>{formatRial(finalPrice)}</span>
|
||||
<span style={{ fontSize: 14, color: 'var(--accent)', fontWeight: 700 }}>هزینه سرویس:</span>
|
||||
<span style={{ fontSize: 14, fontWeight: 700, color: 'var(--text)' }}>{formatRial(finalPrice)}</span>
|
||||
</div>
|
||||
|
||||
{/* تخفیفهای پیشنهادی (قوانین تخفیف) */}
|
||||
{suggestions.length > 0 && (
|
||||
<div className="dark:border-[#35343D]" style={{ border: '1px solid #E8EBFF', background: '#F7F8FF', borderRadius: 8, padding: 12, marginBottom: 16 }}>
|
||||
<span style={{ ...fieldLabel, marginBottom: 10, fontWeight: 600, color: '#3B3F9F' }}>تخفیفهای قابل اعمال:</span>
|
||||
<div style={{ border: '1px solid var(--primary-soft2)', background: 'var(--primary-soft)', borderRadius: 8, padding: 12, marginBottom: 16 }}>
|
||||
<span style={{ ...fieldLabel, marginBottom: 10, fontWeight: 600, color: 'var(--primary-700)' }}>تخفیفهای قابل اعمال:</span>
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
|
||||
{suggestions.map((s) => (
|
||||
<div key={s.rule_uuid} style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 8 }}>
|
||||
<span className="dark:text-[#D7D8ED]" style={{ fontSize: 13, color: '#374151' }}>
|
||||
{s.rule_name} — <span style={{ color: '#D32F2F' }}>{formatRial(s.discount_rials)}</span>
|
||||
{' '}<span style={{ color: '#6B7280', fontSize: 12 }}>({s.discount_type === 'percent' ? `${s.value}٪` : 'مبلغ ثابت'})</span>
|
||||
<span style={{ fontSize: 13, color: 'var(--text)' }}>
|
||||
{s.rule_name} — <span style={{ color: 'var(--danger)' }}>{formatRial(s.discount_rials)}</span>
|
||||
{' '}<span style={{ color: 'var(--text-2)', fontSize: 12 }}>({s.discount_type === 'percent' ? `${s.value}٪` : 'مبلغ ثابت'})</span>
|
||||
</span>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => applyRule(s.rule_uuid)}
|
||||
disabled={discountMut.isPending}
|
||||
style={{ height: 32, minWidth: 64, border: 'none', borderRadius: 6, background: '#5559CE', color: '#fff', fontSize: 12.5, fontWeight: 600, cursor: 'pointer' }}
|
||||
style={{ height: 32, minWidth: 64, border: 'none', borderRadius: 6, background: 'var(--primary)', color: 'var(--on-primary)', fontSize: 12.5, fontWeight: 600, cursor: 'pointer' }}
|
||||
>
|
||||
اعمال
|
||||
</button>
|
||||
@@ -178,8 +178,8 @@ export default function PaymentStep({ recordUuid, session, walletBalance, onCont
|
||||
{/* تخفیف — port of tauri DiscountInput (نوع + مقدار + ثبت) */}
|
||||
<span style={fieldLabel}>تخفیف:</span>
|
||||
<div style={{ display: 'flex', alignItems: 'stretch', gap: 8 }}>
|
||||
<div className="bg-white dark:bg-[#222433] dark:border-[#35343D]" style={{ flex: 1, minWidth: 0, display: 'flex', alignItems: 'center', border: '1px solid #e0e0e0', borderRadius: 8, marginBottom: 16 }}>
|
||||
<div style={{ minWidth: 150, borderLeft: '1px solid #e0e0e0', padding: '0 4px' }}>
|
||||
<div className="bg-[var(--surface)]" style={{ flex: 1, minWidth: 0, display: 'flex', alignItems: 'center', border: '1px solid var(--border-2)', borderRadius: 8, marginBottom: 16 }}>
|
||||
<div style={{ minWidth: 150, borderLeft: '1px solid var(--border-2)', padding: '0 4px' }}>
|
||||
<SearchableSelect
|
||||
options={[{ value: 'percent', label: 'درصدی' }, { value: 'fixed', label: 'مبلغ ثابت' }]}
|
||||
value={discountType}
|
||||
@@ -198,7 +198,7 @@ export default function PaymentStep({ recordUuid, session, walletBalance, onCont
|
||||
type="button"
|
||||
onClick={applyDiscount}
|
||||
disabled={discountMut.isPending || !discountType || discountValue <= 0}
|
||||
style={{ height: 40, minWidth: 72, border: 'none', borderRadius: '0 4px 4px 0', background: '#E8EBFF', color: '#3B3F9F', fontSize: 13, fontWeight: 600, cursor: 'pointer' }}
|
||||
style={{ height: 40, minWidth: 72, border: 'none', borderRadius: '0 4px 4px 0', background: 'var(--primary-soft2)', color: 'var(--primary-700)', fontSize: 13, fontWeight: 600, cursor: 'pointer' }}
|
||||
>
|
||||
ثبت
|
||||
</button>
|
||||
@@ -207,64 +207,64 @@ export default function PaymentStep({ recordUuid, session, walletBalance, onCont
|
||||
onClick={removeDiscount}
|
||||
style={{ display: 'flex', alignItems: 'center', gap: 4, flexShrink: 0, cursor: 'pointer', marginBottom: 16, minWidth: 120, justifyContent: 'center' }}
|
||||
>
|
||||
<TrashRed color="#EF4444" size={18} />
|
||||
<span className="dark:text-[#A1A1A1]" style={{ fontSize: 13, color: '#6B7280' }}>حذف تخفیف</span>
|
||||
<TrashRed color="var(--danger)" size={18} />
|
||||
<span style={{ fontSize: 13, color: 'var(--text-2)' }}>حذف تخفیف</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* خلاصهی مبلغ: قبل از تخفیف / تخفیف / نهایی / منبع */}
|
||||
<div className="dark:border-[#35343D]" style={{ border: '1px solid #e0e0e0', borderRadius: 8, padding: 12, marginBottom: 16, display: 'flex', flexDirection: 'column', gap: 6 }}>
|
||||
<div style={{ border: '1px solid var(--border-2)', borderRadius: 8, padding: 12, marginBottom: 16, display: 'flex', flexDirection: 'column', gap: 6 }}>
|
||||
{hasInsurance && (
|
||||
<>
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 13 }}>
|
||||
<span className="dark:text-[#A1A1A1]" style={{ color: '#6B7280' }}>هزینه کل خدمات:</span>
|
||||
<span className="dark:text-[#D7D8ED]" style={{ color: '#2f2f2f' }}>{formatRial(grossTotal)}</span>
|
||||
<span style={{ color: 'var(--text-2)' }}>هزینه کل خدمات:</span>
|
||||
<span style={{ color: 'var(--text)' }}>{formatRial(grossTotal)}</span>
|
||||
</div>
|
||||
{baseInsurance > 0 && (
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 13 }}>
|
||||
<span className="dark:text-[#A1A1A1]" style={{ color: '#6B7280' }}>سهم بیمه پایه:</span>
|
||||
<span style={{ color: '#2E7D32' }}>{formatRial(baseInsurance)}</span>
|
||||
<span style={{ color: 'var(--text-2)' }}>سهم بیمه پایه:</span>
|
||||
<span style={{ color: 'var(--success)' }}>{formatRial(baseInsurance)}</span>
|
||||
</div>
|
||||
)}
|
||||
{suppInsurance > 0 && (
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 13 }}>
|
||||
<span className="dark:text-[#A1A1A1]" style={{ color: '#6B7280' }}>سهم بیمه تکمیلی:</span>
|
||||
<span style={{ color: '#2E7D32' }}>{formatRial(suppInsurance)}</span>
|
||||
<span style={{ color: 'var(--text-2)' }}>سهم بیمه تکمیلی:</span>
|
||||
<span style={{ color: 'var(--success)' }}>{formatRial(suppInsurance)}</span>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 13 }}>
|
||||
<span className="dark:text-[#A1A1A1]" style={{ color: '#6B7280' }}>{hasInsurance ? 'سهم بیمار:' : 'مبلغ قبل از تخفیف:'}</span>
|
||||
<span className="dark:text-[#D7D8ED]" style={{ color: '#2f2f2f' }}>{formatRial(finalPrice)}</span>
|
||||
<span style={{ color: 'var(--text-2)' }}>{hasInsurance ? 'سهم بیمار:' : 'مبلغ قبل از تخفیف:'}</span>
|
||||
<span style={{ color: 'var(--text)' }}>{formatRial(finalPrice)}</span>
|
||||
</div>
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 13 }}>
|
||||
<span className="dark:text-[#A1A1A1]" style={{ color: '#6B7280' }}>مبلغ تخفیف{appliedRuleLabel ? ` (${appliedRuleLabel})` : ''}:</span>
|
||||
<span style={{ color: '#D32F2F' }}>{formatRial(discountRials)}</span>
|
||||
<span style={{ color: 'var(--text-2)' }}>مبلغ تخفیف{appliedRuleLabel ? ` (${appliedRuleLabel})` : ''}:</span>
|
||||
<span style={{ color: 'var(--danger)' }}>{formatRial(discountRials)}</span>
|
||||
</div>
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 13, fontWeight: 700, borderTop: '1px dashed #e0e0e0', paddingTop: 6 }}>
|
||||
<span className="dark:text-[#D7D8ED]" style={{ color: '#2f2f2f' }}>مبلغ نهایی قابل پرداخت:</span>
|
||||
<span className="dark:text-[#D7D8ED]" style={{ color: '#2f2f2f' }}>{formatRial(payable)}</span>
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 13, fontWeight: 700, borderTop: '1px dashed var(--border-2)', paddingTop: 6 }}>
|
||||
<span style={{ color: 'var(--text)' }}>مبلغ نهایی قابل پرداخت:</span>
|
||||
<span style={{ color: 'var(--text)' }}>{formatRial(payable)}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* تاریخ پرداخت */}
|
||||
<span className="dark:text-[#A1A1A1]" style={{ ...fieldLabel, color: '#3b3b3b' }}>تاریخ پرداخت</span>
|
||||
<span style={{ ...fieldLabel, color: 'var(--text)' }}>تاریخ پرداخت</span>
|
||||
<PersianDateInput value={paymentDate} onChange={setPaymentDate} />
|
||||
|
||||
{/* روشهای پرداخت */}
|
||||
<span className="dark:text-[#A1A1A1]" style={{ ...fieldLabel, color: '#3b3b3b', marginTop: 24 }}>انتخاب روش های پرداخت:</span>
|
||||
<span style={{ ...fieldLabel, color: 'var(--text)', marginTop: 24 }}>انتخاب روش های پرداخت:</span>
|
||||
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 8, flexWrap: 'wrap' }}>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
|
||||
<div style={{ display: 'flex', gap: 4 }}>
|
||||
<FilesServiceBalanceWallet />
|
||||
<span style={{ fontSize: 14, color: '#F97316', marginBottom: 8, fontWeight: 600 }}>موجودی کیف پول:</span>
|
||||
<span style={{ fontSize: 14, color: 'var(--accent)', marginBottom: 8, fontWeight: 600 }}>موجودی کیف پول:</span>
|
||||
</div>
|
||||
<span className="dark:text-[#D7D8ED]" style={{ fontSize: 14, fontWeight: 600, color: '#525252', marginBottom: 4 }}>{formatRial(walletBalance)}</span>
|
||||
<span style={{ fontSize: 14, fontWeight: 600, color: 'var(--text)', marginBottom: 4 }}>{formatRial(walletBalance)}</span>
|
||||
</div>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 6, marginBottom: 4 }}>
|
||||
<span style={{ fontSize: 14, fontWeight: 600, color: '#111827' }}>مبلغ باقیمانده:</span>
|
||||
<span className="dark:text-[#FF5252]" style={{ fontSize: 14, fontWeight: 700, color: '#d32f2f' }}>{formatRial(debt)}</span>
|
||||
<span style={{ fontSize: 14, fontWeight: 600, color: 'var(--text)' }}>مبلغ باقیمانده:</span>
|
||||
<span style={{ fontSize: 14, fontWeight: 700, color: 'var(--danger)' }}>{formatRial(debt)}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -273,15 +273,15 @@ export default function PaymentStep({ recordUuid, session, walletBalance, onCont
|
||||
{METHODS.map((m) => {
|
||||
const open = expanded === m.key;
|
||||
return (
|
||||
<div key={m.key} className="dark:border-[#35343D]" style={{ borderBottom: '1px solid #e0e0e0' }}>
|
||||
<div key={m.key} style={{ borderBottom: '1px solid var(--border-2)' }}>
|
||||
<button
|
||||
type="button"
|
||||
aria-expanded={open}
|
||||
onClick={() => { setExpanded(open ? null : m.key); setAmount(open ? 0 : defaultAmountFor(m.key)); }}
|
||||
style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', width: '100%', padding: '14px 4px', background: 'transparent', border: 'none', cursor: 'pointer' }}
|
||||
>
|
||||
<span className="dark:text-[#D7D8ED]" style={{ fontSize: 14, fontWeight: 600, color: '#111827' }}>{m.label}</span>
|
||||
<ChevronDownIcon style={{ width: 16, color: '#6B7280', transform: open ? 'rotate(180deg)' : undefined, transition: 'transform .15s' }} />
|
||||
<span style={{ fontSize: 14, fontWeight: 600, color: 'var(--text)' }}>{m.label}</span>
|
||||
<ChevronDownIcon style={{ width: 16, color: 'var(--text-2)', transform: open ? 'rotate(180deg)' : undefined, transition: 'transform .15s' }} />
|
||||
</button>
|
||||
{open && (
|
||||
<div style={{ display: 'flex', gap: 8, padding: '0 4px 14px' }}>
|
||||
@@ -309,34 +309,34 @@ export default function PaymentStep({ recordUuid, session, walletBalance, onCont
|
||||
</div>
|
||||
|
||||
{/* پرداخت شدهها — باکس خطچین tauri */}
|
||||
<div className="dark:border-[#404040] dark:bg-[#222433]" style={{ border: '1px dashed #C7C9F4', borderRadius: 8, padding: 16, marginTop: 16, background: '#fff' }}>
|
||||
<span className="dark:text-[#6A6AD9]" style={{ fontSize: 16, fontWeight: 500, color: '#636bd4', display: 'block', marginBottom: 16 }}>پرداخت شده ها:</span>
|
||||
<div style={{ border: '1px dashed var(--primary-soft2)', borderRadius: 8, padding: 16, marginTop: 16, background: 'var(--surface)' }}>
|
||||
<span style={{ fontSize: 16, fontWeight: 500, color: 'var(--primary)', display: 'block', marginBottom: 16 }}>پرداخت شده ها:</span>
|
||||
{payments.length === 0 ? (
|
||||
<span className="dark:text-[#A1A1A1]" style={{ fontSize: 13, color: '#6B7280' }}>پرداختی ثبت نشده است</span>
|
||||
<span style={{ fontSize: 13, color: 'var(--text-2)' }}>پرداختی ثبت نشده است</span>
|
||||
) : (
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
|
||||
{payments.map((p) => (
|
||||
<div key={p.uuid} className="dark:border-[#404040]" style={{ padding: '6px 0', borderBottom: '1px solid #e0e0e0' }}>
|
||||
<div key={p.uuid} style={{ padding: '6px 0', borderBottom: '1px solid var(--border-2)' }}>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 16 }}>
|
||||
<span style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
|
||||
<span className="dark:bg-[#6A6AD9]" style={{ width: 8, height: 8, borderRadius: '50%', background: '#636bd4' }} />
|
||||
<span className="dark:text-[#D7D8ED]" style={{ fontSize: 14, color: '#111827' }}>{METHOD_LABELS[p.method] ?? p.method}</span>
|
||||
<span style={{ width: 8, height: 8, borderRadius: '50%', background: 'var(--primary)' }} />
|
||||
<span style={{ fontSize: 14, color: 'var(--text)' }}>{METHOD_LABELS[p.method] ?? p.method}</span>
|
||||
</span>
|
||||
<span className="dark:text-[#D7D8ED]" style={{ flex: 1, textAlign: 'left', fontSize: 14, color: '#111827' }}>مبلغ : {formatRial(p.amount_rials)}</span>
|
||||
<span style={{ flex: 1, textAlign: 'left', fontSize: 14, color: 'var(--text)' }}>مبلغ : {formatRial(p.amount_rials)}</span>
|
||||
{p.method !== 'wallet' && (
|
||||
<span style={{ display: 'flex', gap: 6, flexShrink: 0 }}>
|
||||
<button type="button" aria-label="ویرایش پرداخت" onClick={() => setEditPay({ uuid: p.uuid, method: p.method, amountToman: rialToToman(p.amount_rials) })}
|
||||
style={{ border: 'none', background: 'transparent', cursor: 'pointer', color: '#5559ce', display: 'flex' }}>
|
||||
style={{ border: 'none', background: 'transparent', cursor: 'pointer', color: 'var(--primary)', display: 'flex' }}>
|
||||
<PencilIcon style={{ width: 16 }} />
|
||||
</button>
|
||||
<button type="button" aria-label="حذف پرداخت" onClick={() => setDelPayUuid(p.uuid)}
|
||||
style={{ border: 'none', background: 'transparent', cursor: 'pointer', color: '#EF4444', display: 'flex' }}>
|
||||
style={{ border: 'none', background: 'transparent', cursor: 'pointer', color: 'var(--danger)', display: 'flex' }}>
|
||||
<TrashIcon style={{ width: 16 }} />
|
||||
</button>
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<div className="dark:text-[#A1A1A1]" style={{ display: 'flex', gap: 12, marginTop: 4, fontSize: 12, color: '#9CA3AF', flexWrap: 'wrap' }}>
|
||||
<div style={{ display: 'flex', gap: 12, marginTop: 4, fontSize: 12, color: 'var(--text-3)', flexWrap: 'wrap' }}>
|
||||
{(p.paid_at ?? p.created_at) && <span>{formatDateTime(p.paid_at ?? p.created_at!)}</span>}
|
||||
{p.created_by_name && <span>ثبت: {p.created_by_name}</span>}
|
||||
</div>
|
||||
@@ -345,8 +345,8 @@ export default function PaymentStep({ recordUuid, session, walletBalance, onCont
|
||||
</div>
|
||||
)}
|
||||
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'flex-end', gap: 8, marginTop: 16 }}>
|
||||
<span className="dark:text-[#D7D8ED]" style={{ fontSize: 14, fontWeight: 500, color: '#111827' }}>مبلغ باقیمانده :</span>
|
||||
<span className="dark:text-[#FF5252]" style={{ fontSize: 14, fontWeight: 600, color: '#d32f2f' }}>{formatRial(debt)}</span>
|
||||
<span style={{ fontSize: 14, fontWeight: 500, color: 'var(--text)' }}>مبلغ باقیمانده :</span>
|
||||
<span style={{ fontSize: 14, fontWeight: 600, color: 'var(--danger)' }}>{formatRial(debt)}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -16,9 +16,9 @@ const FIELD_LABELS: Record<string, string> = {
|
||||
};
|
||||
|
||||
const OP_LABELS: Record<string, { label: string; color: string }> = {
|
||||
create: { label: 'ایجاد', color: '#3c9a4f' },
|
||||
update: { label: 'ویرایش', color: '#5559ce' },
|
||||
delete: { label: 'حذف', color: '#EF4444' },
|
||||
create: { label: 'ایجاد', color: 'var(--success)' },
|
||||
update: { label: 'ویرایش', color: 'var(--primary)' },
|
||||
delete: { label: 'حذف', color: 'var(--danger)' },
|
||||
};
|
||||
|
||||
// مقادیر پولی (ریال) را با فرمت تومان نشان بده؛ بقیه را خام.
|
||||
@@ -53,7 +53,7 @@ export default function SessionAuditModal({ sessionUuid, onClose }: { sessionUui
|
||||
<div key={i} className="card" style={{ padding: 12, display: 'flex', flexDirection: 'column', gap: 6 }}>
|
||||
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 8 }}>
|
||||
<span style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
|
||||
<span className="badge" style={{ fontSize: 11, color: '#fff', background: op.color, borderRadius: 4, padding: '2px 8px' }}>{op.label}</span>
|
||||
<span className="badge" style={{ fontSize: 11, color: 'var(--on-primary)', background: op.color, borderRadius: 4, padding: '2px 8px' }}>{op.label}</span>
|
||||
<span style={{ fontSize: 13, fontWeight: 600, color: 'var(--text)' }}>{FIELD_LABELS[r.field] ?? r.field}</span>
|
||||
</span>
|
||||
<span style={{ fontSize: 12, color: 'var(--text-3)' }}>{formatDateTime(r.created_at)}</span>
|
||||
|
||||
Reference in New Issue
Block a user