98 lines
2.5 KiB
TypeScript
98 lines
2.5 KiB
TypeScript
|
|
/**
|
||
|
|
* Personal dashboards API hooks (Phase M2/M3).
|
||
|
|
*
|
||
|
|
* Layout shape (validated server-side, DashboardLayout):
|
||
|
|
* { version: 1, tabs: [{ id, name, widgets: [{ app_id, settings, col, row, col_span, row_span }] }] }
|
||
|
|
*/
|
||
|
|
|
||
|
|
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
||
|
|
import { apiGet, apiPost, apiPut, apiDelete } from './client';
|
||
|
|
|
||
|
|
export interface DashboardWidget {
|
||
|
|
app_id: string;
|
||
|
|
settings: Record<string, unknown>;
|
||
|
|
col: number;
|
||
|
|
row: number;
|
||
|
|
col_span: number;
|
||
|
|
row_span: number;
|
||
|
|
}
|
||
|
|
|
||
|
|
export interface DashboardTab {
|
||
|
|
id: string;
|
||
|
|
name: string;
|
||
|
|
widgets: DashboardWidget[];
|
||
|
|
}
|
||
|
|
|
||
|
|
export interface DashboardLayout {
|
||
|
|
version: number;
|
||
|
|
tabs: DashboardTab[];
|
||
|
|
}
|
||
|
|
|
||
|
|
export interface Dashboard {
|
||
|
|
id: string;
|
||
|
|
name: string;
|
||
|
|
layout: DashboardLayout;
|
||
|
|
is_default: boolean;
|
||
|
|
user_id: string;
|
||
|
|
created_at: string | null;
|
||
|
|
updated_at: string | null;
|
||
|
|
}
|
||
|
|
|
||
|
|
export interface DashboardInput {
|
||
|
|
name: string;
|
||
|
|
}
|
||
|
|
|
||
|
|
export interface DashboardUpdateInput {
|
||
|
|
name?: string;
|
||
|
|
layout?: DashboardLayout;
|
||
|
|
}
|
||
|
|
|
||
|
|
export const DASHBOARD_QUERY_KEYS = {
|
||
|
|
all: ['dashboards'] as const,
|
||
|
|
one: (id: string) => ['dashboards', id] as const,
|
||
|
|
};
|
||
|
|
|
||
|
|
export function useDashboards() {
|
||
|
|
return useQuery({
|
||
|
|
queryKey: DASHBOARD_QUERY_KEYS.all,
|
||
|
|
queryFn: () => apiGet<Dashboard[]>('/dashboards'),
|
||
|
|
staleTime: 30 * 1000,
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
export function useCreateDashboard() {
|
||
|
|
const qc = useQueryClient();
|
||
|
|
return useMutation({
|
||
|
|
mutationFn: (input: DashboardInput) => apiPost<Dashboard>('/dashboards', input),
|
||
|
|
onSuccess: () => qc.invalidateQueries({ queryKey: DASHBOARD_QUERY_KEYS.all }),
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
export function useUpdateDashboard() {
|
||
|
|
const qc = useQueryClient();
|
||
|
|
return useMutation({
|
||
|
|
mutationFn: ({ id, input }: { id: string; input: DashboardUpdateInput }) =>
|
||
|
|
apiPut<Dashboard>(`/dashboards/${id}`, input),
|
||
|
|
onSuccess: (_data, vars) => {
|
||
|
|
qc.invalidateQueries({ queryKey: DASHBOARD_QUERY_KEYS.all });
|
||
|
|
qc.invalidateQueries({ queryKey: DASHBOARD_QUERY_KEYS.one(vars.id) });
|
||
|
|
},
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
export function useDeleteDashboard() {
|
||
|
|
const qc = useQueryClient();
|
||
|
|
return useMutation({
|
||
|
|
mutationFn: (id: string) => apiDelete<void>(`/dashboards/${id}`),
|
||
|
|
onSuccess: () => qc.invalidateQueries({ queryKey: DASHBOARD_QUERY_KEYS.all }),
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
export function useSetDefaultDashboard() {
|
||
|
|
const qc = useQueryClient();
|
||
|
|
return useMutation({
|
||
|
|
mutationFn: (id: string) => apiPost<Dashboard>(`/dashboards/${id}/set-default`),
|
||
|
|
onSuccess: () => qc.invalidateQueries({ queryKey: DASHBOARD_QUERY_KEYS.all }),
|
||
|
|
});
|
||
|
|
}
|