implemented step 09 by Gemini
- added 3. step of wizard with smart questions
This commit is contained in:
@ -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"}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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>
|
||||||
|
|
||||||
|
|||||||
@ -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) {
|
||||||
|
|||||||
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user