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.
283 lines
11 KiB
283 lines
11 KiB
//
|
|
// TournamentGeneralSettingsView.swift
|
|
// PadelClub
|
|
//
|
|
// Created by Razmig Sarkissian on 18/04/2024.
|
|
//
|
|
|
|
import SwiftUI
|
|
import LeStorage
|
|
|
|
struct TournamentGeneralSettingsView: View {
|
|
@EnvironmentObject var dataStore: DataStore
|
|
|
|
@Bindable var tournament: Tournament
|
|
@State private var tournamentName: String = ""
|
|
@State private var tournamentInformation: String = ""
|
|
@State private var entryFee: Double? = nil
|
|
@State private var confirmationRequired: Bool = false
|
|
@State private var presentConfirmation: Bool = false
|
|
@State private var loserBracketMode: LoserBracketMode
|
|
@FocusState private var focusedField: Tournament.CodingKeys?
|
|
let priceTags: [Double] = [15.0, 20.0, 25.0]
|
|
|
|
init(tournament: Tournament) {
|
|
self.tournament = tournament
|
|
_loserBracketMode = .init(wrappedValue: tournament.loserBracketMode)
|
|
_tournamentName = State(wrappedValue: tournament.name ?? "")
|
|
_tournamentInformation = State(wrappedValue: tournament.information ?? "")
|
|
_entryFee = State(wrappedValue: tournament.entryFee)
|
|
}
|
|
|
|
var body: some View {
|
|
@Bindable var tournament = tournament
|
|
Form {
|
|
|
|
Section {
|
|
TextField("Nom du tournoi", text: $tournamentName, axis: .vertical)
|
|
.lineLimit(2)
|
|
.frame(maxWidth: .infinity)
|
|
.keyboardType(.alphabet)
|
|
.focused($focusedField, equals: ._name)
|
|
} header: {
|
|
Text("Nom du tournoi")
|
|
}
|
|
|
|
Section {
|
|
ZStack {
|
|
Text(tournamentInformation).opacity(0)
|
|
Text(ContactType.defaultCustomMessage).opacity(0)
|
|
TextEditor(text: $tournamentInformation)
|
|
.keyboardType(.alphabet)
|
|
.focused($focusedField, equals: ._information)
|
|
}
|
|
.frame(maxHeight: 200)
|
|
.overlay {
|
|
if tournamentInformation.isEmpty {
|
|
Text("Texte visible dans l'onglet informations sur Padel Club.").italic()
|
|
}
|
|
}
|
|
} header: {
|
|
Text("Description du tournoi")
|
|
} footer: {
|
|
FooterButtonView("Ajouter le prix de l'inscription") {
|
|
tournamentInformation.append("\n" + tournament.entryFeeMessage)
|
|
}
|
|
}
|
|
|
|
Section {
|
|
TournamentDatePickerView()
|
|
TournamentDurationManagerView()
|
|
LabeledContent {
|
|
TextField(tournament.isFree() ? "Gratuite" : "Inscription", value: $entryFee, format: .currency(code: Locale.defaultCurrency()))
|
|
.keyboardType(.decimalPad)
|
|
.multilineTextAlignment(.trailing)
|
|
.frame(maxWidth: .infinity)
|
|
.focused($focusedField, equals: ._entryFee)
|
|
} label: {
|
|
Text("Inscription")
|
|
}
|
|
} footer: {
|
|
Text("Si vous souhaitez que Padel Club vous aide à suivre les encaissements, indiquer un prix d'inscription. Sinon Padel Club vous aidera à suivre simplement l'arrivée et la présence des joueurs.")
|
|
}
|
|
|
|
Section {
|
|
TournamentLevelPickerView()
|
|
}
|
|
|
|
Section {
|
|
Picker(selection: $loserBracketMode) {
|
|
ForEach(LoserBracketMode.allCases) {
|
|
Text($0.localizedLoserBracketMode()).tag($0)
|
|
}
|
|
} label: {
|
|
Text("Position des perdants")
|
|
}
|
|
.onChange(of: loserBracketMode) {
|
|
if tournament.allLoserRoundMatches().anySatisfy({ $0.hasEnded() }) == false {
|
|
_refreshLoserBracketMode()
|
|
} else {
|
|
confirmationRequired = true
|
|
}
|
|
}
|
|
} header: {
|
|
Text("Matchs de classement")
|
|
} footer: {
|
|
if confirmationRequired == false {
|
|
if dataStore.user.loserBracketMode != tournament.loserBracketMode {
|
|
_footerView()
|
|
.onTapGesture(perform: {
|
|
self.dataStore.user.loserBracketMode = tournament.loserBracketMode
|
|
self.dataStore.saveUser()
|
|
})
|
|
} else {
|
|
Text(tournament.loserBracketMode.localizedLoserBracketModeDescription())
|
|
}
|
|
} else {
|
|
_footerViewConfirmationRequired()
|
|
.onTapGesture(perform: {
|
|
presentConfirmation = true
|
|
})
|
|
}
|
|
}
|
|
}
|
|
.confirmationDialog("Attention", isPresented: $presentConfirmation, actions: {
|
|
Button("Confirmer", role: .destructive) {
|
|
_refreshLoserBracketMode()
|
|
confirmationRequired = false
|
|
}
|
|
Button("Annuler", role: .cancel) {
|
|
loserBracketMode = tournament.loserBracketMode
|
|
}
|
|
|
|
})
|
|
.navigationBarBackButtonHidden(focusedField != nil)
|
|
.toolbar(content: {
|
|
if focusedField != nil {
|
|
ToolbarItem(placement: .topBarLeading) {
|
|
Button("Annuler", role: .cancel) {
|
|
focusedField = nil
|
|
}
|
|
}
|
|
}
|
|
})
|
|
.toolbarBackground(.visible, for: .navigationBar)
|
|
.toolbar {
|
|
if focusedField != nil {
|
|
ToolbarItem(placement: .keyboard) {
|
|
HStack {
|
|
if focusedField == ._entryFee {
|
|
if tournament.isFree() {
|
|
ForEach(priceTags, id: \.self) { priceTag in
|
|
Button(priceTag.formatted(.currency(code: Locale.defaultCurrency()).precision(.fractionLength(0)))) {
|
|
entryFee = priceTag
|
|
tournament.entryFee = priceTag
|
|
focusedField = nil
|
|
}
|
|
.buttonStyle(.bordered)
|
|
}
|
|
} else {
|
|
Button("Gratuit") {
|
|
entryFee = nil
|
|
tournament.entryFee = nil
|
|
focusedField = nil
|
|
}
|
|
.buttonStyle(.bordered)
|
|
|
|
}
|
|
}
|
|
Spacer()
|
|
Button("Valider") {
|
|
if focusedField == ._name {
|
|
let tournamentName = tournamentName.prefixMultilineTrimmed(200)
|
|
if tournamentName.isEmpty {
|
|
tournament.name = nil
|
|
} else {
|
|
tournament.name = tournamentName
|
|
}
|
|
} else if focusedField == ._information {
|
|
let tournamentInformation = tournamentInformation.prefixMultilineTrimmed(4000)
|
|
if tournamentInformation.isEmpty {
|
|
tournament.information = nil
|
|
} else {
|
|
tournament.information = tournamentInformation
|
|
}
|
|
} else if focusedField == ._entryFee {
|
|
tournament.entryFee = entryFee
|
|
}
|
|
focusedField = nil
|
|
}
|
|
.buttonStyle(.bordered)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
.onChange(of: tournament.startDate) {
|
|
_save()
|
|
}
|
|
.onChange(of: tournament.entryFee) {
|
|
_save()
|
|
}
|
|
.onChange(of: [tournament.name, tournament.information]) {
|
|
_save()
|
|
}
|
|
.onChange(of: tournament.dayDuration) {
|
|
_save()
|
|
}
|
|
.onChange(of: [
|
|
tournament.federalCategory,
|
|
]) {
|
|
_save()
|
|
}
|
|
.onChange(of: [
|
|
tournament.federalLevelCategory,
|
|
]) {
|
|
_save()
|
|
}
|
|
.onChange(of: [
|
|
tournament.federalAgeCategory,
|
|
]) {
|
|
_save()
|
|
}
|
|
.onChange(of: [
|
|
tournament.groupStageSortMode,
|
|
]) {
|
|
_save()
|
|
}
|
|
}
|
|
|
|
private func _save() {
|
|
do {
|
|
try dataStore.tournaments.addOrUpdate(instance: tournament)
|
|
} catch {
|
|
Logger.error(error)
|
|
}
|
|
}
|
|
|
|
private func _refreshLoserBracketMode() {
|
|
tournament.loserBracketMode = loserBracketMode
|
|
_save()
|
|
|
|
let rounds = tournament.rounds()
|
|
rounds.forEach { round in
|
|
let matches = round.loserRoundsAndChildren().flatMap({ $0._matches() })
|
|
matches.forEach { match in
|
|
match.resetTeamScores(outsideOf: [])
|
|
match.resetMatch()
|
|
match.confirmed = false
|
|
}
|
|
|
|
round.loserBracketMode = tournament.loserBracketMode
|
|
|
|
if loserBracketMode == .automatic {
|
|
matches.forEach { match in
|
|
match.updateTeamScores()
|
|
}
|
|
}
|
|
|
|
do {
|
|
try self.tournament.tournamentStore.matches.addOrUpdate(contentOfs: matches)
|
|
} catch {
|
|
Logger.error(error)
|
|
}
|
|
}
|
|
|
|
do {
|
|
try self.tournament.tournamentStore.rounds.addOrUpdate(contentOfs: rounds)
|
|
} catch {
|
|
Logger.error(error)
|
|
}
|
|
}
|
|
|
|
private func _footerView() -> some View {
|
|
Text(tournament.loserBracketMode.localizedLoserBracketModeDescription())
|
|
+
|
|
Text(" Modifier le réglage par défaut pour tous vos tournois").foregroundStyle(.blue)
|
|
}
|
|
|
|
private func _footerViewConfirmationRequired() -> some View {
|
|
Text("Au moins un match de classement est terminé, en modifiant ce réglage, les résultats de ces matchs de classement seront perdus.")
|
|
+
|
|
Text(" Modifier quand même ?").foregroundStyle(.red)
|
|
}
|
|
}
|
|
|