diff --git a/PadelClub/Data/Federal/FederalTournamentHolder.swift b/PadelClub/Data/Federal/FederalTournamentHolder.swift index 1e5de69..594e98b 100644 --- a/PadelClub/Data/Federal/FederalTournamentHolder.swift +++ b/PadelClub/Data/Federal/FederalTournamentHolder.swift @@ -19,14 +19,9 @@ protocol FederalTournamentHolder { var dayPeriod: DayPeriod { get } func tournamentTitle(_ displayStyle: DisplayStyle, forBuild build: any TournamentBuildHolder) -> String func displayAgeAndCategory(forBuild build: any TournamentBuildHolder) -> Bool - func togglePrivate(isPrivate: Bool) } extension FederalTournamentHolder { - func togglePrivate(isPrivate: Bool) { - - } - func durationLabel() -> String { switch dayDuration { case 1: diff --git a/PadelClub/Data/Tournament.swift b/PadelClub/Data/Tournament.swift index 531e749..804a089 100644 --- a/PadelClub/Data/Tournament.swift +++ b/PadelClub/Data/Tournament.swift @@ -2680,10 +2680,6 @@ extension Tournament: Hashable { } extension Tournament: FederalTournamentHolder { - func togglePrivate(isPrivate: Bool) { - self.isPrivate = isPrivate - } - func tournamentTitle(_ displayStyle: DisplayStyle, forBuild build: any TournamentBuildHolder) -> String { if isAnimation() { if let name { diff --git a/PadelClub/ViewModel/SearchViewModel.swift b/PadelClub/ViewModel/SearchViewModel.swift index 5167d05..8857997 100644 --- a/PadelClub/ViewModel/SearchViewModel.swift +++ b/PadelClub/ViewModel/SearchViewModel.swift @@ -356,6 +356,17 @@ class SearchViewModel: ObservableObject, Identifiable { static func pastePredicate(pasteField: String, mostRecentDate: Date?, filterOption: PlayerFilterOption) -> NSPredicate? { + var andPredicates = [NSPredicate]() + var orPredicates = [NSPredicate]() + + let matches = pasteField.licencesFound() + let licensesPredicates = matches.map { NSPredicate(format: "license contains[cd] %@", $0) } + orPredicates = licensesPredicates + + if matches.count == 2 { + return NSCompoundPredicate(orPredicateWithSubpredicates: orPredicates) + } + let allowedCharacterSet = CharacterSet.alphanumerics.union(.whitespaces) // Remove all characters that are not in the allowedCharacterSet @@ -369,14 +380,8 @@ class SearchViewModel: ObservableObject, Identifiable { let textStrings: [String] = text.components(separatedBy: .whitespacesAndNewlines) let nonEmptyStrings: [String] = textStrings.compactMap { $0.isEmpty ? nil : $0 } let nameComponents = nonEmptyStrings.filter({ $0 != "de" && $0 != "la" && $0 != "le" && $0.count > 1 }) - var andPredicates = [NSPredicate]() - var orPredicates = [NSPredicate]() - //self.wordsCount = nameComponents.count - - if let slashPredicate = getSpecialSlashPredicate(inputString: pasteField) { - orPredicates.append(slashPredicate) - } + //self.wordsCount = nameComponents.count if filterOption == .female { andPredicates.append(NSPredicate(format: "male == NO")) } @@ -385,11 +390,20 @@ class SearchViewModel: ObservableObject, Identifiable { andPredicates.append(NSPredicate(format: "importDate == %@", mostRecentDate as CVarArg)) } - if nameComponents.count > 1 { - orPredicates.append(contentsOf: nameComponents.pairs().map { - return NSPredicate(format: "(firstName BEGINSWITH[cd] %@ AND lastName BEGINSWITH[cd] %@) OR (firstName BEGINSWITH[cd] %@ AND lastName BEGINSWITH[cd] %@)", $0, $1, $1, $0) }) - } else { - orPredicates.append(contentsOf: nameComponents.map { NSPredicate(format: "firstName contains[cd] %@ OR lastName contains[cd] %@", $0,$0) }) + + if let slashPredicate = getSpecialSlashPredicate(inputString: pasteField) { + orPredicates.append(slashPredicate) + } + + print("nameComponents", nameComponents.count) + + if nameComponents.count < 50 { + if nameComponents.count > 1 { + orPredicates.append(contentsOf: nameComponents.pairs().map { + return NSPredicate(format: "(firstName BEGINSWITH[cd] %@ AND lastName BEGINSWITH[cd] %@) OR (firstName BEGINSWITH[cd] %@ AND lastName BEGINSWITH[cd] %@)", $0, $1, $1, $0) }) + } else { + orPredicates.append(contentsOf: nameComponents.map { NSPredicate(format: "firstName contains[cd] %@ OR lastName contains[cd] %@", $0,$0) }) + } } let components = text.split(separator: " ") @@ -397,11 +411,7 @@ class SearchViewModel: ObservableObject, Identifiable { print(text, pattern) let canonicalFullNamePredicate = NSPredicate(format: "canonicalFullName MATCHES[c] %@", pattern) orPredicates.append(canonicalFullNamePredicate) - - let matches = pasteField.licencesFound() - let licensesPredicates = matches.map { NSPredicate(format: "license contains[cd] %@", $0) } - orPredicates = orPredicates + licensesPredicates - + var predicate = NSCompoundPredicate(andPredicateWithSubpredicates: andPredicates) if orPredicates.isEmpty == false { diff --git a/PadelClub/Views/Navigation/Agenda/EventListView.swift b/PadelClub/Views/Navigation/Agenda/EventListView.swift index 833f228..7000131 100644 --- a/PadelClub/Views/Navigation/Agenda/EventListView.swift +++ b/PadelClub/Views/Navigation/Agenda/EventListView.swift @@ -92,35 +92,83 @@ struct EventListView: View { private func _menuOptions(_ pcTournaments: [Tournament]) -> some View { Menu { - Button { - pcTournaments.forEach { tournament in - tournament.togglePrivate(isPrivate: false) + _options(pcTournaments) + } label: { + Text("Options rapides pour ce mois") + .underline() + } + } + + @ViewBuilder + private func _options(_ pcTournaments: [Tournament]) -> some View { + Section { + if pcTournaments.anySatisfy({ $0.isPrivate == true }) { + Button { + pcTournaments.forEach { tournament in + tournament.isPrivate = false + } + do { + try dataStore.tournaments.addOrUpdate(contentOfs: pcTournaments) + } catch { + Logger.error(error) + } + } label: { + Text("Afficher ce\(pcTournaments.count.pluralSuffix) tournoi\(pcTournaments.count.pluralSuffix) sur Padel Club") } - do { - try dataStore.tournaments.addOrUpdate(contentOfs: pcTournaments) - } catch { - Logger.error(error) + } + + if pcTournaments.anySatisfy({ $0.isPrivate == false }) { + Button { + pcTournaments.forEach { tournament in + tournament.isPrivate = true + } + do { + try dataStore.tournaments.addOrUpdate(contentOfs: pcTournaments) + } catch { + Logger.error(error) + } + } label: { + Text("Masquer ce\(pcTournaments.count.pluralSuffix) tournoi\(pcTournaments.count.pluralSuffix) sur Padel Club") } - } label: { - Text("Afficher ces tournois sur Padel Club") } - Button { - pcTournaments.forEach { tournament in - tournament.togglePrivate(isPrivate: true) + } header: { + Text("Visibilité sur Padel Club") + } + Divider() + if pcTournaments.anySatisfy({ $0.hasEnded() == false && $0.enableOnlineRegistration == false && $0.onlineRegistrationCanBeEnabled() }) || pcTournaments.anySatisfy({ $0.enableOnlineRegistration == true }) { + Section { + if pcTournaments.anySatisfy({ $0.hasEnded() == false && $0.enableOnlineRegistration == false && $0.onlineRegistrationCanBeEnabled() }) { + Button { + pcTournaments.forEach { tournament in + tournament.enableOnlineRegistration = true + } + do { + try dataStore.tournaments.addOrUpdate(contentOfs: pcTournaments) + } catch { + Logger.error(error) + } + } label: { + Text("Activer l'inscription en ligne") + } } - do { - try dataStore.tournaments.addOrUpdate(contentOfs: pcTournaments) - } catch { - Logger.error(error) + + if pcTournaments.anySatisfy({ $0.enableOnlineRegistration == true }) { + Button { + pcTournaments.forEach { tournament in + tournament.enableOnlineRegistration = false + } + do { + try dataStore.tournaments.addOrUpdate(contentOfs: pcTournaments) + } catch { + Logger.error(error) + } + } label: { + Text("Désactiver l'inscription en ligne") + } } - } label: { - Text("Masquer ces tournois sur Padel Club") + } header: { + Text("Inscription en ligne") } - - } label: { - Text("Gérer la visibilité sur Padel Club") - .font(.caption) - .underline() } } @@ -160,13 +208,20 @@ struct EventListView: View { NavigationLink(value: tournament) { TournamentCellView(tournament: tournament, shouldTournamentBeOver: tournament.shouldTournamentBeOver()) } + .listRowView(isActive: tournament.enableOnlineRegistration, color: .green, hideColorVariation: true) .contextMenu { if tournament.hasEnded() == false { Button { navigation.openTournamentInOrganizer(tournament) } label: { - Label("Voir dans le gestionnaire", systemImage: "line.diagonal.arrow") + Label("Afficher dans le gestionnaire", systemImage: "line.diagonal.arrow") } + + Divider() + + _options([tournament]) + + } } #if DEBUG diff --git a/PadelClub/Views/Tournament/Screen/AddTeamView.swift b/PadelClub/Views/Tournament/Screen/AddTeamView.swift index 7fd4bf8..f0dbe16 100644 --- a/PadelClub/Views/Tournament/Screen/AddTeamView.swift +++ b/PadelClub/Views/Tournament/Screen/AddTeamView.swift @@ -620,14 +620,11 @@ struct AddTeamView: View { return 1 } - @MainActor private func handlePasteString(_ first: String) { if first.isEmpty == false { - DispatchQueue.main.async { - fetchPlayers.nsPredicate = SearchViewModel.pastePredicate(pasteField: first, mostRecentDate: SourceFileManager.shared.mostRecentDateAvailable, filterOption: _filterOption()) - fetchPlayers.nsSortDescriptors = [NSSortDescriptor(keyPath: \ImportedPlayer.rank, ascending: true)] - autoSelect = true - } + fetchPlayers.nsPredicate = SearchViewModel.pastePredicate(pasteField: first, mostRecentDate: SourceFileManager.shared.mostRecentDateAvailable, filterOption: _filterOption()) + fetchPlayers.nsSortDescriptors = [NSSortDescriptor(keyPath: \ImportedPlayer.rank, ascending: true)] + autoSelect = true } pasteString = first editableTextField = first diff --git a/PadelClub/Views/Tournament/Screen/RegistrationSetupView.swift b/PadelClub/Views/Tournament/Screen/RegistrationSetupView.swift index ea4d552..33f08f7 100644 --- a/PadelClub/Views/Tournament/Screen/RegistrationSetupView.swift +++ b/PadelClub/Views/Tournament/Screen/RegistrationSetupView.swift @@ -141,17 +141,18 @@ struct RegistrationSetupView: View { } Section { - Toggle(isOn: $targetTeamCountEnabled) { - Text("Activer une limite") - } - - if targetTeamCountEnabled { - StepperView(count: $targetTeamCount, minimum: 4) - } - } header: { +// Toggle(isOn: $targetTeamCountEnabled) { +// Text("Activer une limite") +// } +// +// if targetTeamCountEnabled { +// StepperView(count: $targetTeamCount, minimum: 4) +// } + StepperView(count: $targetTeamCount, minimum: 4) + } header: { Text("Paires admises") } footer: { - Text("Si une limite de paire existe, les inscriptions seront indiqués en attente pour les joueurs au-délà de cette limite dans le cas où aucune limite de liste d'attente n'est active ou non atteinte. Dans le cas contraire, plus aucune inscription ne seront possibles.") + Text("Les inscriptions seront indiqués en attente pour les joueurs au-délà de cette limite dans le cas où aucune limite de liste d'attente n'est active ou non atteinte. Dans le cas contraire, plus aucune inscription ne seront possibles.") } Section { @@ -160,7 +161,7 @@ struct RegistrationSetupView: View { } if waitingListLimitEnabled { - StepperView(count: $waitingListLimit, minimum: 1) + StepperView(count: $waitingListLimit, minimum: 0) } } header: { Text("Liste d'attente") diff --git a/PadelClub/Views/Tournament/TournamentInscriptionView.swift b/PadelClub/Views/Tournament/TournamentInscriptionView.swift index a40dee1..c06461a 100644 --- a/PadelClub/Views/Tournament/TournamentInscriptionView.swift +++ b/PadelClub/Views/Tournament/TournamentInscriptionView.swift @@ -21,6 +21,10 @@ struct TournamentInscriptionView: View { Text("Gestion des inscriptions") if let closedRegistrationDate = tournament.closedRegistrationDate { Text("clôturé le " + closedRegistrationDate.formatted(date: .abbreviated, time: .shortened)) + } else if tournament.enableOnlineRegistration { + Text("Inscription en ligne activée") + } else if tournament.onlineRegistrationCanBeEnabled() { + Text("Inscription en ligne désactivée") } } }