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.
 
 
PadelClub/PadelClub/Views/Tournament/TournamentView.swift

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)
// }
//}