feat(tutorials): add video training academy management with YouTube parser and live preview
This commit is contained in:
@@ -0,0 +1,143 @@
|
||||
'use server'
|
||||
|
||||
import { revalidatePath } from 'next/cache'
|
||||
import { auth } from '@/lib/auth'
|
||||
import { supabaseAdmin } from '@/lib/supabaseAdmin'
|
||||
import { extractYoutubeId } from './utils'
|
||||
|
||||
async function requireAdmin() {
|
||||
const session = await auth()
|
||||
if (!session || (session.user as any)?.role !== 'ADMIN') {
|
||||
throw new Error('Yetkisiz erişim')
|
||||
}
|
||||
}
|
||||
|
||||
export async function createTutorialAction(formData: FormData) {
|
||||
await requireAdmin()
|
||||
|
||||
const title = String(formData.get('title') || '').trim()
|
||||
const description = String(formData.get('description') || '').trim()
|
||||
const category = String(formData.get('category') || 'basics').trim()
|
||||
const categoryLabel = String(formData.get('category_label') || '🚀 Hızlı Başlangıç').trim()
|
||||
const duration = String(formData.get('duration') || '03:00').trim()
|
||||
const rawYoutube = String(formData.get('youtube_id') || '').trim()
|
||||
const youtubeId = extractYoutubeId(rawYoutube)
|
||||
const targetView = String(formData.get('target_view') || '').trim() || null
|
||||
const targetViewLabel = String(formData.get('target_view_label') || '').trim() || null
|
||||
const highlightsRaw = String(formData.get('highlights') || '').trim()
|
||||
const sortOrder = parseInt(String(formData.get('sort_order') || '0'), 10) || 0
|
||||
const isActive = formData.get('is_active') === 'on' || formData.get('is_active') === 'true'
|
||||
|
||||
const highlights = highlightsRaw
|
||||
? highlightsRaw.split('\n').map((s) => s.trim()).filter(Boolean)
|
||||
: []
|
||||
|
||||
if (!title) throw new Error('Video başlığı zorunludur')
|
||||
if (!youtubeId) throw new Error('Geçerli bir YouTube video linki veya ID giriniz')
|
||||
|
||||
const { error } = await supabaseAdmin.from('tutorials').insert({
|
||||
title,
|
||||
description,
|
||||
category,
|
||||
category_label: categoryLabel,
|
||||
duration,
|
||||
youtube_id: youtubeId,
|
||||
target_view: targetView,
|
||||
target_view_label: targetViewLabel,
|
||||
highlights,
|
||||
sort_order: sortOrder,
|
||||
is_active: isActive,
|
||||
created_at: new Date().toISOString(),
|
||||
updated_at: new Date().toISOString(),
|
||||
})
|
||||
|
||||
if (error) {
|
||||
throw new Error(`Kayıt hatası: ${error.message}`)
|
||||
}
|
||||
|
||||
revalidatePath('/admin/tutorials')
|
||||
return { success: true }
|
||||
}
|
||||
|
||||
export async function updateTutorialAction(formData: FormData) {
|
||||
await requireAdmin()
|
||||
|
||||
const id = String(formData.get('id') || '').trim()
|
||||
if (!id) throw new Error('Video ID eksik')
|
||||
|
||||
const title = String(formData.get('title') || '').trim()
|
||||
const description = String(formData.get('description') || '').trim()
|
||||
const category = String(formData.get('category') || 'basics').trim()
|
||||
const categoryLabel = String(formData.get('category_label') || '🚀 Hızlı Başlangıç').trim()
|
||||
const duration = String(formData.get('duration') || '03:00').trim()
|
||||
const rawYoutube = String(formData.get('youtube_id') || '').trim()
|
||||
const youtubeId = extractYoutubeId(rawYoutube)
|
||||
const targetView = String(formData.get('target_view') || '').trim() || null
|
||||
const targetViewLabel = String(formData.get('target_view_label') || '').trim() || null
|
||||
const highlightsRaw = String(formData.get('highlights') || '').trim()
|
||||
const sortOrder = parseInt(String(formData.get('sort_order') || '0'), 10) || 0
|
||||
const isActive = formData.get('is_active') === 'on' || formData.get('is_active') === 'true'
|
||||
|
||||
const highlights = highlightsRaw
|
||||
? highlightsRaw.split('\n').map((s) => s.trim()).filter(Boolean)
|
||||
: []
|
||||
|
||||
if (!title) throw new Error('Video başlığı zorunludur')
|
||||
if (!youtubeId) throw new Error('Geçerli bir YouTube video linki veya ID giriniz')
|
||||
|
||||
const { error } = await supabaseAdmin
|
||||
.from('tutorials')
|
||||
.update({
|
||||
title,
|
||||
description,
|
||||
category,
|
||||
category_label: categoryLabel,
|
||||
duration,
|
||||
youtube_id: youtubeId,
|
||||
target_view: targetView,
|
||||
target_view_label: targetViewLabel,
|
||||
highlights,
|
||||
sort_order: sortOrder,
|
||||
is_active: isActive,
|
||||
updated_at: new Date().toISOString(),
|
||||
})
|
||||
.eq('id', id)
|
||||
|
||||
if (error) {
|
||||
throw new Error(`Güncelleme hatası: ${error.message}`)
|
||||
}
|
||||
|
||||
revalidatePath('/admin/tutorials')
|
||||
return { success: true }
|
||||
}
|
||||
|
||||
export async function deleteTutorialAction(id: string) {
|
||||
await requireAdmin()
|
||||
|
||||
if (!id) throw new Error('Video ID eksik')
|
||||
|
||||
const { error } = await supabaseAdmin.from('tutorials').delete().eq('id', id)
|
||||
|
||||
if (error) {
|
||||
throw new Error(`Silme hatası: ${error.message}`)
|
||||
}
|
||||
|
||||
revalidatePath('/admin/tutorials')
|
||||
return { success: true }
|
||||
}
|
||||
|
||||
export async function toggleTutorialStatusAction(id: string, newStatus: boolean) {
|
||||
await requireAdmin()
|
||||
|
||||
const { error } = await supabaseAdmin
|
||||
.from('tutorials')
|
||||
.update({ is_active: newStatus, updated_at: new Date().toISOString() })
|
||||
.eq('id', id)
|
||||
|
||||
if (error) {
|
||||
throw new Error(`Durum güncelleme hatası: ${error.message}`)
|
||||
}
|
||||
|
||||
revalidatePath('/admin/tutorials')
|
||||
return { success: true }
|
||||
}
|
||||
Reference in New Issue
Block a user