multistore
Laurent 2 years ago
commit 56553329a1
  1. 8
      PadelClub.xcodeproj/project.pbxproj
  2. 1
      PadelClub/Data/AppSettings.swift
  3. 6
      PadelClub/Data/Club.swift
  4. 6
      PadelClub/Data/Event.swift
  5. 8
      PadelClub/Data/Match.swift
  6. 2
      PadelClub/Data/MockData.swift
  7. 57
      PadelClub/Data/PlayerRegistration.swift
  8. 45
      PadelClub/Data/TeamRegistration.swift
  9. 75
      PadelClub/Data/Tournament.swift
  10. 38
      PadelClub/Extensions/String+Extensions.swift
  11. 2
      PadelClub/Info.plist
  12. 11
      PadelClub/Utils/PadelRule.swift
  13. 4
      PadelClub/ViewModel/AgendaDestination.swift
  14. 4
      PadelClub/Views/Cashier/CashierDetailView.swift
  15. 4
      PadelClub/Views/Cashier/CashierSettingsView.swift
  16. 107
      PadelClub/Views/Components/FortuneWheelView.swift
  17. 41
      PadelClub/Views/GroupStage/Components/GroupStageTeamView.swift
  18. 10
      PadelClub/Views/Player/Components/PlayerPayView.swift
  19. 2
      PadelClub/Views/Player/Components/PlayerPopoverView.swift
  20. 6
      PadelClub/Views/Player/Components/PlayerSexPickerView.swift
  21. 4
      PadelClub/Views/Player/PlayerDetailView.swift
  22. 19
      PadelClub/Views/Round/RoundView.swift
  23. 2
      PadelClub/Views/Round/RoundsView.swift
  24. 8
      PadelClub/Views/Tournament/Screen/BroadcastView.swift
  25. 2
      PadelClub/Views/Tournament/Screen/Components/InscriptionInfoView.swift
  26. 2
      PadelClub/Views/Tournament/Screen/Components/UpdateSourceRankDateView.swift
  27. 2
      PadelClub/Views/Tournament/Screen/InscriptionManagerView.swift

