// OneSearch Main Application Script // Application State Management class OneSearchApp { constructor() { this.user = null; this.currentSearch = null; this.searchResults = []; this.trustScores = new Map(); this.walletBalance = 47.23; this.isAuthenticated = false; this.init(); } init() { this.setupEventListeners(); this.initializeComponents(); this.loadInitialData(); this.setupWebSocketConnection(); console.log('OneSearch app initialized'); } setupEventListeners() { // Search functionality const searchBtn = document.getElementById('search-btn'); const problemInput = document.getElementById('problem-input'); if (searchBtn) { searchBtn.addEventListener('click', () => this.performSearch()); } if (problemInput) { problemInput.addEventListener('keypress', (e) => { if (e.key === 'Enter') { this.performSearch(); } }); } // QR Generation const generateQrBtn = document.getElementById('generate-qr'); if (generateQrBtn) { generateQrBtn.addEventListener('click', () => this.showQRModal()); } const createQrBtn = document.getElementById('create-qr-btn'); if (createQrBtn) { createQrBtn.addEventListener('click', () => this.showQRModal()); } const closeQrModal = document.getElementById('close-qr-modal'); if (closeQrModal) { closeQrModal.addEventListener('click', () => this.hideQRModal()); } // Authentication const authButton = document.getElementById('auth-button'); if (authButton) { authButton.addEventListener('click', () => this.handleAuth()); } // Navigation this.setupNavigation(); } setupNavigation() { // Smooth scrolling for navigation links document.querySelectorAll('a[href^="#"]').forEach(link => { link.addEventListener('click', (e) => { e.preventDefault(); const target = document.querySelector(link.getAttribute('href')); if (target) { target.scrollIntoView({ behavior: 'smooth', block: 'start' }); } }); }); } async performSearch() { const problemInput = document.getElementById('problem-input'); const query = problemInput?.value.trim(); if (!query) { this.showNotification('Please enter a problem description', 'warning'); return; } try { this.setLoading(true); // Simulate AI-powered problem interpretation const searchResults = await this.interpretProblem(query); this.searchResults = searchResults; this.currentSearch = query; this.updateMindMap(searchResults); this.displaySearchResults(searchResults); this.showNotification('Search completed successfully', 'success'); } catch (error) { console.error('Search error:', error); this.showNotification('Search failed. Please try again.', 'error'); } finally { this.setLoading(false); } } async interpretProblem(query) { // Simulate AI/ML interpretation with mock data await new Promise(resolve => setTimeout(resolve, 1500)); // Simulate API call const mockProducts = [ { id: '1', title: 'Stackable Storage Containers Set', description: 'Apex Kitchen Solutions - Set of 6 BPA-free containers with airtight seals', merchant: 'Apex Kitchen Solutions', category: 'Storage Solutions', price: 32.99, currency: 'USD', score: 82.6, scoreBreakdown: { recommenderReputation: 0.68, provenance: 0.95, usageDuration: 0.6, conversionRate: 0.3, afterSales: 0.7, locality: 0.9, costSatisfaction: 0.64, qualityReviews: 0.92 }, reviewCount: 124, averageRating: 4.2, qrConversions: 23, wageTransparency: true, livingWageCompliant: true, tags: ['kitchen', 'storage', 'organization', 'space-saving'] }, { id: '2', title: 'Modular Cabinet System', description: 'FlexStorage Pro - Adjustable cabinet system for small spaces', merchant: 'FlexStorage Pro', category: 'Storage Solutions', price: 89.99, currency: 'USD', score: 78.3, scoreBreakdown: { recommenderReputation: 0.72, provenance: 0.88, usageDuration: 0.75, conversionRate: 0.25, afterSales: 0.65, locality: 0.85, costSatisfaction: 0.58, qualityReviews: 0.85 }, reviewCount: 89, averageRating: 4.0, qrConversions: 18, wageTransparency: false, livingWageCompliant: false, tags: ['kitchen', 'storage', 'cabinet', 'modular'] }, { id: '3', title: 'Magnetic Organization System', description: 'MagOrganize - Magnetic strips and containers for vertical storage', merchant: 'MagOrganize Co', category: 'Storage Solutions', price: 24.99, currency: 'USD', score: 75.8, scoreBreakdown: { recommenderReputation: 0.65, provenance: 0.82, usageDuration: 0.55, conversionRate: 0.4, afterSales: 0.72, locality: 0.9, costSatisfaction: 0.71, qualityReviews: 0.88 }, reviewCount: 156, averageRating: 4.1, qrConversions: 31, wageTransparency: true, livingWageCompliant: true, tags: ['kitchen', 'storage', 'magnetic', 'vertical'] } ]; return mockProducts; } updateMindMap(results) { const mindMapContainer = document.getElementById('mindmap-container'); if (!mindMapContainer || !window.MindMap) return; // Prepare mind map data const mindMapData = { nodes: [ { id: 'root', label: this.currentSearch, level: 0 }, { id: 'category', label: 'Storage Solutions', level: 1 }, { id: 'budget', label: '$25-$90', level: 1 }, { id: 'size', label: 'Small Space', level: 1 } ], edges: [ { from: 'root', to: 'category' }, { from: 'root', to: 'budget' }, { from: 'root', to: 'size' } ] }; // Add product nodes results.forEach((product, index) => { const nodeId = `product_${product.id}`; mindMapData.nodes.push({ id: nodeId, label: product.title, level: 2, score: product.score }); mindMapData.edges.push({ from: 'category', to: nodeId }); }); window.MindMap.render(mindMapContainer, mindMapData); } displaySearchResults(results) { const resultsContainer = document.getElementById('search-results'); if (!resultsContainer) return; resultsContainer.innerHTML = ''; results.forEach(product => { const resultElement = this.createResultElement(product); resultsContainer.appendChild(resultElement); }); } createResultElement(product) { const result = document.createElement('div'); result.className = 'search-result-item'; result.innerHTML = `

