// Mobile app — full BinGest mobile experience with 4 routable screens.
// Used inside the InteractiveDemo iPhone frame.
const MOBILE_NAV = [
{ id: "inicio", l: "Início", Icon: IconDashboard },
{ id: "obras", l: "Obras", Icon: IconBuilding },
{ id: "ponto", l: "Ponto", Icon: IconClock },
{ id: "fin", l: "$", Icon: IconWallet },
];
function BingestMobile({ screen, onNav, withActivity = true }) {
return (
{/* Top bar — navy */}
Pimba Construções · maio 2026
{/* Curved content area */}
{screen === "inicio" && }
{screen === "obras" && }
{screen === "ponto" && }
{screen === "fin" && }
{/* FAB (only on certain screens) */}
{(screen === "ponto" || screen === "obras") && (
)}
{/* Bottom tab bar */}
{MOBILE_NAV.map(it => {
const active = screen === it.id;
return (
);
})}
);
}
// =================== Screens ===================
function MobileInicio({ withActivity }) {
return (
Olá, Eduardo
} />
} />
{/* DRE summary card */}
DRE — maio
{[
{ l: "Receita Bruta", v: "R$ 19.500,00", c: "#0B132A" },
{ l: "Custos diretos", v: "−R$ 8.210,00", c: "#DC2626" },
{ l: "Resultado op.", v: "R$ 11.290,00", c: "#16A34A", bold: true },
].map((r, i) => (
{r.l}
{r.v}
))}
{/* Quick actions */}
} label="Lançar presença" color="#2A5BFF" />
} label="Ver DRE" color="#16A34A" />
{withActivity &&
}
);
}
function QuickAction({ icon, label, color }) {
return (
{icon}
{label}
);
}
function MobileActivity() {
const events = [
{ t: "diária", title: "Diária registrada", sub: "Carlos Souza · R$ 180,00", color: "#16A34A", icon: },
{ t: "dre", title: "DRE atualizado", sub: "Margem 57,9%", color: "#2A5BFF", icon: },
{ t: "checkin", title: "Check-in no canteiro", sub: "Fernando Jose · 07h12", color: "#16A34A", icon: },
];
return (
<>
Atividade recente
{events.map((ev, i) => (
))}
>
);
}
// ----- OBRAS ------------------------------------------------------------
function MobileObras() {
return (
Obras
1 obra ativa
Ativas (1)
Concluídas
Pausadas
Condomínio das Acácias
Construtora FGR
Ativa
Entrega de Apto.
1 unidade
{/* mini progress bar */}
);
}
// ----- PONTO ------------------------------------------------------------
function MobilePonto() {
const entries = [
{ name: "Filipe Freitas", role: "Pedreiro", time: "07h12", date: "Hoje", d: 1, he: 0, status: "ok" },
{ name: "Fernando Jose", role: "Encarregado", time: "07h05", date: "Hoje", d: 1, he: 1, status: "ok" },
{ name: "Filipe Freitas", role: "Pedreiro", time: "07h08", date: "Ontem", d: 1, he: 0, status: "ok" },
];
return (
Folha de ponto
13 de maio · 2 presenças hoje
Lançar presença
Toque para registrar
Últimos lançamentos
{entries.map((e, i) => (
{e.name.split(" ").map(s => s[0]).join("").slice(0,2)}
{e.name}
{e.role} · {e.date} {e.time}
{e.d}d{e.he ? ` +${e.he}he` : ""}
sincronizado
))}
);
}
// ----- FIN --------------------------------------------------------------
function MobileFin() {
return (
Financeiro
maio · 2026
Atalhos
{[
"Lançar despesa",
"Emitir fatura",
"Pagar diaristas",
"Histórico de pagamentos",
].map((s, i) => (
{s}
))}
);
}
// Shared mobile KPI
function MobileKpi({ label, value, suffix = "", decimals = 0, tint = "blue", icon }) {
const [n, setN] = React.useState(0);
React.useEffect(() => {
let raf, t0;
const dur = 1100;
const step = (t) => {
if (!t0) t0 = t;
const p = Math.min(1, (t - t0) / dur);
const eased = 1 - Math.pow(1 - p, 3);
setN(value * eased);
if (p < 1) raf = requestAnimationFrame(step);
};
raf = requestAnimationFrame(step);
return () => cancelAnimationFrame(raf);
}, [value]);
const display = decimals
? n.toLocaleString("pt-BR", { minimumFractionDigits: decimals, maximumFractionDigits: decimals })
: Math.round(n).toLocaleString("pt-BR");
const colors = {
green: { bg: "#ECFDF5", border: "#BCEAD4", fg: "#15803D" },
blue: { bg: "#EEF3FF", border: "#D7E2FA", fg: "#1E4FD8" },
}[tint];
return (
{icon} {label}
{tint === "green" ? "R$ " : ""}{display}{suffix}
);
}
Object.assign(window, { BingestMobile, MOBILE_NAV });