/** * 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, generateDashboardTasks, type DashboardTask, type DashboardTaskSummary, } from "@customer-portal/domain/dashboard"; import { formatCurrency as formatCurrencyUtil } from "@customer-portal/domain/toolkit"; // Re-export domain business logic for backward compatibility export { ACTIVITY_FILTERS, filterActivities, isActivityClickable, generateDashboardTasks, type DashboardTask, type DashboardTaskSummary, }; /** * 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 `/billing/invoices/${activity.relatedId}`; case "service_activated": return `/subscriptions/${activity.relatedId}`; case "case_created": case "case_closed": return `/support/cases/${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() ? "numeric" : undefined, }); } } catch { return "Unknown date"; } } export function formatActivityDescription(activity: Activity): string { switch (activity.type) { case "invoice_created": case "invoice_paid": { const parsed = invoiceActivityMetadataSchema.safeParse(activity.metadata ?? {}); if (parsed.success && typeof parsed.data.amount === "number") { const formattedAmount = formatCurrencyUtil(parsed.data.amount, parsed.data.currency); if (formattedAmount) { return activity.type === "invoice_paid" ? `${formattedAmount} payment completed` : `${formattedAmount} invoice generated`; } } return activity.description ?? ""; } case "service_activated": { const parsed = serviceActivityMetadataSchema.safeParse(activity.metadata ?? {}); if (parsed.success && parsed.data.productName) { return `${parsed.data.productName} is now active`; } return activity.description ?? ""; } case "case_created": case "case_closed": return activity.description ?? ""; default: return activity.description ?? ""; } } /** * 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); }