#!/usr/bin/env node /** * Reonomy Post-Login Explorer * * This script starts from an already logged-in state and explores * the dashboard to find where leads/properties are located. */ const puppeteer = require('puppeteer'); const fs = require('fs'); // Configuration const START_URL = 'https://app.reonomy.com/#!/account'; // Will login first const REONOMY_EMAIL = process.env.REONOMY_EMAIL || 'henry@realestateenhanced.com'; const REONOMY_PASSWORD = process.env.REONOMY_PASSWORD || '9082166532'; async function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } async function exploreAfterLogin() { console.log('πŸš€ Starting Reonomy exploration...\n'); const browser = await puppeteer.launch({ headless: false, // Keep visible to see what's happening args: ['--no-sandbox', '--disable-setuid-sandbox'] }); const page = await browser.newPage(); await page.setViewport({ width: 1920, height: 1080 }); try { // Step 1: Login console.log('πŸ“ Step 1: Logging in...'); await page.goto(START_URL, { waitUntil: 'networkidle2', timeout: 60000 }); await sleep(2000); await page.type('input[type="email"], input[placeholder*="example"]', REONOMY_EMAIL, { delay: 100 }); await page.type('input[type="password"], input[placeholder*="password"]', REONOMY_PASSWORD, { delay: 100 }); // Click login button - use Auth0-specific selector const loginButton = await page.$('button.auth0-lock-submit, button[type="submit"]'); if (loginButton) { await loginButton.click(); } else { // Fallback: look for button with text "Log In" const buttons = await page.$$('button'); for (const btn of buttons) { const text = await btn.evaluate(e => e.innerText || e.textContent); if (text && text.toLowerCase().includes('log in')) { await btn.click(); break; } } } console.log('⏳ Waiting for login...'); await sleep(5000); // Step 2: Check current state const currentUrl = page.url(); console.log(`πŸ“ Current URL: ${currentUrl}`); // Take screenshot await page.screenshot({ path: '/tmp/reonomy-dashboard.png', fullPage: true }); console.log('πŸ“Έ Screenshot saved: /tmp/reonomy-dashboard.png'); // Step 3: Get page content for analysis const html = await page.content(); fs.writeFileSync('/tmp/reonomy-html.html', html); console.log('πŸ“„ HTML saved: /tmp/reonomy-html.html'); // Step 4: Extract visible text const bodyText = await page.evaluate(() => document.body.innerText); fs.writeFileSync('/tmp/reonomy-text.txt', bodyText); console.log('πŸ“ Text content saved: /tmp/reonomy-text.txt'); // Step 5: Look for links and navigation console.log('\nπŸ” Looking for links and navigation...'); const links = await page.evaluate(() => { const linkElements = Array.from(document.querySelectorAll('a')); return linkElements .map(a => ({ text: a.innerText || a.textContent, href: a.href, className: a.className })) .filter(l => l.text && l.text.trim().length > 0 && l.text.length < 100) .slice(0, 50); // Limit to first 50 }); console.log(`Found ${links.length} links:`); links.forEach((link, i) => { console.log(` ${i + 1}. "${link.text.trim()}" -> ${link.href}`); }); // Step 6: Look for search/property-related elements console.log('\nπŸ” Looking for search elements...'); const searchElements = await page.evaluate(() => { const inputs = Array.from(document.querySelectorAll('input')); return inputs .map(input => ({ type: input.type, placeholder: input.placeholder, name: input.name, className: input.className })) .filter(i => i.placeholder && (i.placeholder.toLowerCase().includes('search') || i.placeholder.toLowerCase().includes('address') || i.placeholder.toLowerCase().includes('property'))); }); if (searchElements.length > 0) { console.log('Found search inputs:'); searchElements.forEach((el, i) => { console.log(` ${i + 1}. Type: ${el.type}, Placeholder: "${el.placeholder}"`); }); } else { console.log(' No obvious search inputs found'); } // Step 7: Look for buttons and actions console.log('\nπŸ” Looking for action buttons...'); const buttonTexts = await page.evaluate(() => { const buttons = Array.from(document.querySelectorAll('button, .btn, [role="button"]')); return buttons .map(b => (b.innerText || b.textContent).trim()) .filter(t => t && t.length > 0 && t.length < 50) .slice(0, 30); }); console.log(`Found ${buttonTexts.length} buttons:`); buttonTexts.forEach((text, i) => { console.log(` ${i + 1}. "${text}"`); }); // Step 8: Check for data tables or lists console.log('\nπŸ” Looking for data containers...'); const dataSelectors = await page.evaluate(() => { const selectors = ['table', '[role="grid"]', '.list', '.results', '.cards', '.grid', '[data-test*="list"]']; const results = {}; selectors.forEach(sel => { const elements = document.querySelectorAll(sel); if (elements.length > 0) { results[sel] = elements.length; } }); return results; }); if (Object.keys(dataSelectors).length > 0) { console.log('Found data containers:'); Object.entries(dataSelectors).forEach(([sel, count]) => { console.log(` ${sel}: ${count} elements`); }); } console.log('\nβœ… Exploration complete!'); console.log('πŸ’‘ Review the saved files to understand the UI structure:'); console.log(' - /tmp/reonomy-dashboard.png (screenshot)'); console.log(' - /tmp/reonomy-html.html (page HTML)'); console.log(' - /tmp/reonomy-text.txt (visible text)'); console.log(' - /tmp/reonomy-links.json (links - saved below)'); // Save links to JSON fs.writeFileSync('/tmp/reonomy-links.json', JSON.stringify(links, null, 2)); console.log('\n⏸️ Browser kept open. Press Ctrl+C to close, or close manually to exit.'); // Keep browser open for manual inspection await new Promise(() => {}); } catch (error) { console.error('❌ Error:', error.message); console.error(error.stack); await page.screenshot({ path: '/tmp/reonomy-error.png', fullPage: true }); } finally { await browser.close(); } } exploreAfterLogin().catch(error => { console.error('Fatal error:', error); process.exit(1); });