Sms Rehber eklemesi,Mobil uyumluluk ayarları,iletişim sayfası düzenlemeler vb.
This commit is contained in:
@@ -11,6 +11,7 @@ interface ProductData {
|
||||
image_url?: string
|
||||
is_active?: boolean
|
||||
images?: string[]
|
||||
product_code?: string
|
||||
}
|
||||
|
||||
export async function createProduct(data: ProductData) {
|
||||
@@ -24,7 +25,8 @@ export async function createProduct(data: ProductData) {
|
||||
description: data.description,
|
||||
price: data.price,
|
||||
image_url: data.image_url, // Main image (can be first of images)
|
||||
is_active: data.is_active ?? true
|
||||
is_active: data.is_active ?? true,
|
||||
product_code: data.product_code
|
||||
}).select().single()
|
||||
|
||||
if (error) throw error
|
||||
@@ -62,7 +64,8 @@ export async function updateProduct(id: number, data: ProductData) {
|
||||
description: data.description,
|
||||
price: data.price,
|
||||
image_url: data.image_url,
|
||||
is_active: data.is_active
|
||||
is_active: data.is_active,
|
||||
product_code: data.product_code
|
||||
}).eq("id", id)
|
||||
|
||||
if (error) throw error
|
||||
|
||||
@@ -32,7 +32,7 @@ export default async function ProductsPage() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="border rounded-md">
|
||||
<div className="border rounded-md overflow-x-auto">
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
|
||||
@@ -19,11 +19,11 @@ export default async function SmsLogsPage() {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex-1 space-y-4 p-8 pt-6">
|
||||
<h2 className="text-3xl font-bold tracking-tight">SMS Geçmişi</h2>
|
||||
<div className="flex-1 space-y-4 p-4 pt-6 md:p-8">
|
||||
<h2 className="text-2xl md:text-3xl font-bold tracking-tight">SMS Geçmişi</h2>
|
||||
<p className="text-muted-foreground">Son gönderilen mesajların durumu.</p>
|
||||
|
||||
<div className="rounded-md border">
|
||||
<div className="rounded-md border overflow-x-auto">
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
|
||||
27
app/(dashboard)/loading.tsx
Normal file
27
app/(dashboard)/loading.tsx
Normal file
@@ -0,0 +1,27 @@
|
||||
import { Skeleton } from "@/components/ui/skeleton"
|
||||
|
||||
export default function DashboardLoading() {
|
||||
return (
|
||||
<div className="flex flex-col space-y-6 p-8">
|
||||
<div className="flex items-center justify-between space-y-2">
|
||||
<div className="space-y-2">
|
||||
<Skeleton className="h-8 w-[200px]" />
|
||||
<Skeleton className="h-4 w-[300px]" />
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<Skeleton className="h-10 w-[120px]" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-4">
|
||||
<Skeleton className="h-[120px] rounded-xl" />
|
||||
<Skeleton className="h-[120px] rounded-xl" />
|
||||
<Skeleton className="h-[120px] rounded-xl" />
|
||||
<Skeleton className="h-[120px] rounded-xl" />
|
||||
</div>
|
||||
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-7">
|
||||
<Skeleton className="col-span-4 h-[400px] rounded-xl" />
|
||||
<Skeleton className="col-span-3 h-[400px] rounded-xl" />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -9,14 +9,14 @@ export default async function ContactPage() {
|
||||
|
||||
return (
|
||||
<div className="container py-12 md:py-24">
|
||||
<div className="text-center mb-12">
|
||||
<h1 className="text-4xl font-bold tracking-tight mb-4 font-outfit">İletişime Geçin</h1>
|
||||
<div className="text-center mb-8 md:mb-12">
|
||||
<h1 className="text-3xl md:text-4xl font-bold tracking-tight mb-4 font-outfit">İletişime Geçin</h1>
|
||||
<p className="text-muted-foreground max-w-xl mx-auto">
|
||||
Sorularınız, teklif talepleriniz veya teknik destek için bize ulaşın.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="grid md:grid-cols-2 gap-12 max-w-5xl mx-auto">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-8 md:gap-12 max-w-5xl mx-auto">
|
||||
<div className="space-y-8">
|
||||
<div className="space-y-6">
|
||||
<h2 className="text-2xl font-semibold">İletişim Bilgileri</h2>
|
||||
@@ -34,7 +34,12 @@ export default async function ContactPage() {
|
||||
<div>
|
||||
<p className="font-medium">Telefon</p>
|
||||
<p className="text-slate-600 dark:text-slate-400">
|
||||
{siteSettings.contact_phone || "+90 (212) 555 00 00"}
|
||||
<a
|
||||
href={`tel:${(siteSettings.contact_phone || "+90 (212) 555 00 00").replace(/[^\d+]/g, '')}`}
|
||||
className="hover:text-primary transition-colors hover:underline"
|
||||
>
|
||||
{siteSettings.contact_phone || "+90 (212) 555 00 00"}
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
33
app/(public)/loading.tsx
Normal file
33
app/(public)/loading.tsx
Normal file
@@ -0,0 +1,33 @@
|
||||
import { Skeleton } from "@/components/ui/skeleton"
|
||||
|
||||
export default function PublicLoading() {
|
||||
return (
|
||||
<div className="container py-12 md:py-24">
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-12">
|
||||
<div className="space-y-4">
|
||||
<Skeleton className="aspect-square w-full rounded-xl" />
|
||||
<div className="grid grid-cols-4 gap-4">
|
||||
<Skeleton className="aspect-square w-full rounded-xl" />
|
||||
<Skeleton className="aspect-square w-full rounded-xl" />
|
||||
<Skeleton className="aspect-square w-full rounded-xl" />
|
||||
<Skeleton className="aspect-square w-full rounded-xl" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-8">
|
||||
<div className="space-y-4">
|
||||
<Skeleton className="h-8 w-1/3" />
|
||||
<Skeleton className="h-12 w-2/3" />
|
||||
</div>
|
||||
<div className="space-y-4">
|
||||
<Skeleton className="h-4 w-full" />
|
||||
<Skeleton className="h-4 w-full" />
|
||||
<Skeleton className="h-4 w-3/4" />
|
||||
</div>
|
||||
<div className="space-y-4 pt-6">
|
||||
<Skeleton className="h-12 w-48" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
105
app/(public)/products/[id]/page.tsx
Normal file
105
app/(public)/products/[id]/page.tsx
Normal file
@@ -0,0 +1,105 @@
|
||||
import { createClient } from "@/lib/supabase-server"
|
||||
import { getSiteContents } from "@/lib/data"
|
||||
import { notFound } from "next/navigation"
|
||||
import Image from "next/image"
|
||||
import Link from "next/link"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Badge } from "@/components/ui/badge"
|
||||
import { Phone } from "lucide-react"
|
||||
import { ProductGallery } from "@/components/product/product-gallery"
|
||||
|
||||
async function getProduct(id: string) {
|
||||
const supabase = createClient()
|
||||
|
||||
// Fetch product
|
||||
const { data: product, error } = await supabase
|
||||
.from("products")
|
||||
.select("*")
|
||||
.eq("id", id)
|
||||
.eq("is_active", true)
|
||||
.single()
|
||||
|
||||
if (error || !product) {
|
||||
return null
|
||||
}
|
||||
|
||||
// Fetch images
|
||||
const { data: images } = await supabase
|
||||
.from("product_images")
|
||||
.select("*")
|
||||
.eq("product_id", id)
|
||||
.order("display_order", { ascending: true })
|
||||
|
||||
return { ...product, images: images || [] }
|
||||
}
|
||||
|
||||
export default async function ProductPage({ params }: { params: { id: string } }) {
|
||||
const product = await getProduct(params.id)
|
||||
const siteSettings = await getSiteContents()
|
||||
const whatsappPhone = siteSettings.contact_phone ? siteSettings.contact_phone.replace(/\s+/g, '') : "905555555555"
|
||||
|
||||
if (!product) {
|
||||
notFound()
|
||||
}
|
||||
|
||||
// Combine main image and gallery images for a full list, filtering duplicates if necessary
|
||||
// Logic: If gallery images exist, use them. If not, fallback to product.image_url.
|
||||
// If product.image_url is in product_images, we might duplicate, but let's just use all distinct.
|
||||
|
||||
let allImages: string[] = []
|
||||
if (product.images && product.images.length > 0) {
|
||||
allImages = product.images.map((img: { image_url: string }) => img.image_url)
|
||||
} else if (product.image_url) {
|
||||
allImages = [product.image_url]
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="container py-12 md:py-24">
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-12">
|
||||
{/* Image Gallery Section */}
|
||||
<ProductGallery images={allImages} productName={product.name} />
|
||||
|
||||
{/* Product Info Section */}
|
||||
<div className="space-y-8">
|
||||
<div>
|
||||
<div className="flex items-center gap-4 mb-2">
|
||||
<Badge variant="secondary" className="text-sm uppercase tracking-wider">
|
||||
{product.category}
|
||||
</Badge>
|
||||
{product.product_code && (
|
||||
<span className="text-sm font-semibold text-slate-500">
|
||||
Kod: {product.product_code}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<h1 className="text-4xl font-bold tracking-tight text-primary font-outfit mb-4">
|
||||
{product.name}
|
||||
</h1>
|
||||
{/* NO PRICE DISPLAY as requested */}
|
||||
</div>
|
||||
|
||||
<div className="prose prose-slate dark:prose-invert max-w-none">
|
||||
<h3 className="text-lg font-semibold mb-2">Ürün Açıklaması</h3>
|
||||
<p className="text-slate-600 dark:text-slate-300 leading-relaxed whitespace-pre-line">
|
||||
{product.description || "Bu ürün için henüz detaylı açıklama eklenmemiştir."}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="pt-6 border-t">
|
||||
<div className="flex flex-col sm:flex-row gap-4">
|
||||
<Button size="lg" className="w-full sm:w-auto" asChild>
|
||||
<Link href={`https://wa.me/${whatsappPhone}?text=Merhaba, ${product.name} (Kod: ${product.product_code || "Yok"}) hakkında bilgi almak istiyorum.`} target="_blank">
|
||||
<Phone className="mr-2 h-5 w-5" />
|
||||
WhatsApp ile Fiyat Sor
|
||||
</Link>
|
||||
</Button>
|
||||
</div>
|
||||
<p className="mt-4 text-sm text-slate-500">
|
||||
* Bu ürün hakkında detaylı bilgi ve fiyat teklifi almak için bizimle iletişime geçebilirsiniz.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
import { createClient } from "@/lib/supabase-server"
|
||||
import { Card, CardFooter, CardHeader, CardTitle } from "@/components/ui/card"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import Link from "next/link"
|
||||
import Image from "next/image"
|
||||
|
||||
|
||||
@@ -57,14 +58,20 @@ export default async function ProductsPage() {
|
||||
<div className="w-full">
|
||||
<div className="flex justify-between items-center w-full">
|
||||
<span className="text-xs font-medium text-slate-500 uppercase tracking-wider">{product.category}</span>
|
||||
<span className="font-bold text-lg text-primary">₺{product.price}</span>
|
||||
{product.product_code && (
|
||||
<span className="text-xs font-semibold text-slate-400">#{product.product_code}</span>
|
||||
)}
|
||||
</div>
|
||||
<CardTitle className="text-lg mt-1">{product.name}</CardTitle>
|
||||
</div>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardFooter className="p-4 pt-0">
|
||||
<Button className="w-full" variant="outline">Detayları İncele</Button>
|
||||
<Button className="w-full" variant="outline" asChild>
|
||||
<Link href={`/products/${product.id}`}>
|
||||
Detayları İncele
|
||||
</Link>
|
||||
</Button>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
))
|
||||
|
||||
Reference in New Issue
Block a user