Add Today dashboard foundation with permission-aware KPI summary API.
Replace hardcoded Today cards with a backend summary endpoint and composable frontend widgets filtered by org type and tab permissions. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -3,22 +3,23 @@
|
||||
import { useTranslations } from 'next-intl';
|
||||
import { Link } from '@/i18n/navigation';
|
||||
import { useAuth } from '@/lib/hooks/useAuth';
|
||||
import { Card } from '@/components/ui/shared/Card';
|
||||
import { TodayKpiGrid } from '@/components/today/TodayKpiGrid';
|
||||
import { useTodaySummary } from '@/lib/hooks/useTodaySummary';
|
||||
import { formatApiErrorMessage } from '@/components/shared/formatApiError';
|
||||
|
||||
export default function TodayPage() {
|
||||
const t = useTranslations('today');
|
||||
const { currentOrganization } = useAuth();
|
||||
const { data, loading, error } = useTodaySummary(Boolean(currentOrganization?.id));
|
||||
const showNoSubscriptionNotice =
|
||||
Boolean(currentOrganization?.isOwner) && !currentOrganization?.plan;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h1 className="text-2xl font-semibold mb-6">
|
||||
{t('welcomeBack')}
|
||||
</h1>
|
||||
<div className="space-y-6">
|
||||
<h1 className="text-2xl font-semibold">{t('welcomeBack')}</h1>
|
||||
|
||||
{showNoSubscriptionNotice && (
|
||||
<div className="mb-6 rounded-[var(--radius-md)] border border-amber-500/30 bg-amber-500/10 p-4">
|
||||
<div className="rounded-[var(--radius-md)] border border-amber-500/30 bg-amber-500/10 p-4">
|
||||
<p className="text-sm text-amber-200">
|
||||
{t('noSubscriptionNotice')}{' '}
|
||||
<Link href="/settings/subscriptions" className="font-medium underline underline-offset-2">
|
||||
@@ -29,27 +30,15 @@ export default function TodayPage() {
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-4 gap-4">
|
||||
<Card>
|
||||
<p className="text-sm text-card-muted">{t('cardTodaysAppointments')}</p>
|
||||
<p className="text-2xl font-semibold mt-2">12</p>
|
||||
<p className="text-xs text-text-muted mt-1">Monday 2/5/2026</p>
|
||||
</Card>
|
||||
<Card>
|
||||
<p className="text-sm text-card-muted">{t('cardActivePatients')}</p>
|
||||
<p className="text-2xl font-semibold mt-2">675</p>
|
||||
</Card>
|
||||
<Card>
|
||||
<p className="text-sm text-card-muted">{t('cardNewLabCase')}</p>
|
||||
<p className="text-2xl font-semibold mt-2">5</p>
|
||||
<p className="text-xs text-text-muted mt-1">35 ↑</p>
|
||||
</Card>
|
||||
<Card>
|
||||
<p className="text-sm text-card-muted">{t('cardTodayInvoices')}</p>
|
||||
<p className="text-2xl font-semibold mt-2">1200$</p>
|
||||
<p className="text-xs text-text-muted mt-1">21,300 $</p>
|
||||
</Card>
|
||||
</div>
|
||||
{error ? (
|
||||
<div className="rounded-[var(--radius-md)] border border-badge-danger-border bg-badge-danger-bg/40 p-4">
|
||||
<p className="text-sm text-badge-danger-fg">
|
||||
{formatApiErrorMessage(error, t('loadError'))}
|
||||
</p>
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
<TodayKpiGrid widgets={data?.widgets ?? {}} loading={loading} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user