diff --git a/app/(dashboard)/dashboard/settings/actions.ts b/app/(dashboard)/dashboard/settings/actions.ts
deleted file mode 100644
index f26c8da..0000000
--- a/app/(dashboard)/dashboard/settings/actions.ts
+++ /dev/null
@@ -1,42 +0,0 @@
-"use server"
-
-import { createClient } from "@/lib/supabase-server"
-import { revalidatePath } from "next/cache"
-
-export async function updateSiteSettings(data: {
- site_title: string
- site_description: string
- contact_email: string
- contact_phone: string
- currency: string
-}) {
- const supabase = createClient()
-
- // Check admin is already handled by RLS on database level, but we can double check here
- const { data: { user } } = await supabase.auth.getUser()
- if (!user) return { error: "Oturum açmanız gerekiyor." }
-
- // We update the single row where id is likely 1 or just the first row
- // Since we initialized it with one row, we can just update match on something true or fetch id first.
- // Easier: Update all rows (there should only be one) or fetch the specific ID first.
-
- // Let's first get the ID just to be precise
- const { data: existing } = await supabase.from('site_settings').select('id').single()
-
- if (!existing) {
- return { error: "Ayarlar bulunamadı." }
- }
-
- const { error } = await supabase
- .from('site_settings')
- .update(data)
- .eq('id', existing.id)
-
- if (error) {
- return { error: "Ayarlar güncellenemedi: " + error.message }
- }
-
- revalidatePath("/dashboard/settings")
- revalidatePath("/") // Revalidate home as it might use these settings
- return { success: true }
-}
diff --git a/app/(dashboard)/dashboard/settings/page.tsx b/app/(dashboard)/dashboard/settings/page.tsx
index f5d1745..7ee1968 100644
--- a/app/(dashboard)/dashboard/settings/page.tsx
+++ b/app/(dashboard)/dashboard/settings/page.tsx
@@ -1,28 +1,62 @@
import { createClient } from "@/lib/supabase-server"
import { SettingsTabs } from "@/components/dashboard/settings-tabs"
import { getSmsSettings } from "@/lib/sms/actions"
+import { SiteContent } from "@/types/cms"
export default async function SettingsPage() {
const supabase = createClient()
- // Fetch site settings
- const { data: siteSettings } = await supabase
- .from('site_settings')
- .select('*')
- .single()
-
- // Fetch SMS settings (server-side call to our action/db)
- // Note: getSmsSettings is an action that checks for admin, which is fine.
- // However, since we are in a server component with a Supabase client, we could also fetch directly if we had admin client.
- // But let's use the clean action or direct logic.
- // Actually, calling server action from server component is fine, but we need to handle the return structure.
+ // Fetch SMS settings
const smsResponse = await getSmsSettings()
const smsSettings = smsResponse.data || null
+ // Fetch Users (Profiles)
+ const { data: profiles } = await supabase
+ .from("profiles")
+ .select("*")
+ .order("created_at", { ascending: false })
+
+ // Fetch Site Contents (CMS)
+ const { data: contents } = await supabase
+ .from('site_contents')
+ .select('*')
+ .order('key')
+
+ // Define default contents for CMS
+ const DEFAULT_CONTENTS: SiteContent[] = [
+ // General
+ { key: 'site_title', value: 'ParaKasa', type: 'text', section: 'general' },
+ { key: 'site_description', value: '', type: 'long_text', section: 'general' },
+ { key: 'site_logo', value: '', type: 'image_url', section: 'general' },
+
+ // Contact
+ { key: 'contact_phone', value: '', type: 'text', section: 'contact' },
+ { key: 'contact_email', value: '', type: 'text', section: 'contact' },
+ { key: 'contact_address', value: '', type: 'long_text', section: 'contact' },
+ { key: 'social_instagram', value: '', type: 'text', section: 'contact' },
+ { key: 'social_youtube', value: '', type: 'text', section: 'contact' },
+ { key: 'social_tiktok', value: '', type: 'text', section: 'contact' },
+ { key: 'contact_map_embed', value: '', type: 'html', section: 'contact' },
+ ]
+
+ // Merge default contents with existing contents
+ const mergedContents = [...(contents as SiteContent[] || [])]
+ const existingKeys = new Set(mergedContents.map(c => c.key))
+
+ DEFAULT_CONTENTS.forEach(item => {
+ if (!existingKeys.has(item.key)) {
+ mergedContents.push(item)
+ }
+ })
+
return (
Ayarlar
-
+
)
}
diff --git a/app/layout.tsx b/app/layout.tsx
index e5e36e9..4e0c429 100644
--- a/app/layout.tsx
+++ b/app/layout.tsx
@@ -6,14 +6,14 @@ import "./globals.css";
const inter = Inter({ subsets: ["latin"] });
const outfit = Outfit({ subsets: ["latin"], variable: "--font-outfit" });
-import { getSiteSettings } from "@/lib/site-settings";
+import { getSiteContents } from "@/lib/data";
export async function generateMetadata() {
- const settings = await getSiteSettings();
+ const settings = await getSiteContents();
return {
- title: settings?.site_title || "ParaKasa - Premium Çelik Kasalar",
- description: settings?.site_description || "Eviniz ve iş yeriniz için en yüksek güvenlikli çelik kasa ve para sayma çözümleri.",
+ title: settings.site_title || "ParaKasa - Premium Çelik Kasalar",
+ description: settings.site_description || "Eviniz ve iş yeriniz için en yüksek güvenlikli çelik kasa ve para sayma çözümleri.",
};
}
diff --git a/components/dashboard/settings-tabs.tsx b/components/dashboard/settings-tabs.tsx
index 5afe841..24be725 100644
--- a/components/dashboard/settings-tabs.tsx
+++ b/components/dashboard/settings-tabs.tsx
@@ -1,32 +1,56 @@
"use client"
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
-import { SiteSettingsForm, SettingsFormValues } from "@/components/dashboard/site-settings-form"
import { SmsSettingsForm } from "@/components/dashboard/sms-settings-form"
import { AppearanceForm } from "@/components/dashboard/appearance-form"
+import { UsersTable } from "@/components/dashboard/users-table"
+import { ContentForm } from "@/components/dashboard/content-form"
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
import { Button } from "@/components/ui/button"
+import { SiteContent } from "@/types/cms"
interface SettingsTabsProps {
- siteSettings: Partial | null
smsSettings: {
username: string
header: string
} | null
+ users: any[]
+ contents: SiteContent[]
}
-export function SettingsTabs({ siteSettings, smsSettings }: SettingsTabsProps) {
+export function SettingsTabs({ smsSettings, users, contents }: SettingsTabsProps) {
return (
-
-
- Genel
+
+
+ İçerik Yönetimi
+ Kullanıcılar
SMS / Bildirimler
Görünüm
Güvenlik
-
-
+
+
+
+
Site İçerik Yönetimi
+
+ Site genel ayarları, iletişim bilgileri ve logolar.
+
+
+
+
+
+
+
+
+
+
Kullanıcı Yönetimi
+
+ Sistemdeki kayıtlı kullanıcıları ve rollerini yönetin.
+
+
+
+
diff --git a/components/dashboard/sidebar.tsx b/components/dashboard/sidebar.tsx
index 65596eb..9a7e3a5 100644
--- a/components/dashboard/sidebar.tsx
+++ b/components/dashboard/sidebar.tsx
@@ -3,7 +3,7 @@
import Link from "next/link"
import { usePathname } from "next/navigation"
import { cn } from "@/lib/utils"
-import { LayoutDashboard, Package, ShoppingCart, Users, Settings, Globe, Tags, FileText } from "lucide-react"
+import { LayoutDashboard, Package, ShoppingCart, Settings, Globe, Tags } from "lucide-react"
const sidebarItems = [
{
@@ -26,16 +26,6 @@ const sidebarItems = [
href: "/dashboard/categories",
icon: Tags,
},
- {
- title: "Kullanıcılar",
- href: "/dashboard/users",
- icon: Users,
- },
- {
- title: "İçerik Yönetimi",
- href: "/dashboard/cms/content",
- icon: FileText,
- },
{
title: "Ayarlar",
href: "/dashboard/settings",
diff --git a/components/dashboard/site-settings-form.tsx b/components/dashboard/site-settings-form.tsx
deleted file mode 100644
index 7f4d8a5..0000000
--- a/components/dashboard/site-settings-form.tsx
+++ /dev/null
@@ -1,163 +0,0 @@
-"use client"
-
-import { useState } from "react"
-import { useRouter } from "next/navigation"
-import { useForm } from "react-hook-form"
-import { zodResolver } from "@hookform/resolvers/zod"
-import * as z from "zod"
-import { Button } from "@/components/ui/button"
-import { Input } from "@/components/ui/input"
-import { Textarea } from "@/components/ui/textarea"
-import {
- Form,
- FormControl,
- FormDescription,
- FormField,
- FormItem,
- FormLabel,
- FormMessage,
-} from "@/components/ui/form"
-import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
-import { toast } from "sonner"
-import { Loader2 } from "lucide-react"
-import { updateSiteSettings } from "@/app/(dashboard)/dashboard/settings/actions"
-
-const settingsSchema = z.object({
- site_title: z.string().min(2, "Site başlığı en az 2 karakter olmalıdır."),
- site_description: z.string(),
- contact_email: z.literal("").or(z.string().email("Geçerli bir e-posta adresi giriniz.")),
- contact_phone: z.string(),
- currency: z.string(),
-})
-
-export type SettingsFormValues = z.infer
-
-interface SiteSettingsFormProps {
- initialData: Partial | null
-}
-
-export function SiteSettingsForm({ initialData }: SiteSettingsFormProps) {
- const router = useRouter()
- const [loading, setLoading] = useState(false)
-
- const form = useForm({
- resolver: zodResolver(settingsSchema),
- defaultValues: {
- site_title: initialData?.site_title || "ParaKasa",
- site_description: initialData?.site_description || "",
- contact_email: initialData?.contact_email || "",
- contact_phone: initialData?.contact_phone || "",
- currency: initialData?.currency || "TRY",
- },
- })
-
- const onSubmit = async (data: SettingsFormValues) => {
- setLoading(true)
- try {
- const result = await updateSiteSettings(data)
-
- if (result.error) {
- toast.error(result.error)
- return
- }
-
- toast.success("Site ayarları güncellendi.")
- router.refresh()
- } catch {
- toast.error("Bir sorun oluştu.")
- } finally {
- setLoading(false)
- }
- }
-
- return (
-
-
- Genel Ayarlar
- Web sitesinin genel yapılandırma ayarları.
-
-
-
-
-
-
- )
-}
diff --git a/components/dashboard/users-table.tsx b/components/dashboard/users-table.tsx
new file mode 100644
index 0000000..b681a0a
--- /dev/null
+++ b/components/dashboard/users-table.tsx
@@ -0,0 +1,69 @@
+"use client"
+
+import { Button } from "@/components/ui/button"
+import Link from "next/link"
+import {
+ Table,
+ TableBody,
+ TableCell,
+ TableHead,
+ TableHeader,
+ TableRow,
+} from "@/components/ui/table"
+import { Badge } from "@/components/ui/badge"
+
+interface Profile {
+ id: string
+ full_name: string
+ role: string
+ created_at: string
+}
+
+interface UsersTableProps {
+ users: Profile[]
+}
+
+export function UsersTable({ users }: UsersTableProps) {
+ return (
+
+
+
Kullanıcı Listesi
+ {/*
+
+
+
+ */}
+
+
+
+
+
+ Ad Soyad
+ Rol
+ Kayıt Tarihi
+ İşlemler
+
+
+
+ {users?.map((profile) => (
+
+ {profile.full_name}
+
+
+ {profile.role === 'admin' ? 'Yönetici' : 'Kullanıcı'}
+
+
+ {new Date(profile.created_at).toLocaleDateString('tr-TR')}
+
+
+
+
+
+
+ ))}
+
+
+
+
+ )
+}
diff --git a/drop_site_settings.sql b/drop_site_settings.sql
new file mode 100644
index 0000000..c2fd82e
--- /dev/null
+++ b/drop_site_settings.sql
@@ -0,0 +1,2 @@
+-- Drop the site_settings table as it is replaced by site_contents
+DROP TABLE IF EXISTS site_settings;
diff --git a/lib/site-settings.ts b/lib/site-settings.ts
deleted file mode 100644
index 46585da..0000000
--- a/lib/site-settings.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import { createClient } from "@/lib/supabase-server"
-import { cache } from "react"
-
-export const getSiteSettings = cache(async () => {
- const supabase = createClient()
- const { data } = await supabase.from('site_settings').select('*').single()
- return data
-})