- Updated CacheModule and CacheService with detailed documentation and new methods for better cache management, including pattern deletion and memory usage tracking. - Refactored CatalogCacheService and OrdersCacheService to utilize CDC-driven cache invalidation, improving data freshness and reducing unnecessary API calls. - Introduced SIM plan options and updated related components to leverage new domain utilities for better plan management and user experience. - Enhanced error handling and validation in TopUpModal for improved user feedback during SIM top-up operations. - Removed obsolete plan formatting utilities to streamline codebase and improve maintainability.
68 lines
2.8 KiB
TypeScript
68 lines
2.8 KiB
TypeScript
"use client";
|
|
|
|
import Link from "next/link";
|
|
import { CalendarDaysIcon, ChevronRightIcon } from "@heroicons/react/24/outline";
|
|
import { format, formatDistanceToNow } from "date-fns";
|
|
|
|
import { useFormatCurrency } from "@/lib/hooks/useFormatCurrency";
|
|
import type { NextInvoice } from "@customer-portal/domain/dashboard";
|
|
|
|
interface UpcomingPaymentBannerProps {
|
|
invoice: NextInvoice;
|
|
onPay?: (invoiceId: number) => void;
|
|
loading?: boolean;
|
|
}
|
|
|
|
export function UpcomingPaymentBanner({ invoice, onPay, loading }: UpcomingPaymentBannerProps) {
|
|
const { formatCurrency } = useFormatCurrency();
|
|
|
|
return (
|
|
<div id="attention" className="bg-white rounded-xl border border-orange-200 shadow-sm p-4">
|
|
<div className="flex items-center gap-4">
|
|
<div className="flex-shrink-0">
|
|
<div className="w-10 h-10 rounded-md bg-gradient-to-r from-amber-500 to-orange-500 flex items-center justify-center">
|
|
<CalendarDaysIcon className="h-5 w-5 text-white" />
|
|
</div>
|
|
</div>
|
|
<div className="flex-1 min-w-0">
|
|
<div className="flex flex-wrap items-center gap-2 text-sm text-gray-700">
|
|
<span className="font-semibold text-gray-900">Upcoming Payment</span>
|
|
<span className="text-gray-400">•</span>
|
|
<span>Invoice #{invoice.id}</span>
|
|
<span className="text-gray-400">•</span>
|
|
<span title={format(new Date(invoice.dueDate), "MMMM d, yyyy")}>
|
|
Due {formatDistanceToNow(new Date(invoice.dueDate), { addSuffix: true })}
|
|
</span>
|
|
</div>
|
|
<div className="mt-1 text-2xl font-bold text-gray-900">
|
|
{formatCurrency(invoice.amount, { currency: invoice.currency })}
|
|
</div>
|
|
<div className="mt-1 text-xs text-gray-500">
|
|
Exact due date: {format(new Date(invoice.dueDate), "MMMM d, yyyy")}
|
|
</div>
|
|
</div>
|
|
<div className="flex flex-col items-end gap-2">
|
|
{onPay && (
|
|
<button
|
|
onClick={() => onPay(invoice.id)}
|
|
disabled={loading}
|
|
className="inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 transition-all disabled:opacity-50 disabled:cursor-not-allowed"
|
|
>
|
|
{loading ? "Opening Payment..." : "Pay Now"}
|
|
{!loading && <ChevronRightIcon className="ml-2 h-4 w-4" />}
|
|
</button>
|
|
)}
|
|
<Link
|
|
href={`/billing/invoices/${invoice.id}`}
|
|
className="text-blue-600 hover:text-blue-700 font-medium text-sm"
|
|
>
|
|
View invoice
|
|
</Link>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export type { UpcomingPaymentBannerProps };
|