diff --git a/portal/setup-wizard.html b/portal/setup-wizard.html index 4172843..7108f13 100644 --- a/portal/setup-wizard.html +++ b/portal/setup-wizard.html @@ -1401,6 +1401,200 @@ // Hide upload section, show conversation document.getElementById('uploadSection').style.display = 'none'; + addMessage('ai', ` +
+
+ Scanning website for menu pages... +
+

This takes about 30 seconds while I crawl the site and look for menu sub-pages.

+ `); + + try { + // Phase 1: Discovery — quick Playwright crawl to find menu pages + const discoverResp = await fetch(`${config.apiBaseUrl}/setup/analyzeMenuUrl.php`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ mode: 'discover', url }) + }); + const discoverResult = await discoverResp.json(); + + if (!discoverResult.OK) { + throw new Error(discoverResult.MESSAGE || 'Failed to scan website'); + } + + console.log('=== DISCOVERY RESULT ===', discoverResult); + document.getElementById('conversation').innerHTML = ''; + + const menuPages = discoverResult.menuPages || []; + const siteName = discoverResult.siteName || ''; + + if (menuPages.length > 1) { + // Multiple menus found — show confirmation step + const pageListHtml = menuPages.map((p, i) => ` + + `).join(''); + + addMessage('ai', ` +

I found ${menuPages.length} menu pages${siteName ? ' for ' + siteName + '' : ''}:

+
+ ${pageListHtml} +
+

Uncheck any that aren't actual menus. Each checked page will be analyzed separately.

+
+ +
+
+ + +
+ `); + } else { + // No sub-pages or just one — fall through to single-page extract + await extractSingleUrl(url); + } + + } catch (error) { + console.error('URL analysis error:', error); + document.getElementById('conversation').innerHTML = ''; + addMessage('ai', ` +

Sorry, I encountered an error importing from that URL:

+

${error.message}

+
+ + +
+ `); + } + } + + // Phase 2: Extract each confirmed menu page individually + async function extractConfirmedMenuPages(mainUrl) { + const checkboxes = document.querySelectorAll('#discoveredMenuPages input[type="checkbox"]:checked'); + const pages = Array.from(checkboxes).map(cb => ({ + url: cb.dataset.menuUrl, + name: cb.dataset.menuName + })); + + // Add extra URL if provided + const extraUrl = (document.getElementById('extraMenuUrl')?.value || '').trim(); + if (extraUrl) { + const slug = extraUrl.replace(/.*\//, '').replace(/[-_]/g, ' '); + pages.push({ url: extraUrl, name: slug ? slug.charAt(0).toUpperCase() + slug.slice(1) : 'Extra' }); + } + + if (pages.length === 0) { + alert('Please select at least one menu page.'); + return; + } + + document.getElementById('conversation').innerHTML = ''; + + // Combined results + const allItems = []; + const allCategories = []; + const allMenus = []; + let businessInfo = {}; + let totalProcessed = 0; + + for (const page of pages) { + addMessage('ai', ` +
+
+ Extracting ${page.name} menu... (${totalProcessed + 1} of ${pages.length}) +
+ `); + + try { + const resp = await fetch(`${config.apiBaseUrl}/setup/analyzeMenuUrl.php`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ mode: 'extract_page', url: page.url, menuName: page.name }) + }); + const result = await resp.json(); + + if (result.OK && result.DATA) { + const data = result.DATA; + // Merge business info (first non-empty wins) + if (data.business && Object.keys(data.business).length > Object.keys(businessInfo).length) { + businessInfo = { ...businessInfo, ...data.business }; + } + // Add categories with menu tag + (data.categories || []).forEach(cat => { + const catName = typeof cat === 'string' ? cat : cat.name; + if (catName && !allCategories.find(c => c.name === catName && c.menuName === page.name)) { + allCategories.push({ name: catName, menuName: page.name }); + } + }); + // Add items (already tagged with menu name by backend) + (data.items || []).forEach(item => allItems.push(item)); + allMenus.push({ name: page.name }); + + totalProcessed++; + // Update with progress + document.getElementById('conversation').innerHTML = ''; + addMessage('ai', ` +

Extracted ${page.name}: ${data.items?.length || 0} items in ${data.categories?.length || 0} categories

+ `); + } else { + document.getElementById('conversation').innerHTML = ''; + addMessage('ai', `

Could not extract items from ${page.name} page.

`); + totalProcessed++; + } + } catch (err) { + console.error(`Error extracting ${page.name}:`, err); + document.getElementById('conversation').innerHTML = ''; + addMessage('ai', `

Error extracting ${page.name}: ${err.message}

`); + totalProcessed++; + } + } + + // Build final combined data + document.getElementById('conversation').innerHTML = ''; + config.extractedData = { + business: businessInfo, + categories: allCategories, + items: allItems, + modifiers: [], + menus: allMenus.length > 1 ? allMenus : [], + imageMappings: [], + imageUrls: [], + headerCandidateIndices: [], + }; + config.sourceUrl = mainUrl; + config.imageMappings = []; + + const totalItems = allItems.length; + const totalCats = allCategories.length; + addMessage('ai', ` +

Done! Found ${totalItems} items across ${totalCats} categories in ${allMenus.length} menus.

+ `); + + console.log('=== MULTI-PAGE EXTRACT RESULT ===', config.extractedData); + + // Brief pause then continue to business info + await new Promise(r => setTimeout(r, 1500)); + document.getElementById('conversation').innerHTML = ''; + if (config.businessId && config.menuId) { + showCategoriesStep(); + } else { + showBusinessInfoStep(); + } + } + + // Fallback: extract entire site as single page (original behavior) + async function skipDiscoveryExtractAll(url) { + document.getElementById('conversation').innerHTML = ''; + await extractSingleUrl(url); + } + + async function extractSingleUrl(url) { addMessage('ai', `
@@ -1422,29 +1616,18 @@ throw new Error(result.MESSAGE || 'Failed to analyze URL'); } - // Store extracted data config.extractedData = result.DATA; config.sourceUrl = result.sourceUrl; - - // Store image mappings for matching uploaded images to items config.imageMappings = result.DATA.imageMappings || []; - // Log debug info console.log('=== URL IMPORT RESPONSE ==='); console.log('Source URL:', result.sourceUrl); - console.log('Pages processed:', result.pagesProcessed); - console.log('Images found:', result.imagesFound); - console.log('Image mappings:', config.imageMappings.length); console.log('Extracted data:', result.DATA); - if (result.steps) { - console.log('Steps:', result.steps); - } + if (result.steps) console.log('Steps:', result.steps); console.log('==========================='); - // Remove loading message and start conversation flow document.getElementById('conversation').innerHTML = ''; - // In add-menu mode, skip business info and header if (config.businessId && config.menuId) { showCategoriesStep(); } else {