import React, { useState, useMemo } from 'react'; import { Card } from '../components/Card'; import { Button } from '../components/Button'; import { Ruler, Droplets, CloudRain, PiggyBank, Paintbrush, ArrowRightLeft, Info, Calculator, Layers, HelpCircle } from 'lucide-react'; import { clsx } from 'clsx'; interface InputGroupProps { label: React.ReactNode; value: string; onChange: (value: string) => void; placeholder?: string; unit?: string; } const InputGroup: React.FC = ({ label, value, onChange, placeholder, unit }) => (
onChange(e.target.value)} /> {unit && {unit}}
); export const CalculatorDashboard: React.FC = () => { const [activeTab, setActiveTab] = useState('conversion'); // 1. Conversion const [microns, setMicrons] = useState(''); const [mils, setMils] = useState(''); const handleMicronChange = (val: string) => { setMicrons(val); if (val) setMils((parseFloat(val) / 25.4).toFixed(2)); else setMils(''); }; const handleMilsChange = (val: string) => { setMils(val); if (val) setMicrons((parseFloat(val) * 25.4).toFixed(1)); else setMicrons(''); }; // 2. Thickness const [epsParams, setEpsParams] = useState({ sv: '', dilution: '', wft: '' }); const epsResult = useMemo(() => { const { sv, dilution, wft } = epsParams; if (sv && wft) { const svVal = parseFloat(sv); const dilVal = parseFloat(dilution) || 0; const wftVal = parseFloat(wft); return (wftVal * svVal) / (100 + dilVal); } return null; }, [epsParams]); const [epuParams, setEpuParams] = useState({ sv: '', dilution: '', dft: '' }); const epuResult = useMemo(() => { const { sv, dilution, dft } = epuParams; if (sv && dft) { const svVal = parseFloat(sv); const dilVal = parseFloat(dilution) || 0; const dftVal = parseFloat(dft); return (dftVal * (100 + dilVal)) / svVal; } return null; }, [epuParams]); const [deadVolParams, setDeadVolParams] = useState({ roughness: '', sv: '', area: '' }); const deadVolResult = useMemo(() => { const { roughness, sv, area } = deadVolParams; if (roughness && sv && area) { const rVal = parseFloat(roughness); const svVal = parseFloat(sv); const aVal = parseFloat(area); const volDry = (aVal * rVal * 0.5) / 1000; const volWet = volDry / (svVal / 100); return { dry: volDry, wet: volWet }; } return null; }, [deadVolParams]); // 3. Dew Point const [envParams, setEnvParams] = useState({ temp: '', rh: '' }); const { dewPoint, dpStatus } = useMemo(() => { const { temp, rh } = envParams; if (temp && rh) { const T = parseFloat(temp); const RH = parseFloat(rh); const a = 17.27; const b = 237.7; const alpha = ((a * T) / (b + T)) + Math.log(RH / 100); const Td = (b * alpha) / (a - alpha); const delta = T - Td; let status = ''; if (delta < 3) status = 'Risco: Condensação iminente (Delta < 3°C)'; else status = 'Condição Segura (Delta > 3°C)'; return { dewPoint: Td, dpStatus: status }; } return { dewPoint: null, dpStatus: '' }; }, [envParams]); // 4. Consumption & Cost const [consAreaParams, setConsAreaParams] = useState({ area: '', eps: '', sv: '', loss: '' }); const consAreaResult = useMemo(() => { const { area, eps, sv, loss } = consAreaParams; if (area && eps && sv) { const a = parseFloat(area); const e = parseFloat(eps); const s = parseFloat(sv); const l = parseFloat(loss) || 0; const theo = (a * e) / (10 * s); return theo / (1 - (l / 100)); } return null; }, [consAreaParams]); const [consWeightParams, setConsWeightParams] = useState({ weight: '', relation: '' }); const consWeightResult = useMemo(() => { const { weight, relation } = consWeightParams; if (weight && relation) { const w = parseFloat(weight); const r = parseFloat(relation); const tons = w / 1000; return tons * r; } return null; }, [consWeightParams]); const [costParams, setCostParams] = useState({ coats: '1', area: '', eps: '', sv: '', dilution: '0', loss: '', price: '' }); const costResult = useMemo(() => { const { coats, area, eps, sv, dilution, loss, price } = costParams; if (area && eps && sv && price) { const c = parseFloat(coats) || 1; const a = parseFloat(area); const e = parseFloat(eps); const s = parseFloat(sv); const d = parseFloat(dilution) || 0; const l = parseFloat(loss) || 0; const p = parseFloat(price); const theoPaint = (a * e) / (10 * s); const realPaintPerCoat = theoPaint / (1 - (l / 100)); const totalPaint = realPaintPerCoat * c; const totalThinner = totalPaint * (d / 100); const totalCost = totalPaint * p; return { totalCost, totalPaint, totalThinner }; } return null; }, [costParams]); // 5. Nozzles const [nozzleCode, setNozzleCode] = useState(''); const [showNozzleHelp, setShowNozzleHelp] = useState(false); const [nozzleResult, setNozzleResult] = useState<{ fan: number, flow: number, desc: string } | null>(null); const calculateNozzle = () => { if (nozzleCode.length < 3) return; const widthDigit = parseInt(nozzleCode[0]); const holeDigits = parseInt(nozzleCode.slice(1)); const fan = widthDigit * 5; const flow = (holeDigits * holeDigits) * 0.0039; let desc = ''; if (holeDigits < 15) desc = "Acabamento fino, líquidos leves (Verniz, Stain)"; else if (holeDigits < 19) desc = "Uso geral, média viscosidade (Látex, Esmalte)"; else if (holeDigits < 25) desc = "Alta produtividade, viscosidade alta (Epóxi, PU)"; else desc = "Extrema cobertura, materiais pesados (Massa, Ignífugo)"; setNozzleResult({ fan, flow, desc }); }; return (
{/* Header */}

Ferramentas & Cálculos

Utilitários técnicos para pintura industrial

{/* Tabs */}
{/* Content for Tabs */}
{/* 1. CONVERSION */} {activeTab === 'conversion' && (

Conversor de Unidades

Microns (μm) ↔ Milesimos de Polegada (mils)

Microns (μm)} unit="μm" value={microns} onChange={handleMicronChange} placeholder="0" />

Fator de conversão: 1 mil = 25.4 μm.

)} {/* 2. THICKNESS */} {activeTab === 'thickness' && (
{/* EPS Calc */}

Cálculo de EPS (Seca)

setEpsParams({ ...epsParams, wft: v })} /> setEpsParams({ ...epsParams, sv: v })} /> setEpsParams({ ...epsParams, dilution: v })} />
Resultado Esperado
{epsResult ? epsResult.toFixed(1) : '--'} μm
{/* EPU Calc */}

