Analytics

This commit is contained in:
Timo Knuth
2025-12-15 20:35:50 +01:00
parent 09ebcf235d
commit f1d1f4291b
5 changed files with 175 additions and 31 deletions

View File

@@ -4,6 +4,7 @@ import React from 'react';
import { Card, CardContent } from '@/components/ui/Card';
import { formatNumber } from '@/lib/utils';
import { useTranslation } from '@/hooks/useTranslation';
import { TrendData } from '@/types/analytics';
interface StatsGridProps {
stats: {
@@ -11,19 +12,42 @@ interface StatsGridProps {
activeQRCodes: number;
conversionRate: number;
};
trends?: {
totalScans?: TrendData;
comparisonPeriod?: 'week' | 'month';
};
}
export const StatsGrid: React.FC<StatsGridProps> = ({ stats }) => {
export const StatsGrid: React.FC<StatsGridProps> = ({ stats, trends }) => {
const { t } = useTranslation();
// Only show growth if there are actual scans
const showGrowth = stats.totalScans > 0;
// Build trend display text
const getTrendText = () => {
if (!trends?.totalScans) {
return 'No data yet';
}
const trend = trends.totalScans;
const sign = trend.isNegative ? '-' : '+';
const period = trends.comparisonPeriod || 'period';
const newLabel = trend.isNew ? ' (new)' : '';
return `${sign}${trend.percentage}%${newLabel} from last ${period}`;
};
const getTrendType = (): 'positive' | 'negative' | 'neutral' => {
if (!trends?.totalScans) return 'neutral';
if (trends.totalScans.trend === 'up') return 'positive';
if (trends.totalScans.trend === 'down') return 'negative';
return 'neutral';
};
const cards = [
{
title: t('dashboard.stats.total_scans'),
value: formatNumber(stats.totalScans),
change: showGrowth ? '+12%' : 'No data yet',
changeType: showGrowth ? 'positive' : 'neutral' as 'positive' | 'negative' | 'neutral',
change: getTrendText(),
changeType: getTrendType(),
icon: (
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
@@ -65,11 +89,11 @@ export const StatsGrid: React.FC<StatsGridProps> = ({ stats }) => {
<p className="text-sm text-gray-600 mb-1">{card.title}</p>
<p className="text-2xl font-bold text-gray-900">{card.value}</p>
<p className={`text-sm mt-2 ${
card.changeType === 'positive' ? 'text-success-600' :
card.changeType === 'negative' ? 'text-red-600' :
card.changeType === 'positive' ? 'text-success-600' :
card.changeType === 'negative' ? 'text-red-600' :
'text-gray-500'
}`}>
{card.changeType === 'neutral' ? card.change : `${card.change} from last month`}
{card.change}
</p>
</div>
<div className="w-12 h-12 bg-primary-100 rounded-lg flex items-center justify-center text-primary-600">