Aggiunge i tornei con hub, pagina pubblica e tabellone per semifinali e finali.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -21,6 +21,15 @@
|
||||
<%= link_to t("club.dashboard.edit_club"), public_edit_club_path(@club), class: "btn btn-secondary" %>
|
||||
<%= link_to t("club.dashboard.subscription"), public_club_billing_path(@club), class: "btn btn-primary" %>
|
||||
<%= link_to t("club.dashboard.new_team"), public_new_club_team_path(@club), class: "btn btn-secondary" %>
|
||||
<% if Tournaments::Entitlements.new(@club).premium_full? %>
|
||||
<%= link_to t("club.dashboard.tournaments"), public_club_tournaments_path(@club), class: "btn btn-secondary" %>
|
||||
<% else %>
|
||||
<%= link_to public_club_billing_path(@club), class: "btn btn-secondary btn-gated",
|
||||
title: t("club.dashboard.tournaments_locked_hint") do %>
|
||||
<%= t("club.dashboard.tournaments") %>
|
||||
<span class="btn-gated__ribbon" aria-hidden="true"><%= t("club.dashboard.tournaments_full_badge") %></span>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<%= link_to t("club.dashboard.live_streams"), public_live_index_path(club_id: @club.id), class: "btn btn-secondary" %>
|
||||
<% if @entitlements&.can_access_recordings? %>
|
||||
<%= link_to t("club.dashboard.replay_archive"), public_club_recordings_path(@club), class: "btn btn-secondary" %>
|
||||
|
||||
@@ -1,13 +1,21 @@
|
||||
<% content_for :title, t("auth.invitation.meta_title") %>
|
||||
<% content_for :meta_description, t("auth.invitation.meta_description") %>
|
||||
<% content_for :robots, "noindex, nofollow" %>
|
||||
<%
|
||||
display_name = if @tournament_invitation
|
||||
@tournament_invitation.tournament.name
|
||||
else
|
||||
@invitation.team.name
|
||||
end
|
||||
email = (@invitation || @tournament_invitation).email
|
||||
%>
|
||||
|
||||
<section class="auth-page">
|
||||
<div class="card">
|
||||
<h1><%= raw t("auth.invitation.title_html", team_name: @invitation.team.name) %></h1>
|
||||
<p><%= raw t("auth.invitation.role_notice_html", email: @invitation.email) %></p>
|
||||
<h1><%= raw t("auth.invitation.title_html", team_name: display_name) %></h1>
|
||||
<p><%= raw t("auth.invitation.role_notice_html", email: email) %></p>
|
||||
<p class="muted" style="font-size:0.9rem;margin-bottom:16px">
|
||||
<%= raw t("auth.invitation.instructions_html", email: @invitation.email) %>
|
||||
<%= raw t("auth.invitation.instructions_html", email: email) %>
|
||||
</p>
|
||||
<% if logged_in? %>
|
||||
<%= button_to t("auth.invitation.accept"), public_invitation_path(token: @token), method: :post, class: "btn btn-primary" %>
|
||||
@@ -16,7 +24,7 @@
|
||||
"auth.invitation.login_or_signup_html",
|
||||
login_link: link_to(t("auth.invitation.login_link"), public_login_path),
|
||||
signup_link: link_to(t("auth.invitation.signup_link"), public_signup_path),
|
||||
email: @invitation.email
|
||||
email: email
|
||||
) %></p>
|
||||
<%= button_to t("auth.invitation.accept_if_logged_in"), public_invitation_path(token: @token), method: :post, class: "btn btn-secondary" %>
|
||||
<% end %>
|
||||
|
||||
@@ -118,13 +118,28 @@
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<% if @sessions.empty? %>
|
||||
<% if @upcoming_matches.any? %>
|
||||
<div class="empty-state empty-state--soft">
|
||||
<p><strong><%= t("live.index.empty_soft_title") %></strong></p>
|
||||
<p><%= t("live.index.empty_soft_body") %></p>
|
||||
</div>
|
||||
<% elsif @club %>
|
||||
<% if @sessions.empty? && @upcoming_matches.any? %>
|
||||
<div class="empty-state empty-state--soft">
|
||||
<p><strong><%= t("live.index.empty_soft_title") %></strong></p>
|
||||
<p><%= t("live.index.empty_soft_body") %></p>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<% if @public_tournaments.any? %>
|
||||
<h2 class="section-heading<%= " section-heading--spaced" if @sessions.any? || @upcoming_matches.any? %>"><%= t("tournaments.directory.section_on_live") %></h2>
|
||||
<p class="results-hint"><%= t("tournaments.directory.live_hint") %></p>
|
||||
<div class="team-directory-grid">
|
||||
<% @public_tournaments.each do |tournament| %>
|
||||
<%= render "public/tournament_pages/directory_card", tournament: tournament %>
|
||||
<% end %>
|
||||
</div>
|
||||
<p class="team-public-more">
|
||||
<%= link_to t("tournaments.directory.all_link"), public_tournament_pages_path %>
|
||||
</p>
|
||||
<% end %>
|
||||
|
||||
<% if @sessions.empty? && @upcoming_matches.empty? && @public_tournaments.blank? %>
|
||||
<% if @club %>
|
||||
<div class="empty-state">
|
||||
<p><strong><%= t("live.index.empty_club_title", name: @club.name) %></strong></p>
|
||||
<p>
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
<% state = tournament_public_board_state(match) %>
|
||||
<% live_session = tournament_public_live_session(match) %>
|
||||
<% recording = tournament_public_recording(match) %>
|
||||
<% score = tournament_public_score_label(match) %>
|
||||
<tr class="tournament-board__row tournament-board__row--<%= state %>">
|
||||
<td>
|
||||
<% if match.scheduled_at %>
|
||||
<%= match.scheduled_at.in_time_zone.strftime("%H:%M") %>
|
||||
<% else %>
|
||||
—
|
||||
<% end %>
|
||||
</td>
|
||||
<td><%= match.court.presence || "—" %></td>
|
||||
<td>
|
||||
<div class="tournament-stream-plan__matchup">
|
||||
<%= tournament_team_chip(match.home_participant, name: match.home_display_name) %>
|
||||
<span class="tournament-stream-plan__vs">–</span>
|
||||
<%= tournament_team_chip(match.away_participant, name: match.away_display_name) %>
|
||||
</div>
|
||||
<% if match.tournament_group || match.tournament_round %>
|
||||
<p class="tournament-board__phase">
|
||||
<%= [match.tournament_group&.name, match.tournament_round&.name].compact.join(" · ") %>
|
||||
</p>
|
||||
<% end %>
|
||||
</td>
|
||||
<td>
|
||||
<% if score.present? %>
|
||||
<strong><%= score %></strong>
|
||||
<% else %>
|
||||
—
|
||||
<% end %>
|
||||
</td>
|
||||
<td>
|
||||
<span class="tournament-live-status tournament-live-status--<%= state %>">
|
||||
<span class="tournament-live-status__dot" aria-hidden="true"></span>
|
||||
<%= t("tournaments.page.state.#{state}") %>
|
||||
</span>
|
||||
</td>
|
||||
<td class="tournament-board__actions">
|
||||
<% if live_session %>
|
||||
<%= link_to t("tournaments.page.watch_live"), public_live_path(live_session), class: "tournament-board__cta tournament-board__cta--live" %>
|
||||
<% elsif recording %>
|
||||
<%= link_to t("tournaments.page.watch_replay"), public_replay_path(recording.stream_session_id), class: "tournament-board__cta" %>
|
||||
<% else %>
|
||||
<span class="muted"><%= t("tournaments.page.no_media") %></span>
|
||||
<% end %>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -0,0 +1,28 @@
|
||||
<% club = tournament.club %>
|
||||
<% logo = tournament.effective_logo_url %>
|
||||
<%= link_to public_tournament_page_path(tournament.slug), class: "team-directory-card tournament-directory-card" do %>
|
||||
<div class="team-directory-card__media">
|
||||
<% if logo.present? %>
|
||||
<%= image_tag logo, alt: "", class: "team-directory-card__photo team-directory-card__photo--logo", width: 72, height: 72 %>
|
||||
<% else %>
|
||||
<div class="team-directory-card__photo team-directory-card__photo--fallback" aria-hidden="true">
|
||||
<%= tournament.name.to_s.first %>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
<div class="team-directory-card__body">
|
||||
<p class="team-directory-card__club"><%= club.name %></p>
|
||||
<h2 class="team-directory-card__name"><%= tournament.name %></h2>
|
||||
<p class="team-directory-card__meta">
|
||||
<%= tournament.sport_label %>
|
||||
· <%= l(tournament.starts_on) %> – <%= l(tournament.ends_on) %>
|
||||
<% if tournament.venue.present? %> · <%= tournament.venue %><% end %>
|
||||
</p>
|
||||
<div class="team-directory-card__badges">
|
||||
<% if tournament.archived? %>
|
||||
<span class="badge badge-scheduled"><%= t("tournaments.status.archived") %></span>
|
||||
<% end %>
|
||||
<span class="tournament-directory-follow"><%= t("tournaments.directory.follow") %></span>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
@@ -0,0 +1,62 @@
|
||||
<section class="team-public-section" id="risultati" aria-labelledby="tournament-results-heading">
|
||||
<h2 id="tournament-results-heading" class="section-heading visually-hidden"><%= t("tournaments.page.tabs.risultati") %></h2>
|
||||
<p class="results-hint"><%= t("tournaments.page.board_hint") %></p>
|
||||
<% if @matches.any? %>
|
||||
<% tournament_matches_grouped_by_date(@matches).each do |date, matches| %>
|
||||
<h3 class="tournament-board__day">
|
||||
<%= date ? l(date, format: :long) : t("tournaments.hub.stream_plan_unscheduled") %>
|
||||
</h3>
|
||||
<div class="tournament-table-wrap">
|
||||
<table class="data tournament-board">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><%= t("tournaments.hub.datetime") %></th>
|
||||
<th><%= t("tournaments.hub.court") %></th>
|
||||
<th><%= t("tournaments.hub.stream_plan_match") %></th>
|
||||
<th><%= t("tournaments.page.score") %></th>
|
||||
<th><%= t("tournaments.hub.stream_plan_live_col") %></th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% matches.each do |match| %>
|
||||
<%= render "public/tournament_pages/board_row", match: match %>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<p class="muted"><%= t("tournaments.hub.no_matches") %></p>
|
||||
<% end %>
|
||||
</section>
|
||||
|
||||
<% if @recordings.any? %>
|
||||
<section class="team-public-section">
|
||||
<h2 class="section-heading section-heading--spaced"><%= t("tournaments.page.section_replays") %></h2>
|
||||
<div class="replay-grid">
|
||||
<% @recordings.each do |rec| %>
|
||||
<% match = rec.stream_session.match %>
|
||||
<%= link_to public_replay_path(rec.stream_session_id), class: "replay-card" do %>
|
||||
<div class="replay-card__media">
|
||||
<% if rec.thumbnail_url %>
|
||||
<img src="<%= rec.thumbnail_url %>" alt="" class="replay-card__thumb" loading="lazy" width="320" height="180">
|
||||
<% else %>
|
||||
<div class="replay-card__thumb replay-card__thumb--placeholder" aria-hidden="true">
|
||||
<span class="replay-card__placeholder-icon">▶</span>
|
||||
</div>
|
||||
<% end %>
|
||||
<% if rec.duration_label.present? %>
|
||||
<span class="replay-card__duration"><%= rec.duration_label %></span>
|
||||
<% end %>
|
||||
<span class="replay-card__play" aria-hidden="true">▶</span>
|
||||
</div>
|
||||
<div class="replay-card__body">
|
||||
<strong class="replay-card__title"><%= rec.title.presence || match.matchup_label %></strong>
|
||||
<p class="replay-card__meta"><%= match.matchup_label %></p>
|
||||
</div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
</section>
|
||||
<% end %>
|
||||
@@ -0,0 +1,60 @@
|
||||
<% visible_rounds = @rounds.select { |round| (@matches_by_round[round.id] || []).any? } %>
|
||||
|
||||
<section class="team-public-section" id="tabellone" aria-labelledby="tournament-bracket-heading">
|
||||
<h2 id="tournament-bracket-heading" class="section-heading visually-hidden"><%= t("tournaments.page.tabs.tabellone") %></h2>
|
||||
|
||||
<% @groups.each do |group| %>
|
||||
<h3 class="tournament-board__day"><%= group.name %> — <%= t("tournaments.hub.standings") %></h3>
|
||||
<div class="tournament-table-wrap">
|
||||
<table class="data">
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th><%= t("tournaments.hub.played") %></th>
|
||||
<th><%= t("tournaments.hub.won") %></th>
|
||||
<th><%= t("tournaments.hub.lost") %></th>
|
||||
<th><%= t("tournaments.hub.points") %></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% @standings_by_group[group].each_with_index do |row, idx| %>
|
||||
<tr>
|
||||
<td><%= idx + 1 %>. <%= tournament_team_chip(row.participant) %></td>
|
||||
<td><%= row.played %></td>
|
||||
<td><%= row.won %></td>
|
||||
<td><%= row.lost %></td>
|
||||
<td><strong><%= row.points %></strong></td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<% visible_rounds.each do |round| %>
|
||||
<h3 class="tournament-board__day"><%= round.name %></h3>
|
||||
<div class="tournament-table-wrap">
|
||||
<table class="data tournament-board">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><%= t("tournaments.hub.datetime") %></th>
|
||||
<th><%= t("tournaments.hub.court") %></th>
|
||||
<th><%= t("tournaments.hub.stream_plan_match") %></th>
|
||||
<th><%= t("tournaments.page.score") %></th>
|
||||
<th><%= t("tournaments.hub.stream_plan_live_col") %></th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% @matches_by_round[round.id].each do |match| %>
|
||||
<%= render "public/tournament_pages/board_row", match: match %>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<% if @groups.none? && visible_rounds.none? %>
|
||||
<p class="muted"><%= t("tournaments.page.bracket_empty") %></p>
|
||||
<% end %>
|
||||
</section>
|
||||
@@ -0,0 +1,20 @@
|
||||
<% content_for :title, t("tournaments.directory.meta_title") %>
|
||||
<% content_for :meta_description, t("tournaments.directory.meta_description") %>
|
||||
<% content_for :canonical_url, seo_absolute_url(public_tournament_pages_path) %>
|
||||
|
||||
<div class="wrap team-directory">
|
||||
<h1><%= t("tournaments.directory.heading") %></h1>
|
||||
<p class="results-hint"><%= t("tournaments.directory.hint") %></p>
|
||||
|
||||
<% if @tournaments.any? %>
|
||||
<div class="team-directory-grid">
|
||||
<% @tournaments.each do |tournament| %>
|
||||
<%= render "public/tournament_pages/directory_card", tournament: tournament %>
|
||||
<% end %>
|
||||
</div>
|
||||
<% else %>
|
||||
<div class="empty-state empty-state--soft">
|
||||
<p><strong><%= t("tournaments.directory.empty") %></strong></p>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
@@ -0,0 +1,82 @@
|
||||
<% content_for :title, t("tournaments.page.title", name: @tournament.name, club: @club.name) %>
|
||||
<% content_for :robots, @tournament.published? ? "index, follow" : "noindex, nofollow" %>
|
||||
<% content_for :canonical_url, seo_absolute_url(public_tournament_page_path(@tournament.slug)) if @tournament.published? %>
|
||||
|
||||
<div class="wrap team-public-page tournament-public">
|
||||
<p class="results-hint" style="margin-bottom:8px">
|
||||
<%= link_to t("tournaments.page.back_to_list"), public_tournament_pages_path, class: "back-link" %>
|
||||
</p>
|
||||
|
||||
<header class="roster-hero card team-public-hero tournament-public-hero" style="--club-primary:<%= @tournament.effective_primary_color %>;--club-secondary:<%= @tournament.effective_secondary_color %>">
|
||||
<% logo = @tournament.effective_logo_url %>
|
||||
<% if logo.present? %>
|
||||
<%= image_tag logo, alt: "", class: "tournament-public-hero__logo", width: 56, height: 56 %>
|
||||
<% else %>
|
||||
<div class="tournament-public-hero__logo tournament-public-hero__logo--fallback" aria-hidden="true">
|
||||
<%= @tournament.name.to_s.first %>
|
||||
</div>
|
||||
<% end %>
|
||||
<div class="roster-hero__intro">
|
||||
<p class="roster-hero__club"><%= @club.name %></p>
|
||||
<h1 class="roster-hero__title"><%= @tournament.name %></h1>
|
||||
<p class="team-public-meta">
|
||||
<%= @tournament.sport_label %>
|
||||
· <%= l(@tournament.starts_on) %> – <%= l(@tournament.ends_on) %>
|
||||
<% if @tournament.venue.present? %> · <%= @tournament.venue %><% end %>
|
||||
</p>
|
||||
<% if @owner_preview %>
|
||||
<p class="muted" style="margin:6px 0 0"><%= t("tournaments.page.draft_banner") %></p>
|
||||
<% end %>
|
||||
</div>
|
||||
<% if @owner_manage %>
|
||||
<%= link_to t("tournaments.index.open"), public_tournament_path(@tournament), class: "btn btn-secondary tournament-public-hero__manage" %>
|
||||
<% end %>
|
||||
</header>
|
||||
|
||||
<% if @live_sessions.any? %>
|
||||
<section class="team-public-section" aria-labelledby="tournament-live-heading">
|
||||
<h2 id="tournament-live-heading" class="section-heading"><%= t("tournaments.page.section_live") %></h2>
|
||||
<div class="live-grid">
|
||||
<% @live_sessions.each do |session| %>
|
||||
<% match = session.match %>
|
||||
<% on_air = @online_paths.include?(session.mediamtx_path_name) %>
|
||||
<article class="live-card">
|
||||
<%= live_match_card_heading(match, link_team: false) %>
|
||||
<p class="meta">
|
||||
<% if match.court_or_location.present? %><%= match.court_or_location %> · <% end %>
|
||||
Match Live TV
|
||||
</p>
|
||||
<% if session.score_state %>
|
||||
<p class="card-score">
|
||||
<span class="card-sets"><%= live_score_sets_label(session.score_state, match) %></span>
|
||||
<% if live_score_partials_label(session.score_state).present? %>
|
||||
<span class="card-partials"><%= t("score.partials_prefix", value: live_score_partials_label(session.score_state)) %></span>
|
||||
<% end %>
|
||||
<span class="card-points"><%= session.score_state.home_points %> - <%= session.score_state.away_points %></span>
|
||||
</p>
|
||||
<% end %>
|
||||
<div class="badges">
|
||||
<% if on_air %>
|
||||
<span class="badge badge-on-air"><%= t("live.index.badge_on_air") %></span>
|
||||
<% elsif session.paused? %>
|
||||
<span class="badge badge-connecting"><%= t("live.index.badge_paused") %></span>
|
||||
<% else %>
|
||||
<span class="badge badge-live"><%= t("live.index.badge_live") %></span>
|
||||
<% end %>
|
||||
</div>
|
||||
<%= link_to t("tournaments.page.watch_live"), public_live_path(session), class: "btn-watch" %>
|
||||
</article>
|
||||
<% end %>
|
||||
</div>
|
||||
</section>
|
||||
<% end %>
|
||||
|
||||
<nav class="tournament-public-tabs" aria-label="<%= t("tournaments.page.tabs_label") %>">
|
||||
<% %w[risultati tabellone].each do |tab| %>
|
||||
<%= link_to t("tournaments.page.tabs.#{tab}"), public_tournament_page_path(@tournament.slug, tab: tab),
|
||||
class: "btn #{@tab == tab ? 'btn-primary' : 'btn-secondary'}" %>
|
||||
<% end %>
|
||||
</nav>
|
||||
|
||||
<%= render "public/tournament_pages/tab_#{@tab}" %>
|
||||
</div>
|
||||
@@ -0,0 +1,10 @@
|
||||
<% participant = match.public_send("#{side}_participant") %>
|
||||
<% if @writable && !tournament_match_sides_locked?(match) %>
|
||||
<%= select_tag "match[#{side}_participant_id]",
|
||||
options_from_collection_for_select(@participants, :id, :name, participant&.id),
|
||||
include_blank: tournament_side_blank_label(match, side),
|
||||
form: form_id,
|
||||
class: "tournament-match-form__team" %>
|
||||
<% else %>
|
||||
<%= tournament_team_chip(participant, name: match.public_send("#{side}_display_name")) %>
|
||||
<% end %>
|
||||
@@ -0,0 +1,64 @@
|
||||
<% assignments = match.broadcast_assignments.to_a %>
|
||||
<% pending = tournament_pending_invites_for(match) %>
|
||||
<% tab = local_assigns.fetch(:return_tab, "dirette") %>
|
||||
<% invite = local_assigns.fetch(:allow_invite, false) %>
|
||||
<td class="tournament-streaming-cell">
|
||||
<% assignments.each do |assignment| %>
|
||||
<% label = tournament_streaming_operator_label(assignment.user) %>
|
||||
<div class="tournament-streaming-chip tournament-streaming-chip--assigned">
|
||||
<i class="fa-solid fa-video" aria-hidden="true"></i>
|
||||
<span class="tournament-streaming-chip__name"><%= label %></span>
|
||||
<% if writable %>
|
||||
<%= button_to public_tournament_assignment_path(@tournament, assignment),
|
||||
method: :delete,
|
||||
class: "tournament-streaming-chip__action",
|
||||
title: t("tournaments.hub.streaming_revoke"),
|
||||
form: {
|
||||
class: "tournament-streaming-chip__form",
|
||||
data: { turbo_confirm: t("tournaments.hub.streaming_revoke_confirm", name: label) }
|
||||
} do %>
|
||||
<i class="fa-solid fa-xmark" aria-hidden="true"></i>
|
||||
<span class="visually-hidden"><%= t("tournaments.hub.streaming_revoke") %></span>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<% pending.each do |invitation| %>
|
||||
<div class="tournament-streaming-chip tournament-streaming-chip--pending">
|
||||
<i class="fa-regular fa-clock" aria-hidden="true"></i>
|
||||
<span class="tournament-streaming-chip__name"><%= invitation.email %></span>
|
||||
<% if writable %>
|
||||
<%= button_to public_tournament_invitation_path(@tournament, invitation),
|
||||
method: :delete,
|
||||
params: { tab: tab },
|
||||
class: "tournament-streaming-chip__action",
|
||||
title: t("team.streaming_staff.cancel_invitation"),
|
||||
form: {
|
||||
class: "tournament-streaming-chip__form",
|
||||
data: { turbo_confirm: tournament_invite_cancel_confirm(invitation) }
|
||||
} do %>
|
||||
<i class="fa-solid fa-xmark" aria-hidden="true"></i>
|
||||
<span class="visually-hidden"><%= t("team.streaming_staff.cancel_invitation") %></span>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<% if writable && invite && assignments.empty? && pending.empty? %>
|
||||
<%= form_with url: public_tournament_invitations_path(@tournament), method: :post, html: { class: "tournament-streaming-form" } do %>
|
||||
<%= hidden_field_tag :from, "calendar" %>
|
||||
<%= hidden_field_tag :tab, tab %>
|
||||
<%= hidden_field_tag "match_ids[]", match.id %>
|
||||
<%= email_field_tag :email, nil,
|
||||
required: true,
|
||||
autocomplete: "email",
|
||||
placeholder: t("tournaments.hub.invite_email"),
|
||||
class: "tournament-streaming-form__email",
|
||||
id: "stream_email_#{match.id}" %>
|
||||
<%= submit_tag t("tournaments.hub.streaming_invite"), class: "btn btn-secondary tournament-match-form__save" %>
|
||||
<% end %>
|
||||
<% elsif assignments.empty? && pending.empty? %>
|
||||
<span class="tournament-streaming-empty">—</span>
|
||||
<% end %>
|
||||
</td>
|
||||
@@ -0,0 +1,140 @@
|
||||
<div class="card">
|
||||
<% if @writable && @tournament.uses_groups? %>
|
||||
<p class="tournament-hub-hint"><%= t("tournaments.hub.generate_hint") %></p>
|
||||
<%= button_to t("tournaments.hub.generate_group_matches"),
|
||||
public_generate_group_matches_tournament_path(@tournament),
|
||||
method: :post, class: "btn btn-secondary" %>
|
||||
<% end %>
|
||||
|
||||
<% if @matches.any? %>
|
||||
<p class="tournament-hub-hint" style="margin-top:16px"><%= t("tournaments.hub.calendar_edit_hint") %></p>
|
||||
<div class="tournament-table-wrap">
|
||||
<table class="data tournament-match-table" data-swap-error="<%= t("flash.tournaments.sides_swap_failed") %>">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><%= t("tournaments.hub.datetime") %></th>
|
||||
<th><%= t("tournaments.hub.court") %></th>
|
||||
<th><%= t("tournaments.hub.round") %></th>
|
||||
<th><%= t("tournaments.hub.home") %></th>
|
||||
<th class="tournament-match-swap-col"></th>
|
||||
<th><%= t("tournaments.hub.away") %></th>
|
||||
<th><%= t("tournaments.hub.result") %></th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% @matches.each do |match| %>
|
||||
<% form_id = "match-edit-#{match.id}" %>
|
||||
<% courts = (@tournament.court_list + [match.court]).compact_blank.uniq %>
|
||||
<%= form_with url: public_tournament_match_path(@tournament, match), method: :patch, html: { id: form_id, class: "visually-hidden" } do %>
|
||||
<%= hidden_field_tag :tab, @tab, form: form_id %>
|
||||
<% end %>
|
||||
<tr>
|
||||
<% if @writable %>
|
||||
<td>
|
||||
<%= datetime_local_field_tag "match[scheduled_at]", tournament_datetime_local(match.scheduled_at),
|
||||
id: "match_at_#{match.id}", form: form_id, required: true, class: "tournament-match-form__datetime" %>
|
||||
</td>
|
||||
<td>
|
||||
<%= select_tag "match[court]", options_for_select(courts, match.court),
|
||||
id: "match_court_#{match.id}", form: form_id, include_blank: true, class: "tournament-match-form__court" %>
|
||||
</td>
|
||||
<td><%= tournament_phase_label(match) %></td>
|
||||
<td data-swap-side="home"><%= render "public/tournaments/match_side_select", match: match, side: :home, form_id: form_id %></td>
|
||||
<td class="tournament-match-swap-col">
|
||||
<%= button_to public_swap_tournament_match_path(@tournament, match), method: :post,
|
||||
class: "tournament-match-swap__btn",
|
||||
title: t("tournaments.hub.swap_sides"),
|
||||
form: { class: "tournament-match-swap__form", data: { turbo: false } } do %>
|
||||
<i class="fa-solid fa-right-left" aria-hidden="true"></i>
|
||||
<span class="visually-hidden"><%= t("tournaments.hub.swap_sides") %></span>
|
||||
<% end %>
|
||||
</td>
|
||||
<td data-swap-side="away"><%= render "public/tournaments/match_side_select", match: match, side: :away, form_id: form_id %></td>
|
||||
<td>
|
||||
<% if match.played? || match.result_status.to_s.start_with?("walkover") %>
|
||||
<span data-swap-played-score><%= match.home_score %>–<%= match.away_score %></span>
|
||||
<% else %>
|
||||
<span class="tournament-match-form__score">
|
||||
<%= number_field_tag :home_score, match.home_score, id: "home_score_#{match.id}", form: form_id, data: { swap_score: "home" } %>
|
||||
<span>–</span>
|
||||
<%= number_field_tag :away_score, match.away_score, id: "away_score_#{match.id}", form: form_id, data: { swap_score: "away" } %>
|
||||
</span>
|
||||
<% end %>
|
||||
</td>
|
||||
<td class="tournament-match-form__actions">
|
||||
<%= submit_tag t("tournaments.hub.save_match"), form: form_id, class: "btn btn-secondary tournament-match-form__save" %>
|
||||
<% if match.deletable? %>
|
||||
<%= button_to t("matches.index.delete"), public_tournament_match_path(@tournament, match),
|
||||
method: :delete, class: "btn btn-secondary tournament-match-form__save",
|
||||
form: { class: "tournament-match-delete-form", data: { turbo_confirm: match.matchup_label } } %>
|
||||
<% end %>
|
||||
</td>
|
||||
<% else %>
|
||||
<td><%= match.scheduled_at ? l(match.scheduled_at, format: :short) : "—" %></td>
|
||||
<td><%= match.court || "—" %></td>
|
||||
<td><%= tournament_phase_label(match) %></td>
|
||||
<td><%= tournament_team_chip(match.home_participant, name: match.home_display_name) %></td>
|
||||
<td class="tournament-match-swap-col"></td>
|
||||
<td><%= tournament_team_chip(match.away_participant, name: match.away_display_name) %></td>
|
||||
<td>
|
||||
<% if match.home_score.present? %>
|
||||
<%= match.home_score %>–<%= match.away_score %>
|
||||
<% else %>
|
||||
—
|
||||
<% end %>
|
||||
</td>
|
||||
<td></td>
|
||||
<% end %>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<% else %>
|
||||
<p class="tournament-hub-hint" style="margin-top:16px"><%= t("tournaments.hub.no_matches") %></p>
|
||||
<% end %>
|
||||
|
||||
<% if @writable %>
|
||||
<details class="tournament-schedule-extra">
|
||||
<summary><%= t("tournaments.hub.schedule_another") %></summary>
|
||||
<%= form_with url: public_tournament_matches_path(@tournament), method: :post, html: { class: "tournament-form", style: "margin-top:16px" } do %>
|
||||
<div class="tournament-form__field">
|
||||
<%= label_tag "match[home_participant_id]", t("tournaments.hub.home") %>
|
||||
<%= select_tag "match[home_participant_id]",
|
||||
options_from_collection_for_select(@participants, :id, :name), include_blank: t("tournaments.tbd") %>
|
||||
</div>
|
||||
<div class="tournament-form__field">
|
||||
<%= label_tag "match[away_participant_id]", t("tournaments.hub.away") %>
|
||||
<%= select_tag "match[away_participant_id]",
|
||||
options_from_collection_for_select(@participants, :id, :name), include_blank: t("tournaments.tbd") %>
|
||||
</div>
|
||||
<div class="tournament-form__field">
|
||||
<%= label_tag "match[court]", t("tournaments.hub.court") %>
|
||||
<%= select_tag "match[court]", options_for_select(@tournament.court_list) %>
|
||||
</div>
|
||||
<div class="tournament-form__field">
|
||||
<%= label_tag "match[scheduled_at]", t("tournaments.hub.datetime") %>
|
||||
<%= datetime_local_field_tag "match[scheduled_at]", nil, required: true %>
|
||||
</div>
|
||||
<% if @groups.any? %>
|
||||
<div class="tournament-form__field">
|
||||
<%= label_tag "match[tournament_group_id]", t("tournaments.hub.group") %>
|
||||
<%= select_tag "match[tournament_group_id]",
|
||||
options_from_collection_for_select(@groups, :id, :name), include_blank: true %>
|
||||
</div>
|
||||
<% end %>
|
||||
<% if @rounds.any? %>
|
||||
<div class="tournament-form__field">
|
||||
<%= label_tag "match[tournament_round_id]", t("tournaments.hub.round") %>
|
||||
<%= select_tag "match[tournament_round_id]",
|
||||
options_from_collection_for_select(@rounds, :id, :name), include_blank: t("tournaments.hub.no_round") %>
|
||||
</div>
|
||||
<% end %>
|
||||
<div class="tournament-form__actions">
|
||||
<%= submit_tag t("tournaments.hub.schedule_match"), class: "btn btn-primary" %>
|
||||
</div>
|
||||
<% end %>
|
||||
</details>
|
||||
<% end %>
|
||||
</div>
|
||||
@@ -0,0 +1,170 @@
|
||||
<% coverage = tournament_streaming_coverage(@matches) %>
|
||||
<% live_counts = tournament_streaming_live_counts(@matches) %>
|
||||
<div class="tournament-stream-plan">
|
||||
<div class="card">
|
||||
<div class="tournament-stream-plan__header">
|
||||
<div>
|
||||
<h2 class="tournament-stream-plan__title"><%= t("tournaments.hub.stream_plan_title") %></h2>
|
||||
<p class="tournament-hub-hint"><%= t("tournaments.hub.stream_plan_hint") %></p>
|
||||
</div>
|
||||
<% if @writable && @matches.any? %>
|
||||
<a class="btn btn-secondary tournament-stream-plan__jump" href="#invito-operatore"><%= t("tournaments.hub.stream_plan_invite_title") %></a>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<% if @matches.any? %>
|
||||
<div class="tournament-stream-plan__stats">
|
||||
<% %i[live waiting_time waiting_operator ended uncovered].each do |state| %>
|
||||
<% count = live_counts[state].to_i %>
|
||||
<% next if count.zero? %>
|
||||
<span class="tournament-stream-plan__stat tournament-stream-plan__stat--<%= state %>">
|
||||
<%= t("tournaments.hub.stream_plan_live_count.#{state}", count: count) %>
|
||||
</span>
|
||||
<% end %>
|
||||
<% if @writable && coverage[:open].positive? %>
|
||||
<button type="button" class="btn btn-secondary tournament-stream-plan__select" data-select-uncovered="tournament-stream-invite">
|
||||
<%= t("tournaments.hub.stream_plan_select_open") %>
|
||||
</button>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<% tournament_matches_grouped_by_date(@matches).each do |date, matches| %>
|
||||
<h3 class="tournament-stream-plan__day">
|
||||
<%= date ? l(date, format: :long) : t("tournaments.hub.stream_plan_unscheduled") %>
|
||||
</h3>
|
||||
<div class="tournament-table-wrap">
|
||||
<table class="data tournament-stream-plan__table">
|
||||
<thead>
|
||||
<tr>
|
||||
<% if @writable %><th class="tournament-stream-plan__check-col"></th><% end %>
|
||||
<th><%= t("tournaments.hub.datetime") %></th>
|
||||
<th><%= t("tournaments.hub.court") %></th>
|
||||
<th><%= t("tournaments.hub.stream_plan_match") %></th>
|
||||
<th><%= t("tournaments.hub.stream_plan_live_col") %></th>
|
||||
<th><%= t("tournaments.hub.stream_plan_operator") %></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% matches.each do |match| %>
|
||||
<% state = tournament_broadcast_live_state(match) %>
|
||||
<% uncovered = state == :uncovered %>
|
||||
<tr class="tournament-stream-plan__row tournament-stream-plan__row--<%= state %>">
|
||||
<% if @writable %>
|
||||
<td class="tournament-stream-plan__check-col">
|
||||
<% if uncovered %>
|
||||
<label class="tournament-stream-plan__check">
|
||||
<%= check_box_tag "match_ids[]", match.id, false,
|
||||
id: "plan_match_#{match.id}",
|
||||
form: "tournament-stream-invite",
|
||||
data: { uncovered_match: true } %>
|
||||
<span class="visually-hidden"><%= t("tournaments.hub.stream_plan_select_match") %></span>
|
||||
</label>
|
||||
<% end %>
|
||||
</td>
|
||||
<% end %>
|
||||
<td><%= match.scheduled_at ? match.scheduled_at.in_time_zone.strftime("%H:%M") : "—" %></td>
|
||||
<td><%= match.court.presence || "—" %></td>
|
||||
<td>
|
||||
<div class="tournament-stream-plan__matchup">
|
||||
<%= tournament_team_chip(match.home_participant, name: match.home_display_name) %>
|
||||
<span class="tournament-stream-plan__vs">–</span>
|
||||
<%= tournament_team_chip(match.away_participant, name: match.away_display_name) %>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<span class="tournament-live-status tournament-live-status--<%= state %>">
|
||||
<span class="tournament-live-status__dot" aria-hidden="true"></span>
|
||||
<%= t("tournaments.hub.stream_plan_live.#{state}") %>
|
||||
</span>
|
||||
</td>
|
||||
<%= render "public/tournaments/match_streaming", match: match, writable: @writable, allow_invite: false, return_tab: "dirette" %>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<p class="tournament-hub-hint" style="margin-top:16px"><%= t("tournaments.hub.no_matches") %></p>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<% if @writable %>
|
||||
<div class="card tournament-stream-plan__invite-card" id="invito-operatore">
|
||||
<h2 class="tournament-stream-plan__title"><%= t("tournaments.hub.stream_plan_invite_title") %></h2>
|
||||
<p class="tournament-hub-hint"><%= t("tournaments.hub.stream_plan_invite_hint") %></p>
|
||||
|
||||
<%= form_with url: public_tournament_invitations_path(@tournament), method: :post,
|
||||
html: { id: "tournament-stream-invite", class: "tournament-form tournament-invite-form tournament-stream-plan__invite" } do %>
|
||||
<%= hidden_field_tag :tab, "dirette" %>
|
||||
<div class="tournament-form__field">
|
||||
<%= label_tag :email, t("tournaments.hub.invite_email") %>
|
||||
<%= email_field_tag :email, @tournament.invite_draft_email, required: true, autocomplete: "email" %>
|
||||
</div>
|
||||
<div class="tournament-form__field">
|
||||
<%= label_tag :note, t("tournaments.hub.invite_note") %>
|
||||
<%= text_area_tag :note, @tournament.invite_draft_note, rows: 2, maxlength: 2000, data: { invite_note: true },
|
||||
placeholder: t("tournaments.hub.invite_note_placeholder") %>
|
||||
</div>
|
||||
<div class="tournament-form__field">
|
||||
<%= label_tag :court, t("tournaments.hub.court") %>
|
||||
<%= select_tag :court, options_for_select(@tournament.court_list) %>
|
||||
</div>
|
||||
<div class="tournament-form__field">
|
||||
<%= label_tag :on_date, t("tournaments.hub.datetime") %>
|
||||
<%= date_field_tag :on_date, @tournament.starts_on %>
|
||||
</div>
|
||||
<p class="tournament-hub-hint tournament-form__full"><%= t("tournaments.hub.stream_plan_court_day_hint") %></p>
|
||||
|
||||
<div class="tournament-form__full tournament-stream-plan__mail">
|
||||
<h3 class="tournament-stream-plan__mail-title"><%= t("tournaments.hub.invite_email_body") %></h3>
|
||||
<p class="tournament-hub-hint"><%= t("tournaments.hub.invite_email_hint") %></p>
|
||||
<% if @tournament.invite_draft_saved_at.present? %>
|
||||
<p class="tournament-hub-hint"><%= t("tournaments.hub.invite_draft_hint", time: l(@tournament.invite_draft_saved_at, format: :short)) %></p>
|
||||
<% end %>
|
||||
<div class="invite-editor"
|
||||
data-invite-editor
|
||||
data-upload-url="<%= public_tournament_invite_images_path(@tournament) %>"
|
||||
data-msg-type="<%= t("tournaments.hub.invite_image_invalid") %>"
|
||||
data-msg-size="<%= t("tournaments.hub.invite_image_too_big") %>"
|
||||
data-msg-uploading="<%= t("tournaments.hub.invite_image_uploading") %>"
|
||||
data-msg-failed="<%= t("tournaments.hub.invite_image_failed") %>"
|
||||
data-msg-link="<%= t("tournaments.hub.invite_editor_link_prompt") %>">
|
||||
<div class="invite-editor__toolbar" role="toolbar" aria-label="<%= t("tournaments.hub.invite_editor_toolbar") %>">
|
||||
<button type="button" class="invite-editor__btn" data-invite-cmd="bold" aria-label="<%= t("tournaments.hub.invite_editor_bold") %>"><i class="fa-solid fa-bold" aria-hidden="true"></i></button>
|
||||
<button type="button" class="invite-editor__btn" data-invite-cmd="italic" aria-label="<%= t("tournaments.hub.invite_editor_italic") %>"><i class="fa-solid fa-italic" aria-hidden="true"></i></button>
|
||||
<button type="button" class="invite-editor__btn" data-invite-cmd="underline" aria-label="<%= t("tournaments.hub.invite_editor_underline") %>"><i class="fa-solid fa-underline" aria-hidden="true"></i></button>
|
||||
<button type="button" class="invite-editor__btn" data-invite-cmd="insertUnorderedList" aria-label="<%= t("tournaments.hub.invite_editor_ul") %>"><i class="fa-solid fa-list-ul" aria-hidden="true"></i></button>
|
||||
<button type="button" class="invite-editor__btn" data-invite-cmd="insertOrderedList" aria-label="<%= t("tournaments.hub.invite_editor_ol") %>"><i class="fa-solid fa-list-ol" aria-hidden="true"></i></button>
|
||||
<button type="button" class="invite-editor__btn" data-invite-cmd="createLink" aria-label="<%= t("tournaments.hub.invite_editor_link") %>"><i class="fa-solid fa-link" aria-hidden="true"></i></button>
|
||||
<button type="button" class="invite-editor__btn" data-invite-cmd="image" aria-label="<%= t("tournaments.hub.invite_editor_image") %>"><i class="fa-solid fa-image" aria-hidden="true"></i></button>
|
||||
<input type="file" accept="image/png,image/jpeg,image/webp,image/gif" hidden data-invite-file>
|
||||
</div>
|
||||
<div class="invite-editor__frame">
|
||||
<div class="invite-editor__surface" contenteditable="true" role="textbox" aria-multiline="true">
|
||||
<%= raw tournament_invite_editor_html(@tournament, current_user) %>
|
||||
</div>
|
||||
<span class="invite-editor__handle" hidden></span>
|
||||
</div>
|
||||
<p class="invite-editor__status" data-invite-status hidden></p>
|
||||
</div>
|
||||
<%= hidden_field_tag :email_html, "", id: "invite-email-html", data: { invite_html: true } %>
|
||||
</div>
|
||||
|
||||
<div class="tournament-form__actions">
|
||||
<%= button_tag t("tournaments.hub.invite_save"), type: "submit", name: "intent", value: "save",
|
||||
formnovalidate: true, class: "btn btn-secondary" %>
|
||||
<%= submit_tag t("tournaments.hub.stream_plan_invite_selected"), class: "btn btn-primary" %>
|
||||
<%= button_tag t("tournaments.hub.stream_plan_invite_court"), type: "submit", name: "whole_court", value: "1", class: "btn btn-secondary" %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<% if flash[:invite_url].present? %>
|
||||
<div class="team-invite-link" id="invito-generato" style="margin-top:16px">
|
||||
<p><%= t("team.invite.share_hint") %></p>
|
||||
<code id="tournament-invite-url"><%= flash[:invite_url] %></code>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
@@ -0,0 +1,100 @@
|
||||
<div class="card">
|
||||
<p class="tournament-hub-hint"><%= t("tournaments.hub.squadre_edit_hint") %></p>
|
||||
<% if @writable %>
|
||||
<%= form_with url: public_tournament_participants_path(@tournament), method: :post, html: { class: "tournament-form" } do %>
|
||||
<div class="tournament-form__field">
|
||||
<%= label_tag "tournament_participant[name]", t("tournaments.hub.add_participant") %>
|
||||
<%= text_field_tag "tournament_participant[name]", nil, required: true, placeholder: t("tournaments.hub.participant_name") %>
|
||||
</div>
|
||||
<% if @groups.any? %>
|
||||
<div class="tournament-form__field">
|
||||
<%= label_tag "tournament_participant[group_id]", t("tournaments.hub.participant_group") %>
|
||||
<%= select_tag "tournament_participant[group_id]",
|
||||
options_for_select([[t("tournaments.hub.no_group"), ""]] + @groups.map { |g| [g.name, g.id] }) %>
|
||||
</div>
|
||||
<% end %>
|
||||
<div class="tournament-form__actions">
|
||||
<%= submit_tag t("tournaments.hub.add_participant"), class: "btn btn-primary" %>
|
||||
</div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
<% if @participants.any? %>
|
||||
<div class="tournament-table-wrap">
|
||||
<table class="data tournament-squad-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><%= t("tournaments.hub.logo") %></th>
|
||||
<th><%= t("tournaments.hub.participant_name") %></th>
|
||||
<th><%= t("tournaments.hub.participant_group") %></th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% @participants.each do |participant| %>
|
||||
<% form_id = "participant-edit-#{participant.id}" %>
|
||||
<% logo = participant.effective_logo_url %>
|
||||
<%= form_with url: public_tournament_participant_path(@tournament, participant),
|
||||
method: :patch,
|
||||
multipart: true,
|
||||
html: { id: form_id, class: "visually-hidden" } do %>
|
||||
<% end %>
|
||||
<tr>
|
||||
<td>
|
||||
<div class="tournament-squad-logo">
|
||||
<div class="tournament-squad-logo__preview" aria-hidden="true">
|
||||
<% if logo.present? %>
|
||||
<%= image_tag logo, alt: "" %>
|
||||
<% else %>
|
||||
<span class="tournament-squad-logo__empty">+</span>
|
||||
<% end %>
|
||||
</div>
|
||||
<% if @writable %>
|
||||
<label class="btn btn-secondary tournament-squad-logo__btn">
|
||||
<%= t("tournaments.hub.logo_file") %>
|
||||
<%= file_field_tag "tournament_participant[logo_file]",
|
||||
id: "logo_file_#{participant.id}",
|
||||
form: form_id,
|
||||
accept: "image/png,image/jpeg,image/webp",
|
||||
onchange: "this.form.requestSubmit()" %>
|
||||
</label>
|
||||
<% end %>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<% if @writable %>
|
||||
<%= text_field_tag "tournament_participant[name]", participant.name,
|
||||
id: "participant_name_#{participant.id}",
|
||||
form: form_id,
|
||||
required: true,
|
||||
class: "tournament-squad-name" %>
|
||||
<% else %>
|
||||
<%= tournament_team_chip(participant) %>
|
||||
<% end %>
|
||||
</td>
|
||||
<td>
|
||||
<% if @writable && @groups.any? %>
|
||||
<%= select_tag "tournament_participant[group_id]",
|
||||
options_for_select([[t("tournaments.hub.no_group"), ""]] + @groups.map { |g| [g.name, g.id] }, participant.group_id),
|
||||
id: "participant_group_#{participant.id}",
|
||||
form: form_id,
|
||||
class: "tournament-squad-group" %>
|
||||
<% else %>
|
||||
<%= participant.group&.name || "—" %>
|
||||
<% end %>
|
||||
</td>
|
||||
<td class="tournament-match-form__actions">
|
||||
<% if @writable %>
|
||||
<%= submit_tag t("tournaments.hub.save_match"), form: form_id, class: "btn btn-secondary tournament-match-form__save" %>
|
||||
<%= button_to t("matches.index.delete"), public_tournament_participant_path(@tournament, participant),
|
||||
method: :delete, class: "btn btn-secondary tournament-match-form__save",
|
||||
form: { data: { turbo_confirm: participant.name } } %>
|
||||
<% end %>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
@@ -0,0 +1,34 @@
|
||||
<div class="card">
|
||||
<p style="color:#888"><%= t("tournaments.form.formats.#{@tournament.format_kind}") %></p>
|
||||
|
||||
<% if @tournament.uses_groups? %>
|
||||
<h2><%= t("tournaments.hub.tabs.struttura") %></h2>
|
||||
<ul>
|
||||
<% @groups.each do |group| %>
|
||||
<li style="margin-bottom:8px">
|
||||
<%= group.name %>
|
||||
<% if @writable %>
|
||||
<%= button_to t("matches.index.delete"), public_tournament_group_path(@tournament, group),
|
||||
method: :delete, class: "btn btn-secondary", style: "padding:4px 10px;font-size:0.8rem;display:inline",
|
||||
form: { data: { turbo_confirm: group.name }, style: "display:inline" } %>
|
||||
<% end %>
|
||||
</li>
|
||||
<% end %>
|
||||
</ul>
|
||||
<% if @writable %>
|
||||
<%= form_with url: public_tournament_groups_path(@tournament), method: :post do %>
|
||||
<%= text_field_tag "tournament_group[name]", nil, placeholder: t("tournaments.hub.add_group") %>
|
||||
<%= submit_tag t("tournaments.hub.add_group"), class: "btn btn-secondary" %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
<% if @tournament.uses_knockout? %>
|
||||
<h2 style="margin-top:20px"><%= t("tournaments.hub.tabs.tabellone") %></h2>
|
||||
<ul>
|
||||
<% @rounds.each do |round| %>
|
||||
<li><%= round.name %></li>
|
||||
<% end %>
|
||||
</ul>
|
||||
<% end %>
|
||||
</div>
|
||||
@@ -0,0 +1,113 @@
|
||||
<div class="card">
|
||||
<% if @writable && @tournament.uses_knockout? %>
|
||||
<div class="tournament-knockout-help">
|
||||
<h2 style="margin-top:0"><%= t("tournaments.hub.knockout_how_title") %></h2>
|
||||
<ol class="tournament-knockout-help__steps">
|
||||
<li><%= t("tournaments.hub.knockout_how_groups") %></li>
|
||||
<li><%= t("tournaments.hub.knockout_how_seed") %></li>
|
||||
<li><%= t("tournaments.hub.knockout_how_advance") %></li>
|
||||
</ol>
|
||||
<% if @tournament.uses_groups? %>
|
||||
<%= button_to t("tournaments.hub.propose_knockout"),
|
||||
public_propose_knockout_tournament_path(@tournament),
|
||||
method: :post, class: "btn btn-primary" %>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<% @groups.each do |group| %>
|
||||
<h2 style="margin-top:20px"><%= group.name %> — <%= t("tournaments.hub.standings") %></h2>
|
||||
<% rows = @standings_by_group[group] %>
|
||||
<% if rows.any? %>
|
||||
<table class="data">
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th><%= t("tournaments.hub.played") %></th>
|
||||
<th><%= t("tournaments.hub.won") %></th>
|
||||
<th><%= t("tournaments.hub.lost") %></th>
|
||||
<th><%= t("tournaments.hub.points") %></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% rows.each_with_index do |row, idx| %>
|
||||
<tr>
|
||||
<td><%= idx + 1 %>. <%= tournament_team_chip(row.participant) %></td>
|
||||
<td><%= row.played %></td>
|
||||
<td><%= row.won %></td>
|
||||
<td><%= row.lost %></td>
|
||||
<td><strong><%= row.points %></strong></td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
<% @rounds.each do |round| %>
|
||||
<h2 style="margin-top:24px"><%= round.name %></h2>
|
||||
<% round_matches = @matches.select { |m| m.tournament_round_id == round.id } %>
|
||||
<% if round_matches.any? %>
|
||||
<div class="tournament-table-wrap">
|
||||
<table class="data tournament-match-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><%= t("tournaments.hub.datetime") %></th>
|
||||
<th><%= t("tournaments.hub.home") %></th>
|
||||
<th><%= t("tournaments.hub.away") %></th>
|
||||
<th><%= t("tournaments.hub.result") %></th>
|
||||
<% if @writable %><th></th><% end %>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% round_matches.each do |match| %>
|
||||
<% form_id = "ko-edit-#{match.id}" %>
|
||||
<%= form_with url: public_tournament_match_path(@tournament, match), method: :patch, html: { id: form_id, class: "visually-hidden" } do %>
|
||||
<%= hidden_field_tag :tab, "tabellone", form: form_id %>
|
||||
<%= datetime_local_field_tag "match[scheduled_at]", tournament_datetime_local(match.scheduled_at),
|
||||
id: "ko_at_#{match.id}", form: form_id %>
|
||||
<% end %>
|
||||
<tr>
|
||||
<td><%= match.scheduled_at ? l(match.scheduled_at, format: :short) : "—" %></td>
|
||||
<td>
|
||||
<%= render "public/tournaments/match_side_select", match: match, side: :home, form_id: form_id %>
|
||||
<% src = tournament_side_source_label(match, :home) %>
|
||||
<% if src.present? && match.home_participant_id.blank? %>
|
||||
<div class="tournament-knockout-source"><%= src %></div>
|
||||
<% end %>
|
||||
</td>
|
||||
<td>
|
||||
<%= render "public/tournaments/match_side_select", match: match, side: :away, form_id: form_id %>
|
||||
<% src = tournament_side_source_label(match, :away) %>
|
||||
<% if src.present? && match.away_participant_id.blank? %>
|
||||
<div class="tournament-knockout-source"><%= src %></div>
|
||||
<% end %>
|
||||
</td>
|
||||
<td>
|
||||
<% if tournament_match_sides_locked?(match) %>
|
||||
<%= match.home_score %>–<%= match.away_score %>
|
||||
<% elsif @writable %>
|
||||
<span class="tournament-match-form__score">
|
||||
<%= number_field_tag :home_score, match.home_score, id: "ko_home_score_#{match.id}", form: form_id %>
|
||||
<span>–</span>
|
||||
<%= number_field_tag :away_score, match.away_score, id: "ko_away_score_#{match.id}", form: form_id %>
|
||||
</span>
|
||||
<% else %>
|
||||
—
|
||||
<% end %>
|
||||
</td>
|
||||
<% if @writable %>
|
||||
<td class="tournament-match-form__actions">
|
||||
<%= submit_tag t("tournaments.hub.save_match"), form: form_id, class: "btn btn-secondary tournament-match-form__save" %>
|
||||
</td>
|
||||
<% end %>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<% else %>
|
||||
<p class="tournament-hub-hint"><%= t("tournaments.hub.knockout_round_empty") %></p>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
@@ -0,0 +1,61 @@
|
||||
<% content_for :title, t("tournaments.index.title", name: @club.name) %>
|
||||
<% content_for :robots, "noindex, nofollow" %>
|
||||
|
||||
<div class="wrap wrap--portal tournament-hub" style="padding-top:20px">
|
||||
<nav class="team-dashboard-nav">
|
||||
<%= link_to "← #{@club.name}", public_club_path(@club), class: "team-dashboard-nav__club" %>
|
||||
</nav>
|
||||
|
||||
<header style="margin:16px 0 20px;display:flex;flex-wrap:wrap;gap:12px;align-items:flex-start;justify-content:space-between">
|
||||
<div>
|
||||
<h1><%= t("tournaments.index.heading") %></h1>
|
||||
<p style="color:#888;margin:8px 0 0"><%= t("tournaments.index.lead") %></p>
|
||||
</div>
|
||||
<% if @can_create %>
|
||||
<%= link_to t("tournaments.index.new"), public_new_club_tournament_path(@club), class: "btn btn-primary" %>
|
||||
<% end %>
|
||||
</header>
|
||||
|
||||
<% unless @can_create %>
|
||||
<div class="flash alert"><%= t("tournaments.index.upgrade") %> <%= link_to t("club.dashboard.subscription"), public_club_billing_path(@club) %></div>
|
||||
<% end %>
|
||||
|
||||
<div class="card">
|
||||
<% if @tournaments.any? %>
|
||||
<div class="tournament-table-wrap">
|
||||
<table class="data">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><%= t("tournaments.index.col_name") %></th>
|
||||
<th><%= t("tournaments.index.col_dates") %></th>
|
||||
<th><%= t("tournaments.index.col_status") %></th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% @tournaments.each do |tournament| %>
|
||||
<tr>
|
||||
<td><strong><%= tournament.name %></strong></td>
|
||||
<td><%= l(tournament.starts_on) %> – <%= l(tournament.ends_on) %></td>
|
||||
<td><%= t("tournaments.status.#{tournament.status}") %></td>
|
||||
<td>
|
||||
<div class="tournament-index-actions">
|
||||
<%= link_to t("tournaments.index.open"), public_tournament_path(tournament), class: "btn btn-secondary", style: "padding:8px 14px;font-size:0.9rem" %>
|
||||
<% if tournament.published? %>
|
||||
<%= link_to t("tournaments.hub.public_page"), public_tournament_page_path(tournament.slug), class: "btn btn-secondary", style: "padding:8px 14px;font-size:0.9rem", target: "_blank", rel: "noopener" %>
|
||||
<% end %>
|
||||
<%= button_to t("tournaments.index.delete"), public_tournament_path(tournament), method: :delete,
|
||||
class: "btn btn-secondary", style: "padding:8px 14px;font-size:0.9rem",
|
||||
form: { data: { turbo_confirm: t("tournaments.hub.delete_confirm", name: tournament.name), confirm_kind: "delete" } } %>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<% else %>
|
||||
<p style="color:#888;margin:0"><%= t("tournaments.index.empty") %></p>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,79 @@
|
||||
<% content_for :title, t("tournaments.new.title", name: @club.name) %>
|
||||
<% content_for :robots, "noindex, nofollow" %>
|
||||
|
||||
<div class="wrap wrap--portal tournament-new" style="padding-top:20px">
|
||||
<nav class="team-dashboard-nav">
|
||||
<%= link_to "← #{t("tournaments.index.heading")}", public_club_tournaments_path(@club), class: "team-dashboard-nav__club" %>
|
||||
</nav>
|
||||
<h1><%= t("tournaments.new.heading") %></h1>
|
||||
<p class="tournament-new__lead"><%= t("tournaments.index.lead") %></p>
|
||||
|
||||
<div class="card" style="margin-top:16px">
|
||||
<%= form_with model: @tournament, url: public_club_tournaments_path(@club), method: :post, html: { class: "tournament-form", multipart: true, data: { tournament_form: true } } do %>
|
||||
<div class="tournament-form__field tournament-form__full">
|
||||
<%= label_tag "tournament[name]", t("tournaments.form.name") %>
|
||||
<%= text_field_tag "tournament[name]", @tournament.name, required: true %>
|
||||
</div>
|
||||
|
||||
<div class="tournament-form__field">
|
||||
<%= label_tag "tournament[sport_key]", t("tournaments.form.sport") %>
|
||||
<%= select_tag "tournament[sport_key]",
|
||||
options_for_select(Sports::Catalog.as_api_list.map { |s| [s[:label], s[:key]] }, @tournament.sport_key) %>
|
||||
</div>
|
||||
|
||||
<div class="tournament-form__field">
|
||||
<%= label_tag "tournament[venue]", t("tournaments.form.venue") %>
|
||||
<%= text_field_tag "tournament[venue]", @tournament.venue %>
|
||||
</div>
|
||||
|
||||
<div class="tournament-form__field">
|
||||
<%= label_tag "tournament[starts_on]", t("tournaments.form.starts_on") %>
|
||||
<%= date_field_tag "tournament[starts_on]", @tournament.starts_on, required: true %>
|
||||
</div>
|
||||
|
||||
<div class="tournament-form__field">
|
||||
<%= label_tag "tournament[ends_on]", t("tournaments.form.ends_on") %>
|
||||
<%= date_field_tag "tournament[ends_on]", @tournament.ends_on, required: true %>
|
||||
</div>
|
||||
|
||||
<div class="tournament-form__field">
|
||||
<%= label_tag "tournament[format_kind]", t("tournaments.form.format") %>
|
||||
<%= select_tag "tournament[format_kind]",
|
||||
options_for_select(Tournament::FORMAT_KINDS.map { |k| [t("tournaments.form.formats.#{k}"), k] }, @tournament.format_kind),
|
||||
data: { tournament_format: true } %>
|
||||
</div>
|
||||
|
||||
<div class="tournament-form__field" data-knockout-field>
|
||||
<%= label_tag "tournament[knockout_size]", t("tournaments.form.knockout_size") %>
|
||||
<%= select_tag "tournament[knockout_size]", options_for_select([2, 4, 8, 16], @tournament.knockout_size || 4) %>
|
||||
</div>
|
||||
|
||||
<div class="tournament-form__field tournament-form__full">
|
||||
<%= label_tag "tournament[logo_file]", t("tournaments.form.logo") %>
|
||||
<%= file_field_tag "tournament[logo_file]", accept: "image/png,image/jpeg,image/webp" %>
|
||||
<p class="tournament-hub-hint" style="margin:6px 0 0"><%= t("tournaments.form.logo_hint") %></p>
|
||||
</div>
|
||||
|
||||
<div class="tournament-form__field tournament-form__full">
|
||||
<%= label_tag "tournament[courts]", t("tournaments.form.courts") %>
|
||||
<%= text_area_tag "tournament[courts]", Array(@tournament.courts).join("\n"), rows: 3 %>
|
||||
</div>
|
||||
|
||||
<div class="tournament-form__actions">
|
||||
<%= submit_tag t("tournaments.new.submit"), class: "btn btn-primary" %>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
document.querySelectorAll("[data-tournament-form]").forEach(function (form) {
|
||||
var format = form.querySelector("[data-tournament-format]");
|
||||
var knockout = form.querySelector("[data-knockout-field]");
|
||||
if (!format || !knockout) return;
|
||||
var sync = function () {
|
||||
knockout.hidden = !(format.value === "knockout" || format.value === "mixed");
|
||||
};
|
||||
format.addEventListener("change", sync);
|
||||
sync();
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,73 @@
|
||||
<% content_for :title, t("tournaments.hub.title", name: @tournament.name) %>
|
||||
<% content_for :robots, "noindex, nofollow" %>
|
||||
|
||||
<div class="wrap wrap--portal tournament-hub" style="padding-top:20px">
|
||||
<nav class="team-dashboard-nav">
|
||||
<%= link_to "← #{t("tournaments.index.heading")}", public_club_tournaments_path(@club), class: "team-dashboard-nav__club" %>
|
||||
</nav>
|
||||
|
||||
<header class="tournament-hub-header">
|
||||
<div class="tournament-hub-header__identity">
|
||||
<% logo = @tournament.effective_logo_url %>
|
||||
<div class="tournament-hub-logo">
|
||||
<div class="tournament-hub-logo__preview" aria-hidden="true">
|
||||
<% if logo.present? %>
|
||||
<%= image_tag logo, alt: "" %>
|
||||
<% else %>
|
||||
<span class="tournament-hub-logo__empty"><%= @tournament.name.to_s.first %></span>
|
||||
<% end %>
|
||||
</div>
|
||||
<% if @writable %>
|
||||
<%= form_with model: @tournament, url: public_tournament_path(@tournament), method: :patch,
|
||||
html: { class: "tournament-hub-logo__form", multipart: true } do %>
|
||||
<label class="btn btn-secondary tournament-hub-logo__btn">
|
||||
<%= t("tournaments.hub.logo_file") %>
|
||||
<%= file_field_tag "tournament[logo_file]", accept: "image/png,image/jpeg,image/webp", onchange: "this.form.requestSubmit()" %>
|
||||
</label>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
<div class="tournament-hub-header__text">
|
||||
<h1><%= @tournament.name %></h1>
|
||||
<p>
|
||||
<%= @tournament.sport_label %>
|
||||
· <%= l(@tournament.starts_on) %> – <%= l(@tournament.ends_on) %>
|
||||
· <%= t("tournaments.status.#{@tournament.status}") %>
|
||||
· <%= t("tournaments.form.formats.#{@tournament.format_kind}") %>
|
||||
</p>
|
||||
<% if @writable %>
|
||||
<p class="tournament-hub-hint" style="margin:4px 0 0"><%= t("tournaments.hub.tournament_logo_hint") %></p>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tournament-hub-header__actions">
|
||||
<% if @tournament.published? %>
|
||||
<%= link_to t("tournaments.hub.public_page"), public_tournament_page_path(@tournament.slug), class: "btn btn-secondary", target: "_blank", rel: "noopener" %>
|
||||
<% if @writable %>
|
||||
<%= button_to t("tournaments.hub.unpublish"), public_unpublish_tournament_path(@tournament), method: :post, class: "btn btn-secondary" %>
|
||||
<% end %>
|
||||
<% elsif @writable %>
|
||||
<%= button_to t("tournaments.hub.publish"), public_publish_tournament_path(@tournament), method: :post, class: "btn btn-primary" %>
|
||||
<% end %>
|
||||
<% if @writable && !@tournament.archived? %>
|
||||
<%= button_to t("tournaments.hub.archive"), public_archive_tournament_path(@tournament), method: :post, class: "btn btn-secondary", form: { data: { turbo_confirm: t("tournaments.hub.archive") } } %>
|
||||
<% end %>
|
||||
<%= button_to t("tournaments.hub.delete"), public_tournament_path(@tournament), method: :delete, class: "btn btn-secondary",
|
||||
form: { data: { turbo_confirm: t("tournaments.hub.delete_confirm", name: @tournament.name), confirm_kind: "delete" } } %>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<% @overlap_warnings.each do |warning| %>
|
||||
<div class="flash alert"><%= warning %></div>
|
||||
<% end %>
|
||||
|
||||
<nav style="display:flex;gap:8px;flex-wrap:wrap;margin-bottom:16px">
|
||||
<% %w[squadre struttura calendario dirette tabellone].each do |tab| %>
|
||||
<%= link_to t("tournaments.hub.tabs.#{tab}"), public_tournament_path(@tournament, tab: tab),
|
||||
class: "btn #{@tab == tab ? 'btn-primary' : 'btn-secondary'}",
|
||||
style: "padding:8px 14px;font-size:0.9rem" %>
|
||||
<% end %>
|
||||
</nav>
|
||||
|
||||
<%= render "public/tournaments/tab_#{@tab}" %>
|
||||
</div>
|
||||
Reference in New Issue
Block a user