Files
clinicpro/assets/admin/components/dashboard/TauriStatCards.tsx
T
hamed 55ab2f5dfc 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.
2026-07-27 16:41:52 +03:30

104 lines
3.6 KiB
TypeScript

/**
* Stat cards row — ported pixel-for-pixel from clinic-pro-tauri
* `src/components/dashboard/cards/` (index + Card). Exact Tailwind arbitrary
* classes / colors kept; icons are the ported SVGs in `dashboardIcons`.
*/
import React from 'react';
import { UserAddIcon, CardIcon, CardTickIcon, CalendarIcon } from './dashboardIcons';
export interface StatCardModel {
/** background tint of the whole card (source `card_color`) */
cardColor: string;
/** solid background of the round icon bubble (source `icon_color`) */
iconColor: string;
icon: React.ReactNode;
value: React.ReactNode;
label: string;
}
function TauriStatCard({ data }: { data: StatCardModel }) {
return (
<li
className={`px-[8px] md:px-[16px] lg:px-[24px] py-[18px] sm:py-[20px] md:py-[22px] lg:py-[24px] rounded-[8px] flex items-center justify-start gap-[4px] md:gap-[8px] lg:gap-[12px] ${data.cardColor} dark:bg-[var(--surface)]`}
>
<div
className={`p-[8px] w-[calc(18px+8px)] sm:w-[calc(20px+8px)] md:w-[calc(22px+8px)] lg:w-[calc(24px+8px)] min-w-[calc(18px+8px)] sm:min-w-[calc(20px+8px)] md:min-w-[calc(22px+8px)] lg:min-w-[calc(24px+8px)] h-[calc(18px+8px)] sm:h-[calc(20px+8px)] md:h-[calc(22px+8px)] lg:h-[calc(24px+8px)] grid place-items-center rounded-full ${data.iconColor}`}
>
{data.icon}
</div>
<div className="flex flex-col w-full items-start justify-center gap-[8px]">
<p className="text-[var(--text)] text-wrap text-[14px] sm:text-[16px] md:text-[18px] lg:text-[20px] font-medium">
{data.value}
</p>
<p className="text-[var(--text-2)] text-[12px] md:text-[14px] lg:text-[16px] font-normal">
{data.label}
</p>
</div>
</li>
);
}
export interface DashboardStats {
/** تعداد کل مراجعین */
totalPatients: number;
/** کل پرداختی‌ها (ریال) */
totalPaymentsRials: number;
/** پرداختی‌های امروز (ریال) */
todayPaymentsRials: number;
/** تعداد نوبت‌های امروز */
todayAppointments: number;
}
/**
* 4-card grid. `formatNumber`/`formatRial` are passed in so this stays a pure
* presentational component (SRP) — no coupling to the app's utils.
*/
export function TauriStatCards({
stats,
formatNumber,
formatRial,
}: {
stats: DashboardStats;
formatNumber: (n: number) => string;
formatRial: (rial: number) => string;
}) {
const cards: StatCardModel[] = [
{
cardColor: 'bg-[rgba(241,119,50,0.10)]',
iconColor: 'bg-[var(--accent)]',
icon: <UserAddIcon />,
value: `${formatNumber(stats.totalPatients)}+`,
label: 'تعداد کل مراجعین',
},
{
cardColor: 'bg-[rgba(0,157,121,0.10)]',
iconColor: 'bg-[var(--success)]',
icon: <CardIcon />,
value: formatRial(stats.totalPaymentsRials),
label: 'کل پرداختی‌ها',
},
{
cardColor: 'bg-[rgba(85,89,206,0.08)]',
iconColor: 'bg-[var(--primary)]',
icon: <CardTickIcon />,
value: formatRial(stats.todayPaymentsRials),
label: 'پرداختی‌های امروز',
},
{
cardColor: 'bg-[rgba(255,192,81,0.11)]',
iconColor: 'bg-[var(--warning)]',
icon: <CalendarIcon />,
value: `${formatNumber(stats.todayAppointments)}+`,
label: 'تعداد نوبت‌های امروز',
},
];
return (
<ul className="grid w-full grid-cols-1 sm:grid-cols-2 xl:grid-cols-4 gap-[16px] sm:gap-[23px] md:gap-[30px] lg:gap-[36px]">
{cards.map((c) => (
<TauriStatCard key={c.label} data={c} />
))}
</ul>
);
}