import { useState } from "react"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { Bell, MessageCircle, Mail, Send, XCircle, RefreshCw, Clock, CheckCircle2, AlertTriangle, } from "lucide-react"; import { api } from "../lib/api"; import { PageHeader, Spinner, EmptyState, Badge } from "../components/ui"; import { formatRelative, cn } from "../lib/format"; const CHANNEL = { whatsapp: { icon: MessageCircle, color: "#10b981", label: "WhatsApp" }, sms: { icon: MessageCircle, color: "#3b66ff", label: "SMS" }, email: { icon: Mail, color: "#a855f7", label: "Email" }, }; const KIND_LABEL: Record = { confirmation: "Confirmación", reminder: "Recordatorio", cancellation: "Cancelación", follow_up: "Seguimiento", review: "Reseña", }; const STATUS = [ { value: "all", label: "Todas" }, { value: "pending", label: "Pendientes" }, { value: "sent", label: "Enviadas" }, ]; export function NotificationsPage() { const qc = useQueryClient(); const [status, setStatus] = useState("pending"); const { data: stats } = useQuery({ queryKey: ["notifications", "stats"], queryFn: () => api.notifications.stats() }); const { data } = useQuery({ queryKey: ["notifications", status], queryFn: () => api.notifications.list(status) }); const regen = useMutation({ mutationFn: () => api.notifications.regenerate(), onSuccess: () => qc.invalidateQueries({ queryKey: ["notifications"] }), }); const act = (id: number, kind: "send" | "cancel") => api.notifications[kind](id).then(() => qc.invalidateQueries({ queryKey: ["notifications"] })); return (
regen.mutate()} className="btn btn-secondary" disabled={regen.isPending}> {regen.isPending ? : } Regenerar } />
{STATUS.map((s) => ( ))}
{!data ? (
) : !data.notifications.length ? ( ) : (
{data.notifications.map((n: any) => { const ch = CHANNEL[n.channel as keyof typeof CHANNEL] ?? CHANNEL.whatsapp; const ChIcon = ch.icon; return (
{n.client_name ?? "Cliente"} {KIND_LABEL[n.kind] ?? n.kind} {n.service_name && · {n.service_name}} {n.status === "pending" && pendiente} {n.status === "sent" && enviada} {n.status === "canceled" && cancelada}

{n.message}

Programa: {formatRelative(n.send_at)} · {ch.label}
{n.status === "pending" && (
)}
); })}
)}

Demo: el envío es simulado (no se conecta a WhatsApp/SMS reales). En producción se integraría con la API de WhatsApp Business / Twilio.

); } function Kpi({ icon: Icon, color, label, value }: any) { return (
{value}
{label}
); }