139 lines
3.9 KiB
TypeScript
Raw Normal View History

/**
* 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<string, boolean>): number {
const states = Object.values(loadingStates);
const completedCount = states.filter(loading => !loading).length;
return Math.round((completedCount / states.length) * 100);
}