This commit is contained in:
Timo Knuth
2025-10-18 17:55:32 +02:00
parent 254e6490b8
commit 91b78cb284
65 changed files with 4481 additions and 1078 deletions

View File

@@ -18,9 +18,9 @@ interface QRCodeCardProps {
status: 'ACTIVE' | 'PAUSED';
createdAt: string;
scans?: number;
style?: any;
};
onEdit: (id: string) => void;
onDuplicate: (id: string) => void;
onPause: (id: string) => void;
onDelete: (id: string) => void;
}
@@ -28,7 +28,6 @@ interface QRCodeCardProps {
export const QRCodeCard: React.FC<QRCodeCardProps> = ({
qr,
onEdit,
onDuplicate,
onPause,
onDelete,
}) => {
@@ -138,11 +137,14 @@ export const QRCodeCard: React.FC<QRCodeCardProps> = ({
>
<DropdownItem onClick={() => downloadQR('png')}>Download PNG</DropdownItem>
<DropdownItem onClick={() => downloadQR('svg')}>Download SVG</DropdownItem>
<DropdownItem onClick={() => onEdit(qr.id)}>Edit</DropdownItem>
<DropdownItem onClick={() => onDuplicate(qr.id)}>Duplicate</DropdownItem>
<DropdownItem onClick={() => onPause(qr.id)}>
{qr.status === 'ACTIVE' ? 'Pause' : 'Resume'}
</DropdownItem>
{qr.type === 'DYNAMIC' && (
<DropdownItem onClick={() => onEdit(qr.id)}>Edit</DropdownItem>
)}
{qr.type === 'DYNAMIC' && (
<DropdownItem onClick={() => onPause(qr.id)}>
{qr.status === 'ACTIVE' ? 'Pause' : 'Resume'}
</DropdownItem>
)}
<DropdownItem onClick={() => onDelete(qr.id)} className="text-red-600">
Delete
</DropdownItem>
@@ -153,8 +155,8 @@ export const QRCodeCard: React.FC<QRCodeCardProps> = ({
<QRCodeSVG
value={qrUrl}
size={96}
fgColor="#000000"
bgColor="#FFFFFF"
fgColor={qr.style?.foregroundColor || '#000000'}
bgColor={qr.style?.backgroundColor || '#FFFFFF'}
level="M"
/>
</div>
@@ -164,10 +166,12 @@ export const QRCodeCard: React.FC<QRCodeCardProps> = ({
<span className="text-gray-500">Type:</span>
<span className="text-gray-900">{qr.contentType}</span>
</div>
<div className="flex items-center justify-between">
<span className="text-gray-500">Scans:</span>
<span className="text-gray-900">{qr.scans || 0}</span>
</div>
{qr.type === 'DYNAMIC' && (
<div className="flex items-center justify-between">
<span className="text-gray-500">Scans:</span>
<span className="text-gray-900">{qr.scans || 0}</span>
</div>
)}
<div className="flex items-center justify-between">
<span className="text-gray-500">Created:</span>
<span className="text-gray-900">{formatDate(qr.createdAt)}</span>

View File

@@ -3,6 +3,7 @@
import React from 'react';
import { Card, CardContent } from '@/components/ui/Card';
import { formatNumber } from '@/lib/utils';
import { useTranslation } from '@/hooks/useTranslation';
interface StatsGridProps {
stats: {
@@ -13,12 +14,13 @@ interface StatsGridProps {
}
export const StatsGrid: React.FC<StatsGridProps> = ({ stats }) => {
const { t } = useTranslation();
// Only show growth if there are actual scans
const showGrowth = stats.totalScans > 0;
const cards = [
{
title: 'Total Scans',
title: t('dashboard.stats.total_scans'),
value: formatNumber(stats.totalScans),
change: showGrowth ? '+12%' : 'No data yet',
changeType: showGrowth ? 'positive' : 'neutral' as 'positive' | 'negative' | 'neutral',
@@ -30,7 +32,7 @@ export const StatsGrid: React.FC<StatsGridProps> = ({ stats }) => {
),
},
{
title: 'Active QR Codes',
title: t('dashboard.stats.active_codes'),
value: stats.activeQRCodes.toString(),
change: stats.activeQRCodes > 0 ? `${stats.activeQRCodes} active` : 'Create your first',
changeType: stats.activeQRCodes > 0 ? 'positive' : 'neutral' as 'positive' | 'negative' | 'neutral',
@@ -41,7 +43,7 @@ export const StatsGrid: React.FC<StatsGridProps> = ({ stats }) => {
),
},
{
title: 'Conversion Rate',
title: t('dashboard.stats.conversion_rate'),
value: `${stats.conversionRate}%`,
change: stats.totalScans > 0 ? `${stats.conversionRate}% rate` : 'No scans yet',
changeType: stats.conversionRate > 0 ? 'positive' : 'neutral' as 'positive' | 'negative' | 'neutral',