[FEAT] licenseExt: sezione dati destinatario pre-compila form + link pronto + modale con recipient data
This commit is contained in:
parent
7bb92b1971
commit
e02e0e21d0
@ -210,6 +210,12 @@ class InviteController extends BaseController
|
||||
$row['used_by_org'] = $org;
|
||||
}
|
||||
|
||||
// Parsa metadata per esporre recipient strutturato
|
||||
if (!empty($row['metadata'])) {
|
||||
$meta = json_decode($row['metadata'], true) ?? [];
|
||||
$row['metadata_recipient'] = $meta['recipient'] ?? null;
|
||||
}
|
||||
|
||||
$this->jsonSuccess($row);
|
||||
}
|
||||
|
||||
|
||||
@ -366,8 +366,9 @@ body { background: var(--bg-main); }
|
||||
<input type="text" id="gLabel" placeholder="Es: NIS2 Starter — Ordine 2026-042">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Destinatario / Reseller</label>
|
||||
<label>Destinatario interno (riferimento)</label>
|
||||
<input type="text" id="gIssuedTo" placeholder="nome@azienda.it o ragione sociale">
|
||||
<div class="form-hint">Solo riferimento interno — non visibile al cliente</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Nome reseller (riferimento interno)</label>
|
||||
@ -387,6 +388,32 @@ body { background: var(--bg-main); }
|
||||
<label>Note interne marketing</label>
|
||||
<textarea id="gNotes" rows="2" placeholder="Ordine di riferimento, condizioni speciali, sconto applicato..."></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Dati destinatario — pre-compilano il form di registrazione -->
|
||||
<h2 style="margin-top:1.5rem">Dati destinatario <span style="font-size:.78rem;font-weight:400;color:var(--text-secondary)">— pre-compilano il form di registrazione del cliente</span></h2>
|
||||
<div class="gen-grid">
|
||||
<div class="form-group">
|
||||
<label>Nome *</label>
|
||||
<input type="text" id="gRcpFirst" placeholder="Es: Cristiano">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Cognome *</label>
|
||||
<input type="text" id="gRcpLast" placeholder="Es: Benassati">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Email destinatario *</label>
|
||||
<input type="email" id="gRcpEmail" placeholder="presidenza@agile.software">
|
||||
<div class="form-hint">Il cliente vedrà questa email pre-compilata nel form</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>P.IVA azienda</label>
|
||||
<input type="text" id="gRcpVat" placeholder="07776161213" maxlength="11">
|
||||
<div class="form-hint">Pre-compila il campo P.IVA nel form di registrazione</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="gen-grid" style="margin-top:1rem">
|
||||
<div class="form-group">
|
||||
<label>Limita a P.IVA (opzionale)</label>
|
||||
<input type="text" id="gRestVat" placeholder="02345678901" maxlength="11">
|
||||
@ -697,6 +724,16 @@ async function generateLicense() {
|
||||
const email = document.getElementById('gRestEmail').value.trim();
|
||||
if (email) body.restrict_email = email;
|
||||
|
||||
// Dati destinatario — pre-compilano il form di registrazione
|
||||
const rcpFirst = document.getElementById('gRcpFirst').value.trim();
|
||||
const rcpLast = document.getElementById('gRcpLast').value.trim();
|
||||
const rcpEmail = document.getElementById('gRcpEmail').value.trim();
|
||||
const rcpVat = document.getElementById('gRcpVat').value.trim();
|
||||
if (rcpFirst) body.recipient_first_name = rcpFirst;
|
||||
if (rcpLast) body.recipient_last_name = rcpLast;
|
||||
if (rcpEmail) body.recipient_email = rcpEmail;
|
||||
if (rcpVat) body.recipient_vat = rcpVat;
|
||||
|
||||
const btn = document.getElementById('genBtn');
|
||||
const ldr = document.getElementById('genLoading');
|
||||
btn.style.display = 'none'; ldr.style.display = '';
|
||||
@ -718,20 +755,27 @@ async function generateLicense() {
|
||||
function renderGenResult(invites) {
|
||||
const res = document.getElementById('genResult');
|
||||
const list = document.getElementById('genTokenList');
|
||||
list.innerHTML = invites.map((inv, i) => `
|
||||
<div style="margin-bottom:.75rem">
|
||||
<div style="font-size:.75rem;color:var(--text-secondary);margin-bottom:.2rem">
|
||||
list.innerHTML = invites.map((inv, i) => {
|
||||
const r = inv.recipient;
|
||||
const recipientLine = r ? `<div style="font-size:.72rem;color:#22c55e;margin-top:.2rem">
|
||||
👤 ${[r.first_name, r.last_name].filter(Boolean).join(' ')}${r.email ? ` <${r.email}>` : ''}${r.vat ? ` · P.IVA ${r.vat}` : ''} — form pre-compilato ✓
|
||||
</div>` : '';
|
||||
return `
|
||||
<div style="margin-bottom:.75rem;padding:.75rem;background:rgba(6,182,212,.05);border:1px solid rgba(6,182,212,.2);border-radius:8px">
|
||||
<div style="font-size:.75rem;color:var(--text-secondary);margin-bottom:.3rem">
|
||||
Licenza #${i+1} — ${inv.plan} · ${inv.duration_months} mesi · ID: ${inv.id}
|
||||
</div>
|
||||
<div class="token-val" id="tok-${i}">${inv.token}</div>
|
||||
<div style="font-size:.72rem;color:var(--text-secondary)">
|
||||
URL: <a href="${inv.invite_url}" style="color:var(--primary)">${inv.invite_url}</a>
|
||||
· Scade invito: ${new Date(inv.expires_at).toLocaleDateString('it-IT')}
|
||||
${inv.max_users_per_org ? ` · Max utenti/org: ${inv.max_users_per_org}` : ''}
|
||||
${inv.price_eur ? ` · € ${inv.price_eur}` : ''}
|
||||
</div>
|
||||
</div>
|
||||
`).join('');
|
||||
<div class="token-val" id="tok-${i}">${inv.token}</div>
|
||||
<div style="font-size:.72rem;color:var(--text-secondary);margin-top:.3rem">
|
||||
🔗 Link da inviare al cliente: <a href="${inv.invite_url}" target="_blank" style="color:var(--primary)">${inv.invite_url}</a>
|
||||
<button class="act-btn" style="font-size:.7rem;padding:.2rem .5rem;margin-left:.5rem" onclick="navigator.clipboard.writeText('${inv.invite_url}').then(()=>showToast('Link copiato','ok'))">Copia link</button>
|
||||
</div>
|
||||
${recipientLine}
|
||||
</div>`;
|
||||
}).join('');
|
||||
res.classList.add('show');
|
||||
res.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
|
||||
}
|
||||
@ -757,7 +801,8 @@ function exportCsv() {
|
||||
}
|
||||
|
||||
function resetForm() {
|
||||
['gLabel','gIssuedTo','gReseller','gNotes','gRestVat','gRestEmail','gPrice','gMaxUsers'].forEach(id => {
|
||||
['gLabel','gIssuedTo','gReseller','gNotes','gRestVat','gRestEmail','gPrice','gMaxUsers',
|
||||
'gRcpFirst','gRcpLast','gRcpEmail','gRcpVat'].forEach(id => {
|
||||
document.getElementById(id).value = '';
|
||||
});
|
||||
document.getElementById('gPlan').value = 'professional';
|
||||
@ -819,7 +864,7 @@ async function showDetail(id) {
|
||||
<div class="detail-item"><div class="dl">Reseller</div><div class="dv">${inv.reseller_name || '—'}</div></div>
|
||||
</div>
|
||||
<div class="detail-row" style="margin-bottom:1rem">
|
||||
<div class="detail-item"><div class="dl">Destinatario</div><div class="dv">${inv.issued_to || '—'}</div></div>
|
||||
<div class="detail-item"><div class="dl">Rif. interno</div><div class="dv">${inv.issued_to || '—'}</div></div>
|
||||
<div class="detail-item"><div class="dl">Creato</div><div class="dv">${new Date(inv.created_at).toLocaleString('it-IT')}</div></div>
|
||||
${inv.used_at ? `<div class="detail-item"><div class="dl">Usato il</div><div class="dv">${new Date(inv.used_at).toLocaleString('it-IT')}</div></div>` : ''}
|
||||
</div>
|
||||
@ -834,6 +879,15 @@ async function showDetail(id) {
|
||||
<strong>${inv.used_by_org.name}</strong>
|
||||
<span style="font-size:.78rem;color:var(--text-secondary);margin-left:.5rem">${inv.used_by_org.sector || ''} · ${inv.used_by_org.nis2_entity_type || ''}</span>
|
||||
</div>` : ''}
|
||||
${inv.metadata_recipient ? (() => { const r = inv.metadata_recipient; return `
|
||||
<div style="background:rgba(34,197,94,.07);border:1px solid rgba(34,197,94,.25);border-radius:8px;padding:.75rem 1rem;margin-bottom:1rem">
|
||||
<div style="font-size:.75rem;color:var(--text-secondary);margin-bottom:.4rem">👤 Dati destinatario (pre-compilano il form)</div>
|
||||
<div style="font-size:.88rem">
|
||||
${[r.first_name, r.last_name].filter(Boolean).join(' ')}
|
||||
${r.email ? `<span style="color:var(--primary);margin-left:.5rem">${r.email}</span>` : ''}
|
||||
${r.vat ? `<span style="color:var(--text-secondary);margin-left:.5rem">P.IVA: ${r.vat}</span>` : ''}
|
||||
</div>
|
||||
</div>`; })() : ''}
|
||||
${inv.notes ? `<div style="font-size:.82rem;color:var(--text-secondary);border-top:1px solid var(--border);padding-top:.75rem"><strong>Note:</strong> ${inv.notes}</div>` : ''}
|
||||
<div style="display:flex;gap:.5rem;margin-top:1rem;flex-wrap:wrap">
|
||||
${inv.status === 'pending' ? `<button class="act-btn danger" onclick="revokeInvite(${inv.id})">Revoca licenza</button>` : ''}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user