Task 5.25: Dashboard-System — GET /api/v1/dashboard/widgets, DashboardWidgetLoader, DashboardGrid with drag-and-drop, 3 example widgets (RecentContacts, TasksSummary, CalendarUpcoming), updated Dashboard.tsx, i18n, 6 tests

This commit is contained in:
Agent Zero
2026-07-24 00:09:26 +02:00
parent 96e183bab2
commit 036e87a9ed
15 changed files with 544 additions and 6 deletions
+17
View File
@@ -2,7 +2,9 @@ import React from 'react';
import { useTranslation } from 'react-i18next';
import { StatCard } from '@/components/shared/StatCard';
import { ActivityFeed, ActivityItem } from '@/components/shared/ActivityFeed';
import { DashboardGrid } from '@/components/dashboard/DashboardGrid';
import { useUnifiedContacts, useAuditLog } from '@/api/hooks';
import { useDashboardWidgets } from '@/api/dashboard';
import { formatDateTime } from '@/utils/date';
export function DashboardPage() {
@@ -10,6 +12,7 @@ export function DashboardPage() {
const { data: companiesData } = useUnifiedContacts(1, 1, undefined, 'company');
const { data: contactsData } = useUnifiedContacts(1, 1, undefined, 'person');
const { data: auditData, isError: auditError } = useAuditLog(1, 5);
const { data: widgetsData, isError: widgetsError } = useDashboardWidgets();
const totalCompanies = companiesData?.total ?? 0;
const totalContacts = contactsData?.total ?? 0;
@@ -41,6 +44,8 @@ export function DashboardPage() {
avatarUrl: null,
}));
const widgets = widgetsData?.items ?? [];
return (
<div className="p-6 max-w-7xl mx-auto" data-testid="dashboard-page">
<h1 className="text-2xl font-bold text-secondary-900 mb-6">{t('dashboard.title')}</h1>
@@ -68,6 +73,18 @@ export function DashboardPage() {
/>
</div>
{/* Dynamic Plugin Widgets */}
{widgetsError ? (
<p className="text-sm text-secondary-500 mb-6" data-testid="dashboard-widgets-unavailable">
{t('dashboard.widgetsUnavailable')}
</p>
) : widgets.length > 0 ? (
<div className="mb-8">
<h2 className="text-lg font-semibold text-secondary-800 mb-4">{t('dashboard.widgets')}</h2>
<DashboardGrid widgets={widgets} />
</div>
) : null}
{auditError ? (
<p className="text-sm text-secondary-500" data-testid="activity-unavailable">
{t('dashboard.activityUnavailable')}