"use client"; import { useState, useEffect } from "react"; import { PageLayout } from "@/components/layout/PageLayout"; import { ErrorBoundary } from "@/components/common"; import { SubCard } from "@/components/ui/sub-card"; import { useSession } from "@/features/auth/hooks"; import { useAuthStore } from "@/features/auth/services/auth.store"; // ApiClientError import removed - using generic error handling import { apiClient } from "@/core/api"; import { openSsoLink } from "@/features/billing/utils/sso"; import { usePaymentRefresh } from "@/features/billing/hooks/usePaymentRefresh"; import { PaymentMethodCard, usePaymentMethods } from "@/features/billing"; import { CreditCardIcon, PlusIcon } from "@heroicons/react/24/outline"; import { InlineToast } from "@/components/ui/inline-toast"; import { SectionHeader } from "@/components/common"; import { Button } from "@/components/ui/button"; import { AsyncBlock } from "@/components/common/AsyncBlock"; import { LoadingCard, Skeleton } from "@/components/ui/loading-skeleton"; import { logger } from "@customer-portal/logging"; import { EmptyState } from "@/components/ui/empty-state"; export function PaymentMethodsContainer() { const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState(null); const { isAuthenticated } = useSession(); const paymentMethodsQuery = usePaymentMethods(); const { data: paymentMethodsData, isLoading: isLoadingPaymentMethods, isFetching: isFetchingPaymentMethods, error: paymentMethodsError, } = paymentMethodsQuery; // Auth hydration flag to avoid showing empty state before auth is checked const { hasCheckedAuth } = useAuthStore(); const paymentRefresh = usePaymentRefresh({ refetch: async () => { const result = await paymentMethodsQuery.refetch(); return { data: result.data }; }, hasMethods: (data?: { totalCount?: number }) => !!data && (data.totalCount || 0) > 0, attachFocusListeners: true, }); const openPaymentMethods = async () => { try { setIsLoading(true); setError(null); if (!isAuthenticated) { setError("Please log in to access payment methods."); setIsLoading(false); return; } const response = await apiClient.POST('/auth/sso-link', { body: { path: "index.php?rp=/account/paymentmethods" } }); const sso = response.data!; openSsoLink(sso.url, { newTab: true }); setIsLoading(false); } catch (error) { logger.error(error, "Failed to open payment methods"); if (error && typeof error === 'object' && 'status' in error && (error as any).status === 401) setError("Authentication failed. Please log in again."); else setError("Unable to access payment methods. Please try again later."); setIsLoading(false); } }; useEffect(() => { // Placeholder hook for future logic when returning from WHMCS }, [isAuthenticated]); if (error || paymentMethodsError) { const errorObj = error || (paymentMethodsError instanceof Error ? paymentMethodsError : new Error("Unexpected error")); return ( } title="Payment Methods" description="Manage your saved payment methods and billing information" > <> ); } return ( } title="Payment Methods" description="Manage your payment methods in the billing portal." > {/* Simplified: remove verbose banner; controls exist via buttons */}
{!hasCheckedAuth || isLoadingPaymentMethods || isFetchingPaymentMethods ? ( <>
{Array.from({ length: 2 }).map((_, i) => (
))}
) : paymentMethodsData && paymentMethodsData.paymentMethods.length > 0 ? ( } >
{paymentMethodsData.paymentMethods.map(paymentMethod => ( ))}
) : ( {(!hasCheckedAuth && !paymentMethodsData) ? ( <> ) : ( <> } title="No Payment Methods" description="Open the billing portal to add a card." action={{ label: isLoading ? "Opening..." : "Manage Cards", onClick: () => void openPaymentMethods(), }} />

Opens in a new tab for security

)}
)}

Secure & Encrypted

All payment information is securely encrypted and protected with industry-standard security.

Supported Payment Methods

  • • Credit Cards (Visa, MasterCard, American Express)
  • • Debit Cards
); } export default PaymentMethodsContainer;