"use client"; import { useRouter } from "next/navigation"; import { useState } from "react"; import { ColumnDef } from "@tanstack/react-table"; import { Button } from "@/components/ui/button"; import { Badge } from "@/components/ui/badge"; import { DataTable } from "@/components/data-table/data-table"; import { EmptyState } from "@/components/empty-state"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, DropdownMenuLabel, DropdownMenuSeparator, } from "@/components/ui/dropdown-menu"; import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, } from "@/components/ui/alert-dialog"; import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, } from "@/components/ui/dialog"; import { useCampaignList, useCancelCampaign, useCampaignReport, useUpdateCampaign, useDeleteCampaign } from "@/modules/campaigns/hooks"; import { Campaign } from "@/modules/campaigns/schemas"; import { useToast } from "@/hooks/use-toast"; import { MoreHorizontal, Plus, Send, Trash, Calendar, Filter, Eye, CheckCircle2, XCircle, Clock, AlertCircle, FileText, TrendingUp, Target, Users, RefreshCw } from "lucide-react"; import { formatDateTime } from "@/lib/utils"; export default function CampaignsPage() { const router = useRouter(); const { toast } = useToast(); const [statusFilter, setStatusFilter] = useState(undefined); const [isRefetching, setIsRefetching] = useState(false); const { data, isLoading, refetch } = useCampaignList(statusFilter); const cancelMutation = useCancelCampaign(); const updateMutation = useUpdateCampaign(); const deleteMutation = useDeleteCampaign(); const [cancelCampaign, setCancelCampaign] = useState<{ id: string; title: string } | null>(null); const [selectedCampaign, setSelectedCampaign] = useState(null); const [isDetailOpen, setIsDetailOpen] = useState(false); const [isEditOpen, setIsEditOpen] = useState(false); const [editFormData, setEditFormData] = useState<{ title?: string; content?: string; date?: string; status?: "pending" | "completed" | "cancelled" | "failed" }>({}); const [reportCampaignId, setReportCampaignId] = useState(null); const [isReportOpen, setIsReportOpen] = useState(false); const handleRefetch = async () => { setIsRefetching(true); try { await refetch(); } finally { setIsRefetching(false); } }; const handleCancel = async () => { if (!cancelCampaign) return; try { await cancelMutation.mutateAsync(cancelCampaign.id); toast({ title: "Campaign cancelled", description: "Campaign has been cancelled successfully", }); setCancelCampaign(null); } catch (error) { toast({ title: "Cancel failed", description: "Failed to cancel campaign", variant: "destructive", }); setCancelCampaign(null); } }; const handleEdit = async () => { if (!selectedCampaign || !editFormData.title) return; try { await updateMutation.mutateAsync({ id: selectedCampaign.UUID_ACP, data: editFormData, }); toast({ title: "Campaign updated", description: "Campaign has been updated successfully", }); setIsEditOpen(false); setEditFormData({}); refetch(); } catch (error) { toast({ title: "Update failed", description: "Failed to update campaign", variant: "destructive", }); } }; const handleDelete = async (campaignId: string) => { try { await deleteMutation.mutateAsync(campaignId); toast({ title: "Campaign deleted", description: "Campaign has been cancelled successfully", }); refetch(); } catch (error) { toast({ title: "Delete failed", description: "Failed to delete campaign", variant: "destructive", }); } }; const getStatusBadge = (status: string | undefined) => { if (!status) { return Unknown; } const variants: Record = { pending: "secondary", completed: "default", cancelled: "destructive", failed: "destructive", }; return ( {status.charAt(0).toUpperCase() + status.slice(1)} ); }; const columns: ColumnDef[] = [ { accessorKey: "Title_ACP", header: "Title", cell: ({ row }) => (
{row.original.Title_ACP || "-"}
), }, { accessorKey: "Content_ACP", header: "Content", cell: ({ row }) => (
{row.original.Content_ACP || "-"}
), }, { accessorKey: "Date_ACP", header: "Scheduled Date", cell: ({ row }) => row.original.Date_ACP ? formatDateTime(row.original.Date_ACP) : "-", }, { accessorKey: "Status_ACP", header: "Status", cell: ({ row }) => getStatusBadge(row.original.Status_ACP), }, { accessorKey: "TargetUsers_ACP", header: "Target", cell: ({ row }) => (
{row.original.TargetUsers_ACP}
), }, { accessorKey: "SentCount_ACP", header: "Sent", cell: ({ row }) => (
{row.original.SentCount_ACP}
), }, { accessorKey: "DeliveryRate_ACP", header: "Delivery Rate", cell: ({ row }) => { const rate = row.original.DeliveryRate_ACP; return (
= 90 ? 'text-green-600' : rate >= 70 ? 'text-yellow-600' : 'text-red-600'}`}> {rate}%
); }, }, { accessorKey: "CreatedAt_ACP", header: "Created", cell: ({ row }) => (
{row.original.CreatedAt_ACP ? formatDateTime(row.original.CreatedAt_ACP) : "-"}
), }, { id: "actions", cell: ({ row }) => ( { setSelectedCampaign(row.original); setIsDetailOpen(true); }} > View Details { setReportCampaignId(row.original.UUID_ACP); setIsReportOpen(true); }} > View Report {row.original.Status_ACP === "pending" && ( <> { setSelectedCampaign(row.original); setEditFormData({ title: row.original.Title_ACP, content: row.original.Content_ACP, date: row.original.Date_ACP, }); setIsEditOpen(true); }} > Edit setCancelCampaign({ id: row.original.UUID_ACP, title: row.original.Title_ACP })} className="text-destructive" > Cancel )} ), }, ]; if (isLoading) { return
Loading...
; } const campaigns = data?.data || []; const filterLabel = statusFilter ? statusFilter.charAt(0).toUpperCase() + statusFilter.slice(1) : "All Status"; return (

Campaign Management

Manage and schedule notification campaigns

Filter by Status setStatusFilter(undefined)}> All Status setStatusFilter("pending")}> Pending setStatusFilter("completed")}> Completed setStatusFilter("cancelled")}> Cancelled setStatusFilter("failed")}> Failed
{campaigns.length === 0 ? (
} /> ) : ( )} !open && setCancelCampaign(null)}> Cancel Campaign Are you sure you want to cancel the campaign "{cancelCampaign?.title}"? This action cannot be undone. Keep Campaign Cancel Campaign Edit Campaign Update campaign details {selectedCampaign && (
setEditFormData({ ...editFormData, title: e.target.value })} className="w-full px-3 py-2 border rounded-md border-input bg-background" placeholder="Campaign title" />