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/Navigation/Umpire/UmpireView.swift

505 lines
19 KiB

//
// UmpireView.swift
// PadelClub
//
// Created by Razmig Sarkissian on 01/03/2024.
//
import SwiftUI
import CoreLocation
import LeStorage
import StoreKit
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
@FocusState private var focusedField: CustomUser.CodingKeys?
// @State var isConnected: Bool = false
init() {
_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()
if Guard.main.currentPlan != .monthlyUnlimited {
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 currentPlayerData {
//todo palmares
ImportedPlayerView(player: currentPlayerData, showProgression: true)
// NavigationLink {
//
// } label: {
// ImportedPlayerView(player: currentPlayerData)
// }
} else {
RowButtonView("Ma fiche joueur", systemImage: "person.bust") {
presentSearchView = true
}
}
} 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.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")
// }
// }
//
_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.")
}
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")
// }
// }
}
.navigationTitle("Juge-Arbitre")
.toolbar {
#if DEBUG
ToolbarItem(placement: .topBarTrailing) {
NetworkStatusView()
// if StoreCenter.main.collectionsCanSynchronize {
// Image(systemName: "checkmark.icloud")
// } else {
// Image(systemName: "icloud.slash")
// }
}
#endif
}
.navigationBarBackButtonHidden(focusedField != nil)
.toolbar(content: {
if focusedField != nil {
ToolbarItem(placement: .topBarLeading) {
Button("Annuler", role: .cancel) {
focusedField = nil
}
}
}
})
.toolbar {
if focusedField != nil {
ToolbarItem(placement: .keyboard) {
HStack {
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: [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()
}
}
.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 {
user.licenceId = player.license?.computedLicense
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) {
do {
try dataStore.clubs.addOrUpdate(instance: userClub)
} catch {
Logger.error(error)
}
}
user.setUserClub(userClub)
}
self.dataStore.saveUser()
}
})
}
.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 _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)
.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.")
}
}
}
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()
//}