You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
335 lines
13 KiB
335 lines
13 KiB
//
|
|
// TournamentView.swift
|
|
// PadelClub
|
|
//
|
|
// Created by Razmig Sarkissian on 29/02/2024.
|
|
//
|
|
|
|
import SwiftUI
|
|
import LeStorage
|
|
import TipKit
|
|
import PadelClubData
|
|
|
|
struct TournamentView: View {
|
|
@EnvironmentObject var dataStore: DataStore
|
|
|
|
@Environment(NavigationViewModel.self) var navigation: NavigationViewModel
|
|
@State var tournament: Tournament
|
|
@State private var showMoreInfos: Bool = false
|
|
@State var shouldTournamentBeOver: Bool = false
|
|
|
|
var presentationContext: PresentationContext = .agenda
|
|
|
|
let tournamentSelectionTip: TournamentSelectionTip = TournamentSelectionTip()
|
|
let tournamentRunningTip: TournamentRunningTip = TournamentRunningTip()
|
|
let onlineRegistrationTip: OnlineRegistrationTip = OnlineRegistrationTip()
|
|
let shouldTournamentBeOverTip: ShouldTournamentBeOverTip = ShouldTournamentBeOverTip()
|
|
|
|
var selectedTournamentId: Binding<String> { Binding(
|
|
get: { tournament.id },
|
|
set: { id in
|
|
if let tournamentFound: Tournament = Store.main.findById(id) {
|
|
self.tournament = tournamentFound
|
|
}
|
|
}
|
|
)}
|
|
|
|
var lastDataSource: String? {
|
|
dataStore.appSettings.lastDataSource
|
|
}
|
|
|
|
var _lastDataSourceDate: Date? {
|
|
guard let lastDataSource else { return nil }
|
|
return URL.importDateFormatter.date(from: lastDataSource)
|
|
}
|
|
|
|
init(tournament: Tournament, presentationContext: PresentationContext = .agenda) {
|
|
self.tournament = tournament
|
|
self.presentationContext = presentationContext
|
|
}
|
|
|
|
var body: some View {
|
|
VStack(spacing: 0.0) {
|
|
List {
|
|
if tournament.shouldShowPaymentInfo {
|
|
PaymentStatusView()
|
|
}
|
|
|
|
switch tournament.state() {
|
|
case .canceled:
|
|
Section {
|
|
RowButtonView("Reprendre le tournoi", role: .destructive) {
|
|
tournament.isCanceled = false
|
|
tournament.endDate = nil
|
|
_save()
|
|
}
|
|
}
|
|
case .initial:
|
|
if tournament.enableOnlineRegistration == false, tournament.onlineRegistrationCanBeEnabled() {
|
|
TipView(onlineRegistrationTip) { action in
|
|
if let actionKey = OnlineRegistrationTip.ActionKey(rawValue: action.id) {
|
|
switch actionKey {
|
|
case .enableOnlineRegistration:
|
|
navigation.path.append(Screen.settings)
|
|
case .more:
|
|
self.showMoreInfos = true
|
|
}
|
|
} else {
|
|
print("Unknown action: \(action.id)")
|
|
}
|
|
}
|
|
.tipStyle(tint: .master, asSection: true)
|
|
}
|
|
|
|
Section {
|
|
TournamentInscriptionView(tournament: tournament)
|
|
}
|
|
TournamentInitView(tournament: tournament)
|
|
case .build:
|
|
if tournament.enableOnlineRegistration == false, tournament.onlineRegistrationCanBeEnabled() {
|
|
TipView(onlineRegistrationTip) { action in
|
|
if let actionKey = OnlineRegistrationTip.ActionKey(rawValue: action.id) {
|
|
switch actionKey {
|
|
case .enableOnlineRegistration:
|
|
navigation.path.append(Screen.settings)
|
|
case .more:
|
|
self.showMoreInfos = true
|
|
}
|
|
} else {
|
|
print("Unknown action: \(action.id)")
|
|
}
|
|
}
|
|
.tipStyle(tint: .master, asSection: true)
|
|
}
|
|
|
|
Section {
|
|
TournamentInscriptionView(tournament: tournament)
|
|
}
|
|
TournamentBuildView(tournament: tournament)
|
|
TournamentInitView(tournament: tournament)
|
|
case .running:
|
|
if shouldTournamentBeOver {
|
|
Section {
|
|
TipView(shouldTournamentBeOverTip) { actions in
|
|
navigation.path.append(Screen.stateSettings)
|
|
}
|
|
.tipStyle(tint: .logoRed, asSection: true)
|
|
}
|
|
}
|
|
TournamentBuildView(tournament: tournament)
|
|
TournamentRunningView(tournament: tournament)
|
|
case .finished:
|
|
TournamentBuildView(tournament: tournament)
|
|
TournamentRunningView(tournament: tournament)
|
|
}
|
|
}
|
|
.sheet(isPresented: $showMoreInfos) {
|
|
RegistrationInfoSheetView()
|
|
}
|
|
}
|
|
.task(priority: .background) {
|
|
self.shouldTournamentBeOver = await tournament.shouldTournamentBeOver()
|
|
}
|
|
.environment(tournament)
|
|
.id(tournament.id)
|
|
.toolbarBackground(.visible, for: .navigationBar)
|
|
.navigationDestination(for: Screen.self, destination: { screen in
|
|
Group {
|
|
switch screen {
|
|
case .structure:
|
|
TableStructureView()
|
|
case .settings:
|
|
TournamentSettingsView()
|
|
case .inscription:
|
|
InscriptionManagerView(tournament: tournament)
|
|
case .groupStage:
|
|
GroupStagesView(tournament: tournament)
|
|
case .round:
|
|
RoundsView(tournament: tournament)
|
|
case .schedule:
|
|
TournamentScheduleView(tournament: tournament)
|
|
case .cashier:
|
|
TournamentCashierView(tournament: tournament)
|
|
case .statistics:
|
|
EventStatusView(tournament: tournament)
|
|
.navigationTitle("Statistiques")
|
|
case .call:
|
|
TournamentCallView(tournament: tournament)
|
|
case .rankings:
|
|
TournamentRankView()
|
|
case .broadcast:
|
|
BroadcastView()
|
|
.environment(navigation)
|
|
case .event:
|
|
if let event = tournament.eventObject() {
|
|
EventView(event: event)
|
|
}
|
|
case .print:
|
|
PrintSettingsView(tournament: tournament)
|
|
case .share:
|
|
ShareModelView(instance: tournament)
|
|
case .restingTime:
|
|
TeamRestingView()
|
|
case .stateSettings:
|
|
TournamentStatusView(tournament: tournament)
|
|
|
|
}
|
|
}
|
|
.environment(tournament)
|
|
})
|
|
.navigationBarTitleDisplayMode(.inline)
|
|
.toolbarTitleMenu {
|
|
if let event = tournament.eventObject() {
|
|
if presentationContext == .agenda {
|
|
Picker(selection: selectedTournamentId) {
|
|
ForEach(event.tournaments) { tournament in
|
|
Text(tournament.tournamentTitle(.title)).tag(tournament.id as String)
|
|
}
|
|
} label: {
|
|
|
|
}
|
|
|
|
Divider()
|
|
}
|
|
|
|
NavigationLink(value: Screen.event) {
|
|
Text("Réglages de l'événement")
|
|
}
|
|
}
|
|
|
|
}
|
|
.toolbarBackground(.visible, for: .navigationBar)
|
|
.toolbar {
|
|
ToolbarItem(placement: .principal) {
|
|
VStack(spacing: -4.0) {
|
|
Text(tournament.tournamentTitle(.title)).font(.headline)
|
|
Text(tournament.formattedDate(.title))
|
|
.font(.subheadline).foregroundStyle(.secondary)
|
|
}
|
|
.popoverTip(tournamentSelectionTip)
|
|
.onAppear {
|
|
TournamentSelectionTip.tournamentCount = tournament.eventObject()?.tournaments.count
|
|
}
|
|
}
|
|
|
|
if tournament.isCanceled == false {
|
|
ToolbarItem(placement: .topBarTrailing) {
|
|
Menu {
|
|
|
|
#if DEBUG
|
|
Button {
|
|
Task {
|
|
do {
|
|
try await self.tournament.payIfNecessary()
|
|
} catch {
|
|
Logger.error(error)
|
|
}
|
|
}
|
|
} label: {
|
|
Label("Payer le tournoi", systemImage: "dollarsign.circle.fill")
|
|
}
|
|
#endif
|
|
|
|
if presentationContext == .agenda {
|
|
Button {
|
|
navigation.openTournamentInOrganizer(tournament)
|
|
} label: {
|
|
Label("Voir dans le gestionnaire", systemImage: "line.diagonal.arrow")
|
|
}
|
|
Divider()
|
|
}
|
|
|
|
NavigationLink(value: Screen.event) {
|
|
Text("Réglages de l'événement")
|
|
}
|
|
NavigationLink(value: Screen.settings) {
|
|
LabelSettings()
|
|
}
|
|
|
|
NavigationLink(value: Screen.call) {
|
|
Text("Convocations")
|
|
}
|
|
|
|
if tournament.tournamentLevel.haveDeadlines() {
|
|
NavigationLink {
|
|
List {
|
|
TournamentDeadlinesView(tournament: tournament)
|
|
}
|
|
.toolbarBackground(.visible, for: .navigationBar)
|
|
.navigationTitle("Rappel des délais")
|
|
} label: {
|
|
Text("Rappel des délais")
|
|
}
|
|
}
|
|
|
|
NavigationLink(value: Screen.structure) {
|
|
LabelStructure()
|
|
}
|
|
|
|
NavigationLink(value: Screen.cashier) {
|
|
Text(tournament.isFree() ? "Présence" : "Encaissement")
|
|
}
|
|
|
|
NavigationLink(value: Screen.statistics) {
|
|
Text("Statistiques")
|
|
}
|
|
|
|
|
|
NavigationLink(value: Screen.rankings) {
|
|
LabeledContent {
|
|
if tournament.publishRankings == false {
|
|
Image(systemName: "exclamationmark.circle.fill")
|
|
.foregroundStyle(.logoYellow)
|
|
} else {
|
|
Image(systemName: "checkmark")
|
|
.foregroundStyle(.green)
|
|
}
|
|
} label: {
|
|
Text("Classement final")
|
|
if tournament.publishRankings == false {
|
|
Text("Vérifiez le classement avant de publier").foregroundStyle(.logoRed)
|
|
}
|
|
}
|
|
}
|
|
|
|
NavigationLink(value: Screen.broadcast) {
|
|
Label("Publication", systemImage: "airplayvideo")
|
|
}
|
|
|
|
NavigationLink(value: Screen.print) {
|
|
Label("Imprimer", systemImage: "printer")
|
|
}
|
|
|
|
// NavigationLink(value: Screen.share) {
|
|
// Label("Partager", systemImage: "square.and.arrow.up")
|
|
// }
|
|
|
|
Divider()
|
|
|
|
NavigationLink(value: Screen.stateSettings) {
|
|
Text("Gestion du tournoi")
|
|
Text("Annuler, supprimer ou terminer le tournoi")
|
|
}
|
|
} label: {
|
|
LabelOptions()
|
|
.popoverTip(tournamentRunningTip)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
.onAppear {
|
|
TournamentRunningTip.isRunning = tournament.state() == .running
|
|
Logger.log("Tournament Id = \(self.tournament.id), Payment = \(String(describing: self.tournament.payment))")
|
|
}
|
|
}
|
|
|
|
private func _save() {
|
|
dataStore.tournaments.addOrUpdate(instance: tournament)
|
|
}
|
|
}
|
|
|
|
//#Preview {
|
|
// NavigationStack {
|
|
// TournamentView(tournament: Tournament.mock(), presentationContext: .agenda)
|
|
// }
|
|
//}
|
|
|