Cálculo de EPU (Úmida)

setEpuParams({ ...epuParams, dft: v })} /> setEpuParams({ ...epuParams, sv: v })} /> setEpuParams({ ...epuParams, dilution: v })} />
Aplicar Camada de
{epuResult ? epuResult.toFixed(0) : '--'} μm
{/* Dead Volume */}

Volume Morto

setDeadVolParams({ ...deadVolParams, area: v })} /> setDeadVolParams({ ...deadVolParams, roughness: v })} /> setDeadVolParams({ ...deadVolParams, sv: v })} />
Volume Tinta (L)
{deadVolResult ? deadVolResult.wet.toFixed(2) : '--'} L
)} {/* 3. DEW POINT */} {activeTab === 'dewpoint' && (

Ponto de Orvalho

Cálculo da temperatura de condensação

setEnvParams({ ...envParams, temp: v })} /> setEnvParams({ ...envParams, rh: v })} />
Ponto de Orvalho Calculado
{dewPoint ? dewPoint.toFixed(1) : '--'}°C
{dpStatus || 'Aguardando dados...'}
)} {/* 4. CONSUMPTION & COST */} {activeTab === 'consumption' && (
{/* Area Consumption */}

Consumo por Área

setConsAreaParams({ ...consAreaParams, area: v })} /> setConsAreaParams({ ...consAreaParams, eps: v })} /> setConsAreaParams({ ...consAreaParams, sv: v })} /> setConsAreaParams({ ...consAreaParams, loss: v })} />
Consumo Estimado
{consAreaResult ? consAreaResult.toFixed(1) : '--'} Litros
{/* Weight Consumption */}

Consumo por Peso

setConsWeightParams({ ...consWeightParams, weight: v })} /> setConsWeightParams({ ...consWeightParams, relation: v })} />
Volume Necessário
{consWeightResult ? consWeightResult.toFixed(1) : '--'} Litros
{/* Cost Estimator */}

Estimativa de Custos

setCostParams({ ...costParams, coats: v })} /> setCostParams({ ...costParams, area: v })} /> setCostParams({ ...costParams, eps: v })} /> setCostParams({ ...costParams, price: v })} /> setCostParams({ ...costParams, sv: v })} /> setCostParams({ ...costParams, loss: v })} /> setCostParams({ ...costParams, dilution: v })} />
Volume Tinta
{costResult ? costResult.totalPaint.toFixed(1) : '--'} L
Volume Diluente
{costResult ? costResult.totalThinner.toFixed(1) : '--'} L
Custo Estimado
R$ {costResult ? costResult.totalCost.toFixed(2) : '--'}
)} {/* 5. Nozzles */} {activeTab === 'nozzles' && (

Seletor de Bicos Airless

Insira o código do bico (ex: 517) para ver detalhes

{showNozzleHelp && (

Entendendo o Código (ex: 517)

  • 1º Dígito
    Ângulo do Leque: Multiplique por 5 para saber a largura em cm (aprox a 30cm da superfície).
    Ex: 5xx = 50° (aprox. 25cm).
  • Últimos
    Orifício (Vazão): Diâmetro em milésimos de polegada. Quanto maior, mais tinta sai.
    Ex: x17 = 0.017". Indicado para látex/esmalte.
)} {nozzleResult && (
Abertura Leque {nozzleResult.fan} cm

(Aprox. a 30cm)

Vazão Aprox. {nozzleResult.flow.toFixed(2)} L/min

(@ 2000 psi)

{nozzleResult.desc}

)}

Valores teóricos de referência. Consulte sempre a ficha técnica do fabricante do equipamento.

)}
); };