From 85c053ff3003e3b8e266c8267ebb70ce2f8ba1b2 Mon Sep 17 00:00:00 2001 From: admtracksteel Date: Fri, 3 Apr 2026 21:35:36 +0000 Subject: [PATCH] =?UTF-8?q?refactor:=20corrige=20duplica=C3=A7=C3=B5es=20e?= =?UTF-8?q?=20c=C3=B3digo=20morto?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Remove Toast Manager duplicado (core/toast-manager.js) - Unifica loadPreferences/savePreferences de app.js para state.js - Unifica adminConfig de app.js para state.js - Remove código morto (if false block) - Adiciona checkStorage para validar localStorage --- public/app.js | 221 ++----------------------------- public/js/core/state.js | 52 +++++++- public/js/core/toast-manager.js | 228 -------------------------------- 3 files changed, 59 insertions(+), 442 deletions(-) delete mode 100644 public/js/core/toast-manager.js diff --git a/public/app.js b/public/app.js index 52f9794..9ae96f4 100644 --- a/public/app.js +++ b/public/app.js @@ -1,116 +1,19 @@ // ======================================== -// SteelBase v6.5 - PROFESSIONAL EDITION +// SteelBase v7.5 - PROFESSIONAL EDITION // Plataforma Técnica Completa com Base de Materiais // ======================================== -// In-memory data storage WITH localStorage for preferences +// Import state from modules (userPreferences only - appState is still global for legacy) +import { userPreferences, loadPreferences, savePreferences, adminConfig } from './js/core/state.js'; + +// Make available globally for legacy code +window.userPreferences = userPreferences; +window.loadPreferences = loadPreferences; +window.savePreferences = savePreferences; +window.adminConfig = adminConfig; + +// In-memory data storage (legacy - still global for compatibility) const appState = { - history: [], - favorites: [], - budgetItems: [], - currentSection: 'cev', - currentTheme: 'dark', // 'dark' or 'light' - expertMode: false, - currentSidebarTab: 0 -}; - -// User preferences (saved to localStorage) -let userPreferences = { - theme: 'dark', - colorScheme: 'default', // default, blue, green, purple, orange - fontSize: 'medium', // small, medium, large, xlarge - fontFamily: 'default' // default, modern, classic, mono -}; - -// Load preferences from localStorage -function loadPreferences() { - try { - const saved = localStorage.getItem('acoCalcPreferences'); - if (saved) { - userPreferences = { ...userPreferences, ...JSON.parse(saved) }; - } - } catch (e) { - console.warn('Não foi possível carregar preferências:', e); - } -} - -// Save preferences to localStorage -function savePreferences() { - try { - localStorage.setItem('acoCalcPreferences', JSON.stringify(userPreferences)); - } catch (e) { - console.warn('Não foi possível salvar preferências:', e); - } -} - -// Admin configuration (in-memory) -const adminConfig = { - appName: 'SteelBase', - appSubtitle: 'Plataforma Técnica com Base de Dados de Materiais Brasileiros', - footerText: '© 2025 SteelBase v6.5 PROFESSIONAL EDITION - Plataforma Técnica com Base de Dados de Materiais Brasileiros', - themeDefault: 'escuro', - modeDefault: 'simples', - toolsVisibility: { - // Aços Estruturais - 'cev': true, - 'seletor': true, - 'equivalencias': false, - 'comparativo': false, - 'assistente-inteligente': true, - // Consumíveis de Soldagem - 'eletrodos': false, - 'arames': false, - 'fluxos': false, - 'gases': false, - // Fixadores - 'parafusos-catalogo': false, - 'porcas': false, - 'arruelas': false, - 'chumbadores': false, - // Tintas e Revestimentos - 'tintas-catalogo': false, - 'sistemas-pintura': false, - 'abrasivos': false, - 'granalha': false, - // Elementos Complementares - 'telhas': false, - 'paineis': false, - 'steel-deck': false, - 'perfis-formados': false, - // Catálogo de Perfis - 'cantoneiras': true, - 'barras-redondas': true, - 'tubos-circulares': true, - 'perfis-i': true, - 'perfis-w': true, - 'tubos-rhs': true, - 'chapas': true, - 'perfis-hp': true, - 'barras-roscadas': true, - 'barras-chatas': true, - // Conexões - 'parafusos': true, - 'layout': true, - 'parafuso-vs-solda': false, - // Soldagem - 'preaquecimento': true, - 'dureza': true, - 'charpy': true, - 'certificado': false, - 'ultrassom': false, - // Pintura - 'area-pintura': true, - 'consumo-tinta': true, - 'galvanizacao': false, - 'custo-pintura': true, - 'secagem': false, - 'inspecao-pintura': false, - // Orçamento - 'orcamento': true, - 'peso-rigging': false, - 'referencia': false - } -}; // ======================================== // CSV MAPPING AND LOADING FUNCTIONS v6.6 @@ -431,108 +334,6 @@ function showSection(sectionId) { }, 500); } - // CÓDIGO ANTIGO REMOVIDO - mantido apenas para referência - if (false && sectionId === 'cantoneiras') { - console.log('🔧 Seção cantoneiras detectada - iniciando carregamento forçado'); - - // Tentar múltiplas vezes até conseguir - let tentativas = 0; - const maxTentativas = 10; - - const tentarCarregar = async () => { - tentativas++; - console.log(`🔄 Tentativa ${tentativas}/${maxTentativas} de carregar cantoneiras`); - - const tbody = document.getElementById('cantoneiras-tbody'); - - if (tbody) { - console.log('✅ Elemento tbody encontrado! Carregando dados...'); - - try { - // Carregar CSV diretamente - const response = await fetch('BD/perfis/cantoneiras_brasil_completo.csv'); - if (!response.ok) { - throw new Error(`HTTP ${response.status}`); - } - - const csvText = await response.text(); - const linhas = csvText.trim().split('\n'); - - console.log(`📊 CSV carregado: ${linhas.length} linhas`); - - const dados = []; - for (let i = 1; i < linhas.length; i++) { - const linha = linhas[i].trim(); - if (!linha) continue; - - const colunas = linha.split(','); - if (colunas.length >= 9) { - dados.push({ - id: colunas[0].trim(), - nome: colunas[1].trim(), - lado_mm: parseFloat(colunas[2]), - espessura_mm: parseFloat(colunas[3]), - peso_kg_m: parseFloat(colunas[4]), - area_cm2: parseFloat(colunas[5]), - momento_inercia_cm4: parseFloat(colunas[6]), - raio_giracao_cm: parseFloat(colunas[7]), - tipo: colunas[8].trim() - }); - } - } - - console.log(`✅ Processados: ${dados.length} cantoneiras`); - - // Exibir na tabela - tbody.innerHTML = dados.map(item => ` - - ${item.nome} - ${item.lado_mm} - ${item.espessura_mm} - ${item.peso_kg_m.toFixed(2)} - ${item.area_cm2.toFixed(2)} - ${item.momento_inercia_cm4.toFixed(2)} - ${item.raio_giracao_cm.toFixed(2)} - ${item.tipo} - - - `).join(''); - - console.log('🎉 Tabela preenchida com sucesso!'); - - // Atualizar contador - const totalEl = document.getElementById('cant-total'); - if (totalEl) { - totalEl.textContent = dados.length; - } - - } catch (error) { - console.error('❌ Erro ao carregar CSV:', error); - tbody.innerHTML = ` - - - ❌ Erro ao carregar dados: ${error.message} -

