/* global React */
const { useState, useEffect, useRef } = React;
// =====================================================================
// MODAL DE LOGIN (fullscreen, bloqueante)
// =====================================================================
function LoginModal({ onSuccess }) {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [err, setErr] = useState('');
const [busy, setBusy] = useState(false);
const emailRef = useRef(null);
useEffect(() => {
setTimeout(() => emailRef.current?.focus(), 100);
}, []);
const submit = async () => {
if (!email || !password) {
setErr('Informe email e senha.');
return;
}
setErr('');
setBusy(true);
try {
await window.sb.signIn(email, password);
setPassword('');
onSuccess();
} catch (e) {
setErr(e.message || 'Credenciais inválidas.');
} finally {
setBusy(false);
}
};
const onKey = (e) => {
if (e.key === 'Enter') submit();
};
return (
af
Calculadora Fiscal
Acesso restrito · Lucro Real
);
}
window.LoginModal = LoginModal;
// =====================================================================
// LOADING OVERLAY GLOBAL
// =====================================================================
function LoadingOverlay({ text }) {
return (
);
}
window.LoadingOverlay = LoadingOverlay;
// =====================================================================
// MODAL DE CONFIRMAÇÃO GENÉRICO (substitui confirm() nativo)
// =====================================================================
function ConfirmModal({ open, title, message, okLabel = 'Confirmar', cancelLabel = 'Cancelar', danger = false, onOk, onCancel }) {
useEffect(() => {
if (!open) return;
const onKey = (e) => {
if (e.key === 'Escape') onCancel?.();
if (e.key === 'Enter') onOk?.();
};
document.addEventListener('keydown', onKey);
return () => document.removeEventListener('keydown', onKey);
}, [open, onOk, onCancel]);
if (!open) return null;
return (
{message}
);
}
window.ConfirmModal = ConfirmModal;
// =====================================================================
// CLOUD HELPERS: salvar, listar, visualizar, deletar
// =====================================================================
window.cloud = {
// --- Salvar simulação ---
async saveSim(state, calc) {
const v = state.venda;
const c = calc;
const prod = state.produtos.find(p => p.id === v.produtoId);
const payload = {
produto_nome: prod?.nome || '(sem produto)',
produto_snapshot_id: null,
qtd: v.qtd || 0,
valor_total: v.valor || 0,
uf_destino: v.uf,
contribuinte: v.contrib === 'SIM',
marketplace: v.mkt === 'SIM',
comissao_pct: v.mkt === 'SIM' ? v.comissao : null,
com_ipi: v.ipi === 'SIM',
cmv_unit: +(c.cmvUn || 0).toFixed(4),
lucro_liq: +(c.dre.lucroLiq || 0).toFixed(2),
margem_liq: +(c.kpi.margemLiq || 0).toFixed(4),
carga_trib: +(c.kpi.cargaTrib || 0).toFixed(4),
tributos_total: +(c.kpi.tributos || 0).toFixed(2),
dre_snapshot: {
valorNota: c.dre.valorNota, ipi: c.dre.ipi, receitaBruta: c.dre.receitaBruta,
icmsDeb: c.dre.icmsDeb, pis: c.dre.pis, cofins: c.dre.cofins, difal: c.dre.difal,
receitaLiq: c.dre.receitaLiq, cmvTotal: c.dre.cmvTotal, lucroBruto: c.dre.lucroBruto,
comissao: c.dre.comissao, custosFixos: c.dre.custosFixos,
lucroAntesIR: c.dre.lucroAntesIR, irpj: c.dre.irpj, csll: c.dre.csll, lucroLiq: c.dre.lucroLiq,
isNaoContrib: c.isNaoContrib, baseICMS: c.baseICMS, basePisCofins: c.basePisCofins,
aliqICMS: c.aliqICMS, aliqInterna: c.aliqInterna,
},
params_snapshot: { ...state.params },
versao_payload: 1,
notas: null,
};
const data = await window.sb.insert('simulations', payload);
return data && data[0];
},
// --- Salvar versão de produto ---
async saveProduto(produto, params) {
const c = window.calcProduto(produto, params);
const ncmDoXml = (produto.nf.xmlInfo && Array.isArray(produto.nf.xmlInfo.ncms) && produto.nf.xmlInfo.ncms.length > 0)
? produto.nf.xmlInfo.ncms[0]
: null;
const payload = {
nome: produto.nome,
ncm: ncmDoXml,
mp_kg_dia: produto.prod.mpKg || 0,
qtd_dia: produto.prod.qtd || 0,
nf_valor: produto.nf.valor || 0,
nf_kg: produto.nf.kg || 0,
nf_icms: produto.nf.icms || 0,
nf_ipi: produto.nf.ipi || 0,
nf_simples: produto.nf.simples === 'SIM',
nf_frete: produto.nf.frete || 0,
nf_seguro: produto.nf.seguro || 0,
nf_outras: produto.nf.outras || 0,
nf_desconto: produto.nf.desconto || 0,
nf_xml_info: produto.nf.xmlInfo || null,
insumos: (produto.insumos || []).map(i => ({
nome: i.nome, valor: i.valor || 0,
credPC: !!i.credPC, credICMS: !!i.credICMS,
aliqICMS: i.aliqICMS || 0,
nota: i.nota || '', custom: !!i.custom,
})),
cmv_calc: +(c.cmv.cmvUn || 0).toFixed(4),
versao_payload: 1,
notas: null,
};
const data = await window.sb.insert('product_versions', payload);
return data && data[0];
},
// --- Listar simulações ---
async listSims() {
return window.sb.select('simulations',
'select=id,seq,produto_nome,qtd,valor_total,uf_destino,marketplace,cmv_unit,lucro_liq,margem_liq,carga_trib,created_at&order=seq.desc&limit=200');
},
async getSim(simId) {
const arr = await window.sb.select('simulations', `id=eq.${simId}&select=*`);
if (!arr || !arr.length) throw new Error('Simulação não encontrada');
return arr[0];
},
async deleteSim(simId) {
return window.sb.del('simulations', `id=eq.${simId}`);
},
// --- Listar produtos ---
async listProds() {
return window.sb.select('product_versions',
'select=id,seq,nome,ncm,mp_kg_dia,qtd_dia,nf_valor,nf_kg,cmv_calc,created_at&order=seq.desc&limit=200');
},
async getProd(prodId) {
const arr = await window.sb.select('product_versions', `id=eq.${prodId}&select=*`);
if (!arr || !arr.length) throw new Error('Produto não encontrado');
return arr[0];
},
async deleteProd(prodId) {
return window.sb.del('product_versions', `id=eq.${prodId}`);
},
};