import { useMemo, useState } from 'react' import { communicationRepository } from '../repositories/communicationRepository.js' const channels = { whatsapp: { label: 'WhatsApp', className: 'bg-emerald-500/20 text-emerald-400', icon: 'message' }, email: { label: 'E-mail', className: 'bg-blue-500/20 text-blue-400', icon: 'mail' }, sms: { label: 'SMS', className: 'bg-purple-500/20 text-purple-400', icon: 'phone' }, } const statusConfig = { entregue: { label: 'Entregue', className: 'text-emerald-400', icon: 'check' }, lida: { label: 'Lida', className: 'text-blue-400', icon: 'eye' }, falha: { label: 'Falha', className: 'text-red-400', icon: 'x-circle' }, pendente: { label: 'Pendente', className: 'text-amber-400', icon: 'clock' }, } const emptyMessage = { patient: '', channel: 'whatsapp', template: 'Lembrete 48h', content: '', } const emptyTemplate = { name: '', channel: 'whatsapp', category: 'Lembrete', content: '', } const cardClass = 'rounded-2xl border border-[#404040] bg-[#262626] shadow-sm' const inputClass = 'h-10 w-full rounded-sm border border-[#404040] bg-[#171717] px-3 text-sm text-[#e5e5e5] outline-none transition placeholder:text-[#a3a3a3] focus:border-[#3b82f6] focus:ring-2 focus:ring-[#3b82f6]/20' const textareaClass = 'min-h-28 w-full resize-y rounded-sm border border-[#404040] bg-[#171717] px-3 py-2 text-sm leading-6 text-[#e5e5e5] outline-none transition placeholder:text-[#a3a3a3] focus:border-[#3b82f6] focus:ring-2 focus:ring-[#3b82f6]/20' const labelClass = 'text-xs font-semibold uppercase tracking-[0.08em] text-[#a3a3a3]' export function MessagesPage() { const campaigns = communicationRepository.getCampaigns() const [messages, setMessages] = useState(() => communicationRepository.getInitialMessages()) const [templates, setTemplates] = useState(() => communicationRepository.getInitialTemplates()) const [activeTab, setActiveTab] = useState('historico') const [channelFilter, setChannelFilter] = useState('todos') const [search, setSearch] = useState('') const [composerOpen, setComposerOpen] = useState(false) const [templateEditorOpen, setTemplateEditorOpen] = useState(false) const [composer, setComposer] = useState(emptyMessage) const [templateDraft, setTemplateDraft] = useState(emptyTemplate) const filteredMessages = useMemo( () => messages.filter((message) => { const matchesChannel = channelFilter === 'todos' || message.channel === channelFilter const query = search.trim().toLowerCase() const matchesSearch = !query || [message.patient, message.template, channels[message.channel].label] .join(' ') .toLowerCase() .includes(query) return matchesChannel && matchesSearch }), [channelFilter, messages, search], ) const stats = useMemo( () => ({ total: messages.length, delivered: messages.filter((message) => message.status === 'entregue' || message.status === 'lida').length, read: messages.filter((message) => message.status === 'lida').length, failed: messages.filter((message) => message.status === 'falha').length, }), [messages], ) function openTemplate(template) { setComposer({ patient: '', channel: template.channel, template: template.name, content: template.content, }) setComposerOpen(true) } function submitMessage(event) { event.preventDefault() if (!composer.patient.trim()) { return } setMessages((current) => [ { id: `local-${Date.now()}`, patient: composer.patient.trim(), channel: composer.channel, template: composer.template.trim() || 'Mensagem avulsa', sentAt: 'Agora', status: 'pendente', response: '', }, ...current, ]) setComposer(emptyMessage) setComposerOpen(false) setActiveTab('historico') } function submitTemplate(event) { event.preventDefault() if (!templateDraft.name.trim() || !templateDraft.content.trim()) { return } setTemplates((current) => [ { id: `template-${Date.now()}`, name: templateDraft.name.trim(), channel: templateDraft.channel, content: templateDraft.content.trim(), category: templateDraft.category.trim() || 'Personalizado', }, ...current, ]) setTemplateDraft(emptyTemplate) setTemplateEditorOpen(false) } return (

Comunicação

WhatsApp, E-mail e SMS - histórico e campanhas

{[ ['historico', 'Histórico'], ['templates', 'Templates'], ['campanha', 'Campanhas'], ].map(([key, label]) => ( ))}
{activeTab === 'historico' ? (
{[ ['todos', 'Todos'], ['whatsapp', 'Whatsapp'], ['email', 'E-mail'], ['sms', 'Sms'], ].map(([key, label]) => ( ))}
{filteredMessages.map((message) => ( ))}
Paciente Canal Template Enviado em Status Resposta
{filteredMessages.length === 0 ? (
Nenhuma comunicação encontrada com os filtros atuais.
) : null}
) : null} {activeTab === 'templates' ? (
{templates.map((template) => ( ))}
) : null} {activeTab === 'campanha' ? (

Campanhas Inteligentes

Crie campanhas segmentadas por perfil comportamental. A IA sugere os melhores horários e canais para cada paciente.

{campaigns.map((campaign) => (

{campaign.title}

{campaign.desc}

{campaign.count}

))}
LGPD Conformidade

Todas as comunicações respeitam as preferências de Opt-in/Opt-out dos pacientes. Os pacientes podem cancelar o recebimento de mensagens a qualquer momento, conforme exigido pela LGPD.

) : null} {composerOpen ? ( { setComposerOpen(false) setComposer(emptyMessage) }} onSubmit={submitMessage} templates={templates} /> ) : null} {templateEditorOpen ? ( { setTemplateEditorOpen(false) setTemplateDraft(emptyTemplate) }} onSubmit={submitTemplate} /> ) : null}
) } function StatCard({ label, value, valueClassName = 'text-[#f5f5f5]' }) { return (

{label}

{value}

) } function MessageRow({ message }) { const channel = channels[message.channel] const status = statusConfig[message.status] return ( {message.patient} {channel.label} {message.template} {message.sentAt} {status.label} {message.response || '-'} ) } function TemplateCard({ onUse, template }) { const channel = channels[template.channel] return (
{channel.label} {template.category}

{template.name}

{template.content}

) } function MessageComposer({ draft, onChange, onClose, onSubmit, templates }) { function update(field, value) { onChange((current) => ({ ...current, [field]: value })) } function applyTemplate(templateName) { const template = templates.find((item) => item.name === templateName) if (!template) { update('template', templateName) return } onChange((current) => ({ ...current, channel: template.channel, template: template.name, content: template.content, })) } return (
update('patient', event.target.value)} placeholder="Nome do paciente" value={draft.patient} />