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

@@ -9,6 +9,7 @@ import { Card, CardHeader, CardTitle, CardContent } from '@/components/ui/Card';
import { Button } from '@/components/ui/Button';
import { Badge } from '@/components/ui/Badge';
import { useTranslation } from '@/hooks/useTranslation';
import { useCsrf } from '@/hooks/useCsrf';
import { showToast } from '@/components/ui/Toast';
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter } from '@/components/ui/Dialog';
@@ -22,17 +23,20 @@ interface QRCodeData {
status: 'ACTIVE' | 'PAUSED';
createdAt: string;
scans: number;
style?: any;
}
export default function DashboardPage() {
const { t } = useTranslation();
const router = useRouter();
const searchParams = useSearchParams();
const { fetchWithCsrf } = useCsrf();
const [qrCodes, setQrCodes] = useState<QRCodeData[]>([]);
const [loading, setLoading] = useState(true);
const [userPlan, setUserPlan] = useState<string>('FREE');
const [showUpgradeDialog, setShowUpgradeDialog] = useState(false);
const [upgradedPlan, setUpgradedPlan] = useState<string>('');
const [deletingAll, setDeletingAll] = useState(false);
const [stats, setStats] = useState({
totalScans: 0,
activeQRCodes: 0,
@@ -116,7 +120,7 @@ export default function DashboardPage() {
slug: 'dynamische-vs-statische-qr-codes',
},
{
title: 'QR-Code Marketing-Strategien für 2024',
title: 'QR-Code Marketing-Strategien für 2025',
excerpt: 'Die besten Marketing-Strategien mit QR-Codes für Ihr Unternehmen...',
readTime: '7 Min',
slug: 'qr-code-marketing-strategien',
@@ -205,19 +209,98 @@ export default function DashboardPage() {
}, []);
const handleEdit = (id: string) => {
console.log('Edit QR:', id);
// Redirect to edit page
router.push(`/qr/${id}/edit`);
};
const handleDuplicate = (id: string) => {
console.log('Duplicate QR:', id);
const handlePause = async (id: string) => {
try {
const qr = qrCodes.find(q => q.id === id);
if (!qr) return;
const newStatus = qr.status === 'ACTIVE' ? 'PAUSED' : 'ACTIVE';
const response = await fetch(`/api/qrs/${id}`, {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ status: newStatus }),
});
if (response.ok) {
// Update local state
setQrCodes(qrCodes.map(q =>
q.id === id ? { ...q, status: newStatus } : q
));
showToast(`QR code ${newStatus === 'ACTIVE' ? 'resumed' : 'paused'}!`, 'success');
} else {
throw new Error('Failed to update status');
}
} catch (error) {
console.error('Error updating QR status:', error);
showToast('Failed to update QR code status', 'error');
}
};
const handlePause = (id: string) => {
console.log('Pause QR:', id);
const handleDelete = async (id: string) => {
if (!confirm('Are you sure you want to delete this QR code? This action cannot be undone.')) {
return;
}
try {
const response = await fetch(`/api/qrs/${id}`, {
method: 'DELETE',
});
if (response.ok) {
// Remove from local state
setQrCodes(qrCodes.filter(q => q.id !== id));
showToast('QR code deleted successfully!', 'success');
} else {
throw new Error('Failed to delete');
}
} catch (error) {
console.error('Error deleting QR:', error);
showToast('Failed to delete QR code', 'error');
}
};
const handleDelete = (id: string) => {
console.log('Delete QR:', id);
const handleDeleteAll = async () => {
if (!confirm('Are you sure you want to delete ALL QR codes? This action cannot be undone.')) {
return;
}
// Double confirmation
if (!confirm('This will permanently delete ALL your QR codes. Are you absolutely sure?')) {
return;
}
setDeletingAll(true);
try {
const response = await fetchWithCsrf('/api/qrs/delete-all', {
method: 'DELETE',
});
if (response.ok) {
const data = await response.json();
setQrCodes([]);
setStats({
totalScans: 0,
activeQRCodes: 0,
conversionRate: 0,
});
showToast(`Successfully deleted ${data.deletedCount} QR code${data.deletedCount !== 1 ? 's' : ''}`, 'success');
} else {
throw new Error('Failed to delete all QR codes');
}
} catch (error) {
console.error('Error deleting all QR codes:', error);
showToast('Failed to delete QR codes', 'error');
} finally {
setDeletingAll(false);
}
};
const getPlanBadgeColor = (plan: string) => {
@@ -263,9 +346,21 @@ export default function DashboardPage() {
<div>
<div className="flex items-center justify-between mb-6">
<h2 className="text-xl font-semibold text-gray-900">{t('dashboard.recent_codes')}</h2>
<Link href="/create">
<Button>Create New QR Code</Button>
</Link>
<div className="flex gap-3">
{qrCodes.length > 0 && (
<Button
variant="outline"
onClick={handleDeleteAll}
disabled={deletingAll}
className="border-red-600 text-red-600 hover:bg-red-50"
>
{deletingAll ? 'Deleting...' : 'Delete All'}
</Button>
)}
<Link href="/create">
<Button>Create New QR Code</Button>
</Link>
</div>
</div>
{loading ? (
@@ -292,7 +387,6 @@ export default function DashboardPage() {
key={qr.id}
qr={qr}
onEdit={handleEdit}
onDuplicate={handleDuplicate}
onPause={handlePause}
onDelete={handleDelete}
/>
@@ -351,11 +445,11 @@ export default function DashboardPage() {
</li>
<li className="flex items-start">
<span className="text-green-600 mr-2"></span>
<span>Branding (Logo, Farben anpassen)</span>
<span>Branding (Farben anpassen)</span>
</li>
<li className="flex items-start">
<span className="text-green-600 mr-2"></span>
<span>Detaillierte Analytics</span>
<span>Detaillierte Analytics (Devices, Locations, Time-Series)</span>
</li>
<li className="flex items-start">
<span className="text-green-600 mr-2"></span>
@@ -363,7 +457,7 @@ export default function DashboardPage() {
</li>
<li className="flex items-start">
<span className="text-green-600 mr-2"></span>
<span>Passwortschutz für QR-Codes</span>
<span>SVG/PNG Download</span>
</li>
</>
)}
@@ -375,15 +469,11 @@ export default function DashboardPage() {
</li>
<li className="flex items-start">
<span className="text-green-600 mr-2"></span>
<span>Team-Zugänge (bis zu 3 User)</span>
<span>Alles von Pro</span>
</li>
<li className="flex items-start">
<span className="text-green-600 mr-2"></span>
<span>Benutzerdefinierte Domains</span>
</li>
<li className="flex items-start">
<span className="text-green-600 mr-2"></span>
<span>White-Label</span>
<span>Bulk QR-Generierung (bis 1,000)</span>
</li>
<li className="flex items-start">
<span className="text-green-600 mr-2"></span>