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.
547 lines
22 KiB
547 lines
22 KiB
//
|
|
// UmpireView.swift
|
|
// PadelClub
|
|
//
|
|
// Created by Razmig Sarkissian on 01/03/2024.
|
|
//
|
|
|
|
import SwiftUI
|
|
import CoreLocation
|
|
import LeStorage
|
|
import StoreKit
|
|
import PadelClubData
|
|
|
|
struct UmpireView: View {
|
|
|
|
@Environment(NavigationViewModel.self) private var navigation: NavigationViewModel
|
|
@EnvironmentObject var dataStore: DataStore
|
|
|
|
@State private var presentSearchView: Bool = false
|
|
@State private var showSubscriptions: Bool = false
|
|
@State private var showProductIds: Bool = false
|
|
@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
|
|
@State private var license: String
|
|
@State private var licenseMessage: String?
|
|
|
|
@FocusState private var focusedField: CustomUser.CodingKeys?
|
|
|
|
// @State var isConnected: Bool = false
|
|
|
|
init() {
|
|
_license = .init(wrappedValue: DataStore.shared.user.licenceId ?? "")
|
|
_umpireCustomMail = State(wrappedValue: DataStore.shared.user.umpireCustomMail ?? "")
|
|
_umpireCustomPhone = State(wrappedValue: DataStore.shared.user.umpireCustomPhone ?? "")
|
|
_umpireCustomContact = State(wrappedValue: DataStore.shared.user.umpireCustomContact ?? "")
|
|
}
|
|
|
|
enum UmpireScreen {
|
|
case login
|
|
}
|
|
|
|
var body: some View {
|
|
@Bindable var navigation = navigation
|
|
NavigationStack(path: $navigation.umpirePath) {
|
|
List {
|
|
|
|
PurchaseListView()
|
|
|
|
Section {
|
|
Button {
|
|
self.showSubscriptions = true
|
|
} label: {
|
|
Label("Les offres", systemImage: "bookmark.fill")
|
|
}.simultaneousGesture(
|
|
LongPressGesture()
|
|
.onEnded { _ in
|
|
self.showProductIds = true
|
|
}
|
|
)
|
|
|
|
.highPriorityGesture(
|
|
TapGesture()
|
|
.onEnded { _ in
|
|
self.showSubscriptions = true
|
|
}
|
|
)
|
|
|
|
}
|
|
|
|
if StoreCenter.main.isAuthenticated {
|
|
NavigationLink {
|
|
AccountView(user: dataStore.user) { }
|
|
} label: {
|
|
AccountRowView(userName: dataStore.user.username)
|
|
}
|
|
} else {
|
|
NavigationLink(value: UmpireScreen.login) {
|
|
AccountRowView(userName: dataStore.user.username)
|
|
}
|
|
}
|
|
|
|
let currentPlayerData = dataStore.user.currentPlayerData()
|
|
Section {
|
|
if let reason = licenseMessage {
|
|
Text(reason).foregroundStyle(.logoRed)
|
|
}
|
|
if let currentPlayerData {
|
|
//todo palmares
|
|
ImportedPlayerView(player: currentPlayerData, showProgression: true)
|
|
// NavigationLink {
|
|
//
|
|
// } label: {
|
|
// ImportedPlayerView(player: currentPlayerData)
|
|
// }
|
|
} else {
|
|
RowButtonView("Ma fiche joueur", systemImage: "person.bust") {
|
|
presentSearchView = true
|
|
}
|
|
TextField("ou indiquer votre licence FFT", text: $license)
|
|
.focused($focusedField, equals: ._licenceId)
|
|
.keyboardType(.alphabet)
|
|
.textContentType(nil)
|
|
.autocorrectionDisabled()
|
|
.frame(maxWidth: .infinity)
|
|
}
|
|
} footer: {
|
|
if dataStore.user.licenceId == nil {
|
|
Text("Si vous avez participé à un tournoi dans les 12 derniers mois, Padel Club peut vous retrouver.")
|
|
} else if let currentPlayerData {
|
|
Menu {
|
|
Button {
|
|
UIPasteboard.general.string = currentPlayerData.formattedLicense()
|
|
} label: {
|
|
Text("Copier ma licence")
|
|
Text(currentPlayerData.formattedLicense())
|
|
}
|
|
|
|
Button("Supprimer ma fiche") {
|
|
dataStore.user.licenceId = nil
|
|
self.license = ""
|
|
self.licenseMessage = nil
|
|
self.dataStore.saveUser()
|
|
}
|
|
|
|
} label: {
|
|
Text("options")
|
|
.foregroundStyle(Color.master)
|
|
.underline()
|
|
}
|
|
}
|
|
}
|
|
|
|
Section {
|
|
NavigationLink {
|
|
ClubsView()
|
|
} label: {
|
|
LabeledContent {
|
|
Text(dataStore.user.clubs.count.formatted())
|
|
} label: {
|
|
Label("Clubs favoris", systemImage: "house.and.flag")
|
|
}
|
|
}
|
|
} footer: {
|
|
Text("Il s'agit des clubs qui sont utilisés pour récupérer les tournois tenup.")
|
|
}
|
|
|
|
// Section {
|
|
// NavigationLink {
|
|
// UmpireStatisticView()
|
|
// } label: {
|
|
// Text("Statistiques de participations")
|
|
// }
|
|
// }
|
|
//
|
|
if StoreCenter.main.isAuthenticated {
|
|
_customUmpireView()
|
|
|
|
Section {
|
|
@Bindable var user = dataStore.user
|
|
if dataStore.user.hideUmpireMail, dataStore.user.hideUmpirePhone {
|
|
Text("Attention, les emails envoyés automatiquement au regard des inscriptions en ligne ne contiendront aucun moyen de vous contacter.").foregroundStyle(.logoRed)
|
|
}
|
|
|
|
Toggle(isOn: $user.hideUmpireMail) {
|
|
Text("Masquer l'email")
|
|
}
|
|
Toggle(isOn: $user.hideUmpirePhone) {
|
|
Text("Masquer le téléphone")
|
|
}
|
|
|
|
} footer: {
|
|
Text("Ces informations ne seront pas affichées sur la page d'information des tournois sur Padel Club et dans les emails envoyés automatiquement au regard des inscriptions en lignes.")
|
|
}
|
|
}
|
|
|
|
if dataStore.user.canEnableOnlinePayment() {
|
|
Section {
|
|
if let tournamentTemplate = Tournament.getTemplateTournament() {
|
|
NavigationLink {
|
|
RegistrationSetupView(tournament: tournamentTemplate)
|
|
} label: {
|
|
Text("Référence")
|
|
Text(tournamentTemplate.tournamentTitle()).foregroundStyle(.secondary)
|
|
}
|
|
} else {
|
|
Text("Aucun tournoi référence. Choisissez-en un dans la liste d'activité")
|
|
}
|
|
} header: {
|
|
Text("Inscription et paiement en ligne")
|
|
} footer: {
|
|
Text("Tournoi référence utilisé pour les réglages des inscriptions en ligne")
|
|
}
|
|
}
|
|
|
|
Section {
|
|
@Bindable var user = dataStore.user
|
|
Toggle(isOn: $user.disableRankingFederalRuling) {
|
|
Text("Désactiver la règle fédéral")
|
|
}
|
|
.onChange(of: user.disableRankingFederalRuling) {
|
|
dataStore.saveUser()
|
|
}
|
|
} header: {
|
|
Text("Règle fédérale classement finale")
|
|
} footer: {
|
|
Text("Dernier de poule ≠ dernier du tournoi")
|
|
}
|
|
|
|
Section {
|
|
@Bindable var user = dataStore.user
|
|
Picker(selection: $user.loserBracketMode) {
|
|
ForEach(LoserBracketMode.allCases) {
|
|
Text($0.localizedLoserBracketMode()).tag($0)
|
|
}
|
|
} label: {
|
|
Text("Position des perdants")
|
|
}
|
|
.onChange(of: user.loserBracketMode) {
|
|
dataStore.saveUser()
|
|
}
|
|
} header: {
|
|
Text("Matchs de classement")
|
|
}
|
|
|
|
Section {
|
|
NavigationLink {
|
|
GlobalSettingsView()
|
|
} label: {
|
|
Label("Formats de jeu par défaut", systemImage: "megaphone")
|
|
}
|
|
NavigationLink {
|
|
DurationSettingsView()
|
|
} label: {
|
|
Label("Définir les durées moyennes", systemImage: "deskclock")
|
|
}
|
|
} footer: {
|
|
Text("Vous pouvez définir vos propres estimations de durées de match en fonction du format de jeu.")
|
|
}
|
|
|
|
// Section {
|
|
// Text("Tenup ID")
|
|
// }
|
|
//
|
|
// Section {
|
|
// Text("Tournois")
|
|
// }
|
|
//
|
|
// Section {
|
|
// NavigationLink {
|
|
//
|
|
// } label: {
|
|
// Text("Favori")
|
|
// }
|
|
// NavigationLink {
|
|
//
|
|
// } label: {
|
|
// Text("Black list")
|
|
// }
|
|
// }
|
|
}
|
|
.onChange(of: StoreCenter.main.userId) {
|
|
license = dataStore.user.licenceId ?? ""
|
|
licenseMessage = nil
|
|
}
|
|
.navigationTitle("Juge-Arbitre")
|
|
.navigationBarBackButtonHidden(focusedField != nil)
|
|
.toolbar(content: {
|
|
if focusedField != nil {
|
|
ToolbarItem(placement: .topBarLeading) {
|
|
Button("Annuler", role: .cancel) {
|
|
focusedField = nil
|
|
}
|
|
}
|
|
}
|
|
})
|
|
.toolbar {
|
|
if focusedField != nil {
|
|
ToolbarItemGroup(placement: .keyboard) {
|
|
if focusedField == ._umpireCustomMail, umpireCustomMail.isEmpty == false {
|
|
Button("Effacer") {
|
|
_deleteUmpireMail()
|
|
}
|
|
.buttonStyle(.borderedProminent)
|
|
} else if focusedField == ._umpireCustomPhone, umpireCustomPhone.isEmpty == false {
|
|
Button("Effacer") {
|
|
_deleteUmpirePhone()
|
|
}
|
|
.buttonStyle(.borderedProminent)
|
|
} else if focusedField == ._umpireCustomContact, umpireCustomContact.isEmpty == false {
|
|
Button("Effacer") {
|
|
_deleteUmpireContact()
|
|
}
|
|
.buttonStyle(.borderedProminent)
|
|
}
|
|
Spacer()
|
|
Button("Valider") {
|
|
focusedField = nil
|
|
}
|
|
.buttonStyle(.borderedProminent)
|
|
}
|
|
}
|
|
}
|
|
.onChange(of: [dataStore.user.umpireCustomMail, dataStore.user.umpireCustomPhone, dataStore.user.umpireCustomContact]) {
|
|
self.dataStore.saveUser()
|
|
}
|
|
.onChange(of: [dataStore.user.hideUmpireMail, dataStore.user.hideUmpirePhone]) {
|
|
self.dataStore.saveUser()
|
|
}
|
|
.onChange(of: focusedField) { old, new in
|
|
if old == ._umpireCustomMail {
|
|
_confirmUmpireMail()
|
|
} else if old == ._umpireCustomPhone {
|
|
_confirmUmpirePhone()
|
|
} else if old == ._umpireCustomContact {
|
|
_confirmUmpireContact()
|
|
} else if old == ._licenceId {
|
|
_confirmlicense()
|
|
}
|
|
}
|
|
.sheet(isPresented: self.$showSubscriptions, content: {
|
|
NavigationStack {
|
|
SubscriptionView(isPresented: self.$showSubscriptions)
|
|
.environment(\.colorScheme, .light)
|
|
}
|
|
})
|
|
.sheet(isPresented: self.$showProductIds, content: {
|
|
ProductIdsView()
|
|
})
|
|
.sheet(isPresented: $presentSearchView) {
|
|
let user = dataStore.user
|
|
NavigationStack {
|
|
SelectablePlayerListView(allowSelection: 1, searchField: user.firstName + " " + user.lastName, playerSelectionAction: { players in
|
|
if let player = players.first {
|
|
if user.clubsObjects().contains(where: { $0.code == player.clubCode }) == false {
|
|
let userClub = Club.findOrCreate(name: player.clubName!, code: player.clubCode)
|
|
if userClub.hasBeenCreated(by: StoreCenter.main.userId) {
|
|
dataStore.clubs.addOrUpdate(instance: userClub)
|
|
}
|
|
user.setUserClub(userClub)
|
|
}
|
|
self._updateUserLicense(license: player.license?.computedLicense)
|
|
}
|
|
})
|
|
}
|
|
.task {
|
|
do {
|
|
try await dataStore.clubs.loadDataFromServerIfAllowed()
|
|
} catch {
|
|
Logger.error(error)
|
|
}
|
|
}
|
|
}
|
|
.navigationDestination(for: UmpireScreen.self) { screen in
|
|
switch screen {
|
|
case .login:
|
|
LoginView {_ in }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private func _confirmlicense() {
|
|
licenseMessage = nil
|
|
if license.isEmpty {
|
|
dataStore.user.licenceId = nil
|
|
} else if license.isLicenseNumber {
|
|
_updateUserLicense(license: license)
|
|
} else {
|
|
licenseMessage = "La licence n'est pas valide. N'oubliez pas d'indiquer la lettre."
|
|
}
|
|
|
|
}
|
|
|
|
private func _updateUserLicense(license: String?) {
|
|
guard let license else { return }
|
|
|
|
let copyUser = CustomUser(username: "", email: "", firstName: "", lastName: "", phone: nil, country: nil, loserBracketMode: .automatic)
|
|
copyUser.copy(from: dataStore.user)
|
|
copyUser.licenceId = license
|
|
|
|
Task {
|
|
do {
|
|
try await self.dataStore.userStorage.tryPutBeforeUpdating(copyUser)
|
|
self.license = license
|
|
self.licenseMessage = nil
|
|
} catch {
|
|
licenseMessage = "Un problème est survenu. La licence n'a pas été sauvegardée, il se peut qu'un autre utilisateur l'ait déjà indiquée pour son compte. N'hésitez pas à nous contacter."
|
|
self.license = ""
|
|
Logger.error(error)
|
|
}
|
|
}
|
|
}
|
|
|
|
private func _confirmUmpireMail() {
|
|
umpireCustomMailIsInvalid = false
|
|
if umpireCustomMail.isEmpty {
|
|
dataStore.user.umpireCustomMail = nil
|
|
} else if umpireCustomMail.isValidEmail() {
|
|
dataStore.user.umpireCustomMail = umpireCustomMail
|
|
} else {
|
|
umpireCustomMailIsInvalid = true
|
|
}
|
|
}
|
|
|
|
private func _deleteUmpireMail() {
|
|
umpireCustomMailIsInvalid = false
|
|
umpireCustomMail = ""
|
|
dataStore.user.umpireCustomMail = nil
|
|
}
|
|
|
|
private func _confirmUmpirePhone() {
|
|
umpireCustomPhoneIsInvalid = false
|
|
if umpireCustomPhone.isEmpty {
|
|
dataStore.user.umpireCustomPhone = nil
|
|
} else if umpireCustomPhone.isPhoneNumber() {
|
|
dataStore.user.umpireCustomPhone = umpireCustomPhone.prefixMultilineTrimmed(15)
|
|
} else {
|
|
umpireCustomPhoneIsInvalid = true
|
|
}
|
|
}
|
|
|
|
private func _deleteUmpirePhone() {
|
|
umpireCustomPhoneIsInvalid = false
|
|
umpireCustomPhone = ""
|
|
dataStore.user.umpireCustomPhone = nil
|
|
}
|
|
|
|
private func _confirmUmpireContact() {
|
|
if umpireCustomContact.isEmpty {
|
|
dataStore.user.umpireCustomContact = nil
|
|
} else {
|
|
dataStore.user.umpireCustomContact = umpireCustomContact.prefixMultilineTrimmed(200)
|
|
}
|
|
}
|
|
|
|
private func _deleteUmpireContact() {
|
|
umpireCustomContact = ""
|
|
dataStore.user.umpireCustomContact = nil
|
|
}
|
|
|
|
|
|
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)
|
|
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)
|
|
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)
|
|
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("Par défaut, les informations de Tenup sont récupérés, et si ce n'est pas le cas, 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.")
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
struct AccountRowView: View {
|
|
@EnvironmentObject var dataStore: DataStore
|
|
|
|
var userName: String
|
|
var body: some View {
|
|
|
|
let isAuthenticated = StoreCenter.main.isAuthenticated
|
|
LabeledContent {
|
|
if isAuthenticated {
|
|
Text(self.userName)
|
|
} else if StoreCenter.main.userName != nil {
|
|
Image(systemName: "xmark.circle.fill")
|
|
.foregroundStyle(.logoRed)
|
|
}
|
|
} label: {
|
|
Label("Mon compte", systemImage: "person.fill")
|
|
if isAuthenticated && dataStore.user.email.isEmpty == false {
|
|
Text(dataStore.user.email)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
struct ProductIdsView: View {
|
|
|
|
@State var transactions: [StoreKit.Transaction] = []
|
|
|
|
var body: some View {
|
|
VStack {
|
|
List {
|
|
LabeledContent("count", value: String(self.transactions.count))
|
|
ForEach(self.transactions) { transaction in
|
|
if #available(iOS 17.2, *) {
|
|
if let offer = transaction.offer {
|
|
LabeledContent(transaction.productID, value: "\(offer.type)")
|
|
} else {
|
|
LabeledContent(transaction.productID, value: "no offer")
|
|
}
|
|
} else {
|
|
Text("need ios 17.2")
|
|
}
|
|
}
|
|
}.onAppear {
|
|
Task {
|
|
self.transactions = Array(Guard.main.purchasedTransactions)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
|
|
//#Preview {
|
|
// UmpireView()
|
|
//}
|
|
|