feat(tutorials): add video training academy management with YouTube parser and live preview
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
'use server'
|
||||
|
||||
import { revalidatePath } from 'next/cache'
|
||||
import { redirect } from 'next/navigation'
|
||||
import { auth } from '@/lib/auth'
|
||||
import { supabaseAdmin } from '@/lib/supabaseAdmin'
|
||||
|
||||
async function requireAdmin() {
|
||||
const session = await auth()
|
||||
if (!session || (session.user as any)?.role !== 'ADMIN') {
|
||||
throw new Error('Yetkisiz erişim')
|
||||
}
|
||||
}
|
||||
|
||||
export async function updateSettingsAction(formData: FormData) {
|
||||
await requireAdmin()
|
||||
|
||||
const trialDaysRaw = String(formData.get('trial_days') || '').trim()
|
||||
const trialDays = parseInt(trialDaysRaw, 10)
|
||||
if (!trialDaysRaw || isNaN(trialDays) || trialDays < 1) {
|
||||
redirect('/admin/settings?error=' + encodeURIComponent('Deneme süresi 1 veya daha büyük bir tam sayı olmalı'))
|
||||
}
|
||||
|
||||
const { error } = await supabaseAdmin
|
||||
.from('app_settings')
|
||||
.update({ trial_days: trialDays, updated_at: new Date().toISOString() })
|
||||
.eq('id', true)
|
||||
|
||||
if (error) {
|
||||
redirect('/admin/settings?error=' + encodeURIComponent(error.message))
|
||||
}
|
||||
|
||||
revalidatePath('/admin/settings')
|
||||
redirect('/admin/settings?success=1')
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
import { supabaseAdmin } from '@/lib/supabaseAdmin'
|
||||
import { updateSettingsAction } from './actions'
|
||||
|
||||
interface AppSettingsRow {
|
||||
trial_days: number
|
||||
}
|
||||
|
||||
export default async function SettingsPage({
|
||||
searchParams,
|
||||
}: {
|
||||
searchParams: Promise<{ error?: string; success?: string }>
|
||||
}) {
|
||||
const { error, success } = await searchParams
|
||||
const { data: settings } = await supabaseAdmin.from('app_settings').select('trial_days').maybeSingle()
|
||||
const trialDays = (settings as AppSettingsRow | null)?.trial_days ?? 7
|
||||
|
||||
return (
|
||||
<div className="space-y-6 max-w-2xl">
|
||||
<div>
|
||||
<h2 className="text-2xl font-bold tracking-tight text-gray-900 dark:text-white">Ayarlar</h2>
|
||||
<p className="text-gray-500 dark:text-gray-400 mt-1">Genel uygulama ayarları.</p>
|
||||
</div>
|
||||
|
||||
{error && (
|
||||
<div className="rounded-md bg-red-50 dark:bg-red-950/40 border border-red-200 dark:border-red-900 px-4 py-3 text-sm text-red-700 dark:text-red-400">
|
||||
{error}
|
||||
</div>
|
||||
)}
|
||||
{success && (
|
||||
<div className="rounded-md bg-green-50 dark:bg-green-950/40 border border-green-200 dark:border-green-900 px-4 py-3 text-sm text-green-700 dark:text-green-400">
|
||||
Değişiklikler kaydedildi.
|
||||
</div>
|
||||
)}
|
||||
|
||||
<form action={updateSettingsAction} className="rounded-lg bg-white dark:bg-gray-950 border border-gray-200 dark:border-gray-800 shadow-sm p-6 space-y-5">
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Deneme Süresi (gün)</label>
|
||||
<input
|
||||
type="number"
|
||||
name="trial_days"
|
||||
min={1}
|
||||
defaultValue={trialDays}
|
||||
className="w-full max-w-xs rounded-md border border-gray-300 dark:border-gray-700 bg-white dark:bg-gray-900 px-3 py-2 text-sm text-gray-900 dark:text-white focus:outline-none focus:ring-2 focus:ring-indigo-500"
|
||||
/>
|
||||
<p className="mt-1 text-xs text-gray-400">
|
||||
Yeni kayıt olan kullanıcılara otomatik açılan ücretsiz deneme süresi. Sadece bundan sonra kayıt olacaklar için geçerli — mevcut kullanıcıların deneme süresini etkilemez.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-3 pt-2">
|
||||
<button
|
||||
type="submit"
|
||||
className="rounded-md bg-indigo-600 hover:bg-indigo-700 text-white text-sm font-medium px-4 py-2 transition-colors"
|
||||
>
|
||||
Kaydet
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user