[FEAT] Simulatore B2B licenze + registrazione ridotta
- simulate-nis2-b2b.php: 6 scenari autonomi (SIM-B1→B6):
mktg login, invito con recipient data, validazione pubblica,
registrazione ridotta, provision org, login con org, API Key M2M
- public/simulate-b2b.html: UI terminale dark con flow diagram e SSE streaming
- public/register.html:
- Registrazione ridotta: con invito che ha recipient data mostra banner
"Ciao [Nome]!" + campi pre-compilati read-only + solo password richiesta
- Post-register con inviteToken: chiama provision automaticamente,
salva nis2_org_id in localStorage, redirect a dashboard.html
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
8304da91b4
commit
8b9a617fd5
@@ -222,6 +222,20 @@
|
||||
|
||||
<!-- 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>
|
||||
|
||||
<form id="register-form" novalidate>
|
||||
<div style="display:flex; gap:.75rem;">
|
||||
<div class="form-group" style="flex:1;">
|
||||
@@ -331,6 +345,8 @@
|
||||
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 pivaData = null;
|
||||
let pivaLookupTimer = null;
|
||||
let successRedirect = 'onboarding.html';
|
||||
@@ -425,7 +441,10 @@
|
||||
if (r.last_name) document.getElementById('lastname').value = r.last_name;
|
||||
if (r.email) document.getElementById('email').value = r.email;
|
||||
if (r.vat) { document.getElementById('piva').value = r.vat; lookupPiva(r.vat); }
|
||||
inviteRecipient = r;
|
||||
isReducedReg = !!(r.first_name && r.last_name && r.email);
|
||||
}
|
||||
if (isReducedReg) applyReducedRegMode();
|
||||
} else {
|
||||
inviteValid = false;
|
||||
inviteToken = null;
|
||||
@@ -493,6 +512,29 @@
|
||||
}, 800);
|
||||
}
|
||||
|
||||
// --- Registrazione Ridotta (invito con dati pre-compilati) ---
|
||||
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 (!selectedRole) selectRole('org_admin');
|
||||
// Avanza direttamente allo step dati senza richiedere click
|
||||
goToStep1();
|
||||
}
|
||||
|
||||
// --- Step Navigation ---
|
||||
function setStep(n) {
|
||||
[0, 1, 2].forEach(i => {
|
||||
@@ -633,6 +675,38 @@
|
||||
// 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, '');
|
||||
if (vatNum.length === 11) {
|
||||
btn.textContent = 'Configurazione in corso...';
|
||||
const provRes = await fetch(api.baseUrl + '/services/provision', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
invite_token: inviteToken,
|
||||
company: {
|
||||
ragione_sociale: companyName,
|
||||
partita_iva: vatNum,
|
||||
sector: pivaData?.sector || 'ict',
|
||||
nis2_entity_type: 'important'
|
||||
},
|
||||
admin: { email, full_name: fullname },
|
||||
caller: { system: 'self-register' }
|
||||
})
|
||||
});
|
||||
const provData = await provRes.json();
|
||||
if (provData.success && provData.data?.org_id) {
|
||||
localStorage.setItem('nis2_org_id', String(provData.data.org_id));
|
||||
}
|
||||
}
|
||||
} catch { /* provision fallita — utente completerà onboarding */ }
|
||||
} else if (selectedRole === 'consultant') {
|
||||
successRedirect = 'companies.html';
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user