"use client" import { useState } from "react" import { toast } from "sonner" import { formatDistanceToNow } from "date-fns" import { Plus, Play, Trash2, ToggleLeft, ToggleRight, Loader2, Bell, DollarSign, Wrench, FileText, Home, X, } from "lucide-react" const RULE_TYPES = [ { value: "overdue_rent", label: "Overdue Rent Reminder", icon: DollarSign, color: "text-red-400", desc: "Remind tenants when rent is overdue" }, { value: "maintenance_stale",label: "Stale Maintenance Alert", icon: Wrench, color: "text-orange-400", desc: "Follow up on open maintenance requests" }, { value: "lease_renewal", label: "Lease Renewal Notice", icon: FileText, color: "text-blue-400", desc: "Alert tenants about expiring leases" }, { value: "vacant_unit", label: "Vacant Unit Reminder", icon: Home, color: "text-amber-400", desc: "Internal alerts for vacant units" }, ] const typeColors: Record = { overdue_rent: "text-red-400 bg-red-500/10", maintenance_stale: "text-orange-400 bg-orange-500/10", lease_renewal: "text-blue-400 bg-blue-500/10", vacant_unit: "text-amber-400 bg-amber-500/10", } export function FollowUpsClient({ rules: initial, logs: initialLogs }: { rules: any[]; logs: any[] }) { const [rules, setRules] = useState(initial) const [logs, setLogs] = useState(initialLogs) const [running, setRunning] = useState(false) const [showForm, setShowForm] = useState(false) const [saving, setSaving] = useState(false) const [form, setForm] = useState({ type: "overdue_rent", name: "", trigger_days: 3, message_template: "" }) async function runFollowUps() { setRunning(true) try { const res = await fetch("/api/follow-ups/run", { method: "POST" }) const data = await res.json() if (!res.ok) { toast.error(data.error ?? "Failed to run"); return } if (data.sent === 0) { toast.info("No follow-ups triggered — all rules are up to date") } else { toast.success(`${data.sent} follow-up${data.sent !== 1 ? "s" : ""} triggered`) setLogs((prev) => [...data.results, ...prev].slice(0, 30)) } // refresh last_run_at const refreshed = await fetch("/api/follow-ups") const refreshedData = await refreshed.json() setRules(refreshedData.rules ?? rules) } catch { toast.error("Network error — please try again") } finally { setRunning(false) } } async function saveRule() { if (!form.name.trim()) return setSaving(true) try { const res = await fetch("/api/follow-ups", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(form), }) const data = await res.json() if (!res.ok) { toast.error(data.error ?? "Failed to save"); return } setRules((prev) => [...prev, data]) setShowForm(false) setForm({ type: "overdue_rent", name: "", trigger_days: 3, message_template: "" }) toast.success("Rule added") } catch { toast.error("Network error") } finally { setSaving(false) } } async function toggleRule(id: string, is_active: boolean) { const res = await fetch(`/api/follow-ups/${id}`, { method: "PATCH", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ is_active: !is_active }), }) const data = await res.json() if (!res.ok) { toast.error(data.error ?? "Failed to update"); return } setRules((prev) => prev.map((r) => r.id === id ? data : r)) } async function deleteRule(id: string) { await fetch(`/api/follow-ups/${id}`, { method: "DELETE" }) setRules((prev) => prev.filter((r) => r.id !== id)) toast.success("Rule deleted") } const cls = "w-full rounded-lg border border-white/10 bg-white/5 px-3 py-2.5 text-sm text-white placeholder-white/30 outline-none focus:border-indigo-500/50 focus:ring-1 focus:ring-indigo-500 transition" return (
{/* Header */}

Automated Follow-ups

Set rules and run them manually to trigger follow-up actions

{/* Add rule form */} {showForm && (

New Follow-up Rule

setForm((f) => ({ ...f, name: e.target.value }))} placeholder="e.g. 3-day overdue reminder" className={cls} />