implemented step 09 by Gemini

- added 3. step of wizard with smart questions
This commit is contained in:
2026-06-14 07:41:52 +02:00
parent aeeaddd3bc
commit 991ff9de00
5 changed files with 232 additions and 4 deletions

View File

@ -9,6 +9,12 @@
{"id": "cafe", "name": "Kaviareň / Bistro"}, {"id": "cafe", "name": "Kaviareň / Bistro"},
{"id": "bar", "name": "Bar / Pub"}, {"id": "bar", "name": "Bar / Pub"},
{"id": "catering", "name": "Catering"} {"id": "catering", "name": "Catering"}
],
"smart_questions": [
{"id": "delivery", "name": "Ponúkate donášku?", "type": "boolean"},
{"id": "reservation", "name": "Prijímate rezervácie vopred?", "type": "boolean"},
{"id": "parking", "name": "Máte k dispozícii parkovisko pre zákazníkov?", "type": "boolean"},
{"id": "terrace", "name": "Máte letnú terasu?", "type": "boolean"}
] ]
}, },
{ {
@ -20,6 +26,12 @@
{"id": "nails", "name": "Manikúra / Pedikúra"}, {"id": "nails", "name": "Manikúra / Pedikúra"},
{"id": "fitness", "name": "Fitness / Gym"}, {"id": "fitness", "name": "Fitness / Gym"},
{"id": "dentist", "name": "Zubár / Poliklinika"} {"id": "dentist", "name": "Zubár / Poliklinika"}
],
"smart_questions": [
{"id": "booking_online", "name": "Umožňujete online objednávky?", "type": "boolean"},
{"id": "gift_vouchers", "name": "Predávate darčekové poukážky?", "type": "boolean"},
{"id": "first_visit_discount", "name": "Ponúkate zľavu na prvú návštevu?", "type": "boolean"},
{"id": "parking", "name": "Je v blízkosti parkovanie?", "type": "boolean"}
] ]
}, },
{ {
@ -31,6 +43,12 @@
{"id": "builder", "name": "Stavebné práce"}, {"id": "builder", "name": "Stavebné práce"},
{"id": "mechanic", "name": "Autoservis"}, {"id": "mechanic", "name": "Autoservis"},
{"id": "cleaning", "name": "Upratovacie služby"} {"id": "cleaning", "name": "Upratovacie služby"}
],
"smart_questions": [
{"id": "emergency_service", "name": "Poskytujete havarijnú službu 24/7?", "type": "boolean"},
{"id": "warranty", "name": "Poskytujete na prácu predĺženú záruku?", "type": "boolean"},
{"id": "free_quote", "name": "Je obhliadka a cenová ponuka zdarma?", "type": "boolean"},
{"id": "materials_included", "name": "Zabezpečujete aj nákup materiálu?", "type": "boolean"}
] ]
}, },
{ {
@ -42,6 +60,12 @@
{"id": "consulting", "name": "Konzultant / Kouč"}, {"id": "consulting", "name": "Konzultant / Kouč"},
{"id": "marketing", "name": "Marketingová agentúra"}, {"id": "marketing", "name": "Marketingová agentúra"},
{"id": "it_services", "name": "IT služby / Software"} {"id": "it_services", "name": "IT služby / Software"}
],
"smart_questions": [
{"id": "online_consultation", "name": "Umožňujete online konzultácie?", "type": "boolean"},
{"id": "fixed_prices", "name": "Máte fixné cenníky služieb?", "type": "boolean"},
{"id": "international", "name": "Pôsobíte aj medzinárodne?", "type": "boolean"},
{"id": "languages", "name": "V akých jazykoch komunikujete?", "type": "text"}
] ]
}, },
{ {
@ -49,6 +73,10 @@
"name": "Iné", "name": "Iné",
"subcategories": [ "subcategories": [
{"id": "custom", "name": "Vlastná kategória"} {"id": "custom", "name": "Vlastná kategória"}
],
"smart_questions": [
{"id": "unique_selling_point", "name": "V čom ste jedinečný oproti konkurencii?", "type": "text"},
{"id": "target_audience", "name": "Kto sú vaši hlavní zákazníci?", "type": "text"}
] ]
} }
] ]

View File

