import { useState, useEffect } from "react"; import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, } from "@/components/ui/dialog"; import { Button } from "@/components/ui/button"; import { Badge } from "@/components/ui/badge"; import { Separator } from "@/components/ui/separator"; import { Textarea } from "@/components/ui/textarea"; import { Label } from "@/components/ui/label"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, } from "@/components/ui/alert-dialog"; import { Play, Pause, XCircle, RefreshCw, Calendar, CreditCard, Package, User, DollarSign, FileText, History } from "lucide-react"; import { toast } from "sonner"; interface Subscription { id: number; order_id: number; product_id: number; variation_id: number; customer_id: number; user_id: number; quantity: number; total: number; status: string; billing_period: string; billing_interval: number; trial_period?: string; trial_end?: string; start_date: string; next_payment_date: string | null; end_date?: string | null; last_payment_date?: string | null; cancelled_date?: string | null; suspension_count: number; payment_method: string; payment_method_title: string; requires_manual_renewal: boolean; created_at: string; updated_at: string; // Enriched data product_name?: string; customer_name?: string; customer_email?: string; currency?: string; } interface SubscriptionDetailDialogProps { subscription: Subscription | null; open: boolean; onOpenChange: (open: boolean) => void; onUpdate: () => void; } const statusColors: Record = { active: "bg-green-100 text-green-800 border-green-300", pending: "bg-yellow-100 text-yellow-800 border-yellow-300", "on-hold": "bg-orange-100 text-orange-800 border-orange-300", cancelled: "bg-red-100 text-red-800 border-red-300", expired: "bg-gray-100 text-gray-800 border-gray-300", "pending-cancel": "bg-orange-100 text-orange-800 border-orange-300", }; const statusLabels: Record = { active: "Active", pending: "Pending", "on-hold": "On Hold", cancelled: "Cancelled", expired: "Expired", "pending-cancel": "Pending Cancellation", }; export function SubscriptionDetailDialog({ subscription: initialSubscription, open, onOpenChange, onUpdate, }: SubscriptionDetailDialogProps) { const [loading, setLoading] = useState(false); const [confirmAction, setConfirmAction] = useState(null); const [note, setNote] = useState(""); const [newStatus, setNewStatus] = useState(""); const [subscription, setSubscription] = useState(initialSubscription); // Update local state when prop changes (e.g., when dialog opens with new subscription) useEffect(() => { setSubscription(initialSubscription); }, [initialSubscription]); if (!subscription) return null; const fetchSubscription = async () => { try { const apiUrl = window.swiftCommerceData?.apiUrl || '/wp-json/swift-commerce/v1'; const response = await fetch( `${apiUrl}/subscriptions/${subscription.id}`, { headers: { "X-WP-Nonce": window.swiftCommerceData?.restNonce || "", }, } ); const data = await response.json(); if (data.success && data.subscription) { setSubscription(data.subscription); } } catch (error) { console.error('Failed to fetch subscription:', error); } }; const formatDate = (dateString: string | null | undefined) => { if (!dateString) return "—"; return new Date(dateString).toLocaleDateString("en-US", { year: "numeric", month: "long", day: "numeric", }); }; const formatDateTime = (dateString: string | null | undefined) => { if (!dateString) return "—"; return new Date(dateString).toLocaleString("en-US", { year: "numeric", month: "short", day: "numeric", hour: "2-digit", minute: "2-digit", }); }; const formatBillingPeriod = (interval: number, period: string) => { if (interval === 1) { return `Every ${period}`; } return `Every ${interval} ${period}s`; }; const formatCurrency = (amount: number) => { return new Intl.NumberFormat(undefined, { style: "currency", currency: subscription?.currency || "USD", }).format(amount); }; const performAction = async (action: string, additionalData?: Record) => { setLoading(true); try { const apiUrl = window.swiftCommerceData?.apiUrl || '/wp-json/swift-commerce/v1'; const response = await fetch( `${apiUrl}/subscriptions/${subscription.id}/action`, { method: "POST", headers: { "Content-Type": "application/json", "X-WP-Nonce": window.swiftCommerceData?.restNonce || "", }, body: JSON.stringify({ action, note, ...additionalData, }), } ); const data = await response.json(); if (data.success) { toast.success(`Subscription ${action} successfully`); setNote(""); setConfirmAction(null); // Update local subscription state immediately if returned if (data.subscription) { setSubscription(data.subscription); } else { // Fallback: fetch the updated subscription await fetchSubscription(); } // Also notify parent to refresh list onUpdate(); } else { toast.error(data.message || `Failed to ${action} subscription`); } } catch (error) { console.error(`Failed to ${action} subscription:`, error); toast.error(`Failed to ${action} subscription`); } finally { setLoading(false); } }; const canActivate = ["pending", "on-hold", "cancelled"].includes(subscription.status); const canSuspend = subscription.status === "active"; const canCancel = ["active", "on-hold", "pending"].includes(subscription.status); return ( <>
Subscription #{subscription.id} {statusLabels[subscription.status] || subscription.status}
Created on {formatDateTime(subscription.created_at)}
{/* Quick Actions */}
{canActivate && ( )} {canSuspend && ( )} {canCancel && ( )} {subscription.status === "active" && ( )}
{/* Subscription Details Grid */}
{/* Left Column */}
{/* Product Info */}

Product Details

Product {subscription.product_name || `Product #${subscription.product_id}`}
{subscription.variation_id > 0 && (
Variation #{subscription.variation_id}
)}
Quantity {subscription.quantity}
{/* Customer Info */}

Customer

Name {subscription.customer_name || `Customer #${subscription.customer_id}`}
{subscription.customer_email && (
Email {subscription.customer_email}
)}
Customer ID #{subscription.customer_id}
{/* Payment Info */}

Payment

Method {subscription.payment_method_title || subscription.payment_method || "—"}
Renewal Type {subscription.requires_manual_renewal ? "Manual" : "Automatic"}
{/* Right Column */}
{/* Billing Info */}

Billing

Amount {formatCurrency(subscription.total)}
Billing Cycle {formatBillingPeriod(subscription.billing_interval, subscription.billing_period)}
{subscription.trial_end && (
Trial Ends {formatDate(subscription.trial_end)}
)}
{/* Schedule Info */}

Schedule

Start Date {formatDate(subscription.start_date)}
Next Payment {subscription.status === "active" ? formatDate(subscription.next_payment_date) : "—" }
{subscription.last_payment_date && (
Last Payment {formatDate(subscription.last_payment_date)}
)} {subscription.end_date && (
End Date {formatDate(subscription.end_date)}
)} {subscription.cancelled_date && (
Cancelled {formatDate(subscription.cancelled_date)}
)}
{/* Status Info */}

Status

Suspension Count {subscription.suspension_count}
Last Updated {formatDateTime(subscription.updated_at)}
{/* Change Status Section */}

Change Status