${product.title}

${product.wageTransparency ? 'Wage Transparent' : ''} ${product.livingWageCompliant ? 'Living Wage' : ''}

${product.description}

by ${product.merchant} ${product.averageRating} (${product.reviewCount} reviews) ${product.qrConversions} recommendations
Recommender
${Math.round(product.scoreBreakdown.recommenderReputation * 100)}%
Provenance
${Math.round(product.scoreBreakdown.provenance * 100)}%
Reviews
${Math.round(product.scoreBreakdown.qualityReviews * 100)}%
Cost Satisfaction
${Math.round(product.scoreBreakdown.costSatisfaction * 100)}%
${product.score}
Trust Score
$${product.price}
`; // Replace feather icons setTimeout(() => { if (window.feather) { window.feather.replace(); } }, 0); return result; } getScoreColorClass(score) { if (score >= 80) return 'trust-score-excellent'; if (score >= 70) return 'trust-score-good'; if (score >= 60) return 'trust-score-average'; return 'trust-score-poor'; } showQRModal() { const modal = document.getElementById('qr-modal'); if (modal) { modal.classList.remove('hidden'); modal.classList.add('fade-in'); } } hideQRModal() { const modal = document.getElementById('qr-modal'); if (modal) { modal.classList.add('hidden'); modal.classList.remove('fade-in'); } } handleAuth() { if (this.isAuthenticated) { this.logout(); } else { this.login(); } } async login() { // Simulate OAuth login try { this.setLoading(true); await new Promise(resolve => setTimeout(resolve, 1000)); this.user = { id: 'user_123', displayName: 'Demo User', profileTrust: 0.94, verifiedLevel: 'merchant-verified', walletAccountId: 'wallet_456' }; this.isAuthenticated = true; this.updateAuthUI(); this.showNotification('Successfully signed in', 'success'); } catch (error) { this.showNotification('Login failed', 'error'); } finally { this.setLoading(false); } } logout() { this.user = null; this.isAuthenticated = false; this.updateAuthUI(); this.showNotification('Signed out successfully', 'info'); } updateAuthUI() { const authButton = document.getElementById('auth-button'); const generateQrButton = document.getElementById('generate-qr'); if (this.isAuthenticated) { authButton.textContent = 'Sign Out'; authButton.className = 'bg-gray-500 hover:bg-gray-600 text-white px-4 py-2 rounded-md text-sm font-medium'; if (generateQrButton) { generateQrButton.classList.remove('hidden'); } } else { authButton.textContent = 'Sign In'; authButton.className = 'bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded-md text-sm font-medium'; if (generateQrButton) { generateQrButton.classList.add('hidden'); } } } setupWebSocketConnection() { // Simulate WebSocket connection for real-time updates if ('WebSocket' in window) { // In a real implementation, this would connect to the actual WebSocket server console.log('WebSocket support detected'); } } initializeComponents() { // Initialize trust score component if (window.TrustScore) { window.TrustScore.init(); } // Initialize review system if (window.ReviewSystem) { window.ReviewSystem.init(); } // Initialize wallet component if (window.Wallet) { window.Wallet.init(); } } loadInitialData() { // Load initial sample data this.updateTrustScores(); this.loadSampleReviews(); } updateTrustScores() { // Simulate trust score updates const scores = [82.6, 78.3, 75.8, 89.2, 71.5]; scores.forEach((score, index) => { this.trustScores.set(`product_${index + 1}`, score); }); } loadSampleReviews() { // Sample reviews are already in the HTML // This method can be used to load dynamic review data } setLoading(loading) { const searchBtn = document.getElementById('search-btn'); if (loading) { searchBtn.disabled = true; searchBtn.innerHTML = ' Searching...'; } else { searchBtn.disabled = false; searchBtn.innerHTML = 'Search'; } } showNotification(message, type = 'info') { // Create notification element const notification = document.createElement('div'); notification.className = `fixed top-4 right-4 z-50 p-4 rounded-lg shadow-lg max-w-sm transform transition-all duration-300 translate-x-full`; const bgColor = { success: 'bg-green-500', error: 'bg-red-500', warning: 'bg-yellow-500', info: 'bg-blue-500' }[type]; notification.classList.add(bgColor); notification.innerHTML = `
${message}
`; document.body.appendChild(notification); // Trigger animation setTimeout(() => { notification.classList.remove('translate-x-full'); }, 100); // Auto remove after 5 seconds setTimeout(() => { notification.classList.add('translate-x-full'); setTimeout(() => { if (notification.parentElement) { notification.remove(); } }, 300); }, 5000); // Replace icons setTimeout(() => { if (window.feather) { window.feather.replace(); } }, 0); } } // Initialize application when DOM is loaded document.addEventListener('DOMContentLoaded', () => { // Initialize the main app window.OneSearchApp = new OneSearchApp(); // Setup global error handling window.addEventListener('error', (event) => { console.error('Global error:', event.error); if (window.OneSearchApp) { window.OneSearchApp.showNotification('An unexpected error occurred', 'error'); } }); // Setup unhandled promise rejection handling window.addEventListener('unhandledrejection', (event) => { console.error('Unhandled promise rejection:', event.reason); if (window.OneSearchApp) { window.OneSearchApp.showNotification('A network error occurred', 'error'); } }); }); // Export for use in other components if (typeof module !== 'undefined' && module.exports) { module.exports = OneSearchApp; }