[UI] SWAP V2: Bootstrap Italia ora UFFICIALE su 27 pagine app (kill della vecchia UI)
Promosse le pagine -bi a nomi ufficiali (contenuto BI), link -bi->plain, titoli '(BI)' rimossi.
La vecchia UI delle pagine app e sostituita. Backup: git (commit 36967f9) + /tmp/nis2-v1-backup.
Promosse (27): auth (login/register/onboarding/forgot/reset) + app (dashboard/assessment/
risks/incidents/policies/supply-chain/training/assets/reports/settings/isms/acn-gap/normative/
whistleblowing/kb/cross-analysis/service-continuity/guida/companies) + admin (index/orgs/users).
common-bi.js: sidebar BI ora linka le pagine ufficiali.
ESCLUSA: index.html (landing marketing 1298 righe) -> conversione dedicata a parte (la -bi
era 557 righe, rischio perdita contenuti). Pagine marketing/demo (presentation/simulate/
workflow/architecture/index-en) restano vecchio stile (fuori scope app autenticata).
Verifica produzione: 27/27 servite 200 con BI, 0 link -bi residui, 0 '(BI)' nei titoli,
auth intatta (401 su pwd errata), common-bi.js node --check OK.
Rollback: git revert HEAD (oppure ripristino da /tmp/nis2-v1-backup).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
36967f9452
commit
1c64211685
+188
-339
@@ -4,156 +4,74 @@
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Registrazione - NIS2 Agile</title>
|
||||
<link rel="stylesheet" href="css/style.css">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
|
||||
<!-- Bootstrap Italia v2.18.1 — self-hostato da /vendor (MAI CDN). Variante "-bi" della register.html. -->
|
||||
<link rel="stylesheet" href="vendor/bootstrap-italia/dist/css/bootstrap-italia.min.css">
|
||||
<style>
|
||||
/* Step indicator */
|
||||
.step-indicator {
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
gap: 0; margin-bottom: 1.75rem;
|
||||
}
|
||||
.step-item {
|
||||
display: flex; flex-direction: column; align-items: center;
|
||||
position: relative;
|
||||
}
|
||||
.step-circle {
|
||||
width: 32px; height: 32px; border-radius: 50%;
|
||||
border: 2px solid var(--border-color, #e5e7eb);
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
font-size: .8rem; font-weight: 700;
|
||||
color: var(--text-secondary, #6b7280);
|
||||
background: var(--bg-card, #fff);
|
||||
transition: all .25s;
|
||||
}
|
||||
.step-item.active .step-circle {
|
||||
border-color: var(--color-primary, #2563eb);
|
||||
color: var(--color-primary, #2563eb);
|
||||
background: #eff6ff;
|
||||
}
|
||||
.step-item.done .step-circle {
|
||||
border-color: var(--color-success, #10b981);
|
||||
background: var(--color-success, #10b981);
|
||||
color: #fff;
|
||||
}
|
||||
.step-label {
|
||||
font-size: .68rem; color: var(--text-secondary, #6b7280);
|
||||
margin-top: 4px; white-space: nowrap;
|
||||
}
|
||||
.step-item.active .step-label { color: var(--color-primary, #2563eb); font-weight: 600; }
|
||||
.step-connector {
|
||||
width: 48px; height: 2px;
|
||||
background: var(--border-color, #e5e7eb);
|
||||
margin-bottom: 18px; transition: background .25s;
|
||||
}
|
||||
.step-connector.done { background: var(--color-success, #10b981); }
|
||||
body { min-height: 100vh; display: flex; align-items: center; background: #f5f6f7; padding: 24px 0; }
|
||||
.auth-wrap { width: 100%; max-width: 560px; margin: 0 auto; padding: 24px; }
|
||||
.auth-brand { text-align: center; margin-bottom: 20px; }
|
||||
.auth-brand .brand-name { font-weight: 700; font-size: 1.5rem; color: #06c; }
|
||||
.auth-brand .brand-name span { color: #17324d; }
|
||||
.auth-brand .brand-sub { color: #5a6772; font-size: .9rem; margin-top: 4px; }
|
||||
|
||||
/* Role cards */
|
||||
.role-grid {
|
||||
display: grid; grid-template-columns: 1fr 1fr;
|
||||
gap: .75rem; margin-bottom: 1.25rem;
|
||||
}
|
||||
.role-card {
|
||||
border: 2px solid var(--border-color, #e5e7eb);
|
||||
border-radius: 12px; padding: 1rem .875rem;
|
||||
cursor: pointer; transition: all .2s;
|
||||
background: var(--bg-card, #fff);
|
||||
text-align: left;
|
||||
}
|
||||
.role-card:hover { border-color: #06B6D4; background: #ecfeff; }
|
||||
.role-card.selected {
|
||||
border-color: #06B6D4; background: #ecfeff;
|
||||
box-shadow: 0 0 0 3px rgba(6,182,212,.15);
|
||||
}
|
||||
.role-card-icon {
|
||||
width: 36px; height: 36px; border-radius: 8px;
|
||||
background: rgba(6,182,212,.12); color: #06B6D4;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
font-size: 1rem; margin-bottom: .6rem;
|
||||
}
|
||||
.role-card.selected .role-card-icon { background: rgba(6,182,212,.2); }
|
||||
.role-card-title { font-weight: 700; font-size: .88rem; color: var(--text-primary, #111); margin-bottom: .2rem; }
|
||||
.role-card-desc { font-size: .72rem; color: var(--text-secondary, #6b7280); line-height: 1.45; }
|
||||
/* Step indicator (BI Blu Italia) */
|
||||
.step-indicator { display: flex; align-items: center; justify-content: center; margin-bottom: 1.5rem; }
|
||||
.step-item { display: flex; flex-direction: column; align-items: center; }
|
||||
.step-circle { width: 32px; height: 32px; border-radius: 50%; border: 2px solid #d4d8db;
|
||||
display: flex; align-items: center; justify-content: center; font-size: .8rem; font-weight: 700;
|
||||
color: #5a6772; background: #fff; transition: all .25s; }
|
||||
.step-item.active .step-circle { border-color: #06c; color: #06c; background: #e6f0ff; }
|
||||
.step-item.done .step-circle { border-color: #008758; background: #008758; color: #fff; }
|
||||
.step-label { font-size: .68rem; color: #5a6772; margin-top: 4px; white-space: nowrap; }
|
||||
.step-item.active .step-label { color: #06c; font-weight: 600; }
|
||||
.step-connector { width: 48px; height: 2px; background: #d4d8db; margin-bottom: 18px; transition: background .25s; }
|
||||
.step-connector.done { background: #008758; }
|
||||
|
||||
/* Invite code section */
|
||||
.invite-section {
|
||||
border: 1px dashed var(--border-color, #e5e7eb);
|
||||
border-radius: 10px; padding: .875rem 1rem; margin-bottom: 1rem;
|
||||
}
|
||||
.invite-section summary {
|
||||
cursor: pointer; font-size: .82rem; font-weight: 600;
|
||||
color: var(--text-secondary, #6b7280); list-style: none;
|
||||
display: flex; align-items: center; gap: .5rem;
|
||||
}
|
||||
.invite-section summary::-webkit-details-marker { display: none; }
|
||||
.invite-section[open] summary { color: var(--color-primary, #2563eb); }
|
||||
.invite-section .form-group { margin-top: .75rem; margin-bottom: 0; }
|
||||
.invite-badge {
|
||||
display: inline-flex; align-items: center; gap: .35rem;
|
||||
font-size: .75rem; padding: .25rem .6rem; border-radius: 20px;
|
||||
background: #dcfce7; color: #15803d; font-weight: 600;
|
||||
margin-top: .5rem;
|
||||
}
|
||||
/* Role cards (BI palette) */
|
||||
.role-grid { display: grid; grid-template-columns: 1fr 1fr; gap: .75rem; margin-bottom: 1.25rem; }
|
||||
.role-card { border: 2px solid #d4d8db; border-radius: 8px; padding: 1rem .875rem; cursor: pointer;
|
||||
transition: all .2s; background: #fff; text-align: left; }
|
||||
.role-card:hover { border-color: #06c; background: #e6f0ff; }
|
||||
.role-card:focus-visible { outline: 2px solid #06c; outline-offset: 2px; }
|
||||
.role-card.selected { border-color: #06c; background: #e6f0ff; box-shadow: 0 0 0 3px rgba(0,102,204,.15); }
|
||||
.role-card-icon { width: 36px; height: 36px; border-radius: 8px; background: rgba(0,102,204,.12); color: #06c;
|
||||
display: flex; align-items: center; justify-content: center; margin-bottom: .6rem; }
|
||||
.role-card-title { font-weight: 700; font-size: .88rem; color: #17324d; margin-bottom: .2rem; }
|
||||
.role-card-desc { font-size: .72rem; color: #5a6772; line-height: 1.45; }
|
||||
|
||||
.invite-section { border: 1px dashed #d4d8db; border-radius: 8px; padding: .875rem 1rem; margin-bottom: 1rem; }
|
||||
.invite-section summary { cursor: pointer; font-size: .82rem; font-weight: 600; color: #5a6772; }
|
||||
.invite-section[open] summary { color: #06c; }
|
||||
|
||||
/* Password eye toggle */
|
||||
.pw-wrap { position: relative; }
|
||||
.pw-wrap .form-input { padding-right: 42px; }
|
||||
.pw-toggle {
|
||||
position: absolute; right: 12px; top: 50%; transform: translateY(-50%);
|
||||
background: none; border: none; cursor: pointer;
|
||||
color: #9CA3AF; font-size: 15px; padding: 0; transition: color .2s;
|
||||
}
|
||||
.pw-toggle:hover { color: #06B6D4; }
|
||||
.pw-wrap .form-control { padding-right: 44px; }
|
||||
.pw-toggle { position: absolute; right: 8px; top: 8px; background: none; border: none; color: #5a6772;
|
||||
cursor: pointer; padding: 6px; }
|
||||
|
||||
/* Lookup status */
|
||||
.lookup-status {
|
||||
font-size: .75rem; margin-top: .35rem; min-height: 1.1rem;
|
||||
display: flex; align-items: center; gap: .35rem;
|
||||
}
|
||||
.lookup-status.ok { color: #15803d; }
|
||||
.lookup-status.err { color: var(--color-danger, #ef4444); }
|
||||
.lookup-status.loading { color: #6b7280; }
|
||||
.lookup-status { font-size: .75rem; margin-top: .35rem; min-height: 1.1rem; display: flex; align-items: center; gap: .35rem; }
|
||||
.lookup-status.ok { color: #008758; }
|
||||
.lookup-status.err { color: #d9364f; }
|
||||
.lookup-status.loading { color: #5a6772; }
|
||||
|
||||
/* Success step */
|
||||
.success-body { text-align: center; padding: .5rem 0 1.5rem; }
|
||||
.success-icon {
|
||||
width: 64px; height: 64px; border-radius: 50%;
|
||||
background: linear-gradient(135deg, #06B6D4, #0891b2);
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
margin: 0 auto 1.25rem; color: #fff; font-size: 1.75rem;
|
||||
}
|
||||
.success-title { font-size: 1.3rem; font-weight: 800; color: var(--text-primary, #111); margin-bottom: .5rem; }
|
||||
.success-desc { font-size: .9rem; color: var(--text-secondary, #6b7280); line-height: 1.6; margin-bottom: 1.5rem; }
|
||||
|
||||
/* Auth terms */
|
||||
.auth-terms {
|
||||
margin-top: 14px; padding-top: 14px;
|
||||
border-top: 1px solid var(--border-color, #e5e7eb);
|
||||
text-align: center; font-size: .72rem; color: #9CA3AF; line-height: 1.8;
|
||||
}
|
||||
.auth-terms a { color: #6B7280; text-decoration: underline; }
|
||||
.success-body { text-align: center; padding: .5rem 0 1rem; }
|
||||
.success-icon { width: 64px; height: 64px; border-radius: 50%; background: #008758;
|
||||
display: flex; align-items: center; justify-content: center; margin: 0 auto 1.25rem; color: #fff; }
|
||||
|
||||
/* Steps display */
|
||||
#step-0, #step-1, #step-2 { display: none; }
|
||||
#step-0 { display: block; }
|
||||
.ico { width: 1em; height: 1em; fill: currentColor; vertical-align: -.125em; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="auth-page">
|
||||
<div class="auth-card">
|
||||
<div class="auth-header">
|
||||
<div class="auth-logo">
|
||||
<div class="auth-logo-icon">
|
||||
<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>
|
||||
</div>
|
||||
<span class="auth-logo-text">NIS2 <span>Agile</span></span>
|
||||
</div>
|
||||
<p class="auth-subtitle" id="auth-subtitle">Crea il tuo account</p>
|
||||
</div>
|
||||
<main class="auth-wrap">
|
||||
<div class="auth-brand">
|
||||
<h1 class="brand-name">NIS2 <span>Agile</span></h1>
|
||||
<div class="brand-sub" id="auth-subtitle">Crea il tuo account</div>
|
||||
</div>
|
||||
|
||||
<div class="auth-body">
|
||||
<div class="card card-bg has-bkg-grey shadow">
|
||||
<div class="card-body">
|
||||
<!-- Step indicator -->
|
||||
<div class="step-indicator" id="step-indicator">
|
||||
<div class="step-item active" id="si-0">
|
||||
@@ -172,136 +90,130 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="auth-error" id="register-error"></div>
|
||||
<div class="alert alert-danger d-none" id="register-error" role="alert"></div>
|
||||
|
||||
<!-- STEP 0: Ruolo + Codice Invito -->
|
||||
<div id="step-0">
|
||||
<div class="role-grid">
|
||||
<div class="role-card" id="card-compliance_manager" onclick="selectRole('compliance_manager')">
|
||||
<div class="role-card-icon"><i class="fas fa-shield-alt"></i></div>
|
||||
<div class="role-grid" role="radiogroup" aria-label="Seleziona il tuo ruolo">
|
||||
<div class="role-card" id="card-compliance_manager" role="radio" aria-checked="false" tabindex="0"
|
||||
onclick="selectRole('compliance_manager')" onkeydown="cardKey(event,'compliance_manager')">
|
||||
<div class="role-card-icon"><svg class="ico" aria-hidden="true"><use href="vendor/bootstrap-italia/dist/svg/sprites.svg#it-locked"></use></svg></div>
|
||||
<div class="role-card-title">CISO / Compliance Manager</div>
|
||||
<div class="role-card-desc">Responsabile sicurezza e conformità NIS2 dell'organizzazione</div>
|
||||
</div>
|
||||
<div class="role-card" id="card-org_admin" onclick="selectRole('org_admin')">
|
||||
<div class="role-card-icon"><i class="fas fa-building"></i></div>
|
||||
<div class="role-card" id="card-org_admin" role="radio" aria-checked="false" tabindex="0"
|
||||
onclick="selectRole('org_admin')" onkeydown="cardKey(event,'org_admin')">
|
||||
<div class="role-card-icon"><svg class="ico" aria-hidden="true"><use href="vendor/bootstrap-italia/dist/svg/sprites.svg#it-user"></use></svg></div>
|
||||
<div class="role-card-title">Legale Rappresentante / Admin</div>
|
||||
<div class="role-card-desc">Amministratore e legale rappresentante dell'organizzazione</div>
|
||||
</div>
|
||||
<div class="role-card" id="card-consultant" onclick="selectRole('consultant')">
|
||||
<div class="role-card-icon"><i class="fas fa-user-tie"></i></div>
|
||||
<div class="role-card" id="card-consultant" role="radio" aria-checked="false" tabindex="0"
|
||||
onclick="selectRole('consultant')" onkeydown="cardKey(event,'consultant')">
|
||||
<div class="role-card-icon"><svg class="ico" aria-hidden="true"><use href="vendor/bootstrap-italia/dist/svg/sprites.svg#it-user"></use></svg></div>
|
||||
<div class="role-card-title">Consulente Cybersecurity</div>
|
||||
<div class="role-card-desc">Gestisco la compliance NIS2 per più aziende clienti</div>
|
||||
</div>
|
||||
<div class="role-card" id="card-auditor" onclick="selectRole('auditor')">
|
||||
<div class="role-card-icon"><i class="fas fa-search"></i></div>
|
||||
<div class="role-card" id="card-auditor" role="radio" aria-checked="false" tabindex="0"
|
||||
onclick="selectRole('auditor')" onkeydown="cardKey(event,'auditor')">
|
||||
<div class="role-card-icon"><svg class="ico" aria-hidden="true"><use href="vendor/bootstrap-italia/dist/svg/sprites.svg#it-search"></use></svg></div>
|
||||
<div class="role-card-title">Auditor / Revisore</div>
|
||||
<div class="role-card-desc">Verifico e valuto l'implementazione dei controlli di sicurezza</div>
|
||||
</div>
|
||||
<div class="role-card" id="card-board_member" onclick="selectRole('board_member')" style="grid-column: span 2;">
|
||||
<div class="role-card-icon"><i class="fas fa-chess-king"></i></div>
|
||||
<div class="role-card" id="card-board_member" role="radio" aria-checked="false" tabindex="0"
|
||||
onclick="selectRole('board_member')" onkeydown="cardKey(event,'board_member')" style="grid-column: span 2;">
|
||||
<div class="role-card-icon"><svg class="ico" aria-hidden="true"><use href="vendor/bootstrap-italia/dist/svg/sprites.svg#it-key"></use></svg></div>
|
||||
<div class="role-card-title">Board Member / DPO</div>
|
||||
<div class="role-card-desc">Membro del consiglio o Responsabile della Protezione dei Dati con visibilità strategica</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<details class="invite-section" id="invite-details">
|
||||
<summary><i class="fas fa-ticket-alt"></i> Ho un codice di invito B2B</summary>
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="invite-code">Codice Invito</label>
|
||||
<input type="text" id="invite-code" class="form-input"
|
||||
<summary>Ho un codice di invito B2B</summary>
|
||||
<div class="form-group mt-2">
|
||||
<label for="invite-code">Codice Invito</label>
|
||||
<input type="text" id="invite-code" class="form-control"
|
||||
placeholder="es. inv_a1b2c3d4e5f6..." autocomplete="off"
|
||||
oninput="validateInvite(this.value)">
|
||||
<div class="lookup-status" id="invite-status"></div>
|
||||
<div class="lookup-status" id="invite-status" aria-live="polite"></div>
|
||||
</div>
|
||||
</details>
|
||||
|
||||
<button class="btn btn-primary btn-lg w-full" id="btn-next-0" onclick="goToStep1()" disabled>
|
||||
Continua <i class="fas fa-arrow-right" style="margin-left:.4rem;"></i>
|
||||
<button class="btn btn-primary w-100 mt-2" id="btn-next-0" onclick="goToStep1()" disabled>
|
||||
Continua
|
||||
<svg class="ico ms-1" aria-hidden="true"><use href="vendor/bootstrap-italia/dist/svg/sprites.svg#it-arrow-right"></use></svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- STEP 1: Dati account -->
|
||||
<div id="step-1">
|
||||
<!-- Banner accesso B2B ridotto (visibile solo con invito + recipient data) -->
|
||||
<div id="invite-welcome" style="display:none; background:linear-gradient(135deg,#ecfeff,#cffafe); border:1.5px solid #06B6D4; border-radius:12px; padding:.875rem 1rem; margin-bottom:1rem;">
|
||||
<div style="display:flex; align-items:center; gap:.75rem; margin-bottom:.4rem;">
|
||||
<div style="width:34px;height:34px;border-radius:8px;background:#06B6D4;color:#fff;display:flex;align-items:center;justify-content:center;flex-shrink:0;">
|
||||
<i class="fas fa-ticket-alt" style="font-size:.85rem;"></i>
|
||||
</div>
|
||||
<div>
|
||||
<div id="invite-welcome-name" style="font-weight:700;font-size:.92rem;color:#0e7490;"></div>
|
||||
<div id="invite-welcome-plan" style="font-size:.73rem;color:#0891b2;margin-top:1px;"></div>
|
||||
</div>
|
||||
</div>
|
||||
<p style="margin:0;font-size:.8rem;color:#0e7490;line-height:1.45;">I tuoi dati sono stati pre-compilati dall'invito. <strong>Scegli solo la password</strong> per accedere alla piattaforma.</p>
|
||||
<div id="invite-welcome" class="alert alert-info" style="display:none;">
|
||||
<div id="invite-welcome-name" style="font-weight:700;"></div>
|
||||
<div id="invite-welcome-plan" style="font-size:.8rem;"></div>
|
||||
<p class="mb-0 mt-1" style="font-size:.85rem;">I tuoi dati sono stati pre-compilati dall'invito. <strong>Scegli solo la password</strong> per accedere alla piattaforma.</p>
|
||||
</div>
|
||||
|
||||
<form id="register-form" novalidate>
|
||||
<div style="display:flex; gap:.75rem;">
|
||||
<div class="form-group" style="flex:1;">
|
||||
<label class="form-label" for="firstname">Nome <span class="required">*</span></label>
|
||||
<input type="text" id="firstname" name="firstname" class="form-input"
|
||||
placeholder="Mario" autocomplete="given-name" required>
|
||||
<div class="row">
|
||||
<div class="form-group col">
|
||||
<label for="firstname" class="active">Nome <span aria-hidden="true">*</span></label>
|
||||
<input type="text" id="firstname" name="firstname" class="form-control"
|
||||
autocomplete="given-name" required>
|
||||
</div>
|
||||
<div class="form-group" style="flex:1;">
|
||||
<label class="form-label" for="lastname">Cognome <span class="required">*</span></label>
|
||||
<input type="text" id="lastname" name="lastname" class="form-input"
|
||||
placeholder="Rossi" autocomplete="family-name" required>
|
||||
<div class="form-group col">
|
||||
<label for="lastname" class="active">Cognome <span aria-hidden="true">*</span></label>
|
||||
<input type="text" id="lastname" name="lastname" class="form-control"
|
||||
autocomplete="family-name" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="email">Indirizzo Email <span class="required">*</span></label>
|
||||
<input type="email" id="email" name="email" class="form-input"
|
||||
placeholder="nome@azienda.it" autocomplete="email" required>
|
||||
<label for="email" class="active">Indirizzo Email <span aria-hidden="true">*</span></label>
|
||||
<input type="email" id="email" name="email" class="form-control"
|
||||
autocomplete="email" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group" id="piva-group">
|
||||
<label class="form-label" for="piva">Partita IVA Azienda <span class="required">*</span></label>
|
||||
<input type="text" id="piva" name="piva" class="form-input"
|
||||
placeholder="12345678901" maxlength="11"
|
||||
<label for="piva" class="active">Partita IVA Azienda <span aria-hidden="true">*</span></label>
|
||||
<input type="text" id="piva" name="piva" class="form-control"
|
||||
placeholder="12345678901" maxlength="11" inputmode="numeric"
|
||||
oninput="lookupPiva(this.value)">
|
||||
<div class="lookup-status" id="piva-status"></div>
|
||||
<div class="lookup-status" id="piva-status" aria-live="polite"></div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="password">Password <span class="required">*</span></label>
|
||||
<label for="password" class="active">Password <span aria-hidden="true">*</span></label>
|
||||
<div class="pw-wrap">
|
||||
<input type="password" id="password" name="password" class="form-input"
|
||||
placeholder="Minimo 8 caratteri" autocomplete="new-password" required>
|
||||
<input type="password" id="password" name="password" class="form-control"
|
||||
placeholder="Minimo 8 caratteri" autocomplete="new-password" required
|
||||
aria-describedby="ps-text">
|
||||
<button type="button" class="pw-toggle" tabindex="-1"
|
||||
onclick="togglePw('password', this)" aria-label="Mostra/nascondi password">
|
||||
<i class="fas fa-eye"></i>
|
||||
onclick="togglePw('password', this)" aria-label="Mostra o nascondi la password">
|
||||
<svg class="icon icon-sm" aria-hidden="true"><use href="vendor/bootstrap-italia/dist/svg/sprites.svg#it-password-visible"></use></svg>
|
||||
</button>
|
||||
</div>
|
||||
<div class="password-strength" id="password-strength">
|
||||
<div class="password-strength-bar">
|
||||
<div class="password-strength-segment" id="ps-1"></div>
|
||||
<div class="password-strength-segment" id="ps-2"></div>
|
||||
<div class="password-strength-segment" id="ps-3"></div>
|
||||
<div class="password-strength-segment" id="ps-4"></div>
|
||||
</div>
|
||||
<div class="password-strength-text" id="ps-text"></div>
|
||||
<div class="progress mt-2" style="height:6px;">
|
||||
<div class="progress-bar" id="ps-bar" role="progressbar" style="width:0%;" aria-hidden="true"></div>
|
||||
</div>
|
||||
<div class="form-text" id="ps-text" aria-live="polite"></div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="password-confirm">Conferma Password <span class="required">*</span></label>
|
||||
<label for="password-confirm" class="active">Conferma Password <span aria-hidden="true">*</span></label>
|
||||
<div class="pw-wrap">
|
||||
<input type="password" id="password-confirm" name="password-confirm" class="form-input"
|
||||
<input type="password" id="password-confirm" name="password-confirm" class="form-control"
|
||||
placeholder="Ripeti la password" autocomplete="new-password" required>
|
||||
<button type="button" class="pw-toggle" tabindex="-1"
|
||||
onclick="togglePw('password-confirm', this)" aria-label="Mostra/nascondi password">
|
||||
<i class="fas fa-eye"></i>
|
||||
onclick="togglePw('password-confirm', this)" aria-label="Mostra o nascondi la password">
|
||||
<svg class="icon icon-sm" aria-hidden="true"><use href="vendor/bootstrap-italia/dist/svg/sprites.svg#it-password-visible"></use></svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="display:flex; gap:.75rem;">
|
||||
<button type="button" class="btn btn-secondary" onclick="goToStep0()" style="flex:0 0 auto;">
|
||||
<i class="fas fa-arrow-left"></i>
|
||||
<div class="d-flex" style="gap:.75rem;">
|
||||
<button type="button" class="btn btn-outline-primary" onclick="goToStep0()" aria-label="Torna allo step precedente">
|
||||
<svg class="ico" aria-hidden="true"><use href="vendor/bootstrap-italia/dist/svg/sprites.svg#it-arrow-left"></use></svg>
|
||||
</button>
|
||||
<button type="submit" class="btn btn-primary btn-lg" id="register-btn" style="flex:1;">
|
||||
<button type="submit" class="btn btn-primary flex-grow-1" id="register-btn">
|
||||
Crea Account
|
||||
</button>
|
||||
</div>
|
||||
@@ -311,79 +223,68 @@
|
||||
<!-- STEP 2: Successo -->
|
||||
<div id="step-2">
|
||||
<div class="success-body">
|
||||
<div class="success-icon"><i class="fas fa-check"></i></div>
|
||||
<div class="success-title" id="success-title">Account creato!</div>
|
||||
<div class="success-desc" id="success-desc">
|
||||
Il tuo account NIS2 Agile è pronto. Stai per essere reindirizzato...
|
||||
<div class="success-icon">
|
||||
<svg class="icon icon-white" aria-hidden="true"><use href="vendor/bootstrap-italia/dist/svg/sprites.svg#it-check"></use></svg>
|
||||
</div>
|
||||
<button class="btn btn-primary btn-lg w-full" id="success-btn" onclick="goToDashboard()">
|
||||
Entra nella piattaforma <i class="fas fa-arrow-right" style="margin-left:.4rem;"></i>
|
||||
<h2 class="h4" id="success-title">Account creato!</h2>
|
||||
<p id="success-desc" class="text-muted">
|
||||
Il tuo account NIS2 Agile è pronto. Stai per essere reindirizzato...
|
||||
</p>
|
||||
<button class="btn btn-primary w-100" id="success-btn" onclick="goToDashboard()">
|
||||
Entra nella piattaforma
|
||||
<svg class="ico ms-1" aria-hidden="true"><use href="vendor/bootstrap-italia/dist/svg/sprites.svg#it-arrow-right"></use></svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="auth-footer">
|
||||
<p>Hai già un account? <a href="login.html">Accedi</a></p>
|
||||
<div class="auth-terms">
|
||||
Registrandoti accetti i nostri
|
||||
<a href="https://agentai.agile.software/terms" target="_blank">Termini di Servizio</a>
|
||||
e la <a href="https://agentai.agile.software/privacy" target="_blank">Privacy Policy</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="text-center mt-3 mb-0">
|
||||
Hai già un account? <a href="login.html">Accedi</a>
|
||||
</p>
|
||||
<p class="text-center small text-muted">
|
||||
Registrandoti accetti i
|
||||
<a href="https://agentai.agile.software/terms" target="_blank" rel="noopener">Termini di Servizio</a>
|
||||
e la <a href="https://agentai.agile.software/privacy" target="_blank" rel="noopener">Privacy Policy</a>.
|
||||
</p>
|
||||
</main>
|
||||
|
||||
<script src="vendor/bootstrap-italia/dist/js/bootstrap-italia.bundle.min.js"></script>
|
||||
<script>
|
||||
if (window.bootstrap && bootstrap.loadFonts) { bootstrap.loadFonts('vendor/bootstrap-italia/dist/fonts'); }
|
||||
</script>
|
||||
|
||||
<!-- Stessa logica della register.html: ZERO modifiche backend -->
|
||||
<script src="js/api.js"></script>
|
||||
<script src="js/common.js"></script>
|
||||
<script>
|
||||
if (api.isAuthenticated()) {
|
||||
window.location.href = 'dashboard.html';
|
||||
}
|
||||
if (api.isAuthenticated()) { window.location.href = 'dashboard.html'; }
|
||||
|
||||
// --- State ---
|
||||
let selectedRole = null;
|
||||
let inviteValid = false;
|
||||
let inviteToken = null;
|
||||
let inviteRecipient = null; // dati destinatario dell'invito (pre-fill)
|
||||
let isReducedReg = false; // true = registrazione ridotta (solo password)
|
||||
let inviteRecipient = null;
|
||||
let isReducedReg = false;
|
||||
let pivaData = null;
|
||||
let pivaLookupTimer = null;
|
||||
let successRedirect = 'onboarding.html';
|
||||
|
||||
// --- URL Params pre-fill ---
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
if (params.get('role')) {
|
||||
// Will apply after DOM is ready (in DOMContentLoaded equivalent below)
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const r = params.get('role');
|
||||
if (document.getElementById('card-' + r)) selectRole(r);
|
||||
});
|
||||
}
|
||||
const _inviteTok = params.get('invite_token') || params.get('invite') || params.get('token');
|
||||
if (_inviteTok) {
|
||||
inviteToken = _inviteTok;
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const details = document.getElementById('invite-details');
|
||||
details.open = true;
|
||||
const inp = document.getElementById('invite-code');
|
||||
inp.value = inviteToken;
|
||||
validateInvite(inviteToken);
|
||||
});
|
||||
}
|
||||
|
||||
// --- Role Selection ---
|
||||
function selectRole(role) {
|
||||
selectedRole = role;
|
||||
document.querySelectorAll('.role-card').forEach(c => c.classList.remove('selected'));
|
||||
document.querySelectorAll('.role-card').forEach(c => { c.classList.remove('selected'); c.setAttribute('aria-checked','false'); });
|
||||
const card = document.getElementById('card-' + role);
|
||||
if (card) card.classList.add('selected');
|
||||
if (card) { card.classList.add('selected'); card.setAttribute('aria-checked','true'); }
|
||||
document.getElementById('btn-next-0').disabled = false;
|
||||
|
||||
// Hide P.IVA for consultant role
|
||||
const pivaGroup = document.getElementById('piva-group');
|
||||
pivaGroup.style.display = (role === 'consultant') ? 'none' : 'block';
|
||||
}
|
||||
function cardKey(e, role) {
|
||||
if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); selectRole(role); }
|
||||
}
|
||||
|
||||
// Pre-fill from URL after DOM ready
|
||||
(function() {
|
||||
@@ -396,7 +297,6 @@
|
||||
document.getElementById('invite-code').value = tok;
|
||||
validateInvite(tok);
|
||||
}
|
||||
// Pre-fill name/email
|
||||
if (params.get('nome')) document.getElementById('firstname').value = params.get('nome');
|
||||
if (params.get('cognome')) document.getElementById('lastname').value = params.get('cognome');
|
||||
if (params.get('email')) document.getElementById('email').value = params.get('email');
|
||||
@@ -409,13 +309,10 @@
|
||||
clearTimeout(inviteTimer);
|
||||
val = val.trim();
|
||||
if (!val) {
|
||||
inviteValid = false;
|
||||
inviteToken = null;
|
||||
statusEl.innerHTML = '';
|
||||
return;
|
||||
inviteValid = false; inviteToken = null; statusEl.innerHTML = ''; statusEl.className = 'lookup-status'; return;
|
||||
}
|
||||
statusEl.className = 'lookup-status loading';
|
||||
statusEl.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Verifica codice...';
|
||||
statusEl.textContent = 'Verifica codice...';
|
||||
inviteTimer = setTimeout(async () => {
|
||||
try {
|
||||
const res = await fetch(api.baseUrl + '/auth/validate-invite', {
|
||||
@@ -425,16 +322,11 @@
|
||||
});
|
||||
const data = await res.json();
|
||||
if (data.success) {
|
||||
inviteValid = true;
|
||||
inviteToken = val;
|
||||
inviteValid = true; inviteToken = val;
|
||||
statusEl.className = 'lookup-status ok';
|
||||
const label = data.data?.label ? ` — ${data.data.label}` : '';
|
||||
statusEl.innerHTML = `<i class="fas fa-check-circle"></i> Codice valido${label} — accesso B2B confermato`;
|
||||
// Pre-fill role if provided
|
||||
if (data.role && document.getElementById('card-' + data.role)) {
|
||||
selectRole(data.role);
|
||||
}
|
||||
// Pre-fill dai dati destinatario nell'invite (recipient)
|
||||
statusEl.textContent = `Codice valido${label} — accesso B2B confermato`;
|
||||
if (data.role && document.getElementById('card-' + data.role)) selectRole(data.role);
|
||||
const r = data.data?.recipient;
|
||||
if (r) {
|
||||
if (r.first_name) document.getElementById('firstname').value = r.first_name;
|
||||
@@ -446,23 +338,20 @@
|
||||
}
|
||||
if (isReducedReg) applyReducedRegMode();
|
||||
} else {
|
||||
inviteValid = false;
|
||||
inviteToken = null;
|
||||
inviteValid = false; inviteToken = null;
|
||||
statusEl.className = 'lookup-status err';
|
||||
statusEl.innerHTML = '<i class="fas fa-times-circle"></i> Codice non valido';
|
||||
statusEl.textContent = 'Codice non valido';
|
||||
}
|
||||
} catch {
|
||||
// Network error: accept token optimistically, validate on submit
|
||||
inviteValid = false;
|
||||
statusEl.className = 'lookup-status err';
|
||||
statusEl.innerHTML = '<i class="fas fa-exclamation-triangle"></i> Impossibile verificare';
|
||||
statusEl.textContent = 'Impossibile verificare';
|
||||
}
|
||||
}, 600);
|
||||
}
|
||||
|
||||
// --- P.IVA Lookup ---
|
||||
function validaFormatoPiva(v) {
|
||||
// Controllo cifra di controllo P.IVA italiana
|
||||
if (!/^\d{11}$/.test(v)) return false;
|
||||
let s = 0;
|
||||
for (let i = 0; i < 10; i++) {
|
||||
@@ -477,16 +366,15 @@
|
||||
clearTimeout(pivaLookupTimer);
|
||||
val = val.replace(/\s/g, '');
|
||||
const statusEl = document.getElementById('piva-status');
|
||||
if (val.length < 11) { pivaData = null; statusEl.innerHTML = ''; return; }
|
||||
if (val.length < 11) { pivaData = null; statusEl.innerHTML = ''; statusEl.className = 'lookup-status'; return; }
|
||||
if (val.length === 11 && !validaFormatoPiva(val)) {
|
||||
pivaData = null;
|
||||
statusEl.className = 'lookup-status err';
|
||||
statusEl.innerHTML = '<i class="fas fa-times-circle"></i> P.IVA non valida (cifra di controllo errata)';
|
||||
statusEl.textContent = 'P.IVA non valida (cifra di controllo errata)';
|
||||
return;
|
||||
}
|
||||
// Formato OK — mostra subito conferma, poi prova lookup
|
||||
statusEl.className = 'lookup-status ok';
|
||||
statusEl.innerHTML = '<i class="fas fa-check-circle"></i> P.IVA valida — ricerca dati azienda...';
|
||||
statusEl.textContent = 'P.IVA valida — ricerca dati azienda...';
|
||||
pivaLookupTimer = setTimeout(async () => {
|
||||
try {
|
||||
const res = await fetch(api.baseUrl + '/onboarding/lookup-piva', {
|
||||
@@ -498,40 +386,32 @@
|
||||
if (data.success && data.data && data.data.company_name) {
|
||||
pivaData = data.data;
|
||||
statusEl.className = 'lookup-status ok';
|
||||
statusEl.innerHTML = '<i class="fas fa-building"></i> ' + data.data.company_name;
|
||||
statusEl.textContent = data.data.company_name;
|
||||
} else {
|
||||
pivaData = null;
|
||||
statusEl.className = 'lookup-status ok';
|
||||
statusEl.innerHTML = '<i class="fas fa-check-circle"></i> P.IVA valida — inserisci i dati aziendali nel passo successivo';
|
||||
statusEl.textContent = 'P.IVA valida — inserisci i dati aziendali nel passo successivo';
|
||||
}
|
||||
} catch {
|
||||
pivaData = null;
|
||||
statusEl.className = 'lookup-status ok';
|
||||
statusEl.innerHTML = '<i class="fas fa-check-circle"></i> P.IVA valida — inserisci i dati aziendali nel passo successivo';
|
||||
statusEl.textContent = 'P.IVA valida — inserisci i dati aziendali nel passo successivo';
|
||||
}
|
||||
}, 800);
|
||||
}
|
||||
|
||||
// --- Registrazione Ridotta (invito con dati pre-compilati) ---
|
||||
// --- Registrazione Ridotta ---
|
||||
function applyReducedRegMode() {
|
||||
const name = ((inviteRecipient.first_name || '') + ' ' + (inviteRecipient.last_name || '')).trim();
|
||||
document.getElementById('invite-welcome-name').textContent = 'Ciao ' + name + '!';
|
||||
document.getElementById('invite-welcome-plan').textContent = 'Accesso B2B — account pre-configurato dall\'invito';
|
||||
document.getElementById('invite-welcome').style.display = 'block';
|
||||
// Campi pre-compilati → read-only
|
||||
['firstname', 'lastname', 'email'].forEach(id => {
|
||||
const el = document.getElementById(id);
|
||||
el.readOnly = true;
|
||||
el.style.background = '#f9fafb';
|
||||
el.style.color = '#6b7280';
|
||||
});
|
||||
// Nascondi P.IVA se già presente nell'invito
|
||||
if (inviteRecipient.vat) {
|
||||
document.getElementById('piva-group').style.display = 'none';
|
||||
}
|
||||
// Seleziona ruolo default se non già selezionato
|
||||
if (inviteRecipient.vat) document.getElementById('piva-group').style.display = 'none';
|
||||
if (!selectedRole) selectRole('org_admin');
|
||||
// Avanza direttamente allo step dati senza richiedere click
|
||||
goToStep1();
|
||||
}
|
||||
|
||||
@@ -541,18 +421,17 @@
|
||||
document.getElementById('step-' + i).style.display = (i === n) ? 'block' : 'none';
|
||||
const si = document.getElementById('si-' + i);
|
||||
si.className = 'step-item' + (i < n ? ' done' : i === n ? ' active' : '');
|
||||
if (i < n) si.querySelector('.step-circle').innerHTML = '<i class="fas fa-check" style="font-size:.75rem;"></i>';
|
||||
if (i < n) si.querySelector('.step-circle').innerHTML = '<svg class="icon icon-xs icon-white" aria-hidden="true"><use href="vendor/bootstrap-italia/dist/svg/sprites.svg#it-check"></use></svg>';
|
||||
else si.querySelector('.step-circle').textContent = i + 1;
|
||||
});
|
||||
document.getElementById('conn-0').className = 'step-connector' + (n > 0 ? ' done' : '');
|
||||
document.getElementById('conn-1').className = 'step-connector' + (n > 1 ? ' done' : '');
|
||||
if (n === 2) document.getElementById('step-indicator').style.display = 'none';
|
||||
else document.getElementById('step-indicator').style.display = 'flex';
|
||||
document.getElementById('step-indicator').style.display = (n === 2) ? 'none' : 'flex';
|
||||
}
|
||||
|
||||
function goToStep1() {
|
||||
if (!selectedRole) return;
|
||||
document.getElementById('register-error').classList.remove('visible');
|
||||
document.getElementById('register-error').classList.add('d-none');
|
||||
const labels = {
|
||||
compliance_manager: 'Dati account — CISO / Compliance Manager',
|
||||
org_admin: 'Dati account — Legale Rappresentante',
|
||||
@@ -566,25 +445,18 @@
|
||||
}
|
||||
|
||||
function goToStep0() {
|
||||
document.getElementById('register-error').classList.remove('visible');
|
||||
document.getElementById('register-error').classList.add('d-none');
|
||||
document.getElementById('auth-subtitle').textContent = 'Crea il tuo account';
|
||||
setStep(0);
|
||||
}
|
||||
|
||||
function goToDashboard() {
|
||||
window.location.href = successRedirect;
|
||||
}
|
||||
function goToDashboard() { window.location.href = successRedirect; }
|
||||
|
||||
// --- Password toggle ---
|
||||
function togglePw(id, btn) {
|
||||
const inp = document.getElementById(id);
|
||||
if (inp.type === 'password') {
|
||||
inp.type = 'text';
|
||||
btn.innerHTML = '<i class="fas fa-eye-slash"></i>';
|
||||
} else {
|
||||
inp.type = 'password';
|
||||
btn.innerHTML = '<i class="fas fa-eye"></i>';
|
||||
}
|
||||
inp.type = (inp.type === 'password') ? 'text' : 'password';
|
||||
const use = btn.querySelector('use');
|
||||
use.setAttribute('href', 'vendor/bootstrap-italia/dist/svg/sprites.svg#' + (inp.type === 'text' ? 'it-password-invisible' : 'it-password-visible'));
|
||||
}
|
||||
|
||||
// --- Password strength ---
|
||||
@@ -604,20 +476,19 @@
|
||||
|
||||
function updateStrengthUI(level, pw) {
|
||||
const labels = { 1: 'Debole', 2: 'Sufficiente', 3: 'Buona', 4: 'Forte' };
|
||||
const classes = { 1: 'weak', 2: 'fair', 3: 'good', 4: 'strong' };
|
||||
for (let i = 1; i <= 4; i++) {
|
||||
const seg = document.getElementById('ps-' + i);
|
||||
seg.className = 'password-strength-segment';
|
||||
if (i <= level && pw.length > 0) seg.classList.add('active', classes[level]);
|
||||
}
|
||||
document.getElementById('ps-text').textContent = pw.length > 0 ? labels[level] : '';
|
||||
const colors = { 1: '#d9364f', 2: '#e58a00', 3: '#06c', 4: '#008758' };
|
||||
const bar = document.getElementById('ps-bar');
|
||||
if (pw.length === 0) { bar.style.width = '0%'; document.getElementById('ps-text').textContent = ''; return; }
|
||||
bar.style.width = (level * 25) + '%';
|
||||
bar.style.backgroundColor = colors[level];
|
||||
document.getElementById('ps-text').textContent = 'Sicurezza: ' + labels[level];
|
||||
}
|
||||
|
||||
// --- Form Submit ---
|
||||
document.getElementById('register-form').addEventListener('submit', async (e) => {
|
||||
e.preventDefault();
|
||||
const errorEl = document.getElementById('register-error');
|
||||
errorEl.classList.remove('visible');
|
||||
errorEl.classList.add('d-none');
|
||||
|
||||
const firstname = document.getElementById('firstname').value.trim();
|
||||
const lastname = document.getElementById('lastname').value.trim();
|
||||
@@ -627,26 +498,12 @@
|
||||
const passwordConfirm = document.getElementById('password-confirm').value;
|
||||
const fullname = firstname + ' ' + lastname;
|
||||
|
||||
if (!firstname || !lastname || !email || !password) {
|
||||
errorEl.textContent = 'Nome, cognome, email e password sono obbligatori.';
|
||||
errorEl.classList.add('visible');
|
||||
return;
|
||||
}
|
||||
if (selectedRole !== 'consultant' && !piva) {
|
||||
errorEl.textContent = 'Inserisci la Partita IVA della tua azienda.';
|
||||
errorEl.classList.add('visible');
|
||||
return;
|
||||
}
|
||||
if (password.length < 8) {
|
||||
errorEl.textContent = 'La password deve avere almeno 8 caratteri.';
|
||||
errorEl.classList.add('visible');
|
||||
return;
|
||||
}
|
||||
if (password !== passwordConfirm) {
|
||||
errorEl.textContent = 'Le password non coincidono.';
|
||||
errorEl.classList.add('visible');
|
||||
return;
|
||||
}
|
||||
function showErr(msg) { errorEl.textContent = msg; errorEl.classList.remove('d-none'); }
|
||||
|
||||
if (!firstname || !lastname || !email || !password) { showErr('Nome, cognome, email e password sono obbligatori.'); return; }
|
||||
if (selectedRole !== 'consultant' && !piva) { showErr('Inserisci la Partita IVA della tua azienda.'); return; }
|
||||
if (password.length < 8) { showErr('La password deve avere almeno 8 caratteri.'); return; }
|
||||
if (password !== passwordConfirm) { showErr('Le password non coincidono.'); return; }
|
||||
|
||||
const btn = document.getElementById('register-btn');
|
||||
btn.disabled = true;
|
||||
@@ -654,9 +511,7 @@
|
||||
|
||||
try {
|
||||
let result;
|
||||
|
||||
if (inviteToken) {
|
||||
// B2B provision flow
|
||||
result = await fetch(api.baseUrl + '/auth/register', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
@@ -672,15 +527,12 @@
|
||||
}
|
||||
|
||||
if (result.success) {
|
||||
// Determine redirect
|
||||
if (inviteToken) {
|
||||
successRedirect = 'dashboard.html';
|
||||
// Salva JWT tokens
|
||||
if (result.data?.access_token) {
|
||||
api.setTokens(result.data.access_token, result.data.refresh_token);
|
||||
localStorage.setItem('nis2_user_role', result.data.user?.role || selectedRole || 'org_admin');
|
||||
}
|
||||
// Chiama provision per creare l'organizzazione
|
||||
try {
|
||||
const companyName = pivaData?.company_name || inviteRecipient?.company || 'Azienda';
|
||||
const vatNum = (piva || inviteRecipient?.vat || '').replace(/[^0-9]/g, '');
|
||||
@@ -706,14 +558,13 @@
|
||||
localStorage.setItem('nis2_org_id', String(provData.data.org_id));
|
||||
}
|
||||
}
|
||||
} catch { /* provision fallita — utente completerà onboarding */ }
|
||||
} catch { /* provision fallita */ }
|
||||
} else if (selectedRole === 'consultant') {
|
||||
successRedirect = 'companies.html';
|
||||
} else {
|
||||
successRedirect = 'onboarding.html';
|
||||
}
|
||||
|
||||
// Success step
|
||||
const titles = {
|
||||
consultant: 'Account Consulente creato!',
|
||||
board_member: 'Account Board Member creato!',
|
||||
@@ -729,12 +580,10 @@
|
||||
setStep(2);
|
||||
setTimeout(goToDashboard, 2500);
|
||||
} else {
|
||||
errorEl.textContent = result.message || 'Errore durante la registrazione.';
|
||||
errorEl.classList.add('visible');
|
||||
showErr(result.message || 'Errore durante la registrazione.');
|
||||
}
|
||||
} catch (err) {
|
||||
errorEl.textContent = 'Errore di connessione al server.';
|
||||
errorEl.classList.add('visible');
|
||||
showErr('Errore di connessione al server.');
|
||||
} finally {
|
||||
btn.disabled = false;
|
||||
btn.textContent = 'Crea Account';
|
||||
|
||||
Reference in New Issue
Block a user