Billing Stripe, link regia mobile e staff solo trasmissione.

Aggiunge fatturazione club, pagina regia condivisibile senza account, roster squadre e rimuove la modalità controller dall'app (v1.1.0).

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-05-29 07:23:13 +02:00
parent 4083bc5dee
commit f4b7be0f80
156 changed files with 5033 additions and 2033 deletions

View File

@@ -0,0 +1,102 @@
module Public
class MatchesController < WebBaseController
before_action :require_login!
before_action :set_team
before_action :require_can_schedule!
before_action :set_match, only: %i[edit update destroy]
def index
@matches = @team.matches
.includes(:stream_sessions)
.order(Arel.sql("scheduled_at ASC NULLS LAST"), created_at: :desc)
@can_manage = @team.club.owned_by?(current_user)
end
def new
@match = @team.matches.build(
sport: @team.sport,
sets_to_win: 3,
scheduled_at: default_scheduled_at
)
end
def create
@match = @team.matches.create!(
match_params.merge(sport: @team.sport, sets_to_win: match_params[:sets_to_win].presence || 3)
)
redirect_to public_team_matches_path(@team),
notice: "Partita programmata: #{@match.opponent_name}. Avvia lo streaming dallapp quando sei in palestra."
rescue ActiveRecord::RecordInvalid => e
@match = @team.matches.build(match_params)
flash.now[:alert] = e.record.errors.full_messages.join(", ")
render :new, status: :unprocessable_entity
end
def edit
end
def update
@match.update!(match_params)
redirect_to public_team_matches_path(@team), notice: "Partita aggiornata."
rescue ActiveRecord::RecordInvalid => e
flash.now[:alert] = e.record.errors.full_messages.join(", ")
render :edit, status: :unprocessable_entity
end
def destroy
active = active_session_for(@match)
if active&.resumable?
redirect_to public_team_matches_path(@team),
alert: "Chiudi la diretta prima di eliminare questa partita."
return
end
@match.destroy!
redirect_to public_team_matches_path(@team), notice: "Partita eliminata."
end
private
def set_team
@team = current_user.manageable_teams.find(params[:team_id])
@club = @team.club
end
def require_can_schedule!
return if current_user.can_schedule_for?(@team)
redirect_to public_team_details_path(@team),
alert: "Solo un responsabile trasmissione o il titolare della società possono programmare le partite."
end
def set_match
@match = @team.matches.find(params[:id])
end
def match_params
p = params.require(:match).permit(:opponent_name, :location, :scheduled_at, :sport, :sets_to_win)
p[:scheduled_at] = parse_scheduled_at(p[:scheduled_at]) if p[:scheduled_at].present?
p
end
def parse_scheduled_at(value)
raw = value.to_s.strip
return nil if raw.blank?
Time.zone.strptime(raw, "%Y-%m-%dT%H:%M")
rescue ArgumentError
Time.zone.parse(raw)
end
def default_scheduled_at
t = Time.current + 2.hours
Time.zone.local(t.year, t.month, t.day, t.hour, 0, 0)
end
def active_session_for(match)
match.stream_sessions
.order(created_at: :desc)
.find { |s| !%w[ended error].include?(s.status) }
end
end
end