fix search view model

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

@ -254,17 +254,23 @@ final class PlayerRegistration: BasePlayerRegistration, SideStorable {
#endif #endif
if let dataFound = try await history(from: sources) { if let dataFound = try await history(from: sources) {
await MainActor.run {
rank = dataFound.rankValue?.toInt() rank = dataFound.rankValue?.toInt()
points = dataFound.points points = dataFound.points
tournamentPlayed = dataFound.tournamentCountValue?.toInt() tournamentPlayed = dataFound.tournamentCountValue?.toInt()
}
} else if let dataFound = try await historyFromName(from: sources) { } else if let dataFound = try await historyFromName(from: sources) {
await MainActor.run {
rank = dataFound.rankValue?.toInt() rank = dataFound.rankValue?.toInt()
points = dataFound.points points = dataFound.points
tournamentPlayed = dataFound.tournamentCountValue?.toInt() tournamentPlayed = dataFound.tournamentCountValue?.toInt()
}
} else { } else {
await MainActor.run {
rank = lastRank rank = lastRank
} }
} }
}
func history(from sources: [CSVParser]) async throws -> Line? { func history(from sources: [CSVParser]) async throws -> Line? {
#if DEBUG_TIME #if DEBUG_TIME

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

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

Loading…
Cancel
Save