/** * Pending Payment Banner * Shows alert banner when account status is 'pending_payment' * Displays invoice details and provides link to payment confirmation */ import { useState, useEffect } from 'react'; import { AlertCircle, CreditCard, X } from 'lucide-react'; import { Link } from 'react-router-dom'; import Button from '../ui/button/Button'; import { useAuthStore } from '../../store/authStore'; import { API_BASE_URL } from '../../services/api'; import PaymentConfirmationModal from './PaymentConfirmationModal'; interface Invoice { id: number; invoice_number: string; total?: string; // For backward compatibility total_amount?: string; // Backend returns 'total_amount' currency: string; status: string; due_date?: string; created_at: string; } interface PendingPaymentBannerProps { className?: string; } export default function PendingPaymentBanner({ className = '' }: PendingPaymentBannerProps) { const [invoice, setInvoice] = useState(null); const [paymentMethod, setPaymentMethod] = useState(null); const [loading, setLoading] = useState(true); const [dismissed, setDismissed] = useState(false); const [showPaymentModal, setShowPaymentModal] = useState(false); const { user, refreshUser } = useAuthStore(); const accountStatus = user?.account?.status; const isPendingPayment = accountStatus === 'pending_payment'; useEffect(() => { if (isPendingPayment && !dismissed) { loadPendingInvoice(); } else { setLoading(false); } }, [isPendingPayment, dismissed]); const loadPendingInvoice = async () => { try { setLoading(true); const token = useAuthStore.getState().token; // Fetch pending invoices for this account const response = await fetch(`${API_BASE_URL}/v1/billing/invoices/?status=pending&limit=1`, { method: 'GET', headers: { 'Content-Type': 'application/json', ...(token && { Authorization: `Bearer ${token}` }), }, credentials: 'include', }); const data = await response.json(); if (response.ok && data.success && data.results?.length > 0) { setInvoice(data.results[0]); // Load payment method if available - use public endpoint const country = (user?.account as any)?.billing_country || 'US'; const pmResponse = await fetch(`${API_BASE_URL}/v1/billing/payment-configs/payment-methods/?country=${country}`, { method: 'GET', headers: { 'Content-Type': 'application/json', }, }); const pmData = await pmResponse.json(); // Use public endpoint response format if (pmResponse.ok && pmData.success && pmData.results?.length > 0) { setPaymentMethod(pmData.results[0]); } else if (pmResponse.ok && Array.isArray(pmData) && pmData.length > 0) { setPaymentMethod(pmData[0]); } } } catch (err) { console.error('Failed to load pending invoice:', err); } finally { setLoading(false); } }; const handleDismiss = () => { setDismissed(true); // Store dismissal in sessionStorage to persist during session sessionStorage.setItem('payment-banner-dismissed', 'true'); }; const handlePaymentSuccess = async () => { setShowPaymentModal(false); // Refresh user data to update account status await refreshUser(); }; // Don't show if not pending payment, loading, or dismissed if (!isPendingPayment || loading || dismissed) { return null; } // Check if already dismissed in this session if (sessionStorage.getItem('payment-banner-dismissed') === 'true') { return null; } // If no invoice found, show simplified banner if (!invoice) { return (

Payment Required

Your account is pending payment. Please complete your payment to activate your subscription.

); } // Format due date const formatDate = (dateString?: string) => { if (!dateString) return 'N/A'; const date = new Date(dateString); return date.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' }); }; const isDueSoon = invoice.due_date && new Date(invoice.due_date) <= new Date(Date.now() + 3 * 24 * 60 * 60 * 1000); const isOverdue = invoice.due_date && new Date(invoice.due_date) < new Date(); return ( <>

{isOverdue ? 'Payment Overdue' : 'Payment Required'}

{isDueSoon && !isOverdue && ( Due Soon )}

Your subscription is pending payment confirmation. Complete your payment to activate your account and unlock all features.

{/* Invoice Details */}
Invoice #{invoice.invoice_number}
Amount {invoice.currency} {invoice.total_amount}
Status {invoice.status}
{isOverdue ? 'Was Due' : 'Due Date'} {formatDate(invoice.due_date)}
{/* Action Buttons */}
{/* Dismiss Button */}
{/* Payment Confirmation Modal */} {showPaymentModal && invoice && ( setShowPaymentModal(false)} onSuccess={handlePaymentSuccess} invoice={invoice} paymentMethod={paymentMethod || { payment_method: 'bank_transfer', display_name: 'Bank Transfer', country_code: 'US' }} /> )} ); }