/** * WebWizard Frontend Logic */ const App = { state: { userId: localStorage.getItem('ww_user_id'), currentStep: 1, totalSteps: 8, project: null, categories: [], selection: { category: null, subcategory: null, customDescription: '' } }, async init() { console.log('Initializing WebWizard...'); if (!this.state.userId) { await this.initSession(); } await this.loadCategories(); this.bindEvents(); // If we don't have a project, try to load existing or create one if (!this.state.project) { await this.loadLastProject(); } this.showStep(this.state.currentStep); }, async loadLastProject() { try { const response = await this.apiCall('listProjects'); if (response.success && response.data.length > 0) { // Load the most recent project const lastProject = response.data[0]; const statusResponse = await this.apiCall('getProjectStatus', {}, lastProject.project_id); if (statusResponse.success) { this.state.project = statusResponse.data; this.state.currentStep = this.state.project.current_step || 1; console.log('Loaded existing project:', this.state.project.project_id); this.syncSelectionWithProject(); } } else { await this.createProject(); } } catch (error) { console.error('Failed to load projects:', error); await this.createProject(); } }, syncSelectionWithProject() { if (this.state.project && this.state.project.wizard_data) { const wd = this.state.project.wizard_data; // Step 1 if (wd.business_category) { const bc = wd.business_category; this.state.selection.category = bc.group; this.state.selection.subcategory = bc.subcategory; this.state.selection.customDescription = bc.custom_description || ''; if (this.state.selection.category) { this.selectCategory(this.state.selection.category); this.state.selection.subcategory = bc.subcategory; this.renderSubcategories(this.state.selection.category); } } // Step 2 if (wd.identity) { document.getElementById('business-name').value = wd.identity.business_name || ''; document.getElementById('business-tagline').value = wd.identity.tagline || ''; document.getElementById('business-description').value = wd.identity.description || ''; } if (wd.contact) { document.getElementById('contact-email').value = wd.contact.email || ''; document.getElementById('contact-phone').value = wd.contact.phone || ''; document.getElementById('contact-address').value = wd.contact.address || ''; document.getElementById('contact-city').value = wd.contact.city || ''; document.getElementById('contact-facebook').value = wd.contact.socials?.facebook || ''; document.getElementById('contact-instagram').value = wd.contact.socials?.instagram || ''; } // Step 3 if (wd.services && wd.services.items) { const list = document.getElementById('services-list'); list.innerHTML = ''; wd.services.items.forEach(item => this.addServiceItem(item)); document.getElementById('pricing-note').value = wd.services.pricing_note || ''; } else { this.addServiceItem(); } } }, async initSession() { try { const response = await this.apiCall('initSession'); if (response.success) { this.state.userId = response.data.user_id; localStorage.setItem('ww_user_id', this.state.userId); console.log('Session initialized:', this.state.userId); } } catch (error) { console.error('Failed to initialize session:', error); alert('Chyba pri inicializácii session.'); } }, async createProject() { try { const response = await this.apiCall('createProject'); if (response.success) { this.state.project = response.data; console.log('Project created:', this.state.project.project_id); } } catch (error) { console.error('Failed to create project:', error); } }, async loadCategories() { try { const response = await this.apiCall('getCategories'); if (response.success) { this.state.categories = response.data.categories; this.renderCategories(); } } catch (error) { console.error('Failed to load categories:', error); } }, async apiCall(action, payload = {}, projectId = null) { const body = { action, project_id: projectId || (this.state.project ? this.state.project.project_id : null), payload }; const headers = { 'Content-Type': 'application/json' }; if (this.state.userId) { headers['X-User-ID'] = this.state.userId; } const response = await fetch('/ajax.php', { method: 'POST', headers, body: JSON.stringify(body) }); const result = await response.json(); if (!result.success) { throw new Error(result.error.message || 'API Error'); } return result; }, bindEvents() { document.getElementById('btn-next').addEventListener('click', () => this.nextStep()); document.getElementById('btn-prev').addEventListener('click', () => this.prevStep()); document.getElementById('custom-description').addEventListener('input', (e) => { this.state.selection.customDescription = e.target.value; }); // Step 2 validation listeners ['business-name', 'gdpr-consent', 'contact-email', 'contact-phone'].forEach(id => { const el = document.getElementById(id); if (el) { el.addEventListener('input', () => this.updateUI()); el.addEventListener('change', () => this.updateUI()); } }); // Step 3 events document.getElementById('btn-add-service').addEventListener('click', () => this.addServiceItem()); }, renderCategories() { const container = document.getElementById('category-list'); container.innerHTML = ''; const icons = { gastro: '🍕', beauty: '✨', crafts: '🛠️', professional: '💼', other: '❓' }; this.state.categories.forEach(cat => { const card = document.createElement('div'); card.className = 'category-card'; if (this.state.selection.category === cat.id) card.classList.add('selected'); card.innerHTML = `
${icons[cat.id] || '📁'}
${cat.name}
`; card.addEventListener('click', () => this.selectCategory(cat.id)); container.appendChild(card); }); }, selectCategory(categoryId) { this.state.selection.category = categoryId; this.state.selection.subcategory = null; this.renderCategories(); this.renderSubcategories(categoryId); this.renderSmartQuestions(categoryId); document.getElementById('subcategory-container').classList.remove('hidden'); if (categoryId === 'other') { document.getElementById('custom-category-group').classList.remove('hidden'); } else { document.getElementById('custom-category-group').classList.add('hidden'); } }, renderSubcategories(categoryId) { const container = document.getElementById('subcategory-list'); container.innerHTML = ''; const category = this.state.categories.find(c => c.id === categoryId); if (!category) return; category.subcategories.forEach(sub => { const chip = document.createElement('div'); chip.className = 'chip'; if (this.state.selection.subcategory === sub.id) chip.classList.add('selected'); chip.textContent = sub.name; chip.addEventListener('click', () => { this.state.selection.subcategory = sub.id; this.renderSubcategories(categoryId); }); container.appendChild(chip); }); }, addServiceItem(data = {}) { const container = document.getElementById('services-list'); const itemDiv = document.createElement('div'); itemDiv.className = 'service-item'; itemDiv.innerHTML = `
Služba
`; itemDiv.querySelector('.btn-remove-service').addEventListener('click', () => { if (container.querySelectorAll('.service-item').length > 1) { itemDiv.remove(); } else { alert('Zadajte aspoň jednu službu.'); } }); container.appendChild(itemDiv); }, renderSmartQuestions(categoryId) { const container = document.getElementById('smart-questions-list'); container.innerHTML = ''; const category = this.state.categories.find(c => c.id === categoryId); if (!category || !category.smart_questions) { document.getElementById('smart-questions-container').classList.add('hidden'); return; } document.getElementById('smart-questions-container').classList.remove('hidden'); category.smart_questions.forEach(q => { const qDiv = document.createElement('div'); qDiv.className = 'smart-question-item'; if (q.type === 'boolean') { qDiv.innerHTML = `
`; } else { qDiv.innerHTML = `
`; } container.appendChild(qDiv); // Apply existing answer if available if (this.state.project && this.state.project.wizard_data.smart_answers) { const answer = this.state.project.wizard_data.smart_answers[q.id]; if (answer !== undefined) { const input = qDiv.querySelector(`#sq-${q.id}`); if (q.type === 'boolean') { input.checked = !!answer; } else { input.value = answer; } } } }); }, showStep(n) { const steps = document.querySelectorAll('.step'); steps.forEach(step => step.classList.remove('active')); const activeStep = document.querySelector(`.step[data-step="${n}"]`); if (activeStep) { activeStep.classList.add('active'); } this.state.currentStep = n; this.updateUI(); }, async nextStep() { if (this.state.currentStep === 1) { if (!this.state.selection.category || !this.state.selection.subcategory) { alert('Prosím, vyberte kategóriu aj podkategóriu.'); return; } try { await this.apiCall('saveStep', { step: 1, data: { business_category: { group: this.state.selection.category, subcategory: this.state.selection.subcategory, custom_description: this.state.selection.category === 'other' ? this.state.selection.customDescription : null } } }); } catch (error) { console.error('Save step failed:', error); alert('Nepodarilo sa uložiť dáta.'); return; } } else if (this.state.currentStep === 2) { const businessName = document.getElementById('business-name').value; const tagline = document.getElementById('business-tagline').value; const description = document.getElementById('business-description').value; const email = document.getElementById('contact-email').value; const phone = document.getElementById('contact-phone').value; const address = document.getElementById('contact-address').value; const city = document.getElementById('contact-city').value; const gdpr = document.getElementById('gdpr-consent').checked; if (!businessName || !gdpr || (!email && !phone)) { alert('Prosím, vyplňte povinné údaje a zaškrtnite GDPR súhlas.'); return; } try { // 1. Save Consent await this.apiCall('saveConsent', { consent_text: document.querySelector('label[for="gdpr-consent"]').textContent }); // 2. Save Step 2 await this.apiCall('saveStep', { step: 2, data: { identity: { business_name: businessName, tagline: tagline, description: description }, contact: { email: email, phone: phone, address: address, city: city, socials: { facebook: document.getElementById('contact-facebook').value, instagram: document.getElementById('contact-instagram').value } } } }); } catch (error) { console.error('Save step 2 failed:', error); alert('Nepodarilo sa uložiť dáta: ' + error.message); return; } } else if (this.state.currentStep === 3) { const serviceItems = []; document.querySelectorAll('.service-item').forEach(item => { const name = item.querySelector('.service-name').value; if (name) { serviceItems.push({ name: name, price_from: item.querySelector('.service-price').value, description: item.querySelector('.service-desc').value }); } }); const smartAnswers = {}; document.querySelectorAll('.smart-question-item input').forEach(input => { const id = input.getAttribute('data-id'); if (input.type === 'checkbox') { smartAnswers[id] = input.checked; } else { smartAnswers[id] = input.value; } }); try { await this.apiCall('saveStep', { step: 3, data: { services: { items: serviceItems, pricing_note: document.getElementById('pricing-note').value }, smart_answers: smartAnswers } }); } catch (error) { console.error('Save step 3 failed:', error); alert('Nepodarilo sa uložiť dáta: ' + error.message); return; } } if (this.state.currentStep < this.state.totalSteps) { this.showStep(this.state.currentStep + 1); } }, prevStep() { if (this.state.currentStep > 1) { this.showStep(this.state.currentStep - 1); } }, updateUI() { const btnPrev = document.getElementById('btn-prev'); const btnNext = document.getElementById('btn-next'); btnPrev.disabled = this.state.currentStep === 1; // Validation for Next button let nextDisabled = false; if (this.state.currentStep === 1) { nextDisabled = !this.state.selection.category || !this.state.selection.subcategory; } else if (this.state.currentStep === 2) { const name = document.getElementById('business-name').value; const email = document.getElementById('contact-email').value; const phone = document.getElementById('contact-phone').value; const gdpr = document.getElementById('gdpr-consent').checked; nextDisabled = !name || !gdpr || (!email && !phone); } btnNext.disabled = nextDisabled; if (this.state.currentStep === this.state.totalSteps) { btnNext.textContent = 'Dokončiť'; } else { btnNext.textContent = 'Pokračovať'; } const progressFill = document.querySelector('.progress-fill'); const percent = ((this.state.currentStep - 1) / (this.state.totalSteps - 1)) * 100; progressFill.style.width = `${percent}%`; } }; document.addEventListener('DOMContentLoaded', () => App.init());