diff --git a/public/css/wizard.css b/public/css/wizard.css
index 5b53ad0..2ee7cb8 100644
--- a/public/css/wizard.css
+++ b/public/css/wizard.css
@@ -216,7 +216,7 @@ label {
font-size: 0.875rem;
}
-textarea, input[type="text"], input[type="email"] {
+textarea, input[type="text"], input[type="email"], input[type="password"] {
width: 100%;
padding: 0.75rem;
border: 1px solid var(--border-color);
@@ -225,7 +225,7 @@ textarea, input[type="text"], input[type="email"] {
font-size: 0.875rem;
}
-textarea:focus, input[type="text"]:focus, input[type="email"]:focus {
+textarea:focus, input[type="text"]:focus, input[type="email"]:focus, input[type="password"]:focus {
outline: none;
border-color: var(--primary-color);
box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.1);
@@ -398,6 +398,45 @@ textarea:focus, input[type="text"]:focus, input[type="email"]:focus {
border-radius: 0.25rem;
}
+/* Checkbox Grid */
+.checkbox-grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
+ gap: 1rem;
+}
+
+/* Radio Group Tabs */
+.radio-group-tabs {
+ display: flex;
+ gap: 0.5rem;
+ background-color: #f1f5f9;
+ padding: 0.25rem;
+ border-radius: 0.5rem;
+ margin-top: 0.5rem;
+}
+
+.radio-group-tabs input[type="radio"] {
+ display: none;
+}
+
+.radio-group-tabs label {
+ flex: 1;
+ text-align: center;
+ padding: 0.5rem;
+ cursor: pointer;
+ border-radius: 0.375rem;
+ transition: all 0.2s;
+ font-size: 0.875rem;
+ margin-bottom: 0;
+}
+
+.radio-group-tabs input[type="radio"]:checked + label {
+ background-color: white;
+ box-shadow: 0 1px 3px rgba(0,0,0,0.1);
+ color: var(--primary-color);
+ font-weight: 600;
+}
+
.gallery-upload-grid {
display: flex;
flex-wrap: wrap;
diff --git a/public/index.html b/public/index.html
index bf7a856..1299a5f 100644
--- a/public/index.html
+++ b/public/index.html
@@ -214,10 +214,93 @@
-
Moduly webu
-
Vyberte si sekcie a funkcie vášho webu.
-
diff --git a/public/js/wizard.js b/public/js/wizard.js
index 321e80e..fd9c74b 100644
--- a/public/js/wizard.js
+++ b/public/js/wizard.js
@@ -102,6 +102,48 @@ const App = {
} 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 || '';
+ }
+ }
+ }
}
},
@@ -212,6 +254,18 @@ const App = {
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');
+ });
+ });
},
renderCategories() {
@@ -610,6 +664,46 @@ const App = {
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) {
@@ -641,6 +735,16 @@ const App = {
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;
diff --git a/src/Actions/ProjectActions.php b/src/Actions/ProjectActions.php
index 08a7ec3..8fc7e0d 100644
--- a/src/Actions/ProjectActions.php
+++ b/src/Actions/ProjectActions.php
@@ -171,6 +171,34 @@ class ProjectActions
$projectData['wizard_data']['visuals'] = $data['visuals'];
$projectData['wizard_data']['assets'] = $data['assets'];
break;
+
+ case 5:
+ if (!isset($data['modules'])) {
+ throw new Exception("Missing modules data.", 400);
+ }
+
+ $modules = $data['modules'];
+
+ // Secure local password if present
+ if ($modules['contact_form']['enabled'] && $modules['contact_form']['mode'] === 'local') {
+ if (!empty($modules['contact_form']['local_viewer']['password'])) {
+ $modules['contact_form']['local_viewer']['password_hash'] = password_hash(
+ $modules['contact_form']['local_viewer']['password'],
+ PASSWORD_DEFAULT
+ );
+ // Never store plain-text password
+ unset($modules['contact_form']['local_viewer']['password']);
+ } else {
+ // Keep existing hash if password not provided (updating other fields)
+ $oldHash = $projectData['wizard_data']['modules']['contact_form']['local_viewer']['password_hash'] ?? null;
+ if ($oldHash) {
+ $modules['contact_form']['local_viewer']['password_hash'] = $oldHash;
+ }
+ }
+ }
+
+ $projectData['wizard_data']['modules'] = $modules;
+ break;
// More steps will be added later
}