import { useState, useEffect } from "react"; import { useQuery, useMutation } from "@tanstack/react-query"; import { Button } from "@/components/ui/button"; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from "@/components/ui/dialog"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { Textarea } from "@/components/ui/textarea"; import { Label } from "@/components/ui/label"; import { MessageSquare, Send, Loader2, Save } from "lucide-react"; import { useToast } from "@/hooks/use-toast"; import { apiRequest, queryClient } from "@/lib/queryClient"; import type { Patient } from "@repo/db/types"; interface SmsTemplateDialogProps { open: boolean; onOpenChange: (open: boolean) => void; patient: Patient | null; } const DEFAULT_TEMPLATES: Record = { appointment_reminder: { name: "Appointment Reminder", body: (firstName: string) => `Hi ${firstName}, this is your dental office. Reminder: You have an appointment scheduled. Please confirm or call us if you need to reschedule.`, } as any, appointment_confirmation: { name: "Appointment Confirmation", body: (firstName: string) => `Hi ${firstName}, your appointment has been confirmed. We look forward to seeing you! If you have any questions, please call our office.`, } as any, follow_up: { name: "Follow-Up", body: (firstName: string) => `Hi ${firstName}, thank you for visiting our dental office. How are you feeling after your treatment? Please let us know if you have any concerns.`, } as any, payment_reminder: { name: "Payment Reminder", body: (firstName: string) => `Hi ${firstName}, this is a friendly reminder about your outstanding balance. Please contact our office to discuss payment options.`, } as any, general: { name: "General Message", body: (firstName: string) => `Hi ${firstName}, this is your dental office. `, } as any, custom: { name: "Custom Message", body: () => "", } as any, }; const TEMPLATE_KEYS = Object.keys(DEFAULT_TEMPLATES); function getDefaultBody(key: string, firstName: string): string { const t = DEFAULT_TEMPLATES[key]; if (!t) return ""; return typeof t.body === "function" ? (t.body as any)(firstName) : t.body; } export function SmsTemplateDialog({ open, onOpenChange, patient, }: SmsTemplateDialogProps) { const [selectedKey, setSelectedKey] = useState("appointment_reminder"); const [messageText, setMessageText] = useState(""); const { toast } = useToast(); const { data: savedTemplates = {} } = useQuery>({ queryKey: ["/api/twilio/templates"], enabled: open, }); // Resolve effective body for a given key (saved override or default) const resolveBody = (key: string) => { if (key === "custom") return ""; if (savedTemplates[key]) { // Replace placeholder first name with actual patient name return savedTemplates[key].replace(/^Hi \w+,/, `Hi ${patient?.firstName ?? ""},`); } return getDefaultBody(key, patient?.firstName ?? ""); }; // When dialog opens or template changes, populate message useEffect(() => { if (open) setMessageText(resolveBody(selectedKey)); }, [open, selectedKey, savedTemplates, patient?.firstName]); const sendMutation = useMutation({ mutationFn: async (message: string) => { return apiRequest("POST", "/api/twilio/send-sms", { to: patient!.phone, message, patientId: patient!.id, }); }, onSuccess: () => { toast({ title: "SMS Sent", description: `Message sent to ${patient?.firstName} ${patient?.lastName}` }); onOpenChange(false); setSelectedKey("appointment_reminder"); setMessageText(""); }, onError: (err: any) => { toast({ title: "Failed to Send SMS", description: err.message || "Please check your Twilio configuration.", variant: "destructive" }); }, }); const updateMutation = useMutation({ mutationFn: async ({ key, body }: { key: string; body: string }) => { return apiRequest("PUT", `/api/twilio/templates/${key}`, { body }); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["/api/twilio/templates"] }); toast({ title: "Template Updated", description: "This template will be used going forward." }); }, onError: (err: any) => { toast({ title: "Failed to Update Template", description: err.message, variant: "destructive" }); }, }); const handleTemplateChange = (key: string) => { setSelectedKey(key); setMessageText(resolveBody(key)); }; return ( Send SMS to {patient?.firstName} {patient?.lastName} Choose a template or write a custom message
{selectedKey !== "custom" && ( )}