[FEAT] Visura auto-fill, adesione volontaria, modulo NCR/CAPA
1. Fix auto-fill visura: mapping corretto suggested_sector e employees_range, indicatori visivi verdi sui campi auto-compilati, fatturato sempre manuale 2. Adesione volontaria: colonna voluntary_compliance, checkbox in onboarding step 5 quando not_applicable, toggle in settings, reset su ri-classificazione 3. Modulo NCR/CAPA: NonConformityController con 10 endpoint API, tabelle non_conformities + capa_actions, generazione NCR dai gap assessment, predisposizione integrazione SistemiG.agile (webhook + sync) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
+211
-7
@@ -598,6 +598,91 @@
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
/* ── Auto-fill indicators ──────────────────────────────────── */
|
||||
.auto-filled .form-input,
|
||||
.auto-filled .form-select {
|
||||
border-color: #86efac;
|
||||
background: #f0fdf4;
|
||||
}
|
||||
|
||||
.auto-fill-badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: 2px 8px;
|
||||
margin-left: 8px;
|
||||
font-size: 0.65rem;
|
||||
font-weight: 600;
|
||||
color: #15803d;
|
||||
background: #dcfce7;
|
||||
border-radius: 100px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.03em;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
/* ── Voluntary Compliance ──────────────────────────────────── */
|
||||
.voluntary-section {
|
||||
display: none;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.voluntary-section.visible {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.voluntary-card {
|
||||
border: 2px solid var(--primary-light);
|
||||
border-radius: var(--border-radius-lg);
|
||||
padding: 24px;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 16px;
|
||||
background: var(--card-bg);
|
||||
transition: all var(--transition);
|
||||
}
|
||||
|
||||
.voluntary-card.checked {
|
||||
border-color: var(--primary);
|
||||
background: var(--primary-bg);
|
||||
}
|
||||
|
||||
.voluntary-card input[type="checkbox"] {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
cursor: pointer;
|
||||
accent-color: var(--primary);
|
||||
flex-shrink: 0;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.voluntary-card h4 {
|
||||
font-size: 0.9375rem;
|
||||
font-weight: 700;
|
||||
color: var(--gray-900);
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.voluntary-card p {
|
||||
font-size: 0.8125rem;
|
||||
color: var(--gray-600);
|
||||
line-height: 1.6;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.classification-result.voluntary {
|
||||
border-color: var(--primary);
|
||||
background: linear-gradient(135deg, #eff6ff, #dbeafe);
|
||||
}
|
||||
|
||||
.classification-result.voluntary .classification-result-icon {
|
||||
background: var(--primary);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.classification-result.voluntary .classification-result-label {
|
||||
color: var(--primary);
|
||||
}
|
||||
|
||||
/* ── Responsive ─────────────────────────────────────────────── */
|
||||
@media (max-width: 768px) {
|
||||
.wizard-header {
|
||||
@@ -1040,6 +1125,22 @@
|
||||
<div class="classification-result-desc" id="classification-desc"></div>
|
||||
</div>
|
||||
|
||||
<!-- Voluntary Compliance Option -->
|
||||
<div class="voluntary-section" id="voluntary-section">
|
||||
<div class="voluntary-card" id="voluntary-card">
|
||||
<input type="checkbox" id="voluntary-checkbox" onchange="onVoluntaryChange(this.checked)">
|
||||
<div>
|
||||
<h4>Adesione Volontaria alla NIS2</h4>
|
||||
<p>
|
||||
Anche se la tua organizzazione non rientra nell'ambito di applicazione obbligatorio della
|
||||
Direttiva NIS2, puoi scegliere di aderire volontariamente adottando le misure di sicurezza
|
||||
previste dalla normativa. Questo consente di migliorare la postura di cybersicurezza e di
|
||||
prepararsi a possibili future designazioni.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Summary -->
|
||||
<div class="summary-card">
|
||||
<div class="summary-card-header">Riepilogo Dati Aziendali</div>
|
||||
@@ -1142,9 +1243,22 @@
|
||||
role: '',
|
||||
phone: ''
|
||||
},
|
||||
classification: null
|
||||
classification: null,
|
||||
autoFilledFields: new Set(),
|
||||
voluntaryCompliance: false
|
||||
};
|
||||
|
||||
// ── Helper: parse employees range string to number ────────
|
||||
function parseEmployeesRange(range) {
|
||||
if (!range) return '';
|
||||
if (typeof range === 'number') return range;
|
||||
const str = String(range).trim();
|
||||
if (str.endsWith('+')) return parseInt(str);
|
||||
const parts = str.split('-');
|
||||
if (parts.length === 2) return parseInt(parts[0]);
|
||||
return parseInt(str) || '';
|
||||
}
|
||||
|
||||
// ── Step 1: Method selection ────────────────────────────────────
|
||||
function selectMethod(method) {
|
||||
wizardState.method = method;
|
||||
@@ -1308,11 +1422,24 @@
|
||||
wizardState.company.website = d.website || d.sito_web || '';
|
||||
wizardState.company.email = d.email || d.pec || '';
|
||||
wizardState.company.phone = d.phone || d.telefono || '';
|
||||
wizardState.company.sector = d.sector || '';
|
||||
wizardState.company.employee_count = d.employee_count || d.employees || '';
|
||||
wizardState.company.annual_turnover = d.annual_turnover || d.turnover || '';
|
||||
wizardState.company.sector = d.suggested_sector || d.sector || '';
|
||||
wizardState.company.employee_count = parseEmployeesRange(d.employees_range) || d.employee_count || d.employees || '';
|
||||
// Fatturato resta SEMPRE manuale — non auto-compilare dalla visura
|
||||
wizardState.company.annual_turnover = '';
|
||||
wizardState.dataSource = 'Dati precompilati dalla visura camerale';
|
||||
|
||||
// Track auto-filled fields
|
||||
wizardState.autoFilledFields.clear();
|
||||
if (wizardState.company.name) wizardState.autoFilledFields.add('company-name');
|
||||
if (wizardState.company.vat_number) wizardState.autoFilledFields.add('vat-number');
|
||||
if (wizardState.company.fiscal_code) wizardState.autoFilledFields.add('fiscal-code');
|
||||
if (wizardState.company.address) wizardState.autoFilledFields.add('address');
|
||||
if (wizardState.company.city) wizardState.autoFilledFields.add('city');
|
||||
if (wizardState.company.email) wizardState.autoFilledFields.add('company-email');
|
||||
if (wizardState.company.phone) wizardState.autoFilledFields.add('company-phone');
|
||||
if (wizardState.company.sector) wizardState.autoFilledFields.add('sector');
|
||||
if (wizardState.company.employee_count) wizardState.autoFilledFields.add('employee-count');
|
||||
|
||||
showNotification('Visura analizzata con successo!', 'success');
|
||||
|
||||
// Auto-advance to step 3
|
||||
@@ -1361,11 +1488,24 @@
|
||||
wizardState.company.website = d.website || d.sito_web || '';
|
||||
wizardState.company.email = d.email || d.pec || '';
|
||||
wizardState.company.phone = d.phone || d.telefono || '';
|
||||
wizardState.company.sector = d.sector || '';
|
||||
wizardState.company.employee_count = d.employee_count || d.employees || '';
|
||||
wizardState.company.annual_turnover = d.annual_turnover || d.turnover || '';
|
||||
wizardState.company.sector = d.suggested_sector || d.sector || '';
|
||||
wizardState.company.employee_count = parseEmployeesRange(d.employees_range) || d.employee_count || d.employees || '';
|
||||
// Fatturato resta SEMPRE manuale
|
||||
wizardState.company.annual_turnover = '';
|
||||
wizardState.dataSource = 'Dati recuperati da CertiSource';
|
||||
|
||||
// Track auto-filled fields
|
||||
wizardState.autoFilledFields.clear();
|
||||
if (wizardState.company.name) wizardState.autoFilledFields.add('company-name');
|
||||
if (wizardState.company.vat_number) wizardState.autoFilledFields.add('vat-number');
|
||||
if (wizardState.company.fiscal_code) wizardState.autoFilledFields.add('fiscal-code');
|
||||
if (wizardState.company.address) wizardState.autoFilledFields.add('address');
|
||||
if (wizardState.company.city) wizardState.autoFilledFields.add('city');
|
||||
if (wizardState.company.email) wizardState.autoFilledFields.add('company-email');
|
||||
if (wizardState.company.phone) wizardState.autoFilledFields.add('company-phone');
|
||||
if (wizardState.company.sector) wizardState.autoFilledFields.add('sector');
|
||||
if (wizardState.company.employee_count) wizardState.autoFilledFields.add('employee-count');
|
||||
|
||||
showNotification('Dati aziendali recuperati con successo!', 'success');
|
||||
|
||||
// Auto-advance to step 3
|
||||
@@ -1413,6 +1553,27 @@
|
||||
} else {
|
||||
banner.classList.remove('visible');
|
||||
}
|
||||
|
||||
// Apply auto-fill visual indicators
|
||||
const autoFields = wizardState.autoFilledFields;
|
||||
document.querySelectorAll('#step-3 .form-input, #step-3 .form-select').forEach(el => {
|
||||
const wrapper = el.closest('.form-group');
|
||||
if (!wrapper) return;
|
||||
|
||||
// Remove previous indicators
|
||||
wrapper.classList.remove('auto-filled');
|
||||
const existing = wrapper.querySelector('.auto-fill-badge');
|
||||
if (existing) existing.remove();
|
||||
|
||||
if (autoFields.has(el.id)) {
|
||||
wrapper.classList.add('auto-filled');
|
||||
const badge = document.createElement('span');
|
||||
badge.className = 'auto-fill-badge';
|
||||
badge.textContent = 'da visura';
|
||||
const label = wrapper.querySelector('.form-label');
|
||||
if (label) label.appendChild(badge);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function submitStep3() {
|
||||
@@ -1553,6 +1714,21 @@
|
||||
const result = classifyLocally(sector, employees, turnover);
|
||||
wizardState.classification = result;
|
||||
|
||||
// Reset voluntary state when re-entering step 5
|
||||
wizardState.voluntaryCompliance = false;
|
||||
const voluntaryCheckbox = document.getElementById('voluntary-checkbox');
|
||||
if (voluntaryCheckbox) voluntaryCheckbox.checked = false;
|
||||
const voluntaryCard = document.getElementById('voluntary-card');
|
||||
if (voluntaryCard) voluntaryCard.classList.remove('checked');
|
||||
|
||||
// Show/hide voluntary compliance section
|
||||
const voluntarySection = document.getElementById('voluntary-section');
|
||||
if (result.classification === 'not_applicable') {
|
||||
voluntarySection.classList.add('visible');
|
||||
} else {
|
||||
voluntarySection.classList.remove('visible');
|
||||
}
|
||||
|
||||
// Update classification UI
|
||||
const container = document.getElementById('classification-result');
|
||||
const labelEl = document.getElementById('classification-label');
|
||||
@@ -1589,6 +1765,32 @@
|
||||
document.getElementById('sum-turnover').textContent = turnover ? '\u20AC ' + turnover.toLocaleString('it-IT') : '-';
|
||||
}
|
||||
|
||||
// ── Voluntary Compliance Toggle ───────────────────────────────
|
||||
function onVoluntaryChange(checked) {
|
||||
wizardState.voluntaryCompliance = checked;
|
||||
|
||||
const card = document.getElementById('voluntary-card');
|
||||
const container = document.getElementById('classification-result');
|
||||
const labelEl = document.getElementById('classification-label');
|
||||
const sumEntityType = document.getElementById('sum-entity-type');
|
||||
|
||||
card.classList.toggle('checked', checked);
|
||||
|
||||
if (checked) {
|
||||
container.className = 'classification-result voluntary';
|
||||
container.querySelector('.classification-result-icon').innerHTML = '<svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 1L3 5v6c0 5.55 3.84 10.74 9 12 5.16-1.26 9-6.45 9-12V5l-9-4zm0 2.18l7 3.12v4.7c0 4.83-3.23 9.36-7 10.57-3.77-1.21-7-5.74-7-10.57V6.3l7-3.12z"/><path d="M10 12.5l-2-2-1.41 1.41L10 15.32l5.41-5.41L14 8.5l-4 4z"/></svg>';
|
||||
labelEl.textContent = 'Adesione Volontaria';
|
||||
document.getElementById('classification-desc').textContent = 'La tua organizzazione aderisce volontariamente alla Direttiva NIS2, adottando le misure di sicurezza previste dalla normativa per migliorare la propria postura di cybersicurezza.';
|
||||
sumEntityType.textContent = 'Adesione Volontaria';
|
||||
} else {
|
||||
container.className = 'classification-result not-applicable';
|
||||
container.querySelector('.classification-result-icon').innerHTML = '<svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z"/></svg>';
|
||||
labelEl.textContent = wizardState.classification.label;
|
||||
document.getElementById('classification-desc').textContent = wizardState.classification.description;
|
||||
sumEntityType.textContent = wizardState.classification.label;
|
||||
}
|
||||
}
|
||||
|
||||
// ── Complete Onboarding ─────────────────────────────────────────
|
||||
async function completeOnboarding() {
|
||||
const btn = document.getElementById('complete-btn');
|
||||
@@ -1612,6 +1814,8 @@
|
||||
sector: c.sector,
|
||||
employee_count: parseInt(c.employee_count) || 0,
|
||||
annual_turnover_eur: parseInt(c.annual_turnover) || 0,
|
||||
// Voluntary compliance
|
||||
voluntary_compliance: wizardState.voluntaryCompliance ? 1 : 0,
|
||||
// Profile data
|
||||
full_name: p.full_name,
|
||||
phone: p.phone,
|
||||
|
||||
Reference in New Issue
Block a user