@ -277,6 +277,42 @@ textarea:focus, input[type="text"]:focus, input[type="email"]:focus {
font-weight: 400; font-weight: 400;
} }
/* Service Items */
.service-item {
background-color: #f8fafc;
border: 1px solid var(--border-color);
border-radius: 0.5rem;
padding: 1.25rem;
margin-bottom: 1rem;
position: relative;
}
.service-item-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 1rem;
}
.btn-remove-service {
background: none;
border: none;
color: #ef4444;
cursor: pointer;
padding: 0.25rem;
font-size: 1.25rem;
line-height: 1;
}
.btn-remove-service:hover {
color: #dc2626;
}
/* Smart Questions */
.smart-question-item {
margin-bottom: 1.5rem;
}
button:disabled { button:disabled {
opacity: 0.5; opacity: 0.5;
cursor: not-allowed; cursor: not-allowed;

View File

@ -106,10 +106,27 @@
<!-- Step 3: Služby a smart otázky --> <!-- Step 3: Služby a smart otázky -->
<div class="step" data-step="3"> <div class="step" data-step="3">
<h2>Služby</h2> <h2>Služby a doplňujúce otázky</h2>
<p class="step-description">Čo presne ponúkate vašim zákazníkom?</p> <p class="step-description">Čo presne ponúkate vašim zákazníkom? AI na základe týchto dát pripraví texty.</p>
<div class="form-placeholder">
<p>Obsah pre krok 3...</p> <div class="form-section">
<h3>Vaše hlavné služby</h3>
<div id="services-list">
<!-- Service items will be added here -->
</div>
<button id="btn-add-service" class="btn-secondary" style="margin-top: 1rem;">+ Pridať službu</button>
<div class="form-group" style="margin-top: 2rem;">
<label for="pricing-note">Poznámka k cenám (voliteľné)</label>
<input type="text" id="pricing-note" placeholder="Napr. Ceny sú orientačné, Konečná cena po obhliadke...">
</div>
</div>
<div id="smart-questions-container" class="form-section">
<h3>Doplňujúce informácie</h3>
<div id="smart-questions-list">
<!-- Smart questions will be injected here -->
</div>
</div> </div>
</div> </div>

View File

@ -88,6 +88,16 @@ const App = {
document.getElementById('contact-facebook').value = wd.contact.socials?.facebook || ''; document.getElementById('contact-facebook').value = wd.contact.socials?.facebook || '';
document.getElementById('contact-instagram').value = wd.contact.socials?.instagram || ''; 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();
}
} }
}, },
@ -174,6 +184,9 @@ const App = {
el.addEventListener('change', () => this.updateUI()); el.addEventListener('change', () => this.updateUI());
} }
}); });
// Step 3 events
document.getElementById('btn-add-service').addEventListener('click', () => this.addServiceItem());
}, },
renderCategories() { renderCategories() {
@ -209,6 +222,7 @@ const App = {
this.renderCategories(); this.renderCategories();
this.renderSubcategories(categoryId); this.renderSubcategories(categoryId);
this.renderSmartQuestions(categoryId);
document.getElementById('subcategory-container').classList.remove('hidden'); document.getElementById('subcategory-container').classList.remove('hidden');
@ -241,6 +255,92 @@ const App = {
}); });
}, },
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;
}
}
}
});
},
showStep(n) { showStep(n) {
const steps = document.querySelectorAll('.step'); const steps = document.querySelectorAll('.step');
steps.forEach(step => step.classList.remove('active')); steps.forEach(step => step.classList.remove('active'));
@ -324,6 +424,45 @@ const App = {
alert('Nepodarilo sa uložiť dáta: ' + error.message); alert('Nepodarilo sa uložiť dáta: ' + error.message);
return; 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) { if (this.state.currentStep < this.state.totalSteps) {

View File

@ -156,6 +156,14 @@ class ProjectActions
$projectData['wizard_data']['contact'] = $data['contact']; $projectData['wizard_data']['contact'] = $data['contact'];
break; break;
case 3:
if (!isset($data['services']) || !isset($data['smart_answers'])) {
throw new Exception("Missing services or smart_answers data.", 400);
}
$projectData['wizard_data']['services'] = $data['services'];
$projectData['wizard_data']['smart_answers'] = $data['smart_answers'];
break;
// More steps will be added later // More steps will be added later
} }