|
|
|
|
@ -22,6 +22,7 @@ struct TournamentGeneralSettingsView: View { |
|
|
|
|
@State private var umpireCustomContact: String |
|
|
|
|
@State private var umpireCustomMailIsInvalid: Bool = false |
|
|
|
|
@State private var umpireCustomPhoneIsInvalid: Bool = false |
|
|
|
|
@State private var showCurrencyPicker: Bool = false // New state for action sheet |
|
|
|
|
|
|
|
|
|
@FocusState private var focusedField: Tournament.CodingKeys? |
|
|
|
|
let priceTags: [Double] = [15.0, 20.0, 25.0] |
|
|
|
|
@ -45,7 +46,7 @@ struct TournamentGeneralSettingsView: View { |
|
|
|
|
TournamentDatePickerView() |
|
|
|
|
TournamentDurationManagerView() |
|
|
|
|
LabeledContent { |
|
|
|
|
TextField(tournament.isFree() ? "Gratuite" : "Inscription", value: $entryFee, format: .currency(code: Locale.defaultCurrency())) |
|
|
|
|
TextField(tournament.isFree() ? "Gratuite" : "Inscription", value: $entryFee, format: .currency(code: tournament.defaultCurrency())) |
|
|
|
|
.keyboardType(.decimalPad) |
|
|
|
|
.multilineTextAlignment(.trailing) |
|
|
|
|
.frame(maxWidth: .infinity) |
|
|
|
|
@ -60,10 +61,14 @@ struct TournamentGeneralSettingsView: View { |
|
|
|
|
|
|
|
|
|
} label: { |
|
|
|
|
Text("Inscription") |
|
|
|
|
FooterButtonView("modifier la devise") { |
|
|
|
|
showCurrencyPicker = true |
|
|
|
|
} |
|
|
|
|
.font(.footnote) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
LabeledContent { |
|
|
|
|
TextField("Réduction", value: $clubMemberFeeDeduction, format: .currency(code: Locale.defaultCurrency())) |
|
|
|
|
TextField("Réduction", value: $clubMemberFeeDeduction, format: .currency(code: tournament.defaultCurrency())) |
|
|
|
|
.keyboardType(.decimalPad) |
|
|
|
|
.multilineTextAlignment(.trailing) |
|
|
|
|
.frame(maxWidth: .infinity) |
|
|
|
|
@ -84,27 +89,62 @@ struct TournamentGeneralSettingsView: View { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if tournament.onlineRegistrationCanBeEnabled() { |
|
|
|
|
let canEnableOnlinePayment = dataStore.user.canEnableOnlinePayment() |
|
|
|
|
|
|
|
|
|
Section { |
|
|
|
|
NavigationLink { |
|
|
|
|
RegistrationSetupView(tournament: tournament) |
|
|
|
|
// MARK: - Online Registration Row |
|
|
|
|
LabeledContent { |
|
|
|
|
if tournament.enableOnlineRegistration { |
|
|
|
|
Text("Activée") |
|
|
|
|
.foregroundStyle(.green) |
|
|
|
|
.font(.headline) |
|
|
|
|
} else { |
|
|
|
|
Text("Désactivée") |
|
|
|
|
.foregroundStyle(.logoRed) |
|
|
|
|
.font(.headline) |
|
|
|
|
} |
|
|
|
|
} label: { |
|
|
|
|
Text("Inscription en ligne") |
|
|
|
|
Text(tournament.getOnlineRegistrationStatus().statusLocalized()) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// MARK: - Online Payment Row (Conditionally Visible) |
|
|
|
|
if canEnableOnlinePayment { |
|
|
|
|
LabeledContent { |
|
|
|
|
if tournament.enableOnlineRegistration { |
|
|
|
|
Text("activée").foregroundStyle(.green) |
|
|
|
|
if tournament.enableOnlinePayment { |
|
|
|
|
Text("Activé") |
|
|
|
|
.foregroundStyle(.green) |
|
|
|
|
.font(.headline) |
|
|
|
|
} else { |
|
|
|
|
Text("désactivée").foregroundStyle(.logoRed) |
|
|
|
|
Text("Désactivé") |
|
|
|
|
.foregroundStyle(.logoRed) |
|
|
|
|
.font(.headline) |
|
|
|
|
} |
|
|
|
|
} label: { |
|
|
|
|
Text("Accéder aux paramètres") |
|
|
|
|
Text(tournament.getOnlineRegistrationStatus().statusLocalized()) |
|
|
|
|
Text("Paiement en ligne") |
|
|
|
|
Text(tournament.getPaymentStatus().statusLocalized()) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// MARK: - Access Settings Row |
|
|
|
|
NavigationLink { |
|
|
|
|
RegistrationSetupView(tournament: tournament) |
|
|
|
|
} label: { |
|
|
|
|
Text("Accès aux réglages") |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} header: { |
|
|
|
|
Text("Inscription en ligne") |
|
|
|
|
if canEnableOnlinePayment { |
|
|
|
|
Text("Inscription et paiement en ligne") |
|
|
|
|
} else { |
|
|
|
|
Text("Inscription en ligne") |
|
|
|
|
} |
|
|
|
|
} footer: { |
|
|
|
|
Text("Paramétrez les possibilités d'inscription en ligne à votre tournoi via Padel Club") |
|
|
|
|
if canEnableOnlinePayment { |
|
|
|
|
Text("Paramétrez les possibilités d'inscription en ligne à votre tournoi via Padel Club") |
|
|
|
|
} else { |
|
|
|
|
Text("Paramétrez les possibilités d'inscription et paiement en ligne à votre tournoi via Padel Club") |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -156,9 +196,14 @@ struct TournamentGeneralSettingsView: View { |
|
|
|
|
} footer: { |
|
|
|
|
FooterButtonView("Ajouter le prix de l'inscription") { |
|
|
|
|
tournamentInformation.append("\n" + tournament.entryFeeMessage) |
|
|
|
|
_save() |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
.sheet(isPresented: $showCurrencyPicker, content: { |
|
|
|
|
CurrencySelectorView() |
|
|
|
|
.environment(tournament) |
|
|
|
|
}) |
|
|
|
|
.navigationBarBackButtonHidden(focusedField != nil) |
|
|
|
|
.toolbar(content: { |
|
|
|
|
if focusedField != nil { |
|
|
|
|
@ -177,7 +222,7 @@ struct TournamentGeneralSettingsView: View { |
|
|
|
|
if focusedField == ._entryFee { |
|
|
|
|
if tournament.isFree() { |
|
|
|
|
ForEach(priceTags, id: \.self) { priceTag in |
|
|
|
|
Button(priceTag.formatted(.currency(code: Locale.defaultCurrency()).precision(.fractionLength(0)))) { |
|
|
|
|
Button(priceTag.formatted(.currency(code: tournament.defaultCurrency()).precision(.fractionLength(0)))) { |
|
|
|
|
entryFee = priceTag |
|
|
|
|
tournament.entryFee = priceTag |
|
|
|
|
focusedField = nil |
|
|
|
|
@ -195,7 +240,7 @@ struct TournamentGeneralSettingsView: View { |
|
|
|
|
} |
|
|
|
|
} else if focusedField == ._clubMemberFeeDeduction { |
|
|
|
|
ForEach(deductionTags, id: \.self) { deductionTag in |
|
|
|
|
Button(deductionTag.formatted(.currency(code: Locale.defaultCurrency()).precision(.fractionLength(0)))) { |
|
|
|
|
Button(deductionTag.formatted(.currency(code: tournament.defaultCurrency()).precision(.fractionLength(0)))) { |
|
|
|
|
clubMemberFeeDeduction = deductionTag |
|
|
|
|
tournament.clubMemberFeeDeduction = deductionTag |
|
|
|
|
focusedField = nil |
|
|
|
|
@ -291,6 +336,100 @@ struct TournamentGeneralSettingsView: View { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
struct CurrencySelectorView: View { |
|
|
|
|
@EnvironmentObject var dataStore: DataStore |
|
|
|
|
@Environment(Tournament.self) var tournament |
|
|
|
|
@Environment(\.dismiss) var dismiss |
|
|
|
|
@State private var currencySearchText: String = "" |
|
|
|
|
|
|
|
|
|
func formatter(forCurrencyCode currencyCode: String) -> NumberFormatter { |
|
|
|
|
let formatter = NumberFormatter() |
|
|
|
|
formatter.numberStyle = .currency |
|
|
|
|
formatter.currencyCode = currencyCode |
|
|
|
|
return formatter |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
struct CurrencyData: Identifiable { |
|
|
|
|
let id: String |
|
|
|
|
let name: String |
|
|
|
|
let symbol: String |
|
|
|
|
|
|
|
|
|
init?(code: String) { |
|
|
|
|
if let name = Locale.current.localizedString(forCurrencyCode: code) { |
|
|
|
|
let formatter = NumberFormatter() |
|
|
|
|
formatter.numberStyle = .currency |
|
|
|
|
formatter.currencyCode = code |
|
|
|
|
self.symbol = formatter.currencySymbol ?? code |
|
|
|
|
self.id = code |
|
|
|
|
self.name = name |
|
|
|
|
} else { |
|
|
|
|
return nil |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
let currencies : [CurrencyData] = Locale.Currency.isoCurrencies.sorted(by: { Locale.current.localizedString(forCurrencyCode: $0.identifier) ?? $0.identifier < Locale.current.localizedString(forCurrencyCode: $1.identifier) ?? $1.identifier }).compactMap { currency in |
|
|
|
|
CurrencyData(code: currency.identifier) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
var currencyCode: Binding<String?> { |
|
|
|
|
Binding { |
|
|
|
|
tournament.defaultCurrency() |
|
|
|
|
} set: { currency in |
|
|
|
|
tournament.currencyCode = currency |
|
|
|
|
dataStore.tournaments.addOrUpdate(instance: tournament) |
|
|
|
|
dismiss() |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
var filteredCurrencies: [CurrencyData] { |
|
|
|
|
if currencySearchText.isEmpty { |
|
|
|
|
return currencies |
|
|
|
|
} else { |
|
|
|
|
return currencies.filter { |
|
|
|
|
$0.name.lowercased().contains(currencySearchText.lowercased()) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
var body: some View { |
|
|
|
|
NavigationStack { |
|
|
|
|
List(selection: currencyCode) { |
|
|
|
|
Section { |
|
|
|
|
LabeledContent { |
|
|
|
|
Text(tournament.defaultCurrency()) |
|
|
|
|
} label: { |
|
|
|
|
Text("Devise utilisée du tournoi") |
|
|
|
|
} |
|
|
|
|
} header: { |
|
|
|
|
Text("") |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Section { |
|
|
|
|
ForEach(filteredCurrencies) { currency in |
|
|
|
|
LabeledContent { |
|
|
|
|
Text(currency.symbol) |
|
|
|
|
} label: { |
|
|
|
|
Text(currency.name) |
|
|
|
|
} |
|
|
|
|
.tag(currency.id) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
.navigationBarTitle("Choisir une devise") |
|
|
|
|
.searchable(text: $currencySearchText, placement: .navigationBarDrawer(displayMode: .always)) |
|
|
|
|
.toolbar { |
|
|
|
|
ToolbarItem(placement: .topBarLeading) { |
|
|
|
|
Button("Retour", role: .cancel) { |
|
|
|
|
self.dismiss() |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
.toolbarBackground(.visible, for: .navigationBar) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private func _confirmUmpireMail() { |
|
|
|
|
umpireCustomMailIsInvalid = false |
|
|
|
|
if umpireCustomMail.isEmpty { |
|
|
|
|
|