import React, { useState, useEffect } from "react"; import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from "./ui/card"; import { Badge } from "./ui/badge"; import { Button } from "./ui/button"; import { Input } from "./ui/input"; import { Textarea } from "./ui/textarea"; import { Label } from "./ui/label"; import { Dialog, DialogClose, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger, } from "./ui/dialog"; import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger, } from "./ui/alert-dialog"; import { Calendar, DollarSign, Mail, FileText, TrendingUp, Edit3, CheckCircle, XCircle, AlertCircle, ExternalLink, Eye, } from "lucide-react"; import { supabase, type Debt, type DebtVariable } from "../lib/supabase"; import { toast } from "sonner"; import { formatCurrency } from "../lib/utils"; import { replaceVariables, saveVariablesToDatabase, getVariablesForTemplate, updateVariablesForTextChange, } from "../lib/emailVariables"; import { ManualResponseDialog } from "./ManualResponseDialog"; import { ConversationTimeline } from "./ConversationTimeline"; interface DebtCardProps { debt: Debt; onUpdate?: () => void; // Callback to refresh data after updates debts: Debt[]; setDebts: (debts: Debt[]) => void; } const statusColors = { received: "bg-blue-100 text-blue-800 border-blue-200 dark:bg-blue-900/20 dark:text-blue-300 dark:border-blue-800", negotiating: "bg-yellow-100 text-yellow-800 border-yellow-200 dark:bg-yellow-900/20 dark:text-yellow-300 dark:border-yellow-800", approved: "bg-teal-100 text-teal-800 border-teal-200 dark:bg-teal-900/20 dark:text-teal-300 dark:border-teal-800", sent: "bg-purple-100 text-purple-800 border-purple-200 dark:bg-purple-900/20 dark:text-purple-300 dark:border-purple-800", awaiting_response: "bg-blue-100 text-blue-800 border-blue-200 dark:bg-blue-900/20 dark:text-blue-300 dark:border-blue-800", counter_negotiating: "bg-yellow-100 text-yellow-800 border-yellow-200 dark:bg-yellow-900/20 dark:text-yellow-300 dark:border-yellow-800", requires_manual_review: "bg-amber-100 text-amber-800 border-amber-200 dark:bg-amber-900/20 dark:text-amber-300 dark:border-amber-800", accepted: "bg-green-100 text-green-800 border-green-200 dark:bg-green-900/20 dark:text-green-300 dark:border-green-800", rejected: "bg-red-100 text-red-800 border-red-200 dark:bg-red-900/20 dark:text-red-300 dark:border-red-800", settled: "bg-green-100 text-green-800 border-green-200 dark:bg-green-900/20 dark:text-green-300 dark:border-green-800", failed: "bg-red-100 text-red-800 border-red-200 dark:bg-red-900/20 dark:text-red-300 dark:border-red-800", opted_out: "bg-gray-100 text-gray-800 border-gray-200 dark:bg-gray-800/20 dark:text-gray-300 dark:border-gray-700", }; const statusLabels = { received: "Received", negotiating: "Negotiating", approved: "Approved", sent: "Sent", awaiting_response: "Awaiting Response", counter_negotiating: "Counter Negotiating", requires_manual_review: "Manual Review Required", accepted: "Accepted", rejected: "Rejected", settled: "Settled", failed: "Failed", opted_out: "Opted Out", }; export function DebtCard({ debt, onUpdate, debts, setDebts }: DebtCardProps) { const [isApproving, setIsApproving] = useState(false); const [isRejecting, setIsRejecting] = useState(false); const [userProfile, setUserProfile] = useState(null); const [hasServerToken, setHasServerToken] = useState( undefined ); const isReadOnly = debt.status === "approved" || debt.status === "sent" || debt.status === "awaiting_response" || debt.status === "accepted" || debt.status === "rejected" || debt.status === "settled" || debt.status === "failed" || debt.status === "opted_out"; const formatDate = (dateString: string) => { return new Date(dateString).toLocaleDateString("en-US", { year: "numeric", month: "short", day: "numeric", hour: "2-digit", minute: "2-digit", }); }; const EditableResponseDialog = () => { const [isEditing, setIsEditing] = useState(false); const [isSaving, setIsSaving] = useState(false); const [subject, setSubject] = useState(""); const [body, setBody] = useState(""); const [variables, setVariables] = useState>({}); // Check if debt is in read-only state (approved or sent) // Initialize data when dialog opens useEffect(() => { const initializeData = async () => { if (debt.metadata?.aiEmail) { const aiEmail = debt.metadata.aiEmail; setSubject(aiEmail.subject || ""); setBody(aiEmail.body || ""); // Get variables for the template using the modular function const initialVariables = await getVariablesForTemplate( debt.id, aiEmail.subject || "", aiEmail.body || "" ); setVariables(initialVariables); } }; initializeData(); }, [debt.metadata?.aiEmail]); // Update variables when body changes const handleBodyChange = (newBody: string) => { setBody(newBody); // Update variables using the modular function const updatedVariables = updateVariablesForTextChange( variables, newBody, subject ); setVariables(updatedVariables); }; // Update variables when subject changes const handleSubjectChange = (newSubject: string) => { setSubject(newSubject); // Update variables using the modular function const updatedVariables = updateVariablesForTextChange( variables, newSubject, body ); setVariables(updatedVariables); }; // Update variables only (don't modify the text) const handleVariableChange = (variableName: string, value: string) => { const newVariables = { ...variables, [variableName]: value }; setVariables(newVariables); }; // Get display text for subject (for preview in input) const getSubjectDisplay = () => { return replaceVariables(subject, variables); }; // Get display text for body (for preview in textarea) const getBodyDisplay = () => { return replaceVariables(body, variables); }; // Save changes to database const handleSave = async () => { setIsSaving(true); try { // Update the metadata with the new subject and body const updatedMetadata = { ...debt.metadata, aiEmail: { ...debt.metadata?.aiEmail, subject, body, }, }; const { error } = await supabase .from("debts") .update({ metadata: updatedMetadata }) .eq("id", debt.id); if (error) { console.error("Error saving debt metadata:", error); toast.error("Error", { description: "Failed to save email changes. Please try again.", }); return; } // Save variables to database await saveVariablesToDatabase(debt.id, variables); toast.success("Changes saved", { description: "Your email and variables have been updated successfully.", }); // Call onUpdate callback to refresh the parent component if (onUpdate) { onUpdate(); } setIsEditing(false); } catch (error) { console.error("Error saving changes:", error); toast.error("Error", { description: "Failed to save changes. Please try again.", }); } finally { setIsSaving(false); } }; if (!debt.metadata?.aiEmail) return null; return ( {isReadOnly ? "View Negotiation Response" : "Edit Negotiation Response"} {isReadOnly ? "Review your FDCPA-compliant response" : "Customize your FDCPA-compliant response before sending"}
{/* Variables Form */} {Object.keys(variables).length > 0 && (

Complete the placeholders below to personalize your message

{Object.entries(variables).map(([variableName, value]) => (
!isReadOnly && handleVariableChange(variableName, e.target.value) } placeholder={`Enter ${variableName.toLowerCase()}`} className="w-full" readOnly={isReadOnly} />
))}
)} {/* Divider */}
{/* Subject Line */}
!isReadOnly && handleSubjectChange(e.target.value) } placeholder="Enter email subject (use {{ Variable Name }} for placeholders)" className="w-full" readOnly={isReadOnly} /> {/* Preview of subject with variables replaced */} {Object.keys(variables).length > 0 && (
Preview: {getSubjectDisplay()}
)}
{/* Body */}