@ -15,21 +15,23 @@ struct TournamentGeneralSettingsView: View {
@ 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
@ State private var umpireCustomMail : String
@ State private var umpireCustomPhone : String
@ State private var umpireCustomContact : String
@ State private var umpireCustomMailIsInvalid : Bool = false
@ State private var umpireCustomPhoneIsInvalid : Bool = false
@ 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 )
_umpireCustomMail = State ( wrappedValue : tournament . umpireCustomMail ? ? " " )
_umpireCustomPhone = State ( wrappedValue : tournament . umpireCustomPhone ? ? " " )
_umpireCustomContact = State ( wrappedValue : tournament . umpireCustomContact ? ? " " )
}
var body : some View {
@ -78,6 +80,22 @@ struct TournamentGeneralSettingsView: View {
_customUmpireView ( )
Section {
if tournament . hideUmpireMail , tournament . hideUmpirePhone , tournament . enableOnlineRegistration {
Text ( " Attention, les emails envoyés automatiquement au regard des inscriptions en ligne ne contiendront aucun moyen de vous contacter. " ) . foregroundStyle ( . logoRed )
}
Toggle ( isOn : $ tournament . hideUmpireMail ) {
Text ( " Masquer l'email " )
}
Toggle ( isOn : $ tournament . hideUmpirePhone ) {
Text ( " Masquer le téléphone " )
}
} footer : {
Text ( " Ces informations ne seront pas affichées sur la page d'information du tournoi sur Padel Club et dans les emails envoyés automatiquement au regard des inscriptions en lignes. " )
}
Section {
TextField ( " Nom du tournoi " , text : $ tournamentName , axis : . vertical )
. lineLimit ( 2 )
@ -110,53 +128,7 @@ struct TournamentGeneralSettingsView: View {
tournamentInformation . append ( " \n " + tournament . entryFeeMessage )
}
}
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 {
@ -196,14 +168,12 @@ struct TournamentGeneralSettingsView: View {
Button ( " Effacer " ) {
tournament . name = nil
tournamentName = " "
_save ( )
}
. buttonStyle ( . borderless )
} else if focusedField = = . _information , tournamentInformation . isEmpty = = false {
Button ( " Effacer " ) {
tournament . information = nil
tournamentInformation = " "
_save ( )
}
. buttonStyle ( . borderless )
} else if focusedField = = . _umpireCustomMail , umpireCustomMail . isEmpty = = false {
@ -211,29 +181,20 @@ struct TournamentGeneralSettingsView: View {
_deleteUmpireMail ( )
}
. buttonStyle ( . borderless )
} else if focusedField = = . _umpireCustomPhone , umpireCustomPhone . isEmpty = = false {
Button ( " Effacer " ) {
_deleteUmpirePhone ( )
}
. buttonStyle ( . borderless )
} else if focusedField = = . _umpireCustomContact , umpireCustomContact . isEmpty = = false {
Button ( " Effacer " ) {
_deleteUmpireContact ( )
}
. buttonStyle ( . borderless )
}
}
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
} else if focusedField = = . _umpireCustomMail {
_confirmUmpireMail ( )
}
focusedField = nil
}
. buttonStyle ( . bordered )
@ -247,15 +208,39 @@ struct TournamentGeneralSettingsView: View {
. onChange ( of : tournament . entryFee ) {
_save ( )
}
. onChange ( of : [ tournament . name , tournament . information ] ) {
. onChange ( of : [ tournament . name , tournament . information , tournament . umpireCustomMail , tournament . umpireCustomPhone , tournament . umpireCustomContact ] ) {
_save ( )
}
. onChange ( of : [ tournament . hideUmpireMail , tournament . hideUmpirePhone ] ) {
_save ( )
}
. onChange ( of : tournament . dayDuration ) {
_save ( )
}
. onChange ( of : [
tournament . groupStageSortMode ,
] ) {
. onChange ( of : focusedField ) { old , new in
if old = = . _name {
let tournamentName = tournamentName . prefixMultilineTrimmed ( 200 )
if tournamentName . isEmpty {
tournament . name = nil
} else {
tournament . name = tournamentName
}
} else if old = = . _information {
let tournamentInformation = tournamentInformation . prefixMultilineTrimmed ( 4000 )
if tournamentInformation . isEmpty {
tournament . information = nil
} else {
tournament . information = tournamentInformation
}
} else if old = = . _entryFee {
tournament . entryFee = entryFee
} else if old = = . _umpireCustomMail {
_confirmUmpireMail ( )
} else if old = = . _umpireCustomPhone {
_confirmUmpirePhone ( )
} else if old = = . _umpireCustomContact {
_confirmUmpireContact ( )
}
_save ( )
}
}
@ -264,10 +249,8 @@ struct TournamentGeneralSettingsView: View {
umpireCustomMailIsInvalid = false
if umpireCustomMail . isEmpty {
tournament . umpireCustomMail = nil
_save ( )
} else if umpireCustomMail . isValidEmail ( ) {
tournament . umpireCustomMail = umpireCustomMail
_save ( )
} else {
umpireCustomMailIsInvalid = true
}
@ -277,47 +260,41 @@ struct TournamentGeneralSettingsView: View {
umpireCustomMailIsInvalid = false
umpireCustomMail = " "
tournament . umpireCustomMail = nil
_save ( )
}
private func _save ( ) {
do {
try dataStore . tournaments . addOrUpdate ( instance : tournament )
} catch {
Logger . error ( error )
private func _confirmUmpirePhone ( ) {
umpireCustomPhoneIsInvalid = false
if umpireCustomPhone . isEmpty {
tournament . umpireCustomPhone = nil
} else if umpireCustomPhone . isPhoneNumber ( ) {
tournament . umpireCustomPhone = umpireCustomPhone . prefixMultilineTrimmed ( 15 )
} else {
umpireCustomPhoneIsInvalid = true
}
}
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 )
}
private func _deleteUmpirePhone ( ) {
umpireCustomPhoneIsInvalid = false
umpireCustomPhone = " "
tournament . umpireCustomPhone = nil
}
private func _confirmUmpireContact ( ) {
if umpireCustomContact . isEmpty {
tournament . umpireCustomContact = nil
} else {
tournament . umpireCustomContact = umpireCustomContact . prefixMultilineTrimmed ( 200 )
}
}
private func _deleteUmpireContact ( ) {
umpireCustomContact = " "
tournament . umpireCustomContact = nil
}
private func _save ( ) {
do {
try self . tournament . tournamentStore ? . rounds . addOrUpdate ( contentOfs : rounds )
try dataStore . tournaments . addOrUpdate ( instance : tournament )
} catch {
Logger . error ( error )
}
@ -325,32 +302,55 @@ struct TournamentGeneralSettingsView: View {
private func _customUmpireView ( ) -> some View {
Section {
if umpireCustomMailIsInvalid {
Text ( " Vous n'avez pas indiqué un email valide. " ) . foregroundStyle ( . logoRed )
VStack ( alignment : . leading ) {
TextField ( dataStore . user . email , text : $ umpireCustomMail )
. frame ( maxWidth : . infinity )
. keyboardType ( . emailAddress )
. autocapitalization ( . none )
. focused ( $ focusedField , equals : . _umpireCustomMail )
. onSubmit {
_confirmUmpireMail ( )
}
if umpireCustomMailIsInvalid {
Text ( " Vous n'avez pas indiqué un email valide. " ) . foregroundStyle ( . logoRed )
}
}
TextField ( dataStore . user . email , text : $ umpireCustomMail )
. frame ( maxWidth : . infinity )
. keyboardType ( . emailAddress )
. focused ( $ focusedField , equals : . _umpireCustomMail )
. onSubmit {
_confirmUmpireMail ( )
VStack ( alignment : . leading ) {
TextField ( dataStore . user . phone ? ? " Téléphone " , text : $ umpireCustomPhone )
. frame ( maxWidth : . infinity )
. keyboardType ( . phonePad )
. focused ( $ focusedField , equals : . _umpireCustomPhone )
. onSubmit {
_confirmUmpirePhone ( )
}
if umpireCustomPhoneIsInvalid {
Text ( " Vous n'avez pas indiqué un téléphone valide. " ) . foregroundStyle ( . logoRed )
}
}
VStack ( alignment : . leading ) {
TextField ( dataStore . user . fullName ( ) , text : $ umpireCustomContact )
. frame ( maxWidth : . infinity )
. keyboardType ( . default )
. focused ( $ focusedField , equals : . _umpireCustomContact )
. onSubmit {
_confirmUmpireContact ( )
}
if dataStore . user . summonsMessageSignature != nil , umpireCustomContact != dataStore . user . fullName ( ) {
Text ( " Attention vous avez une signature personnalisée contenant un contact différent. " ) . foregroundStyle ( . logoRed )
FooterButtonView ( " retirer la personnalisation ? " ) {
dataStore . user . summonsMessageSignature = nil
self . dataStore . saveUser ( )
}
} }
} header : {
Text ( " Email du juge-arbitre " )
Text ( " J uge-arbitre" )
} footer : {
Text ( " Cet email sera utilisé pour vous contacter. Vous pouvez le modifier si vous souhaitez utiliser un autre email que celui de votre compte Padel Club. " )
Text ( " Ces informations seront utilisées pour vous contacter. Vous pouvez les modifier si vous souhaitez utiliser les informations de contact différentes de votre compte Padel Club. " )
}
}
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 )
}
}