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/Screen/Components/TournamentGeneralSettingsVi...

355 lines
15 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 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
_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 {
@Bindable var tournament = tournament
Form {
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.")
}
if tournament.onlineRegistrationCanBeEnabled() {
Section {
NavigationLink {
RegistrationSetupView(tournament: tournament)
} label: {
LabeledContent {
if tournament.enableOnlineRegistration {
Text("activée").foregroundStyle(.green)
.font(.headline)
} else {
Text("désactivée").foregroundStyle(.logoRed)
.font(.headline)
}
} label: {
Text("Accéder aux paramètres")
Text(tournament.getOnlineRegistrationStatus().statusLocalized())
}
}
} header: {
Text("Inscription en ligne")
} footer: {
Text("Paramétrez les possibilités d'inscription en ligne à votre tournoi via Padel Club")
}
}
_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)
.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, focusedField != ._information {
Text("Texte visible dans l'onglet informations sur Padel Club.").italic()
.foregroundStyle(.secondary)
}
}
} header: {
Text("Description du tournoi")
} footer: {
FooterButtonView("Ajouter le prix de l'inscription") {
tournamentInformation.append("\n" + tournament.entryFeeMessage)
}
}
}
.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)
}
} else {
if focusedField == ._name, tournamentName.isEmpty == false {
Button("Effacer") {
tournament.name = nil
tournamentName = ""
}
.buttonStyle(.borderless)
} else if focusedField == ._information, tournamentInformation.isEmpty == false {
Button("Effacer") {
tournament.information = nil
tournamentInformation = ""
}
.buttonStyle(.borderless)
} else if focusedField == ._umpireCustomMail, umpireCustomMail.isEmpty == false {
Button("Effacer") {
_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") {
focusedField = nil
}
.buttonStyle(.bordered)
}
}
}
}
.onChange(of: tournament.startDate) {
_save()
}
.onChange(of: tournament.entryFee) {
_save()
}
.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: 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()
}
}
}
private func _confirmUmpireMail() {
umpireCustomMailIsInvalid = false
if umpireCustomMail.isEmpty {
tournament.umpireCustomMail = nil
} else if umpireCustomMail.isValidEmail() {
tournament.umpireCustomMail = umpireCustomMail
} else {
umpireCustomMailIsInvalid = true
}
}
private func _deleteUmpireMail() {
umpireCustomMailIsInvalid = false
umpireCustomMail = ""
tournament.umpireCustomMail = nil
}
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 _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 dataStore.tournaments.addOrUpdate(instance: tournament)
} catch {
Logger.error(error)
}
}
private func _customUmpireView() -> some View {
Section {
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)
}
}
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.getSummonsMessageSignature() != 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("Juge-arbitre")
} footer: {
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.")
}
}
}