Completa i18n IT/EN/FR/DE/ES su sito pubblico, area autenticata e admin.

Tutte le view marketing, legali, viewer, dashboard e admin usano t(); mailer utente-facing e flash localizzati; admin con LocaleResolver e selettore lingua.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-07-24 00:38:50 +02:00
co-authored by Cursor
parent fb7068f86c
commit b88f44ab1c
158 changed files with 9444 additions and 1536 deletions
+5 -5
View File
@@ -1,26 +1,26 @@
<div style="max-width:360px;margin:4rem auto">
<h2>Accesso admin</h2>
<h2><%= t("admin.auth.new.title") %></h2>
<% if flash[:alert] %>
<p style="color:#ff6b6b"><%= flash[:alert] %></p>
<% end %>
<%= form_with url: admin_login_path, method: :post, local: true do %>
<p>
<label for="username">Username</label><br>
<label for="username"><%= t("admin.auth.new.username_label") %></label><br>
<input type="text" name="username" id="username" required autofocus autocomplete="username"
style="width:100%;padding:0.5rem;margin-top:0.25rem;background:#1E1E1E;border:1px solid #333;color:#fff;border-radius:6px">
</p>
<p>
<label for="password">Password</label><br>
<label for="password"><%= t("admin.auth.new.password_label") %></label><br>
<input type="password" name="password" id="password" required autocomplete="current-password"
style="width:100%;padding:0.5rem;margin-top:0.25rem;background:#1E1E1E;border:1px solid #333;color:#fff;border-radius:6px">
</p>
<p>
<button type="submit" style="background:#FF2D2D;color:#fff;border:0;padding:0.6rem 1.2rem;border-radius:6px;cursor:pointer;font-weight:700">
Accedi
<%= t("admin.auth.new.submit") %>
</button>
</p>
<% end %>
<p style="color:#888;font-size:0.85rem;margin-top:1.5rem">
Credenziali iniziali: <code>admin</code> / <code>admin</code>. Cambia la password dopo il primo accesso.
<%= t("admin.auth.new.initial_credentials_html") %>
</p>
</div>
+17 -17
View File
@@ -1,12 +1,12 @@
<h2>Pagamenti da fatturare</h2>
<h2><%= t("admin.billing.index.title") %></h2>
<p style="color:#666;margin-bottom:16px">
Pagamenti Stripe <strong>pagati</strong> senza PDF fattura. Genera il PDF nei tuoi sistemi, poi caricalo qui: viene associato al pagamento e inviato via email al cliente.
<%= t("admin.billing.index.description") %>
</p>
<% if @clubs.many? %>
<p style="margin-bottom:16px">
Filtra società:
<%= link_to "Tutte", admin_billing_path, class: (@filter_club ? nil : "admin-nav-active") %>
<%= t("admin.billing.index.filter_label") %>
<%= link_to t("admin.billing.index.filter_all"), admin_billing_path, class: (@filter_club ? nil : "admin-nav-active") %>
<% @clubs.each do |club| %>
· <%= link_to club.name, admin_billing_path(club_id: club.id), class: (@filter_club&.id == club.id ? "admin-nav-active" : nil) %>
<% end %>
@@ -33,7 +33,7 @@
· <strong><%= payment.formatted_amount %></strong>
</div>
<% unless club.billing_profile_complete? %>
<span class="billing-pending-card__warn">Dati fatturazione incompleti</span>
<span class="billing-pending-card__warn"><%= t("admin.billing.index.incomplete_profile_warning") %></span>
<% end %>
</header>
@@ -46,16 +46,16 @@
<% end %>
</dl>
<% else %>
<p class="billing-pending-card__warn">Nessun dato di fatturazione — il cliente deve completare il profilo.</p>
<p class="billing-pending-card__warn"><%= t("admin.billing.index.no_billing_data") %></p>
<% end %>
<%= form_with url: admin_billing_payment_attach_pdf_path(payment),
method: :post, multipart: true, local: true, class: "billing-upload-form" do %>
<label class="billing-upload-form__label">
PDF fattura
<%= t("admin.billing.index.pdf_label") %>
<%= file_field_tag :pdf, accept: "application/pdf", required: true %>
</label>
<%= submit_tag "Carica PDF e invia al cliente", class: "admin-btn admin-btn--primary" %>
<%= submit_tag t("admin.billing.index.upload_button"), class: "admin-btn admin-btn--primary" %>
<% end %>
</div>
</article>
@@ -63,21 +63,21 @@
</div>
<% else %>
<p class="admin-flash" style="background:#1b3d1b;border-color:#2e7d32">
Nessun pagamento in attesa di fattura<%= @filter_club ? " per #{@filter_club.name}" : "" %>.
<%= t("admin.billing.index.none_pending", club: (@filter_club ? t("admin.billing.index.none_pending_for_club", club: @filter_club.name) : "")) %>
</p>
<% end %>
<% if @completed_payments.any? %>
<h2 style="margin-top:40px;font-size:1.15rem">Fatture già caricate</h2>
<h2 style="margin-top:40px;font-size:1.15rem"><%= t("admin.billing.index.uploaded_title") %></h2>
<table class="admin-table">
<thead>
<tr>
<th>Data</th>
<th>Società</th>
<th>Descrizione</th>
<th>Importo</th>
<th>Fattura</th>
<th>Stato</th>
<th><%= t("admin.billing.index.table.date") %></th>
<th><%= t("admin.billing.index.table.club") %></th>
<th><%= t("admin.billing.index.table.description") %></th>
<th><%= t("admin.billing.index.table.amount") %></th>
<th><%= t("admin.billing.index.table.invoice") %></th>
<th><%= t("admin.billing.index.table.status") %></th>
</tr>
</thead>
<tbody>
@@ -96,4 +96,4 @@
</table>
<% end %>
<p style="margin-top:24px"><%= link_to "← Dashboard", admin_root_path %></p>
<p style="margin-top:24px"><%= link_to t("admin.billing.index.back_dashboard"), admin_root_path %></p>
@@ -1,45 +1,45 @@
<h1>Fattura <%= @invoice.number %><%= @club.name %></h1>
<h1><%= t("admin.billing_invoices.edit.title", number: @invoice.number, club: @club.name) %></h1>
<p style="color:#666">
Stato: <strong><%= @invoice.status %></strong>
<%= t("admin.billing_invoices.edit.status_label") %> <strong><%= @invoice.status %></strong>
<% if @invoice.emailed_at.present? %>
· Inviata il <%= @invoice.emailed_at.in_time_zone.strftime("%d/%m/%Y %H:%M") %>
· <%= t("admin.billing_invoices.edit.sent_at", date: @invoice.emailed_at.in_time_zone.strftime("%d/%m/%Y %H:%M")) %>
<% end %>
</p>
<div class="card">
<%= form_with model: @invoice, url: admin_club_billing_invoice_path(@club, @invoice), multipart: true, method: :patch do |f| %>
<%= f.label :number, "Numero fattura" %>
<%= f.label :number, t("admin.billing_invoices.edit.number_label") %>
<%= f.text_field :number, required: true, disabled: @invoice.status.in?(%w[sent]) %>
<%= f.label :issued_on, "Data emissione" %>
<%= f.label :issued_on, t("admin.billing_invoices.edit.issued_on_label") %>
<%= f.date_field :issued_on, required: true, disabled: @invoice.status.in?(%w[sent]) %>
<%= label_tag :amount_euros, "Importo (€)" %>
<%= label_tag :amount_euros, t("admin.billing_invoices.edit.amount_label") %>
<%= number_field_tag "billing_invoice[amount_euros]",
@invoice.amount_cents / 100.0,
step: 0.01, min: 0.01, required: true, disabled: @invoice.status.in?(%w[sent]) %>
<% if @payment %>
<p style="color:#888;font-size:0.9rem">Pagamento: <%= @payment.display_description %><%= @payment.formatted_amount %></p>
<p style="color:#888;font-size:0.9rem"><%= t("admin.billing_invoices.edit.payment_info", description: @payment.display_description, amount: @payment.formatted_amount) %></p>
<% end %>
<%= f.label :pdf, "PDF fattura" %>
<%= f.label :pdf, t("admin.billing_invoices.edit.pdf_label") %>
<% if @invoice.pdf.attached? %>
<p style="color:#888">PDF già caricato: <%= @invoice.pdf.filename %></p>
<p style="color:#888"><%= t("admin.billing_invoices.edit.pdf_already", filename: @invoice.pdf.filename) %></p>
<% end %>
<%= f.file_field :pdf, accept: "application/pdf" %>
<%= f.label :notes, "Note interne" %>
<%= f.label :notes, t("admin.billing_invoices.edit.notes_label") %>
<%= f.text_area :notes, rows: 2 %>
<div style="margin-top:16px;display:flex;gap:10px;flex-wrap:wrap">
<% unless @invoice.status.in?(%w[sent]) %>
<%= f.submit "Salva bozza", class: "btn btn-secondary" %>
<%= f.submit "Emetti e invia via email", class: "btn btn-primary",
data: { turbo_confirm: "Inviare la fattura a #{@club.billing_email}?" } %>
<%= f.submit t("admin.billing_invoices.edit.save_draft"), name: "commit_action", value: "draft", class: "btn btn-secondary" %>
<%= f.submit t("admin.billing_invoices.edit.issue_send"), name: "commit_action", value: "issue", class: "btn btn-primary",
data: { turbo_confirm: t("admin.billing_invoices.edit.issue_confirm", email: @club.billing_email) } %>
<% end %>
</div>
<% end %>
</div>
<p><%= link_to "← Pagamenti e fatture", admin_club_billing_invoices_path(@club) %></p>
<p><%= link_to t("admin.billing_invoices.edit.back"), admin_club_billing_invoices_path(@club) %></p>
@@ -1,18 +1,18 @@
<h1>Fatturazione — <%= @club.name %></h1>
<h1><%= t("admin.billing_invoices.index.title", club: @club.name) %></h1>
<p>
<%= link_to "← Dashboard", admin_root_path %>
· <%= link_to "Nuova fattura (senza pagamento)", new_admin_club_billing_invoice_path(@club), class: "btn btn-secondary" %>
<%= link_to t("admin.billing_invoices.index.back_dashboard"), admin_root_path %>
· <%= link_to t("admin.billing_invoices.index.new_invoice"), new_admin_club_billing_invoice_path(@club), class: "btn btn-secondary" %>
</p>
<h2 style="margin-top:24px;font-size:1.1rem">Pagamenti</h2>
<h2 style="margin-top:24px;font-size:1.1rem"><%= t("admin.billing_invoices.index.payments_title") %></h2>
<% if @payments.any? %>
<table class="data">
<thead>
<tr>
<th>Data</th>
<th>Descrizione</th>
<th>Importo</th>
<th>Fattura</th>
<th><%= t("admin.billing_invoices.index.table.date") %></th>
<th><%= t("admin.billing_invoices.index.table.description") %></th>
<th><%= t("admin.billing_invoices.index.table.amount") %></th>
<th><%= t("admin.billing_invoices.index.table.invoice") %></th>
<th></th>
</tr>
</thead>
@@ -26,16 +26,16 @@
<td>
<% if inv %>
<%= inv.number %><%= inv.status %>
<% if inv.pdf.attached? %> (PDF)<% end %>
<% if inv.pdf.attached? %><%= t("admin.billing_invoices.index.pdf_suffix") %><% end %>
<% else %>
<%= t("admin.common.dash") %>
<% end %>
</td>
<td>
<% if inv %>
<%= link_to "Modifica / invia PDF", edit_admin_club_billing_invoice_path(@club, inv) %>
<%= link_to t("admin.billing_invoices.index.edit_send_pdf"), edit_admin_club_billing_invoice_path(@club, inv) %>
<% else %>
<%= link_to "Crea fattura", new_admin_club_billing_invoice_path(@club, billing_payment_id: payment.id), class: "btn btn-primary", style: "padding:6px 10px;font-size:0.85rem" %>
<%= link_to t("admin.billing_invoices.index.create_invoice"), new_admin_club_billing_invoice_path(@club, billing_payment_id: payment.id), class: "btn btn-primary", style: "padding:6px 10px;font-size:0.85rem" %>
<% end %>
</td>
</tr>
@@ -43,14 +43,21 @@
</tbody>
</table>
<% else %>
<p>Nessun pagamento registrato per questa società.</p>
<p><%= t("admin.billing_invoices.index.no_payments") %></p>
<% end %>
<h2 style="margin-top:32px;font-size:1.1rem">Tutte le fatture</h2>
<h2 style="margin-top:32px;font-size:1.1rem"><%= t("admin.billing_invoices.index.all_invoices_title") %></h2>
<% if @invoices.any? %>
<table class="data">
<thead>
<tr><th>Numero</th><th>Data</th><th>Importo</th><th>Stato</th><th>Pagamento</th><th></th></tr>
<tr>
<th><%= t("admin.billing_invoices.index.table2.number") %></th>
<th><%= t("admin.billing_invoices.index.table2.date") %></th>
<th><%= t("admin.billing_invoices.index.table2.amount") %></th>
<th><%= t("admin.billing_invoices.index.table2.status") %></th>
<th><%= t("admin.billing_invoices.index.table2.payment") %></th>
<th></th>
</tr>
</thead>
<tbody>
<% @invoices.each do |inv| %>
@@ -59,12 +66,12 @@
<td><%= inv.issued_on %></td>
<td><%= inv.formatted_amount %></td>
<td><%= inv.status %></td>
<td><%= inv.billing_payment_id.present? ? "Sì" : "No" %></td>
<td><%= link_to "Modifica", edit_admin_club_billing_invoice_path(@club, inv) %></td>
<td><%= inv.billing_payment_id.present? ? t("admin.common.yes") : t("admin.common.no") %></td>
<td><%= link_to t("admin.billing_invoices.index.edit"), edit_admin_club_billing_invoice_path(@club, inv) %></td>
</tr>
<% end %>
</tbody>
</table>
<% else %>
<p>Nessuna fattura.</p>
<p><%= t("admin.billing_invoices.index.no_invoices") %></p>
<% end %>
@@ -1,32 +1,32 @@
<h1>Nuova fattura — <%= @club.name %></h1>
<h1><%= t("admin.billing_invoices.new.title", club: @club.name) %></h1>
<% if @payment %>
<p style="color:#666">Collegata al pagamento del <%= @payment.paid_at&.to_date || @payment.created_at.to_date %> (<%= @payment.formatted_amount %>).</p>
<p style="color:#666"><%= t("admin.billing_invoices.new.linked_payment", date: (@payment.paid_at&.to_date || @payment.created_at.to_date), amount: @payment.formatted_amount) %></p>
<% end %>
<div class="card">
<%= form_with model: @invoice, url: admin_club_billing_invoices_path(@club) do |f| %>
<%= f.hidden_field :billing_payment_id if @payment %>
<%= f.label :number, "Numero fattura" %>
<%= f.label :number, t("admin.billing_invoices.new.number_label") %>
<%= f.text_field :number, required: true %>
<%= f.label :issued_on, "Data emissione" %>
<%= f.label :issued_on, t("admin.billing_invoices.new.issued_on_label") %>
<%= f.date_field :issued_on, required: true %>
<%= label_tag :amount_euros, "Importo (€)" %>
<%= label_tag :amount_euros, t("admin.billing_invoices.new.amount_label") %>
<%= number_field_tag "billing_invoice[amount_euros]",
(@invoice.amount_cents ? @invoice.amount_cents / 100.0 : nil),
step: 0.01, min: 0.01, required: true %>
<%= f.label :notes, "Note interne (opzionale)" %>
<%= f.label :notes, t("admin.billing_invoices.new.notes_label") %>
<%= f.text_area :notes, rows: 2 %>
<p style="color:#666;font-size:0.9rem;margin-top:12px">
Salva la bozza, poi carica il PDF e inviala al cliente dalla schermata successiva.
<%= t("admin.billing_invoices.new.hint") %>
</p>
<%= f.submit "Crea bozza fattura", class: "btn btn-primary" %>
<%= f.submit t("admin.billing_invoices.new.submit"), class: "btn btn-primary" %>
<% end %>
</div>
<p><%= link_to "← Pagamenti e fatture", admin_club_billing_invoices_path(@club) %></p>
<p><%= link_to t("admin.billing_invoices.new.back"), admin_club_billing_invoices_path(@club) %></p>
@@ -1,4 +1,4 @@
<% content_for :title, "Replay — #{@club.name}" %>
<% content_for :title, t("admin.club_recordings.index.title", club: @club.name) %>
<% content_for :replay_archive_styles, true %>
<%= render "recordings/club_archive", admin_mode: true %>
@@ -1,43 +1,43 @@
<%# locals: (club:, subscription:, return_to: nil) %>
<section class="admin-comped-card" style="margin-bottom:24px;padding:16px;border:1px solid #3d3520;border-radius:8px;background:#2a2618">
<h2 style="margin:0 0 8px;font-size:1.1rem">Abbonamento omaggio</h2>
<h2 style="margin:0 0 8px;font-size:1.1rem"><%= t("admin.comped.title") %></h2>
<p style="color:#bbb;font-size:0.9rem;margin:0 0 14px">
Sponsor o promozione: assegna Premium Light/Full senza pagamento Stripe. Revocabile in qualsiasi momento.
<%= t("admin.comped.description") %>
</p>
<% sub = subscription %>
<% if sub&.admin_comped? %>
<p style="margin:0 0 12px">
<strong>Attivo:</strong> <%= sub.plan.name %>
<strong><%= t("admin.comped.active_label") %></strong> <%= sub.plan.name %>
<% if sub.admin_comped_reason.present? %>
· <%= sub.admin_comped_reason %>
<% end %>
<% if sub.admin_comped_at.present? %>
<br><span style="color:#888;font-size:0.85rem">Dal <%= l(sub.admin_comped_at, format: :long) %>
<% if sub.admin_comped_by.present? %> · admin <%= sub.admin_comped_by.username %><% end %>
<br><span style="color:#888;font-size:0.85rem"><%= t("admin.comped.since_label_html", date: l(sub.admin_comped_at, format: :long)) %>
<% if sub.admin_comped_by.present? %> <%= t("admin.comped.by_admin", username: sub.admin_comped_by.username) %><% end %>
</span>
<% end %>
<% if sub.stripe_subscription_id.present? %>
<br><span style="color:#888;font-size:0.85rem">Nota: esiste anche un abbonamento Stripe collegato; lomaggio ha priorità sul piano.</span>
<br><span style="color:#888;font-size:0.85rem"><%= t("admin.comped.stripe_note") %></span>
<% end %>
</p>
<%= button_to "Revoca omaggio (torna Free o ripristina Stripe)",
<%= button_to t("admin.comped.revoke_button"),
revoke_comped_admin_club_path(club, return_to: return_to),
method: :delete,
class: "admin-btn admin-btn--secondary",
form: { data: { turbo_confirm: "Revocare labbonamento omaggio per #{club.name}?" } } %>
form: { data: { turbo_confirm: t("admin.comped.revoke_confirm", club: club.name) } } %>
<% else %>
<p style="margin:0 0 12px;color:#888">
Piano attuale: <strong><%= sub&.plan&.name || "Free" %></strong>
<%= t("admin.comped.current_plan", plan: sub&.plan&.name || t("admin.common.free_plan")) %>
<% if sub&.stripe_subscription_id.present? %>
· pagamento Stripe attivo
<%= t("admin.comped.stripe_active") %>
<% end %>
</p>
<%= form_with url: grant_comped_admin_club_path(club), method: :post, local: true, class: "admin-comped-form" do %>
<%= hidden_field_tag :return_to, return_to if return_to.present? %>
<div style="display:flex;flex-wrap:wrap;gap:12px;align-items:flex-end">
<label style="display:flex;flex-direction:column;gap:4px;font-size:0.85rem">
Piano
<%= t("admin.comped.plan_label") %>
<%= select_tag :plan_slug,
options_for_select(
[["Premium Light", "premium_light"], ["Premium Full", "premium_full"]]
@@ -46,10 +46,10 @@
class: "admin-input" %>
</label>
<label style="display:flex;flex-direction:column;gap:4px;font-size:0.85rem;flex:1;min-width:200px">
Motivo (es. sponsor 2026)
<%= text_field_tag :reason, nil, placeholder: "Sponsor, promozione…", class: "admin-input", style: "width:100%" %>
<%= t("admin.comped.reason_label") %>
<%= text_field_tag :reason, nil, placeholder: t("admin.comped.reason_placeholder"), class: "admin-input", style: "width:100%" %>
</label>
<%= submit_tag "Concedi omaggio", class: "admin-btn admin-btn--primary" %>
<%= submit_tag t("admin.comped.grant_button"), class: "admin-btn admin-btn--primary" %>
</div>
<% end %>
<% end %>
+13 -14
View File
@@ -1,17 +1,16 @@
<h2>Società e squadre</h2>
<h2><%= t("admin.clubs.index.title") %></h2>
<p style="color:#888;margin-bottom:16px">
Abbonamenti omaggio (sponsor / promozioni) e stato YouTube per squadra.
Pagamenti Stripe: <%= link_to "Fatturazione", admin_billing_path %>.
<%= t("admin.clubs.index.subtitle_html", billing_link: link_to(t("admin.clubs.index.billing_link"), admin_billing_path)) %>
</p>
<table class="admin-table">
<thead>
<tr>
<th>Società</th>
<th>Piano</th>
<th>Squadre</th>
<th>Omaggio</th>
<th>Stripe</th>
<th><%= t("admin.clubs.index.table.club") %></th>
<th><%= t("admin.clubs.index.table.plan") %></th>
<th><%= t("admin.clubs.index.table.teams") %></th>
<th><%= t("admin.clubs.index.table.comped") %></th>
<th><%= t("admin.clubs.index.table.stripe") %></th>
<th></th>
</tr>
</thead>
@@ -20,20 +19,20 @@
<% sub = club.subscription %>
<tr>
<td><strong><%= club.name %></strong></td>
<td><%= sub&.plan&.name || "Free" %></td>
<td><%= sub&.plan&.name || t("admin.common.free_plan") %></td>
<td><%= club.teams.size %></td>
<td>
<% if sub&.admin_comped? %>
<span style="color:#ffb74d"></span>
<span style="color:#ffb74d"><%= t("admin.common.yes") %></span>
<% if sub.admin_comped_reason.present? %> · <%= sub.admin_comped_reason %><% end %>
<% else %>
<%= t("admin.common.dash") %>
<% end %>
</td>
<td><%= sub&.stripe_subscription_id.present? ? "Sì" : "—" %></td>
<td><%= sub&.stripe_subscription_id.present? ? t("admin.common.yes") : t("admin.common.dash") %></td>
<td>
<%= link_to "Gestisci", admin_club_path(club) %>
· <%= link_to "Fatture", admin_billing_path(club_id: club.id) %>
<%= link_to t("admin.clubs.index.manage"), admin_club_path(club) %>
· <%= link_to t("admin.clubs.index.invoices"), admin_billing_path(club_id: club.id) %>
</td>
</tr>
<% end %>
+14 -14
View File
@@ -1,36 +1,36 @@
<p style="margin-bottom:16px"><%= link_to "← Società e squadre", admin_clubs_path %></p>
<p style="margin-bottom:16px"><%= link_to t("admin.clubs.show.back"), admin_clubs_path %></p>
<h2><%= @club.name %></h2>
<p style="color:#888">
Sport: <%= @club.sport %>
· <%= link_to "Archivio replay", admin_club_recordings_path(@club) %>
· <%= link_to "Pagamenti e fatture", admin_billing_path(club_id: @club.id) %>
· <%= link_to "Canale YouTube piattaforma", admin_youtube_platform_path %>
<%= t("admin.clubs.show.sport_label", sport: @club.sport) %>
· <%= link_to t("admin.clubs.show.recordings_archive"), admin_club_recordings_path(@club) %>
· <%= link_to t("admin.clubs.show.billing_link"), admin_billing_path(club_id: @club.id) %>
· <%= link_to t("admin.clubs.show.youtube_platform_link"), admin_youtube_platform_path %>
</p>
<%= render "admin/clubs/comped_form", club: @club, subscription: @subscription, return_to: admin_club_path(@club) %>
<% cred = @club.youtube_credential %>
<p style="margin-top:16px">
<strong>YouTube società:</strong>
<strong><%= t("admin.clubs.show.youtube_club_label") %></strong>
<% if cred %>
<%= cred.channel_title.presence || cred.channel_id %> (collegato)
<%= cred.channel_title.presence || cred.channel_id %> <%= t("admin.clubs.show.youtube_connected") %>
<% elsif @teams.any? { |t| t.entitlements.premium_full? } %>
<span class="muted">Premium Full — canale società non collegato (usa Match Live TV)</span>
<span class="muted"><%= t("admin.clubs.show.youtube_premium_full_not_connected") %></span>
<% else %>
<span class="muted"></span>
<span class="muted"><%= t("admin.common.dash") %></span>
<% end %>
</p>
<h3 style="font-size:1rem;margin-top:28px">Squadre</h3>
<h3 style="font-size:1rem;margin-top:28px"><%= t("admin.clubs.show.teams_title") %></h3>
<% if @teams.empty? %>
<p class="muted">Nessuna squadra registrata.</p>
<p class="muted"><%= t("admin.clubs.show.no_teams") %></p>
<% else %>
<table class="admin-table">
<thead>
<tr>
<th>Squadra</th>
<th>Sport</th>
<th><%= t("admin.clubs.show.table.team") %></th>
<th><%= t("admin.clubs.show.table.sport") %></th>
<th></th>
</tr>
</thead>
@@ -39,7 +39,7 @@
<tr>
<td><strong><%= team.name %></strong></td>
<td><%= team.sport %></td>
<td><%= link_to "Partite e dettagli", admin_team_path(team) %> · <%= link_to "Replay", admin_club_recordings_path(@club, team_id: team.id) %></td>
<td><%= link_to t("admin.clubs.show.matches_and_details"), admin_team_path(team) %> · <%= link_to t("admin.clubs.show.replay"), admin_club_recordings_path(@club, team_id: team.id) %></td>
</tr>
<% end %>
</tbody>
@@ -2,147 +2,153 @@
<section class="kpi-grid">
<div class="kpi-card kpi-card--accent">
<div class="kpi-label">Sessioni attive</div>
<div class="kpi-label"><%= t("admin.dashboard.kpi.active_sessions") %></div>
<div class="kpi-value kpi-value--live" id="kpi-active-sessions"><%= @stats[:active_sessions] %></div>
<div class="kpi-sub">in diretta ora</div>
<div class="kpi-sub"><%= t("admin.dashboard.kpi.active_sessions_sub") %></div>
</div>
<div class="kpi-card">
<div class="kpi-label">Trasmesse oggi</div>
<div class="kpi-label"><%= t("admin.dashboard.kpi.today") %></div>
<div class="kpi-value" id="kpi-sessions-today"><%= @stats[:sessions_today] %></div>
<div class="kpi-sub"><%= format_duration_minutes(@stats[:stream_minutes_today]) %> di streaming</div>
<div class="kpi-sub"><%= t("admin.dashboard.kpi.today_sub", duration: format_duration_minutes(@stats[:stream_minutes_today])) %></div>
</div>
<div class="kpi-card">
<div class="kpi-label">Trasmesse questo mese</div>
<div class="kpi-label"><%= t("admin.dashboard.kpi.month") %></div>
<div class="kpi-value" id="kpi-sessions-month"><%= @stats[:sessions_month] %></div>
<div class="kpi-sub"><%= format_duration_minutes(@stats[:stream_minutes_month]) %> totali</div>
<div class="kpi-sub"><%= t("admin.dashboard.kpi.month_sub", duration: format_duration_minutes(@stats[:stream_minutes_month])) %></div>
</div>
<div class="kpi-card">
<div class="kpi-label">Squadre</div>
<div class="kpi-label"><%= t("admin.dashboard.kpi.teams") %></div>
<div class="kpi-value"><%= @stats[:teams_count] %></div>
<div class="kpi-sub"><%= @stats[:users_count] %> utenti</div>
<div class="kpi-sub"><%= t("admin.dashboard.kpi.teams_sub", count: @stats[:users_count]) %></div>
</div>
<div class="kpi-card">
<div class="kpi-label">CPU</div>
<div class="kpi-label"><%= t("admin.dashboard.kpi.cpu") %></div>
<div class="kpi-value" id="kpi-cpu"><%= @host[:cpu] %>%</div>
<div class="kpi-sub">load <%= @host[:load_avg]["1m"] %> / <%= @host[:load_avg]["5m"] %> / <%= @host[:load_avg]["15m"] %></div>
<div class="kpi-sub"><%= t("admin.dashboard.kpi.cpu_sub", one: @host[:load_avg]["1m"], five: @host[:load_avg]["5m"], fifteen: @host[:load_avg]["15m"]) %></div>
</div>
<div class="kpi-card">
<div class="kpi-label">RAM</div>
<div class="kpi-label"><%= t("admin.dashboard.kpi.ram") %></div>
<div class="kpi-value" id="kpi-mem"><%= @host[:memory][:used_percent] %>%</div>
<div class="kpi-sub"><%= format_bytes(@host[:memory][:used_bytes]) %> / <%= format_bytes(@host[:memory][:total_bytes]) %></div>
<div class="kpi-sub"><%= t("admin.dashboard.kpi.ram_sub", used: format_bytes(@host[:memory][:used_bytes]), total: format_bytes(@host[:memory][:total_bytes])) %></div>
</div>
<div class="kpi-card">
<div class="kpi-label">Banda (totale)</div>
<div class="kpi-label"><%= t("admin.dashboard.kpi.network") %></div>
<div class="kpi-value" style="font-size:1.2rem" id="kpi-network"><%= format_bytes(@host[:network][:total_bytes]) %></div>
<div class="kpi-sub"><%= format_bytes(@host[:network][:tx_bytes_total]) %> · ↓ <%= format_bytes(@host[:network][:rx_bytes_total]) %></div>
<div class="kpi-sub"><%= t("admin.dashboard.kpi.network_sub", tx: format_bytes(@host[:network][:tx_bytes_total]), rx: format_bytes(@host[:network][:rx_bytes_total])) %></div>
</div>
<div class="kpi-card">
<div class="kpi-label">Replay in archivio</div>
<div class="kpi-label"><%= t("admin.dashboard.kpi.recordings") %></div>
<div class="kpi-value"><%= @stats[:recordings_ready] %></div>
<div class="kpi-sub"><%= @stats[:recordings_count] %> registrazioni</div>
<div class="kpi-sub"><%= t("admin.dashboard.kpi.recordings_sub", count: @stats[:recordings_count]) %></div>
</div>
</section>
<section class="charts-grid">
<div class="chart-card">
<h3>CPU (%)</h3>
<h3><%= t("admin.dashboard.charts.cpu") %></h3>
<div class="chart-wrap"><canvas id="chart-cpu"></canvas></div>
</div>
<div class="chart-card">
<h3>RAM (%)</h3>
<h3><%= t("admin.dashboard.charts.ram") %></h3>
<div class="chart-wrap"><canvas id="chart-mem"></canvas></div>
</div>
</section>
<section class="panel" style="margin-bottom:1.25rem">
<h2>Stato piattaforma (Ops)</h2>
<h2><%= t("admin.dashboard.ops_panel.title") %></h2>
<% critical = Ops::Incident.critical_open.count %>
<% warnings = Ops::Incident.open.where(severity: "warning").count %>
<% if critical.positive? %>
<p class="admin-flash" style="margin-bottom:0.75rem"><%= critical %> incidente/i critico/i aperto/i — <%= link_to "Vedi dashboard Ops", admin_ops_path %></p>
<p class="admin-flash" style="margin-bottom:0.75rem"><%= t("admin.dashboard.ops_panel.critical", count: critical) %><%= link_to t("admin.dashboard.ops_panel.view_dashboard"), admin_ops_path %></p>
<% elsif warnings.positive? %>
<p class="kpi-sub" style="margin-bottom:0.75rem"><%= warnings %> warning — <%= link_to "Dashboard Ops", admin_ops_path %></p>
<p class="kpi-sub" style="margin-bottom:0.75rem"><%= t("admin.dashboard.ops_panel.warnings", count: warnings) %><%= link_to t("admin.dashboard.ops_panel.dashboard_link"), admin_ops_path %></p>
<% else %>
<p class="empty" style="margin:0">Nessun incidente aperto. <%= link_to "Dashboard Ops", admin_ops_path %></p>
<p class="empty" style="margin:0"><%= t("admin.dashboard.ops_panel.none_html", link: link_to(t("admin.dashboard.ops_panel.dashboard_link"), admin_ops_path)) %></p>
<% end %>
</section>
<section class="charts-grid" style="grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));">
<div class="chart-card">
<h3>Disco sistema</h3>
<h3><%= t("admin.dashboard.disk.system_title") %></h3>
<% root = @host[:disk][:root] %>
<% if root[:total_bytes] %>
<div class="disk-row">
<header><span><%= root[:path] %></span><span><%= format_bytes(root[:used_bytes]) %> / <%= format_bytes(root[:total_bytes]) %></span></header>
<div class="progress-bar <%= 'progress-bar--ok' if root[:used_percent].to_f < 80 %>"><span style="width:<%= root[:used_percent] %>%"></span></div>
<p class="kpi-sub" style="margin-top:0.35rem">Libero: <%= format_bytes(root[:free_bytes]) %> (<%= root[:used_percent] %>% usato)</p>
<p class="kpi-sub" style="margin-top:0.35rem"><%= t("admin.dashboard.disk.free_label", free: format_bytes(root[:free_bytes]), percent: root[:used_percent]) %></p>
</div>
<% else %>
<p class="empty">Metriche disco non disponibili</p>
<p class="empty"><%= t("admin.dashboard.disk.not_available") %></p>
<% end %>
</div>
<div class="chart-card">
<h3>Archivio registrazioni</h3>
<h3><%= t("admin.dashboard.disk.recordings_title") %></h3>
<% rec = @host[:disk][:recordings] %>
<% if rec[:total_bytes] %>
<div class="disk-row">
<header><span><%= rec[:path] %></span><span><%= format_bytes(rec[:used_bytes]) %> / <%= format_bytes(rec[:total_bytes]) %></span></header>
<div class="progress-bar <%= 'progress-bar--ok' if rec[:used_percent].to_f < 80 %>"><span style="width:<%= rec[:used_percent] %>%"></span></div>
<% if rec[:dir_size_bytes] %>
<p class="kpi-sub" style="margin-top:0.35rem">Contenuto registrazioni: <%= format_bytes(rec[:dir_size_bytes]) %></p>
<p class="kpi-sub" style="margin-top:0.35rem"><%= t("admin.dashboard.disk.recordings_content", size: format_bytes(rec[:dir_size_bytes])) %></p>
<% end %>
</div>
<% else %>
<p class="empty">Percorso <%= Admin::HostMetrics::RECORDINGS_PATH %> non montato</p>
<p class="empty"><%= t("admin.dashboard.disk.recordings_not_mounted", path: Admin::HostMetrics::RECORDINGS_PATH) %></p>
<% end %>
</div>
</section>
<section class="admin-panels">
<div class="panel">
<h2>Sessioni attive</h2>
<h2><%= t("admin.dashboard.sessions.title") %></h2>
<% if @active_sessions.any? %>
<table class="admin-table">
<thead>
<tr><th>Partita</th><th>Stato</th><th>Inizio</th><th>Link</th><th></th></tr>
<tr>
<th><%= t("admin.dashboard.sessions.table.match") %></th>
<th><%= t("admin.dashboard.sessions.table.status") %></th>
<th><%= t("admin.dashboard.sessions.table.start") %></th>
<th><%= t("admin.dashboard.sessions.table.link") %></th>
<th></th>
</tr>
</thead>
<tbody id="active-sessions-body">
<% @active_sessions.each do |s| %>
<tr>
<td><%= s.match.team.name %> vs <%= s.match.opponent_name %></td>
<td><span class="badge badge--<%= s.status == 'live' ? 'live' : (s.status == 'paused' ? 'paused' : 'connecting') %>"><%= s.status %></span></td>
<td class="muted"><%= s.started_at&.strftime("%d/%m %H:%M") || "—" %></td>
<td class="muted"><%= s.started_at&.strftime("%d/%m %H:%M") || t("admin.common.dash") %></td>
<td class="admin-link-compact">
<% admin_session_watch_links(s).each do |link| %>
<%= link_to link[:label], link[:url], target: "_blank", rel: "noopener", class: "admin-link-chip" %>
<% end %>
<%= link_to "Regia", admin_session_path(s), class: "admin-link-chip admin-link-chip--regia" %>
<%= link_to t("admin.dashboard.sessions.regia"), admin_session_path(s), class: "admin-link-chip admin-link-chip--regia" %>
</td>
<td class="admin-actions">
<%= link_to "Dettaglio", admin_session_path(s) %>
<%= button_to "Termina", stop_admin_session_path(s), method: :post, class: "admin-btn admin-btn--danger admin-btn--sm", form: { data: { turbo_confirm: "Terminare questa sessione?" } } %>
<%= link_to t("admin.dashboard.sessions.detail"), admin_session_path(s) %>
<%= button_to t("admin.dashboard.sessions.stop"), stop_admin_session_path(s), method: :post, class: "admin-btn admin-btn--danger admin-btn--sm", form: { data: { turbo_confirm: t("admin.dashboard.sessions.stop_confirm") } } %>
</td>
</tr>
<% end %>
</tbody>
</table>
<% else %>
<p class="empty">Nessuna sessione attiva in questo momento.</p>
<p class="empty"><%= t("admin.dashboard.sessions.none") %></p>
<% end %>
</div>
<div class="panel">
<h2>Squadre</h2>
<h2><%= t("admin.dashboard.teams.title") %></h2>
<ul class="team-list">
<% @teams.each do |t| %>
<% @teams.each do |t_| %>
<li>
<%= link_to t.name, admin_team_path(t) %>
<span class="muted"><%= t.matches.count %> partite</span>
<%= link_to t_.name, admin_team_path(t_) %>
<span class="muted"><%= t("admin.dashboard.teams.matches_count", count: t_.matches.count) %></span>
</li>
<% end %>
</ul>
<% if @stats[:teams_count] > @teams.size %>
<p class="kpi-sub" style="margin-top:0.75rem"><%= link_to "Vedi società (#{@stats[:teams_count]} squadre)", admin_clubs_path %></p>
<p class="kpi-sub" style="margin-top:0.75rem"><%= link_to t("admin.dashboard.teams.view_all", count: @stats[:teams_count]), admin_clubs_path %></p>
<% end %>
</div>
</section>
+22 -16
View File
@@ -2,30 +2,30 @@
<section class="kpi-grid">
<div class="kpi-card <%= @summary[:open_critical].positive? ? 'kpi-card--danger' : 'kpi-card--accent' %>">
<div class="kpi-label">Critici aperti</div>
<div class="kpi-label"><%= t("admin.ops.kpi.critical") %></div>
<div class="kpi-value"><%= @summary[:open_critical] %></div>
</div>
<div class="kpi-card">
<div class="kpi-label">Warning aperti</div>
<div class="kpi-label"><%= t("admin.ops.kpi.warning") %></div>
<div class="kpi-value"><%= @summary[:open_warning] %></div>
</div>
<div class="kpi-card">
<div class="kpi-label">Totale aperti</div>
<div class="kpi-label"><%= t("admin.ops.kpi.total") %></div>
<div class="kpi-value"><%= @summary[:open_total] %></div>
</div>
</section>
<div class="panel" style="margin-bottom:1.5rem">
<h2>Incidenti aperti</h2>
<h2><%= t("admin.ops.open.title") %></h2>
<% if @open_incidents.any? %>
<table class="admin-table">
<thead>
<tr>
<th>Severità</th>
<th>Tipo</th>
<th>Titolo</th>
<th>Occ.</th>
<th>Ultimo</th>
<th><%= t("admin.ops.open.table.severity") %></th>
<th><%= t("admin.ops.open.table.kind") %></th>
<th><%= t("admin.ops.open.table.title") %></th>
<th><%= t("admin.ops.open.table.occurrences") %></th>
<th><%= t("admin.ops.open.table.last_seen") %></th>
<th></th>
</tr>
</thead>
@@ -44,26 +44,32 @@
<td class="muted"><%= inc.last_seen_at&.strftime("%d/%m %H:%M") %></td>
<td class="admin-actions">
<% unless inc.status == 'acknowledged' %>
<%= button_to "Preso in carico", acknowledge_admin_op_path(inc), method: :post, class: "admin-btn admin-btn--sm" %>
<%= button_to t("admin.ops.actions.acknowledge"), acknowledge_admin_op_path(inc), method: :post, class: "admin-btn admin-btn--sm" %>
<% end %>
<%= button_to "Risolvi", resolve_admin_op_path(inc), method: :post, class: "admin-btn admin-btn--sm" %>
<%= button_to "Mute 24h", mute_admin_op_path(inc), method: :post, class: "admin-btn admin-btn--sm admin-btn--outline" %>
<%= button_to t("admin.ops.actions.resolve"), resolve_admin_op_path(inc), method: :post, class: "admin-btn admin-btn--sm" %>
<%= button_to t("admin.ops.actions.mute"), mute_admin_op_path(inc), method: :post, class: "admin-btn admin-btn--sm admin-btn--outline" %>
</td>
</tr>
<% end %>
</tbody>
</table>
<% else %>
<p class="empty">Nessun incidente aperto. La piattaforma risulta sana.</p>
<p class="empty"><%= t("admin.ops.open.none") %></p>
<% end %>
</div>
<div class="panel">
<h2>Risolti (ultimi 30 giorni)</h2>
<h2><%= t("admin.ops.resolved.title") %></h2>
<% if @resolved_incidents.any? %>
<table class="admin-table">
<thead>
<tr><th>Severità</th><th>Tipo</th><th>Titolo</th><th>Occ.</th><th>Risolto</th></tr>
<tr>
<th><%= t("admin.ops.open.table.severity") %></th>
<th><%= t("admin.ops.open.table.kind") %></th>
<th><%= t("admin.ops.open.table.title") %></th>
<th><%= t("admin.ops.open.table.occurrences") %></th>
<th><%= t("admin.ops.resolved.table.resolved_at") %></th>
</tr>
</thead>
<tbody>
<% @resolved_incidents.each do |inc| %>
@@ -78,6 +84,6 @@
</tbody>
</table>
<% else %>
<p class="empty">Nessun incidente risolto di recente.</p>
<p class="empty"><%= t("admin.ops.resolved.none") %></p>
<% end %>
</div>
@@ -1,29 +1,29 @@
<div style="max-width:400px">
<h2>Cambia password</h2>
<h2><%= t("admin.passwords.edit.title") %></h2>
<% if flash[:alert] %>
<p style="color:#ff6b6b"><%= flash[:alert] %></p>
<% end %>
<%= form_with url: admin_password_path, method: :patch, local: true do %>
<p>
<label for="current_password">Password attuale</label><br>
<label for="current_password"><%= t("admin.passwords.edit.current_password_label") %></label><br>
<input type="password" name="current_password" id="current_password" required autocomplete="current-password"
style="width:100%;padding:0.5rem;margin-top:0.25rem;background:#1E1E1E;border:1px solid #333;color:#fff;border-radius:6px">
</p>
<p>
<label for="password">Nuova password (min. 8 caratteri)</label><br>
<label for="password"><%= t("admin.passwords.edit.new_password_label") %></label><br>
<input type="password" name="password" id="password" required autocomplete="new-password"
style="width:100%;padding:0.5rem;margin-top:0.25rem;background:#1E1E1E;border:1px solid #333;color:#fff;border-radius:6px">
</p>
<p>
<label for="password_confirmation">Conferma nuova password</label><br>
<label for="password_confirmation"><%= t("admin.passwords.edit.confirm_password_label") %></label><br>
<input type="password" name="password_confirmation" id="password_confirmation" required autocomplete="new-password"
style="width:100%;padding:0.5rem;margin-top:0.25rem;background:#1E1E1E;border:1px solid #333;color:#fff;border-radius:6px">
</p>
<p>
<button type="submit" style="background:#FF2D2D;color:#fff;border:0;padding:0.6rem 1.2rem;border-radius:6px;cursor:pointer;font-weight:700">
Salva password
<%= t("admin.passwords.edit.submit") %>
</button>
<%= link_to "Annulla", admin_root_path %>
<%= link_to t("admin.passwords.edit.cancel"), admin_root_path %>
</p>
<% end %>
</div>
@@ -1,6 +1,6 @@
<% watch_links = admin_session_watch_links(session) %>
<section class="admin-links-panel">
<h3>Link diretta</h3>
<h3><%= t("admin.sessions.links.watch_title") %></h3>
<% if watch_links.any? %>
<ul class="admin-link-list">
<% watch_links.each do |link| %>
@@ -11,28 +11,28 @@
<% end %>
</ul>
<% else %>
<p class="muted">Nessun link video disponibile per questa sessione.</p>
<p class="muted"><%= t("admin.sessions.links.none") %></p>
<% end %>
<h3>Link regia</h3>
<h3><%= t("admin.sessions.links.regia_title") %></h3>
<% if session.terminal? %>
<p class="muted">Sessione terminata — link regia non disponibile.</p>
<p class="muted"><%= t("admin.sessions.links.terminated") %></p>
<% else %>
<% if flash[:regia_url].present? %>
<p class="admin-link-generated">
<span class="admin-link-label">Regia</span>
<span class="admin-link-label"><%= t("admin.sessions.links.regia_label") %></span>
<%= link_to flash[:regia_url], flash[:regia_url], target: "_blank", rel: "noopener", class: "admin-link-url" %>
</p>
<p><code class="admin-link-code"><%= flash[:regia_url] %></code></p>
<% if (expires = admin_regia_expires_label(flash[:regia_expires_at])) %>
<p class="muted">Valido fino a <%= expires %></p>
<p class="muted"><%= t("admin.sessions.links.valid_until", date: expires) %></p>
<% end %>
<% elsif session.regia_token_active? %>
<p class="muted">Esiste già un link regia attivo (lURL non è recuperabile). Generane uno nuovo se serve condividerlo di nuovo.</p>
<p class="muted"><%= t("admin.sessions.links.active_exists") %></p>
<% else %>
<p class="muted">Nessun link regia attivo. Genera un link da condividere con chi gestisce il punteggio.</p>
<p class="muted"><%= t("admin.sessions.links.none_active") %></p>
<% end %>
<%= button_to "Genera link regia",
<%= button_to t("admin.sessions.links.generate_button"),
regia_link_admin_session_path(session),
method: :post,
class: "admin-btn admin-btn--secondary admin-btn--sm",
@@ -1,6 +1,14 @@
<h2>Stream Sessions</h2>
<h2><%= t("admin.sessions.index.title") %></h2>
<table class="admin-table">
<thead><tr><th>Match</th><th>Status</th><th>Disconnects</th><th>Link</th><th></th></tr></thead>
<thead>
<tr>
<th><%= t("admin.sessions.index.table.match") %></th>
<th><%= t("admin.sessions.index.table.status") %></th>
<th><%= t("admin.sessions.index.table.disconnects") %></th>
<th><%= t("admin.sessions.index.table.link") %></th>
<th></th>
</tr>
</thead>
<tbody>
<% @sessions.each do |s| %>
<tr>
@@ -11,9 +19,9 @@
<% admin_session_watch_links(s).each do |link| %>
<%= link_to link[:label], link[:url], target: "_blank", rel: "noopener", class: "admin-link-chip" %>
<% end %>
<%= link_to "Regia", admin_session_path(s), class: "admin-link-chip admin-link-chip--regia" %>
<%= link_to t("admin.sessions.index.regia"), admin_session_path(s), class: "admin-link-chip admin-link-chip--regia" %>
</td>
<td><%= link_to "Dettaglio", admin_session_path(s) %></td>
<td><%= link_to t("admin.sessions.index.detail"), admin_session_path(s) %></td>
</tr>
<% end %>
</tbody>
+15 -9
View File
@@ -1,26 +1,32 @@
<h2>Session <%= @session.id %></h2>
<p>Status: <strong><%= @session.status %></strong></p>
<h2><%= t("admin.sessions.show.title", id: @session.id) %></h2>
<p><%= t("admin.sessions.show.status_label") %> <strong><%= @session.status %></strong></p>
<% unless @session.terminal? %>
<p>
<%= button_to "Termina sessione",
<%= button_to t("admin.sessions.show.stop_button"),
stop_admin_session_path(@session),
method: :post,
class: "admin-btn admin-btn--danger",
form: { data: { turbo_confirm: "Terminare la trasmissione? Il path RTMP verrà rimosso e lo stato passerà a ended." } } %>
form: { data: { turbo_confirm: t("admin.sessions.show.stop_confirm") } } %>
</p>
<% end %>
<p>Match: <%= @session.match.team.name %> vs <%= @session.match.opponent_name %></p>
<p><%= t("admin.sessions.show.match_label", team: @session.match.team.name, opponent: @session.match.opponent_name) %></p>
<%= render "admin/sessions/links", session: @session %>
<% if @session.youtube_broadcast_id %>
<p>YouTube Studio: <a href="https://studio.youtube.com/video/<%= @session.youtube_broadcast_id %>/livestreaming" target="_blank" rel="noopener">Broadcast</a></p>
<p><%= t("admin.sessions.show.youtube_studio") %>: <a href="https://studio.youtube.com/video/<%= @session.youtube_broadcast_id %>/livestreaming" target="_blank" rel="noopener"><%= t("admin.sessions.show.broadcast") %></a></p>
<% end %>
<p>RTMP ingest: <code><%= @session.rtmp_ingest_url %></code></p>
<p><%= t("admin.sessions.show.rtmp_ingest") %> <code><%= @session.rtmp_ingest_url %></code></p>
<h3>Eventi</h3>
<h3><%= t("admin.sessions.show.events_title") %></h3>
<table>
<thead><tr><th>Tipo</th><th>Quando</th><th>Meta</th></tr></thead>
<thead>
<tr>
<th><%= t("admin.sessions.show.table.type") %></th>
<th><%= t("admin.sessions.show.table.when") %></th>
<th><%= t("admin.sessions.show.table.meta") %></th>
</tr>
</thead>
<tbody>
<% @events.each do |e| %>
<tr>
+13 -11
View File
@@ -1,34 +1,36 @@
<% if @team.club %>
<p style="margin-bottom:16px"><%= link_to "← #{@team.club.name}", admin_club_path(@team.club) %></p>
<p style="margin-bottom:16px"><%= link_to t("admin.teams.show.back", club: @team.club.name), admin_club_path(@team.club) %></p>
<% end %>
<h2><%= @team.name %></h2>
<p>Sport: <%= @team.sport %></p>
<p><%= t("admin.teams.show.sport_label", sport: @team.sport) %></p>
<% if @team.club %>
<p>Società: <%= @team.club.name %> · <%= link_to "Replay squadra", admin_club_recordings_path(@team.club, team_id: @team.id) %> · <%= link_to "Pagamenti e fatture", admin_billing_path(club_id: @team.club.id) %></p>
<p><%= t("admin.teams.show.club_label_html",
club: @team.club.name,
replay_link: link_to(t("admin.teams.show.replay_link"), admin_club_recordings_path(@team.club, team_id: @team.id)),
billing_link: link_to(t("admin.teams.show.billing_link"), admin_billing_path(club_id: @team.club.id))) %></p>
<% end %>
<% yt = Youtube::TeamStatus.new(@team) %>
<p>
YouTube:
<%= t("admin.teams.show.youtube_label") %>
<% if yt.selectable? %>
<strong><%= yt.channel_title || "—" %></strong>
<strong><%= yt.channel_title || t("admin.common.dash") %></strong>
<% if yt.uses_platform_channel? %>
(canale piattaforma<%= @team.entitlements.premium_full? && @team.club.youtube_credential.blank? ? ", default senza OAuth società" : "" %>)
<%= t("admin.teams.show.youtube_platform_channel", suffix: (@team.entitlements.premium_full? && @team.club.youtube_credential.blank? ? t("admin.teams.show.youtube_platform_default_no_oauth") : "")) %>
<% else %>
(canale società)
<%= t("admin.teams.show.youtube_club_channel") %>
<% end %>
<% else %>
non pronto
<%= t("admin.teams.show.youtube_not_ready") %>
<% end %>
</p>
<% if @team.entitlements.premium_full? && @team.club.youtube_credential.blank? %>
<p class="muted">
Senza canale collegato, lapp usa il canale Match Live TV.
<%= link_to "Collega canale (pagina società)", public_club_path(@team.club) %>.
<%= t("admin.teams.show.no_channel_hint_html", link: link_to(t("admin.teams.show.link_channel"), public_club_path(@team.club))) %>
</p>
<% end %>
<h3>Partite</h3>
<h3><%= t("admin.teams.show.matches_title") %></h3>
<ul>
<% @matches.each do |m| %>
<li><%= m.opponent_name %><%= m.scheduled_at %></li>
@@ -1,10 +1,10 @@
<!DOCTYPE html>
<html lang="it">
<html lang="<%= I18n.locale %>">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="robots" content="noindex, nofollow">
<title>Token YouTube — Match Live TV</title>
<title><%= t("admin.youtube.platform_token.page_title") %></title>
<style>
body { font-family: system-ui, sans-serif; background: #0a0a0e; color: #f0f0f5; margin: 0; padding: 32px 20px; line-height: 1.5; }
.wrap { max-width: 720px; margin: 0 auto; }
@@ -17,27 +17,24 @@
</head>
<body>
<div class="wrap">
<h1>Token canale Match Live TV</h1>
<h1><%= t("admin.youtube.platform_token.title") %></h1>
<% if @channel_title.present? %>
<p>Canale: <strong><%= @channel_title %></strong></p>
<p><%= t("admin.youtube.platform_token.channel_label", title: @channel_title) %></p>
<% end %>
<% if @refresh_token.present? %>
<p class="ok">Collegamento riuscito. Copia subito questa riga:</p>
<p>Aggiungi in <code>/opt/matchlivetv/infra/.env</code>:</p>
<p class="ok"><%= t("admin.youtube.platform_token.success") %></p>
<p><%= t("admin.youtube.platform_token.env_hint_html") %></p>
<pre id="yt-token">YOUTUBE_PLATFORM_REFRESH_TOKEN=<%= @refresh_token %></pre>
<p class="muted">Non verrà mostrato di nuovo. Poi: <code>docker compose -f docker-compose.prod.yml restart rails sidekiq</code></p>
<p class="muted"><%= t("admin.youtube.platform_token.not_shown_again_html") %></p>
<% else %>
<p class="muted">
Google non ha restituito un refresh token. In
<a href="https://myaccount.google.com/permissions" target="_blank" rel="noopener">account Google → accesso app</a>
revoca «Match Live TV», poi ripeti da
<a href="/admin/youtube/platform">/admin/youtube/platform</a>.
<%= t("admin.youtube.platform_token.no_refresh_token_html") %>
</p>
<% end %>
<p><a href="/admin/">← Dashboard admin</a></p>
<p><a href="/admin/"><%= t("admin.youtube.platform_token.back_dashboard") %></a></p>
</div>
</body>
</html>