From 8fdeff82f111929c3072446bbaff0254f631cef8 Mon Sep 17 00:00:00 2001 From: Razmig Sarkissian Date: Tue, 7 Oct 2025 09:06:01 +0200 Subject: [PATCH] overhaul screens disposition --- PadelClub.xcodeproj/project.pbxproj | 32 ++ PadelClub/PadelClubApp.swift | 10 +- PadelClub/ViewModel/NavigationViewModel.swift | 2 +- PadelClub/ViewModel/TabDestination.swift | 5 + PadelClub/Views/Club/ClubsView.swift | 77 ++-- .../Views/GroupStage/GroupStageView.swift | 3 + .../Navigation/Agenda/ActivityView.swift | 2 +- PadelClub/Views/Navigation/MainView.swift | 13 +- .../Navigation/MyAccount/MyAccountView.swift | 226 ++++++++++ .../Navigation/Toolbox/ToolboxView.swift | 116 ++--- .../Navigation/Umpire/UmpireOptionsView.swift | 68 +++ .../Umpire/UmpireSettingsView.swift | 85 ++++ .../Views/Navigation/Umpire/UmpireView.swift | 412 +++++------------- PadelClub/Views/Round/LoserRoundView.swift | 3 + PadelClub/Views/Round/RoundView.swift | 1 + .../Views/Shared/SupportButtonView.swift | 11 +- .../Views/Tournament/TournamentView.swift | 23 +- PadelClub/Views/User/AccountView.swift | 55 --- PadelClub/Views/User/LoginView.swift | 2 +- 19 files changed, 654 insertions(+), 492 deletions(-) create mode 100644 PadelClub/Views/Navigation/MyAccount/MyAccountView.swift create mode 100644 PadelClub/Views/Navigation/Umpire/UmpireOptionsView.swift create mode 100644 PadelClub/Views/Navigation/Umpire/UmpireSettingsView.swift diff --git a/PadelClub.xcodeproj/project.pbxproj b/PadelClub.xcodeproj/project.pbxproj index e006acf..67a13b2 100644 --- a/PadelClub.xcodeproj/project.pbxproj +++ b/PadelClub.xcodeproj/project.pbxproj @@ -161,6 +161,15 @@ FF30ACF12E8D7078008B6006 /* PaymentRequestButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF30ACF02E8D7078008B6006 /* PaymentRequestButton.swift */; }; FF30ACF22E8D7078008B6006 /* PaymentRequestButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF30ACF02E8D7078008B6006 /* PaymentRequestButton.swift */; }; FF30ACF32E8D7078008B6006 /* PaymentRequestButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF30ACF02E8D7078008B6006 /* PaymentRequestButton.swift */; }; + FF30AD302E92A994008B6006 /* MyAccountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF30AD2F2E92A994008B6006 /* MyAccountView.swift */; }; + FF30AD312E92A994008B6006 /* MyAccountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF30AD2F2E92A994008B6006 /* MyAccountView.swift */; }; + FF30AD322E92A994008B6006 /* MyAccountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF30AD2F2E92A994008B6006 /* MyAccountView.swift */; }; + FF30AD342E93E5B4008B6006 /* UmpireOptionsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF30AD332E93E5B4008B6006 /* UmpireOptionsView.swift */; }; + FF30AD352E93E5B4008B6006 /* UmpireOptionsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF30AD332E93E5B4008B6006 /* UmpireOptionsView.swift */; }; + FF30AD362E93E5B4008B6006 /* UmpireOptionsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF30AD332E93E5B4008B6006 /* UmpireOptionsView.swift */; }; + FF30AD3C2E93E822008B6006 /* UmpireSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF30AD3B2E93E822008B6006 /* UmpireSettingsView.swift */; }; + FF30AD3D2E93E822008B6006 /* UmpireSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF30AD3B2E93E822008B6006 /* UmpireSettingsView.swift */; }; + FF30AD3E2E93E822008B6006 /* UmpireSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF30AD3B2E93E822008B6006 /* UmpireSettingsView.swift */; }; FF3795622B9396D0004EA093 /* PadelClubApp.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = FF3795602B9396D0004EA093 /* PadelClubApp.xcdatamodeld */; }; FF3795662B9399AA004EA093 /* Persistence.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF3795652B9399AA004EA093 /* Persistence.swift */; }; FF39B6152DC8825E004E10CE /* PadelClubData.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C49770202DC25A23005CD239 /* PadelClubData.framework */; }; @@ -1030,6 +1039,9 @@ FF2EFBEF2BDE295E0049CE3B /* SendToAllView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SendToAllView.swift; sourceTree = ""; }; FF30ACEC2E8D700B008B6006 /* PaymentService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaymentService.swift; sourceTree = ""; }; FF30ACF02E8D7078008B6006 /* PaymentRequestButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaymentRequestButton.swift; sourceTree = ""; }; + FF30AD2F2E92A994008B6006 /* MyAccountView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyAccountView.swift; sourceTree = ""; }; + FF30AD332E93E5B4008B6006 /* UmpireOptionsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UmpireOptionsView.swift; sourceTree = ""; }; + FF30AD3B2E93E822008B6006 /* UmpireSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UmpireSettingsView.swift; sourceTree = ""; }; FF3795612B9396D0004EA093 /* Model.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = Model.xcdatamodel; sourceTree = ""; }; FF3795652B9399AA004EA093 /* Persistence.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Persistence.swift; sourceTree = ""; }; FF39B60F2DC87FEB004E10CE /* PadelClubData.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = PadelClubData.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -1594,12 +1606,21 @@ path = SeedData; sourceTree = ""; }; + FF30AD2E2E92A936008B6006 /* MyAccount */ = { + isa = PBXGroup; + children = ( + FF30AD2F2E92A994008B6006 /* MyAccountView.swift */, + ); + path = MyAccount; + sourceTree = ""; + }; FF39719B2B8DE04B004C4E75 /* Navigation */ = { isa = PBXGroup; children = ( FF59FFB62B90EFBF0061EFF9 /* MainView.swift */, FFB0FF662E81B671009EDEAC /* OnboardingView.swift */, FFD783FB2B91B919000F62A6 /* Agenda */, + FF30AD2E2E92A936008B6006 /* MyAccount */, FF3F74FA2B91A04B004CFE0E /* Organizer */, FF3F74FB2B91A060004CFE0E /* Toolbox */, FF3F74FC2B91A06B004CFE0E /* Umpire */, @@ -1683,6 +1704,8 @@ isa = PBXGroup; children = ( FF3F74F52B919E45004CFE0E /* UmpireView.swift */, + FF30AD3B2E93E822008B6006 /* UmpireSettingsView.swift */, + FF30AD332E93E5B4008B6006 /* UmpireOptionsView.swift */, FFA252AC2CDB734A0074E63F /* UmpireStatisticView.swift */, FFD783FE2B91BA42000F62A6 /* PadelClubView.swift */, C488C8812CCBE8FC0082001F /* NetworkStatusView.swift */, @@ -2270,11 +2293,13 @@ FF1DC5572BAB3AED00FD8220 /* ClubsView.swift in Sources */, FFE103122C366E5900684FC9 /* ImagePickerView.swift in Sources */, FF8F264F2BAE0B9600650388 /* MatchTypeSelectionView.swift in Sources */, + FF30AD312E92A994008B6006 /* MyAccountView.swift in Sources */, FF967D062BAF3C4200A9A3BD /* MatchSetupView.swift in Sources */, FF4AB6B52B9248200002987F /* NetworkManager.swift in Sources */, FF2B6F5E2C036A1500835EE7 /* EventLinksView.swift in Sources */, FF025AE12BD0EB9000A86CF8 /* TournamentClubSettingsView.swift in Sources */, FFBF065C2BBD2657009D6715 /* GroupStageTeamView.swift in Sources */, + FF30AD362E93E5B4008B6006 /* UmpireOptionsView.swift in Sources */, FF5DA1932BB9279B00A33061 /* RoundSettingsView.swift in Sources */, FFBE62052CE9DA0900815D33 /* MatchViewStyle.swift in Sources */, FFE2D2E22C231BEE00D0C7BE /* SupportButtonView.swift in Sources */, @@ -2440,6 +2465,7 @@ FF8E52342DF01D6100099B75 /* EventStatusView.swift in Sources */, FFE8B63C2DACEAED00BDE966 /* ConfigurationService.swift in Sources */, FF0E0B6D2BC254C6005F00A9 /* TournamentScheduleView.swift in Sources */, + FF30AD3D2E93E822008B6006 /* UmpireSettingsView.swift in Sources */, FF025AF12BD1AEBD00A86CF8 /* MatchFormatStorageView.swift in Sources */, FF3F74F62B919E45004CFE0E /* UmpireView.swift in Sources */, FF967D012BAEF0B400A9A3BD /* MatchSummaryView.swift in Sources */, @@ -2542,11 +2568,13 @@ FF4CBF532C996C0600151637 /* ClubsView.swift in Sources */, FF4CBF542C996C0600151637 /* ImagePickerView.swift in Sources */, FF4CBF552C996C0600151637 /* MatchTypeSelectionView.swift in Sources */, + FF30AD302E92A994008B6006 /* MyAccountView.swift in Sources */, FF4CBF562C996C0600151637 /* MatchSetupView.swift in Sources */, FF4CBF572C996C0600151637 /* NetworkManager.swift in Sources */, FF4CBF582C996C0600151637 /* EventLinksView.swift in Sources */, FF4CBF5A2C996C0600151637 /* TournamentClubSettingsView.swift in Sources */, FF4CBF5B2C996C0600151637 /* GroupStageTeamView.swift in Sources */, + FF30AD342E93E5B4008B6006 /* UmpireOptionsView.swift in Sources */, FF4CBF5C2C996C0600151637 /* RoundSettingsView.swift in Sources */, FFBE62072CE9DA0900815D33 /* MatchViewStyle.swift in Sources */, FF4CBF5D2C996C0600151637 /* SupportButtonView.swift in Sources */, @@ -2712,6 +2740,7 @@ FF8E52362DF01D6100099B75 /* EventStatusView.swift in Sources */, FF4CBFFB2C996C0600151637 /* MatchFormatStorageView.swift in Sources */, FF4CBFFC2C996C0600151637 /* UmpireView.swift in Sources */, + FF30AD3C2E93E822008B6006 /* UmpireSettingsView.swift in Sources */, FF4CBFFE2C996C0600151637 /* MatchSummaryView.swift in Sources */, FFE8B5B52DA848D400BDE966 /* OnlineWaitingListFaqSheetView.swift in Sources */, FFA252B52CDD2C6C0074E63F /* OngoingDestination.swift in Sources */, @@ -2792,11 +2821,13 @@ FF70FAD22C90584900129CC2 /* ClubsView.swift in Sources */, FF70FAD32C90584900129CC2 /* ImagePickerView.swift in Sources */, FF70FAD42C90584900129CC2 /* MatchTypeSelectionView.swift in Sources */, + FF30AD322E92A994008B6006 /* MyAccountView.swift in Sources */, FF70FAD52C90584900129CC2 /* MatchSetupView.swift in Sources */, FF70FAD62C90584900129CC2 /* NetworkManager.swift in Sources */, FF70FAD72C90584900129CC2 /* EventLinksView.swift in Sources */, FF70FAD92C90584900129CC2 /* TournamentClubSettingsView.swift in Sources */, FF70FADA2C90584900129CC2 /* GroupStageTeamView.swift in Sources */, + FF30AD352E93E5B4008B6006 /* UmpireOptionsView.swift in Sources */, FF70FADB2C90584900129CC2 /* RoundSettingsView.swift in Sources */, FFBE62062CE9DA0900815D33 /* MatchViewStyle.swift in Sources */, FF70FADC2C90584900129CC2 /* SupportButtonView.swift in Sources */, @@ -2962,6 +2993,7 @@ FF8E52352DF01D6100099B75 /* EventStatusView.swift in Sources */, FF70FB7A2C90584900129CC2 /* MatchFormatStorageView.swift in Sources */, FF70FB7B2C90584900129CC2 /* UmpireView.swift in Sources */, + FF30AD3E2E93E822008B6006 /* UmpireSettingsView.swift in Sources */, FF70FB7D2C90584900129CC2 /* MatchSummaryView.swift in Sources */, FFE8B5B42DA848D400BDE966 /* OnlineWaitingListFaqSheetView.swift in Sources */, FFA252B72CDD2C6C0074E63F /* OngoingDestination.swift in Sources */, diff --git a/PadelClub/PadelClubApp.swift b/PadelClub/PadelClubApp.swift index 182c68d..e295549 100644 --- a/PadelClub/PadelClubApp.swift +++ b/PadelClub/PadelClubApp.swift @@ -193,11 +193,11 @@ struct PadelClubApp: App { navigationViewModel.selectedTab = .umpire } - if navigationViewModel.umpirePath.isEmpty { - navigationViewModel.umpirePath.append(UmpireView.UmpireScreen.login) - } else if navigationViewModel.umpirePath.last! != .login { - navigationViewModel.umpirePath.removeAll() - navigationViewModel.umpirePath.append(UmpireView.UmpireScreen.login) + if navigationViewModel.accountPath.isEmpty { + navigationViewModel.accountPath.append(MyAccountView.AccountScreen.login) + } else if navigationViewModel.accountPath.last! != .login { + navigationViewModel.accountPath.removeAll() + navigationViewModel.accountPath.append(MyAccountView.AccountScreen.login) } } }.resume() diff --git a/PadelClub/ViewModel/NavigationViewModel.swift b/PadelClub/ViewModel/NavigationViewModel.swift index e53e2d5..2898190 100644 --- a/PadelClub/ViewModel/NavigationViewModel.swift +++ b/PadelClub/ViewModel/NavigationViewModel.swift @@ -12,7 +12,7 @@ import PadelClubData class NavigationViewModel { var path = NavigationPath() var toolboxPath = NavigationPath() - var umpirePath: [UmpireView.UmpireScreen] = [] + var accountPath: [MyAccountView.AccountScreen] = [] var ongoingPath = NavigationPath() var selectedTab: TabDestination? var agendaDestination: AgendaDestination? = .activity diff --git a/PadelClub/ViewModel/TabDestination.swift b/PadelClub/ViewModel/TabDestination.swift index 429b2fd..edd8e84 100644 --- a/PadelClub/ViewModel/TabDestination.swift +++ b/PadelClub/ViewModel/TabDestination.swift @@ -17,6 +17,7 @@ enum TabDestination: CaseIterable, Identifiable { case tournamentOrganizer case umpire case ongoing + case myAccount var title: String { switch self { @@ -30,6 +31,8 @@ enum TabDestination: CaseIterable, Identifiable { return "Gestionnaire" case .umpire: return "Juge-Arbitre" + case .myAccount: + return "Compte" } } @@ -45,6 +48,8 @@ enum TabDestination: CaseIterable, Identifiable { return "squares.below.rectangle" case .umpire: return "person.bust" + case .myAccount: + return "person.crop.circle" } } } diff --git a/PadelClub/Views/Club/ClubsView.swift b/PadelClub/Views/Club/ClubsView.swift index 85839f8..53cd3fc 100644 --- a/PadelClub/Views/Club/ClubsView.swift +++ b/PadelClub/Views/Club/ClubsView.swift @@ -28,19 +28,19 @@ struct ClubsView: View { var body: some View { List { - #if DEBUG - Section { - RowButtonView("Delete unexisted clubs", action: { - let ids = dataStore.user.clubs - ids.forEach { clubId in - if dataStore.clubs.findById(clubId) == nil { - dataStore.user.clubs.removeAll(where: { $0 == clubId }) - } - } - dataStore.saveUser() - }) - } - #endif +// #if DEBUG +// Section { +// RowButtonView("Delete unexisted clubs", action: { +// let ids = dataStore.user.clubs +// ids.forEach { clubId in +// if dataStore.clubs.findById(clubId) == nil { +// dataStore.user.clubs.removeAll(where: { $0 == clubId }) +// } +// } +// dataStore.saveUser() +// }) +// } +// #endif let clubs : [Club] = dataStore.user.clubsObjects(includeCreated: false) let onlyCreatedClubs : [Club] = dataStore.user.createdClubsObjectsNotFavorite() @@ -106,7 +106,6 @@ struct ClubsView: View { } } .navigationTitle(selection == nil ? "Clubs favoris" : "Choisir un club") - .navigationBarTitleDisplayMode(.inline) .toolbarBackground(.visible, for: .navigationBar) .sheet(isPresented: presentClubCreationView) { if let newClub { @@ -129,23 +128,41 @@ struct ClubsView: View { .tint(.master) } .toolbar { - ToolbarItemGroup(placement: .topBarTrailing) { - Button { - presentClubSearchView = true - } label: { - Image(systemName: "magnifyingglass.circle.fill") - .resizable() - .scaledToFit() - .frame(minHeight: 28) + ToolbarItem(placement: .topBarTrailing) { + if #available(iOS 26.0, *) { + Button("Chercher", systemImage: "magnifyingglass") { + presentClubSearchView = true + } + } else { + Button { + presentClubSearchView = true + } label: { + Image(systemName: "magnifyingglass.circle.fill") + .resizable() + .scaledToFit() + .frame(minHeight: 28) + } } - - Button { - newClub = Club.newEmptyInstance() - } label: { - Image(systemName: "plus.circle.fill") - .resizable() - .scaledToFit() - .frame(minHeight: 28) + } + if #available(iOS 26.0, *) { + ToolbarSpacer(placement: .topBarTrailing) + } + + + ToolbarItem(placement: .topBarTrailing) { + if #available(iOS 26.0, *) { + Button("Ajouter", systemImage: "plus") { + newClub = Club.newEmptyInstance() + } + } else { + Button { + newClub = Club.newEmptyInstance() + } label: { + Image(systemName: "plus.circle.fill") + .resizable() + .scaledToFit() + .frame(minHeight: 28) + } } } } diff --git a/PadelClub/Views/GroupStage/GroupStageView.swift b/PadelClub/Views/GroupStage/GroupStageView.swift index 7007e66..ac06bfa 100644 --- a/PadelClub/Views/GroupStage/GroupStageView.swift +++ b/PadelClub/Views/GroupStage/GroupStageView.swift @@ -96,6 +96,9 @@ struct GroupStageView: View { } } + .onAppear(perform: { + groupStage.clearScoreCache() + }) .toolbar { ToolbarItem(placement: .topBarTrailing) { _groupStageMenuView() diff --git a/PadelClub/Views/Navigation/Agenda/ActivityView.swift b/PadelClub/Views/Navigation/Agenda/ActivityView.swift index 8caba04..f2c4bce 100644 --- a/PadelClub/Views/Navigation/Agenda/ActivityView.swift +++ b/PadelClub/Views/Navigation/Agenda/ActivityView.swift @@ -546,7 +546,7 @@ struct ActivityView: View { .frame(width: 100) } } description: { - Text("Aucun événement en cours ou à venir dans votre agenda.") + Text("Aucun événement dans votre agenda.") } actions: { RowButtonView("Créer un nouvel événement") { newTournament = Tournament.newEmptyInstance() diff --git a/PadelClub/Views/Navigation/MainView.swift b/PadelClub/Views/Navigation/MainView.swift index 003a22a..3fd2bc7 100644 --- a/PadelClub/Views/Navigation/MainView.swift +++ b/PadelClub/Views/Navigation/MainView.swift @@ -80,9 +80,12 @@ struct MainView: View { } .toolbarBackground(.visible, for: .tabBar) - TournamentOrganizerView() - .tabItem(for: .tournamentOrganizer) + UmpireOptionsView() + .tabItem(for: .umpire) .toolbarBackground(.visible, for: .tabBar) +// TournamentOrganizerView() +// .tabItem(for: .tournamentOrganizer) +// .toolbarBackground(.visible, for: .tabBar) OngoingContainerView() .tabItem(for: .ongoing) .badge(self.dataStore.runningMatches().count) @@ -90,10 +93,10 @@ struct MainView: View { ToolboxView() .tabItem(for: .toolbox) .toolbarBackground(.visible, for: .tabBar) - UmpireView() - .tabItem(for: .umpire) - .badge(badgeText) + MyAccountView() + .tabItem(for: .myAccount) .toolbarBackground(.visible, for: .tabBar) + .badge(badgeText) // PadelClubView() // .tabItem(for: .padelClub) } diff --git a/PadelClub/Views/Navigation/MyAccount/MyAccountView.swift b/PadelClub/Views/Navigation/MyAccount/MyAccountView.swift new file mode 100644 index 0000000..0568ea5 --- /dev/null +++ b/PadelClub/Views/Navigation/MyAccount/MyAccountView.swift @@ -0,0 +1,226 @@ +// +// MyAccountView.swift +// PadelClub +// +// Created by Razmig Sarkissian on 01/03/2024. +// + +import SwiftUI +import CoreLocation +import LeStorage +import StoreKit +import PadelClubData + +struct MyAccountView: View { + + @Environment(NavigationViewModel.self) private var navigation: NavigationViewModel + @EnvironmentObject var dataStore: DataStore + + @State private var showSubscriptions: Bool = false + @State private var showProductIds: Bool = false + + @FocusState private var focusedField: CustomUser.CodingKeys? + +// @State var isConnected: Bool = false + + enum AccountScreen { + case login + } + + var body: some View { + @Bindable var navigation = navigation + NavigationStack(path: $navigation.accountPath) { + List { + Section { + SupportButtonView(supportButtonType: .bugReport, showIcon: true) + } + + 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: AccountScreen.login) { + AccountRowView(userName: dataStore.user.username) + } + } + + if StoreCenter.main.isAuthenticated { + let onlineRegPaymentMode = dataStore.user.registrationPaymentMode + Section { + LabeledContent { + switch onlineRegPaymentMode { + case .corporate: + Text("Activé") + .bold() + .foregroundStyle(.green) + case .disabled: + Text("Désactivé") + .bold() + case .noFee: + Text("Activé") + .bold() + .foregroundStyle(.green) + case .stripe: + Text("Activé") + .bold() + .foregroundStyle(.green) + } + } label: { + Text("Option 'Paiement en ligne'") + if onlineRegPaymentMode == .corporate { + Text("Mode Padel Club") + .foregroundStyle(.secondary) + } else if onlineRegPaymentMode == .noFee { + Text("Commission Stripe") + .foregroundStyle(.secondary) + } else if onlineRegPaymentMode == .stripe { + Text("Commission Stripe et Padel Club") + .foregroundStyle(.secondary) + } + } + } footer: { + if onlineRegPaymentMode == .disabled { + FooterButtonView("Contactez nous pour activer cette option.") { + let emailTo: String = "support@padelclub.app" + let subject: String = "Activer l'option de paiment en ligne : \(dataStore.user.email)" + if let url = URL(string: "mailto:\(emailTo)?subject=\(subject)"), UIApplication.shared.canOpenURL(url) { + UIApplication.shared.open(url, options: [:], completionHandler: nil) + } + } + .font(.callout) + .multilineTextAlignment(.leading) + } else { + Text("Permet de proposer le paiement de vos tournois en ligne.") + } + } + + Section { + SupportButtonView(supportButtonType: .sharingRequest) + } header: { + Text("Partage et délégation de compte") + } footer: { + Text("Vous souhaitez partager la supervision d'un tournoi à un autre compte ? Vous avez plusieurs juge-arbitres dans votre club ?") + } + } + + Section { + Link(destination: URLs.appReview.url) { + Text("Partagez vos impressions !") + } + + Link(destination: URLs.instagram.url) { + Text("Compte Instagram PadelClub.app") + } + + Link(destination: URLs.appDescription.url) { + Text("Page de présentation de Padel Club") + } + + } + + Section { + Link(destination: URLs.privacy.url) { + Text("Politique de confidentialité") + } + Link(destination: URLs.eula.url) { + Text("Contrat d'utilisation") + } + } + } + .sheet(isPresented: self.$showSubscriptions, content: { + NavigationStack { + SubscriptionView(isPresented: self.$showSubscriptions) + .environment(\.colorScheme, .light) + } + }) + .sheet(isPresented: self.$showProductIds, content: { + ProductIdsView() + }) + .navigationDestination(for: AccountScreen.self) { screen in + switch screen { + case .login: + LoginView {_ in } + } + } + .navigationTitle("Mon compte") + } + } +} + +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) + } + } + } + } + +} diff --git a/PadelClub/Views/Navigation/Toolbox/ToolboxView.swift b/PadelClub/Views/Navigation/Toolbox/ToolboxView.swift index cc61638..38060f4 100644 --- a/PadelClub/Views/Navigation/Toolbox/ToolboxView.swift +++ b/PadelClub/Views/Navigation/Toolbox/ToolboxView.swift @@ -39,44 +39,6 @@ struct ToolboxView: View { @Bindable var navigation = navigation NavigationStack(path: $navigation.toolboxPath) { List { - Section { - Link(destination: URLs.main.url) { - Text("Accéder à padelclub.app") - } - .contextMenu { - ShareLink(item: URLs.main.url) - } - - SupportButtonView(supportButtonType: .bugReport) - - Link(destination: URLs.appReview.url) { - Text("Partagez vos impressions !") - } - - Link(destination: URLs.instagram.url) { - Text("Compte Instagram PadelClub.app") - } - } - - if self.showDebugViews { - DebugView() - } - - Section { - NavigationLink { - SelectablePlayerListView(isPresented: false, lastDataSource: true) - .toolbar(.hidden, for: .tabBar) - } label: { - Label("Rechercher un joueur", systemImage: "person.fill.viewfinder") - } - - NavigationLink { - RankCalculatorView() - } label: { - Label("Calculateur de points", systemImage: "scalemass") - } - } - Section { NavigationLink { PadelClubView() @@ -86,8 +48,7 @@ struct ToolboxView: View { Image(systemName: "checkmark.circle.fill") .foregroundStyle(.green) } label: { - Text(_lastDataSourceDate.monthYearFormatted) - Text("Classement mensuel utilisé") + Label(_lastDataSourceDate.monthYearFormatted, systemImage: "calendar.badge.checkmark") } } else { LabeledContent { @@ -95,16 +56,46 @@ struct ToolboxView: View { .tint(.logoRed) } label: { if let _mostRecentDateAvailable { - Text(_mostRecentDateAvailable.monthYearFormatted) + Label(_mostRecentDateAvailable.monthYearFormatted, systemImage: "calendar.badge") } else { - Text("Aucun") + Label("Aucun", systemImage: "calendar.badge.exclamationmark") } Text("Classement mensuel disponible") } } } + } header: { + Text("Classement mensuel utilisé") + } + + Section { + NavigationLink { + SelectablePlayerListView(isPresented: false, lastDataSource: true) + .toolbar(.hidden, for: .tabBar) + } label: { + Label("Rechercher un joueur", systemImage: "person.fill.viewfinder") + } + + NavigationLink { + RankCalculatorView() + } label: { + Label("Calculateur de points", systemImage: "scalemass") + } } + Section { + Link(destination: URLs.main.url) { + Label("Padel Club sur le Web", systemImage: "link") + } + .contextMenu { + ShareLink(item: URLs.main.url) + } + + ShareLink(item: URLs.appStore.url) { + Label("Padel Club sur l'App Store", systemImage: "link") + } + } + Section { Link("Guide de la compétition", destination: URLs.padelCompetitionGeneralGuide.url) Link("CDC des tournois", destination: URLs.padelCompetitionSpecificGuide.url) @@ -119,21 +110,10 @@ struct ToolboxView: View { } } - Section { - Link(destination: URLs.appDescription.url) { - Text("Page de présentation de Padel Club") - } - } - - Section { - Link(destination: URLs.privacy.url) { - Text("Politique de confidentialité") - } - Link(destination: URLs.eula.url) { - Text("Contrat d'utilisation") - } + if self.showDebugViews { + DebugView() } - + Section { RowButtonView("Effacer les logs", role: .destructive) { StoreCenter.main.resetLoggingCollections() @@ -163,16 +143,9 @@ struct ToolboxView: View { } } } -// .navigationBarTitleDisplayMode(.large) - // .navigationTitle(TabDestination.toolbox.title) + .navigationBarTitleDisplayMode(.large) + .navigationTitle(TabDestination.toolbox.title) .toolbar { - ToolbarItem(placement: .principal) { - Text(TabDestination.toolbox.title) - .font(.headline) - .onTapGesture { - _handleTitleTap() - } - } ToolbarItem(placement: .topBarLeading) { Link(destination: URLs.appStore.url) { Text("v\(PadelClubApp.appVersion)") @@ -180,15 +153,16 @@ struct ToolboxView: View { } ToolbarItem(placement: .topBarTrailing) { Menu { - ShareLink(item: URLs.appStore.url) { - Label("Lien AppStore", systemImage: "link") - } - ShareLink(item: ZipLog(), preview: .init("Mon archive")) { - Label("Mes données", systemImage: "server.rack") + Text("Archiver mes données") } + + Divider() + + Toggle("Outils avancées", isOn: $showDebugViews) + } label: { - Label("Partagez", systemImage: "square.and.arrow.up").labelStyle(.iconOnly) + LabelOptions() } } } diff --git a/PadelClub/Views/Navigation/Umpire/UmpireOptionsView.swift b/PadelClub/Views/Navigation/Umpire/UmpireOptionsView.swift new file mode 100644 index 0000000..61fa208 --- /dev/null +++ b/PadelClub/Views/Navigation/Umpire/UmpireOptionsView.swift @@ -0,0 +1,68 @@ +// +// UmpireOptionsView.swift +// PadelClub +// +// Created by Razmig Sarkissian on 06/10/2025. +// + +import SwiftUI +import PadelClubData + +struct UmpireOptionsView: View { + @Environment(NavigationViewModel.self) private var navigation: NavigationViewModel + @State private var umpireOption: UmpireOption? = .umpire + + var body: some View { + @Bindable var navigation = navigation + NavigationStack { + VStack(spacing: 0) { + GenericDestinationPickerView(selectedDestination: $umpireOption, destinations: UmpireOption.allCases, nilDestinationIsValid: true) + switch umpireOption { + case .none: + UmpireSettingsView() + .navigationTitle("Préférences") + case .umpire: + UmpireView() + .navigationTitle("Juge-Arbitre") + case .clubs: + ClubsView() + } + } + .navigationBarTitleDisplayMode(.large) + .navigationTitle("Juge-Arbitre") + .toolbarBackground(.visible, for: .navigationBar) + } + } +} + +enum UmpireOption: Int, CaseIterable, Identifiable, Selectable, Equatable { + func badgeValue() -> Int? { + nil + } + + func badgeImage() -> PadelClubData.Badge? { + nil + } + + func badgeValueColor() -> Color? { + nil + } + + var id: Int { self.rawValue } + + case umpire + case clubs + + var localizedTitleKey: String { + switch self { + case .umpire: + return "Juge-Arbitre" + case .clubs: + return "Clubs Favoris" + } + } + + func selectionLabel(index: Int) -> String { + localizedTitleKey + } +} diff --git a/PadelClub/Views/Navigation/Umpire/UmpireSettingsView.swift b/PadelClub/Views/Navigation/Umpire/UmpireSettingsView.swift new file mode 100644 index 0000000..3706385 --- /dev/null +++ b/PadelClub/Views/Navigation/Umpire/UmpireSettingsView.swift @@ -0,0 +1,85 @@ +// +// UmpireSettingsView.swift +// PadelClub +// +// Created by Razmig Sarkissian on 06/10/2025. +// + +import SwiftUI +import CoreLocation +import LeStorage +import StoreKit +import PadelClubData + +struct UmpireSettingsView: View { + + @EnvironmentObject var dataStore: DataStore + + var body: some View { + List { + 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.") + } + } + } +} diff --git a/PadelClub/Views/Navigation/Umpire/UmpireView.swift b/PadelClub/Views/Navigation/Umpire/UmpireView.swift index 4756177..5d8ae4f 100644 --- a/PadelClub/Views/Navigation/Umpire/UmpireView.swift +++ b/PadelClub/Views/Navigation/Umpire/UmpireView.swift @@ -17,8 +17,6 @@ struct UmpireView: View { @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 @@ -38,50 +36,9 @@ struct UmpireView: View { _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) - } - } - + List { + if StoreCenter.main.isAuthenticated { let currentPlayerData = dataStore.user.currentPlayerData() Section { if let reason = licenseMessage { @@ -90,11 +47,11 @@ struct UmpireView: View { if let currentPlayerData { //todo palmares ImportedPlayerView(player: currentPlayerData, showProgression: true) -// NavigationLink { -// -// } label: { -// ImportedPlayerView(player: currentPlayerData) -// } + // NavigationLink { + // + // } label: { + // ImportedPlayerView(player: currentPlayerData) + // } } else { RowButtonView("Ma fiche joueur", systemImage: "person.bust") { presentSearchView = true @@ -106,6 +63,8 @@ struct UmpireView: View { .autocorrectionDisabled() .frame(maxWidth: .infinity) } + } header: { + Text("Mes infos licencié") } footer: { if dataStore.user.licenceId == nil { Text("Si vous avez participé à un tournoi dans les 12 derniers mois, Padel Club peut vous retrouver.") @@ -124,7 +83,7 @@ struct UmpireView: View { self.licenseMessage = nil self.dataStore.saveUser() } - + } label: { Text("options") .foregroundStyle(Color.master) @@ -132,231 +91,119 @@ struct UmpireView: View { } } } + _customUmpireView() Section { - NavigationLink { - ClubsView() - } label: { - LabeledContent { - Text(dataStore.user.clubs.count.formatted()) - } label: { - Label("Clubs favoris", systemImage: "house.and.flag") - } + @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) } - } 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.") + Toggle(isOn: $user.hideUmpireMail) { + Text("Masquer l'email") } - } - - 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") + Toggle(isOn: $user.hideUmpirePhone) { + Text("Masquer le téléphone") } - } - - 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") + 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 - Picker(selection: $user.loserBracketMode) { - ForEach(LoserBracketMode.allCases) { - Text($0.localizedLoserBracketMode()).tag($0) - } - } label: { - Text("Position des perdants") - } - .onChange(of: user.loserBracketMode) { - dataStore.saveUser() + } + } + .overlay(content: { + if StoreCenter.main.isAuthenticated == false { + ContentUnavailableView { + Label("Aucun compte", systemImage: "person.crop.circle.badge.exclamationmark") + } description: { + Text("Créer un compte Padel Club pour personnaliser vos informations de Juge-Arbitre") + } actions: { + RowButtonView("Créer un compte") { + _openCreateAccountView() } - } 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") + } + }) + .onChange(of: StoreCenter.main.userId) { + license = dataStore.user.licenceId ?? "" + licenseMessage = nil + } + .navigationBarBackButtonHidden(focusedField != nil) + .toolbarBackground(.visible, for: .navigationBar) + .toolbar(content: { + if focusedField != nil { + ToolbarItem(placement: .topBarLeading) { + Button("Annuler", role: .cancel) { + focusedField = nil } - } 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() } - } - } - }) - .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) + .buttonStyle(.borderedProminent) + } else if focusedField == ._umpireCustomPhone, umpireCustomPhone.isEmpty == false { + Button("Effacer") { + _deleteUmpirePhone() } - Spacer() - Button("Valider") { - focusedField = nil + .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() - } + } + .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) + } + .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) } - self._updateUserLicense(license: player.license?.computedLicense) + user.setUserClub(userClub) } - }) - } - .task { - do { - try await dataStore.clubs.loadDataFromServerIfAllowed() - } catch { - Logger.error(error) + self._updateUserLicense(license: player.license?.computedLicense) } - } + }) } - .navigationDestination(for: UmpireScreen.self) { screen in - switch screen { - case .login: - LoginView {_ in } + .task { + do { + try await dataStore.clubs.loadDataFromServerIfAllowed() + } catch { + Logger.error(error) } } } @@ -374,6 +221,10 @@ struct UmpireView: View { } + private func _openCreateAccountView() { + navigation.selectedTab = .myAccount + } + private func _updateUserLicense(license: String?) { guard let license else { return } @@ -481,67 +332,10 @@ struct UmpireView: View { } } } header: { - Text("Juge-arbitre") + Text("Mes infos 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() -//} diff --git a/PadelClub/Views/Round/LoserRoundView.swift b/PadelClub/Views/Round/LoserRoundView.swift index 235c7c1..56b8077 100644 --- a/PadelClub/Views/Round/LoserRoundView.swift +++ b/PadelClub/Views/Round/LoserRoundView.swift @@ -103,6 +103,9 @@ struct LoserRoundView: View { } .onAppear(perform: { updateDisplayedMatches() + self.loserBracket.rounds.forEach({ round in + round.invalidateCache() + }) }) .onChange(of: isEditingTournamentSeed.wrappedValue) { updateDisplayedMatches() diff --git a/PadelClub/Views/Round/RoundView.swift b/PadelClub/Views/Round/RoundView.swift index b97768b..904880b 100644 --- a/PadelClub/Views/Round/RoundView.swift +++ b/PadelClub/Views/Round/RoundView.swift @@ -29,6 +29,7 @@ struct RoundView: View { func _refreshRound() { self.upperRound.playedMatches = self.upperRound.round.playedMatches() + self.upperRound.round.invalidateCache() } init(upperRound: UpperRound) { diff --git a/PadelClub/Views/Shared/SupportButtonView.swift b/PadelClub/Views/Shared/SupportButtonView.swift index eb20ba5..94af878 100644 --- a/PadelClub/Views/Shared/SupportButtonView.swift +++ b/PadelClub/Views/Shared/SupportButtonView.swift @@ -90,8 +90,15 @@ struct SupportButtonView: View { _zip() } case .bugReport: - Button("Signaler un problème") { - _zip() + if showIcon { + Button("Signaler un problème", systemImage: "square.and.pencil") { + _zip() + } + .labelStyle(.titleAndIcon) + } else { + Button("Signaler un problème") { + _zip() + } } } } diff --git a/PadelClub/Views/Tournament/TournamentView.swift b/PadelClub/Views/Tournament/TournamentView.swift index c15760d..350712d 100644 --- a/PadelClub/Views/Tournament/TournamentView.swift +++ b/PadelClub/Views/Tournament/TournamentView.swift @@ -236,14 +236,14 @@ struct TournamentView: View { } #endif - if presentationContext == .agenda { - Button { - navigation.openTournamentInOrganizer(tournament) - } label: { - Label("Gestionnaire", systemImage: "pin") - } - Divider() - } +// if presentationContext == .agenda { +// Button { +// navigation.openTournamentInOrganizer(tournament) +// } label: { +// Label("Gestionnaire", systemImage: "pin") +// } +// Divider() +// } NavigationLink(value: Screen.event) { Label("Événement", systemImage: "info") @@ -277,10 +277,9 @@ struct TournamentView: View { Label(tournament.isFree() ? "Présence" : "Encaissement", systemImage: tournament.isFree() ? "person.crop.circle.badge.checkmark" : "eurosign.circle") } -// NavigationLink(value: Screen.statistics) { -// Label("Statistiques", systemImage: "123.rectangle") -// } -// + NavigationLink(value: Screen.statistics) { + Label("Statistiques", systemImage: "123.rectangle") + } NavigationLink(value: Screen.rankings) { LabeledContent { diff --git a/PadelClub/Views/User/AccountView.swift b/PadelClub/Views/User/AccountView.swift index e47d216..1cfa234 100644 --- a/PadelClub/Views/User/AccountView.swift +++ b/PadelClub/Views/User/AccountView.swift @@ -24,61 +24,6 @@ struct AccountView: View { PurchaseView(purchaseRow: PurchaseRow(id: purchase.id, name: purchase.productId, item: item)) } #endif - - let onlineRegPaymentMode = dataStore.user.registrationPaymentMode - Section { - LabeledContent { - switch onlineRegPaymentMode { - case .corporate: - Text("Activé") - .bold() - .foregroundStyle(.green) - case .disabled: - Text("Désactivé") - .bold() - case .noFee: - Text("Activé") - .bold() - .foregroundStyle(.green) - case .stripe: - Text("Activé") - .bold() - .foregroundStyle(.green) - } - } label: { - Text("Option 'Paiement en ligne'") - if onlineRegPaymentMode == .corporate { - Text("Mode Padel Club") - .foregroundStyle(.secondary) - } else if onlineRegPaymentMode == .noFee { - Text("Commission Stripe") - .foregroundStyle(.secondary) - } else if onlineRegPaymentMode == .stripe { - Text("Commission Stripe et Padel Club") - .foregroundStyle(.secondary) - } - } - } footer: { - if onlineRegPaymentMode == .disabled { - FooterButtonView("Contactez nous pour activer cette option.") { - let emailTo: String = "support@padelclub.app" - let subject: String = "Activer l'option de paiment en ligne : \(dataStore.user.email)" - if let url = URL(string: "mailto:\(emailTo)?subject=\(subject)"), UIApplication.shared.canOpenURL(url) { - UIApplication.shared.open(url, options: [:], completionHandler: nil) - } - } - .font(.callout) - .multilineTextAlignment(.leading) - } else { - Text("Permet de proposer le paiement de vos tournois en ligne.") - } - } - - Section { - Text("Vous souhaitez partager la supervision d'un tournoi à un autre compte ? Vous avez plusieurs juge-arbitres dans votre club ?") - SupportButtonView(supportButtonType: .sharingRequest) - } - Section { NavigationLink("Changer de mot de passe") { ChangePasswordView() diff --git a/PadelClub/Views/User/LoginView.swift b/PadelClub/Views/User/LoginView.swift index 3a15eef..7959230 100644 --- a/PadelClub/Views/User/LoginView.swift +++ b/PadelClub/Views/User/LoginView.swift @@ -207,7 +207,7 @@ struct LoginView: View { dataStore.appSettingsStorage.write() } self.handler(user) - navigation.umpirePath.removeAll() + navigation.accountPath.removeAll() } catch { self.isLoading = false self.errorText = ErrorUtils.message(error: error)