export type RegistryPresentationColumn = { key: "name" | "status" | "version" | "updated_at" | "visibility"; label: string; }; export type RegistryPresentation = { label: string; englishLabel: string; pluralLabel: string; description: string; icon: string; accentColor: string; navigationTitle: string; sectionTitle: string; emptyStateTitle: string; emptyStateDescription: string; createButtonText: string; editDialogTitle: string; deleteConfirmation: string; publishLabel: string; archiveLabel: string; statusMap: Readonly>; columns: readonly RegistryPresentationColumn[]; }; const STATUS_LABELS: Readonly> = { active: "فعال", inactive: "غیرفعال", draft: "پیش‌نویس", published: "منتشرشده", pending: "در انتظار بررسی", pending_payment: "در انتظار پرداخت", verified: "تأییدشده", unverified: "تأییدنشده", failed: "ناموفق", succeeded: "موفق", completed: "تکمیل‌شده", expired: "منقضی‌شده", trialing: "در دوره آزمایشی", trial: "آزمایشی", suspended: "تعلیق‌شده", canceled: "لغوشده", cancelled: "لغوشده", archived: "بایگانی‌شده", deprecated: "از رده خارج", planned: "برنامه‌ریزی‌شده", concept: "در حال طراحی", mature: "پایدار", ga: "آماده ارائه", beta: "نسخه آزمایشی", grace_period: "در مهلت تمدید", processing: "در حال پردازش", paid: "پرداخت‌شده", unpaid: "پرداخت‌نشده", refunded: "بازپرداخت‌شده", partially_refunded: "بازپرداخت جزئی", }; const DEFAULT_COLUMNS: readonly RegistryPresentationColumn[] = [ { key: "name", label: "نام" }, { key: "status", label: "وضعیت" }, { key: "version", label: "نسخه" }, { key: "updated_at", label: "آخرین تغییر" }, { key: "visibility", label: "نمایش" }, ]; function definePresentation({ label, englishLabel, pluralLabel = label, description, icon, accentColor, columns = DEFAULT_COLUMNS, }: { label: string; englishLabel: string; pluralLabel?: string; description: string; icon: string; accentColor: string; columns?: readonly RegistryPresentationColumn[]; }): RegistryPresentation { return { label, englishLabel, pluralLabel, description, icon, accentColor, navigationTitle: pluralLabel, sectionTitle: `مدیریت ${pluralLabel}`, emptyStateTitle: `هنوز ${pluralLabel} ثبت نشده است`, emptyStateDescription: `پس از ثبت اولین مورد، اطلاعات ${pluralLabel} در این بخش نمایش داده می‌شود.`, createButtonText: `افزودن ${label}`, editDialogTitle: `ویرایش ${label}`, deleteConfirmation: `آیا از حذف این ${label} مطمئن هستید؟`, publishLabel: `انتشار ${label}`, archiveLabel: `بایگانی ${label}`, statusMap: STATUS_LABELS, columns, }; } /** * Universal Commercial Presentation Dictionary. * API paths and registry records never provide user-facing copy. */ export const presentationRegistry = { products: definePresentation({ label: "محصول", englishLabel: "Product", pluralLabel: "محصولات", description: "راهکارهای نرم‌افزاری قابل ارائه به کسب‌وکارها", icon: "◫", accentColor: "bg-sky-50 text-sky-700", }), bundles: definePresentation({ label: "بسته خدمات", englishLabel: "Service Bundle", pluralLabel: "بسته‌های خدمات", description: "ترکیب آماده محصولات و امکانات برای نیازهای مختلف", icon: "▦", accentColor: "bg-violet-50 text-violet-700", }), pricing: definePresentation({ label: "قیمت", englishLabel: "Pricing Item", pluralLabel: "قیمت‌گذاری", description: "قیمت‌های ماهانه، سالانه، آزمایشی و سازمانی", icon: "◉", accentColor: "bg-emerald-50 text-emerald-700", }), plans: definePresentation({ label: "پلن اشتراک", englishLabel: "Subscription Plan", pluralLabel: "پلن‌های اشتراک", description: "پلن‌های قابل انتخاب برای شروع و توسعه کسب‌وکار", icon: "▤", accentColor: "bg-indigo-50 text-indigo-700", }), capabilities: definePresentation({ label: "قابلیت", englishLabel: "Capability", pluralLabel: "قابلیت‌ها", description: "امکانات کاربردی قابل ارائه در محصولات و بسته‌ها", icon: "✦", accentColor: "bg-amber-50 text-amber-700", }), "business-types": definePresentation({ label: "نوع کسب‌وکار", englishLabel: "Business Type", pluralLabel: "انواع کسب‌وکار", description: "الگوهای کسب‌وکار برای پیشنهاد دقیق‌تر محصولات", icon: "⌂", accentColor: "bg-orange-50 text-orange-700", }), "recommendation-rules": definePresentation({ label: "قاعده پیشنهاد", englishLabel: "Recommendation Rule", pluralLabel: "قواعد پیشنهاد", description: "قواعد تجاری برای پیشنهاد راهکار مناسب به هر کسب‌وکار", icon: "◎", accentColor: "bg-fuchsia-50 text-fuchsia-700", }), "assessment-schemas": definePresentation({ label: "الگوی ارزیابی", englishLabel: "Assessment Schema", pluralLabel: "الگوهای ارزیابی", description: "پرسش‌های کسب‌وکاری برای شناخت نیاز مشتری", icon: "☷", accentColor: "bg-cyan-50 text-cyan-700", }), assets: definePresentation({ label: "دارایی دیجیتال", englishLabel: "Digital Asset", pluralLabel: "دارایی‌های دیجیتال", description: "دارایی‌های قابل استفاده در محصولات و تجربه مشتری", icon: "◇", accentColor: "bg-rose-50 text-rose-700", }), extensions: definePresentation({ label: "افزونه", englishLabel: "Extension", pluralLabel: "افزونه‌ها", description: "امکانات تکمیلی قابل افزودن به محصولات", icon: "⊞", accentColor: "bg-teal-50 text-teal-700", }), "automation-packs": definePresentation({ label: "بسته اتوماسیون", englishLabel: "Automation Pack", pluralLabel: "بسته‌های اتوماسیون", description: "فرایندهای آماده برای کاهش کارهای تکراری", icon: "⚙", accentColor: "bg-blue-50 text-blue-700", }), metadata: definePresentation({ label: "ویژگی تکمیلی", englishLabel: "Additional Attribute", pluralLabel: "ویژگی‌های تکمیلی", description: "اطلاعات تکمیلی سازمان‌یافته برای نمایش و دسته‌بندی", icon: "≡", accentColor: "bg-slate-100 text-slate-700", }), policies: definePresentation({ label: "قانون تجاری", englishLabel: "Commercial Policy", pluralLabel: "قوانین تجاری", description: "قوانین دسترسی، دامنه، فروش و ارائه خدمات", icon: "✓", accentColor: "bg-lime-50 text-lime-700", }), "usage-plans": definePresentation({ label: "برنامه مصرف", englishLabel: "Usage Plan", pluralLabel: "برنامه‌های مصرف", description: "سقف‌ها و الگوهای مصرف خدمات", icon: "◔", accentColor: "bg-purple-50 text-purple-700", }), subscriptions: definePresentation({ label: "اشتراک", englishLabel: "Subscription", pluralLabel: "اشتراک‌ها", description: "اشتراک‌های فعال، آزمایشی و در انتظار تمدید مشتریان", icon: "↻", accentColor: "bg-sky-50 text-sky-700", }), licenses: definePresentation({ label: "لایسنس", englishLabel: "License", pluralLabel: "لایسنس‌ها", description: "مجوزهای استفاده از محصولات و بسته‌های خریداری‌شده", icon: "⌘", accentColor: "bg-indigo-50 text-indigo-700", }), entitlements: definePresentation({ label: "مجوز دسترسی", englishLabel: "Entitlement", pluralLabel: "مجوزهای دسترسی", description: "امکانات و سهمیه‌های در دسترس هر فضای کاری", icon: "◈", accentColor: "bg-emerald-50 text-emerald-700", }), promotions: definePresentation({ label: "پیشنهاد ویژه", englishLabel: "Promotion", pluralLabel: "پیشنهادهای ویژه", description: "پیشنهادهای فروش زمان‌دار برای مشتریان", icon: "★", accentColor: "bg-pink-50 text-pink-700", }), coupons: definePresentation({ label: "کوپن", englishLabel: "Coupon", pluralLabel: "کوپن‌ها", description: "کوپن‌های تخفیف قابل استفاده هنگام خرید", icon: "✂", accentColor: "bg-rose-50 text-rose-700", }), currencies: definePresentation({ label: "واحد پول", englishLabel: "Currency", pluralLabel: "واحدهای پول", description: "واحدهای پول قابل استفاده در قیمت‌گذاری", icon: "¤", accentColor: "bg-green-50 text-green-700", }), taxes: definePresentation({ label: "گروه مالیاتی", englishLabel: "Tax Class", pluralLabel: "گروه‌های مالیاتی", description: "قواعد محاسبه مالیات برای محصولات و خدمات", icon: "%", accentColor: "bg-amber-50 text-amber-700", }), notifications: definePresentation({ label: "اعلان تجاری", englishLabel: "Commercial Notification", pluralLabel: "اعلان‌های تجاری", description: "پیام‌های مرتبط با خرید، اشتراک و تمدید", icon: "◌", accentColor: "bg-cyan-50 text-cyan-700", }), announcements: definePresentation({ label: "اطلاعیه تجاری", englishLabel: "Commercial Announcement", pluralLabel: "اطلاعیه‌های تجاری", description: "اطلاعیه‌های قابل نمایش به مشتریان", icon: "◍", accentColor: "bg-blue-50 text-blue-700", }), transactions: definePresentation({ label: "تراکنش", englishLabel: "Transaction", pluralLabel: "تراکنش‌ها", description: "سوابق پرداخت و بازپرداخت مشتریان", icon: "⇄", accentColor: "bg-teal-50 text-teal-700", }), invoices: definePresentation({ label: "صورتحساب", englishLabel: "Invoice", pluralLabel: "صورتحساب‌ها", description: "صورتحساب‌های صادرشده برای اشتراک و خدمات", icon: "▧", accentColor: "bg-orange-50 text-orange-700", }), "trial-rules": definePresentation({ label: "قانون دوره آزمایشی", englishLabel: "Trial Rule", pluralLabel: "قوانین دوره آزمایشی", description: "مدت، محدودیت و شرایط استفاده آزمایشی", icon: "◷", accentColor: "bg-green-50 text-green-700", }), "subscription-templates": definePresentation({ label: "الگوی اشتراک", englishLabel: "Subscription Template", pluralLabel: "الگوهای اشتراک", description: "الگوهای آماده برای ایجاد و تمدید اشتراک", icon: "▥", accentColor: "bg-indigo-50 text-indigo-700", }), "discount-campaigns": definePresentation({ label: "کمپین تخفیف", englishLabel: "Discount Campaign", pluralLabel: "کمپین‌های تخفیف", description: "کمپین‌های زمان‌دار تخفیف و فروش", icon: "↓", accentColor: "bg-red-50 text-red-700", }), "regional-pricing": definePresentation({ label: "قیمت منطقه‌ای", englishLabel: "Regional Pricing", pluralLabel: "قیمت‌های منطقه‌ای", description: "تنظیم قیمت متناسب با منطقه و بازار", icon: "⌖", accentColor: "bg-cyan-50 text-cyan-700", }), languages: definePresentation({ label: "زبان", englishLabel: "Language", pluralLabel: "زبان‌ها", description: "زبان‌های قابل استفاده در تجربه مشتری", icon: "文", accentColor: "bg-violet-50 text-violet-700", }), "marketplace-visibility": definePresentation({ label: "نحوه نمایش در بازار", englishLabel: "Marketplace Visibility", pluralLabel: "تنظیمات نمایش در بازار", description: "کنترل نمایش محصولات و خدمات در بازار", icon: "◐", accentColor: "bg-slate-100 text-slate-700", }), "release-channels": definePresentation({ label: "کانال انتشار", englishLabel: "Release Channel", pluralLabel: "کانال‌های انتشار", description: "مسیرهای عرضه نسخه‌های پایدار و آزمایشی", icon: "➜", accentColor: "bg-blue-50 text-blue-700", }), "support-levels": definePresentation({ label: "سطح پشتیبانی", englishLabel: "Support Level", pluralLabel: "سطوح پشتیبانی", description: "سطوح پاسخ‌گویی و خدمات پشتیبانی", icon: "☏", accentColor: "bg-emerald-50 text-emerald-700", }), "activation-logs": definePresentation({ label: "فرایند فعال‌سازی", englishLabel: "Activation Process", pluralLabel: "فرایندهای فعال‌سازی", description: "مراحل آماده‌سازی محصولات برای فضای کاری", icon: "▶", accentColor: "bg-lime-50 text-lime-700", }), } satisfies Record; export type PresentationRegistryKind = keyof typeof presentationRegistry; const KIND_ALIASES: Readonly> = { product: "products", bundle: "bundles", price: "pricing", prices: "pricing", plan: "plans", capability: "capabilities", "business-type": "business-types", recommendations: "recommendation-rules", recommendation: "recommendation-rules", "recommendation-rules": "recommendation-rules", assessments: "assessment-schemas", "tax-classes": "taxes", tax: "taxes", notification: "notifications", invoice: "invoices", transaction: "transactions", license: "licenses", entitlement: "entitlements", subscription: "subscriptions", }; export function normalizeRegistryKind(kind: string): PresentationRegistryKind | null { const normalized = kind.trim().toLowerCase().replace(/_/g, "-"); if (normalized in presentationRegistry) return normalized as PresentationRegistryKind; return KIND_ALIASES[normalized] || null; } export function getRegistryPresentation(kind: string): RegistryPresentation { const normalized = normalizeRegistryKind(kind); if (normalized) return presentationRegistry[normalized]; return definePresentation({ label: "بخش تجاری جدید", englishLabel: "New Commercial Section", pluralLabel: "اطلاعات بخش تجاری جدید", description: "اطلاعات این بخش پس از تکمیل عنوان نمایشی قابل مدیریت است.", icon: "◈", accentColor: "bg-slate-100 text-slate-700", }); } const TOKEN_LABELS: Readonly> = { restaurant: "رستوران", hospitality: "رستوران و پذیرایی", food: "غذا", beverage: "پذیرایی", platform: "پلتفرم", starter: "شروع", start: "شروع", growth: "رشد", professional: "حرفه‌ای", pro: "حرفه‌ای", enterprise: "سازمانی", loyalty: "باشگاه مشتریان", delivery: "ارسال و پیک", booking: "رزرو", reservation: "رزرو", payment: "پرداخت", accounting: "حسابداری", website: "وب‌سایت", experience: "وب‌سایت و تجربه دیجیتال", crm: "مدیریت ارتباط با مشتری", inventory: "انبارداری", pos: "صندوق فروش", communication: "ارتباط با مشتریان", marketplace: "بازار آنلاین", sports: "مجموعه ورزشی", "sports-center": "مجموعه ورزشی", identity: "مدیریت کاربران", operations: "عملیات", sales: "فروش", marketing: "بازاریابی", finance: "مالی", customers: "مشتریان", online: "حضور آنلاین", online_presence: "حضور آنلاین", automation: "اتوماسیون", ai: "هوش مصنوعی", retail: "خرده‌فروشی", service: "خدمات", services: "خدمات", ecommerce: "فروشگاه آنلاین", clinic: "مرکز درمانی", healthcare: "سلامت و درمان", beauty: "زیبایی و سلامت", education: "آموزش", monthly: "ماهانه", month: "ماهانه", yearly: "سالانه", annual: "سالانه", year: "سالانه", trial: "آزمایشی", public: "قابل مشاهده برای همه", private: "فقط مشتریان مجاز", hidden: "پنهان", admin: "فقط مدیران", route: "داخل سامانه", external: "پیوند بیرونی", disabled: "غیرفعال", deny: "غیرفعال", allow: "فعال", enterprise_quote: "استعلام قیمت", enterprisequote: "استعلام قیمت", irr: "ریال", rial: "ریال", recommended: "پیشنهاد‌شده", popular: "محبوب", most_popular: "محبوب‌ترین", recurring: "اشتراکی", flat: "مبلغ ثابت", one_time: "پرداخت یک‌باره", usage_based: "بر اساس مصرف", per_user: "به‌ازای هر کاربر", free: "رایگان", standard: "استاندارد", premium: "ویژه", unlimited: "نامحدود", required: "ضروری", optional: "پیشنهادی", later: "قابل افزودن در آینده", ...STATUS_LABELS, }; export const FIELD_LABELS: Readonly> = { display_name: "نام", name: "نام", title: "عنوان", description: "توضیح کوتاه", status: "وضعیت", role: "نوع اشتراک", pricing_model: "مدل پرداخت", amount_minor: "قیمت", currency: "واحد پول", interval: "دوره پرداخت", trial_days: "مدت دوره آزمایشی", duration_days: "مدت دوره آزمایشی", grace_period_days: "مهلت تمدید", product_codes: "محصولات", capability_codes: "قابلیت‌ها", required_capabilities: "قابلیت‌های موردنیاز", feature_refs: "امکانات", pricing_refs: "روش‌های پرداخت", discount_refs: "تخفیف‌ها", coupon_code: "کد تخفیف", tax_class_code: "گروه مالیاتی", trial_eligible: "امکان استفاده آزمایشی", visibility: "نحوه نمایش", display_order: "اولویت نمایش", category: "دسته‌بندی", is_verified: "وضعیت تأیید", domain_type: "نوع دامنه", current_period_end: "تاریخ تمدید", trial_ends_at: "پایان دوره آزمایشی", created_at: "تاریخ ایجاد", updated_at: "آخرین تغییر", published_at: "تاریخ انتشار", starts_at: "تاریخ شروع", ends_at: "تاریخ پایان", version: "نسخه", metadata: "اطلاعات تکمیلی", attributes: "ویژگی‌ها", parameters: "تنظیمات", usage_limits: "سقف استفاده", feature_limits: "محدودیت امکانات", auto_disable: "غیرفعال‌سازی خودکار", expiration_behavior: "رفتار پس از پایان", ssl_ready: "وضعیت گواهی امنیتی", dns_instructions: "راهنمای اتصال دامنه", custom_domain_allowed: "دامنه اختصاصی", subdomain_only: "فقط زیردامنه", reason: "دلیل پیشنهاد", priority: "اولویت", sellable: "قابل فروش", lifecycle: "مرحله ارائه", recommended_products: "محصولات ضروری", recommended_bundles: "بسته‌های پیشنهادی", recommended_services: "خدمات پیشنهادی", recommended_upgrades: "پیشنهادهای قابل افزودن", recommended_automation_packs: "اتوماسیون‌های پیشنهادی", recommended_extensions: "افزونه‌های پیشنهادی", score: "میزان تطبیق", }; export const COMMERCIAL_FIELD_GROUPS = [ { title: "اطلاعات پایه", keys: ["display_name", "title", "description", "category"], }, { title: "اطلاعات تجاری", keys: [ "role", "pricing_model", "amount_minor", "currency", "interval", "trial_days", "duration_days", "grace_period_days", ], }, { title: "قیمت‌گذاری", keys: ["pricing_refs", "tax_class_code", "discount_refs", "coupon_code"], }, { title: "قابلیت‌ها", keys: [ "product_codes", "capability_codes", "feature_refs", "required_capabilities", ], }, { title: "نمایش", keys: ["visibility", "display_order", "trial_eligible"], }, { title: "انتشار", keys: ["status", "lifecycle", "published_at", "starts_at", "ends_at"], }, { title: "اطلاعات تکمیلی", keys: ["metadata", "attributes", "parameters", "usage_limits", "feature_limits"], }, ] as const; export const FIELD_ENUM_OPTIONS: Readonly> = { status: [ "draft", "active", "published", "inactive", "suspended", "archived", ], visibility: ["public", "private", "hidden", "admin"], pricing_model: [ "monthly", "yearly", "trial", "enterprise_quote", "one_time", "usage_based", ], interval: ["monthly", "yearly"], currency: ["IRR"], lifecycle: ["concept", "planned", "beta", "ga", "mature", "deprecated"], }; const REFERENCE_KIND_BY_FIELD: Readonly> = { product_codes: "products", products: "products", recommended_products: "products", recommended_services: "products", bundle_codes: "bundles", bundles: "bundles", recommended_bundles: "bundles", pricing_refs: "pricing", pricing_items: "pricing", capability_codes: "capabilities", capabilities: "capabilities", feature_refs: "capabilities", required_capabilities: "capabilities", recommended_upgrades: "products", recommended_automation_packs: "automation-packs", recommended_extensions: "extensions", }; export function registryKindForField( field?: string | null ): PresentationRegistryKind | null { if (!field) return null; return REFERENCE_KIND_BY_FIELD[field] || null; } const TECHNICAL_FIELD = /(^id$|_id$|_code$|^code$|^kind$|^slug$|^stable_code$|^payload$|^raw_json$|^source$|^version_code$|^schema_version$|^rule_trace$|^href$|_route$|launch_strategy|created_by|updated_by|is_deleted|clone_of_id)/i; export function isTechnicalField(key: string): boolean { return TECHNICAL_FIELD.test(key); } export function fieldLabel(key: string): string { if (FIELD_LABELS[key]) return FIELD_LABELS[key]; const translated = key .split(/[_\-.]+/) .map((token) => TOKEN_LABELS[token.toLowerCase()] || "") .filter(Boolean) .join(" "); return translated || "ویژگی تکمیلی"; } export function enumLabel(value: unknown): string { if (typeof value === "boolean") return value ? "بله" : "خیر"; if (value == null || value === "") return "ثبت نشده"; const raw = String(value).trim(); const normalized = raw.toLowerCase().replace(/[-\s]+/g, "_"); const translated = TOKEN_LABELS[normalized] || humanizeCommercialCode(raw); return translated === "عنوان تجاری ثبت‌نشده" ? "سایر" : translated; } function hasPersian(value?: string | null): boolean { return Boolean(value && /[\u0600-\u06ff]/.test(value)); } function translatedTokens(tokens: string[]): string[] { return tokens .map((token) => TOKEN_LABELS[token.toLowerCase()] || "") .filter(Boolean); } type CodeFormatterContext = { translated: string[]; subject: string; interval: string; }; const CODE_FORMATTERS: Readonly< Record string> > = { price: ({ translated, interval }) => { const business = translated[0] || "کسب‌وکار"; const tier = translated.slice(1).join(" "); return `پلن ${business}${tier ? ` — نسخه ${tier}` : ""}${interval ? ` (${interval})` : ""}`; }, pricing: ({ translated, interval }) => CODE_FORMATTERS.price({ translated, subject: translated.join(" "), interval }), plan: ({ translated, interval }) => CODE_FORMATTERS.price({ translated, subject: translated.join(" "), interval }), bundle: ({ translated }) => { const business = translated.find((token) => token !== "شروع") || "کسب‌وکار"; const tier = translated.includes("شروع") ? "شروع" : translated.slice(1).join(" "); return `بسته ${tier || "خدمات"} ${business}`.trim(); }, product: ({ subject }) => `سیستم ${subject || "مدیریت کسب‌وکار"}`, capability: ({ subject }) => subject || "قابلیت کاربردی", feature: ({ subject }) => subject || "قابلیت کاربردی", tax: ({ subject }) => subject || "گروه مالیاتی", coupon: ({ subject }) => subject || "تخفیف", discount: ({ subject }) => subject || "تخفیف", }; export function humanizeCommercialCode(code: unknown, explicitName?: string | null): string { if (explicitName && hasPersian(explicitName)) return explicitName.trim(); if (code == null) return "عنوان تجاری ثبت‌نشده"; const raw = String(code).trim(); if (!raw) return "عنوان تجاری ثبت‌نشده"; const normalized = raw.toLowerCase().replace(/_/g, "-"); if (TOKEN_LABELS[normalized]) return TOKEN_LABELS[normalized]; const tokens = raw.toLowerCase().split(/[._:/-]+/).filter(Boolean); const kind = tokens[0]; const body = tokens.slice(1); const intervalToken = body.find((token) => /^(monthly|month|yearly|annual|year|trial)$/.test(token)); const interval = intervalToken ? TOKEN_LABELS[intervalToken] : ""; const subjectTokens = body.filter((token) => token !== intervalToken); const translated = translatedTokens(subjectTokens); const subject = translated.join(" "); const formatter = CODE_FORMATTERS[kind]; if (formatter) return formatter({ translated, subject, interval }); if (subject) return subject; if (hasPersian(raw)) return raw; return "عنوان تجاری ثبت‌نشده"; } export function commercialEntityName( kind: string, code: unknown, explicitName?: string | null ): string { if (explicitName && hasPersian(explicitName)) return explicitName.trim(); const normalizedKind = normalizeRegistryKind(kind); const raw = code == null ? "" : String(code); const entityPrefixes: Partial> = { products: "product", bundles: "bundle", pricing: "price", plans: "price", capabilities: "capability", }; const prefix = normalizedKind ? entityPrefixes[normalizedKind] : null; if (prefix) { const translated = humanizeCommercialCode( raw.startsWith(`${prefix}.`) ? raw : `${prefix}.${raw}` ); const genericFallbacks = [ "سیستم مدیریت کسب‌وکار", "بسته خدمات کسب‌وکار", "پلن کسب‌وکار", "قابلیت کاربردی", ]; if ( genericFallbacks.includes(translated) && explicitName?.trim() && !looksTechnical(explicitName) ) { return `${getRegistryPresentation(kind).label} ${explicitName.trim()}`; } return translated; } return humanizeCommercialCode(raw, explicitName); } export function commercialDescription( kind: string, description?: string | null ): string { if (description && hasPersian(description)) return description.trim(); return getRegistryPresentation(kind).description; } export function looksTechnical(value: string): boolean { return ( /[a-z0-9]+[._:/][a-z0-9_.:/-]+/i.test(value) || /^[a-z][a-z0-9_-]+$/i.test(value) || /\b(payload|json|registry|runtime|frontend|backend|metadata|heuristic|fallback|trace|api)\b/i.test( value ) ); } export function formatMoney(amount?: number | null, currency?: string | null): string { if (amount == null) return "استعلام قیمت"; const unit = !currency || /irr|rial/i.test(currency) ? "ریال" : enumLabel(currency); return `${new Intl.NumberFormat("fa-IR").format(amount)} ${unit}`; } export function formatDate(value?: string | null): string { if (!value) return "ثبت نشده"; const date = new Date(value); return Number.isNaN(date.getTime()) ? "ثبت نشده" : new Intl.DateTimeFormat("fa-IR", { dateStyle: "medium" }).format(date); } export function friendlyMessage( message?: string | null, fallback = "در حال حاضر اطلاعاتی برای نمایش نداریم." ): string { if (!message || looksTechnical(message) || /\b(4\d\d|5\d\d)\b/.test(message)) { return fallback; } return message.replace(/\[object Object\]/g, "اطلاعات تکمیلی"); } export function recommendationReason(reason?: string | null): string { if (!reason || looksTechnical(reason)) return "بر اساس پاسخ‌های شما"; const normalized = reason.toLowerCase(); if (/branch|شعب/.test(normalized)) return "چون چند شعبه دارید"; if (/delivery|ارسال/.test(normalized)) return "چون ارسال کالا دارید"; if (/online|website|وب/.test(normalized)) return "چون فروش آنلاین دارید"; if (/pos|in.person|حضوری|فروش/.test(normalized)) return "چون فروش حضوری دارید"; if (/loyal|باشگاه/.test(normalized)) return "چون باشگاه مشتریان برای شما مهم است"; if (/booking|reservation|رزرو/.test(normalized)) return "چون به مدیریت رزرو نیاز دارید"; return reason; } export function presentValue( value: unknown ): string | Array> | Record { if (Array.isArray(value)) { return value.map((item) => { if (item && typeof item === "object") return item as Record; return typeof item === "string" ? humanizeCommercialCode(item) : enumLabel(item); }); } if (value && typeof value === "object") return value as Record; if (typeof value === "string") return enumLabel(value); if (typeof value === "boolean") return value ? "بله" : "خیر"; if (typeof value === "number") return new Intl.NumberFormat("fa-IR").format(value); return "ثبت نشده"; }