@ -131,6 +131,7 @@
FF3B60A32BC49BBC008C2E66 /* MatchScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF3B60A22BC49BBC008C2E66 /* MatchScheduler.swift */; };
FF3F74F62B919E45004CFE0E /* UmpireView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF3F74F52B919E45004CFE0E /* UmpireView.swift */; };
FF3F74FF2B91A2D4004CFE0E /* AgendaDestination.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF3F74FE2B91A2D4004CFE0E /* AgendaDestination.swift */; };
FF44421C2BE39FA2008BBF0B /* Launch Screen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = FFD784002B91BF79000F62A6 /* Launch Screen.storyboard */; };
FF4AB6B52B9248200002987F /* NetworkManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF4AB6B42B9248200002987F /* NetworkManager.swift */; };
FF4AB6BB2B9256D50002987F /* SearchViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF4AB6BA2B9256D50002987F /* SearchViewModel.swift */; };
FF4AB6BD2B9256E10002987F /* SelectablePlayerListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF4AB6BC2B9256E10002987F /* SelectablePlayerListView.swift */; };
@ -1369,6 +1370,7 @@
buildActionMask = 2147483647;
files = (
C425D4082B6D249E002A7B48 /* Preview Assets.xcassets in Resources */,
FF44421C2BE39FA2008BBF0B /* Launch Screen.storyboard in Resources */,
FF0EC54E2BB195E20056B6D1 /* CLASSEMENT-PADEL-MESSIEURS-2-02-2023.csv in Resources */,
FF0EC54F2BB195E20056B6D1 /* CLASSEMENT-PADEL-MESSIEURS-08-2022.csv in Resources */,
FF0EC5502BB195E20056B6D1 /* CLASSEMENT-PADEL-DAMES-12-2022.csv in Resources */,
@ -1808,7 +1810,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
CURRENT_PROJECT_VERSION = 4;
DEFINES_MODULE = YES;
DEVELOPMENT_ASSET_PATHS = "\"PadelClub/Preview Content\"";
DEVELOPMENT_TEAM = BQ3Y44M3Q6;
@ -1817,6 +1819,7 @@
INFOPLIST_FILE = PadelClub/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = "Padel Club";
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.sports";
INFOPLIST_KEY_LSSupportsOpeningDocumentsInPlace = YES;
INFOPLIST_KEY_NSLocationWhenInUseUsageDescription = "Padel Club a besoin de votre position pour rechercher les clubs autour de vous.";
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
@ -1842,7 +1845,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
CURRENT_PROJECT_VERSION = 4;
DEFINES_MODULE = YES;
DEVELOPMENT_ASSET_PATHS = "\"PadelClub/Preview Content\"";
DEVELOPMENT_TEAM = BQ3Y44M3Q6;
@ -1851,6 +1854,7 @@
INFOPLIST_FILE = PadelClub/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = "Padel Club";
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.sports";
INFOPLIST_KEY_LSSupportsOpeningDocumentsInPlace = YES;
INFOPLIST_KEY_NSLocationWhenInUseUsageDescription = "Padel Club a besoin de votre position pour rechercher les clubs autour de vous.";
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;

@ -15,6 +15,7 @@ class AppSettings: MicroStorable {
static var fileName: String { "appsettings.json" }
var lastDataSource: String? = nil
var callMessageBody : String? = nil
var callMessageSignature: String? = nil
var callDisplayFormat: Bool = false

@ -23,10 +23,12 @@ class Club : ModelObject, Storable, Hashable {
}
var id: String = Store.randomId()
var creator: String?
var name: String
var acronym: String
var phone: String?
var code: String?
//var federalClubData: Data?
var address: String?
var city: String?
var zipCode: String?
@ -34,7 +36,8 @@ class Club : ModelObject, Storable, Hashable {
var longitude: Double?
//var courtCount: Int?
internal init(name: String, acronym: String? = nil, phone: String? = nil, code: String? = nil, address: String? = nil, city: String? = nil, zipCode: String? = nil, latitude: Double? = nil, longitude: Double? = nil) {
internal init(creator: String? = nil, name: String, acronym: String? = nil, phone: String? = nil, code: String? = nil, address: String? = nil, city: String? = nil, zipCode: String? = nil, latitude: Double? = nil, longitude: Double? = nil) {
self.creator = creator
self.name = name
self.acronym = acronym ?? name.acronym()
self.phone = phone
@ -69,6 +72,7 @@ class Club : ModelObject, Storable, Hashable {
enum CodingKeys: String, CodingKey {
case _id = "id"
case _creator = "creator"
case _name = "name"
case _acronym = "acronym"
case _phone = "phone"

@ -14,9 +14,11 @@ class Event: ModelObject, Storable {
static func resourceName() -> String { return "events" }
var id: String = Store.randomId()
var creator: String?
var club: String?
var creationDate: Date = Date()
var name: String?
//var federalTournamentData: Data?
//var courtCount: Int?
var tenupId: String?
// var groupStageFormat: Int?
@ -24,7 +26,8 @@ class Event: ModelObject, Storable {
// var loserRoundFormat: Int?
//var timeslots ?
internal init(club: String? = nil, name: String? = nil, tenupId: String? = nil) {
internal init(creator: String? = nil, club: String? = nil, name: String? = nil, tenupId: String? = nil) {
self.creator = creator
self.club = club
self.name = name
// self.courtCount = courtCount
@ -61,6 +64,7 @@ class Event: ModelObject, Storable {
extension Event {
enum CodingKeys: String, CodingKey {
case _id = "id"
case _creator = "creator"
case _club = "club"
case _creationDate = "creationDate"
case _name = "name"

@ -56,11 +56,11 @@ class Match: ModelObject, Storable {
}
func matchWarningSubject() -> String {
[roundTitle(), matchTitle()].compacted().joined(separator: " ")
[roundTitle(), matchTitle(.short)].compacted().joined(separator: " ")
}
func matchWarningMessage() -> String {
[roundTitle(), matchTitle(), startDate?.localizedDate(), courtName()].compacted().joined(separator: "\n")
[roundTitle(), matchTitle(.short), startDate?.localizedDate(), courtName()].compacted().joined(separator: "\n")
}
func matchTitle(_ displayStyle: DisplayStyle = .wide) -> String {
@ -448,6 +448,10 @@ class Match: ModelObject, Storable {
endDate ?? .distantFuture
}
func hasSpaceLeft() -> Bool {
teams().count == 1
}
func isReady() -> Bool {
teams().count == 2
}

@ -61,6 +61,6 @@ extension TeamRegistration {
extension PlayerRegistration {
static func mock() -> PlayerRegistration {
PlayerRegistration(firstName: "Raz", lastName: "Shark", sex: 1)
PlayerRegistration(firstName: "Raz", lastName: "Shark", sex: .male)
}
}

@ -18,9 +18,8 @@ class PlayerRegistration: ModelObject, Storable {
var lastName: String
var licenceId: String?
var rank: Int?
var registrationType: PaymentType?
var registrationDate: Date?
var sex: Int
var paymentType: PlayerPaymentType?
var sex: PlayerSexType?
var tournamentPlayed: Int?
var points: Double?
@ -37,14 +36,13 @@ class PlayerRegistration: ModelObject, Storable {
var hasArrived: Bool = false
internal init(teamRegistration: String? = nil, firstName: String, lastName: String, licenceId: String? = nil, rank: Int? = nil, registrationType: PaymentType? = nil, registrationDate: Date? = nil, sex: Int, source: PlayerDataSource? = nil) {
internal init(teamRegistration: String? = nil, firstName: String, lastName: String, licenceId: String? = nil, rank: Int? = nil, paymentType: PlayerPaymentType? = nil, sex: PlayerSexType?, source: PlayerDataSource? = nil) {
self.teamRegistration = teamRegistration
self.firstName = firstName
self.lastName = lastName
self.licenceId = licenceId
self.rank = rank
self.registrationType = registrationType
self.registrationDate = registrationDate
self.paymentType = paymentType
self.sex = sex
self.source = source
}
@ -55,7 +53,7 @@ class PlayerRegistration: ModelObject, Storable {
self.lastName = importedPlayer.lastName ?? ""
self.licenceId = importedPlayer.license ?? nil
self.rank = Int(importedPlayer.rank)
self.sex = importedPlayer.male ? 1 : 0
self.sex = importedPlayer.male ? .male : .female
self.tournamentPlayed = importedPlayer.tournamentPlayed
self.points = importedPlayer.getPoints()
self.clubName = importedPlayer.clubName
@ -76,14 +74,14 @@ class PlayerRegistration: ModelObject, Storable {
source = .beachPadel
if sexUnknown {
if sex == 1 && FileImportManager.shared.foundInWomenData(license: federalData[3]) {
self.sex = 0
self.sex = .female
} else if FileImportManager.shared.foundInMenData(license: federalData[3]) {
self.sex = 1
self.sex = .male
} else {
self.sex = -1
self.sex = nil
}
} else {
self.sex = sex
self.sex = PlayerSexType(rawValue: sex)
}
}
@ -135,15 +133,21 @@ class PlayerRegistration: ModelObject, Storable {
}
func hasPaid() -> Bool {
registrationType != nil
paymentType != nil
}
func playerLabel(_ displayStyle: DisplayStyle = .wide) -> String {
switch displayStyle {
case .wide:
lastName.trimmed.capitalized + " " + firstName.trimmed.capitalized
return lastName.trimmed.capitalized + " " + firstName.trimmed.capitalized
case .short:
lastName.trimmed.capitalized + " " + firstName.trimmed.prefix(1).capitalized + "."
let names = lastName.components(separatedBy: .whitespaces)
if lastName.components(separatedBy: .whitespaces).count > 1 {
if let firstLongWord = names.first(where: { $0.count > 3 }) {
return firstLongWord.trimmed.capitalized.trunc(length: 10) + " " + firstName.trimmed.prefix(1).capitalized + "."
}
}
return lastName.trimmed.capitalized.trunc(length: 10) + " " + firstName.trimmed.prefix(1).capitalized + "."
}
}
@ -245,7 +249,7 @@ class PlayerRegistration: ModelObject, Storable {
}
func isMalePlayer() -> Bool {
sex == 1
sex == .male
}
func validateLicenceId(_ year: Int) {
@ -265,8 +269,7 @@ class PlayerRegistration: ModelObject, Storable {
case _lastName = "lastName"
case _licenceId = "licenceId"
case _rank = "rank"
case _registrationType = "registrationType"
case _registrationDate = "registrationDate"
case _paymentType = "paymentType"
case _sex = "sex"
case _tournamentPlayed = "tournamentPlayed"
case _points = "points"
@ -283,11 +286,25 @@ class PlayerRegistration: ModelObject, Storable {
}
enum PlayerDataSource: Int, Codable {
case frenchFederation
case beachPadel
case frenchFederation = 0
case beachPadel = 1
}
enum PlayerSexType: Int, Hashable, CaseIterable, Identifiable, Codable {
init?(rawValue: Int?) {
guard let value = rawValue else { return nil }
self.init(rawValue: value)
}
var id: Self {
self
}
case female = 0
case male = 1
}
enum PaymentType: Int, CaseIterable, Identifiable, Codable {
enum PlayerPaymentType: Int, CaseIterable, Identifiable, Codable {
init?(rawValue: Int?) {
guard let value = rawValue else { return nil }
self.init(rawValue: value)

@ -28,13 +28,12 @@ class TeamRegistration: ModelObject, Storable {
var walkOut: Bool = false
var wildCardBracket: Bool = false
var wildCardGroupStage: Bool = false
var category: TournamentCategory?
var weight: Int = 0
var lockWeight: Int?
var confirmationDate: Date?
var qualified: Bool = false
internal init(tournament: String, groupStage: String? = nil, registrationDate: Date? = nil, callDate: Date? = nil, bracketPosition: Int? = nil, groupStagePosition: Int? = nil, comment: String? = nil, source: String? = nil, sourceValue: String? = nil, logo: String? = nil, name: String? = nil, category: TournamentCategory? = nil) {
internal init(tournament: String, groupStage: String? = nil, registrationDate: Date? = nil, callDate: Date? = nil, bracketPosition: Int? = nil, groupStagePosition: Int? = nil, comment: String? = nil, source: String? = nil, sourceValue: String? = nil, logo: String? = nil, name: String? = nil) {
self.tournament = tournament
self.groupStage = groupStage
self.registrationDate = registrationDate
@ -46,7 +45,6 @@ class TeamRegistration: ModelObject, Storable {
self.sourceValue = sourceValue
self.logo = logo
self.name = name
self.category = category
}
func isSeedable() -> Bool {
@ -101,12 +99,7 @@ class TeamRegistration: ModelObject, Storable {
}
var tournamentCategory: TournamentCategory {
get {
category ?? .men
}
set {
category = newValue
}
tournamentObject()?.tournamentCategory ?? .men
}
@objc
@ -121,8 +114,8 @@ class TeamRegistration: ModelObject, Storable {
})
}
func updateWeight() {
setWeight(from: self.players())
func updateWeight(inTournamentCategory tournamentCategory: TournamentCategory) {
setWeight(from: self.players(), inTournamentCategory: tournamentCategory)
}
func teamLabel(_ displayStyle: DisplayStyle = .wide) -> String {
@ -130,7 +123,7 @@ class TeamRegistration: ModelObject, Storable {
case .wide:
players().map { $0.playerLabel(displayStyle) }.joined(separator: " & ")
case .short:
players().map { $0.playerLabel(.wide) }.joined(separator: "\n")
players().map { $0.playerLabel(.short) }.joined(separator: "\n")
}
}
@ -201,9 +194,9 @@ class TeamRegistration: ModelObject, Storable {
}
func updatePlayers(_ players: Set<PlayerRegistration>) {
func updatePlayers(_ players: Set<PlayerRegistration>, inTournamentCategory tournamentCategory: TournamentCategory) {
try? DataStore.shared.playerRegistrations.delete(contentOfs: unsortedPlayers())
setWeight(from: Array(players))
setWeight(from: Array(players), inTournamentCategory: tournamentCategory)
players.forEach { player in
player.teamRegistration = id
@ -251,7 +244,7 @@ class TeamRegistration: ModelObject, Storable {
func players() -> [PlayerRegistration] {
Store.main.filter { $0.teamRegistration == self.id }.sorted { (lhs, rhs) in
let predicates: [AreInIncreasingOrder] = [
{ $0.sex < $1.sex },
{ $0.sex?.rawValue ?? 0 < $1.sex?.rawValue ?? 0 },
{ $0.rank ?? 0 < $1.rank ?? 0 },
{ $0.lastName < $1.lastName},
{ $0.firstName < $1.firstName }
@ -273,31 +266,20 @@ class TeamRegistration: ModelObject, Storable {
Store.main.filter { $0.teamRegistration == self.id }
}
func setWeight(from players: [PlayerRegistration]) {
func setWeight(from players: [PlayerRegistration], inTournamentCategory tournamentCategory: TournamentCategory) {
let significantPlayerCount = significantPlayerCount()
weight = (players.prefix(significantPlayerCount).map { $0.weight } + missingPlayerType().map { unrankValue(for: $0 == 1 ? true : false ) }).prefix(significantPlayerCount).reduce(0,+)
weight = (players.prefix(significantPlayerCount).map { $0.weight } + missingPlayerType(inTournamentCategory: tournamentCategory).map { unrankValue(for: $0 == 1 ? true : false ) }).prefix(significantPlayerCount).reduce(0,+)
}
func significantPlayerCount() -> Int {
tournamentObject()?.significantPlayerCount() ?? 2
}
func mandatoryPlayerType() -> [Int] {
switch tournamentCategory {
case .mix:
return [0, 1]
case .women:
return [0, 0]
case .men:
return [1, 1]
}
}
func missingPlayerType() -> [Int] {
func missingPlayerType(inTournamentCategory tournamentCategory: TournamentCategory) -> [Int] {
let players = unsortedPlayers()
if players.count >= 2 { return [] }
let s = players.map { $0.sex }
var missing = mandatoryPlayerType()
let s = players.compactMap { $0.sex?.rawValue }
var missing = tournamentCategory.mandatoryPlayerType()
s.forEach { i in
if let index = missing.firstIndex(of: i) {
missing.remove(at: index)
@ -351,7 +333,6 @@ class TeamRegistration: ModelObject, Storable {
case _name = "name"
case _wildCardBracket = "wildCardBracket"
case _wildCardGroupStage = "wildCardGroupStage"
case _category = "category"
case _weight = "weight"
case _walkOut = "walkOut"
case _lockWeight = "lockWeight"

@ -14,7 +14,6 @@ class Tournament : ModelObject, Storable {
var id: String = Store.randomId()
var event: String?
var creator: String?
var name: String?
var startDate: Date
var endDate: Date?
@ -33,7 +32,6 @@ class Tournament : ModelObject, Storable {
var federalLevelCategory: TournamentLevel
var federalAgeCategory: FederalTournamentAge
var groupStageCourtCount: Int?
var seedCount: Int
var closedRegistrationDate: Date?
var groupStageAdditionalQualified: Int
var courtCount: Int = 2
@ -85,9 +83,8 @@ class Tournament : ModelObject, Storable {
case _payment = "globalId"
}
internal init(event: String? = nil, creator: String? = nil, name: String? = nil, startDate: Date = Date(), endDate: Date? = nil, creationDate: Date = Date(), isPrivate: Bool = true, groupStageFormat: MatchFormat? = nil, roundFormat: MatchFormat? = nil, loserRoundFormat: MatchFormat? = nil, groupStageSortMode: GroupStageOrderingMode, groupStageCount: Int = 4, rankSourceDate: Date? = nil, dayDuration: Int = 1, teamCount: Int = 24, teamSorting: TeamSortingType? = nil, federalCategory: TournamentCategory, federalLevelCategory: TournamentLevel, federalAgeCategory: FederalTournamentAge, groupStageCourtCount: Int? = nil, seedCount: Int = 8, closedRegistrationDate: Date? = nil, groupStageAdditionalQualified: Int = 0, courtCount: Int = 2, prioritizeClubMembers: Bool = false, qualifiedPerGroupStage: Int = 1, teamsPerGroupStage: Int = 4, entryFee: Double? = nil) {
internal init(event: String? = nil, name: String? = nil, startDate: Date = Date(), endDate: Date? = nil, creationDate: Date = Date(), isPrivate: Bool = true, groupStageFormat: MatchFormat? = nil, roundFormat: MatchFormat? = nil, loserRoundFormat: MatchFormat? = nil, groupStageSortMode: GroupStageOrderingMode, groupStageCount: Int = 4, rankSourceDate: Date? = nil, dayDuration: Int = 1, teamCount: Int = 24, teamSorting: TeamSortingType? = nil, federalCategory: TournamentCategory, federalLevelCategory: TournamentLevel, federalAgeCategory: FederalTournamentAge, groupStageCourtCount: Int? = nil, closedRegistrationDate: Date? = nil, groupStageAdditionalQualified: Int = 0, courtCount: Int = 2, prioritizeClubMembers: Bool = false, qualifiedPerGroupStage: Int = 1, teamsPerGroupStage: Int = 4, entryFee: Double? = nil) {
self.event = event
self.creator = creator
self.name = name
self.startDate = startDate
self.endDate = endDate
@ -106,7 +103,6 @@ class Tournament : ModelObject, Storable {
self.federalLevelCategory = federalLevelCategory
self.federalAgeCategory = federalAgeCategory
self.groupStageCourtCount = groupStageCourtCount
self.seedCount = seedCount
self.closedRegistrationDate = closedRegistrationDate
self.groupStageAdditionalQualified = groupStageAdditionalQualified
self.courtCount = courtCount
@ -120,7 +116,6 @@ class Tournament : ModelObject, Storable {
let container = try decoder.container(keyedBy: CodingKeys.self)
id = try container.decode(String.self, forKey: ._id)
event = try container.decodeIfPresent(String.self, forKey: ._event)
creator = try container.decodeIfPresent(String.self, forKey: ._creator)
name = try container.decodeIfPresent(String.self, forKey: ._name)
startDate = try container.decode(Date.self, forKey: ._startDate)
endDate = try container.decodeIfPresent(Date.self, forKey: ._endDate)
@ -139,7 +134,6 @@ class Tournament : ModelObject, Storable {
federalLevelCategory = try container.decode(TournamentLevel.self, forKey: ._federalLevelCategory)
federalAgeCategory = try container.decode(FederalTournamentAge.self, forKey: ._federalAgeCategory)
groupStageCourtCount = try container.decodeIfPresent(Int.self, forKey: ._groupStageCourtCount)
seedCount = try container.decode(Int.self, forKey: ._seedCount)
closedRegistrationDate = try container.decodeIfPresent(Date.self, forKey: ._closedRegistrationDate)
groupStageAdditionalQualified = try container.decode(Int.self, forKey: ._groupStageAdditionalQualified)
courtCount = try container.decode(Int.self, forKey: ._courtCount)
@ -189,7 +183,6 @@ class Tournament : ModelObject, Storable {
try container.encode(id, forKey: ._id)
try container.encodeIfPresent(event, forKey: ._event)
try container.encodeIfPresent(creator, forKey: ._creator)
try container.encodeIfPresent(name, forKey: ._name)
try container.encode(startDate, forKey: ._startDate)
try container.encodeIfPresent(endDate, forKey: ._endDate)
@ -208,7 +201,6 @@ class Tournament : ModelObject, Storable {
try container.encode(federalLevelCategory, forKey: ._federalLevelCategory)
try container.encode(federalAgeCategory, forKey: ._federalAgeCategory)
try container.encodeIfPresent(groupStageCourtCount, forKey: ._groupStageCourtCount)
try container.encode(seedCount, forKey: ._seedCount)
try container.encodeIfPresent(closedRegistrationDate, forKey: ._closedRegistrationDate)
try container.encode(groupStageAdditionalQualified, forKey: ._groupStageAdditionalQualified)
try container.encode(courtCount, forKey: ._courtCount)
@ -512,6 +504,10 @@ class Tournament : ModelObject, Storable {
let groupStages = groupStages()
return groupStages.filter({ $0.hasStarted() && $0.hasEnded() == false }).sorted(by: \.index).first ?? groupStages.first
}
func matchesWithSpace() -> [Match] {
getActiveRound()?.playedMatches().filter({ $0.hasSpaceLeft() }) ?? []
}
func getActiveRound(withSeeds: Bool = false) -> Round? {
let rounds = rounds()
@ -719,7 +715,7 @@ class Tournament : ModelObject, Storable {
var teamsToImport = [TeamRegistration]()
teams.forEach { team in
if let previousTeam = team.previousTeam {
previousTeam.updatePlayers(team.players)
previousTeam.updatePlayers(team.players, inTournamentCategory: team.tournamentCategory)
teamsToImport.append(previousTeam)
} else {
let newTeam = addTeam(team.players, registrationDate: team.registrationDate)
@ -745,7 +741,7 @@ class Tournament : ModelObject, Storable {
let selectedTeams : [TeamRegistration] = selectedSortedTeams()
let callDateIssue : [TeamRegistration] = selectedTeams.filter { $0.callDate != nil && isStartDateIsDifferentThanCallDate($0) }
let duplicates : [PlayerRegistration] = duplicates(in: players)
let problematicPlayers : [PlayerRegistration] = players.filter({ $0.sex == -1 })
let problematicPlayers : [PlayerRegistration] = players.filter({ $0.sex == nil })
let inadequatePlayers : [PlayerRegistration] = inadequatePlayers(in: players)
let playersWithoutValidLicense : [PlayerRegistration] = playersWithoutValidLicense(in: players)
let playersMissing : [TeamRegistration] = selectedTeams.filter({ $0.unsortedPlayers().count < 2 })
@ -851,7 +847,7 @@ class Tournament : ModelObject, Storable {
teams.forEach { team in
let players = team.unsortedPlayers()
players.forEach { $0.setWeight(in: self) }
team.setWeight(from: players)
team.setWeight(from: players, inTournamentCategory: tournamentCategory)
try? DataStore.shared.playerRegistrations.addOrUpdate(contentOfs: players)
}
try? DataStore.shared.teamRegistrations.addOrUpdate(contentOfs: teams)
@ -879,7 +875,7 @@ class Tournament : ModelObject, Storable {
let dataURLs = SourceFileManager.shared.allFiles.filter({ $0.dateFromPath == newDate })
let sources = dataURLs.map { CSVParser(url: $0) }
try await player.updateRank(from: sources, lastRank: (player.sex == 0 ? lastRankWoman : lastRankMan) ?? 0)
try await player.updateRank(from: sources, lastRank: (player.sex == .female ? lastRankWoman : lastRankMan) ?? 0)
}
}
@ -1163,10 +1159,17 @@ class Tournament : ModelObject, Storable {
selectedSortedTeams().firstIndex(where: { $0.id == team.id })
}
func labelIndexOf(team: TeamRegistration) -> String? {
if let teamIndex = indexOf(team: team) {
return "#" + (teamIndex + 1).formatted()
} else {
return nil
}
}
func addTeam(_ players: Set<PlayerRegistration>, registrationDate: Date? = nil) -> TeamRegistration {
let team = TeamRegistration(tournament: id, registrationDate: registrationDate ?? Date())
team.tournamentCategory = tournamentCategory
team.setWeight(from: Array(players))
team.setWeight(from: Array(players), inTournamentCategory: tournamentCategory)
players.forEach { player in
player.teamRegistration = team.id
}
@ -1445,6 +1448,42 @@ fileprivate extension Bool {
}
}
//extension Tournament {
// enum CodingKeys: String, CodingKey {
// case _id = "id"
// case _event = "event"
// case _name = "name"
// case _startDate = "startDate"
// case _endDate = "endDate"
// case _creationDate = "creationDate"
// case _isPrivate = "isPrivate"
// case _groupStageFormat = "groupStageFormat"
// case _roundFormat = "roundFormat"
// case _loserRoundFormat = "loserRoundFormat"
// case _groupStageSortMode = "groupStageSortMode"
// case _groupStageCount = "groupStageCount"
// case _rankSourceDate = "rankSourceDate"
// case _dayDuration = "dayDuration"
// case _teamCount = "teamCount"
// case _teamSorting = "teamSorting"
// case _federalCategory = "federalCategory"
// case _federalLevelCategory = "federalLevelCategory"
// case _federalAgeCategory = "federalAgeCategory"
// case _groupStageCourtCount = "groupStageCourtCount"
// case _closedRegistrationDate = "closedRegistrationDate"
// case _groupStageAdditionalQualified = "groupStageAdditionalQualified"
// case _courtCount = "courtCount"
// case _prioritizeClubMembers = "prioritizeClubMembers"
// case _qualifiedPerGroupStage = "qualifiedPerGroupStage"
// case _teamsPerGroupStage = "teamsPerGroupStage"
// case _entryFee = "entryFee"
// case _additionalEstimationDuration = "additionalEstimationDuration"
// case _isDeleted = "isDeleted"
// case _isCanceled = "localId"
// case _payment = "globalId"
// }
//}
extension Tournament: Hashable {
static func == (lhs: Tournament, rhs: Tournament) -> Bool {
lhs.id == rhs.id
@ -1504,12 +1543,12 @@ extension Tournament {
let tournamentLevel = TournamentLevel.mostUsed(inTournaments: tournaments)
let tournamentCategory = TournamentCategory.mostUsed(inTournaments: tournaments)
let federalTournamentAge = FederalTournamentAge.mostUsed(inTournaments: tournaments)
return Tournament(creator: DataStore.shared.user?.id, groupStageSortMode: .snake, rankSourceDate: rankSourceDate, teamSorting: tournamentLevel.defaultTeamSortingType, federalCategory: tournamentCategory, federalLevelCategory: tournamentLevel, federalAgeCategory: federalTournamentAge)
//creator: DataStore.shared.user?.id
return Tournament(groupStageSortMode: .snake, rankSourceDate: rankSourceDate, teamSorting: tournamentLevel.defaultTeamSortingType, federalCategory: tournamentCategory, federalLevelCategory: tournamentLevel, federalAgeCategory: federalTournamentAge)
}
static func fake() -> Tournament {
return Tournament(event: "Roland Garros", creator: "", name: "Magic P100", startDate: Date(), endDate: Date(), creationDate: Date(), isPrivate: false, groupStageFormat: .nineGames, roundFormat: nil, loserRoundFormat: nil, groupStageSortMode: .snake, groupStageCount: 4, rankSourceDate: nil, dayDuration: 2, teamCount: 24, teamSorting: .rank, federalCategory: .men, federalLevelCategory: .p100, federalAgeCategory: .a45, groupStageCourtCount: nil, seedCount: 8, closedRegistrationDate: nil, groupStageAdditionalQualified: 0, courtCount: 4, prioritizeClubMembers: false, qualifiedPerGroupStage: 2, teamsPerGroupStage: 4, entryFee: nil)
return Tournament(event: "Roland Garros", name: "Magic P100", startDate: Date(), endDate: Date(), creationDate: Date(), isPrivate: false, groupStageFormat: .nineGames, roundFormat: nil, loserRoundFormat: nil, groupStageSortMode: .snake, groupStageCount: 4, rankSourceDate: nil, dayDuration: 2, teamCount: 24, teamSorting: .rank, federalCategory: .men, federalLevelCategory: .p100, federalAgeCategory: .a45, groupStageCourtCount: nil, closedRegistrationDate: nil, groupStageAdditionalQualified: 0, courtCount: 4, prioritizeClubMembers: false, qualifiedPerGroupStage: 2, teamsPerGroupStage: 4, entryFee: nil)
}
}

@ -7,7 +7,12 @@
import Foundation
// MARK: - Trimming and stuff
extension String {
func trunc(length: Int, trailing: String = "") -> String {
return (self.count > length) ? self.prefix(length) + trailing : self
}
var trimmed: String {
trimmingCharacters(in: .whitespacesAndNewlines)
}
@ -29,6 +34,7 @@ extension String {
}
}
// MARK: - Club Name
extension String {
func acronym() -> String {
let acronym = canonicalVersion.replaceCharactersFromSet(characterSet: .whitespacesAndNewlines)
@ -58,16 +64,8 @@ extension String {
}
}
// MARK: - FFT License
extension String {
enum RegexStatic {
static let mobileNumber = /^0[6-7]/
//static let mobileNumber = /^(?:(?:\+|00)33[\s.-]{0,3}(?:\(0\)[\s.-]{0,3})?|0)[1-9](?:(?:[\s.-]?\d{2}){4}|\d{2}(?:[\s.-]?\d{3}){2})$/
}
func isMobileNumber() -> Bool {
firstMatch(of: RegexStatic.mobileNumber) != nil
}
var computedLicense: String {
if let licenseKey {
return self + licenseKey
@ -138,20 +136,24 @@ extension String {
}
return nil
}
}
extension String {
func licencesFound() -> [String] {
let matches = self.matches(of: /[1-9][0-9]{5,7}/)
return matches.map { String(self[$0.range]) }
}
}
extension LosslessStringConvertible {
var string: String { .init(self) }
}
// MARK: - FFT Source Importing
extension String {
enum RegexStatic {
static let mobileNumber = /^0[6-7]/
//static let mobileNumber = /^(?:(?:\+|00)33[\s.-]{0,3}(?:\(0\)[\s.-]{0,3})?|0)[1-9](?:(?:[\s.-]?\d{2}){4}|\d{2}(?:[\s.-]?\d{3}){2})$/
}
func isMobileNumber() -> Bool {
firstMatch(of: RegexStatic.mobileNumber) != nil
}
//april 04-2024 bug with accent characters / adobe / fft
mutating func replace(characters: [(Character, Character)]) {
for (targetChar, replacementChar) in characters {
@ -160,7 +162,13 @@ extension String {
}
}
// MARK: - Player Names
extension StringProtocol {
var firstUppercased: String { prefix(1).uppercased() + dropFirst() }
var firstCapitalized: String { prefix(1).capitalized + dropFirst() }
}
// MARK: - todo clean up ??
extension LosslessStringConvertible {
var string: String { .init(self) }
}

@ -18,5 +18,7 @@
</array>
</dict>
</array>
<key>ITSAppUsesNonExemptEncryption</key>
<false/>
</dict>
</plist>

@ -638,6 +638,17 @@ enum TournamentCategory: Int, Hashable, Codable, CaseIterable, Identifiable {
self.init(rawValue: value)
}
func mandatoryPlayerType() -> [Int] {
switch self {
case .mix:
return [0, 1]
case .women:
return [0, 0]
case .men:
return [1, 1]
}
}
var localizedPlayerLabel: String {
switch self {
case .women:

@ -53,7 +53,7 @@ enum AgendaDestination: CaseIterable, Identifiable, Selectable {
case .history:
DataStore.shared.tournaments.filter { $0.endDate != nil && FederalDataViewModel.shared.isTournamentValidForFilters($0) }.count
case .tenup:
FederalDataViewModel.shared.filteredFederalTournaments.count
FederalDataViewModel.shared.filteredFederalTournaments.map { $0.tournaments.count }.reduce(0,+)
}
}
@ -61,6 +61,8 @@ enum AgendaDestination: CaseIterable, Identifiable, Selectable {
switch self {
case .history:
return .green
case .tenup:
return .logoBackground
default:
return nil
}

@ -42,8 +42,8 @@ struct CashierDetailView: View {
private func _tournamentCashierDetailView(_ tournament: Tournament) -> some View {
DisclosureGroup {
ForEach(PlayerRegistration.PaymentType.allCases) { type in
let count = tournament.selectedPlayers().filter({ $0.registrationType == type }).count
ForEach(PlayerRegistration.PlayerPaymentType.allCases) { type in
let count = tournament.selectedPlayers().filter({ $0.paymentType == type }).count
LabeledContent {
if let entryFee = tournament.entryFee {
let sum = Double(count) * entryFee

@ -26,7 +26,7 @@ struct CashierSettingsView: View {
let players = tournaments.flatMap({ $0.selectedPlayers() })
players.forEach { player in
if player.hasPaid() == false {
player.registrationType = .gift
player.paymentType = .gift
}
}
try? dataStore.playerRegistrations.addOrUpdate(contentOfs: players)
@ -39,7 +39,7 @@ struct CashierSettingsView: View {
RowButtonView("Personne n'a réglé", role: .destructive) {
let players = tournaments.flatMap({ $0.selectedPlayers() })
players.forEach { player in
player.registrationType = nil
player.paymentType = nil
}
try? dataStore.playerRegistrations.addOrUpdate(contentOfs: players)
}

@ -8,24 +8,35 @@
import SwiftUI
protocol SpinDrawable {
func segmentLabel() -> String
func segmentLabel(_ displayStyle: DisplayStyle) -> [String]
}
extension String: SpinDrawable {
func segmentLabel() -> String {
self
func segmentLabel(_ displayStyle: DisplayStyle) -> [String] {
[self]
}
}
extension Match: SpinDrawable {
func segmentLabel() -> String {
self.matchTitle(.wide)
func segmentLabel(_ displayStyle: DisplayStyle) -> [String] {
let teams = teams()
if teams.count == 1 {
return teams.first!.segmentLabel(displayStyle)
} else {
return [roundTitle(), matchTitle(displayStyle)].compactMap { $0 }
}
}
}
extension TeamRegistration: SpinDrawable {
func segmentLabel() -> String {
self.teamLabel(.short)
func segmentLabel(_ displayStyle: DisplayStyle) -> [String] {
var strings: [String] = []
let indexLabel = tournamentObject()?.labelIndexOf(team: self)
if let indexLabel {
strings.append(indexLabel)
}
strings.append(contentsOf: self.players().map { $0.playerLabel(displayStyle) })
return strings
}
}
@ -40,15 +51,14 @@ struct DrawOption: Identifiable, SpinDrawable {
let initialIndex: Int
let option: SpinDrawable
func segmentLabel() -> String {
option.segmentLabel()
func segmentLabel(_ displayStyle: DisplayStyle) -> [String] {
option.segmentLabel(displayStyle)
}
}
struct SpinDrawView: View {
@Environment(\.dismiss) private var dismiss
let time: Date = Date()
let drawees: [any SpinDrawable]
@State var segments: [any SpinDrawable]
let completion: ([DrawResult]) -> Void // Completion closure
@ -56,29 +66,20 @@ struct SpinDrawView: View {
@State private var drawCount: Int = 0
@State private var draws: [DrawResult] = [DrawResult]()
@State private var drawOptions: [DrawOption] = [DrawOption]()
@State private var selectedIndex: Int?
var autoMode: Bool {
drawees.count > 1
}
func validationLabel(drawee: Int, result: SpinDrawable) -> String {
let draw = drawees[drawee]
return draw.segmentLabel() + " -> " + result.segmentLabel()
}
@State private var selectedIndex: Int?
var body: some View {
List {
Section {
Text(time.formatted(date: .complete, time: .complete))
Text(time, style: .timer)
}
if selectedIndex != nil {
Section {
Text(validationLabel(drawee: drawCount, result: segments[draws.last!.drawIndex]))
_validationLabelView(drawee: drawCount, result: segments[draws.last!.drawIndex])
if autoMode == false || drawCount == drawees.count {
RowButtonView("ok") {
RowButtonView("Valider le tirage") {
completion(draws)
dismiss()
}
} else {
@ -87,15 +88,15 @@ struct SpinDrawView: View {
}
} else if drawCount < drawees.count {
Section {
Text(drawees[drawCount].segmentLabel())
_segmentLabelView(segment: drawees[drawCount].segmentLabel(.wide), horizontalAlignment: .center)
}
Section {
FortuneWheelTestView(segments: drawOptions, autoMode: autoMode) { index in
FortuneWheelContainerView(segments: drawOptions, autoMode: autoMode) { index in
self.selectedIndex = index
self.draws.append(DrawResult(drawee: drawCount, drawIndex: drawOptions[index].initialIndex))
self.drawOptions.remove(at: index)
if autoMode && drawCount < drawees.count {
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
self.drawCount += 1
@ -117,7 +118,7 @@ struct SpinDrawView: View {
Section {
Text("Tous les tirages sont terminés")
ForEach(draws) { drawResult in
Text(validationLabel(drawee: drawResult.drawee, result: segments[drawResult.drawIndex]))
_validationLabelView(drawee: drawResult.drawee, result: segments[drawResult.drawIndex])
}
}
@ -135,6 +136,18 @@ struct SpinDrawView: View {
Text("Comité du tournoi")
}
}
.toolbar {
ToolbarItem(placement: .cancellationAction) {
Button("Annuler", role: .cancel) {
dismiss()
}
}
}
.navigationBarBackButtonHidden()
.navigationTitle("Tirage au sort")
.navigationBarTitleDisplayMode(.inline)
.toolbarBackground(.visible, for: .navigationBar)
.toolbar(.hidden, for: .tabBar)
.listStyle(.insetGrouped)
.scrollDisabled(true)
.onAppear {
@ -143,9 +156,29 @@ struct SpinDrawView: View {
}
}
}
private func _segmentLabelView(segment: [String], horizontalAlignment: HorizontalAlignment = .leading) -> some View {
VStack(alignment: horizontalAlignment, spacing: 0.0) {
ForEach(segment, id: \.self) { string in
Text(string)
.frame(maxWidth: .infinity)
}
}
}
@ViewBuilder
private func _validationLabelView(drawee: Int, result: SpinDrawable) -> some View {
HStack(spacing: 0.0) {
let draw = drawees[drawee]
_segmentLabelView(segment: draw.segmentLabel(.wide), horizontalAlignment: .leading)
Image(systemName: "arrowshape.forward.fill")
_segmentLabelView(segment: result.segmentLabel(.wide), horizontalAlignment: .trailing)
}
}
}
struct FortuneWheelTestView: View {
struct FortuneWheelContainerView: View {
@State private var rotation: Double = 0
let segments: [any SpinDrawable]
let autoMode: Bool
@ -162,7 +195,6 @@ struct FortuneWheelTestView: View {
.stroke(Color.black, lineWidth: 2)
.frame(width: 20, height: 20)
.rotationEffect(.degrees(180))
}
.onAppear {
if autoMode {
@ -186,7 +218,6 @@ struct FortuneWheelTestView: View {
}
func rollWheel() {
rotation = 0
// Generate a random angle for the wheel to rotate
@ -249,10 +280,16 @@ struct FortuneWheelView: View {
}
.fill(getColor(forIndex:index))
Text(segments[index].segmentLabel()).multilineTextAlignment(.trailing)
.rotationEffect(.degrees(Double(index) * (360 / Double(segments.count)) + (360 / Double(segments.count) / 2)))
.foregroundColor(.white)
.position(arcPosition(index: index, radius: radius))
VStack(alignment: .trailing, spacing: 0.0) {
let strings = segments[index].segmentLabel(.short)
ForEach(strings, id: \.self) { string in
Text(string).bold()
}
}
.padding(.trailing, 30)
.rotationEffect(.degrees(Double(index) * (360 / Double(segments.count)) + (360 / Double(segments.count) / 2)))
.foregroundColor(.white)
.position(arcPosition(index: index, radius: radius))
}
}
}

@ -22,11 +22,30 @@ struct GroupStageTeamView: View {
}
if groupStage.tournamentObject()?.hasEnded() == false {
Section {
NavigationLink {
GroupStageTeamReplacementView(team: team)
} label: {
Text("Chercher à remplacer")
if team.qualified && team.bracketPosition == nil, let tournament = team.tournamentObject() {
Section {
NavigationLink {
SpinDrawView(drawees: [team], segments: tournament.matchesWithSpace()) { results in
}
} label: {
Text("Tirage au sort visuel")
}
}
Section {
RowButtonView("Tirage au sort automatique", role: .destructive) {
}
}
}
if team.qualified == false {
Section {
NavigationLink {
GroupStageTeamReplacementView(team: team)
} label: {
Text("Chercher à remplacer")
}
}
}
@ -46,11 +65,13 @@ struct GroupStageTeamView: View {
}
}
Section {
RowButtonView("Retirer de la poule", role: .destructive) {
team.groupStagePosition = nil
team.groupStage = nil
_save()
if team.qualified == false {
Section {
RowButtonView("Retirer de la poule", role: .destructive) {
team.groupStagePosition = nil
team.groupStage = nil
_save()
}
}
}
}

@ -12,16 +12,16 @@ struct PlayerPayView: View {
@Bindable var player: PlayerRegistration
var body: some View {
Picker(selection: $player.registrationType) {
Text("Non réglé").tag(nil as PlayerRegistration.PaymentType?)
ForEach(PlayerRegistration.PaymentType.allCases) { type in
Text(type.localizedLabel()).tag(type as PlayerRegistration.PaymentType?)
Picker(selection: $player.paymentType) {
Text("Non réglé").tag(nil as PlayerRegistration.PlayerPaymentType?)
ForEach(PlayerRegistration.PlayerPaymentType.allCases) { type in
Text(type.localizedLabel()).tag(type as PlayerRegistration.PlayerPaymentType?)
}
} label: {
}
.pickerStyle(.menu)
.fixedSize()
.onChange(of: player.registrationType) {
.onChange(of: player.paymentType) {
_save()
}
}

@ -246,7 +246,7 @@ struct PlayerPopoverView: View {
}
func createManualPlayer() {
let playerRegistration = PlayerRegistration(firstName: firstName, lastName: lastName, licenceId: license.trimmed.isEmpty ? nil : license, rank: rank, sex: sex)
let playerRegistration = PlayerRegistration(firstName: firstName, lastName: lastName, licenceId: license.trimmed.isEmpty ? nil : license, rank: rank, sex: PlayerRegistration.PlayerSexType(rawValue: sex))
self.creationCompletionHandler(playerRegistration)
}

@ -17,8 +17,8 @@ struct PlayerSexPickerView: View {
Text(player.playerLabel())
Spacer()
Picker(selection: $player.sex) {
Text("Homme").tag(1 as Int)
Text("Femme").tag(0 as Int)
Text("Homme").tag(PlayerRegistration.PlayerSexType.male)
Text("Femme").tag(PlayerRegistration.PlayerSexType.female)
} label: {
}
@ -35,7 +35,7 @@ struct PlayerSexPickerView: View {
player.setWeight(in: tournament)
try dataStore.playerRegistrations.addOrUpdate(instance: player)
if let team = player.team() {
team.updateWeight()
team.updateWeight(inTournamentCategory: tournament.tournamentCategory)
try dataStore.teamRegistrations.addOrUpdate(instance: team)
}

@ -80,12 +80,12 @@ struct PlayerDetailView: View {
_save()
}
.onChange(of: player.weight) {
player.team()?.updateWeight()
player.team()?.updateWeight(inTournamentCategory: tournament.tournamentCategory)
_save()
}
.onChange(of: player.rank) {
player.setWeight(in: tournament)
player.team()?.updateWeight()
player.team()?.updateWeight(inTournamentCategory: tournament.tournamentCategory)
_save()
}
.headerProminence(.increased)

@ -18,7 +18,9 @@ struct RoundView: View {
List {
let loserRounds = round.loserRounds()
let availableQualifiedTeams = tournament.availableQualifiedTeams()
let displayableMatches = round.displayableMatches()
let spaceLeft = displayableMatches.filter({ $0.hasSpaceLeft() })
if isEditingTournamentSeed.wrappedValue == false {
//(where: { $0.isDisabled() == false || isEditingTournamentSeed.wrappedValue })
if loserRounds.isEmpty == false {
@ -33,6 +35,19 @@ struct RoundView: View {
}
}
}
} else if availableQualifiedTeams.isEmpty == false && spaceLeft.isEmpty == false {
NavigationLink("Tirer au sort la position d'un qualifié") {
SpinDrawView(drawees: availableQualifiedTeams, segments: spaceLeft) { results in
results.forEach { drawResult in
print(availableQualifiedTeams[drawResult.drawee].teamLabel())
print(spaceLeft[drawResult.drawIndex].matchTitle())
availableQualifiedTeams[drawResult.drawee].setSeedPosition(inSpot: spaceLeft[drawResult.drawIndex], slot: nil, opposingSeeding: true)
}
try? dataStore.matches.addOrUpdate(contentOfs: spaceLeft)
try? dataStore.teamRegistrations.addOrUpdate(contentOfs: availableQualifiedTeams)
isEditingTournamentSeed.wrappedValue.toggle()
}
}
} else if let availableSeedGroup = tournament.seedGroupAvailable(atRoundIndex: round.index) {
RowButtonView("Placer \(availableSeedGroup.localizedLabel())" + ((availableSeedGroup.isFixed() == false) ? " au hasard" : "")) {
@ -62,7 +77,7 @@ struct RoundView: View {
}
}
ForEach(round.displayableMatches()) { match in
ForEach(displayableMatches) { match in
Section {
MatchRowView(match: match, matchViewStyle: .sectionedStandardStyle)
} header: {

@ -15,7 +15,7 @@ struct RoundsView: View {
init(tournament: Tournament) {
self.tournament = tournament
_selectedRound = State(wrappedValue: tournament.getActiveRound())
if tournament.availableSeeds().isEmpty == false {
if tournament.availableSeeds().isEmpty == false || tournament.availableQualifiedTeams().isEmpty == false {
_isEditingTournamentSeed = State(wrappedValue: true)
}
}

@ -126,9 +126,13 @@ struct BroadcastView: View {
Label("Partager le lien", systemImage: "link")
}
} label: {
Text("lien")
.underline()
HStack {
Spacer()
Text("lien")
.underline()
}
}
.frame(maxWidth: .infinity)
.buttonStyle(.borderless)
}

@ -20,7 +20,7 @@ struct InscriptionInfoView: View {
var waitingList : [TeamRegistration] { tournament.waitingListTeams(in: selectedTeams) }
var duplicates : [PlayerRegistration] { tournament.duplicates(in: players) }
var problematicPlayers : [PlayerRegistration] { players.filter({ $0.sex == -1 }) }
var problematicPlayers : [PlayerRegistration] { players.filter({ $0.sex == nil }) }
var inadequatePlayers : [PlayerRegistration] { tournament.inadequatePlayers(in: players) }
var playersWithoutValidLicense : [PlayerRegistration] { tournament.playersWithoutValidLicense(in: players) }
var entriesFromBeachPadel : [TeamRegistration] { tournament.unsortedTeams().filter({ $0.isImported() }) }

@ -46,7 +46,7 @@ struct UpdateSourceRankDateView: View {
try dataStore.playerRegistrations.addOrUpdate(contentOfs: tournament.unsortedPlayers())
tournament.unsortedTeams().forEach { team in
team.setWeight(from: team.players())
team.setWeight(from: team.players(), inTournamentCategory: tournament.tournamentCategory)
if forceRefreshLockWeight {
team.lockWeight = team.weight
}

@ -555,7 +555,7 @@ struct InscriptionManagerView: View {
private func _updateTeam() {
guard let editedTeam else { return }
let players = _currentSelection()
editedTeam.updatePlayers(players)
editedTeam.updatePlayers(players, inTournamentCategory: tournament.tournamentCategory)
try? dataStore.teamRegistrations.addOrUpdate(instance: editedTeam)
try? dataStore.playerRegistrations.addOrUpdate(contentOfs: players)
createdPlayers.removeAll()

Loading…
Cancel
Save