import type { TenantPackageSummary } from '../../api'; type Translate = any; type LimitUsageOverrides = { remainingEvents?: number | null; usedEvents?: number | null; }; const FEATURE_LABELS: Record = { priority_support: { key: 'mobileDashboard.packageSummary.feature.priority_support', fallback: 'Priority support', }, reseller_dashboard: { key: 'mobileDashboard.packageSummary.feature.reseller_dashboard', fallback: 'Reseller dashboard', }, custom_domain: { key: 'mobileDashboard.packageSummary.feature.custom_domain', fallback: 'Custom domain', }, custom_branding: { key: 'mobileDashboard.packageSummary.feature.custom_branding', fallback: 'Custom branding', }, custom_tasks: { key: 'mobileDashboard.packageSummary.feature.custom_tasks', fallback: 'Custom tasks', }, unlimited_sharing: { key: 'mobileDashboard.packageSummary.feature.unlimited_sharing', fallback: 'Unlimited sharing', }, analytics: { key: 'mobileDashboard.packageSummary.feature.analytics', fallback: 'Analytics', }, advanced_reporting: { key: 'mobileDashboard.packageSummary.feature.advanced_reporting', fallback: 'Advanced reporting', }, live_slideshow: { key: 'mobileDashboard.packageSummary.feature.live_slideshow', fallback: 'Live slideshow', }, basic_uploads: { key: 'mobileDashboard.packageSummary.feature.basic_uploads', fallback: 'Guest uploads', }, team_management: { key: 'mobileDashboard.packageSummary.feature.team_management', fallback: 'Team management', }, moderation_tools: { key: 'mobileDashboard.packageSummary.feature.moderation_tools', fallback: 'Moderation tools', }, prints: { key: 'mobileDashboard.packageSummary.feature.prints', fallback: 'Print uploads', }, photo_likes_enabled: { key: 'mobileDashboard.packageSummary.feature.photo_likes_enabled', fallback: 'Photo likes', }, event_checklist: { key: 'mobileDashboard.packageSummary.feature.event_checklist', fallback: 'Event checklist', }, advanced_analytics: { key: 'mobileDashboard.packageSummary.feature.advanced_analytics', fallback: 'Advanced analytics', }, branding_allowed: { key: 'mobileDashboard.packageSummary.feature.branding_allowed', fallback: 'Branding', }, watermark_allowed: { key: 'mobileDashboard.packageSummary.feature.watermark_allowed', fallback: 'Watermarks', }, }; const LIMIT_LABELS: Array<{ key: string; labelKey: string; fallback: string }> = [ { key: 'max_photos', labelKey: 'packageLimits.max_photos', fallback: 'Photos', }, { key: 'max_guests', labelKey: 'packageLimits.max_guests', fallback: 'Guests', }, { key: 'max_tasks', labelKey: 'packageLimits.max_tasks', fallback: 'Tasks', }, { key: 'gallery_days', labelKey: 'packageLimits.gallery_days', fallback: 'Gallery days', }, { key: 'max_events_per_year', labelKey: 'packageLimits.max_events_per_year', fallback: 'Events per year', }, ]; export type PackageLimitEntry = { key: string; label: string; value: string; }; const toNumber = (value: unknown): number | null => { if (typeof value === 'number' && Number.isFinite(value)) { return value; } if (typeof value === 'string' && value.trim() !== '') { const parsed = Number(value); if (Number.isFinite(parsed)) { return parsed; } } return null; }; const formatLimitWithRemaining = (limit: number | null, remaining: number | null, t: Translate): string => { if (limit === null || limit === undefined) { return t('mobileDashboard.packageSummary.unlimited', 'Unlimited'); } if (remaining !== null && remaining >= 0) { const normalizedRemaining = Number.isFinite(remaining) ? Math.max(0, Math.round(remaining)) : remaining; if (normalizedRemaining > limit) { return t('mobileBilling.usage.remaining', { count: normalizedRemaining, defaultValue: 'Remaining {{count}}', }); } return t('mobileBilling.usage.remainingOf', { remaining: normalizedRemaining, limit, defaultValue: '{{remaining}} of {{limit}} remaining', }); } return String(limit); }; export function getPackageFeatureLabel(feature: string, t: Translate): string { const entry = FEATURE_LABELS[feature]; if (entry) { return t(entry.key, entry.fallback); } return t(`mobileDashboard.packageSummary.feature.${feature}`, feature); } export function formatPackageLimit(value: number | null | undefined, t: Translate): string { if (value === null || value === undefined) { return t('mobileDashboard.packageSummary.unlimited', 'Unlimited'); } return String(value); } export function getPackageLimitEntries( limits: Record | null, t: Translate, usageOverrides: LimitUsageOverrides = {} ): PackageLimitEntry[] { if (!limits) { return []; } return LIMIT_LABELS.map(({ key, labelKey, fallback }) => ({ key, label: t(labelKey, fallback), value: formatLimitWithRemaining( toNumber((limits as Record)[key]), resolveRemainingForKey(limits, key, usageOverrides), t ), })); } const resolveRemainingForKey = ( limits: Record, key: string, usageOverrides: LimitUsageOverrides ): number | null => { if (key === 'max_events_per_year') { return toNumber(usageOverrides.remainingEvents ?? limits.remaining_events); } const map: Record = { max_photos: 'remaining_photos', max_guests: 'remaining_guests', gallery_days: 'remaining_gallery_days', }; const remainingKey = map[key]; if (!remainingKey) { return null; } return toNumber(limits[remainingKey]); }; export function collectPackageFeatures(pkg: TenantPackageSummary): string[] { const features = new Set(); const direct = Array.isArray(pkg.features) ? pkg.features : []; const limitFeatures = Array.isArray((pkg.package_limits as any)?.features) ? (pkg.package_limits as any).features : []; direct.forEach((feature) => { if (typeof feature === 'string' && feature.trim()) { features.add(feature); } }); limitFeatures.forEach((feature: unknown) => { if (typeof feature === 'string' && feature.trim()) { features.add(feature); } }); if (pkg.branding_allowed) { features.add('branding_allowed'); } if (pkg.watermark_allowed) { features.add('watermark_allowed'); } return Array.from(features); } export function formatEventUsage(used: number | null, limit: number | null, t: Translate): string | null { if (limit === null || used === null) { return null; } return t('mobileBilling.eventsCreated', { used, limit, defaultValue: '{{used}} of {{limit}} events created' }); }