fix search view model

online_payment
Raz 7 months ago
parent f72e98df8b
commit f1b013a88c
  1. 20
      PadelClub/Data/PlayerRegistration.swift
  2. 46
      PadelClub/Extensions/String+Extensions.swift
  3. 75
      PadelClub/ViewModel/SearchViewModel.swift
  4. 6
      PadelClub/Views/Tournament/Screen/InscriptionManagerView.swift

@ -254,15 +254,21 @@ final class PlayerRegistration: BasePlayerRegistration, SideStorable {
#endif
if let dataFound = try await history(from: sources) {
rank = dataFound.rankValue?.toInt()
points = dataFound.points
tournamentPlayed = dataFound.tournamentCountValue?.toInt()
await MainActor.run {
rank = dataFound.rankValue?.toInt()
points = dataFound.points
tournamentPlayed = dataFound.tournamentCountValue?.toInt()
}
} else if let dataFound = try await historyFromName(from: sources) {
rank = dataFound.rankValue?.toInt()
points = dataFound.points
tournamentPlayed = dataFound.tournamentCountValue?.toInt()
await MainActor.run {
rank = dataFound.rankValue?.toInt()
points = dataFound.points
tournamentPlayed = dataFound.tournamentCountValue?.toInt()
}
} else {
rank = lastRank
await MainActor.run {
rank = lastRank
}
}
}

@ -162,8 +162,50 @@ extension String {
}
func licencesFound() -> [String] {
let matches = self.matches(of: /[1-9][0-9]{5,7}/)
return matches.map { String(self[$0.range]) }
// First try to find licenses with format: 5-8 digits followed by optional letter
let precisePattern = /[1-9][0-9]{5,7}[ ]?[A-Za-z]?/
let preciseMatches = self.matches(of: precisePattern)
let preciseResults = preciseMatches.map { String(self[$0.range]).trimmingCharacters(in: .whitespaces) }
// If we find potential licenses with the precise pattern
if !preciseResults.isEmpty {
// Filter to only include those with trailing letters
let licensesWithLetters = preciseResults.filter {
let lastChar = $0.last
return lastChar != nil && lastChar!.isLetter
}
print("🎫 Found \(preciseResults.count) potential licenses, filtering to \(licensesWithLetters.count) with trailing letters")
// If we have licenses with letters, validate them
if !licensesWithLetters.isEmpty {
let validLicenses = licensesWithLetters.filter { $0.isLicenseNumber }
// If we have valid licenses, return the numeric part of each
if !validLicenses.isEmpty {
let numericLicenses = validLicenses.map { license -> String in
// Extract just the numeric part (all characters except the last letter)
if let lastChar = license.last, lastChar.isLetter {
return String(license.dropLast())
}
return license
}
if numericLicenses.isEmpty == false {
print("🎫 Found valid licenses: \(validLicenses), returning numeric parts: \(numericLicenses)")
return numericLicenses
}
}
}
}
// Fallback to just number pattern if we didn't find good matches
let numberPattern = /[1-9][0-9]{5,7}/
let numberMatches = self.matches(of: numberPattern)
let numberResults = numberMatches.map { String(self[$0.range]) }
print("🎫 Falling back to number-only pattern, found: \(numberResults)")
return numberResults
}
}