- - - - `; - } - } else { - console.warn(`⚠️ Elemento tbody não encontrado (tentativa ${tentativas})`); - - if (tentativas < maxTentativas) { - setTimeout(tentarCarregar, 300); - } else { - console.error('❌ Falha após todas as tentativas'); - } - } - }; - - // Iniciar tentativas após um pequeno delay - setTimeout(tentarCarregar, 200); - } - // Add help button after content loads setTimeout(() => { if (sectionId === 'preaquecimento') { diff --git a/public/js/core/state.js b/public/js/core/state.js index d6aba2d..5abb320 100644 --- a/public/js/core/state.js +++ b/public/js/core/state.js @@ -15,13 +15,34 @@ export const appState = { }; // User preferences (persisted to localStorage) -export const userPreferences = { +export let userPreferences = { theme: 'dark', - colorScheme: 'default', // default, blue, green, purple, orange - fontSize: 'medium', // small, medium, large, xlarge - fontFamily: 'default' // default, modern, classic, mono + colorScheme: 'default', + fontSize: 'medium', + fontFamily: 'default' }; +// Load preferences from localStorage +export function loadPreferences() { + try { + const saved = localStorage.getItem('acoCalcPreferences'); + if (saved) { + userPreferences = { ...userPreferences, ...JSON.parse(saved) }; + } + } catch (e) { + console.warn('Não foi possível carregar preferências:', e); + } +} + +// Save preferences to localStorage +export function savePreferences() { + try { + localStorage.setItem('acoCalcPreferences', JSON.stringify(userPreferences)); + } catch (e) { + console.warn('Não foi possível salvar preferências:', e); + } +} + // Admin configuration export const adminConfig = { appName: 'SteelBase', @@ -89,3 +110,26 @@ export function updatePreference(key, value) { export function getPreference(key) { return userPreferences[key]; } + +/** + * Check if localStorage is available and has space + * @returns {object} Storage status + */ +export function checkStorage() { + try { + const testKey = '__storage_test__'; + localStorage.setItem(testKey, testKey); + localStorage.removeItem(testKey); + + let totalSize = 0; + for (let key in localStorage) { + if (localStorage.hasOwnProperty(key)) { + totalSize += localStorage[key].length * 2; + } + } + + return { available: true, usedBytes: totalSize }; + } catch (error) { + return { available: false, error: error.message }; + } +} diff --git a/public/js/core/toast-manager.js b/public/js/core/toast-manager.js deleted file mode 100644 index 517ab79..0000000 --- a/public/js/core/toast-manager.js +++ /dev/null @@ -1,228 +0,0 @@ -/** - * ToastManager - Sistema de Notificações Visuais - * Gerencia notificações toast não-intrusivas para o usuário - */ -class ToastManager { - constructor() { - this.container = null; - this.toasts = new Map(); - this.config = { - position: 'top-right', - duration: 5000, - maxToasts: 5, - animationDuration: 300 - }; - this.init(); - } - - init() { - this.createContainer(); - console.log('🍞 ToastManager inicializado'); - } - - createContainer() { - // Remover container existente se houver - const existingContainer = document.querySelector('.toast-container'); - if (existingContainer) { - existingContainer.remove(); - } - - // Criar novo container - this.container = document.createElement('div'); - this.container.className = `toast-container toast-${this.config.position}`; - this.container.style.cssText = ` - position: fixed; - z-index: 10000; - pointer-events: none; - `; - - // Definir posição baseada na configuração - this.setContainerPosition(); - - document.body.appendChild(this.container); - } - - setContainerPosition() { - if (!this.container) return; - - const positions = { - 'top-right': { top: '20px', right: '20px', bottom: 'auto', left: 'auto' }, - 'top-left': { top: '20px', left: '20px', bottom: 'auto', right: 'auto' }, - 'top-center': { top: '20px', left: '50%', transform: 'translateX(-50%)', bottom: 'auto', right: 'auto' }, - 'bottom-right': { bottom: '20px', right: '20px', top: 'auto', left: 'auto' }, - 'bottom-left': { bottom: '20px', left: '20px', top: 'auto', right: 'auto' }, - 'bottom-center': { bottom: '20px', left: '50%', transform: 'translateX(-50%)', top: 'auto', right: 'auto' } - }; - - const pos = positions[this.config.position] || positions['top-right']; - Object.assign(this.container.style, pos); - } - - show(message, type = 'info', duration = null, options = {}) { - const toast = this.createToast(message, type, options); - const toastId = toast.dataset.toastId; - - // Adicionar ao container - this.container.appendChild(toast); - - // Armazenar referência - this.toasts.set(toastId, toast); - - // Limitar número de toasts - this.limitToasts(); - - // Animar entrada - requestAnimationFrame(() => { - toast.classList.add('show'); - }); - - // Configurar tempo de remoção - const autoHideDuration = duration !== null ? duration : this.config.duration; - if (autoHideDuration > 0) { - setTimeout(() => { - this.hide(toastId); - }, autoHideDuration); - } - - return toastId; - } - - createToast(message, type, options) { - const toast = document.createElement('div'); - const toastId = 'toast_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9); - - toast.dataset.toastId = toastId; - toast.className = `toast toast-${type}`; - toast.style.cssText = ` - background: var(--toast-bg, #333); - color: var(--toast-color, #fff); - padding: 16px 20px; - margin-bottom: 10px; - border-radius: 8px; - box-shadow: 0 4px 12px rgba(0,0,0,0.15); - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; - font-size: 14px; - line-height: 1.4; - max-width: 400px; - min-width: 300px; - opacity: 0; - transform: translateX(100%); - transition: all ${this.config.animationDuration}ms ease; - pointer-events: auto; - position: relative; - overflow: hidden; - `; - - // Definir cores baseadas no tipo - const colors = { - success: { bg: '#22c55e', color: '#fff' }, - error: { bg: '#ef4444', color: '#fff' }, - warning: { bg: '#f59e0b', color: '#fff' }, - info: { bg: '#3b82f6', color: '#fff' } - }; - - const colorConfig = colors[type] || colors.info; - toast.style.setProperty('--toast-bg', colorConfig.bg); - toast.style.setProperty('--toast-color', colorConfig.color); - - // Adicionar ícone baseado no tipo - const icons = { - success: '✅', - error: '❌', - warning: '⚠️', - info: 'ℹ️' - }; - - const icon = options.icon || icons[type] || icons.info; - - toast.innerHTML = ` -
- ${icon} -
${message}
- -
- `; - - return toast; - } - - limitToasts() { - if (this.toasts.size <= this.config.maxToasts) return; - - const toastsArray = Array.from(this.toasts.entries()); - const toRemove = toastsArray.slice(0, toastsArray.length - this.config.maxToasts); - - toRemove.forEach(([toastId]) => { - this.hide(toastId); - }); - } - - hide(toastId) { - const toast = this.toasts.get(toastId); - if (!toast) return; - - toast.classList.remove('show'); - - setTimeout(() => { - if (toast.parentNode) { - toast.parentNode.removeChild(toast); - } - this.toasts.delete(toastId); - }, this.config.animationDuration); - } - - hideAll() { - this.toasts.forEach((toast, toastId) => { - this.hide(toastId); - }); - } - - // Métodos de conveniência - success(message, duration, options) { - return this.show(message, 'success', duration, options); - } - - error(message, duration, options) { - return this.show(message, 'error', duration, options); - } - - warning(message, duration, options) { - return this.show(message, 'warning', duration, options); - } - - info(message, duration, options) { - return this.show(message, 'info', duration, options); - } - - // Configurar posição - setPosition(position) { - if (['top-right', 'top-left', 'top-center', 'bottom-right', 'bottom-left', 'bottom-center'].includes(position)) { - this.config.position = position; - this.createContainer(); - } - } - - // Obter estatísticas - getStats() { - return { - activeToasts: this.toasts.size, - maxToasts: this.config.maxToasts, - position: this.config.position, - duration: this.config.duration - }; - } -} - -// Tornar disponível globalmente -window.ToastManager = ToastManager; -window.toastManager = new ToastManager(); \ No newline at end of file