// Caririaçu Guincho — Tab Lembrete const { useState: useStateTL, useEffect: useEffectTL, useMemo: useMemoTL } = React; const CORES_LEMBRETE = { ativo: { bg: '#ECFDF5', border: '#86EFAC', text: '#065F46', icon: '🟢' }, proximo: { bg: '#FEF3C7', border: '#FCD34D', text: '#92400E', icon: '🟡' }, vencido: { bg: '#FEE2E2', border: '#FCA5A5', text: '#991B1B', icon: '🔴' }, }; const TabLembrete = ({ guincho, onLembreteChange }) => { const [items, setItems] = useStateTL([]); const [edit, setEdit] = useStateTL(null); const [tick, setTick] = useStateTL(0); useEffectTL(() => { db.list('lembretes', { eq: { guincho_id: guincho.id, status: 'ativo' }, order: 'created_at', asc: false }) .then(setItems); }, [guincho.id, tick]); const itemsComStatus = useMemoTL(() => { const order = { vencido: 0, proximo: 1, ativo: 2 }; return items.map(x => ({ ...x, st: window.statusLembrete(x, guincho.km_atual) })).sort((a, b) => order[a.st.estado] - order[b.st.estado]); }, [items, guincho.km_atual]); const metricas = useMemoTL(() => { const ativos = itemsComStatus.filter(x => x.st.estado === 'ativo').length; const proximos = itemsComStatus.filter(x => x.st.estado === 'proximo').length; const vencidos = itemsComStatus.filter(x => x.st.estado === 'vencido').length; return { ativos, proximos, vencidos }; }, [itemsComStatus]); const novo = () => setEdit({ descricao: '', gatilho: 'km', proximo_km: (guincho.km_atual || 0) + 5000, proxima_data: null, antecedencia_km: 500, antecedencia_dias: 15, recorrente: false, intervalo_km: 10000, intervalo_dias: 90, }); const salvar = async () => { if (!edit.descricao?.trim()) { showToast('Descreva o lembrete', 'warning'); return; } if (edit.gatilho === 'km' && !edit.proximo_km) { showToast('Informe próximo km', 'warning'); return; } if (edit.gatilho === 'data' && !edit.proxima_data) { showToast('Informe próxima data', 'warning'); return; } const payload = { ...edit, guincho_id: guincho.id, proximo_km: edit.gatilho !== 'data' ? parseInt(edit.proximo_km) : null, proxima_data: edit.gatilho !== 'km' ? edit.proxima_data : null, antecedencia_km: parseInt(edit.antecedencia_km || 0), antecedencia_dias: parseInt(edit.antecedencia_dias || 0), intervalo_km: edit.recorrente && edit.gatilho !== 'data' ? parseInt(edit.intervalo_km || 0) || null : null, intervalo_dias: edit.recorrente && edit.gatilho !== 'km' ? parseInt(edit.intervalo_dias || 0) || null : null, }; const result = edit.id ? await db.update('lembretes', edit.id, payload) : await db.insert('lembretes', payload); if (!result) return; setEdit(null); setTick(t => t + 1); onLembreteChange?.(); showToast('Lembrete salvo', 'success'); }; const concluir = async (item) => { if (!confirm(`Marcar "${item.descricao}" como concluído?`)) return; const { error } = await sb.rpc('concluir_lembrete', { p_lembrete_id: item.id }); if (error) { showToast('Erro: ' + error.message, 'error'); return; } setTick(t => t + 1); onLembreteChange?.(); showToast(item.recorrente ? 'Concluído (próximo lembrete criado)' : 'Concluído', 'success'); }; const excluir = async () => { if (!confirm('Excluir este lembrete?')) return; const ok = await db.remove('lembretes', edit.id); if (!ok) return; setEdit(null); setTick(t => t + 1); onLembreteChange?.(); }; return ( <>