feat: Implement Phase 2 features including blog, collections, saved listings, manifest, and api cron sync
This commit is contained in:
+133
@@ -93,6 +93,7 @@ export async function approveSubmissionAction(id: string) {
|
||||
priceRange: 2,
|
||||
rating: 5.0,
|
||||
isLocalApproved: false,
|
||||
isFeatured: false,
|
||||
images: submission.imageUrl ? [submission.imageUrl] : []
|
||||
})
|
||||
|
||||
@@ -149,6 +150,7 @@ export async function createOrUpdateListingAction(formData: FormData) {
|
||||
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
|
||||
@@ -209,6 +211,7 @@ export async function createOrUpdateListingAction(formData: FormData) {
|
||||
priceRange,
|
||||
rating,
|
||||
isLocalApproved,
|
||||
isFeatured,
|
||||
latitude,
|
||||
longitude,
|
||||
openingHours,
|
||||
@@ -230,3 +233,133 @@ export async function createOrUpdateListingAction(formData: FormData) {
|
||||
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 }
|
||||
}
|
||||
|
||||
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 }
|
||||
} 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('/seckiler')
|
||||
return { success: true }
|
||||
}
|
||||
|
||||
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('/seckiler')
|
||||
revalidatePath(`/secki/${slug}`)
|
||||
return { success: true }
|
||||
} catch (err: any) {
|
||||
return { success: false, error: err.message || 'Koleksiyon kaydedilemedi.' }
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user