{
  "name": "www-geo-itajai",
  "nodes": [
    {
      "parameters": {
        "html": "<!DOCTYPE html>\n<html lang=\"pt-br\">\n\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>Extrator de Dados de Im\u00f3veis - n8n</title>\n    <!-- Google Fonts -->\n    <link href=\"https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap\" rel=\"stylesheet\">\n    <!-- Tailwind CSS for layout -->\n    <script src=\"https://cdn.tailwindcss.com\"></script>\n    <style>\n        body {\n            font-family: 'Roboto', sans-serif;\n            background-color: #f7f7f7;\n            color: #000;\n        }\n\n        .dropzone {\n            border: 2px dashed #ccc;\n            border-radius: 8px;\n            padding: 20px;\n            text-align: center;\n            background: #fff;\n            transition: border-color 0.3s ease;\n            cursor: pointer;\n        }\n\n        .dropzone:hover {\n            border-color: #3b82f6;\n        }\n\n        .terminal {\n            background-color: #212121;\n            color: #00FF00;\n            font-family: 'Courier New', Courier, monospace;\n            padding: 1rem;\n            border-radius: 4px;\n            height: 150px;\n            overflow-y: auto;\n            font-size: 0.875rem;\n        }\n\n        .progress-bar-container {\n            background-color: #e0e0e0;\n            border-radius: 10px;\n            height: 12px;\n            width: 100%;\n            overflow: hidden;\n        }\n\n        .progress-bar-fill {\n            background-color: #3b82f6;\n            height: 100%;\n            width: 0%;\n            transition: width 0.3s ease;\n        }\n\n        .btn-primary {\n            background-color: #1976d2;\n            color: white;\n            padding: 8px 16px;\n            border-radius: 4px;\n            font-weight: 500;\n            text-transform: uppercase;\n            box-shadow: 0px 3px 1px -2px rgba(0, 0, 0, 0.2), 0px 2px 2px 0px rgba(0, 0, 0, 0.14), 0px 1px 5px 0px rgba(0, 0, 0, 0.12);\n            transition: background-color 0.2s;\n        }\n\n        .btn-primary:hover {\n            background-color: #1565c0;\n        }\n\n        .btn-primary:disabled {\n            background-color: #ccc;\n            cursor: not-allowed;\n            box-shadow: none;\n        }\n\n        .btn-success {\n            border: 1px solid #2e7d32;\n            color: #2e7d32;\n            padding: 8px 16px;\n            border-radius: 4px;\n            font-weight: 500;\n            text-transform: uppercase;\n        }\n\n        .btn-success:hover {\n            background-color: rgba(46, 125, 50, 0.04);\n        }\n\n        .btn-secondary {\n            border: 1px solid #9c27b0;\n            color: #9c27b0;\n            padding: 8px 16px;\n            border-radius: 4px;\n            font-weight: 500;\n            text-transform: uppercase;\n        }\n\n        .btn-secondary:hover {\n            background-color: rgba(156, 39, 176, 0.04);\n        }\n\n        .card {\n            background: white;\n            padding: 24px;\n            border-radius: 4px;\n            box-shadow: 0px 2px 1px -1px rgba(0, 0, 0, 0.2), 0px 1px 1px 0px rgba(0, 0, 0, 0.14), 0px 1px 3px 0px rgba(0, 0, 0, 0.12);\n        }\n    </style>\n</head>\n\n<body class=\"p-8\">\n    <div class=\"max-w-7xl mx-auto\">\n        <h1 class=\"text-xl font-bold mb-6\">Extrator de dados de im\u00f3veis</h1>\n\n        <div class=\"grid grid-cols-1 md:grid-cols-2 gap-6\">\n            <!-- Coluna de A\u00e7\u00e3o -->\n            <div class=\"space-y-4\">\n                <div>\n                    <label class=\"block text-sm font-medium text-gray-700 mb-1\">Cole os dados CSV aqui</label>\n                    <textarea id=\"csvText\" rows=\"4\"\n                        class=\"w-full p-2 border border-gray-300 rounded shadow-sm focus:ring-blue-500 focus:border-blue-500\"\n                        placeholder=\"C\u00f3digo do Im\u00f3vel, Raz\u00e3o Social...\"></textarea>\n                </div>\n\n                <div id=\"dropzone\" class=\"dropzone\">\n                    <div id=\"dropzoneText\">Arraste o CSV para c\u00e1</div>\n                    <input type=\"file\" id=\"fileInput\" accept=\".csv\" class=\"hidden\">\n                    <div id=\"fileInfo\" class=\"mt-2 text-sm font-medium text-blue-600 hidden\"></div>\n                </div>\n\n                <div class=\"flex flex-wrap gap-2 items-center\">\n                    <button id=\"processBtn\" class=\"btn-primary flex items-center gap-2\">\n                        <span id=\"btnSpinner\"\n                            class=\"hidden animate-spin rounded-full h-4 w-4 border-2 border-white border-t-transparent\"></span>\n                        <span id=\"btnText\">Processar</span>\n                    </button>\n\n                    <a id=\"downloadXLSX\" href=\"#\" target=\"_blank\" class=\"btn-success hidden\">Baixar XLSX</a>\n                    <a id=\"downloadCSV\" href=\"#\" target=\"_blank\" class=\"btn-secondary hidden\">Baixar CSV</a>\n                </div>\n\n                <div id=\"logs\" class=\"terminal\">\n                    Logs do processo\n                </div>\n\n                <div class=\"space-y-1\">\n                    <div class=\"text-xs font-medium\">Progresso: <span id=\"progressText\">0</span>%</div>\n                    <div class=\"progress-bar-container\">\n                        <div id=\"progressBar\" class=\"progress-bar-fill\"></div>\n                    </div>\n                </div>\n            </div>\n\n            <!-- Coluna de Manual -->\n            <div class=\"card\">\n                <h2 class=\"text-lg font-bold mb-4\">Manual de Uso</h2>\n                <ul class=\"space-y-3 text-sm text-gray-600\">\n                    <li>1. Cole os dados CSV no campo ou envie o arquivo CSV.</li>\n                    <li>2. Clique em \"Processar\" para enviar ao processamento.</li>\n                    <li>3. O sistema far\u00e1 a consulta dos propriet\u00e1rios, o processo pode demorar alguns minutos\n                        dependendo da quantidade de im\u00f3veis.</li>\n                    <li>4. O arquivo gerado ser\u00e1 exibido para download assim que finalizado.</li>\n                </ul>\n            </div>\n        </div>\n    </div>\n\n    <!-- Notification Toast (Snackbar equivalent) -->\n    <div id=\"toast\"\n        class=\"fixed bottom-4 left-1/2 transform -translate-x-1/2 p-4 rounded shadow-lg hidden transition-opacity duration-300\">\n        <span id=\"toastMessage\"></span>\n    </div>\n\n    <script>\n        const csvText = document.getElementById('csvText');\n        const dropzone = document.getElementById('dropzone');\n        const fileInput = document.getElementById('fileInput');\n        const fileInfo = document.getElementById('fileInfo');\n        const processBtn = document.getElementById('processBtn');\n        const btnText = document.getElementById('btnText');\n        const btnSpinner = document.getElementById('btnSpinner');\n        const logsContainer = document.getElementById('logs');\n        const progressBar = document.getElementById('progressBar');\n        const progressText = document.getElementById('progressText');\n        const downloadXLSX = document.getElementById('downloadXLSX');\n        const downloadCSV = document.getElementById('downloadCSV');\n        const toast = document.getElementById('toast');\n        const toastMessage = document.getElementById('toastMessage');\n\n        let selectedFile = null;\n\n        // Dropzone interactions\n        dropzone.addEventListener('click', () => fileInput.click());\n        dropzone.addEventListener('dragover', (e) => {\n            e.preventDefault();\n            dropzone.style.borderColor = '#3b82f6';\n        });\n        dropzone.addEventListener('dragleave', () => {\n            dropzone.style.borderColor = '#ccc';\n        });\n        dropzone.addEventListener('drop', (e) => {\n            e.preventDefault();\n            dropzone.style.borderColor = '#ccc';\n            if (e.dataTransfer.files.length) {\n                handleFile(e.dataTransfer.files[0]);\n            }\n        });\n        fileInput.addEventListener('change', (e) => {\n            if (e.target.files.length) {\n                handleFile(e.target.files[0]);\n            }\n        });\n\n        function handleFile(file) {\n            if (file.name.endsWith('.csv')) {\n                selectedFile = file;\n                fileInfo.textContent = `Arquivo selecionado: ${file.name}`;\n                fileInfo.classList.remove('hidden');\n            } else {\n                showToast('Apenas arquivos .csv s\u00e3o permitidos.', 'error');\n            }\n        }\n\n        function appendLog(msg) {\n            const time = new Date().toLocaleTimeString();\n            const logEntry = document.createElement('div');\n            logEntry.textContent = `${time}: ${msg}`;\n            if (logsContainer.textContent === 'Logs do processo') logsContainer.textContent = '';\n            logsContainer.appendChild(logEntry);\n            logsContainer.scrollTop = logsContainer.scrollHeight;\n        }\n\n        function setProgress(val) {\n            progressBar.style.width = `${val}%`;\n            progressText.textContent = val;\n        }\n\n        function showToast(msg, severity = 'success') {\n            toastMessage.textContent = msg;\n            toast.className = `fixed bottom-4 left-1/2 transform -translate-x-1/2 p-4 rounded shadow-lg transition-opacity duration-300 ${severity === 'success' ? 'bg-green-600 text-white' : 'bg-red-600 text-white'\n                }`;\n            toast.classList.remove('hidden');\n            setTimeout(() => toast.classList.add('hidden'), 5000);\n        }\n\n        const WEBHOOK_URL = 'https://geo-imoveis.wernerhost.com.br/api/processar';\n\n        processBtn.addEventListener('click', async () => {\n            if (!selectedFile && !csvText.value.trim()) {\n                showToast('Nenhum conte\u00fado CSV fornecido.', 'error');\n                return;\n            }\n\n            processBtn.disabled = true;\n            btnText.textContent = 'Processando...';\n            btnSpinner.classList.remove('hidden');\n\n            appendLog('--- In\u00edcio da Solicita\u00e7\u00e3o ---');\n            setProgress(10);\n            appendLog('Enviando arquivo via backend...');\n\n            try {\n                const formData = new FormData();\n                if (selectedFile) {\n                    formData.append('arquivo', selectedFile);\n                } else {\n                    const blob = new Blob([csvText.value], { type: 'text/csv' });\n                    formData.append('arquivo', blob, 'dados.csv');\n                }\n\n                const response = await fetch(WEBHOOK_URL, {\n                    method: 'POST',\n                    body: formData,\n                });\n\n                if (!response.ok) throw new Error('Erro na requisi\u00e7\u00e3o ao backend');\n\n                appendLog('\u2705 backend recebeu o arquivo. Aguardando processamento...');\n                setProgress(20);\n\n            } catch (err) {\n                appendLog(`\u274c Erro no envio: ${err.message}`);\n                showToast(err.message, 'error');\n            } finally {\n                processBtn.disabled = false;\n                btnText.textContent = 'Processar';\n                btnSpinner.classList.add('hidden');\n            }\n        });\n\n        // Conectando aos logs reais via HTTPS (Domain Proxy)\n        const eventSource = new EventSource('https://geo-imoveis.wernerhost.com.br/api/logs');\n\n        appendLog('\ud83d\udd0c Conectando ao canal de logs...');\n\n        eventSource.onopen = () => {\n            appendLog('\ud83d\udfe2 Conectado ao servidor! Logs em tempo real ativos.');\n        };\n\n        eventSource.onmessage = (event) => {\n            const message = event.data;\n            if (message === ':heartbeat') return;\n\n            appendLog(`[BACKEND]: ${message}`);\n\n            if (message.includes('Link XLSX:')) {\n                const url = message.split('Link XLSX:')[1].trim();\n                downloadXLSX.href = url;\n                downloadXLSX.classList.remove('hidden');\n                setProgress(100);\n                appendLog('\u2728 Bot\u00e3o de download XLSX dispon\u00edvel.');\n            }\n            if (message.includes('Link CSV:')) {\n                const url = message.split('Link CSV:')[1].trim();\n                downloadCSV.href = url;\n                downloadCSV.classList.remove('hidden');\n                setProgress(100);\n                appendLog('\u2728 Bot\u00e3o de download CSV dispon\u00edvel.');\n            }\n        };\n\n        eventSource.onerror = (err) => {\n            console.error('Erro SSE:', err);\n            appendLog('\u26a0\ufe0f Conex\u00e3o de logs interrompida. Tentando reconectar automaticamente...');\n        };\n    </script>\n</body>\n\n</html>"
      },
      "type": "n8n-nodes-base.html",
      "typeVersion": 1.2,
      "position": [
        400,
        0
      ],
      "id": "1a34b52f-ad8d-4dea-8a1e-1ffc5794c93e",
      "name": "HTML"
    },
    {
      "parameters": {
        "path": "geo-itajai",
        "responseMode": "responseNode",
        "options": {}
      },
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2.1,
      "position": [
        112,
        0
      ],
      "id": "edc52a61-3bf0-4562-8ae0-def66a9a7175",
      "name": "www"
    },
    {
      "parameters": {
        "respondWith": "text",
        "responseBody": "={{ $json.html }}",
        "options": {}
      },
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.5,
      "position": [
        656,
        0
      ],
      "id": "49f3193f-1e4b-42ec-b041-57499e1d676f",
      "name": "Respond to Webhook"
    },
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "imoveis-processar",
        "options": {}
      },
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2.1,
      "position": [
        112,
        208
      ],
      "id": "08badbea-708d-4f56-9bd5-ec2a02d0f652",
      "name": "processar"
    },
    {
      "parameters": {
        "method": "POST",
        "url": "http://172.29.0.1:3000/processar",
        "sendBody": true,
        "contentType": "multipart-form-data",
        "bodyParameters": {
          "parameters": [
            {
              "parameterType": "formBinaryData",
              "name": "arquivo",
              "inputDataFieldName": "arquivo"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.3,
      "position": [
        336,
        208
      ],
      "id": "ef0a4bed-296a-4c28-b092-68b90926b51c",
      "name": "send-processar"
    }
  ],
  "connections": {
    "HTML": {
      "main": [
        [
          {
            "node": "Respond to Webhook",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "www": {
      "main": [
        [
          {
            "node": "HTML",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "processar": {
      "main": [
        [
          {
            "node": "send-processar",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": true,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "4285ee7b-37de-4df5-9047-a86d2e53e1cb",
  "id": "wGu63PjrWzvDgg1l",
  "tags": []
}