892 lines
27 KiB
JavaScript
892 lines
27 KiB
JavaScript
/**
|
||
* 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: '',
|
||
style: null,
|
||
palette: null,
|
||
logo: null,
|
||
gallery: []
|
||
}
|
||
},
|
||
|
||
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();
|
||
|
||
// Resume polling if generating
|
||
const pollingStatuses = ['queued', 'generating', 'rendering'];
|
||
if (pollingStatuses.includes(this.state.project.status)) {
|
||
this.state.currentStep = 6;
|
||
this.startPolling();
|
||
}
|
||
}
|
||
} 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();
|
||
}
|
||
|
||
// Step 4
|
||
if (wd.visuals) {
|
||
this.state.selection.style = wd.visuals.style;
|
||
this.state.selection.palette = wd.visuals.palette;
|
||
this.updateStyleSelection();
|
||
this.updatePaletteSelection();
|
||
}
|
||
if (wd.assets) {
|
||
this.state.selection.logo = wd.assets.logo;
|
||
this.state.selection.gallery = wd.assets.gallery || [];
|
||
if (this.state.selection.logo) this.renderLogoPreview();
|
||
this.renderGalleryPreviews();
|
||
}
|
||
|
||
// Step 5
|
||
if (wd.modules) {
|
||
const m = wd.modules;
|
||
if (m.sections) {
|
||
m.sections.forEach(sec => {
|
||
const el = document.querySelector(`input[data-module="${sec}"]`);
|
||
if (el) el.checked = true;
|
||
});
|
||
}
|
||
if (m.contact_form) {
|
||
document.getElementById('form-enabled').checked = m.contact_form.enabled;
|
||
document.getElementById('form-config-container').classList.toggle('hidden', !m.contact_form.enabled);
|
||
|
||
if (m.contact_form.mode) {
|
||
document.querySelector(`input[name="form-mode"][value="${m.contact_form.mode}"]`).checked = true;
|
||
document.getElementById('config-local').classList.toggle('hidden', m.contact_form.mode !== 'local');
|
||
document.getElementById('config-smtp').classList.toggle('hidden', m.contact_form.mode !== 'smtp');
|
||
}
|
||
|
||
if (m.contact_form.smtp) {
|
||
document.getElementById('smtp-host').value = m.contact_form.smtp.host || '';
|
||
document.getElementById('smtp-port').value = m.contact_form.smtp.port || '';
|
||
document.getElementById('smtp-user').value = m.contact_form.smtp.user || '';
|
||
document.getElementById('smtp-recipient').value = m.contact_form.smtp.recipient || '';
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
|
||
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());
|
||
|
||
// Step 4 events
|
||
document.querySelectorAll('#style-grid .category-card').forEach(card => {
|
||
card.addEventListener('click', () => {
|
||
this.state.selection.style = card.getAttribute('data-style');
|
||
this.updateStyleSelection();
|
||
});
|
||
});
|
||
|
||
document.querySelectorAll('#palette-list .palette-card').forEach(card => {
|
||
card.addEventListener('click', () => {
|
||
this.state.selection.palette = card.getAttribute('data-palette');
|
||
this.updatePaletteSelection();
|
||
});
|
||
});
|
||
|
||
document.getElementById('logo-upload-box').addEventListener('click', () => document.getElementById('logo-input').click());
|
||
document.getElementById('logo-input').addEventListener('change', (e) => this.handleFileUpload(e, 'logo'));
|
||
|
||
document.getElementById('gallery-add-box').addEventListener('click', () => document.getElementById('gallery-input').click());
|
||
document.getElementById('gallery-input').addEventListener('change', (e) => this.handleFileUpload(e, 'gallery'));
|
||
|
||
// Step 5 events
|
||
document.getElementById('form-enabled').addEventListener('change', (e) => {
|
||
document.getElementById('form-config-container').classList.toggle('hidden', !e.target.checked);
|
||
});
|
||
|
||
document.querySelectorAll('input[name="form-mode"]').forEach(radio => {
|
||
radio.addEventListener('change', (e) => {
|
||
document.getElementById('config-local').classList.toggle('hidden', e.target.value !== 'local');
|
||
document.getElementById('config-smtp').classList.toggle('hidden', e.target.value !== 'smtp');
|
||
});
|
||
});
|
||
|
||
// Step 7 events
|
||
document.querySelectorAll('.btn-toggle').forEach(btn => {
|
||
btn.addEventListener('click', (e) => {
|
||
document.querySelectorAll('.btn-toggle').forEach(b => b.classList.remove('active'));
|
||
e.target.classList.add('active');
|
||
const view = e.target.getAttribute('data-view');
|
||
document.getElementById('preview-container').className = 'preview-window ' + view;
|
||
});
|
||
});
|
||
|
||
// Step 8 events
|
||
document.getElementById('btn-download-zip').addEventListener('click', () => this.downloadWebsite());
|
||
document.getElementById('btn-view-live').addEventListener('click', () => {
|
||
if (this.state.project) {
|
||
window.open(`/exports/${this.state.project.project_id}/index.html`, '_blank');
|
||
}
|
||
});
|
||
},
|
||
|
||
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 = `
|
||
<div class="category-icon">${icons[cat.id] || '📁'}</div>
|
||
<div class="category-name">${cat.name}</div>
|
||
`;
|
||
|
||
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');
|
||
}
|
||
|
||
this.updateUI();
|
||
},
|
||
|
||
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);
|
||
this.updateUI();
|
||
});
|
||
|
||
container.appendChild(chip);
|
||
});
|
||
},
|
||
|
||
addServiceItem(data = {}) {
|
||
const container = document.getElementById('services-list');
|
||
const itemDiv = document.createElement('div');
|
||
itemDiv.className = 'service-item';
|
||
|
||
itemDiv.innerHTML = `
|
||
<div class="service-item-header">
|
||
<span class="service-number">Služba</span>
|
||
<button class="btn-remove-service" title="Odstrániť">×</button>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Názov služby *</label>
|
||
<input type="text" class="service-name" placeholder="Napr. Klasická masáž" value="${data.name || ''}" required>
|
||
</div>
|
||
<div class="form-grid">
|
||
<div class="form-group">
|
||
<label>Cena od (€)</label>
|
||
<input type="text" class="service-price" placeholder="25" value="${data.price_from || ''}">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Stručný popis</label>
|
||
<input type="text" class="service-desc" placeholder="Trvanie 45 minút..." value="${data.description || ''}">
|
||
</div>
|
||
</div>
|
||
`;
|
||
|
||
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 = `
|
||
<div class="checkbox-group">
|
||
<input type="checkbox" id="sq-${q.id}" data-id="${q.id}">
|
||
<label for="sq-${q.id}">${q.name}</label>
|
||
</div>
|
||
`;
|
||
} else {
|
||
qDiv.innerHTML = `
|
||
<div class="form-group">
|
||
<label for="sq-${q.id}">${q.name}</label>
|
||
<input type="text" id="sq-${q.id}" data-id="${q.id}" placeholder="Vaša odpoveď...">
|
||
</div>
|
||
`;
|
||
}
|
||
|
||
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;
|
||
}
|
||
}
|
||
}
|
||
});
|
||
},
|
||
|
||
updateStyleSelection() {
|
||
document.querySelectorAll('#style-grid .category-card').forEach(card => {
|
||
card.classList.toggle('selected', card.getAttribute('data-style') === this.state.selection.style);
|
||
});
|
||
this.updateUI();
|
||
},
|
||
|
||
updatePaletteSelection() {
|
||
document.querySelectorAll('#palette-list .palette-card').forEach(card => {
|
||
card.classList.toggle('selected', card.getAttribute('data-palette') === this.state.selection.palette);
|
||
});
|
||
this.updateUI();
|
||
},
|
||
|
||
async handleFileUpload(event, target) {
|
||
const files = event.target.files;
|
||
if (!files.length) return;
|
||
|
||
for (const file of files) {
|
||
const formData = new FormData();
|
||
formData.append('action', 'uploadAsset');
|
||
formData.append('project_id', this.state.project.project_id);
|
||
formData.append('file', file);
|
||
formData.append('X-User-ID', this.state.userId);
|
||
|
||
try {
|
||
const response = await fetch('/ajax.php', {
|
||
method: 'POST',
|
||
body: formData
|
||
});
|
||
const result = await response.json();
|
||
if (result.success) {
|
||
if (target === 'logo') {
|
||
this.state.selection.logo = result.data.path;
|
||
this.renderLogoPreview();
|
||
} else {
|
||
if (this.state.selection.gallery.length < 5) {
|
||
this.state.selection.gallery.push(result.data.path);
|
||
this.renderGalleryPreviews();
|
||
} else {
|
||
alert('Maximálne 5 fotografií.');
|
||
}
|
||
}
|
||
} else {
|
||
alert('Upload zlyhal: ' + result.error.message);
|
||
}
|
||
} catch (error) {
|
||
console.error('Upload error:', error);
|
||
alert('Chyba pri nahrávaní.');
|
||
}
|
||
}
|
||
this.updateUI();
|
||
},
|
||
|
||
renderLogoPreview() {
|
||
const preview = document.getElementById('logo-preview');
|
||
preview.innerHTML = `<img src="/${this.state.selection.logo}" alt="Logo">
|
||
<button class="btn-remove-asset" id="btn-remove-logo">×</button>`;
|
||
preview.classList.remove('hidden');
|
||
document.querySelector('#logo-upload-box .upload-placeholder').classList.add('hidden');
|
||
|
||
document.getElementById('btn-remove-logo').addEventListener('click', (e) => {
|
||
e.stopPropagation();
|
||
this.removeAsset('logo');
|
||
});
|
||
},
|
||
|
||
renderGalleryPreviews() {
|
||
const container = document.getElementById('gallery-previews');
|
||
container.innerHTML = '';
|
||
this.state.selection.gallery.forEach((path, index) => {
|
||
const item = document.createElement('div');
|
||
item.className = 'gallery-item';
|
||
item.innerHTML = `<img src="/${path}" alt="Gallery ${index+1}">
|
||
<button class="btn-remove-asset" data-index="${index}">×</button>`;
|
||
|
||
item.querySelector('.btn-remove-asset').addEventListener('click', (e) => {
|
||
e.stopPropagation();
|
||
this.removeAsset('gallery', index);
|
||
});
|
||
|
||
container.appendChild(item);
|
||
});
|
||
},
|
||
|
||
removeAsset(target, index = null) {
|
||
if (target === 'logo') {
|
||
this.state.selection.logo = null;
|
||
document.getElementById('logo-preview').classList.add('hidden');
|
||
document.querySelector('#logo-upload-box .upload-placeholder').classList.remove('hidden');
|
||
} else {
|
||
this.state.selection.gallery.splice(index, 1);
|
||
this.renderGalleryPreviews();
|
||
}
|
||
this.updateUI();
|
||
},
|
||
|
||
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;
|
||
|
||
// Specific step logic
|
||
if (n === 7) {
|
||
this.loadPreview();
|
||
}
|
||
|
||
this.updateUI();
|
||
},
|
||
|
||
loadPreview() {
|
||
const iframe = document.getElementById('preview-iframe');
|
||
const timestamp = new Date().getTime();
|
||
iframe.src = `/exports/${this.state.project.project_id}/index.html?t=${timestamp}`;
|
||
},
|
||
|
||
async downloadWebsite() {
|
||
const btn = document.getElementById('btn-download-zip');
|
||
const originalText = btn.textContent;
|
||
|
||
btn.disabled = true;
|
||
btn.textContent = 'Pripravujem archív...';
|
||
|
||
try {
|
||
const result = await this.apiCall('exportWebsite');
|
||
if (result.success) {
|
||
// Trigger download
|
||
const link = document.createElement('a');
|
||
link.href = '/' + result.data.download_url;
|
||
link.download = result.data.filename;
|
||
document.body.appendChild(link);
|
||
link.click();
|
||
document.body.removeChild(link);
|
||
}
|
||
} catch (error) {
|
||
console.error('Export failed:', error);
|
||
alert('Chyba pri generovaní ZIP archívu.');
|
||
} finally {
|
||
btn.disabled = false;
|
||
btn.textContent = originalText;
|
||
}
|
||
},
|
||
|
||
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;
|
||
}
|
||
} else if (this.state.currentStep === 4) {
|
||
if (!this.state.selection.style || !this.state.selection.palette) {
|
||
alert('Prosím, vyberte vizuálny štýl a farebnú paletu.');
|
||
return;
|
||
}
|
||
|
||
try {
|
||
await this.apiCall('saveStep', {
|
||
step: 4,
|
||
data: {
|
||
visuals: {
|
||
style: this.state.selection.style,
|
||
palette: this.state.selection.palette
|
||
},
|
||
assets: {
|
||
logo: this.state.selection.logo,
|
||
gallery: this.state.selection.gallery
|
||
}
|
||
}
|
||
});
|
||
} catch (error) {
|
||
console.error('Save step 4 failed:', error);
|
||
alert('Nepodarilo sa uložiť dáta: ' + error.message);
|
||
return;
|
||
}
|
||
} else if (this.state.currentStep === 5) {
|
||
const sections = [];
|
||
document.querySelectorAll('input[data-module]:checked').forEach(el => {
|
||
sections.push(el.getAttribute('data-module'));
|
||
});
|
||
|
||
const formEnabled = document.getElementById('form-enabled').checked;
|
||
const formMode = document.querySelector('input[name="form-mode"]:checked').value;
|
||
|
||
const modulesData = {
|
||
pages: ['home'],
|
||
sections: sections,
|
||
contact_form: {
|
||
enabled: formEnabled,
|
||
mode: formMode,
|
||
smtp: formMode === 'smtp' ? {
|
||
host: document.getElementById('smtp-host').value,
|
||
port: document.getElementById('smtp-port').value,
|
||
user: document.getElementById('smtp-user').value,
|
||
pass: document.getElementById('smtp-pass').value,
|
||
recipient: document.getElementById('smtp-recipient').value
|
||
} : null,
|
||
local_viewer: formMode === 'local' ? {
|
||
password: document.getElementById('local-password').value
|
||
} : null
|
||
}
|
||
};
|
||
|
||
try {
|
||
await this.apiCall('saveStep', {
|
||
step: 5,
|
||
data: {
|
||
modules: modulesData
|
||
}
|
||
});
|
||
} catch (error) {
|
||
console.error('Save step 5 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);
|
||
|
||
// Trigger generation if entering step 6
|
||
if (this.state.currentStep === 6) {
|
||
this.startWebsiteGeneration();
|
||
}
|
||
}
|
||
},
|
||
|
||
async startWebsiteGeneration() {
|
||
try {
|
||
const result = await this.apiCall('generateWebsite');
|
||
if (result.success) {
|
||
|
||
this.startPolling();
|
||
}
|
||
} catch (error) {
|
||
console.error('Failed to start generation:', error);
|
||
document.getElementById('generation-status').textContent = 'Chyba: ' + error.message;
|
||
}
|
||
},
|
||
|
||
startPolling() {
|
||
if (this.pollingInterval) clearInterval(this.pollingInterval);
|
||
|
||
this.pollingInterval = setInterval(async () => {
|
||
try {
|
||
const response = await this.apiCall('getProjectStatus');
|
||
if (response.success) {
|
||
const project = response.data;
|
||
this.state.project = project;
|
||
this.updateGenerationStatus(project.status);
|
||
|
||
if (project.status === 'ready' || project.status === 'failed') {
|
||
clearInterval(this.pollingInterval);
|
||
if (project.status === 'ready') {
|
||
// Move to preview step
|
||
this.showStep(7);
|
||
} else {
|
||
document.getElementById('generation-status').textContent = 'Generovanie zlyhalo. Skúste to neskôr.';
|
||
}
|
||
}
|
||
}
|
||
} catch (error) {
|
||
console.error('Polling error:', error);
|
||
}
|
||
}, 5000);
|
||
},
|
||
|
||
updateGenerationStatus(status) {
|
||
const statusEl = document.getElementById('generation-status');
|
||
const messages = {
|
||
'queued': 'Zaradené do fronty, čakám na AI...',
|
||
'generating': 'AI práve píše texty pre váš web...',
|
||
'rendering': 'Skladáme výslednú stránku...',
|
||
'ready': 'Hotovo! Pripravujem náhľad...',
|
||
'failed': 'Nastal problém pri generovaní.'
|
||
};
|
||
statusEl.textContent = messages[status] || 'Spracovávam...';
|
||
},
|
||
|
||
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);
|
||
} else if (this.state.currentStep === 4) {
|
||
nextDisabled = !this.state.selection.style || !this.state.selection.palette;
|
||
} else if (this.state.currentStep === 5) {
|
||
const formEnabled = document.getElementById('form-enabled').checked;
|
||
if (formEnabled) {
|
||
const mode = document.querySelector('input[name="form-mode"]:checked').value;
|
||
if (mode === 'local') {
|
||
nextDisabled = !document.getElementById('local-password').value;
|
||
} else {
|
||
nextDisabled = !document.getElementById('smtp-host').value || !document.getElementById('smtp-recipient').value;
|
||
}
|
||
}
|
||
}
|
||
|
||
btnNext.disabled = nextDisabled;
|
||
|
||
// Hide footer in generating step
|
||
document.querySelector('.wizard-footer').classList.toggle('hidden', this.state.currentStep === 6);
|
||
|
||
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());
|