feat: Implement dashboard navigation, payments list, and deployment docs

This commit is contained in:
2025-12-07 19:05:59 +03:00
parent ce41fdb432
commit b189a19651
5 changed files with 248 additions and 49 deletions

View File

@@ -6,6 +6,7 @@ import {
Table,
TableBody,
TableCell,
TableFooter,
TableHead,
TableHeader,
TableRow,
@@ -83,6 +84,16 @@ export default async function ExpensesPage() {
))
)}
</TableBody>
<TableFooter>
<TableRow>
<TableCell colSpan={3} className="font-bold text-right">Toplam Gider:</TableCell>
<TableCell className="text-right font-bold text-red-600 dark:text-red-400">
- {new Intl.NumberFormat('tr-TR', { style: 'currency', currency: 'TRY' }).format(
expenses?.reduce((sum, expense) => sum + Number(expense.amount), 0) || 0
)}
</TableCell>
</TableRow>
</TableFooter>
</Table>
</div>
</div>

View File

@@ -72,39 +72,43 @@ export default async function DashboardPage() {
</div>
<div className="grid gap-6 md:grid-cols-2 lg:grid-cols-4">
<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">
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-2xl font-bold mt-2">{totalRevenue.toLocaleString('tr-TR')}</div>
<p className="text-xs text-muted-foreground mt-1 flex items-center">
Tahsil edilen ödemeler
</p>
</CardContent>
</Card>
<Link href="/dashboard/payments" className="block">
<Card className="card-hover border-l-4 border-l-green-500 h-full cursor-pointer hover:bg-muted/5 transition-colors">
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium text-muted-foreground">
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-2xl font-bold mt-2">{totalRevenue.toLocaleString('tr-TR')}</div>
<p className="text-xs text-muted-foreground mt-1 flex items-center">
Tahsil edilen ödemeler
</p>
</CardContent>
</Card>
</Link>
<Card className="card-hover border-l-4 border-l-red-500">
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium text-muted-foreground">
Toplam Gider
</CardTitle>
<div className="h-8 w-8 rounded-full bg-red-100 dark:bg-red-900/20 flex items-center justify-center">
<TrendingUp className="h-4 w-4 text-red-600 dark:text-red-400 rotate-180" />
</div>
</CardHeader>
<CardContent>
<div className="text-2xl font-bold mt-2">{totalExpenses.toLocaleString('tr-TR')}</div>
<p className="text-xs text-muted-foreground mt-1 flex items-center">
İşletme giderleri
</p>
</CardContent>
</Card>
<Link href="/dashboard/expenses" className="block">
<Card className="card-hover border-l-4 border-l-red-500 h-full cursor-pointer hover:bg-muted/5 transition-colors">
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium text-muted-foreground">
Toplam Gider
</CardTitle>
<div className="h-8 w-8 rounded-full bg-red-100 dark:bg-red-900/20 flex items-center justify-center">
<TrendingUp className="h-4 w-4 text-red-600 dark:text-red-400 rotate-180" />
</div>
</CardHeader>
<CardContent>
<div className="text-2xl font-bold mt-2">{totalExpenses.toLocaleString('tr-TR')}</div>
<p className="text-xs text-muted-foreground mt-1 flex items-center">
İşletme giderleri
</p>
</CardContent>
</Card>
</Link>
<Card className="card-hover border-l-4 border-l-blue-500">
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
@@ -123,22 +127,24 @@ export default async function DashboardPage() {
</CardContent>
</Card>
<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">
Toplam Rezervasyon
</CardTitle>
<div className="h-8 w-8 rounded-full bg-purple-100 dark:bg-purple-900/20 flex items-center justify-center">
<CalendarDays className="h-4 w-4 text-purple-600 dark:text-purple-400" />
</div>
</CardHeader>
<CardContent>
<div className="text-2xl font-bold mt-2">{totalReservations || 0}</div>
<p className="text-xs text-muted-foreground mt-1 flex items-center">
Aktif rezervasyonlar
</p>
</CardContent>
</Card>
<Link href="/dashboard/reservations" className="block">
<Card className="card-hover border-l-4 border-l-purple-500 h-full cursor-pointer hover:bg-muted/5 transition-colors">
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium text-muted-foreground">
Toplam Rezervasyon
</CardTitle>
<div className="h-8 w-8 rounded-full bg-purple-100 dark:bg-purple-900/20 flex items-center justify-center">
<CalendarDays className="h-4 w-4 text-purple-600 dark:text-purple-400" />
</div>
</CardHeader>
<CardContent>
<div className="text-2xl font-bold mt-2">{totalReservations || 0}</div>
<p className="text-xs text-muted-foreground mt-1 flex items-center">
Aktif rezervasyonlar
</p>
</CardContent>
</Card>
</Link>
</div>
<div className="grid gap-6 md:grid-cols-2 lg:grid-cols-7">

View File

@@ -0,0 +1,131 @@
import { createClient } from "@/lib/supabase/server"
import {
Table,
TableBody,
TableCell,
TableFooter,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table"
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
import { format } from "date-fns"
import { tr } from "date-fns/locale"
import { Badge } from "@/components/ui/badge"
export default async function PaymentsPage() {
const supabase = await createClient()
const { data: payments } = await supabase
.from('payments')
.select(`
id,
amount,
created_at,
payment_method,
payment_type,
status,
reservations (
id,
start_time,
status,
customers (full_name)
)
`)
.order('created_at', { ascending: false })
const getStatusBadge = (status: string) => {
switch (status) {
case 'paid': return <Badge className="bg-green-600">Ödendi</Badge>
case 'pending': return <Badge variant="secondary">Bekliyor</Badge>
case 'refunded': return <Badge variant="destructive">İade</Badge>
case 'confirmed': return <Badge className="bg-blue-600">Onaylandı</Badge>
case 'cancelled': return <Badge variant="destructive">İptal</Badge>
case 'completed': return <Badge variant="outline">Tamamlandı</Badge>
default: return <Badge>{status}</Badge>
}
}
const getCustomerName = (reservation: any) => {
if (!reservation) return "-"
const res = Array.isArray(reservation) ? reservation[0] : reservation
const customer = res?.customers
const cust = Array.isArray(customer) ? customer[0] : customer
return cust?.full_name || "-"
}
const getReservationDate = (reservation: any) => {
if (!reservation) return "-"
const res = Array.isArray(reservation) ? reservation[0] : reservation
return res?.start_time ? format(new Date(res.start_time), 'd MMM yyyy', { locale: tr }) : "-"
}
const getReservationStatus = (reservation: any) => {
if (!reservation) return "-"
const res = Array.isArray(reservation) ? reservation[0] : reservation
return res?.status || "-"
}
return (
<div className="space-y-6">
<div>
<h2 className="text-3xl font-bold tracking-tight">Ödemeler</h2>
<p className="text-muted-foreground">Tüm alınan ödemelerin listesi.</p>
</div>
<div className="rounded-md border bg-card">
<Table>
<TableHeader>
<TableRow>
<TableHead>Tarih</TableHead>
<TableHead>Müşteri</TableHead>
<TableHead>Rez. Tarihi</TableHead>
<TableHead>Tutar</TableHead>
<TableHead>Ödeme Türü</TableHead>
<TableHead>Ödeme Yöntemi</TableHead>
<TableHead>Ödeme Durumu</TableHead>
<TableHead>Rez. Durumu</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{payments?.length === 0 ? (
<TableRow>
<TableCell colSpan={8} className="text-center h-24 text-muted-foreground">
Henüz ödeme kaydı yok.
</TableCell>
</TableRow>
) : (
payments?.map((payment: any) => (
<TableRow key={payment.id}>
<TableCell className="font-medium">
{format(new Date(payment.created_at), 'd MMMM yyyy HH:mm', { locale: tr })}
</TableCell>
<TableCell>{getCustomerName(payment.reservations)}</TableCell>
<TableCell>{getReservationDate(payment.reservations)}</TableCell>
<TableCell>{Number(payment.amount).toLocaleString('tr-TR')}</TableCell>
<TableCell className="capitalize">
{payment.payment_type === 'deposit' ? 'Kapora' :
payment.payment_type === 'full' ? 'Tam Ödeme' :
payment.payment_type === 'remaining' ? 'Kalan' : payment.payment_type}
</TableCell>
<TableCell className="capitalize">{payment.payment_method === 'credit_card' ? 'Kredi Kartı' : payment.payment_method === 'cash' ? 'Nakit' : 'Havale/EFT'}</TableCell>
<TableCell>{getStatusBadge(payment.status)}</TableCell>
<TableCell>{getStatusBadge(getReservationStatus(payment.reservations))}</TableCell>
</TableRow>
))
)}
</TableBody>
<TableFooter>
<TableRow>
<TableCell colSpan={3} className="font-bold text-right">Toplam:</TableCell>
<TableCell className="font-bold">
{payments?.reduce((sum: number, p: any) => sum + Number(p.amount), 0).toLocaleString('tr-TR')}
</TableCell>
<TableCell colSpan={4}></TableCell>
</TableRow>
</TableFooter>
</Table>
</div>
</div>
)
}

View File

@@ -29,7 +29,7 @@ export default async function ReservationsPage() {
customers (full_name),
packages (name, price)
`)
.order('start_time', { ascending: true })
.order('created_at', { ascending: false })
const getStatusBadge = (status: string) => {
switch (status) {