/** * Dashboard Utilities * Helper functions for dashboard data processing and formatting */ import { invoiceActivityMetadataSchema, serviceActivityMetadataSchema, type Activity, // Re-export business logic from domain ACTIVITY_FILTERS, filterActivities, isActivityClickable, generateQuickActions, type QuickActionTask, type DashboardTaskSummary, } from "@customer-portal/domain/dashboard"; import { Formatting } from "@customer-portal/domain/toolkit"; // Re-export domain business logic for backward compatibility export { ACTIVITY_FILTERS, filterActivities, isActivityClickable, generateQuickActions, type QuickActionTask, type DashboardTaskSummary, }; const formatCurrencyUtil = Formatting.formatCurrency; /** * Get navigation path for an activity */ export function getActivityNavigationPath(activity: Activity): string | null { if (!isActivityClickable(activity) || !activity.relatedId) { return null; } switch (activity.type) { case "invoice_created": case "invoice_paid": return `/account/billing/invoices/${activity.relatedId}`; case "service_activated": return `/account/subscriptions/${activity.relatedId}`; case "case_created": case "case_closed": return `/account/support/${activity.relatedId}`; default: return null; } } /** * Format activity date for display */ export function formatActivityDate(date: string): string { try { const activityDate = new Date(date); const now = new Date(); const diffInHours = (now.getTime() - activityDate.getTime()) / (1000 * 60 * 60); if (diffInHours < 1) { const diffInMinutes = Math.floor(diffInHours * 60); return diffInMinutes <= 1 ? "Just now" : `${diffInMinutes} minutes ago`; } else if (diffInHours < 24) { const hours = Math.floor(diffInHours); return `${hours} hour${hours === 1 ? "" : "s"} ago`; } else if (diffInHours < 48) { return "Yesterday"; } else { return activityDate.toLocaleDateString("en-US", { month: "short", day: "numeric", year: activityDate.getFullYear() === now.getFullYear() ? undefined : "numeric", }); } } catch { return "Unknown date"; } } function formatInvoiceActivity(activity: Activity): string | null { const parsed = invoiceActivityMetadataSchema.safeParse(activity.metadata ?? {}); if (!parsed.success || typeof parsed.data.amount !== "number") { return null; } const formattedAmount = formatCurrencyUtil(parsed.data.amount, parsed.data.currency); if (!formattedAmount) { return null; } return activity.type === "invoice_paid" ? `${formattedAmount} payment completed` : `${formattedAmount} invoice generated`; } function formatServiceActivity(activity: Activity): string | null { const parsed = serviceActivityMetadataSchema.safeParse(activity.metadata ?? {}); if (!parsed.success || !parsed.data.productName) { return null; } return `${parsed.data.productName} is now active`; } export function formatActivityDescription(activity: Activity): string { const fallback = activity.description ?? ""; switch (activity.type) { case "invoice_created": case "invoice_paid": return formatInvoiceActivity(activity) ?? fallback; case "service_activated": return formatServiceActivity(activity) ?? fallback; default: return fallback; } } /** * Truncate text to specified length */ export function truncateText(text: string, maxLength = 28): string { if (text.length <= maxLength) { return text; } return text.slice(0, Math.max(0, maxLength - 1)) + "…"; } /** * Calculate dashboard loading progress */ export function calculateLoadingProgress(loadingStates: Record): number { const states = Object.values(loadingStates); const completedCount = states.filter(loading => !loading).length; return Math.round((completedCount / states.length) * 100); }