feat(ar1-admin): variabili cliccabili nel dialog modifica testo email
I 7 Tag delle variabili disponibili (company_name, company_piva, ar1_form_url,
expires_at, days_to_expiry, variant, signer_name) sono ora CLICCABILI dentro
il dialog di modifica testo. Click inserisce {{variabile}} nel campo attivo
al punto del cursore (o in coda se focus perso).
Cambiamenti:
- Stato nuovo: activeEmailField ('subject' | 'body_html' | 'body_text'),
inizialmente 'body_html'
- 3 ref: subjectInputRef, bodyHtmlInputRef, bodyTextInputRef
- Funzione insertVariable(varName):
1. Legge editEmailData[activeEmailField]
2. Calcola posizione cursore via ref.getInput().selectionStart (fallback: coda)
3. Inserisce '{{' + varName + '}}' al cursore
4. Riposiziona cursor dopo il token inserito (setTimeout 0 per React re-render)
- 3 campi Input wrappati con ref + onFocus={() => setActiveEmailField(...)}
- Box variabili spostato DENTRO il dialog (prima era nel TabPanel, poco scopribile).
Mostra live quale campo e attivo: 'inserite in: Oggetto / Corpo HTML / Corpo testo'
- Tag stile severity=info + cursor:pointer + userSelect:none per feedback visuale
- Box variabili nel tab ora e un semplice Message informativo (la funzione e nel dialog)
UX: l'utente clicca dentro Oggetto, poi clicca {{company_name}}, vede il token
comparire al cursore. Se clicca Corpo HTML, poi un'altra variabile, va in quel
campo. Nessun drag&drop, nessuna complicazione.
This commit is contained in:
@@ -59,7 +59,7 @@ const PEC_KIND_OPTIONS = [
|
||||
];
|
||||
|
||||
/**
|
||||
* Ar1AdminConfig — configurazione AR1 per superadmin. (build 1776949690)
|
||||
* Ar1AdminConfig — configurazione AR1 per superadmin. (build 1776950093)
|
||||
* URL: /ar1-admin
|
||||
*
|
||||
* 5 sezioni (TabView):
|
||||
@@ -112,6 +112,51 @@ const Ar1AdminConfig = () => {
|
||||
const [editEmailData, setEditEmailData] = useState(null);
|
||||
const [previewHtml, setPreviewHtml] = useState(null);
|
||||
const [previewSubject, setPreviewSubject] = useState(null);
|
||||
// Tracking campo attivo per inserimento variabili con click
|
||||
const [activeEmailField, setActiveEmailField] = useState('body_html'); // 'subject' | 'body_html' | 'body_text'
|
||||
const subjectInputRef = useRef(null);
|
||||
const bodyHtmlInputRef = useRef(null);
|
||||
const bodyTextInputRef = useRef(null);
|
||||
|
||||
// Inserisce {{variabile}} nel campo attivo, al cursore se possibile
|
||||
const insertVariable = (varName) => {
|
||||
if (!editEmailData) return;
|
||||
const token = '{{' + varName + '}}';
|
||||
const fieldName = activeEmailField;
|
||||
const refMap = { subject: subjectInputRef, body_html: bodyHtmlInputRef, body_text: bodyTextInputRef };
|
||||
const ref = refMap[fieldName];
|
||||
const currentValue = editEmailData[fieldName] || '';
|
||||
|
||||
// InputText/InputTextarea PrimeReact espone l'elemento nativo via .getElement() o .current.element in v10+
|
||||
// fallback sicuro: appendo in coda
|
||||
let insertAt = currentValue.length;
|
||||
let el = null;
|
||||
try {
|
||||
el = ref?.current?.getInput ? ref.current.getInput() : (ref?.current?.element || ref?.current);
|
||||
if (el && typeof el.selectionStart === 'number') {
|
||||
insertAt = el.selectionStart;
|
||||
}
|
||||
} catch (e) {
|
||||
// ignore, insertAt rimane a length
|
||||
}
|
||||
|
||||
const before = currentValue.slice(0, insertAt);
|
||||
const after = currentValue.slice(insertAt);
|
||||
const newValue = before + token + after;
|
||||
|
||||
setEditEmailData({ ...editEmailData, [fieldName]: newValue });
|
||||
|
||||
// riposiziono focus e cursor dopo il token appena inserito
|
||||
setTimeout(() => {
|
||||
try {
|
||||
if (el && typeof el.setSelectionRange === 'function') {
|
||||
el.focus();
|
||||
const pos = insertAt + token.length;
|
||||
el.setSelectionRange(pos, pos);
|
||||
}
|
||||
} catch (e) { /* ignore */ }
|
||||
}, 0);
|
||||
};
|
||||
|
||||
// ---- load all ----
|
||||
const loadTemplates = () => {
|
||||
@@ -655,12 +700,7 @@ const Ar1AdminConfig = () => {
|
||||
<Card>
|
||||
<Message severity="info" style={{ marginBottom: 10 }} text="Qui modifichi oggetto e corpo delle PEC inviate dal sistema. Ogni modifica incrementa la versione: il backend Gepafin sincronizza automaticamente i testi nei suoi template per-hub (PEC Massiva / Mailgun)." />
|
||||
|
||||
{availableVariables.length > 0 && (
|
||||
<div style={{ marginBottom: 14, padding: 10, background: '#f5f5f5', borderRadius: 4 }}>
|
||||
<strong>Variabili disponibili</strong> (usa nel testo come <code>{'{{nome_variabile}}'}</code>):<br />
|
||||
{availableVariables.map(v => <Tag key={v} value={v} style={{ marginRight: 4, marginTop: 4 }} />)}
|
||||
</div>
|
||||
)}
|
||||
<Message severity="info" style={{ marginBottom: 10 }} text="Clicca su 'Modifica' per editare un testo. Dentro il dialog potrai inserire le variabili con un click." />
|
||||
|
||||
<DataTable value={emailTemplates} loading={loadingEmail} emptyMessage="Nessun testo configurato">
|
||||
<Column field="kind" header="Tipo comunicazione" body={(r) => (
|
||||
@@ -859,21 +899,61 @@ const Ar1AdminConfig = () => {
|
||||
>
|
||||
{editEmailData && (
|
||||
<div>
|
||||
<Message severity="info" style={{ marginBottom: 10 }} text="Usa le variabili nei testi con la sintassi {{nome}} (es. {{company_name}}). Il backend Gepafin le sostituira al momento dell'invio." />
|
||||
<Message severity="info" style={{ marginBottom: 10 }} text="Clicca un campo per attivarlo, poi clicca una variabile qui sotto per inserirla al cursore." />
|
||||
|
||||
{availableVariables.length > 0 && (
|
||||
<div style={{ marginBottom: 14, padding: 10, background: '#eef6ff', border: '1px solid #cfe0f7', borderRadius: 4 }}>
|
||||
<strong style={{ fontSize: 13 }}>Variabili disponibili </strong>
|
||||
<small style={{ color: '#555' }}>
|
||||
(inserite in: <strong>{activeEmailField === 'subject' ? 'Oggetto' : activeEmailField === 'body_html' ? 'Corpo HTML' : 'Corpo testo'}</strong>)
|
||||
</small>
|
||||
<div style={{ marginTop: 8, display: 'flex', flexWrap: 'wrap', gap: 6 }}>
|
||||
{availableVariables.map(v => (
|
||||
<Tag
|
||||
key={v}
|
||||
value={'{{' + v + '}}'}
|
||||
severity="info"
|
||||
style={{ cursor: 'pointer', userSelect: 'none' }}
|
||||
onClick={() => insertVariable(v)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div style={{ marginBottom: 10 }}>
|
||||
<label style={{ display: 'block', marginBottom: 4, fontWeight: 500 }}>Oggetto</label>
|
||||
<InputText value={editEmailData.subject} onChange={(e) => setEditEmailData({ ...editEmailData, subject: e.target.value })} style={{ width: '100%' }} />
|
||||
<InputText
|
||||
ref={subjectInputRef}
|
||||
value={editEmailData.subject}
|
||||
onChange={(e) => setEditEmailData({ ...editEmailData, subject: e.target.value })}
|
||||
onFocus={() => setActiveEmailField('subject')}
|
||||
style={{ width: '100%' }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div style={{ marginBottom: 10 }}>
|
||||
<label style={{ display: 'block', marginBottom: 4, fontWeight: 500 }}>Corpo HTML</label>
|
||||
<InputTextarea value={editEmailData.body_html} onChange={(e) => setEditEmailData({ ...editEmailData, body_html: e.target.value })} rows={10} style={{ width: '100%', fontFamily: 'monospace', fontSize: 12 }} />
|
||||
<InputTextarea
|
||||
ref={bodyHtmlInputRef}
|
||||
value={editEmailData.body_html}
|
||||
onChange={(e) => setEditEmailData({ ...editEmailData, body_html: e.target.value })}
|
||||
onFocus={() => setActiveEmailField('body_html')}
|
||||
rows={10}
|
||||
style={{ width: '100%', fontFamily: 'monospace', fontSize: 12 }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div style={{ marginBottom: 10 }}>
|
||||
<label style={{ display: 'block', marginBottom: 4, fontWeight: 500 }}>Corpo testo semplice (fallback)</label>
|
||||
<InputTextarea value={editEmailData.body_text} onChange={(e) => setEditEmailData({ ...editEmailData, body_text: e.target.value })} rows={5} style={{ width: '100%', fontSize: 13 }} />
|
||||
<InputTextarea
|
||||
ref={bodyTextInputRef}
|
||||
value={editEmailData.body_text}
|
||||
onChange={(e) => setEditEmailData({ ...editEmailData, body_text: e.target.value })}
|
||||
onFocus={() => setActiveEmailField('body_text')}
|
||||
rows={5}
|
||||
style={{ width: '100%', fontSize: 13 }}
|
||||
/>
|
||||
<small style={{ color: '#888' }}>Usato dai client email che non supportano HTML.</small>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user