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:
2026-07-11 00:07:48 +03:30
parent 893cd5b128
commit 22466490bf
16 changed files with 966 additions and 43 deletions

View File

@@ -0,0 +1,14 @@
import { apiClient } from './client';
import type { TodaySummaryResponse } from '@/types/today';
export interface TodaySummaryParams {
from: string;
to: string;
}
export const todayApi = {
summary: async (params: TodaySummaryParams): Promise<TodaySummaryResponse> => {
const response = await apiClient.get('/today/summary', { params });
return response.data;
},
};

View File

@@ -0,0 +1,49 @@
'use client';
import { useCallback, useEffect, useState } from 'react';
import { getLocalDayIsoRange } from '@/components/appointments/appointmentTime';
import { todayApi } from '@/lib/api/today';
import type { TodaySummaryData } from '@/types/today';
import type { ApiError } from '@/types/api';
interface UseTodaySummaryResult {
data: TodaySummaryData | null;
loading: boolean;
error: ApiError | null;
reload: () => Promise<void>;
}
export function useTodaySummary(enabled = true): UseTodaySummaryResult {
const [data, setData] = useState<TodaySummaryData | null>(null);
const [loading, setLoading] = useState(enabled);
const [error, setError] = useState<ApiError | null>(null);
const reload = useCallback(async () => {
if (!enabled) {
setData(null);
setLoading(false);
setError(null);
return;
}
setLoading(true);
setError(null);
try {
const range = getLocalDayIsoRange(new Date());
const response = await todayApi.summary(range);
setData(response.data);
} catch (err) {
setData(null);
setError(err as ApiError);
} finally {
setLoading(false);
}
}, [enabled]);
useEffect(() => {
void reload();
}, [reload]);
return { data, loading, error, reload };
}