Files
dashboards/apps/business/src/utils/websiteLinks.ts
T
Alireza HassaniandCursor 4c3bf8324e Add customer SMS/Excel tools, selection bar, and sticky import toasts.
Bulk and single SMS from Users, row selection with overflow summary, persistent large import toasts, and business SMS sender in Super Admin.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-08 14:12:57 +03:30

140 lines
3.9 KiB
TypeScript

import { getBusinessDomain } from '../lib/config'
export type WebsiteLinkKind = 'product' | 'storeItem' | 'blog' | 'portfolio' | 'video' | 'workshop'
export type WebsiteContentKind =
| 'product'
| 'blog'
| 'portfolio'
| 'video'
| 'instruction'
| 'workshop'
export type WebsiteLinkFilter = 'category' | 'tag'
export const WEBSITE_LINK_KINDS: WebsiteLinkKind[] = [
'product',
'storeItem',
'blog',
'portfolio',
'video',
'workshop',
]
export const WEBSITE_LINK_KIND_PATH: Record<WebsiteLinkKind, string> = {
product: '/products',
storeItem: '/store-items',
blog: '/blogs',
portfolio: '/portfolios',
video: '/videos',
workshop: '/workshops',
}
/** Matches backend `slugifyForUrl` used by website sitemaps / SEO paths. */
export function slugifyForWebsitePath(value: string, fallback = 'item'): string {
const slug = value
.trim()
.normalize('NFC')
.replace(/\s+/g, '-')
.replace(
/[^\u0600-\u06FF\u0750-\u077F\u08A0-\u08FF\uFB50-\uFDFF\uFE70-\uFEFFa-zA-Z0-9-]+/g,
'',
)
.replace(/-+/g, '-')
.replace(/^-|-$/g, '')
return slug || fallback
}
export function getWebsiteOrigin(domain = getBusinessDomain()): string {
const host = domain.trim().replace(/^https?:\/\//i, '').replace(/\/$/, '')
const protocol = window.location.protocol === 'http:' ? 'http:' : 'https:'
return `${protocol}//${host}`
}
/**
* Public storefront detail URL for a content item (canonical Meshkee website paths).
* Returns '' when a required slug/title is missing.
*/
export function buildWebsiteContentUrl(
kind: WebsiteContentKind,
item: {
id: string
slug?: string | null
title?: string | null
titleFa?: string | null
nameFa?: string | null
nameEn?: string | null
},
domain = getBusinessDomain(),
): string {
const origin = getWebsiteOrigin(domain)
const id = item.id?.trim()
if (!id) return ''
switch (kind) {
case 'product': {
const pathSlug = slugifyForWebsitePath(
item.nameFa?.trim() || item.nameEn?.trim() || item.title?.trim() || '',
'product',
)
return `${origin}/products/${encodeURIComponent(id)}/${encodeURIComponent(pathSlug)}`
}
case 'blog': {
const pathSlug = slugifyForWebsitePath(item.title?.trim() || '', 'blog')
return `${origin}/blog/${encodeURIComponent(id)}/${encodeURIComponent(pathSlug)}`
}
case 'portfolio': {
const pathSlug = slugifyForWebsitePath(
item.titleFa?.trim() || item.title?.trim() || '',
'portfolio',
)
return `${origin}/portfolios/${encodeURIComponent(id)}/${encodeURIComponent(pathSlug)}`
}
case 'video': {
const slug = item.slug?.trim()
return slug ? `${origin}/videos/${encodeURIComponent(slug)}` : ''
}
case 'instruction': {
const slug = item.slug?.trim()
return slug ? `${origin}/instructions/${encodeURIComponent(slug)}` : ''
}
case 'workshop': {
const slug = item.slug?.trim()
return slug ? `${origin}/workshops/${encodeURIComponent(slug)}` : ''
}
default:
return ''
}
}
export function buildWebsiteCategoryUrl(
kind: WebsiteLinkKind,
category: { id: string; slug?: string | null },
domain = getBusinessDomain(),
): string {
const path = WEBSITE_LINK_KIND_PATH[kind]
const query = category.slug
? `category=${encodeURIComponent(category.slug)}`
: `categoryId=${encodeURIComponent(category.id)}`
return `${getWebsiteOrigin(domain)}${path}?${query}`
}
export function buildWebsiteTagsUrl(
kind: WebsiteLinkKind,
tags: string[],
domain = getBusinessDomain(),
): string {
const cleaned = [
...new Set(tags.map((tag) => tag.trim()).filter(Boolean)),
]
if (cleaned.length === 0) return ''
const path = WEBSITE_LINK_KIND_PATH[kind]
const query =
cleaned.length === 1
? `tag=${encodeURIComponent(cleaned[0])}`
: `tags=${cleaned.map((tag) => encodeURIComponent(tag)).join(',')}`
return `${getWebsiteOrigin(domain)}${path}?${query}`
}