Files
plantillas-proyectos/frontend/src/lib/components/dashboard/kpi-card.svelte
acazares 3865a53c5c feat(dashboard): add dashboard module for business metrics and statistics
- Implemented DTOs for KPIs, activity items, chart data points, and dashboard statistics.
- Created API routes for fetching dashboard statistics, operations overview, and inventory metrics.
- Developed a service layer to handle the logic for generating dashboard statistics, including invoice metrics, client/provider metrics, and recent activity.
- Added frontend API client methods for fetching dashboard data.
- Created TypeScript types for dashboard data structures.
- Developed Svelte components for displaying recent activity, KPI cards, trend charts, and donut charts.
2026-01-12 18:09:06 -06:00

57 lines
1.6 KiB
Svelte

<script lang="ts">
import * as Card from '$lib/components/ui/card';
import { TrendingUp, TrendingDown, Minus } from 'lucide-svelte';
import type { KPIMetric } from '$lib/api/dashboard/types';
import { cn } from '$lib/utils';
interface Props {
metric: KPIMetric;
icon?: any;
iconColor?: string;
}
let { metric, icon: Icon, iconColor = 'text-primary' }: Props = $props();
const trendIcons = {
up: TrendingUp,
down: TrendingDown,
stable: Minus
};
const trendColors = {
up: 'text-green-600',
down: 'text-red-600',
stable: 'text-gray-600'
};
const TrendIcon = metric.trend ? trendIcons[metric.trend] : null;
</script>
<Card.Root class="overflow-hidden">
<Card.Header class="flex flex-row items-center justify-between space-y-0 pb-2">
<Card.Title class="text-sm font-medium text-muted-foreground">
{metric.label}
</Card.Title>
{#if Icon}
<Icon class={cn('h-4 w-4', iconColor)} />
{/if}
</Card.Header>
<Card.Content>
<div class="text-2xl font-bold">
{metric.value.toLocaleString()}
{#if metric.unit}
<span class="text-sm font-normal text-muted-foreground ml-1">{metric.unit}</span>
{/if}
</div>
{#if metric.percentage_change !== undefined && TrendIcon}
<div class="flex items-center text-xs mt-1">
<TrendIcon class={cn('h-3 w-3 mr-1', trendColors[metric.trend || 'stable'])} />
<span class={cn(trendColors[metric.trend || 'stable'])}>
{Math.abs(metric.percentage_change).toFixed(1)}%
</span>
<span class="text-muted-foreground ml-1">vs mes anterior</span>
</div>
{/if}
</Card.Content>
</Card.Root>