283 lines
7.4 KiB
JavaScript
283 lines
7.4 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: ''
|
|
}
|
|
},
|
|
|
|
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.business_category) {
|
|
const bc = this.state.project.wizard_data.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; // restore after selectCategory resets it
|
|
this.renderSubcategories(this.state.selection.category);
|
|
}
|
|
}
|
|
},
|
|
|
|
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;
|
|
});
|
|
},
|
|
|
|
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);
|
|
|
|
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);
|
|
});
|
|
},
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
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;
|
|
|
|
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());
|