106 lines
4.3 KiB
TypeScript
106 lines
4.3 KiB
TypeScript
/**
|
|
* Ported clinic/doctor dashboard view — pixel-for-pixel from clinic-pro-tauri
|
|
* `src/components/dashboard/index.jsx` (Cards → Charts → New-appointments list,
|
|
* stacked with 24px gaps). Purely presentational; both ClinicDashboard and
|
|
* DoctorDashboard feed it their (real-API) data.
|
|
*/
|
|
import React from 'react';
|
|
import { Link } from 'react-router-dom';
|
|
import { TauriStatCards, type DashboardStats } from './TauriStatCards';
|
|
import { TauriBarChart, TauriLineChart, type ChartPoint } from './TauriCharts';
|
|
import { NewAppointmentsTable, type ApptRow } from './NewAppointmentsTable';
|
|
import SearchableSelect from '../ui/SearchableSelect';
|
|
|
|
/** small cosmetic dropdown — mirrors source SmSelector (does not drive data) */
|
|
function SmSelector({ options }: { options: string[] }) {
|
|
const [value, setValue] = React.useState<string | number | null>(options[0] ?? null);
|
|
return (
|
|
<div style={{ minWidth: 110 }}>
|
|
<SearchableSelect
|
|
options={options.map((o) => ({ value: o, label: o }))}
|
|
value={value}
|
|
onChange={setValue}
|
|
height={34}
|
|
/>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
function ChartTitle({ text }: { text: string }) {
|
|
return <p className="text-[#525252] dark:text-[#D7D8ED] text-[14px] md:text-[16px] font-bold">{text}</p>;
|
|
}
|
|
|
|
function ChartCard({ title, selectorOptions, children }: { title: string; selectorOptions: string[]; children: React.ReactNode }) {
|
|
return (
|
|
<div className="w-full rounded-[8px] border border-solid border-[#EFEFEF] dark:border-transparent bg-[#FFF] dark:bg-[#222433]">
|
|
<div className="flex px-[20px] py-[12px] md:py-[14px] lg:py-[16px] items-center justify-between gap-[12px]">
|
|
<ChartTitle text={title} />
|
|
<SmSelector options={selectorOptions} />
|
|
</div>
|
|
{children}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
const MONTHS = ['فروردین', 'اردیبهشت', 'خرداد', 'تیر', 'مرداد', 'شهریور', 'مهر', 'آبان', 'آذر', 'دی', 'بهمن', 'اسفند'];
|
|
const YEARS = ['سال ۱۴۰۳', 'سال ۱۴۰۲', 'سال ۱۴۰۱', 'سال ۱۴۰۰'];
|
|
|
|
export interface TauriDashboardViewProps {
|
|
stats: DashboardStats;
|
|
/** «نمودار تعداد بیماران» series (appointments_by_day) */
|
|
patientBars: ChartPoint[];
|
|
/** «میزان درآمد» series (revenue_by_day) */
|
|
incomeLine: ChartPoint[];
|
|
appointments: ApptRow[];
|
|
loading: boolean;
|
|
formatNumber: (n: number) => string;
|
|
formatRial: (rial: number) => string;
|
|
}
|
|
|
|
export function TauriDashboardView({
|
|
stats,
|
|
patientBars,
|
|
incomeLine,
|
|
appointments,
|
|
loading,
|
|
formatNumber,
|
|
formatRial,
|
|
}: TauriDashboardViewProps) {
|
|
return (
|
|
<div className="flex flex-col items-stretch gap-y-[24px] w-full">
|
|
{/* Cards */}
|
|
<TauriStatCards stats={stats} formatNumber={formatNumber} formatRial={formatRial} />
|
|
|
|
{/* Charts — grid-2 (1fr 1fr, collapses to 1fr on narrow) for reliable
|
|
full-width equal columns, matching the rest of the admin dashboard */}
|
|
<div className="grid-2 w-full">
|
|
<ChartCard title="نمودار تعداد بیماران" selectorOptions={MONTHS}>
|
|
<TauriBarChart data={patientBars} />
|
|
</ChartCard>
|
|
<ChartCard title="میزان درآمد" selectorOptions={YEARS}>
|
|
<TauriLineChart data={incomeLine} />
|
|
</ChartCard>
|
|
</div>
|
|
|
|
{/* New appointments list */}
|
|
<div className="w-full rounded-[8px] border border-solid border-transparent md:border-[#EFEFEF] dark:border-transparent bg-transparent md:bg-[#FFF] md:dark:bg-[#222433]">
|
|
<div className="md:pt-[18px] md:px-[24px] md:pb-[20px] flex items-center justify-between">
|
|
<p className="text-[#525252] dark:text-[#D7D8ED] text-[14px] md:text-[16px] font-bold">لیست نوبتهای جدید</p>
|
|
<Link
|
|
to="/admin/appointments"
|
|
className="flex items-center gap-[4px] p-1 text-[12px] md:text-[14px] text-[#616161] dark:text-[#A1A1A1] font-normal hover:text-[#5559ce]"
|
|
>
|
|
نوبتها
|
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none">
|
|
<path d="M15 6L9 12L15 18" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
|
|
</svg>
|
|
</Link>
|
|
</div>
|
|
<div className="px-0 md:px-[24px] pb-[16px]">
|
|
<NewAppointmentsTable rows={appointments} loading={loading} />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|