Add Stripe subscription integration with pricing plans

This commit is contained in:
Timo Knuth
2025-10-14 16:58:11 +02:00
parent 157e53af83
commit bccf771ffc
8 changed files with 654 additions and 12 deletions

View File

@@ -2,6 +2,7 @@
import React, { useState, useEffect } from 'react';
import Link from 'next/link';
import { useSession } from 'next-auth/react';
import { StatsGrid } from '@/components/dashboard/StatsGrid';
import { QRCodeCard } from '@/components/dashboard/QRCodeCard';
import { Card, CardHeader, CardTitle, CardContent } from '@/components/ui/Card';
@@ -23,8 +24,10 @@ interface QRCodeData {
export default function DashboardPage() {
const { t } = useTranslation();
const { data: session } = useSession();
const [qrCodes, setQrCodes] = useState<QRCodeData[]>([]);
const [loading, setLoading] = useState(true);
const [userPlan, setUserPlan] = useState<string>('FREE');
const [stats, setStats] = useState({
totalScans: 0,
activeQRCodes: 0,
@@ -116,19 +119,20 @@ export default function DashboardPage() {
];
useEffect(() => {
// Load real QR codes from API
// Load real QR codes and user plan from API
const fetchData = async () => {
try {
const response = await fetch('/api/qrs');
if (response.ok) {
const data = await response.json();
// Fetch QR codes
const qrResponse = await fetch('/api/qrs');
if (qrResponse.ok) {
const data = await qrResponse.json();
setQrCodes(data);
// Calculate real stats
const totalScans = data.reduce((sum: number, qr: QRCodeData) => sum + (qr.scans || 0), 0);
const activeQRCodes = data.filter((qr: QRCodeData) => qr.status === 'ACTIVE').length;
const conversionRate = activeQRCodes > 0 ? Math.round((totalScans / (activeQRCodes * 100)) * 100) : 0;
setStats({
totalScans,
activeQRCodes,
@@ -143,6 +147,15 @@ export default function DashboardPage() {
conversionRate: 0,
});
}
// Fetch user plan
if (session?.user?.email) {
const userResponse = await fetch('/api/user/plan');
if (userResponse.ok) {
const userData = await userResponse.json();
setUserPlan(userData.plan || 'FREE');
}
}
} catch (error) {
console.error('Error fetching data:', error);
setQrCodes([]);
@@ -157,7 +170,7 @@ export default function DashboardPage() {
};
fetchData();
}, []);
}, [session]);
const handleEdit = (id: string) => {
console.log('Edit QR:', id);
@@ -175,12 +188,48 @@ export default function DashboardPage() {
console.log('Delete QR:', id);
};
const getPlanBadgeColor = (plan: string) => {
switch (plan) {
case 'PRO':
return 'info';
case 'BUSINESS':
return 'warning';
default:
return 'default';
}
};
const getPlanEmoji = (plan: string) => {
switch (plan) {
case 'FREE':
return '🟢';
case 'PRO':
return '🔵';
case 'BUSINESS':
return '🟣';
default:
return '⚪';
}
};
return (
<div className="space-y-8">
{/* Header */}
<div>
<h1 className="text-3xl font-bold text-gray-900">{t('dashboard.title')}</h1>
<p className="text-gray-600 mt-2">{t('dashboard.subtitle')}</p>
{/* Header with Plan Badge */}
<div className="flex items-start justify-between">
<div>
<h1 className="text-3xl font-bold text-gray-900">{t('dashboard.title')}</h1>
<p className="text-gray-600 mt-2">{t('dashboard.subtitle')}</p>
</div>
<div className="flex items-center space-x-3">
<Badge variant={getPlanBadgeColor(userPlan)} className="text-lg px-4 py-2">
{getPlanEmoji(userPlan)} {userPlan} Plan
</Badge>
{userPlan === 'FREE' && (
<Link href="/pricing">
<Button variant="primary">Upgrade</Button>
</Link>
)}
</div>
</div>
{/* Stats Grid */}