Site Yönetimi,Kullanıcı Girişi,Karanlık mod özellikleri db bağlantıları.
This commit is contained in:
33
app/(dashboard)/dashboard/products/[productId]/page.tsx
Normal file
33
app/(dashboard)/dashboard/products/[productId]/page.tsx
Normal file
@@ -0,0 +1,33 @@
|
||||
import { createClient } from "@/lib/supabase-server"
|
||||
import { ProductForm } from "@/components/dashboard/product-form"
|
||||
import { notFound } from "next/navigation"
|
||||
|
||||
interface ProductEditPageProps {
|
||||
params: {
|
||||
productId: string
|
||||
}
|
||||
}
|
||||
|
||||
export default async function ProductEditPage({ params }: ProductEditPageProps) {
|
||||
const supabase = createClient()
|
||||
const { data: product } = await supabase
|
||||
.from("products")
|
||||
.select("*")
|
||||
.eq("id", params.productId)
|
||||
.single()
|
||||
|
||||
if (!product) {
|
||||
notFound()
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex-1 space-y-4 p-8 pt-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<h2 className="text-3xl font-bold tracking-tight">Ürün Düzenle</h2>
|
||||
</div>
|
||||
<div className="max-w-2xl">
|
||||
<ProductForm initialData={product} />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
51
app/(dashboard)/dashboard/products/actions.ts
Normal file
51
app/(dashboard)/dashboard/products/actions.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
"use server"
|
||||
|
||||
import { createClient } from "@/lib/supabase-server"
|
||||
import { revalidatePath } from "next/cache"
|
||||
|
||||
export async function createProduct(data: any) {
|
||||
const supabase = createClient()
|
||||
|
||||
// Validate data manually or use Zod schema here again securely
|
||||
// For simplicity, we assume data is coming from the strongly typed Client Form
|
||||
// In production, ALWAYS validate server-side strictly.
|
||||
|
||||
try {
|
||||
const { error } = await supabase.from("products").insert({
|
||||
name: data.name,
|
||||
category: data.category,
|
||||
description: data.description,
|
||||
price: data.price,
|
||||
image_url: data.image_url,
|
||||
})
|
||||
|
||||
if (error) throw error
|
||||
|
||||
revalidatePath("/dashboard/products")
|
||||
return { success: true }
|
||||
} catch (error: any) {
|
||||
return { success: false, error: error.message }
|
||||
}
|
||||
}
|
||||
|
||||
export async function updateProduct(id: number, data: any) {
|
||||
const supabase = createClient()
|
||||
|
||||
try {
|
||||
const { error } = await supabase.from("products").update({
|
||||
name: data.name,
|
||||
category: data.category,
|
||||
description: data.description,
|
||||
price: data.price,
|
||||
image_url: data.image_url,
|
||||
}).eq("id", id)
|
||||
|
||||
if (error) throw error
|
||||
|
||||
revalidatePath("/dashboard/products")
|
||||
revalidatePath(`/dashboard/products/${id}`)
|
||||
return { success: true }
|
||||
} catch (error: any) {
|
||||
return { success: false, error: error.message }
|
||||
}
|
||||
}
|
||||
14
app/(dashboard)/dashboard/products/new/page.tsx
Normal file
14
app/(dashboard)/dashboard/products/new/page.tsx
Normal file
@@ -0,0 +1,14 @@
|
||||
import { ProductForm } from "@/components/dashboard/product-form"
|
||||
|
||||
export default function NewProductPage() {
|
||||
return (
|
||||
<div className="flex-1 space-y-4 p-8 pt-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<h2 className="text-3xl font-bold tracking-tight">Yeni Ürün Ekle</h2>
|
||||
</div>
|
||||
<div className="max-w-2xl">
|
||||
<ProductForm />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
75
app/(dashboard)/dashboard/products/page.tsx
Normal file
75
app/(dashboard)/dashboard/products/page.tsx
Normal file
@@ -0,0 +1,75 @@
|
||||
import { createClient } from "@/lib/supabase-server"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableHead,
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from "@/components/ui/table"
|
||||
import { Plus } from "lucide-react"
|
||||
import Link from "next/link"
|
||||
import { Badge } from "@/components/ui/badge"
|
||||
|
||||
export default async function ProductsPage() {
|
||||
const supabase = createClient()
|
||||
const { data: products } = await supabase
|
||||
.from("products")
|
||||
.select("*")
|
||||
.order("created_at", { ascending: false })
|
||||
|
||||
return (
|
||||
<div className="flex-1 space-y-4 p-8 pt-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<h2 className="text-3xl font-bold tracking-tight">Ürünler</h2>
|
||||
<div className="flex items-center space-x-2">
|
||||
<Link href="/dashboard/products/new">
|
||||
<Button>
|
||||
<Plus className="mr-2 h-4 w-4" /> Yeni Ekle
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="border rounded-md">
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>Ad</TableHead>
|
||||
<TableHead>Kategori</TableHead>
|
||||
<TableHead>Fiyat</TableHead>
|
||||
<TableHead className="text-right">İşlemler</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{products?.length === 0 ? (
|
||||
<TableRow>
|
||||
<TableCell colSpan={4} className="h-24 text-center">
|
||||
Henüz ürün eklenmemiş.
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
) : (
|
||||
products?.map((product) => (
|
||||
<TableRow key={product.id}>
|
||||
<TableCell className="font-medium">{product.name}</TableCell>
|
||||
<TableCell>
|
||||
<Badge variant="secondary" className="capitalize">
|
||||
{product.category}
|
||||
</Badge>
|
||||
</TableCell>
|
||||
<TableCell>₺{product.price}</TableCell>
|
||||
<TableCell className="text-right">
|
||||
<Link href={`/dashboard/products/${product.id}`}>
|
||||
<Button variant="ghost" size="sm">Düzenle</Button>
|
||||
</Link>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))
|
||||
)}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user