Feat: Connect Dashboard to real Supabase data

This commit is contained in:
2025-12-03 22:24:46 +03:00
parent e5f7680393
commit e4adb85498

View File

@@ -1,7 +1,66 @@
import { createClient } from "@/lib/supabase/server"
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
import { CalendarDays, CreditCard, Users, DollarSign, TrendingUp, ArrowUpRight } from "lucide-react"
import { CalendarDays, CreditCard, Users, DollarSign, TrendingUp, ArrowUpRight, Calendar as CalendarIcon } from "lucide-react"
import { format } from "date-fns"
import { tr } from "date-fns/locale"
import Link from "next/link"
import { Badge } from "@/components/ui/badge"
export default async function DashboardPage() {
const supabase = await createClient()
// 1. Total Reservations (Count)
const { count: totalReservations } = await supabase
.from('reservations')
.select('*', { count: 'exact', head: true })
.neq('status', 'cancelled')
// 2. Active Customers (Count)
const { count: totalCustomers } = await supabase
.from('customers')
.select('*', { count: 'exact', head: true })
// 3. Pending Payments (Sum of remaining balances)
// This is complex to calculate in one query without a view or function,
// so we'll approximate or fetch pending payments directly if possible.
// For now, let's just count pending reservations as a proxy or fetch recent payments.
// Better: Sum of 'amount' from 'payments' where status = 'pending' (if we tracked pending payments that way)
// Or: Calculate total potential revenue vs paid revenue.
// Let's stick to "Total Revenue" (Paid) for now.
const { data: payments } = await supabase
.from('payments')
.select('amount')
.eq('status', 'paid')
const totalRevenue = payments?.reduce((sum, p) => sum + Number(p.amount), 0) || 0
// 4. Upcoming Events (Next 5)
const { data: upcomingEvents } = await supabase
.from('reservations')
.select(`
id,
start_time,
status,
halls (name),
customers (full_name)
`)
.gte('start_time', new Date().toISOString())
.neq('status', 'cancelled')
.order('start_time', { ascending: true })
.limit(5)
// 5. Recent Activities (Last 5 created reservations)
const { data: recentReservations } = await supabase
.from('reservations')
.select(`
id,
created_at,
customers (full_name)
`)
.order('created_at', { ascending: false })
.limit(5)
export default function DashboardPage() {
return (
<div className="space-y-8">
<div className="flex items-center justify-between">
@@ -22,9 +81,9 @@ export default function DashboardPage() {
</div>
</CardHeader>
<CardContent>
<div className="text-3xl font-bold mt-2">12</div>
<div className="text-3xl font-bold mt-2">{totalReservations || 0}</div>
<p className="text-xs text-muted-foreground mt-1 flex items-center">
<span className="text-green-600 flex items-center mr-1"><TrendingUp className="h-3 w-3 mr-1" /> +2</span> geçen aydan beri
Aktif rezervasyonlar
</p>
</CardContent>
</Card>
@@ -32,33 +91,16 @@ export default function DashboardPage() {
<Card className="card-hover border-l-4 border-l-purple-500">
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium text-muted-foreground">
Aktif Müşteriler
Toplam Müşteri
</CardTitle>
<div className="h-8 w-8 rounded-full bg-purple-100 dark:bg-purple-900/20 flex items-center justify-center">
<Users className="h-4 w-4 text-purple-600 dark:text-purple-400" />
</div>
</CardHeader>
<CardContent>
<div className="text-3xl font-bold mt-2">50</div>
<div className="text-3xl font-bold mt-2">{totalCustomers || 0}</div>
<p className="text-xs text-muted-foreground mt-1 flex items-center">
<span className="text-green-600 flex items-center mr-1"><ArrowUpRight className="h-3 w-3 mr-1" /> +4</span> geçen aydan beri
</p>
</CardContent>
</Card>
<Card className="card-hover border-l-4 border-l-orange-500">
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium text-muted-foreground">
Bekleyen Ödemeler
</CardTitle>
<div className="h-8 w-8 rounded-full bg-orange-100 dark:bg-orange-900/20 flex items-center justify-center">
<CreditCard className="h-4 w-4 text-orange-600 dark:text-orange-400" />
</div>
</CardHeader>
<CardContent>
<div className="text-3xl font-bold mt-2">12,000</div>
<p className="text-xs text-muted-foreground mt-1">
3 rezervasyon için
Kayıtlı müşteri sayısı
</p>
</CardContent>
</Card>
@@ -66,16 +108,16 @@ export default function DashboardPage() {
<Card className="card-hover border-l-4 border-l-green-500">
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium text-muted-foreground">
Aylık Gelir
Toplam Gelir
</CardTitle>
<div className="h-8 w-8 rounded-full bg-green-100 dark:bg-green-900/20 flex items-center justify-center">
<DollarSign className="h-4 w-4 text-green-600 dark:text-green-400" />
</div>
</CardHeader>
<CardContent>
<div className="text-3xl font-bold mt-2">45,000</div>
<div className="text-3xl font-bold mt-2">{totalRevenue.toLocaleString('tr-TR')}</div>
<p className="text-xs text-muted-foreground mt-1 flex items-center">
<span className="text-green-600 flex items-center mr-1"><TrendingUp className="h-3 w-3 mr-1" /> +10%</span> geçen aydan beri
Tahsil edilen ödemeler
</p>
</CardContent>
</Card>
@@ -87,28 +129,55 @@ export default function DashboardPage() {
<CardTitle>Yaklaşan Etkinlikler</CardTitle>
</CardHeader>
<CardContent>
<div className="h-[300px] flex items-center justify-center bg-muted/20 rounded-lg border border-dashed">
<p className="text-muted-foreground">Takvim önizlemesi buraya gelecek.</p>
{upcomingEvents?.length === 0 ? (
<div className="h-[200px] flex items-center justify-center bg-muted/20 rounded-lg border border-dashed">
<p className="text-muted-foreground">Yaklaşan etkinlik bulunmuyor.</p>
</div>
) : (
<div className="space-y-4">
{upcomingEvents?.map((event) => (
<div key={event.id} className="flex items-center justify-between p-4 border rounded-lg bg-card hover:bg-accent/50 transition-colors">
<div className="flex items-center gap-4">
<div className="h-10 w-10 rounded-full bg-primary/10 flex items-center justify-center text-primary">
<CalendarIcon className="h-5 w-5" />
</div>
<div>
<p className="font-medium">{event.customers?.full_name}</p>
<p className="text-sm text-muted-foreground">{event.halls?.name}</p>
</div>
</div>
<div className="text-right">
<p className="font-medium">{format(new Date(event.start_time), 'd MMM yyyy', { locale: tr })}</p>
<p className="text-sm text-muted-foreground">{format(new Date(event.start_time), 'HH:mm')}</p>
</div>
</div>
))}
</div>
)}
</CardContent>
</Card>
<Card className="col-span-3 shadow-md border-none">
<CardHeader>
<CardTitle>Son Aktiviteler</CardTitle>
<CardTitle>Son İşlemler</CardTitle>
</CardHeader>
<CardContent>
<div className="space-y-4">
{[1, 2, 3].map((i) => (
<div key={i} className="flex items-center gap-4 p-3 rounded-lg hover:bg-muted/50 transition-colors">
{recentReservations?.map((res) => (
<div key={res.id} className="flex items-center gap-4 p-3 rounded-lg hover:bg-muted/50 transition-colors">
<div className="h-9 w-9 rounded-full bg-primary/10 flex items-center justify-center text-primary font-bold text-sm">
AH
{res.customers?.full_name?.substring(0, 2).toUpperCase()}
</div>
<div className="flex-1">
<p className="text-sm font-medium">Ahmet Hakan rezervasyon yaptı</p>
<p className="text-xs text-muted-foreground">2 dakika önce</p>
<p className="text-sm font-medium">{res.customers?.full_name} rezervasyon oluşturdu</p>
<p className="text-xs text-muted-foreground">
{format(new Date(res.created_at), 'd MMM HH:mm', { locale: tr })}
</p>
</div>
</div>
))}
{recentReservations?.length === 0 && (
<p className="text-sm text-muted-foreground text-center py-4">Henüz işlem yok.</p>
)}
</div>
</CardContent>
</Card>