feat: integrate Cloudinary image upload, Instagram Feed, and fix Next.js warnings
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
import { getAboutSettings } from "@/app/actions/about";
|
||||
import AboutClient from "@/components/admin/AboutClient";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
export default async function AboutPage() {
|
||||
const result = await getAboutSettings();
|
||||
|
||||
const settings = result.success && result.data ? result.data : {
|
||||
title: "Sonsuz Mavilikte Bir Kaçış",
|
||||
description: "Kozmos Beach & More, denizin esintisiyle doğanın ritmini bir araya getiren eşsiz bir deneyim sunuyor. Gündüz güneşin ve berrak denizin tadını çıkarırken, gün batımıyla birlikte DJ performansları ve özel kokteyller eşliğinde unutulmaz anılar biriktirin.",
|
||||
card1Title: "Kusursuz Sahil",
|
||||
card1Desc: "İncecik altın kumu ve turkuaz sularıyla kendinizi tamamen yenileyin.",
|
||||
card2Title: "Gastronomi",
|
||||
card2Desc: "Dünya mutfağından özenle seçilmiş lezzetler ve imza kokteyller.",
|
||||
card3Title: "Canlı Eğlence",
|
||||
card3Desc: "Her akşam gün batımında başlayan benzersiz DJ performansları.",
|
||||
image: "https://images.unsplash.com/photo-1544148103-0773bf10d330?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80",
|
||||
};
|
||||
|
||||
return <AboutClient settings={settings as any} />;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
import { getAdmins } from "@/app/actions/admin";
|
||||
import AdminsClient from "@/components/admin/AdminsClient";
|
||||
|
||||
// Vercel / Next.js için dinamik rendering (cache'lemeyi kapatmak için)
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
export default async function AdminsPage() {
|
||||
const result = await getAdmins();
|
||||
const admins = result.success && result.data ? result.data : [];
|
||||
|
||||
return <AdminsClient initialAdmins={admins} />;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import { getBeachSettings } from "@/app/actions/beach";
|
||||
import BeachClient from "@/components/admin/BeachClient";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
export default async function BeachPage() {
|
||||
const result = await getBeachSettings();
|
||||
|
||||
// result.data will always be populated if success because we upsert "default"
|
||||
const settings = result.success && result.data ? result.data : {
|
||||
title: "Ayrıcalıklı Bir Gevşeme Alanı",
|
||||
description: "Tertemiz sularla buluşan özel plajımız, kendinizi tamamen yenileyebilmeniz için rahatlığın merkezinde. Altın kumların ve berrak denizin tadını çıkarırken, dünya standartlarındaki hizmetimizle her anınızın özel hissettirmesini sağlıyoruz.",
|
||||
reservationInfo: "VIP cabana ve ön sıra şezlonglar yoğun talep görmektedir. Yeriniz garantilemek için en az bir gün önceden bizimle iletişime geçmenizi öneririz.",
|
||||
image1: "https://images.unsplash.com/photo-1544148103-0773bf10d330?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80",
|
||||
image2: "https://images.unsplash.com/photo-1519046904884-53103b34b206?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80",
|
||||
image3: "https://images.unsplash.com/photo-1499793983690-e29da59ef1c2?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80",
|
||||
image4: "https://images.unsplash.com/photo-1520250497591-112f2f40a3f4?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80",
|
||||
};
|
||||
|
||||
return <BeachClient settings={settings as any} />;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
import { getContactSettings } from "@/app/actions/contact";
|
||||
import ContactClient from "@/components/admin/ContactClient";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
export default async function ContactPage() {
|
||||
const result = await getContactSettings();
|
||||
|
||||
// result.data will always be populated if success because we upsert "default"
|
||||
const settings = result.success && result.data ? result.data : {
|
||||
address: "Akyaka, Gökova Körfezi, Muğla",
|
||||
phone: "905000000000",
|
||||
instagram: "https://www.instagram.com/kozmosbeach/",
|
||||
mapUrl: "https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d12754.717654763133!2d28.3144!3d36.9507!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x14bf76ccf312ba37%3A0xcdaaa97b102b4bb7!2sAkyaka%2C%20Ula%2FMu%C4%9Fla!5e0!3m2!1str!2str!4v1700000000000!5m2!1str!2str"
|
||||
};
|
||||
|
||||
return <ContactClient settings={settings as any} />;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
import { getEvents } from "@/app/actions/events";
|
||||
import EventsClient from "@/components/admin/EventsClient";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
export default async function EventsPage() {
|
||||
const result = await getEvents();
|
||||
const events = result.success && result.data ? result.data : [];
|
||||
|
||||
// Data parsing for Client Component
|
||||
const parsedEvents = events.map(e => ({
|
||||
...e,
|
||||
createdAt: e.createdAt.toISOString(),
|
||||
updatedAt: e.updatedAt.toISOString(),
|
||||
}));
|
||||
|
||||
return <EventsClient initialEvents={parsedEvents as any} />;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
import { getGalleryImages } from "@/app/actions/gallery";
|
||||
import GalleryClient from "@/components/admin/GalleryClient";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
export default async function GalleryPage() {
|
||||
const result = await getGalleryImages();
|
||||
const images = result.success && result.data ? result.data : [];
|
||||
|
||||
// Data parsing for Client Component
|
||||
const parsedImages = images.map(img => ({
|
||||
...img,
|
||||
createdAt: img.createdAt.toISOString(),
|
||||
updatedAt: img.updatedAt.toISOString(),
|
||||
}));
|
||||
|
||||
return <GalleryClient initialImages={parsedImages as any} />;
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
import { Marcellus } from 'next/font/google';
|
||||
import '@/app/globals.css';
|
||||
import Link from 'next/link';
|
||||
import { Users, LayoutDashboard, LogOut } from 'lucide-react';
|
||||
|
||||
const marcellus = Marcellus({
|
||||
subsets: ['latin'],
|
||||
variable: '--font-marcellus',
|
||||
weight: ['400'],
|
||||
});
|
||||
|
||||
export const metadata = {
|
||||
title: 'Kozmos Admin',
|
||||
description: 'Kozmos Beach & More - Yönetim Paneli',
|
||||
};
|
||||
|
||||
export default function AdminLayout({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}) {
|
||||
return (
|
||||
<html lang="tr" className={`${marcellus.variable}`}>
|
||||
<body className="bg-gray-50 text-gray-900 font-body antialiased flex min-h-screen">
|
||||
|
||||
{/* Sidebar */}
|
||||
<aside className="w-64 bg-charcoal text-cream flex flex-col shadow-2xl">
|
||||
{/* Header */}
|
||||
<div className="p-6 border-b border-gray-700 flex items-center justify-center">
|
||||
<img src="/logo.png" alt="Kozmos Logo" className="h-12 brightness-0 invert opacity-90 object-contain" />
|
||||
</div>
|
||||
|
||||
<nav className="flex-1 p-4 space-y-2">
|
||||
<Link
|
||||
href="/admin"
|
||||
className="flex items-center gap-3 px-4 py-3 rounded-lg hover:bg-gray-800 transition-colors"
|
||||
>
|
||||
<LayoutDashboard className="w-5 h-5" />
|
||||
<span>Dashboard</span>
|
||||
</Link>
|
||||
|
||||
<Link
|
||||
href="/admin/admins"
|
||||
className="flex items-center gap-3 px-4 py-3 rounded-lg hover:bg-gray-800 transition-colors"
|
||||
>
|
||||
<Users className="w-5 h-5" />
|
||||
<span>Admin Yönetimi</span>
|
||||
</Link>
|
||||
|
||||
<Link
|
||||
href="/admin/events"
|
||||
className="flex items-center gap-3 px-4 py-3 rounded-lg hover:bg-gray-800 transition-colors"
|
||||
>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><rect x="3" y="4" width="18" height="18" rx="2" ry="2"></rect><line x1="16" y1="2" x2="16" y2="6"></line><line x1="8" y1="2" x2="8" y2="6"></line><line x1="3" y1="10" x2="21" y2="10"></line></svg>
|
||||
<span>Etkinlik Yönetimi</span>
|
||||
</Link>
|
||||
|
||||
<Link
|
||||
href="/admin/about"
|
||||
className="flex items-center gap-3 px-4 py-3 rounded-lg hover:bg-gray-800 transition-colors"
|
||||
>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="10"></circle><line x1="12" y1="16" x2="12" y2="12"></line><line x1="12" y1="8" x2="12.01" y2="8"></line></svg>
|
||||
<span>Hakkımızda Yönetimi</span>
|
||||
</Link>
|
||||
|
||||
<Link
|
||||
href="/admin/beach"
|
||||
className="flex items-center gap-3 px-4 py-3 rounded-lg hover:bg-gray-800 transition-colors"
|
||||
>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="10"></circle><path d="M12 2v20"></path><path d="M2 12h20"></path></svg>
|
||||
<span>Plaj Yönetimi</span>
|
||||
</Link>
|
||||
|
||||
<Link
|
||||
href="/admin/gallery"
|
||||
className="flex items-center gap-3 px-4 py-3 rounded-lg hover:bg-gray-800 transition-colors"
|
||||
>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect><circle cx="8.5" cy="8.5" r="1.5"></circle><polyline points="21 15 16 10 5 21"></polyline></svg>
|
||||
<span>Galeri Yönetimi</span>
|
||||
</Link>
|
||||
|
||||
<Link
|
||||
href="/admin/contact"
|
||||
className="flex items-center gap-3 px-4 py-3 rounded-lg hover:bg-gray-800 transition-colors"
|
||||
>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"></path><circle cx="12" cy="10" r="3"></circle></svg>
|
||||
<span>İletişim & Konum</span>
|
||||
</Link>
|
||||
</nav>
|
||||
|
||||
<div className="p-4 border-t border-gray-700 space-y-2">
|
||||
<a
|
||||
href="/"
|
||||
className="flex items-center gap-3 px-4 py-3 rounded-lg hover:bg-gray-800 transition-colors text-gray-400 hover:text-white"
|
||||
>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"></path><polyline points="9 22 9 12 15 12 15 22"></polyline></svg>
|
||||
<span>Siteye Git</span>
|
||||
</a>
|
||||
|
||||
<form action={async () => {
|
||||
"use server";
|
||||
const { logout } = await import("@/app/actions/auth");
|
||||
await logout();
|
||||
}}>
|
||||
<button
|
||||
type="submit"
|
||||
className="w-full flex items-center gap-3 px-4 py-3 rounded-lg hover:bg-red-900/50 transition-colors text-red-400 hover:text-red-300"
|
||||
>
|
||||
<LogOut className="w-5 h-5" />
|
||||
<span>Çıkış Yap</span>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
{/* Main Content */}
|
||||
<main className="flex-1 overflow-y-auto">
|
||||
{children}
|
||||
</main>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
export default function AdminDashboard() {
|
||||
return (
|
||||
<div className="p-8">
|
||||
<h1 className="text-3xl font-serif text-gray-900 mb-8">Dashboard</h1>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
|
||||
<div className="bg-white p-6 rounded-xl shadow-sm border border-gray-100">
|
||||
<h3 className="text-gray-500 text-sm font-medium mb-2">Sisteme Hoş Geldiniz</h3>
|
||||
<p className="text-2xl font-bold text-gray-900">Kozmos Yönetim Paneli</p>
|
||||
<p className="text-sm text-gray-500 mt-4">
|
||||
Sol menüden "Admin Yönetimi" kısmına giderek yeni yönetici ekleyebilir veya silebilirsiniz.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user