"use client"; import { useState, useEffect } from "react"; import { PageLayout } from "@/components/templates/PageLayout"; import { ErrorBoundary } from "@/components/molecules"; import { useSession } from "@/features/auth/hooks"; import { useAuthStore } from "@/features/auth/services/auth.store"; import { isApiError } from "@/lib/api"; import { openSsoLink } from "@/features/billing/utils/sso"; import { usePaymentRefresh } from "@/features/billing/hooks/usePaymentRefresh"; import { PaymentMethodCard, usePaymentMethods, useCreatePaymentMethodsSsoLink, } from "@/features/billing"; import { CreditCardIcon } from "@heroicons/react/24/outline"; import { InlineToast } from "@/components/atoms/inline-toast"; import { Button } from "@/components/atoms/button"; import { AsyncBlock } from "@/components/molecules/AsyncBlock/AsyncBlock"; import { Skeleton } from "@/components/atoms/loading-skeleton"; import { logger } from "@/lib/logger"; export function PaymentMethodsContainer() { const [error, setError] = useState(null); const { isAuthenticated } = useSession(); const paymentMethodsQuery = usePaymentMethods(); const { data: paymentMethodsData, isLoading: isLoadingPaymentMethods, isFetching: isFetchingPaymentMethods, error: paymentMethodsError, } = paymentMethodsQuery; const createPaymentMethodsSsoLink = useCreatePaymentMethodsSsoLink(); // 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 => Boolean(data && (data.totalCount > 0 || data.paymentMethods.length > 0)), attachFocusListeners: true, }); const openPaymentMethods = async () => { if (!isAuthenticated) { setError("Please log in to access payment methods."); return; } setError(null); try { const ssoLink = await createPaymentMethodsSsoLink.mutateAsync(); openSsoLink(ssoLink.url, { newTab: true }); } catch (err: unknown) { logger.error(err, "Failed to open payment methods"); // Check if error looks like an API error with response if ( isApiError(err) && "response" in err && typeof err.response === "object" && err.response !== null && "status" in err.response && err.response.status === 401 ) { setError("Authentication failed. Please log in again."); } else { setError("Unable to access payment methods. Please try again later."); } } }; useEffect(() => { // Placeholder hook for future logic when returning from WHMCS }, [isAuthenticated]); const combinedError = error ? new Error(error) : paymentMethodsError instanceof Error ? paymentMethodsError : paymentMethodsError ? new Error(String(paymentMethodsError)) : null; if (combinedError) { return ( } title="Payment Methods" description="Manage your saved payment methods and billing information" > <> ); } return ( } title="Payment Methods" description="Manage your saved payment methods and billing information" >
{!hasCheckedAuth || isLoadingPaymentMethods || isFetchingPaymentMethods ? (
{Array.from({ length: 2 }).map((_, i) => (
))}
) : paymentMethodsData && paymentMethodsData.paymentMethods.length > 0 ? (

Your Payment Methods

{paymentMethodsData.paymentMethods.length} payment method {paymentMethodsData.paymentMethods.length !== 1 ? "s" : ""} on file

Opens in a new tab for security

{paymentMethodsData.paymentMethods.map(paymentMethod => ( ))}
) : (
{!hasCheckedAuth && !paymentMethodsData ? (
<>
) : (

No Payment Methods

Open the billing portal to add a card.

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;