feat(5.13): carduri compacte mobil/tableta + fix editare preview (OOB tr) + toast

Dogfood pe import + Trimiteri (mobil/tableta <1024px), pur CSS + markup, backend
trimitere neatins:

- Card compact real pentru .tabel-trimiteri (preview + Trimiteri): vehicul=titlu,
  stare=pill dreapta-sus, operatie+cod, meta data/km muted, nota mica. Inlocuieste
  stiva generica eticheta+valoare (carduri de ~450px -> ~135px). Anuleaza regula
  desktop tr.trimitere-row > td{padding:11px} in blocul compact.
- FIX editare preview: OOB swap pe <tr> esua tacit in htmx 1.9 (un <tr> brut se
  pierde la parsarea unui fragment fara context de tabel) -> randul ramanea cu
  starea veche dupa salvare. Inlocuit cu reload complet al preview-ului prin
  HX-Trigger:reincarcaPreview + detalii randSalvat. /editeaza si /confirma-review
  folosesc helper-ul _raspuns_rand_salvat.
- Feedback post-salvare: toast global "Randul N actualizat · <stare>" + scroll +
  flash pe randul actualizat (base.html window.arataToast + listener randSalvat).
- Modal editare: Salveaza + Anuleaza pe acelasi rand (sistem .act): desktop text,
  mobil doua iconite Lucide 44px alaturate (save/x). Macro icon('x') + .act-primary.
- Randuri deja-trimise/duplicate colapsate implicit in preview + toggle "Arata N".
- Select "Operatii de mapat" full-width pe mobil (nu mai iese din viewport).
- Bara de filtre Trimiteri adaptata mobil: pills pe banda cu scroll orizontal,
  cautare vehicul proeminenta (nu 8 butoane full-width stivuite).
- Nota preview = culoarea camp-fix (accent) ca sa atraga atentia; hint-urile
  camp-fix per-camp scoase (campul Note e self-explanatory).
- Confirmare trimitere: scos campul email (Declarant); text mai clar
  ("Confirma numarul din N gata de trimis"). Backend confirmed_by ramane optional.

Teste: contractul OOB (rupt in browser) inlocuit cu noul contract
(reincarcaPreview + randSalvat) in test_web_preview_edit / test_preview_edit_ui /
test_import_review. Suita: 992 passed (exclus live).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Claude Agent
2026-06-27 23:34:33 +00:00
parent bafaf05e83
commit 8d4ff3400e
18 changed files with 633 additions and 303 deletions

View File

@@ -1,5 +1,12 @@
{% import '_macros.html' as ui %}
<div id="import-section">
{# reincarcaPreview (emis de /editeaza si /confirma-review prin HX-Trigger): preview-ul
se reincarca COMPLET (rand + contoare + colaps deja-trimise corecte) in loc de OOB swap
pe <tr> (fragil in htmx 1.9). Evidentierea + toast-ul randului salvat: base.html. #}
<div id="import-section"
hx-get="/_import/{{ import_id }}/preview"
hx-trigger="reincarcaPreview from:body"
hx-target="#import-section"
hx-swap="outerHTML">
{% set pas = 3 %}{% include '_stepper.html' %}
<div class="card">
<div style="display:flex; align-items:center; gap:8px; flex-wrap:wrap; margin-bottom:12px;">
@@ -123,10 +130,22 @@
{% endif %}
</div>
<!-- Toggle randuri deja-trimise / duplicate: colapsate implicit (nu ocupa loc).
Click -> comuta clasa .preview-arata-trimise pe tabel (CSS in base.html). -->
{% set _n_trimise = summary.get('already_sent', 0) + summary.get('duplicate_in_file', 0) %}
{% if _n_trimise %}
<div style="margin-bottom:8px;">
<button type="button" class="btn-secondary btn-sm" aria-expanded="false"
onclick="var t=document.getElementById('preview-tabel'); var on=t.classList.toggle('preview-arata-trimise'); this.setAttribute('aria-expanded', on); this.querySelector('.tgl-tx').textContent = on ? 'Ascunde {{ _n_trimise }} deja trimise / duplicate' : 'Arata {{ _n_trimise }} deja trimise / duplicate';">
<span class="tgl-tx">Arata {{ _n_trimise }} deja trimise / duplicate</span>
</button>
</div>
{% endif %}
<!-- Tabel preview in format identic cu tabelul Trimiteri (.tabel-trimiteri).
US-007: 8 coloane (coloana de verificare eliminata).
Randurile au FORM PROPRIU pentru editare (NU sunt in #confirm-form). -->
<div class="tablewrap tabel-trimiteri">
<div id="preview-tabel" class="tablewrap tabel-trimiteri">
<table>
<thead>
<tr>
@@ -169,31 +188,19 @@
prezentari la RAR (ireversibil).
</div>
<div style="display:flex; gap:12px; align-items:center; flex-wrap:wrap;">
<div>
<label for="n-confirmat"
style="font-size:13px; color:var(--muted); display:block; margin-bottom:2px;">
Numar prezentari de confirmat
</label>
<input type="number" id="n-confirmat" name="n_confirmat"
value="{{ summary.get('ok', 0) }}"
min="0" required
style="max-width:80px;"
aria-describedby="n-hint">
<span id="n-hint" class="muted" style="font-size:12px; margin-left:6px;">
(<span id="n-hint-ok">{{ summary.get('ok', 0) }}</span> ok)
</span>
</div>
<div>
<label for="confirmed-by"
style="font-size:13px; color:var(--muted); display:block; margin-bottom:2px;">
Declarant (optional)
</label>
<input type="text" id="confirmed-by" name="confirmed_by"
placeholder="email sau nume"
style="max-width:200px;">
</div>
<div style="display:flex; gap:8px; align-items:center; flex-wrap:wrap;">
<label for="n-confirmat"
style="font-size:13px; color:var(--muted);">
Confirma numarul
</label>
<input type="number" id="n-confirmat" name="n_confirmat"
value="{{ summary.get('ok', 0) }}"
min="0" required
style="max-width:80px;"
aria-describedby="n-hint">
<span id="n-hint" class="muted" style="font-size:12px;">
din <span id="n-hint-ok">{{ summary.get('ok', 0) }}</span> gata de trimis
</span>
</div>
</div>
@@ -281,5 +288,18 @@
/* Filtru implicit "Toate" activ la incarcare */
filterRows('all');
updateN();
/* Evidentiere rand dupa reincarcarea preview-ului (window.__randSalvat setat de
listener-ul 'randSalvat' din base.html): scroll + flash, ca userul sa vada CARE
rand s-a schimbat si sa nu ramana cu impresia ca "nu s-a intamplat nimic". */
if (window.__randSalvat) {
var d = window.__randSalvat; window.__randSalvat = null;
var r = document.getElementById('preview-row-' + d.rowIndex);
if (r) {
r.scrollIntoView({block:'center', behavior:'smooth'});
void r.offsetWidth;
r.classList.add('rand-actualizat');
}
}
})();
</script>