Files
rar-autopass/app/web/templates/_chips_prestatii.html
Claude Agent 5a2c976d46 feat(web): UI compact Trimiteri + bara bulk contextuala + fix buton "+" editor (PRD 5.22)
Trimiteri desktop = tabel grid cu header, un rand per trimitere: status =
bulina cu tooltip, mediu = litera T/P, multi-cod = primul cod + badge +N,
sub-linie de eroare cu textul brut RAR doar pe error/needs_data. Mobil:
2 linii prin grid-areas, fara header. Actiunile bulk apar doar la selectie
(bara contextuala cu contor + texte explicite). Mapari: exemplu concret in
loc de descriere la Reguli automate.

Fix buton "+" chips (nu facea nimic, fara eroare): hx-disabled-elt="find
button" mostenit de la form-ul parinte crapa htmx inainte de request ->
hx-disabled-elt="this" explicit pe butoanele chips; separat, no-op-urile
silentioase din post_form_chips au acum mesaje (cod invalid/duplicat) si
confirmare cu chip evidentiat la succes.

Suita: 1622 passed. Verify E2E in browser (desktop 1280 + mobil 390).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 12:27:42 +00:00

250 lines
12 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{#
_chips_prestatii.html — sectiunea de prestatii chips (E4, server-driven via /form-chips).
Re-randata de endpoint-ul /form-chips la fiecare add/remove de chip.
Inclusa si din _form_editare.html pentru randarea initiala.
Starea chip-urilor traieste in input-uri hidden din form (NU in DB mid-edit).
Fiecare operatie are un picker propriu cand e nemapata (E4 binding op<->cod).
Reveal odometru initial semnalat prin data-has-r-odo="true" si chip-warn pe R-ODO/I-ODO.
Context vars (toate cu defaults):
prestatii_chips — list of {cod_prestatie, cod_op_service, denumire}
nomenclator_rar — list of {cod_prestatie, nume_prestatie} pentru picker
has_r_odo — True daca orice chip e R-ODO sau I-ODO (server-computed)
form_chips_url — URL pentru HTMX; default '/form-chips'
chips_section_id — ID div (default 'chips-section')
csrf_token — CSRF (trecut prin hx-include din form parinte)
#}
{% set _chips_url = form_chips_url or '/form-chips' %}
{% set _sec_id = chips_section_id or 'chips-section' %}
{% set _chips = prestatii_chips or [] %}
{% set _has_ops = _chips | selectattr('cod_op_service') | list | length > 0 %}
{# chips_submission_id e setat din _detaliu_ctx cand chips sunt randate in modalul de detaliu.
Lipseste cand _chips_prestatii.html e rerandat via /form-chips (stateless, fara submission). #}
{% set _sub_id = chips_submission_id if chips_submission_id is defined else none %}
<div id="{{ _sec_id }}" data-has-r-odo="{{ 'true' if has_r_odo else 'false' }}"
aria-live="polite" aria-label="Prestatii cod RAR">
{# ===== Input-uri hidden pentru starea curenta a chip-urilor =====
TOATE itemele emit 3 hidden inputs (cod poate fi "" pentru unmapped).
Paralele index-by-index: cod_prestatie[i], chip_op_service[i], chip_denumire[i].
Filtrate la submit de post_corectie_trimitere (coduri goale = neschimbate). #}
{% for chip in _chips %}
<input type="hidden" name="cod_prestatie" value="{{ chip.cod_prestatie or '' }}">
<input type="hidden" name="chip_op_service" value="{{ chip.cod_op_service or '' }}">
<input type="hidden" name="chip_denumire" value="{{ chip.denumire or '' }}">
{% endfor %}
<div class="camp-slim" style="margin-bottom:8px;">
<label>Prestatii — cod RAR pe fiecare operatie</label>
{% if _has_ops %}
{# ===== Mod operatii: UN picker PE operatie (E4 binding) ===== #}
{% for chip in _chips %}
{% if chip.cod_op_service %}
{% set _is_warn = chip.cod_prestatie in ('R-ODO', 'I-ODO') %}
{% set _nemapat = not chip.cod_prestatie %}
{% set _e_nou = (chips_added_cod is defined) and chips_added_cod and chip.cod_prestatie == chips_added_cod %}
<div class="op-row {% if _nemapat %}op-row-warn{% endif %}" style="margin-bottom:6px;">
<span class="op-row-name">
{{ chip.cod_op_service }}
{% if chip.denumire and chip.denumire != chip.cod_op_service %}
<span class="muted" style="font-weight:400;font-size:11px;"> — {{ chip.denumire }}</span>
{% endif %}
{% if _nemapat %}
<span style="color:var(--warn);font-size:10px;font-weight:400;"> · lipsa cod</span>
{% endif %}
</span>
<span style="display:flex;align-items:center;gap:8px;">
{% if chip.cod_prestatie %}
{# ===== Operatie mapata: chip cu × ===== #}
<span class="chip {% if _is_warn %}chip-warn{% endif %} {% if _e_nou %}chip-nou{% endif %}"
aria-label="Prestatie {{ chip.cod_prestatie }} adaugata pentru {{ chip.cod_op_service }}">
{{ chip.cod_prestatie }}
<button type="button" class="chip-del"
hx-post="{{ _chips_url }}"
hx-disabled-elt="this"
hx-include="closest form"
hx-target="#{{ _sec_id }}"
hx-swap="outerHTML"
hx-vals='{"chips_action":"remove","chips_remove_index":{{ loop.index0 }}}'
aria-label="Sterge codul {{ chip.cod_prestatie }} pentru {{ chip.cod_op_service }}">
&times;
</button>
</span>
{# "salveaza ca regula op->cod" — apare doar cand submission_id e cunoscut
(in modalul de detaliu, nu la re-randarea stateless via /form-chips).
Reuse EXACT save_mapping + reresolve_account via endpoint dedicat.
hx-include="closest form" propaga csrf_token din form-ul parinte. #}
<span id="save-rule-slot-{{ loop.index0 }}" class="save-rule-slot">
{% if _sub_id and chip.cod_op_service and chip.cod_prestatie %}
<button type="button"
style="font-size:10px;color:var(--muted);background:none;border:none;cursor:pointer;text-decoration:underline;padding:0;margin-left:4px;line-height:1;"
hx-post="/trimitere/{{ _sub_id }}/salveaza-regula-chip"
hx-disabled-elt="this"
hx-include="closest form"
hx-target="#detaliu-modal-body"
hx-swap="innerHTML"
hx-vals='{"salveaza_op":{{ chip.cod_op_service | tojson }},"salveaza_cod":{{ chip.cod_prestatie | tojson }}}'
aria-label="Salveaza regula {{ chip.cod_op_service }} -> {{ chip.cod_prestatie }}">
salveaza ca regula
</button>
{% endif %}
</span>
{% else %}
{# ===== Operatie nemapata: picker galben cu "alege cod RAR" ===== #}
<select name="chips_add_cod_{{ loop.index0 }}"
id="picker-op-{{ loop.index0 }}"
aria-label="Alege cod RAR pentru {{ chip.cod_op_service }}"
style="min-width:160px;font-size:11px;height:26px;">
<option value="">— alege cod RAR —</option>
{% for n in (nomenclator_rar or []) %}
<option value="{{ n.cod_prestatie }}">{{ n.cod_prestatie }} — {{ n.nume_prestatie }}</option>
{% endfor %}
</select>
<button type="button"
class="add-code"
hx-post="{{ _chips_url }}"
hx-disabled-elt="this"
hx-include="closest form"
hx-target="#{{ _sec_id }}"
hx-swap="outerHTML"
hx-vals='{"chips_action":"add","chips_add_op_index":{{ loop.index0 }}}'
aria-label="Adauga cod RAR pentru {{ chip.cod_op_service }}">
+ Adauga
</button>
{% endif %}
</span>
</div>
{% endif %}
{% endfor %}
{# ===== Chips extra + picker '+ Adauga alta operatie / cod RAR' in mod operatii ===== #}
{# Chips extra: cod_op_service gol, cod_prestatie setat — afisate flat cu × (reuse remove_flat).
Containerul .chips se randeaza DOAR cand exista chips extra — altfel ramanea
un chenar gol nefinisat sub randurile de operatie. #}
{% set _extra_chips = _chips | rejectattr('cod_op_service') | selectattr('cod_prestatie') | list %}
{% if _extra_chips %}
<div class="chips" role="group" aria-label="Coduri RAR suplimentare" style="margin-top:4px;">
{% for chip in _extra_chips %}
{% set _is_warn_extra = chip.cod_prestatie in ('R-ODO', 'I-ODO') %}
{% set _e_nou_extra = (chips_added_cod is defined) and chips_added_cod and chip.cod_prestatie == chips_added_cod %}
<span class="chip {% if _is_warn_extra %}chip-warn{% endif %} {% if _e_nou_extra %}chip-nou{% endif %}"
aria-label="Cod RAR suplimentar {{ chip.cod_prestatie }}">
{{ chip.cod_prestatie }}
<button type="button" class="chip-del"
hx-post="{{ _chips_url }}"
hx-disabled-elt="this"
hx-include="closest form"
hx-target="#{{ _sec_id }}"
hx-swap="outerHTML"
hx-vals='{"chips_action":"remove_flat","chips_remove_cod":"{{ chip.cod_prestatie }}"}'
aria-label="Sterge codul suplimentar {{ chip.cod_prestatie }}">&times;</button>
</span>
{% endfor %}
</div>
{% endif %}
{% if nomenclator_rar %}
<span style="display:inline-flex;align-items:center;gap:4px;margin-top:4px;">
<select name="chips_add_cod_flat"
aria-label="Adauga cod RAR suplimentar"
style="min-width:160px;font-size:11px;height:26px;border:1px dashed color-mix(in srgb,var(--accent) 55%,var(--line));border-radius:5px;background:transparent;color:var(--accent);">
<option value="">+ Adauga alta operatie / cod RAR</option>
{% for n in nomenclator_rar %}
<option value="{{ n.cod_prestatie }}">{{ n.cod_prestatie }} — {{ n.nume_prestatie }}</option>
{% endfor %}
</select>
<button type="button"
class="add-code"
hx-post="{{ _chips_url }}"
hx-disabled-elt="this"
hx-include="closest form"
hx-target="#{{ _sec_id }}"
hx-swap="outerHTML"
hx-vals='{"chips_action":"add_extra"}'
aria-label="Adauga cod RAR suplimentar la trimitere">
+
</button>
</span>
{% else %}
{# T-D1/T-E5 (5.16): empty state in mod operatii cand nomenclatorul lipseste #}
<div class="chips-nom-gol" style="font-size:11px;color:var(--warn);padding:4px 0;margin-top:4px;">
Nomenclator indisponibil — adaugarea de coduri suplimentare nu e posibila.
</div>
{% endif %}
{% else %}
{# ===== Mod plat: lista de coduri libere (corectie pura, fara op_service) ===== #}
<div class="chips" role="group" aria-label="Coduri RAR selectate">
{% for chip in _chips %}
{% if chip.cod_prestatie %}
{% set _is_warn_flat = chip.cod_prestatie in ('R-ODO', 'I-ODO') %}
{% set _e_nou_flat = (chips_added_cod is defined) and chips_added_cod and chip.cod_prestatie == chips_added_cod %}
<span class="chip {% if _is_warn_flat %}chip-warn{% endif %} {% if _e_nou_flat %}chip-nou{% endif %}"
aria-label="Prestatie {{ chip.cod_prestatie }}">
{{ chip.cod_prestatie }}
<button type="button" class="chip-del"
hx-post="{{ _chips_url }}"
hx-disabled-elt="this"
hx-include="closest form"
hx-target="#{{ _sec_id }}"
hx-swap="outerHTML"
hx-vals='{"chips_action":"remove_flat","chips_remove_cod":"{{ chip.cod_prestatie }}"}'
aria-label="Sterge codul {{ chip.cod_prestatie }}">&times;</button>
</span>
{% endif %}
{% endfor %}
{# Picker adaugare cod nou in mod plat #}
{% if nomenclator_rar %}
<span style="display:inline-flex;align-items:center;gap:4px;">
<select name="chips_add_cod_flat"
aria-label="Adauga cod RAR nou"
style="font-size:11px;height:22px;border:1px dashed color-mix(in srgb,var(--accent) 55%,var(--line));border-radius:5px;background:transparent;color:var(--accent);">
<option value="">+ cod</option>
{% for n in nomenclator_rar %}
<option value="{{ n.cod_prestatie }}">{{ n.cod_prestatie }} — {{ n.nume_prestatie }}</option>
{% endfor %}
</select>
<button type="button"
class="add-code"
hx-post="{{ _chips_url }}"
hx-disabled-elt="this"
hx-include="closest form"
hx-target="#{{ _sec_id }}"
hx-swap="outerHTML"
hx-vals='{"chips_action":"add_flat"}'
aria-label="Adauga cod RAR selectat in lista">
+
</button>
</span>
{% else %}
{# T-D1/T-E5 (5.16): empty state in mod plat cand nomenclatorul lipseste #}
<div class="chips-nom-gol" style="font-size:11px;color:var(--warn);padding:4px 0;">
Nomenclator indisponibil — nu se pot adauga coduri RAR momentan.
</div>
{% endif %}
</div>
{% endif %}
{# Rezultatul ultimei adaugari, in ambele moduri: refuz (rol=alert) sau confirmare.
Clasa chips-extra-error pastrata pe eroare (selector stabil pentru teste/QA). #}
{% if chips_error is defined and chips_error %}
<div class="chips-extra-error" style="font-size:11px;color:var(--err);padding:2px 0;" role="alert">
{{ chips_error }}
</div>
{% elif chips_ok is defined and chips_ok %}
<div class="chips-adaugat-ok" style="font-size:11px;color:var(--ok);padding:2px 0;" role="status">
{{ chips_ok }}
</div>
{% endif %}
{# Hint discret fara chips (debut) #}
{% if not _chips %}
<div style="font-size:10px;color:var(--muted);padding:4px 0;">
Niciun cod RAR inca — alege din picker (sus) sau adauga prin mapare.
</div>
{% endif %}
</div>
</div>