@ -472,32 +472,42 @@ class SearchViewModel: ObservableObject, Identifiable {
static func pastePredicate(
pasteField: String, mostRecentDate: Date?, filterOption: PlayerFilterOption
) -> NSPredicate? {
print("🔍 pastePredicate called with: \(pasteField)")
print("📅 mostRecentDate: \(String(describing: mostRecentDate))")
print("🔍 filterOption: \(filterOption)")
var andPredicates = [NSPredicate]()
var orPredicates = [NSPredicate]()
// Check for license numbers
let matches = pasteField.licencesFound()
print("🎫 Licenses found: \(matches)")
let licensesPredicates = matches.map { NSPredicate(format: "license contains[cd] %@", $0) }
orPredicates = licensesPredicates
if matches.count == 2 {
print("✅ Returning early with 2 license predicates")
return NSCompoundPredicate(orPredicateWithSubpredicates: orPredicates)
}
// Add gender filter if specified
if filterOption == .female {
print("👩 Adding female filter")
andPredicates.append(NSPredicate(format: "male == NO"))
} else if filterOption == .male {
print("👨 Adding male filter")
andPredicates.append(NSPredicate(format: "male == YES"))
}
// Add date filter if specified
if let mostRecentDate {
print("📆 Adding date filter for: \(mostRecentDate)")
andPredicates.append(NSPredicate(format: "importDate == %@", mostRecentDate as CVarArg))
}
// Check for slashes (representing alternatives)
if let slashPredicate = getSpecialSlashPredicate(inputString: pasteField) {
print("🔀 Found slash predicate")
orPredicates.append(slashPredicate)
}
@ -506,66 +516,80 @@ class SearchViewModel: ObservableObject, Identifiable {
pasteField
.replacingOccurrences(of: "[\\(\\)\\[\\]\\{\\}]", with: "", options: .regularExpression)
.replacingOccurrences(of: "/", with: " ") // Replace slashes with spaces
.replacingOccurrences(of: "[\\.,;:!?]", with: " ", options: .regularExpression) // Replace common punctuation with spaces
.trimmingCharacters(in: .whitespacesAndNewlines)
print("🧹 Cleaned text: \"\(text)\"")
// Remove digits
let digitPattern = /\b\w*\d\w*\b/
text = text.replacing(digitPattern, with: "").trimmingCharacters(
in: .whitespacesAndNewlines)
print("🔢 After digit removal: \"\(text)\"")
// Split text by whitespace to get potential name components
let textComponents = text.components(separatedBy: .whitespacesAndNewlines)
.map { $0.trimmingCharacters(in: .whitespacesAndNewlines) }
.filter {
!$0.isEmpty && $0.count > 1 && !["de", "la", "le", "du"].contains($0.lowercased())
!$0.isEmpty && $0.count > 1 && !["de", "la", "le", "du", "et", "si"].contains($0.lowercased())
}
print("📚 Text components: \(textComponents)")
if textComponents.count < 50 {
print("✓ Text components count is reasonable: \(textComponents.count)")
// Handle exact fullname match
let fullName = textComponents.joined(separator: " ")
if !fullName.isEmpty {
print("📝 Adding predicate for full name: \"\(fullName)\"")
orPredicates.append(
NSPredicate(format: "canonicalFullName CONTAINS[cd] %@", fullName))
}
// Handle hyphenated last names
let hyphenatedComponents = textComponents.filter { $0.contains("-") }
print("🔗 Hyphenated components: \(hyphenatedComponents)")
for component in hyphenatedComponents {
orPredicates.append(NSPredicate(format: "lastName CONTAINS[cd] %@", component))
print("➕ Added hyphenated last name predicate: \"\(component)\"")
// Also search for each part of the hyphenated name
let parts = component.components(separatedBy: "-")
for part in parts {
if part.count > 1 {
orPredicates.append(NSPredicate(format: "lastName CONTAINS[cd] %@", part))
print("➕ Added hyphenated part predicate: \"\(part)\"")
}
}
}
// Try different combinations for first/last name
if textComponents.count > 1 {
print("🔄 Creating combinations with \(textComponents.count) components")
// Try each pair of components as first+last and last+first
for i in 0..<textComponents.count {
for j in 0..<textComponents.count where i != j {
orPredicates.append(
NSPredicate(
format:
"(firstName CONTAINS[cd] %@ AND lastName CONTAINS[cd] %@) OR (firstName CONTAINS[cd] %@ AND lastName CONTAINS[cd] %@)",
textComponents[i], textComponents[j], textComponents[j],
textComponents[i]
))
// Also try beginswith for more precise matches
orPredicates.append(
NSPredicate(
format:
"(firstName BEGINSWITH[cd] %@ AND lastName BEGINSWITH[cd] %@) OR (firstName BEGINSWITH[cd] %@ AND lastName BEGINSWITH[cd] %@)",
textComponents[i], textComponents[j], textComponents[j],
textComponents[i]
))
}
for i in 0..<textComponents.count-1 {
let j = i + 1
print("👥 Trying adjacent pair: \"\(textComponents[i])\" and \"\(textComponents[j])\"")
// orPredicates.append(
// NSPredicate(
// format:
// "(firstName CONTAINS[cd] %@ AND lastName CONTAINS[cd] %@) OR (firstName CONTAINS[cd] %@ AND lastName CONTAINS[cd] %@)",
// textComponents[i], textComponents[j], textComponents[j],
// textComponents[i]
// ))
// Also try beginswith for more precise matches
orPredicates.append(
NSPredicate(
format:
"(firstName BEGINSWITH[cd] %@ AND lastName BEGINSWITH[cd] %@) OR (firstName BEGINSWITH[cd] %@ AND lastName BEGINSWITH[cd] %@)",
textComponents[i], textComponents[j], textComponents[j],
textComponents[i]
))
}
} else if textComponents.count == 1 {
print("👤 Single component search: \"\(textComponents[0])\"")
// If only one component, search in both first and last name
orPredicates.append(
NSPredicate(
@ -574,14 +598,19 @@ class SearchViewModel: ObservableObject, Identifiable {
}
// Add pattern match for canonical full name
let pattern = textComponents.joined(separator: ".*")
orPredicates.append(NSPredicate(format: "canonicalFullName MATCHES[c] %@", pattern))
// let pattern = textComponents.joined(separator: ".*")
// print("🔍 Adding pattern match: \"\(pattern)\"")
// orPredicates.append(NSPredicate(format: "canonicalFullName MATCHES[c] %@", pattern))
} else {
print(" Too many text components: \(textComponents.count) - skipping name combinations")
}
// Construct final predicate
var predicate = NSCompoundPredicate(andPredicateWithSubpredicates: andPredicates)
print("📊 AND predicates count: \(andPredicates.count)")
if !orPredicates.isEmpty {
print("📊 OR predicates count: \(orPredicates.count)")
let orCompoundPredicate = NSCompoundPredicate(
orPredicateWithSubpredicates: orPredicates)
predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [
@ -589,6 +618,8 @@ class SearchViewModel: ObservableObject, Identifiable {
])
}
print("🏁 Final predicate created")
print(predicate)
return predicate
}

@ -720,6 +720,12 @@ struct InscriptionManagerView: View {
}
}
.pickerStyle(.menu)
if currentRankSourceDate == SourceFileManager.shared.mostRecentDateAvailable {
Button("Rafraîchir") {
confirmUpdateRank = true
}
}
}
}

Loading…
Cancel
Save