feat(setari): pagina Setari compacta — 3 sub-taburi, plan clarificat, copy scurt

- Date firma mutat in sub-tabul Cont (date firma + plan + parola); 3 taburi in loc de 4
- Plan afisat o singura data (tier bold + consum) cu bara de progres; fara dublarea 'Plan curent'/'Plan:'
- Copy Credentiale RAR redus la un rand; confirmare Productie scurtata; parola setata are placeholder distinct
- Formulare compacte pe 2 coloane (setari-fgrid), titluri de sectiune uppercase mici, microcopy langa butoane
- activ_subtab implicit 'firma' -> 'cont'; 'firma' vechi mapat defensiv la 'cont'

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Claude Agent
2026-07-06 16:53:05 +00:00
parent e2627c1aa4
commit d7adeaf382
3 changed files with 157 additions and 131 deletions

View File

@@ -464,7 +464,7 @@ def _render_panel_cont(request: Request, conn, account_id: int) -> str:
"account_meta": account_meta, "account_meta": account_meta,
"date_firma_mesaj": None, "date_firma_mesaj": None,
"date_firma_eroare": None, "date_firma_eroare": None,
"activ_subtab": "firma", "activ_subtab": "cont",
"parola_mesaj": None, "parola_mesaj": None,
"parola_eroare": None, "parola_eroare": None,
"creds_test_mesaj": None, "creds_test_mesaj": None,
@@ -4507,9 +4507,9 @@ def _render_cont(
date_firma_mesaj: str | None = None, date_firma_mesaj: str | None = None,
date_firma_eroare: str | None = None, date_firma_eroare: str | None = None,
are_cheie: bool = False, are_cheie: bool = False,
# Sub-tab activ dupa re-randare: 'firma' | 'rar' | 'api' | 'cont'. # Sub-tab activ dupa re-randare: 'cont' | 'rar' | 'api'.
# Fiecare handler POST intoarce sub-tabul propriu, ca swap-ul HTMX sa nu resete la firma. # Fiecare handler POST intoarce sub-tabul propriu, ca swap-ul HTMX sa nu resete la primul.
activ_subtab: str = "firma", activ_subtab: str = "cont",
# Schimbare parola de acces (sub-tab Cont). # Schimbare parola de acces (sub-tab Cont).
parola_mesaj: str | None = None, parola_mesaj: str | None = None,
parola_eroare: str | None = None, parola_eroare: str | None = None,
@@ -4985,7 +4985,7 @@ async def cont_rar_medii(request: Request) -> HTMLResponse:
if prod_enabled_form and not was_prod_enabled and not prod_confirmare: if prod_enabled_form and not was_prod_enabled and not prod_confirmare:
creds_prod_eroare = ( creds_prod_eroare = (
"Bifati confirmarea de mai jos pentru a activa mediul Productie: " "Bifati confirmarea de mai jos pentru a activa mediul Productie: "
"\"Inteleg ca trimiterile pe Productie sunt declaratii reale (L.142)\"." "\"Confirm: trimiterile pe Productie sunt declaratii reale (L.142)\"."
) )
account_meta = _fetch_account_meta(conn, acct) account_meta = _fetch_account_meta(conn, acct)
env_ctx = _fetch_cont_env_state(conn, acct) env_ctx = _fetch_cont_env_state(conn, acct)

View File

@@ -1,80 +1,138 @@
{# Pagina Setari: sub-taburi interne — Date firma / Credentiale RAR / Cheie API / {# Pagina Setari: sub-taburi interne — Cont (date firma + plan + parola) /
Cont (plan + parola). `activ_subtab` (server) alege panoul activ dupa fiecare Credentiale RAR / Cheie API. `activ_subtab` (server) alege panoul activ dupa fiecare
swap HTMX, ca re-randarea sa nu resete la primul tab. Comutarea intre taburi swap HTMX, ca re-randarea sa nu resete la primul tab. Comutarea intre taburi
fara server = JS delegat in base.html (#card-cont). #} fara server = JS delegat in base.html (#card-cont). #}
{% set _firma_ok = account_meta.name and account_meta.email and account_meta.cui %} {% set _firma_ok = account_meta.name and account_meta.email and account_meta.cui %}
{% set _rar_ok = medii_disponibile and medii_disponibile|length > 0 %} {% set _rar_ok = medii_disponibile and medii_disponibile|length > 0 %}
<div class="card" id="card-cont" data-activ-subtab="{{ activ_subtab|default('firma') }}"> {% set _subtab = activ_subtab|default('cont') %}
<div class="setari-head"> {% if _subtab == 'firma' %}{% set _subtab = 'cont' %}{% endif %}
<h2 class="setari-title"> <div class="card" id="card-cont" data-activ-subtab="{{ _subtab }}">
<svg class="ic" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="3"/><path d="M12 2v3M12 19v3M2 12h3M19 12h3M4.6 4.6l2.1 2.1M17.3 17.3l2.1 2.1M4.6 19.4l2.1-2.1M17.3 6.7l2.1-2.1"/></svg> <h2 class="setari-title">
Setari <svg class="ic" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="3"/><path d="M12 2v3M12 19v3M2 12h3M19 12h3M4.6 4.6l2.1 2.1M17.3 17.3l2.1 2.1M4.6 19.4l2.1-2.1M17.3 6.7l2.1-2.1"/></svg>
</h2> Setari
<p class="setari-sub">Datele firmei, credentialele RAR, cheia API si contul tau.</p> </h2>
</div>
<div class="setari-subtabs" role="tablist" aria-label="Sectiuni setari"> <div class="setari-subtabs" role="tablist" aria-label="Sectiuni setari">
<button type="button" class="setari-subtab{{ ' is-active' if activ_subtab|default('firma') == 'firma' else '' }}" role="tab" data-subtab="firma" <button type="button" class="setari-subtab{{ ' is-active' if _subtab == 'cont' else '' }}" role="tab" data-subtab="cont"
aria-selected="{{ 'true' if activ_subtab|default('firma') == 'firma' else 'false' }}"> aria-selected="{{ 'true' if _subtab == 'cont' else 'false' }}">
<span class="st-dot {{ 'ok' if _firma_ok else 'warn' }}" aria-hidden="true"></span>Date firma</button> <span class="st-dot {{ 'ok' if _firma_ok else 'warn' }}" aria-hidden="true"></span>Cont</button>
<button type="button" class="setari-subtab{{ ' is-active' if activ_subtab|default('firma') == 'rar' else '' }}" role="tab" data-subtab="rar" <button type="button" class="setari-subtab{{ ' is-active' if _subtab == 'rar' else '' }}" role="tab" data-subtab="rar"
aria-selected="{{ 'true' if activ_subtab|default('firma') == 'rar' else 'false' }}"> aria-selected="{{ 'true' if _subtab == 'rar' else 'false' }}">
<span class="st-dot {{ 'ok' if _rar_ok else 'warn' }}" aria-hidden="true"></span>Credentiale RAR</button> <span class="st-dot {{ 'ok' if _rar_ok else 'warn' }}" aria-hidden="true"></span>Credentiale RAR</button>
<button type="button" class="setari-subtab{{ ' is-active' if activ_subtab|default('firma') == 'api' else '' }}" role="tab" data-subtab="api" <button type="button" class="setari-subtab{{ ' is-active' if _subtab == 'api' else '' }}" role="tab" data-subtab="api"
aria-selected="{{ 'true' if activ_subtab|default('firma') == 'api' else 'false' }}"> aria-selected="{{ 'true' if _subtab == 'api' else 'false' }}">
<span class="st-dot {{ 'ok' if are_cheie else 'warn' }}" aria-hidden="true"></span>Cheie API</button> <span class="st-dot {{ 'ok' if are_cheie else 'warn' }}" aria-hidden="true"></span>Cheie API</button>
<button type="button" class="setari-subtab{{ ' is-active' if activ_subtab|default('firma') == 'cont' else '' }}" role="tab" data-subtab="cont"
aria-selected="{{ 'true' if activ_subtab|default('firma') == 'cont' else 'false' }}">
<span class="st-dot info" aria-hidden="true"></span>Cont</button>
</div> </div>
{# ============================ Sub-tab: Date firma ============================ #} {# ================= Sub-tab: Cont (date firma + plan + parola) ================ #}
<div class="setari-pane" data-subpane="firma" role="tabpanel" <div class="setari-pane" data-subpane="cont" role="tabpanel"
{% if activ_subtab|default('firma') != 'firma' %}hidden{% endif %}> {% if _subtab != 'cont' %}hidden{% endif %}>
{# --- Date firma --- #}
<div class="setari-zone-title"> <div class="setari-zone-title">
<svg class="ic" viewBox="0 0 24 24" aria-hidden="true"><path d="M4 21V4a1 1 0 0 1 1-1h9a1 1 0 0 1 1 1v17"/><path d="M15 9h4a1 1 0 0 1 1 1v11"/><path d="M2 21h20"/><path d="M8 7h3M8 11h3M8 15h3"/></svg> <svg class="ic" viewBox="0 0 24 24" aria-hidden="true"><path d="M4 21V4a1 1 0 0 1 1-1h9a1 1 0 0 1 1 1v17"/><path d="M15 9h4a1 1 0 0 1 1 1v11"/><path d="M2 21h20"/><path d="M8 7h3M8 11h3M8 15h3"/></svg>
Date firma Date firma
<span class="setari-badge {{ 'sb-ok' if _firma_ok else 'sb-warn' }}">{{ 'complet' if _firma_ok else 'incomplet' }}</span> <span class="setari-badge {{ 'sb-ok' if _firma_ok else 'sb-warn' }}">{{ 'complet' if _firma_ok else 'incomplet' }}</span>
</div> </div>
<p class="setari-zone-desc">Apar pe declaratiile catre RAR si pe facturile de plan.</p>
{% if date_firma_mesaj %}<div class="flash" style="margin-bottom:12px;">{{ date_firma_mesaj }}</div>{% endif %} {% if date_firma_mesaj %}<div class="flash" style="margin-bottom:12px;">{{ date_firma_mesaj }}</div>{% endif %}
{% if date_firma_eroare %}<div class="banner" style="margin-bottom:12px; padding:8px 12px;">{{ date_firma_eroare }}</div>{% endif %} {% if date_firma_eroare %}<div class="banner" style="margin-bottom:12px; padding:8px 12px;">{{ date_firma_eroare }}</div>{% endif %}
<form hx-post="/cont/date-firma" hx-target="#card-cont" hx-swap="outerHTML"> <form hx-post="/cont/date-firma" hx-target="#card-cont" hx-swap="outerHTML">
<input type="hidden" name="csrf_token" value="{{ csrf_token }}"> <input type="hidden" name="csrf_token" value="{{ csrf_token }}">
<p style="margin:0 0 8px;"> <div class="setari-fgrid">
<label style="font-size:13px; color:var(--muted);">Companie</label><br> <div>
<input type="text" name="companie" required value="{{ account_meta.name or '' }}" <label for="df-companie">Companie</label>
style="width:100%; max-width:340px;" placeholder="Numele firmei (ex. Service Auto SRL)"> <input id="df-companie" type="text" name="companie" required value="{{ account_meta.name or '' }}"
</p> placeholder="Numele firmei (ex. Service Auto SRL)">
<p style="margin:0 0 8px;"> </div>
<label style="font-size:13px; color:var(--muted);">Email contact</label><br> <div>
<input type="email" name="email" required value="{{ account_meta.email or '' }}" <label for="df-cui">CUI</label>
style="width:100%; max-width:340px;" placeholder="contact@firma.ro"> <input id="df-cui" type="text" name="cui" required value="{{ account_meta.cui or '' }}"
</p> placeholder="RO12345678">
<p style="margin:0 0 12px;"> </div>
<label style="font-size:13px; color:var(--muted);">CUI (cod unic de identificare)</label><br> <div class="fg-full">
<input type="text" name="cui" required value="{{ account_meta.cui or '' }}" <label for="df-email">Email contact</label>
style="width:100%; max-width:340px;" placeholder="RO12345678"> <input id="df-email" type="email" name="email" required value="{{ account_meta.email or '' }}"
</p> placeholder="contact@firma.ro">
<button type="submit">Salveaza datele firmei</button> </div>
</div>
<div class="setari-btn-row">
<button type="submit">Salveaza</button>
<span class="setari-micro">Apar pe declaratiile RAR si pe facturi.</span>
</div>
</form>
{# --- Plan --- #}
{% if plan_linie is defined %}
<hr class="setari-subzone-sep">
<div id="sectiune-plan" class="setari-zone-title">
<svg class="ic" viewBox="0 0 24 24" aria-hidden="true"><path d="M12 3 3 8l9 5 9-5z"/><path d="M3 13l9 5 9-5"/></svg>
Plan
</div>
{# plan_linie vine ca "Plan: <tier> · <detaliu>"; aici tier-ul apare O data, bold. #}
{% set _plan_text = plan_linie|replace('Plan: ', '', 1) %}
{% set _plan_parts = _plan_text.split(' · ', 1) %}
<div class="plan-row">
<span class="plan-tier">{{ _plan_parts[0] }}</span>
{% if _plan_parts|length > 1 %}
<span class="plan-usage" style="{% if plan_limita_atinsa|default(false) %}color:var(--err); font-weight:600;{% elif plan_warn|default(false) %}color:var(--warn); font-weight:600;{% endif %}">{{ _plan_parts[1] }}</span>
{% endif %}
</div>
{% if monthly_limit_val|default(none) and usage_lunar is defined %}
{% set _pct = (usage_lunar / monthly_limit_val * 100)|round|int %}
<div class="plan-meter" role="progressbar" aria-valuenow="{{ usage_lunar }}" aria-valuemin="0"
aria-valuemax="{{ monthly_limit_val }}" aria-label="Consum plan luna curenta">
<span style="width:{{ [_pct, 100]|min }}%;{% if plan_limita_atinsa|default(false) %} background:var(--err);{% elif plan_warn|default(false) %} background:var(--warn);{% endif %}"></span>
</div>
{% endif %}
{% if plan_limita_atinsa|default(false) %}
<p class="setari-micro" style="color:var(--err); margin:0 0 6px;">Limita lunara atinsa — trimiterile noi sunt blocate pana luna viitoare.</p>
{% endif %}
<p class="setari-micro" style="margin:0;">Pentru mai mult volum sau acces API, <a href="mailto:contact@romfast.ro">contacteaza-ne</a>.</p>
{% endif %}
{# --- Parola de acces --- #}
<hr class="setari-subzone-sep">
<div class="setari-zone-title">
<svg class="ic" viewBox="0 0 24 24" aria-hidden="true"><rect x="4" y="10" width="16" height="11" rx="2"/><path d="M8 10V7a4 4 0 0 1 8 0v3"/><circle cx="12" cy="15.5" r="1.2"/></svg>
Parola de acces
</div>
<p class="setari-zone-desc">Parola dashboard-ului — separata de credentialele RAR. Minim 10 caractere.</p>
{% if parola_mesaj %}<div class="flash" style="margin-bottom:12px;">{{ parola_mesaj }}</div>{% endif %}
{% if parola_eroare %}<div class="banner" style="margin-bottom:12px; padding:8px 12px;">{{ parola_eroare }}</div>{% endif %}
<form hx-post="/cont/schimba-parola" hx-target="#card-cont" hx-swap="outerHTML">
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
<div class="setari-fgrid">
<div class="fg-full" style="max-width:273px;">
<label for="pw-actuala">Parola actuala</label>
<input id="pw-actuala" type="password" name="parola_actuala" autocomplete="current-password">
</div>
<div>
<label for="pw-noua">Parola noua</label>
<input id="pw-noua" type="password" name="parola_noua" autocomplete="new-password">
</div>
<div>
<label for="pw-confirma">Confirma parola noua</label>
<input id="pw-confirma" type="password" name="parola_confirma" autocomplete="new-password">
</div>
</div>
<button type="submit">Schimba parola</button>
</form> </form>
</div> </div>
{# ========================= Sub-tab: Credentiale RAR ========================= #} {# ========================= Sub-tab: Credentiale RAR ========================= #}
<div class="setari-pane" data-subpane="rar" role="tabpanel" <div class="setari-pane" data-subpane="rar" role="tabpanel"
{% if activ_subtab|default('firma') != 'rar' %}hidden{% endif %}> {% if _subtab != 'rar' %}hidden{% endif %}>
<div class="setari-zone-title"> <div class="setari-zone-title">
<svg class="ic" viewBox="0 0 24 24" aria-hidden="true"><path d="M5 11l1.5-4A2 2 0 0 1 8.4 5.6h7.2A2 2 0 0 1 17.5 7L19 11"/><path d="M4 11h16v6H4z"/><path d="M6 17v2M18 17v2"/><circle cx="7.5" cy="14" r="1"/><circle cx="16.5" cy="14" r="1"/></svg> <svg class="ic" viewBox="0 0 24 24" aria-hidden="true"><path d="M5 11l1.5-4A2 2 0 0 1 8.4 5.6h7.2A2 2 0 0 1 17.5 7L19 11"/><path d="M4 11h16v6H4z"/><path d="M6 17v2M18 17v2"/><circle cx="7.5" cy="14" r="1"/><circle cx="16.5" cy="14" r="1"/></svg>
Credentiale RAR (portal AUTOPASS) Credentiale RAR
<span class="setari-badge {{ 'sb-ok' if _rar_ok else 'sb-warn' }}">{{ 'configurat' if _rar_ok else 'neconfigurat' }}</span> <span class="setari-badge {{ 'sb-ok' if _rar_ok else 'sb-warn' }}">{{ 'configurat' if _rar_ok else 'neconfigurat' }}</span>
</div> </div>
<p class="setari-zone-desc"> <p class="setari-zone-desc">
Configureaza mediile RAR — Testare si/sau Productie — fiecare cu credentialele lui, Fiecare mediu are propriile credentiale, verificate la salvare. Trimiterile merg doar pe mediile active.
validate separat la salvare pe sistemul RAR corespunzator. Un mediu devine activ cand e
bifat si are credentiale; abia atunci importul web poate trimite pe el. (Canalul API ramane
pe mediul global al instantei, {{ mediu_instanta() }}, pentru ca isi cara singur credentialele.)
</p> </p>
{% if creds_mesaj %}<div class="flash" style="margin-bottom:12px;">{{ creds_mesaj }}</div>{% endif %} {% if creds_mesaj %}<div class="flash" style="margin-bottom:12px;">{{ creds_mesaj }}</div>{% endif %}
@@ -93,10 +151,11 @@
<input type="checkbox" name="test_enabled" value="1" {% if test_enabled %}checked{% endif %}> <input type="checkbox" name="test_enabled" value="1" {% if test_enabled %}checked{% endif %}>
Activare Testare Activare Testare
</label> </label>
<label class="env-lbl">Email RAR Testare</label> <label class="env-lbl" for="rar-test-email">Email RAR Testare</label>
<input type="email" name="test_email" placeholder="email@service.ro"> <input id="rar-test-email" type="email" name="test_email" placeholder="email@service.ro">
<label class="env-lbl">Parola RAR Testare</label> <label class="env-lbl" for="rar-test-parola">Parola RAR Testare</label>
<input type="password" name="test_parola" autocomplete="new-password"> <input id="rar-test-parola" type="password" name="test_parola" autocomplete="new-password"
{% if test_disponibil %}placeholder="&bull;&bull;&bull;&bull;&bull;&bull;&bull;&bull; (setata)"{% endif %}>
{% if creds_test_mesaj %}<div class="flash" style="margin-top:6px;">{{ creds_test_mesaj }}</div>{% endif %} {% if creds_test_mesaj %}<div class="flash" style="margin-top:6px;">{{ creds_test_mesaj }}</div>{% endif %}
{% if creds_test_eroare %}<div class="banner" style="margin-top:6px; padding:8px 12px;">{{ creds_test_eroare }}</div>{% endif %} {% if creds_test_eroare %}<div class="banner" style="margin-top:6px; padding:8px 12px;">{{ creds_test_eroare }}</div>{% endif %}
</div> </div>
@@ -110,13 +169,14 @@
<input type="checkbox" name="prod_enabled" value="1" {% if prod_enabled %}checked{% endif %}> <input type="checkbox" name="prod_enabled" value="1" {% if prod_enabled %}checked{% endif %}>
Activare Productie Activare Productie
</label> </label>
<label class="env-lbl">Email RAR Productie</label> <label class="env-lbl" for="rar-prod-email">Email RAR Productie</label>
<input type="email" name="prod_email" placeholder="email@service.ro"> <input id="rar-prod-email" type="email" name="prod_email" placeholder="email@service.ro">
<label class="env-lbl">Parola RAR Productie</label> <label class="env-lbl" for="rar-prod-parola">Parola RAR Productie</label>
<input type="password" name="prod_parola" autocomplete="new-password"> <input id="rar-prod-parola" type="password" name="prod_parola" autocomplete="new-password"
{% if prod_disponibil %}placeholder="&bull;&bull;&bull;&bull;&bull;&bull;&bull;&bull; (setata)"{% endif %}>
<label class="env-confirm"> <label class="env-confirm">
<input type="checkbox" name="prod_confirmare" value="1"> <input type="checkbox" name="prod_confirmare" value="1">
<span>Inteleg ca trimiterile pe Productie sunt declaratii reale (L.142), finale si fara anulare.</span> <span>Confirm: trimiterile pe Productie sunt declaratii reale (L.142), finale si fara anulare.</span>
</label> </label>
{% if creds_prod_mesaj %}<div class="flash" style="margin-top:6px;">{{ creds_prod_mesaj }}</div>{% endif %} {% if creds_prod_mesaj %}<div class="flash" style="margin-top:6px;">{{ creds_prod_mesaj }}</div>{% endif %}
{% if creds_prod_eroare %}<div class="banner" style="margin-top:6px; padding:8px 12px;">{{ creds_prod_eroare }}</div>{% endif %} {% if creds_prod_eroare %}<div class="banner" style="margin-top:6px; padding:8px 12px;">{{ creds_prod_eroare }}</div>{% endif %}
@@ -124,9 +184,9 @@
</div> </div>
<div class="default-env"> <div class="default-env">
<label style="font-size:13px; color:var(--muted);">Mediu implicit pentru trimiteri</label> <label for="rar-env-default" style="font-size:13px; color:var(--muted);">Mediu implicit pentru trimiteri</label>
{% if medii_disponibile %} {% if medii_disponibile %}
<select name="rar_env_default"> <select id="rar-env-default" name="rar_env_default">
{% for env in medii_disponibile %} {% for env in medii_disponibile %}
<option value="{{ env }}"{% if env == rar_env_default %} selected{% endif %}>{{ "Testare" if env == "test" else "Productie" }}</option> <option value="{{ env }}"{% if env == rar_env_default %} selected{% endif %}>{{ "Testare" if env == "test" else "Productie" }}</option>
{% endfor %} {% endfor %}
@@ -138,22 +198,23 @@
{% if creds_default_eroare %}<div class="banner" style="margin-top:6px; padding:8px 12px; flex-basis:100%;">{{ creds_default_eroare }}</div>{% endif %} {% if creds_default_eroare %}<div class="banner" style="margin-top:6px; padding:8px 12px; flex-basis:100%;">{{ creds_default_eroare }}</div>{% endif %}
</div> </div>
<button type="submit">Salveaza mediile RAR</button> <div class="setari-btn-row">
<span style="font-size:12px; color:var(--muted); margin-left:8px;">Parolele stocate criptat, niciodata in clar.</span> <button type="submit">Salveaza</button>
<span class="setari-micro">Parolele se stocheaza criptat.</span>
</div>
</form> </form>
</div> </div>
{# ============================ Sub-tab: Cheie API ============================ #} {# ============================ Sub-tab: Cheie API ============================ #}
<div class="setari-pane" data-subpane="api" role="tabpanel" <div class="setari-pane" data-subpane="api" role="tabpanel"
{% if activ_subtab|default('firma') != 'api' %}hidden{% endif %}> {% if _subtab != 'api' %}hidden{% endif %}>
<div class="setari-zone-title"> <div class="setari-zone-title">
<svg class="ic" viewBox="0 0 24 24" aria-hidden="true"><circle cx="8" cy="15" r="4"/><path d="M11 12l9-9"/><path d="M17 6l2.5 2.5M14 9l2.5 2.5"/></svg> <svg class="ic" viewBox="0 0 24 24" aria-hidden="true"><circle cx="8" cy="15" r="4"/><path d="M11 12l9-9"/><path d="M17 6l2.5 2.5M14 9l2.5 2.5"/></svg>
Cheie API Cheie API
<span class="setari-badge {{ 'sb-ok' if are_cheie else 'sb-warn' }}">{{ 'activa' if are_cheie else 'lipsa' }}</span> <span class="setari-badge {{ 'sb-ok' if are_cheie else 'sb-warn' }}">{{ 'activa' if are_cheie else 'lipsa' }}</span>
</div> </div>
<p class="setari-zone-desc"> <p class="setari-zone-desc">
O foloseste softul propriu / ROAAUTO ca sa trimita prezentari prin API. Se vede integral o Pentru trimiteri din softul propriu / ROAAUTO. Se afiseaza integral o singura data.
singura data, la creare sau rotire.
</p> </p>
{% if api_key %} {% if api_key %}
@@ -164,9 +225,6 @@
onclick="navigator.clipboard.writeText(this.dataset.key).then(()=>this.textContent='Copiat!')"> onclick="navigator.clipboard.writeText(this.dataset.key).then(()=>this.textContent='Copiat!')">
Copiaza cheia Copiaza cheia
</button> </button>
<p style="font-size:13px; color:var(--warn); margin:10px 0 0;">
Atentie: la urmatoarea vizita aceasta cheie dispare. Daca o pierzi, roteste din nou.
</p>
{% endif %} {% endif %}
{% if rot_eroare %}<div class="banner" style="margin:12px 0; padding:8px 12px;">{{ rot_eroare }}</div>{% endif %} {% if rot_eroare %}<div class="banner" style="margin:12px 0; padding:8px 12px;">{{ rot_eroare }}</div>{% endif %}
@@ -174,62 +232,10 @@
<form hx-post="/cont/roteste-cheie" hx-target="#card-cont" hx-swap="outerHTML" <form hx-post="/cont/roteste-cheie" hx-target="#card-cont" hx-swap="outerHTML"
style="margin-top:{% if api_key %}14px{% else %}0{% endif %};"> style="margin-top:{% if api_key %}14px{% else %}0{% endif %};">
<input type="hidden" name="csrf_token" value="{{ csrf_token }}"> <input type="hidden" name="csrf_token" value="{{ csrf_token }}">
<button type="submit" class="btn-warn">{{ 'Roteste cheia API' if are_cheie else 'Genereaza cheia API' }}</button> <div class="setari-btn-row">
<span style="font-size:12px; color:var(--muted); margin-left:8px;">Cheia veche se revoca imediat.</span> <button type="submit" class="btn-warn">{{ 'Roteste cheia API' if are_cheie else 'Genereaza cheia API' }}</button>
</form> <span class="setari-micro">Rotirea revoca imediat cheia veche.</span>
</div> </div>
{# ========================= Sub-tab: Cont (plan + parola) ==================== #}
<div class="setari-pane" data-subpane="cont" role="tabpanel"
{% if activ_subtab|default('firma') != 'cont' %}hidden{% endif %}>
{# --- Plan curent --- #}
{% if plan_linie is defined %}
<div class="setari-zone-title">
<svg class="ic" viewBox="0 0 24 24" aria-hidden="true"><path d="M12 3 3 8l9 5 9-5z"/><path d="M3 13l9 5 9-5"/></svg>
Plan curent
<span class="setari-badge sb-info">{{ tier_label|default('Gratuit') }}</span>
</div>
<div style="font-size:var(--fs-md); font-weight:600; margin-bottom:6px;
color:{% if plan_limita_atinsa|default(false) %}var(--err){% elif plan_warn|default(false) %}var(--warn){% else %}var(--ink){% endif %};">
{{ plan_linie }}
</div>
{% if plan_limita_atinsa|default(false) %}
<p class="setari-zone-desc" style="color:var(--err);">Limita lunara a fost atinsa — trimiterile noi sunt blocate pana la inceputul lunii urmatoare.</p>
{% elif plan_warn|default(false) %}
<p class="setari-zone-desc" style="color:var(--warn);">Te apropii de limita lunara.</p>
{% endif %}
<p class="setari-zone-desc">
Pentru mai mult volum sau import prin API, <a href="mailto:contact@romfast.ro">contacteaza-ne</a> — alocarea planurilor se face manual.
</p>
<hr class="setari-subzone-sep">
{% endif %}
{# --- Parola de acces --- #}
<div class="setari-zone-title">
<svg class="ic" viewBox="0 0 24 24" aria-hidden="true"><rect x="4" y="10" width="16" height="11" rx="2"/><path d="M8 10V7a4 4 0 0 1 8 0v3"/><circle cx="12" cy="15.5" r="1.2"/></svg>
Parola de acces
</div>
<p class="setari-zone-desc">Parola cu care te autentifici in dashboard (separata de credentialele RAR). Minim 10 caractere.</p>
{% if parola_mesaj %}<div class="flash" style="margin-bottom:12px;">{{ parola_mesaj }}</div>{% endif %}
{% if parola_eroare %}<div class="banner" style="margin-bottom:12px; padding:8px 12px;">{{ parola_eroare }}</div>{% endif %}
<form hx-post="/cont/schimba-parola" hx-target="#card-cont" hx-swap="outerHTML">
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
<p style="margin:0 0 8px;">
<label style="font-size:13px; color:var(--muted);">Parola actuala</label><br>
<input type="password" name="parola_actuala" autocomplete="current-password" style="width:100%; max-width:340px;">
</p>
<p style="margin:0 0 8px;">
<label style="font-size:13px; color:var(--muted);">Parola noua</label><br>
<input type="password" name="parola_noua" autocomplete="new-password" style="width:100%; max-width:340px;">
</p>
<p style="margin:0 0 12px;">
<label style="font-size:13px; color:var(--muted);">Confirma parola noua</label><br>
<input type="password" name="parola_confirma" autocomplete="new-password" style="width:100%; max-width:340px;">
</p>
<button type="submit">Schimba parola</button>
</form> </form>
</div> </div>
</div> </div>

View File

@@ -857,10 +857,30 @@
.st-dot.warn { background:var(--warn); } .st-dot.warn { background:var(--warn); }
.st-dot.info { background:var(--muted); } .st-dot.info { background:var(--muted); }
.setari-pane[hidden] { display:none; } .setari-pane[hidden] { display:none; }
.setari-zone-title { font-size:var(--fs-md); font-weight:600; margin:0 0 4px; display:flex; /* Titlu de sectiune compact (uppercase mic) — ierarhie sub titlul paginii, nu concurenta cu el. */
align-items:center; gap:10px; flex-wrap:wrap; } .setari-zone-title { font-size:var(--fs-xs); font-weight:600; text-transform:uppercase;
.setari-zone-title .ic { opacity:.7; } letter-spacing:.07em; color:var(--muted); margin:0 0 10px; display:flex;
.setari-zone-desc { color:var(--muted); font-size:var(--fs-sm); margin:0 0 16px; max-width:64ch; line-height:1.5; } align-items:center; gap:8px; flex-wrap:wrap; }
.setari-zone-title .ic { opacity:.7; width:15px; height:15px; }
.setari-zone-title .setari-badge { text-transform:none; letter-spacing:0; }
.setari-zone-desc { color:var(--muted); font-size:var(--fs-sm); margin:0 0 12px; max-width:60ch; line-height:1.5; }
/* Formulare compacte pe 2 coloane in Setari. */
.setari-fgrid { display:grid; grid-template-columns:1fr 1fr; gap:10px 14px; max-width:560px; margin:0 0 12px; }
.setari-fgrid .fg-full { grid-column:1 / -1; }
.setari-fgrid label { display:block; font-size:var(--fs-xs); color:var(--muted); margin-bottom:3px; }
.setari-fgrid input { width:100%; box-sizing:border-box; font:inherit; font-size:14px;
background:var(--bg); color:var(--ink); border:1px solid var(--line);
border-radius:6px; padding:7px 10px; }
@media (max-width:560px) { .setari-fgrid { grid-template-columns:1fr; } }
.setari-btn-row { display:flex; align-items:center; gap:10px; flex-wrap:wrap; }
.setari-micro { font-size:var(--fs-xs); color:var(--muted); }
/* Plan: tier + consum pe un rand, bara de progres sub ele. */
.plan-row { display:flex; align-items:baseline; gap:10px; flex-wrap:wrap; margin:0 0 8px; }
.plan-tier { font-size:var(--fs-md); font-weight:600; color:var(--ink); }
.plan-usage { font-size:var(--fs-sm); color:var(--muted); font-variant-numeric:tabular-nums; }
.plan-meter { height:6px; border-radius:99px; background:var(--line2); max-width:340px;
overflow:hidden; margin:0 0 8px; }
.plan-meter > span { display:block; height:100%; border-radius:99px; background:var(--accent); }
.setari-badge { font-size:11px; font-weight:700; padding:2px 9px; border-radius:99px; .setari-badge { font-size:11px; font-weight:700; padding:2px 9px; border-radius:99px;
text-transform:uppercase; letter-spacing:.03em; border:1px solid transparent; } text-transform:uppercase; letter-spacing:.03em; border:1px solid transparent; }
.setari-badge.sb-ok { color:var(--ok); background:color-mix(in srgb,var(--ok) 12%,transparent); .setari-badge.sb-ok { color:var(--ok); background:color-mix(in srgb,var(--ok) 12%,transparent);
@@ -869,7 +889,7 @@
border-color:color-mix(in srgb,var(--warn) 40%,transparent); } border-color:color-mix(in srgb,var(--warn) 40%,transparent); }
.setari-badge.sb-info { color:var(--muted); background:color-mix(in srgb,var(--muted) 12%,transparent); .setari-badge.sb-info { color:var(--muted); background:color-mix(in srgb,var(--muted) 12%,transparent);
border-color:color-mix(in srgb,var(--muted) 35%,transparent); } border-color:color-mix(in srgb,var(--muted) 35%,transparent); }
.setari-subzone-sep { border:none; border-top:1px solid var(--line); margin:26px 0 22px; } .setari-subzone-sep { border:none; border-top:1px solid var(--line); margin:20px 0 18px; }
/* Cheie API afisata o singura data. */ /* Cheie API afisata o singura data. */
.keybox { font-family:var(--font-mono); font-size:14px; background:var(--card2); .keybox { font-family:var(--font-mono); font-size:14px; background:var(--card2);
border:1px solid var(--line); border-radius:8px; padding:12px 14px; word-break:break-all; border:1px solid var(--line); border-radius:8px; padding:12px 14px; word-break:break-all;