Extract admin dashboard from ghabilee-frontend2 into a dedicated Next.js app for backoffice.ghabilee.ir (no SEO indexing / Clarity).
92 lines
3.2 KiB
TypeScript
92 lines
3.2 KiB
TypeScript
import type { FaqItem, StagedMediaItem } from '@/components/events/create/types'
|
|
import type { EventFaq, EventMedia } from '@/services/eventDetail'
|
|
import { createEventFaq, createEventMedia, deleteEventFaq, deleteEventMedia, updateEventFaq, updateEventMedia } from '@/services/events'
|
|
|
|
/**
|
|
* Diff staged wizard media against the loaded server set and apply create/
|
|
* update/delete. Poster creates run first so former posters can be deleted.
|
|
*/
|
|
export async function syncEventMedia(eventId: string, initial: EventMedia[], current: StagedMediaItem[]): Promise<void> {
|
|
const initialById = new Map(initial.map((item) => [item.id, item]))
|
|
const currentIds = new Set(current.map((item) => item.id))
|
|
|
|
const toCreate = current.filter((item) => !initialById.has(item.id))
|
|
const toUpdate = current.filter((item) => {
|
|
const existing = initialById.get(item.id)
|
|
|
|
if (!existing) return false
|
|
|
|
return (
|
|
existing.url !== item.url ||
|
|
Boolean(existing.isPoster) !== item.isPoster ||
|
|
Boolean(existing.isSquarePoster) !== item.isSquarePoster ||
|
|
(existing.sortOrder ?? 0) !== item.sortOrder
|
|
)
|
|
})
|
|
const toDelete = initial.filter((item) => !currentIds.has(item.id))
|
|
|
|
// پوسترهای جدید اول ساخته میشوند تا پرچم پوستر از آیتمهای قدیمی برداشته شود
|
|
const createPosterFirst = [...toCreate].sort((a, b) => Number(b.isPoster || b.isSquarePoster) - Number(a.isPoster || a.isSquarePoster))
|
|
|
|
for (const item of createPosterFirst) {
|
|
await createEventMedia(eventId, {
|
|
mediaType: 'image',
|
|
url: item.url,
|
|
sortOrder: item.sortOrder,
|
|
isPoster: item.isPoster,
|
|
isSquarePoster: item.isSquarePoster,
|
|
})
|
|
}
|
|
|
|
for (const item of toUpdate) {
|
|
await updateEventMedia(eventId, item.id, {
|
|
url: item.url,
|
|
sortOrder: item.sortOrder,
|
|
isPoster: item.isPoster,
|
|
isSquarePoster: item.isSquarePoster,
|
|
})
|
|
}
|
|
|
|
// حذف بعد از create/update تا محدودیت «پوستر قابل حذف نیست» نقض نشود
|
|
for (const item of toDelete) {
|
|
await deleteEventMedia(eventId, item.id)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Diff staged FAQs against the loaded server set. FaqEditor only supports
|
|
* add/remove (not in-place edit), so updates cover sortOrder if ids persist.
|
|
*/
|
|
export async function syncEventFaqs(eventId: string, initial: EventFaq[], current: FaqItem[]): Promise<void> {
|
|
const initialById = new Map(initial.map((item) => [item.id, item]))
|
|
const currentIds = new Set(current.map((item) => item.id))
|
|
|
|
for (let index = 0; index < current.length; index += 1) {
|
|
const faq = current[index]
|
|
const existing = initialById.get(faq.id)
|
|
|
|
if (!existing) {
|
|
await createEventFaq(eventId, {
|
|
question: faq.question,
|
|
answer: faq.answer,
|
|
sortOrder: index,
|
|
})
|
|
continue
|
|
}
|
|
|
|
if (existing.question !== faq.question || existing.answer !== faq.answer || (existing.sortOrder ?? 0) !== index) {
|
|
await updateEventFaq(eventId, faq.id, {
|
|
question: faq.question,
|
|
answer: faq.answer,
|
|
sortOrder: index,
|
|
})
|
|
}
|
|
}
|
|
|
|
for (const item of initial) {
|
|
if (!currentIds.has(item.id)) {
|
|
await deleteEventFaq(eventId, item.id)
|
|
}
|
|
}
|
|
}
|