// // 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 { 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("Gestionnaire", systemImage: "pin") } Divider() } Menu { NavigationLink(value: Screen.event) { Text("Événement") } NavigationLink(value: Screen.settings) { Text("Tournoi") } NavigationLink(value: Screen.structure) { LabelStructure() } Divider() NavigationLink(value: Screen.stateSettings) { Label("Gestion", systemImage: "trash") } .disabled((self.tournament.sharing != nil)) } label: { Label("Réglages", systemImage: "wrench.and.screwdriver") } NavigationLink(value: Screen.call) { Label("Convocations", systemImage: "calendar.badge.clock") } if tournament.tournamentLevel.haveDeadlines() { NavigationLink { List { TournamentDeadlinesView(tournament: tournament) } .toolbarBackground(.visible, for: .navigationBar) .navigationTitle("Rappel des délais") } label: { Label("Rappel des délais", systemImage: "calendarcalendar.badge.exclamationmark") } } NavigationLink(value: Screen.cashier) { Label(tournament.isFree() ? "Présence" : "Encaissement", systemImage: tournament.isFree() ? "person.crop.circle.badge.checkmark" : "eurosign.circle") } NavigationLink(value: Screen.statistics) { Label("Statistiques", systemImage: "123.rectangle") } 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") } if self.tournament.sharing == nil { Divider() NavigationLink(value: Screen.stateSettings) { Text("Gestion du tournoi") Text("Annuler, supprimer ou terminer le tournoi") } } Divider() NavigationLink(value: Screen.stateSettings) { Label("Tournoi", systemImage: "trash") } } 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) // } //}