685 lines
22 KiB
TypeScript
685 lines
22 KiB
TypeScript
"use server"
|
||
|
||
import { redirect } from "next/navigation"
|
||
|
||
import { mockDb } from '@/lib/mockDb'
|
||
import { uploadToOpeninary } from '@/lib/openinary'
|
||
import { revalidatePath } from 'next/cache'
|
||
|
||
export async function submitBusinessAction(formData: FormData) {
|
||
const businessName = formData.get('businessName') as string
|
||
const categoryId = formData.get('categoryId') as string
|
||
const neighborhoodId = formData.get('neighborhoodId') as string
|
||
const address = formData.get('address') as string
|
||
const phone = formData.get('phone') as string
|
||
const whatsapp = formData.get('whatsapp') as string
|
||
const description = formData.get('description') as string
|
||
const contactName = formData.get('contactName') as string
|
||
const contactEmail = formData.get('contactEmail') as string
|
||
const imageFile = formData.get('imageFile') as File | null
|
||
|
||
if (!businessName || !categoryId || !neighborhoodId || !address || !description || !contactName || !contactEmail) {
|
||
return { error: 'Lütfen tüm zorunlu alanları doldurun.' }
|
||
}
|
||
|
||
let imageUrl = null
|
||
if (imageFile && imageFile.size > 0) {
|
||
try {
|
||
imageUrl = await uploadToOpeninary(imageFile, 'submissions')
|
||
} catch (e: any) {
|
||
console.error('Openinary upload error:', e)
|
||
return { error: `Görsel yüklenemedi: ${e.message}` }
|
||
}
|
||
}
|
||
|
||
await mockDb.createSubmission({
|
||
businessName,
|
||
categoryId,
|
||
neighborhoodId,
|
||
address,
|
||
phone,
|
||
whatsapp,
|
||
description,
|
||
contactName,
|
||
contactEmail,
|
||
imageUrl
|
||
})
|
||
|
||
revalidatePath('/admin/submissions')
|
||
return { success: true, error: undefined }
|
||
}
|
||
|
||
export async function submitContactMessageAction(formData: FormData) {
|
||
const name = formData.get('name') as string
|
||
const email = formData.get('email') as string
|
||
const subject = formData.get('subject') as string
|
||
const message = formData.get('message') as string
|
||
|
||
if (!name || !email || !subject || !message) {
|
||
return { error: 'Lütfen tüm alanları doldurun.' }
|
||
}
|
||
|
||
await mockDb.createMessage({
|
||
name,
|
||
email,
|
||
subject,
|
||
message
|
||
})
|
||
|
||
revalidatePath('/admin/messages')
|
||
return { success: true, error: undefined }
|
||
}
|
||
|
||
export async function approveSubmissionAction(id: string) {
|
||
const submission = await mockDb.getSubmissionById(id)
|
||
if (!submission) return { error: 'Başvuru bulunamadı' }
|
||
|
||
const slug = submission.businessName.toLowerCase()
|
||
.replace(/[^a-z0-9\s-]/g, '')
|
||
.replace(/\s+/g, '-')
|
||
|
||
await mockDb.createListing({
|
||
slug,
|
||
categoryId: submission.categoryId,
|
||
neighborhoodId: submission.neighborhoodId,
|
||
city: 'marmaris',
|
||
nameTr: submission.businessName,
|
||
nameEn: submission.businessName,
|
||
nameRu: submission.businessName,
|
||
descriptionTr: submission.description,
|
||
descriptionEn: submission.description,
|
||
descriptionRu: submission.description,
|
||
address: submission.address,
|
||
phone: submission.phone,
|
||
whatsapp: submission.whatsapp,
|
||
priceRange: 2,
|
||
rating: 5.0,
|
||
isLocalApproved: false,
|
||
isFeatured: false,
|
||
hasWidgetInstalled: false,
|
||
images: submission.imageUrl ? [submission.imageUrl] : []
|
||
})
|
||
|
||
await mockDb.updateSubmissionStatus(id, 'APPROVED')
|
||
|
||
revalidatePath('/admin/submissions')
|
||
revalidatePath('/restaurants')
|
||
revalidatePath('/aparts')
|
||
revalidatePath('/businesses')
|
||
return { success: true, error: undefined }
|
||
}
|
||
|
||
export async function rejectSubmissionAction(id: string) {
|
||
await mockDb.updateSubmissionStatus(id, 'REJECTED')
|
||
revalidatePath('/admin/submissions')
|
||
return { success: true, error: undefined }
|
||
}
|
||
|
||
export async function deleteListingAction(id: string) {
|
||
await mockDb.deleteListing(id)
|
||
revalidatePath('/admin/listings')
|
||
revalidatePath('/restaurants')
|
||
revalidatePath('/aparts')
|
||
revalidatePath('/businesses')
|
||
return { success: true, error: undefined }
|
||
}
|
||
|
||
export async function restoreListingAction(id: string) {
|
||
await mockDb.restoreListing(id)
|
||
revalidatePath('/admin/trash')
|
||
revalidatePath('/admin/listings')
|
||
return { success: true, error: undefined }
|
||
}
|
||
|
||
export async function hardDeleteListingAction(id: string) {
|
||
try {
|
||
await mockDb.hardDeleteListing(id)
|
||
revalidatePath('/admin/trash')
|
||
return { success: true, error: undefined }
|
||
} catch (err: any) {
|
||
if (err.message?.includes('RESTRICT') || err.message?.includes('Foreign key constraint')) {
|
||
return { success: false, error: 'Silme başarısız: Bu mekana bağlı etkinlik (Event) veya kayıtlar var.' }
|
||
}
|
||
return { success: false, error: err.message || 'Bilinmeyen bir hata oluştu.' }
|
||
}
|
||
}
|
||
|
||
export async function markMessageReadAction(id: string) {
|
||
await mockDb.markMessageAsRead(id)
|
||
revalidatePath('/admin/messages')
|
||
return { success: true, error: undefined }
|
||
}
|
||
|
||
export async function createOrUpdateListingAction(formData: FormData) {
|
||
const id = formData.get('id') as string | null
|
||
const slug = formData.get('slug') as string
|
||
const categoryId = formData.get('categoryId') as string
|
||
const neighborhoodId = formData.get('neighborhoodId') as string
|
||
|
||
const nameTr = formData.get('nameTr') as string
|
||
const nameEn = formData.get('nameEn') as string
|
||
const nameRu = formData.get('nameRu') as string
|
||
|
||
const descriptionTr = formData.get('descriptionTr') as string
|
||
const descriptionEn = formData.get('descriptionEn') as string
|
||
const descriptionRu = formData.get('descriptionRu') as string
|
||
|
||
const address = formData.get('address') as string
|
||
const phone = formData.get('phone') as string || null
|
||
const whatsapp = formData.get('whatsapp') as string || null
|
||
const website = formData.get('website') as string || null
|
||
const instagram = formData.get('instagram') as string || null
|
||
|
||
const priceRange = parseInt(formData.get('priceRange') as string)
|
||
const rating = formData.get('rating') ? parseFloat(formData.get('rating') as string) : null
|
||
const isLocalApproved = formData.get('isLocalApproved') === 'true'
|
||
const isFeatured = formData.get('isFeatured') === 'true'
|
||
|
||
const latitude = formData.get('latitude') ? parseFloat(formData.get('latitude') as string) : null
|
||
const longitude = formData.get('longitude') ? parseFloat(formData.get('longitude') as string) : null
|
||
|
||
const openingHoursStr = formData.get('openingHours') as string
|
||
const openingHours = openingHoursStr ? { all: openingHoursStr } : null
|
||
|
||
// Handle images
|
||
const images: string[] = []
|
||
|
||
const imageFile1 = formData.get('imageFile1') as File | null
|
||
const imageUrl1 = formData.get('imageUrl1') as string | null
|
||
const imageFile2 = formData.get('imageFile2') as File | null
|
||
const imageUrl2 = formData.get('imageUrl2') as string | null
|
||
|
||
// Process first image
|
||
if (imageFile1 && imageFile1.size > 0) {
|
||
try {
|
||
const url = await uploadToOpeninary(imageFile1, `listings/${slug}`)
|
||
images.push(url)
|
||
} catch (e: any) {
|
||
console.error('Image 1 upload error:', e)
|
||
return { success: false, error: `1. Görsel yüklenemedi: ${e.message}` }
|
||
}
|
||
} else if (imageUrl1) {
|
||
images.push(imageUrl1)
|
||
}
|
||
|
||
// Process second image
|
||
if (imageFile2 && imageFile2.size > 0) {
|
||
try {
|
||
const url = await uploadToOpeninary(imageFile2, `listings/${slug}`)
|
||
images.push(url)
|
||
} catch (e: any) {
|
||
console.error('Image 2 upload error:', e)
|
||
return { success: false, error: `2. Görsel yüklenemedi: ${e.message}` }
|
||
}
|
||
} else if (imageUrl2) {
|
||
images.push(imageUrl2)
|
||
}
|
||
|
||
const data = {
|
||
slug,
|
||
categoryId,
|
||
neighborhoodId,
|
||
city: 'marmaris',
|
||
nameTr,
|
||
nameEn,
|
||
nameRu,
|
||
descriptionTr,
|
||
descriptionEn,
|
||
descriptionRu,
|
||
address,
|
||
phone,
|
||
whatsapp,
|
||
website,
|
||
instagram,
|
||
priceRange,
|
||
rating,
|
||
isLocalApproved,
|
||
isFeatured,
|
||
latitude,
|
||
longitude,
|
||
openingHours,
|
||
images,
|
||
hasWidgetInstalled: false
|
||
}
|
||
|
||
try {
|
||
if (id && id !== 'new') {
|
||
await mockDb.updateListing(id, data)
|
||
} else {
|
||
await mockDb.createListing(data)
|
||
}
|
||
revalidatePath('/admin/listings')
|
||
revalidatePath('/restaurants')
|
||
revalidatePath('/aparts')
|
||
revalidatePath('/businesses')
|
||
return { success: true, error: undefined }
|
||
} catch (err: any) {
|
||
return { success: false, error: err.message || 'Mekan kaydedilemedi.' }
|
||
}
|
||
}
|
||
|
||
// Blog Actions
|
||
export async function deleteBlogPostAction(id: string) {
|
||
await mockDb.deleteBlogPost(id)
|
||
revalidatePath('/admin/blog')
|
||
revalidatePath('/blog')
|
||
return { success: true, error: undefined }
|
||
}
|
||
|
||
export async function createOrUpdateBlogPostAction(formData: FormData) {
|
||
const id = formData.get('id') as string | null
|
||
const slug = formData.get('slug') as string
|
||
const titleTr = formData.get('titleTr') as string
|
||
const titleEn = formData.get('titleEn') as string
|
||
const titleRu = formData.get('titleRu') as string
|
||
const contentTr = formData.get('contentTr') as string
|
||
const contentEn = formData.get('contentEn') as string
|
||
const contentRu = formData.get('contentRu') as string
|
||
|
||
const tagsStr = formData.get('tags') as string || ''
|
||
const tags = tagsStr.split(',').map(t => t.trim()).filter(Boolean)
|
||
|
||
const relatedListingIdsStr = formData.get('relatedListingIds') as string || ''
|
||
const relatedListingIds = relatedListingIdsStr.split(',').map(i => i.trim()).filter(Boolean)
|
||
|
||
const isPublished = formData.get('isPublished') === 'true'
|
||
const publishedAt = isPublished ? new Date() : null
|
||
|
||
// Handle Cover Image
|
||
const coverImageFile = formData.get('coverImageFile') as File | null
|
||
let coverImage = formData.get('coverImageUrl') as string | null || null
|
||
|
||
if (coverImageFile && coverImageFile.size > 0) {
|
||
try {
|
||
coverImage = await uploadToOpeninary(coverImageFile, `blog/${slug}`)
|
||
} catch (e: any) {
|
||
console.error('Blog cover upload error:', e)
|
||
return { success: false, error: `Kapak görseli yüklenemedi: ${e.message}` }
|
||
}
|
||
}
|
||
|
||
const data = {
|
||
slug,
|
||
titleTr,
|
||
titleEn,
|
||
titleRu,
|
||
contentTr,
|
||
contentEn,
|
||
contentRu,
|
||
coverImage,
|
||
tags,
|
||
relatedListingIds,
|
||
publishedAt
|
||
}
|
||
|
||
try {
|
||
if (id && id !== 'new') {
|
||
await mockDb.updateBlogPost(id, data)
|
||
} else {
|
||
await mockDb.createBlogPost(data)
|
||
}
|
||
revalidatePath('/admin/blog')
|
||
revalidatePath('/blog')
|
||
revalidatePath(`/blog/${slug}`)
|
||
return { success: true, error: undefined }
|
||
} catch (err: any) {
|
||
return { success: false, error: err.message || 'Yazı kaydedilemedi.' }
|
||
}
|
||
}
|
||
|
||
// Collections Actions
|
||
export async function deleteCollectionAction(id: string) {
|
||
await mockDb.deleteCollection(id)
|
||
revalidatePath('/admin/collections')
|
||
revalidatePath('/collections')
|
||
return { success: true, error: undefined }
|
||
}
|
||
|
||
export async function createOrUpdateCollectionAction(formData: FormData) {
|
||
const id = formData.get('id') as string | null
|
||
const slug = formData.get('slug') as string
|
||
const titleTr = formData.get('titleTr') as string
|
||
const titleEn = formData.get('titleEn') as string
|
||
const titleRu = formData.get('titleRu') as string
|
||
const descriptionTr = formData.get('descriptionTr') as string
|
||
const descriptionEn = formData.get('descriptionEn') as string
|
||
const descriptionRu = formData.get('descriptionRu') as string
|
||
|
||
const listingIdsStr = formData.get('listingIds') as string || ''
|
||
const listingIds = listingIdsStr.split(',').map(i => i.trim()).filter(Boolean)
|
||
|
||
// Handle Cover Image
|
||
const coverImageFile = formData.get('coverImageFile') as File | null
|
||
let coverImage = formData.get('coverImageUrl') as string | null || null
|
||
|
||
if (coverImageFile && coverImageFile.size > 0) {
|
||
try {
|
||
coverImage = await uploadToOpeninary(coverImageFile, `collections/${slug}`)
|
||
} catch (e: any) {
|
||
console.error('Collection cover upload error:', e)
|
||
return { success: false, error: `Kapak görseli yüklenemedi: ${e.message}` }
|
||
}
|
||
}
|
||
|
||
const data = {
|
||
slug,
|
||
titleTr,
|
||
titleEn,
|
||
titleRu,
|
||
descriptionTr,
|
||
descriptionEn,
|
||
descriptionRu,
|
||
coverImage,
|
||
listingIds
|
||
}
|
||
|
||
try {
|
||
if (id && id !== 'new') {
|
||
await mockDb.updateCollection(id, data)
|
||
} else {
|
||
await mockDb.createCollection(data)
|
||
}
|
||
revalidatePath('/admin/collections')
|
||
revalidatePath('/collections')
|
||
revalidatePath(`/collection/${slug}`)
|
||
return { success: true, error: undefined }
|
||
} catch (err: any) {
|
||
return { success: false, error: err.message || 'Koleksiyon kaydedilemedi.' }
|
||
}
|
||
}
|
||
|
||
// Events Actions (Phase 3)
|
||
export async function deleteEventAction(id: string) {
|
||
await mockDb.deleteEvent(id)
|
||
revalidatePath('/admin/events')
|
||
revalidatePath('/events')
|
||
return { success: true, error: undefined }
|
||
}
|
||
|
||
export async function createOrUpdateEventAction(formData: FormData) {
|
||
const id = formData.get('id') as string | null
|
||
const slug = formData.get('slug') as string
|
||
const listingId = formData.get('listingId') as string | null || null
|
||
const titleTr = formData.get('titleTr') as string
|
||
const titleEn = formData.get('titleEn') as string
|
||
const titleRu = formData.get('titleRu') as string
|
||
const descriptionTr = formData.get('descriptionTr') as string
|
||
const descriptionEn = formData.get('descriptionEn') as string
|
||
const descriptionRu = formData.get('descriptionRu') as string
|
||
|
||
const startDateStr = formData.get('startDate') as string
|
||
const endDateStr = formData.get('endDate') as string | null
|
||
const isSponsored = formData.get('isSponsored') === 'true'
|
||
|
||
const startDate = new Date(startDateStr)
|
||
const endDate = endDateStr ? new Date(endDateStr) : null
|
||
|
||
// Handle Cover Image
|
||
const coverImageFile = formData.get('coverImageFile') as File | null
|
||
let coverImage = formData.get('coverImageUrl') as string | null || null
|
||
|
||
if (coverImageFile && coverImageFile.size > 0) {
|
||
try {
|
||
coverImage = await uploadToOpeninary(coverImageFile, `events/${slug}`)
|
||
} catch (e: any) {
|
||
console.error('Event cover upload error:', e)
|
||
return { success: false, error: `Kapak görseli yüklenemedi: ${e.message}` }
|
||
}
|
||
}
|
||
|
||
const data = {
|
||
slug,
|
||
listingId,
|
||
titleTr,
|
||
titleEn,
|
||
titleRu,
|
||
descriptionTr,
|
||
descriptionEn,
|
||
descriptionRu,
|
||
startDate,
|
||
endDate,
|
||
coverImage,
|
||
isSponsored
|
||
}
|
||
|
||
try {
|
||
if (id && id !== 'new') {
|
||
await mockDb.updateEvent(id, data)
|
||
} else {
|
||
await mockDb.createEvent(data)
|
||
}
|
||
revalidatePath('/admin/events')
|
||
revalidatePath('/events')
|
||
revalidatePath(`/event/${slug}`)
|
||
return { success: true, error: undefined }
|
||
} catch (err: any) {
|
||
return { success: false, error: err.message || 'Etkinlik kaydedilemedi.' }
|
||
}
|
||
}
|
||
// Neighborhood Actions
|
||
export async function deleteNeighborhoodAction(id: string) {
|
||
try {
|
||
const listings = await mockDb.getListings({ neighborhoodId: id })
|
||
if (listings && listings.length > 0) {
|
||
return { success: false, error: `Silme başarısız: Bu mahalleye kayıtlı ${listings.length} adet mekan var.` }
|
||
}
|
||
|
||
await mockDb.deleteNeighborhood(id)
|
||
revalidatePath('/admin/neighborhoods')
|
||
return { success: true, error: undefined }
|
||
} catch (err: any) {
|
||
if (err.message?.includes('RESTRICT') || err.message?.includes('Foreign key constraint')) {
|
||
return { success: false, error: 'Silme başarısız: Bu mahalleye bağlı gizli (silinmiş veya arşivlenmiş) mekanlar veya etkinlikler var.' }
|
||
}
|
||
return { success: false, error: err.message || 'Bilinmeyen bir hata oluştu.' }
|
||
}
|
||
}
|
||
|
||
export async function createOrUpdateNeighborhoodAction(formData: FormData) {
|
||
const id = formData.get('id') as string | null
|
||
const slug = formData.get('slug') as string
|
||
const nameTr = formData.get('nameTr') as string
|
||
const nameEn = formData.get('nameEn') as string
|
||
const nameRu = formData.get('nameRu') as string
|
||
|
||
if (!slug || !nameTr || !nameEn || !nameRu) {
|
||
return { error: 'Zorunlu alanları doldurun.' }
|
||
}
|
||
|
||
const data = {
|
||
slug,
|
||
nameTr,
|
||
nameEn,
|
||
nameRu,
|
||
}
|
||
|
||
try {
|
||
if (id && id !== 'new') {
|
||
await mockDb.updateNeighborhood(id, data)
|
||
} else {
|
||
await mockDb.createNeighborhood(data)
|
||
}
|
||
revalidatePath('/admin/neighborhoods')
|
||
return { success: true, error: undefined }
|
||
} catch (err: any) {
|
||
return { success: false, error: err.message || 'Mahalle kaydedilemedi.' }
|
||
}
|
||
}
|
||
|
||
// AI Itinerary Planner Actions (Phase 3)
|
||
import crypto from 'crypto'
|
||
|
||
async function generateMockItinerary(days: number, style: string, neighborhoodSlugs: string[]) {
|
||
const allListings = await mockDb.getListings()
|
||
const matchingListings = allListings.filter(l =>
|
||
!l.deletedAt && l.isLocalApproved &&
|
||
(neighborhoodSlugs.length === 0 ||
|
||
(l.neighborhood && neighborhoodSlugs.includes(l.neighborhood.slug)))
|
||
)
|
||
|
||
const pool = matchingListings.length > 0 ? matchingListings : allListings.filter(l => !l.deletedAt && l.isLocalApproved)
|
||
|
||
let md = `# marmaris local kişisel gezi rotası 🌴\n\n`
|
||
md += `**gün sayısı:** ${days} gün | **gezi tarzı:** ${style === 'gastronomy' ? 'gurme' : style === 'relaxation' ? 'dinlenme' : 'macera'} | **keşif bölgeleri:** ${neighborhoodSlugs.join(', ')}\n\n`
|
||
md += `bu rota, marmaris local topluluğu tarafından onaylanmış yerel işletmeler temel alınarak oluşturulmuştur.\n\n---\n\n`
|
||
|
||
for (let day = 1; day <= days; day++) {
|
||
md += `## 🗓️ gün ${day}\n\n`
|
||
|
||
const dayListings = [...pool].sort(() => 0.5 - Math.random()).slice(0, 3)
|
||
|
||
if (dayListings.length >= 1) {
|
||
md += `### 🌅 sabah: kahvaltı ve başlangıç\n`
|
||
md += `güne yerel onaylı **[${dayListings[0].nameTr}](/${dayListings[0].category?.slug || 'isletme'}/${dayListings[0].slug})** işletmesinde başlayın. \n`
|
||
md += `> **yerel ipucu:** ${dayListings[0].descriptionTr}\n\n`
|
||
}
|
||
|
||
if (dayListings.length >= 2) {
|
||
md += `### ☀️ öğle: keşif zamanı\n`
|
||
md += `öğleden sonra **[${dayListings[1].nameTr}](/${dayListings[1].category?.slug || 'isletme'}/${dayListings[1].slug})** mekanına uğrayın ve çevreyi keşfedin.\n`
|
||
md += `> **editör notu:** ${dayListings[1].address}\n\n`
|
||
}
|
||
|
||
if (dayListings.length >= 3) {
|
||
md += `### 🌌 akşam: gün batımı ve akşam yemeği\n`
|
||
md += `akşamı şık bir akşam yemeğiyle taçlandırın: **[${dayListings[2].nameTr}](/${dayListings[2].category?.slug || 'isletme'}/${dayListings[2].slug})**.\n`
|
||
md += `> **özel detaylar:** rating: ★${dayListings[2].rating} • tel: ${dayListings[2].phone || 'belirtilmemiş'}\n\n`
|
||
}
|
||
|
||
md += `---\n\n`
|
||
}
|
||
|
||
md += `*not: seyahatiniz boyunca yerel rehberimizdeki işletmeleri ziyaret etmeyi ve favorilerinize eklemeyi unutmayın!*`
|
||
|
||
return {
|
||
content: md,
|
||
listingIds: pool.map(l => l.id)
|
||
}
|
||
}
|
||
|
||
export async function generateItineraryAction(days: number, style: string, neighborhoodSlugs: string[]) {
|
||
const sorted = [...neighborhoodSlugs].sort()
|
||
const paramsHash = crypto.createHash('md5').update(JSON.stringify({ days, style, neighborhoodSlugs: sorted })).digest('hex')
|
||
|
||
const existing = await mockDb.getItineraryByHash(paramsHash)
|
||
if (existing) {
|
||
return { success: true, id: existing.id }
|
||
}
|
||
|
||
// Generate new program
|
||
const { content, listingIds } = await generateMockItinerary(days, style, sorted)
|
||
|
||
const newItin = await mockDb.createItinerary({
|
||
paramsHash,
|
||
params: { days, style, neighborhoodSlugs: sorted },
|
||
content,
|
||
listingIds
|
||
})
|
||
|
||
return { success: true, id: newItin.id }
|
||
}
|
||
|
||
|
||
|
||
export async function createOrUpdateCategoryAction(formData: FormData) {
|
||
const id = formData.get('id') as string
|
||
const slug = formData.get('slug') as string
|
||
const nameTr = formData.get('nameTr') as string
|
||
const nameEn = formData.get('nameEn') as string
|
||
const nameRu = formData.get('nameRu') as string
|
||
|
||
if (!slug || !nameTr || !nameEn || !nameRu) {
|
||
throw new Error('Eksik alanlar var')
|
||
}
|
||
|
||
if (id && id !== 'new') {
|
||
await mockDb.updateCategory(id, { slug, nameTr, nameEn, nameRu })
|
||
} else {
|
||
await mockDb.createCategory({ slug, nameTr, nameEn, nameRu })
|
||
}
|
||
|
||
revalidatePath('/admin/categories')
|
||
redirect('/tr/admin/categories')
|
||
}
|
||
|
||
export async function deleteCategoryAction(formData: FormData) {
|
||
const id = formData.get('id') as string
|
||
if (!id) return
|
||
await mockDb.deleteCategory(id)
|
||
revalidatePath('/admin/categories')
|
||
}
|
||
|
||
export async function deleteSubmissionAction(id: string) {
|
||
await mockDb.deleteSubmission(id)
|
||
revalidatePath('/admin/submissions')
|
||
return { success: true, error: undefined }
|
||
}
|
||
|
||
export async function deleteMessageAction(id: string) {
|
||
await mockDb.deleteMessage(id)
|
||
revalidatePath('/admin/messages')
|
||
return { success: true, error: undefined }
|
||
}
|
||
|
||
export async function searchListingsAction(query: string) {
|
||
if (!query || query.length < 2) return []
|
||
|
||
const allListings = await mockDb.getListings()
|
||
const q = query.toLowerCase()
|
||
|
||
const results = allListings.filter(l =>
|
||
!l.deletedAt && (
|
||
l.nameTr.toLowerCase().includes(q) ||
|
||
l.nameEn?.toLowerCase().includes(q) ||
|
||
l.nameRu?.toLowerCase().includes(q)
|
||
)
|
||
).slice(0, 5) // Return max 5 suggestions
|
||
|
||
return results.map(l => ({
|
||
id: l.id,
|
||
nameTr: l.nameTr,
|
||
nameEn: l.nameEn,
|
||
nameRu: l.nameRu,
|
||
slug: l.slug,
|
||
categorySlug: l.category?.slug || 'restoran'
|
||
}))
|
||
}
|
||
|
||
|
||
export async function saveWidgetPartnerAction(formData: FormData) {
|
||
const id = formData.get('id') as string | null
|
||
const name = formData.get('name') as string
|
||
const url = formData.get('url') as string
|
||
const neighborhoodSlug = formData.get('neighborhoodSlug') as string | null
|
||
const isActive = formData.get('isActive') === 'true'
|
||
|
||
if (!name || !url) {
|
||
return { error: 'Lütfen zorunlu alanları doldurun.' }
|
||
}
|
||
|
||
const data = {
|
||
name,
|
||
url,
|
||
neighborhoodSlug: neighborhoodSlug || null,
|
||
isActive
|
||
}
|
||
|
||
try {
|
||
if (id && id !== 'new') {
|
||
await mockDb.updateWidgetPartner(id, data)
|
||
} else {
|
||
await mockDb.createWidgetPartner(data)
|
||
}
|
||
revalidatePath('/admin/widget-partners')
|
||
return { success: true, error: undefined }
|
||
} catch (error: any) {
|
||
return { error: error.message || 'Bir hata oluştu.' }
|
||
}
|
||
}
|
||
|
||
export async function deleteWidgetPartnerAction(id: string) {
|
||
await mockDb.deleteWidgetPartner(id)
|
||
revalidatePath('/admin/widget-partners')
|
||
return { success: true, error: undefined }
|
||
}
|