Skip for now
๐Ÿ‘
EWE
Ready to help you get started

Your Page Preview

Waiting to start...
๐Ÿช

Your business page will appear here as we chat!

๐ŸŽ‰
You're All Set!
Your page is ready to go live
function getOmniaIdentity() { try { const stored = localStorage.getItem('omnia_identity'); return stored ? JSON.parse(stored) : null; } catch(e) { return null; } } // Personalized greeting for users upgrading from Talent Liberation function getUpgradeGreeting(identity) { const interests = identity?.preferences?.interests || []; const chatCount = identity?.engagement?.chatMessages || 0; let greeting = "Hey! I saw you found us through Talent Liberation! ๐ŸŽ‰\n\n"; if (chatCount > 0) { greeting += "Looks like you've been chatting with CHESTER over there - "; } greeting += "Welcome to EWEPIP, the full experience!\n\n"; // Personalize based on detected interests if (interests.includes('jobs')) { greeting += "Since you're interested in work opportunities, let me show you how to create your own profile so employers can find YOU.\n\n"; } else if (interests.includes('business')) { greeting += "I see you're into business stuff - great! Here you can build your full presence and connect with clients.\n\n"; } else { greeting += "This is where you get saved searches, your own dashboard, AI tools, and way more.\n\n"; } greeting += "What's your name?"; return greeting; } // Greeting for returning cross-site users function getCrossSiteGreeting(identity) { const sites = identity.journey.sitesVisited.filter(s => !s.includes('ewepip')); let greeting = "Hey, welcome back! ๐Ÿ‘\n\n"; if (sites.length > 1) { greeting += "I see you've been exploring the OMNIA ecosystem - love that curiosity!\n\n"; } else if (sites.some(s => s.includes('knuckledragger'))) { greeting += "Coming from the builder side, I see! Ready to set up your profile?\n\n"; } else if (sites.some(s => s.includes('academy'))) { greeting += "Been doing some learning? Awesome! Now let's put that knowledge to work.\n\n"; } greeting += "I'm EWE, and I'll help you get set up here on EWEPIP.\n\nWhat's your name?"; return greeting; } function addMessage(text, role, quickActions = null) { const container = document.getElementById('chatMessages'); const div = document.createElement('div'); div.className = 'message ' + role; const time = new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }); let html = `
${escapeHtmlBr(text)}
`; html += `
${time}
`; if (quickActions && role === 'assistant') { html += '
'; quickActions.forEach(action => { html += ``; }); html += '
'; } div.innerHTML = html; container.appendChild(div); container.scrollTop = container.scrollHeight; // Store in context conversationContext.push({ role, content: text }); } function escapeHtmlBr(text) { return escapeHtml(text).replace(/\n/g, '
'); } // ============================================ // INSTANT ACK SYSTEM - Makes EWE feel alive // ============================================ function getInstantAck(text, step) { const lower = text.toLowerCase(); // Context-aware acks based on what step we're on const stepAcks = { 0: () => { // Just got their name const name = extractName(text); if (name.length <= 3) return "Hey!"; return ["Hey " + name + "!", "Oh hi!", name + "! Nice."][Math.floor(Math.random() * 3)]; }, 1: () => { // Purpose if (lower.includes('earn') || lower.includes('money')) return "Love that energy."; if (lower.includes('business')) return "Ooh, entrepreneur!"; if (lower.includes('hire') || lower.includes('shop')) return "Looking to get stuff done!"; if (lower.includes('explor')) return "Just vibes, I respect it."; return "Gotcha."; }, 2: () => { // Business name if (text.length > 20) return "That's a good name!"; return ["Nice!", "Love it.", "Solid name."][Math.floor(Math.random() * 3)]; }, 3: () => { // Location return ["Oh cool!", "Nice area.", "Got it."][Math.floor(Math.random() * 3)]; }, 4: () => { // Services if (lower.includes('cookie') || lower.includes('bake')) return "Mmm, baking! ๐Ÿช"; if (lower.includes('collect') || lower.includes('figure')) return "Oh nice, collectibles!"; if (lower.includes('photo')) return "Photography, love it!"; if (lower.includes('web') || lower.includes('design')) return "Tech skills, nice!"; if (lower.includes('clean')) return "Always in demand!"; if (lower.includes('food') || lower.includes('cook')) return "Yum!"; return "Cool, I can work with that."; }, 5: () => { // Description if (text.length > 50) return "Great detail!"; return "Perfect."; } }; // Get step-specific ack or generic if (stepAcks[step]) { return stepAcks[step](); } // Generic fallbacks const generics = ["Hmm...", "Okay...", "Let me see...", "Got it.", "Alright..."]; return generics[Math.floor(Math.random() * generics.length)]; } function addQuickAck(text) { const container = document.getElementById('chatMessages'); const div = document.createElement('div'); div.className = 'message assistant'; div.innerHTML = `
${text}
`; container.appendChild(div); container.scrollTop = container.scrollHeight; } function selectQuickAction(value, text) { // Disable all quick action buttons document.querySelectorAll('.quick-btn').forEach(btn => btn.disabled = true); // Send as user message processUserInput(text, value); } async function sendMessage() { const input = document.getElementById('chatInput'); const text = input.value.trim(); if (!text || isProcessing) return; input.value = ''; processUserInput(text); } async function processUserInput(text, quickValue = null) { isProcessing = true; document.getElementById('sendBtn').disabled = true; addMessage(text, 'user'); // INSTANT ACK - respond immediately before thinking const ack = getInstantAck(text, onboardingStep); if (ack) { await delay(150); // Tiny pause feels more natural than 0ms addQuickAck(ack); } // Show typing document.getElementById('typing').classList.add('show'); // Process based on current step const currentFlow = onboardingFlow[onboardingStep]; // Extract data from response await extractAndUpdate(currentFlow.extract, text, quickValue); // Move to next step onboardingStep++; // Find next applicable step (skip if needed) while (onboardingStep < onboardingFlow.length) { const nextFlow = onboardingFlow[onboardingStep]; if (nextFlow.skipIf && nextFlow.skipIf(profile)) { onboardingStep++; } else { break; } } // Try to get EWE's natural response from API let eweResponse = null; try { const resp = await fetch(API_URL + '/api/chat/domain', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ message: `User said: "${text}". We're on step ${onboardingStep} of onboarding. Their profile so far: ${JSON.stringify(profile)}. Give a friendly, brief response acknowledging what they said and naturally leading to the next question.`, domain: DOMAIN, context: 'onboarding', profile: profile }) }); const data = await resp.json(); if (data.response) { eweResponse = data.response; } } catch (e) { console.log('Using fallback response'); } document.getElementById('typing').classList.remove('show'); if (onboardingStep < onboardingFlow.length) { const nextFlow = onboardingFlow[onboardingStep]; let message; if (eweResponse && onboardingStep > 2 && onboardingStep < 6) { // Use EWE's natural response for middle steps (but not early ones) message = eweResponse; } else { // Use scripted message // Messages can be: string, func(), func(name), or func(profile) if (typeof nextFlow.message === 'function') { if (nextFlow.key === 'done') { message = nextFlow.message(profile); } else { message = nextFlow.message(profile.name); } } else { message = nextFlow.message; } } addMessage(message, 'assistant', nextFlow.quickActions); // Add teaching hint occasionally (not overwhelming) maybeShowTeachingHint(); } else { // Onboarding complete completeOnboarding(); } isProcessing = false; document.getElementById('sendBtn').disabled = false; updatePreview(); updateProgress(); saveProfile(); } // Progressive teaching - gentle hints, not overwhelming let hintsShown = 0; const maxHintsPerSession = 2; function maybeShowTeachingHint() { if (hintsShown >= maxHintsPerSession) return; if (Math.random() > 0.3) return; // Only 30% chance const hints = [ { step: 3, hint: "Tip: Your services become searchable tags. People find you when they search for these!" }, { step: 4, hint: "Did you know? Your location helps nearby customers discover you automatically." }, { step: 5, hint: "Pro tip: A good description helps EWE recommend you to the right customers." } ]; const relevantHint = hints.find(h => h.step === onboardingStep); if (relevantHint) { setTimeout(() => { addTeachingHint(relevantHint.hint); hintsShown++; }, 1500); } } function addTeachingHint(hint) { const container = document.getElementById('chatMessages'); const div = document.createElement('div'); div.className = 'message assistant'; div.innerHTML = `
๐Ÿ’ก ${hint}
`; container.appendChild(div); container.scrollTop = container.scrollHeight; } async function extractAndUpdate(field, text, quickValue) { switch (field) { case 'name': profile.name = extractName(text); break; case 'purpose': profile.purpose = quickValue || guessPurpose(text); break; case 'businessName': profile.businessName = text.trim(); // Generate emoji based on business profile.emoji = guessEmoji(text); break; case 'location': profile.location = text.trim(); break; case 'services': profile.services = extractServices(text); break; case 'description': profile.description = text.trim(); break; } } function extractName(text) { // Simple name extraction - take first word or two const cleaned = text.replace(/^(i'm|i am|my name is|call me|it's|its)\s*/i, ''); const words = cleaned.split(/\s+/); return words.slice(0, 2).join(' ').replace(/[.,!?]$/, ''); } function guessPurpose(text) { const lower = text.toLowerCase(); if (lower.includes('earn') || lower.includes('money') || lower.includes('work') || lower.includes('job')) return 'earn'; if (lower.includes('business') || lower.includes('sell') || lower.includes('offer')) return 'business'; if (lower.includes('hire') || lower.includes('buy') || lower.includes('shop') || lower.includes('find')) return 'consumer'; return 'explore'; } // Smart service extraction - parses natural language into clean tags function extractServices(text) { const lower = text.toLowerCase(); // Common filler words to remove const stopWords = ['make', 'sell', 'offer', 'provide', 'do', 'create', 'want', 'to', 'a', 'an', 'the', 'and', 'or', 'for', 'of', 'in', 'on', 'with', 'my', 'i', 'we', 'our', 'bunch', 'lot', 'lots', 'some', 'store', 'shop', 'business', 'service', 'services', 'stuff', 'things', 'like', 'such', 'as', 'etc', 'e-store', 'estore', 'online']; // Known service/product keywords to recognize const knownServices = { 'collectables': ['collectable', 'collectables', 'collectible', 'collectibles', 'collection'], 'action figures': ['action figure', 'action figures', 'figures', 'figurines'], 'toys': ['toy', 'toys'], 'knickknacks': ['knickknack', 'knickknacks', 'knick-knack', 'knick-knacks', 'trinket', 'trinkets'], 'vintage items': ['vintage', 'antique', 'antiques', 'retro'], 'cookies': ['cookie', 'cookies', 'biscuit', 'biscuits'], 'baking': ['bake', 'baking', 'baked goods', 'bakery'], 'cakes': ['cake', 'cakes', 'cupcake', 'cupcakes'], 'photography': ['photo', 'photos', 'photography', 'photographer', 'portraits'], 'web design': ['web design', 'website', 'websites', 'web development'], 'graphic design': ['graphic design', 'graphics', 'logo', 'logos', 'branding'], 'crafts': ['craft', 'crafts', 'handmade', 'handcraft'], 'art': ['art', 'artwork', 'painting', 'paintings', 'artist'], 'jewelry': ['jewelry', 'jewellery', 'necklace', 'bracelet', 'earrings'], 'clothing': ['clothing', 'clothes', 'apparel', 'fashion', 'shirts', 't-shirts'], 'consulting': ['consulting', 'consultant', 'advice', 'advisory'], 'tutoring': ['tutor', 'tutoring', 'teaching', 'lessons'], 'cleaning': ['cleaning', 'clean', 'housekeeping', 'maid'], 'landscaping': ['landscaping', 'lawn', 'garden', 'gardening', 'yard'], 'repairs': ['repair', 'repairs', 'fix', 'fixing', 'maintenance'] }; let extractedServices = []; // First, check for known multi-word services for (const [serviceName, keywords] of Object.entries(knownServices)) { for (const keyword of keywords) { if (lower.includes(keyword)) { if (!extractedServices.includes(serviceName)) { extractedServices.push(serviceName); } break; } } } // If we found known services, return them if (extractedServices.length > 0) { return extractedServices.slice(0, 5); // Max 5 tags } // Fallback: split by commas/and and clean up let parts = text.split(/[,;&]|\band\b/).map(s => s.trim()).filter(s => s.length > 2); // Clean each part parts = parts.map(part => { // Remove stop words let words = part.toLowerCase().split(/\s+/).filter(w => !stopWords.includes(w) && w.length > 2); return words.join(' '); }).filter(s => s.length > 0); return parts.slice(0, 5); // Max 5 tags } function guessEmoji(businessName) { const lower = businessName.toLowerCase(); if (lower.includes('collect') || lower.includes('figure') || lower.includes('toy')) return '๐ŸŽฏ'; if (lower.includes('vintage') || lower.includes('antique') || lower.includes('retro')) return '๐Ÿบ'; if (lower.includes('cookie') || lower.includes('bake') || lower.includes('cake')) return '๐Ÿช'; if (lower.includes('food') || lower.includes('restaurant') || lower.includes('cafe')) return '๐Ÿฝ๏ธ'; if (lower.includes('tech') || lower.includes('web') || lower.includes('software') || lower.includes('code')) return '๐Ÿ’ป'; if (lower.includes('design') || lower.includes('art') || lower.includes('creative')) return '๐ŸŽจ'; if (lower.includes('photo')) return '๐Ÿ“ธ'; if (lower.includes('music') || lower.includes('dj')) return '๐ŸŽต'; if (lower.includes('fitness') || lower.includes('gym') || lower.includes('train')) return '๐Ÿ’ช'; if (lower.includes('clean')) return '๐Ÿงน'; if (lower.includes('garden') || lower.includes('lawn') || lower.includes('plant')) return '๐ŸŒฑ'; if (lower.includes('pet') || lower.includes('dog') || lower.includes('cat')) return '๐Ÿ•'; if (lower.includes('car') || lower.includes('auto')) return '๐Ÿš—'; if (lower.includes('electric') || lower.includes('plumb')) return '๐Ÿ”ง'; if (lower.includes('beauty') || lower.includes('hair') || lower.includes('salon')) return '๐Ÿ’‡'; if (lower.includes('tutor') || lower.includes('teach') || lower.includes('education')) return '๐Ÿ“š'; if (lower.includes('consult')) return '๐Ÿ’ผ'; return '๐Ÿช'; } function updatePreview() { const preview = document.getElementById('businessPreview'); const empty = document.getElementById('previewEmpty'); if (profile.businessName || profile.name) { empty.style.display = 'none'; preview.style.display = 'block'; document.getElementById('previewAvatar').textContent = profile.emoji; document.getElementById('previewName').textContent = profile.businessName || `${profile.name}'s Services`; document.getElementById('previewTagline').textContent = profile.tagline || (profile.services.length ? profile.services.slice(0, 2).join(' & ') : 'Services'); if (profile.location) { document.getElementById('previewLocation').style.display = 'flex'; document.getElementById('locationText').textContent = profile.location; } else { document.getElementById('previewLocation').style.display = 'none'; } const servicesContainer = document.getElementById('previewServices'); servicesContainer.innerHTML = profile.services.map(s => `${s}` ).join(''); document.getElementById('previewDescription').textContent = profile.description || 'Your description will appear here...'; document.getElementById('statusDot').classList.add('active'); document.getElementById('statusText').textContent = 'Building your page...'; } } function updateProgress() { const totalSteps = 5; const progress = Math.min(onboardingStep, totalSteps); for (let i = 1; i <= totalSteps; i++) { const step = document.getElementById('step' + i); step.classList.remove('done', 'current'); if (i < progress) step.classList.add('done'); else if (i === progress) step.classList.add('current'); } } function saveProfile() { localStorage.setItem('ewepip_profile', JSON.stringify(profile)); } async function completeOnboarding() { // Save final profile profile.status = 'active'; profile.publishedAt = new Date().toISOString(); saveProfile(); // Store in local "database" let businesses = JSON.parse(localStorage.getItem('ewepip_businesses') || '[]'); const existingIndex = businesses.findIndex(b => b.id === profile.id); if (existingIndex >= 0) { businesses[existingIndex] = profile; } else { businesses.push(profile); } localStorage.setItem('ewepip_businesses', JSON.stringify(businesses)); // Sync with OMNIA Pages API try { const resp = await fetch(API_URL + '/api/pages', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ id: profile.id, businessName: profile.businessName, name: profile.name, tagline: profile.tagline, description: profile.description, services: profile.services, location: profile.location, emoji: profile.emoji, category: profile.category }) }); if (resp.ok) { } } catch (e) { } // Show completion with personalized message const completionMessages = [ `๐ŸŽ‰ Done! Your page "${profile.businessName}" is now live!\n\nPeople in ${profile.location || 'your area'} can find you on EWEPIP. Come back anytime to update your profile or check messages.`, `๐Ÿ‘ Baa-rillliant! "${profile.businessName}" is ready to go!\n\nYou're all set up. When customers find you, you'll get notified. Feel free to explore or add more details later!`, `โœจ "${profile.businessName}" is live!\n\nThat wasn't so bad, right? Your page is ready for customers. You can always tweak things later - no pressure!` ]; addMessage(completionMessages[Math.floor(Math.random() * completionMessages.length)], 'assistant'); document.getElementById('statusText').textContent = 'Published!'; document.getElementById('viewPageBtn').href = '/pages/?id=' + profile.id; // Show completion view after delay setTimeout(() => { document.getElementById('completionView').classList.add('show'); }, 1000); } function delay(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } // Initialize init();