'use client'; import { useState, useEffect, useCallback } from 'react'; import { api } from '@/lib/api'; import { PageHeader } from '@/components/ui/page-header'; import { Button } from '@/components/ui/button'; import { Badge } from '@/components/ui/badge'; import { Modal } from '@/components/ui/modal'; import { EmptyState } from '@/components/ui/empty-state'; import { CardSkeleton } from '@/components/ui/skeleton'; import { useToast } from '@/components/ui/toast'; interface Plan { id: string; name: string; description: string | null; speedDown: number; speedUp: number; price: string; billingCycle: number; isActive: boolean; _count: { subscriptions: number }; } export default function PlansPage() { const { toast } = useToast(); const [plans, setPlans] = useState([]); const [loading, setLoading] = useState(true); const [showCreate, setShowCreate] = useState(false); const [deleteTarget, setDeleteTarget] = useState(null); const [deleting, setDeleting] = useState(false); const loadPlans = useCallback(async () => { try { const res = await api.get<{ data: Plan[] }>('/plans'); setPlans(res.data.data); } catch { toast('Failed to load plans', 'error'); } finally { setLoading(false); } }, [toast]); useEffect(() => { loadPlans(); }, [loadPlans]); async function handleDelete() { if (!deleteTarget) return; setDeleting(true); try { await api.delete(`/plans/${deleteTarget.id}`); toast(`Plan "${deleteTarget.name}" deleted`, 'success'); setDeleteTarget(null); loadPlans(); } catch (err: any) { toast(err.response?.data?.error || 'Failed to delete', 'error'); } finally { setDeleting(false); } } return (
setShowCreate(!showCreate)} variant={showCreate ? 'secondary' : 'primary'}>{showCreate ? 'Cancel' : 'Add Plan'}} /> {showCreate && { setShowCreate(false); loadPlans(); toast('Plan created', 'success'); }} />} {loading ? (
{[1, 2, 3].map((i) => )}
) : plans.length === 0 ? (
} action={} />
) : (
{plans.map((plan) => (

{plan.name}

{plan.description &&

{plan.description}

}
Speed{plan.speedDown}/{plan.speedUp} Mbps
PricePHP {Number(plan.price).toLocaleString()}
Billing Cycle{plan.billingCycle} days
{plan._count.subscriptions} subscriber{plan._count.subscriptions !== 1 ? 's' : ''} {plan._count.subscriptions === 0 && }
))}
)} setDeleteTarget(null)} title="Delete Plan" description={`Are you sure you want to delete "${deleteTarget?.name}"? This action cannot be undone.`} variant="danger" confirmLabel="Delete Plan" onConfirm={handleDelete} loading={deleting} />
); } function CreatePlanForm({ onCreated }: { onCreated: () => void }) { const { toast } = useToast(); const [form, setForm] = useState({ name: '', description: '', speedDown: 25, speedUp: 25, price: 999, billingCycle: 30 }); const [submitting, setSubmitting] = useState(false); async function handleSubmit(e: React.FormEvent) { e.preventDefault(); setSubmitting(true); try { await api.post('/plans', { ...form, description: form.description || undefined }); onCreated(); } catch (err: any) { toast(err.response?.data?.error || 'Failed to create plan', 'error'); } finally { setSubmitting(false); } } return (
setForm({ ...form, name: e.target.value })} className="mt-1 block w-full rounded-lg border border-surface-200 dark:border-surface-700 px-3.5 py-2.5 text-sm text-surface-900 dark:text-surface-200 placeholder:text-surface-400 focus:border-primary-500 focus:outline-none focus:ring-2 focus:ring-primary-500/20 transition-all duration-200" placeholder="e.g. Basic 25" />
setForm({ ...form, description: e.target.value })} className="mt-1 block w-full rounded-lg border border-surface-200 dark:border-surface-700 px-3.5 py-2.5 text-sm text-surface-900 dark:text-surface-200 placeholder:text-surface-400 focus:border-primary-500 focus:outline-none focus:ring-2 focus:ring-primary-500/20 transition-all duration-200" />
setForm({ ...form, speedDown: parseInt(e.target.value) || 0 })} className="mt-1 block w-full rounded-lg border border-surface-200 dark:border-surface-700 px-3.5 py-2.5 text-sm focus:border-primary-500 focus:outline-none focus:ring-2 focus:ring-primary-500/20 transition-all duration-200" />
setForm({ ...form, speedUp: parseInt(e.target.value) || 0 })} className="mt-1 block w-full rounded-lg border border-surface-200 dark:border-surface-700 px-3.5 py-2.5 text-sm focus:border-primary-500 focus:outline-none focus:ring-2 focus:ring-primary-500/20 transition-all duration-200" />
setForm({ ...form, price: parseFloat(e.target.value) || 0 })} className="mt-1 block w-full rounded-lg border border-surface-200 dark:border-surface-700 px-3.5 py-2.5 text-sm focus:border-primary-500 focus:outline-none focus:ring-2 focus:ring-primary-500/20 transition-all duration-200" />
setForm({ ...form, billingCycle: parseInt(e.target.value) || 30 })} className="mt-1 block w-full rounded-lg border border-surface-200 dark:border-surface-700 px-3.5 py-2.5 text-sm focus:border-primary-500 focus:outline-none focus:ring-2 focus:ring-primary-500/20 transition-all duration-200" />
); }