// ============================================================ // JuFlow — Atendimentos (Appointments list) // ============================================================ const { useState: useStAT, useMemo: useMemoAT } = React; const UAT = window.JFUtils; const Atendimentos = ({ appointments, onViewAppt, onNewAppt }) => { const [search, setSearch] = useStAT(''); const [statusF, setStatusF] = useStAT('all'); const [profF, setProfF] = useStAT('all'); const [period, setPeriod] = useStAT('30'); const filtered = useMemoAT(() => { const cutoff = UAT.addDays(window.JF.TODAY, -Number(period)); let list = appointments.filter(a => new Date(a.datetime) >= cutoff); if (statusF !== 'all') list = list.filter(a => a.status === statusF); if (profF !== 'all') list = list.filter(a => a.professionalId === Number(profF)); if (search) { const q = search.toLowerCase(); list = list.filter(a => { const c = UAT.getClient(a.clientId); const s = UAT.getService(a.serviceId); return c?.name.toLowerCase().includes(q) || s?.name.toLowerCase().includes(q); }); } return list.sort((a,b) => new Date(b.datetime) - new Date(a.datetime)); }, [appointments, statusF, profF, period, search]); const totalRevenue = filtered.filter(a=>a.status==='completed').reduce((s,a)=>s+a.price,0); const completedCnt = filtered.filter(a=>a.status==='completed').length; const cancelledCnt = filtered.filter(a=>a.status==='cancelled'||a.status==='no_show').length; return (
{/* Metrics */}
{/* Filters */}
{[ { val:statusF, set:setStatusF, opts:[['all','Todos'],['completed','Realizados'],['confirmed','Confirmados'],['pending','Pendentes'],['cancelled','Cancelados'],['no_show','Faltas']] }, ].map(({val,set,opts},i) => ( ))} {filtered.length} registros
{/* Table */}
{filtered.length === 0 ? ( ) : (
{['Data/Hora','Cliente','Serviço','Profissional','Duração','Valor','Pagamento','Status','Ações'].map(h => ( ))} {filtered.slice(0,50).map((appt, i) => { const client = UAT.getClient(appt.clientId); const service = UAT.getService(appt.serviceId); const prof = UAT.getProfessional(appt.professionalId); return ( onViewAppt(appt)} onMouseEnter={e=>e.currentTarget.style.background='#F9FAFB'} onMouseLeave={e=>e.currentTarget.style.background='#fff'} > ); })}
{h}
{UAT.formatDate(appt.datetime)}
{UAT.formatTime(appt.datetime)}
{client?.name}
{service?.name}
{prof?.name?.split(' ').slice(0,2).join(' ')}
{appt.duration}min {UAT.formatCurrency(appt.price)} {appt.paymentMethod || '—'} e.stopPropagation()}>
{filtered.length > 50 && (
Exibindo 50 de {filtered.length} registros. Use os filtros para refinar.
)}
)}
); }; Object.assign(window, { Atendimentos });