// ============================================================ // JuFlow — Marketing // ============================================================ const { useState: useStMK } = React; const UMK = window.JFUtils; const MK_TEMPLATES = { birthday: 'Oi {{nome}}! 🎉 Hoje queremos celebrar você! Toda a equipe do Studio JuFlow deseja um feliz aniversário. Como presente, preparamos um cupom exclusivo: BDAY15 (15% off em qualquer serviço durante este mês). Te esperamos!', inactive: 'Olá {{nome}}! Sentimos sua falta aqui no Studio JuFlow. Que tal agendar uma sessão? Como incentivo para você voltar, oferecemos 20% de desconto no seu próximo atendimento. Use o código VOLTEI20 ao agendar.', }; const Marketing = ({ appointments, addToast }) => { const [tab, setTab] = useStMK('overview'); const [bulk, setBulk] = useStMK({ open:false, type:'birthday', message:'', recipients:[], selected:{} }); const birthdays = window.JF.CLIENTS.filter(c => UMK.isBirthdayThisMonth(c.birthdate)); const inactive = window.JF.CLIENTS.filter(c => c.lastVisit && UMK.daysBetween(c.lastVisit, window.JF.TODAY) > 60); const reviews = window.JF.REVIEWS; const avgRating = reviews.reduce((s,r) => s+r.rating, 0) / reviews.length; const openBulk = (type, recipients, focusedId = null) => { const selected = {}; recipients.forEach(c => { selected[c.id] = focusedId ? c.id === focusedId : true; }); setBulk({ open:true, type, message: MK_TEMPLATES[type], recipients, selected }); }; const closeBulk = () => setBulk(b => ({ ...b, open:false })); const toggleRecipient = (id) => setBulk(b => ({ ...b, selected: { ...b.selected, [id]: !b.selected[id] } })); const toggleAll = (val) => setBulk(b => { const sel = {}; b.recipients.forEach(c => { sel[c.id] = val; }); return { ...b, selected: sel }; }); const sendBulk = () => { const count = bulk.recipients.filter(c => bulk.selected[c.id]).length; if (count === 0) { addToast('Selecione ao menos um destinatário.', 'warning'); return; } const verb = bulk.type === 'birthday' ? 'aniversário' : 'reativação'; addToast(`${count} mensagem(ns) de ${verb} enviada(s) via WhatsApp! 📲`, 'success'); closeBulk(); }; const selectedCount = bulk.recipients.filter(c => bulk.selected[c.id]).length; const allSelected = bulk.recipients.length > 0 && selectedCount === bulk.recipients.length; const ActionCard = ({ title, subtitle, icon, color, count, children, actionLabel, onAction }) => (
{title}
{subtitle}
{count !== undefined && (
{count}
)}
{children} {actionLabel && ( )}
); const StarRating = ({ rating }) => (
{[1,2,3,4,5].map(i => ( ))}
); return (
{/* Metrics */}
{/* Birthdays */} openBulk('birthday', birthdays)} >
{birthdays.length === 0 ? (

Nenhum aniversariante este mês

) : birthdays.map(c => (
{c.name}
{UMK.formatDate(c.birthdate,'dd/MM')} · {UMK.age(c.birthdate)} anos
))}
{/* Inactive clients */} openBulk('inactive', inactive)} >
{inactive.length === 0 ? (

Nenhum cliente inativo 🎉

) : inactive.map(c => { const days = UMK.daysBetween(c.lastVisit, window.JF.TODAY); return (
{c.name}
Ausente há {days} dias
); })}
{/* Reviews */}
{avgRating.toFixed(1)}
{[1,2,3,4,5].map(i => )}
{reviews.length} avaliações
{reviews.map(rev => { const client = UMK.getClient(rev.clientId); const prof = UMK.getProfessional(rev.professionalId); return (
{client?.name}
{prof?.name} · {UMK.formatDate(rev.date)}
{[1,2,3,4,5].map(i => )}

"{rev.comment}"

); })}
{/* Smart suggestions */}
{[ { client: window.JF.CLIENTS.find(c=>c.status==='inactive'), type:'reactivate', msg:'não retorna há 97 dias. Envie uma oferta especial!', urgency:'high' }, { client: window.JF.CLIENTS.find(c=>c.tags.includes('Inadimplente')), type:'payment', msg:'possui um débito em aberto. Entre em contato.', urgency:'medium' }, { client: birthdays[0], type:'birthday', msg:`faz aniversário em ${birthdays[0] ? UMK.formatDate(birthdays[0].birthdate,'dd/MM') : ''}. Envie parabéns!`, urgency:'low' }, ].filter(s => s.client).map((s, i) => { const urgencyColor = { high:'#EF4444', medium:'#D97706', low:'#059669' }[s.urgency]; return (
{s.client?.name} {s.msg}
); })}
{/* Bulk message modal */} } >
Mensagem (WhatsApp) · use {'{{nome}}'} para personalizar