// ============================================================
// 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 }) => (
{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
Destinatários
{selectedCount} de {bulk.recipients.length} selecionados
{bulk.recipients.length === 0 ? (
Nenhum destinatário disponível.
) : bulk.recipients.map(c => {
const checked = !!bulk.selected[c.id];
const accent = bulk.type === 'birthday' ? '#7C3AED' : '#EF4444';
return (
);
})}
);
};
Object.assign(window, { Marketing });