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:
14
frontend/src/lib/api/today.ts
Normal file
14
frontend/src/lib/api/today.ts
Normal 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;
|
||||
},
|
||||
};
|
||||
49
frontend/src/lib/hooks/useTodaySummary.ts
Normal file
49
frontend/src/lib/hooks/useTodaySummary.ts
Normal 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 };
|
||||
}
|
||||
Reference in New Issue
Block a user