Extract admin dashboard from ghabilee-frontend2 into a dedicated Next.js app for backoffice.ghabilee.ir (no SEO indexing / Clarity).
60 lines
1.7 KiB
TypeScript
60 lines
1.7 KiB
TypeScript
import { isPublicEventSlug } from '@/lib/routing/eventRoute'
|
|
|
|
export const EVENT_SLUG_MAX_LENGTH = 220
|
|
export const EVENT_SLUG_FALLBACK = 'event'
|
|
|
|
/** Previous wizard default: `event-` + first 8 chars of a UUID. */
|
|
const RANDOM_PLACEHOLDER_SLUG = /^event-[0-9a-f]{8}$/i
|
|
|
|
// Same single-pass map as backend/src/modules/events/event-slug.util.ts.
|
|
const PERSIAN_TRANSLIT_FROM = 'ابپتثجچحخدذرزژسشصضطظعغفقکگلمنوهیآأإئءؤةيك '
|
|
const PERSIAN_TRANSLIT_TO = 'abptsjchxdzrzjsssztzaqfqkglmnvhyaaaeaotyk-'
|
|
const PERSIAN_DIGITS = '۰۱۲۳۴۵۶۷۸۹'
|
|
|
|
export function slugifyEventTitle(title: string): string {
|
|
const trimmed = title.trim()
|
|
|
|
if (!trimmed) return ''
|
|
|
|
let withLatinDigits = ''
|
|
|
|
for (const char of trimmed) {
|
|
const digit = PERSIAN_DIGITS.indexOf(char)
|
|
|
|
withLatinDigits += digit === -1 ? char : String(digit)
|
|
}
|
|
|
|
let raw = ''
|
|
|
|
for (const char of withLatinDigits) {
|
|
const index = PERSIAN_TRANSLIT_FROM.indexOf(char)
|
|
|
|
raw += index === -1 ? char : PERSIAN_TRANSLIT_TO[index]
|
|
}
|
|
|
|
const slug = raw
|
|
.toLowerCase()
|
|
.replace(/[^a-z0-9]+/g, '-')
|
|
.replace(/-+/g, '-')
|
|
.replace(/(^-+|-+$)/g, '')
|
|
.slice(0, EVENT_SLUG_MAX_LENGTH)
|
|
.replace(/-+$/g, '')
|
|
|
|
if (!slug || !isPublicEventSlug(slug)) return EVENT_SLUG_FALLBACK
|
|
|
|
return slug
|
|
}
|
|
|
|
/**
|
|
* True when the slug field should keep tracking the title: empty, leftover
|
|
* random placeholder, or still equal to the slug generated from `title`.
|
|
*/
|
|
export function shouldAutogenerateEventSlug(currentSlug: string, title: string): boolean {
|
|
const slug = currentSlug.trim()
|
|
|
|
if (!slug) return true
|
|
if (RANDOM_PLACEHOLDER_SLUG.test(slug)) return true
|
|
|
|
return slug === slugifyEventTitle(title)
|
|
}
|