"use client"; import { useState } from "react"; import Link from "next/link"; import { useRouter } from "next/navigation"; import type { Activity, DashboardSummary } from "@customer-portal/domain"; import { ServerIcon, ChatBubbleLeftRightIcon, ChevronRightIcon, DocumentTextIcon, ArrowTrendingUpIcon, CalendarDaysIcon, } from "@heroicons/react/24/outline"; import { CreditCardIcon as CreditCardIconSolid, ServerIcon as ServerIconSolid, ChatBubbleLeftRightIcon as ChatBubbleLeftRightIconSolid, ClipboardDocumentListIcon as ClipboardDocumentListIconSolid, } from "@heroicons/react/24/solid"; import { format, formatDistanceToNow } from "date-fns"; import { useAuthStore } from "@/features/auth/services/auth.store"; import { useDashboardSummary } from "@/features/dashboard/hooks"; import { StatCard, QuickAction, DashboardActivityItem } from "@/features/dashboard/components"; import { LoadingStats, LoadingTable } from "@/components/atoms"; import { ErrorState } from "@/components/atoms/error-state"; import { formatCurrency, getCurrencyLocale } from "@customer-portal/domain"; import { log } from "@customer-portal/logging"; import { useCreateInvoiceSsoLink } from "@/features/billing/hooks/useBilling"; export function DashboardView() { const router = useRouter(); const { user, isAuthenticated, loading: authLoading } = useAuthStore(); const { data: summary, isLoading: summaryLoading, error } = useDashboardSummary(); const upcomingInvoice = summary?.nextInvoice ?? null; const createSsoLinkMutation = useCreateInvoiceSsoLink(); const [paymentLoading, setPaymentLoading] = useState(false); const [paymentError, setPaymentError] = useState(null); // Handle Pay Now functionality const handlePayNow = (invoiceId: number) => { setPaymentLoading(true); setPaymentError(null); void (async () => { try { const ssoLink = await createSsoLinkMutation.mutateAsync({ invoiceId, target: "pay" }); window.open(ssoLink.url, "_blank", "noopener,noreferrer"); } catch (error) { log.error("Failed to create payment link", { invoiceId, error: error instanceof Error ? error.message : String(error) }); setPaymentError(error instanceof Error ? error.message : "Failed to open payment page"); } finally { setPaymentLoading(false); } })(); }; // Handle activity item clicks const handleActivityClick = (activity: Activity) => { if (activity.type === "invoice_created" || activity.type === "invoice_paid") { // Use the related invoice ID for navigation if (activity.relatedId) { router.push(`/billing/invoices/${activity.relatedId}`); } } }; if (authLoading || summaryLoading || !isAuthenticated) { return (

Loading dashboard...

); } // Handle error state if (error) { return ( ); } return ( <>
{/* Modern Header */}

Welcome back, {user?.firstName || user?.email?.split("@")[0] || "User"}!

{/* Tasks chip */}
Portal / Dashboard
{/* No duplicate page-level CTAs here per guidelines */}
{/* Modern Stats Grid */}
0 ? "from-amber-500 to-orange-500" : "from-gray-500 to-gray-600" } href="/billing/invoices" zeroHint={{ text: "Set up auto-pay", href: "/billing/payments" }} /> 0 ? "from-blue-500 to-cyan-500" : "from-gray-500 to-gray-600" } href="/support/cases" zeroHint={{ text: "Open a ticket", href: "/support/new" }} />
{/* Main Content Area */}
{/* Upcoming Payment - compressed attention banner */} {upcomingInvoice && (
Upcoming Payment Invoice #{upcomingInvoice.id} Due{" "} {formatDistanceToNow(new Date(upcomingInvoice.dueDate), { addSuffix: true, })}
{formatCurrency(upcomingInvoice.amount, { currency: upcomingInvoice.currency || "JPY", locale: getCurrencyLocale(upcomingInvoice.currency || "JPY"), })}
Exact due date: {format(new Date(upcomingInvoice.dueDate), "MMMM d, yyyy")}
View invoice
)} {/* Payment Error Display */} {paymentError && ( setPaymentError(null)} retryLabel="Dismiss" /> )} {/* Recent Activity - filtered list */}
{/* Sidebar */}
{/* Quick Actions - simplified */}

Quick Actions

); } // Helpers and small components (local to dashboard) function TasksChip({ summaryLoading, summary, }: { summaryLoading: boolean; summary: DashboardSummary | undefined; }) { const router = useRouter(); if (summaryLoading) return null; const tasks: Array<{ label: string; href: string }> = []; if (summary?.nextInvoice) tasks.push({ label: "Pay upcoming invoice", href: "#attention" }); const count = tasks.length; if (count === 0) return null; return ( ); } function RecentActivityCard({ activities, onItemClick, }: { activities: Activity[]; onItemClick: (a: Activity) => void; }) { const [filter, setFilter] = useState<"all" | "billing" | "orders" | "support">("all"); const filtered = activities.filter(a => { if (filter === "all") return true; if (filter === "billing") return a.type === "invoice_created" || a.type === "invoice_paid"; if (filter === "orders") return a.type === "service_activated"; if (filter === "support") return a.type === "case_created" || a.type === "case_closed"; return true; }); return (

Recent Activity

{( [ { k: "all", label: "All" }, { k: "billing", label: "Billing" }, { k: "orders", label: "Orders" }, { k: "support", label: "Support" }, ] as const ).map(opt => ( ))}
{filtered.length > 0 ? (
{filtered.slice(0, 10).map(activity => { const isClickable = activity.type === "invoice_created" || activity.type === "invoice_paid"; return ( onItemClick(activity) : undefined} /> ); })}
) : (

No recent activity

Your account activity will appear here.

)}
); }