fix a lot of stuff post PBL

sync2
Raz 1 year ago
parent 8ca2193579
commit f691681e94
  1. 8
      PadelClub.xcodeproj/project.pbxproj
  2. 4
      PadelClub/Data/Coredata/ImportedPlayer+Extensions.swift
  3. 1
      PadelClub/Data/Federal/PlayerHolder.swift
  4. 10
      PadelClub/Data/GroupStage.swift
  5. 14
      PadelClub/Data/MatchScheduler.swift
  6. 8
      PadelClub/Data/PlayerRegistration.swift
  7. 1
      PadelClub/Data/TeamRegistration.swift
  8. 22
      PadelClub/Data/Tournament.swift
  9. 22
      PadelClub/Utils/PadelRule.swift
  10. 27
      PadelClub/ViewModel/FederalDataViewModel.swift
  11. 2
      PadelClub/Views/Calling/Components/MenuWarningView.swift
  12. 13
      PadelClub/Views/Cashier/CashierDetailView.swift
  13. 43
      PadelClub/Views/Cashier/CashierSettingsView.swift
  14. 93
      PadelClub/Views/Cashier/CashierView.swift
  15. 12
      PadelClub/Views/Components/FooterButtonView.swift
  16. 4
      PadelClub/Views/GroupStage/Components/GroupStageTeamView.swift
  17. 5
      PadelClub/Views/GroupStage/GroupStageView.swift
  18. 2
      PadelClub/Views/GroupStage/Shared/GroupStageTeamReplacementView.swift
  19. 2
      PadelClub/Views/Match/Components/MatchDateView.swift
  20. 10
      PadelClub/Views/Match/Components/PlayerBlockView.swift
  21. 11
      PadelClub/Views/Match/MatchDetailView.swift
  22. 8
      PadelClub/Views/Navigation/Agenda/CalendarView.swift
  23. 4
      PadelClub/Views/Navigation/Agenda/EventListView.swift
  24. 10
      PadelClub/Views/Navigation/Agenda/TournamentSubscriptionView.swift
  25. 4
      PadelClub/Views/Planning/PlanningSettingsView.swift
  26. 18
      PadelClub/Views/Player/Components/EditablePlayerView.swift
  27. 5
      PadelClub/Views/Shared/ImportedPlayerView.swift
  28. 11
      PadelClub/Views/Team/TeamRowView.swift
  29. 8
      PadelClub/Views/Tournament/Screen/TournamentCashierView.swift
  30. 9
      PadelClub/Views/Tournament/Shared/TournamentCellView.swift
  31. 2
      PadelClub/Views/Tournament/TournamentBuildView.swift

@ -3293,7 +3293,7 @@
CODE_SIGN_ENTITLEMENTS = PadelClub/PadelClub.entitlements; CODE_SIGN_ENTITLEMENTS = PadelClub/PadelClub.entitlements;
CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 4; CURRENT_PROJECT_VERSION = 3;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEFINES_MODULE = YES; DEFINES_MODULE = YES;
DEVELOPMENT_ASSET_PATHS = "\"PadelClub/Preview Content\""; DEVELOPMENT_ASSET_PATHS = "\"PadelClub/Preview Content\"";
@ -3315,7 +3315,7 @@
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
MARKETING_VERSION = 1.0.14; MARKETING_VERSION = 1.0.15;
PRODUCT_BUNDLE_IDENTIFIER = app.padelclub; PRODUCT_BUNDLE_IDENTIFIER = app.padelclub;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = ""; PROVISIONING_PROFILE_SPECIFIER = "";
@ -3335,7 +3335,7 @@
CODE_SIGN_ENTITLEMENTS = PadelClub/PadelClub.entitlements; CODE_SIGN_ENTITLEMENTS = PadelClub/PadelClub.entitlements;
CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 4; CURRENT_PROJECT_VERSION = 3;
DEFINES_MODULE = YES; DEFINES_MODULE = YES;
DEVELOPMENT_ASSET_PATHS = "\"PadelClub/Preview Content\""; DEVELOPMENT_ASSET_PATHS = "\"PadelClub/Preview Content\"";
DEVELOPMENT_TEAM = BQ3Y44M3Q6; DEVELOPMENT_TEAM = BQ3Y44M3Q6;
@ -3356,7 +3356,7 @@
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
MARKETING_VERSION = 1.0.14; MARKETING_VERSION = 1.0.15;
PRODUCT_BUNDLE_IDENTIFIER = app.padelclub; PRODUCT_BUNDLE_IDENTIFIER = app.padelclub;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = ""; PROVISIONING_PROFILE_SPECIFIER = "";

@ -122,6 +122,10 @@ extension ImportedPlayer: PlayerHolder {
func getProgression() -> Int { func getProgression() -> Int {
return Int(progression) return Int(progression)
} }
func getComputedRank() -> Int? {
nil
}
} }
fileprivate extension Int { fileprivate extension Int {

@ -27,6 +27,7 @@ protocol PlayerHolder {
func isNotFromCurrentDate() -> Bool func isNotFromCurrentDate() -> Bool
func getBirthYear() -> Int? func getBirthYear() -> Int?
func getProgression() -> Int func getProgression() -> Int
func getComputedRank() -> Int?
} }
extension PlayerHolder { extension PlayerHolder {

@ -266,11 +266,11 @@ final class GroupStage: ModelObject, Storable {
case 4: case 4:
return [2, 3, 1, 4, 5, 0] return [2, 3, 1, 4, 5, 0]
case 5: case 5:
return [5, 8, 0, 7, 3, 4, 2, 6, 1, 9] // return [5, 8, 0, 7, 3, 4, 2, 6, 1, 9]
// return [3, 5, 8, 2, 6, 7, 1, 9, 4, 0] return [3, 5, 8, 2, 6, 1, 9, 4, 7, 0]
case 6: case 6:
return [1, 7, 13, 11, 3, 6, 10, 2, 8, 12, 5, 4, 9, 14, 0] //return [1, 7, 13, 11, 3, 6, 10, 2, 8, 12, 5, 4, 9, 14, 0]
//return [4, 7, 9, 3, 6, 11, 2, 8, 10, 1, 13, 5, 12, 14, 0] return [4, 7, 9, 3, 6, 11, 2, 8, 10, 1, 13, 5, 12, 14, 0]
default: default:
return [] return []
} }
@ -283,7 +283,7 @@ final class GroupStage: ModelObject, Storable {
func localizedMatchUpLabel(for matchIndex: Int) -> String { func localizedMatchUpLabel(for matchIndex: Int) -> String {
let matchUp = _matchUp(for: matchIndex) let matchUp = _matchUp(for: matchIndex)
if let index = matchUp.first, let index2 = matchUp.last { if let index = matchUp.first, let index2 = matchUp.last {
return "#\(index + 1) contre #\(index2 + 1)" return "#\(index + 1) vs #\(index2 + 1)"
} else { } else {
return "--" return "--"
} }

@ -199,11 +199,11 @@ final class MatchScheduler : ModelObject, Storable {
while slots.count < flattenedMatches.count { while slots.count < flattenedMatches.count {
teamsPerRotation[rotationIndex] = [] teamsPerRotation[rotationIndex] = []
freeCourtPerRotation[rotationIndex] = [] freeCourtPerRotation[rotationIndex] = []
let previousRotationBracketIndexes = slots.filter { $0.rotationIndex == rotationIndex - 1 }.map { ($0.groupIndex, 1) } (0..<numberOfCourtsAvailablePerRotation).forEach { courtIndex in
//print(mt.map { ($0.bracket!.index.intValue, counts[$0.bracket!.index.intValue]) })
let previousRotationBracketIndexes = slots.map { ($0.groupIndex, 1) }
let counts = Dictionary(previousRotationBracketIndexes, uniquingKeysWith: +) let counts = Dictionary(previousRotationBracketIndexes, uniquingKeysWith: +)
var rotationMatches = Array(availableMatchs.filter({ match in var rotationMatches = Array(availableMatchs)
teamsPerRotation[rotationIndex]!.allSatisfy({ match.containsTeamId($0) == false }) == true
}).prefix(numberOfCourtsAvailablePerRotation))
if rotationIndex > 0 { if rotationIndex > 0 {
rotationMatches = rotationMatches.sorted(by: { rotationMatches = rotationMatches.sorted(by: {
@ -215,15 +215,13 @@ final class MatchScheduler : ModelObject, Storable {
}) })
} }
(0..<numberOfCourtsAvailablePerRotation).forEach { courtIndex in
//print(mt.map { ($0.bracket!.index.intValue, counts[$0.bracket!.index.intValue]) })
if let first = rotationMatches.first(where: { match in if let first = rotationMatches.first(where: { match in
let estimatedDuration = match.matchFormat.getEstimatedDuration(additionalEstimationDuration) let estimatedDuration = match.matchFormat.getEstimatedDuration(additionalEstimationDuration)
let timeIntervalToAdd = (Double(rotationIndex)) * Double(estimatedDuration) * 60 let timeIntervalToAdd = (Double(rotationIndex)) * Double(estimatedDuration) * 60
let rotationStartDate: Date = startingDate.addingTimeInterval(timeIntervalToAdd) let rotationStartDate: Date = startingDate.addingTimeInterval(timeIntervalToAdd)
let courtsUnavailable = courtsUnavailable(startDate: rotationStartDate, duration: match.matchFormat.getEstimatedDuration(additionalEstimationDuration), courtsUnavailability: courtsUnavailability) let courtsUnavailable = courtsUnavailable(startDate: rotationStartDate, duration: match.matchFormat.getEstimatedDuration(additionalEstimationDuration), courtsUnavailability: courtsUnavailability)
if courtIndex >= numberOfCourtsAvailablePerRotation - courtsUnavailable.count { if courtsUnavailable.contains(courtIndex) {
return false return false
} else { } else {
return teamsPerRotation[rotationIndex]!.allSatisfy({ match.containsTeamId($0) == false }) == true return teamsPerRotation[rotationIndex]!.allSatisfy({ match.containsTeamId($0) == false }) == true
@ -486,7 +484,7 @@ final class MatchScheduler : ModelObject, Storable {
let roundObject = match.roundObject! let roundObject = match.roundObject!
let courtsUnavailable = courtsUnavailable(startDate: rotationStartDate, duration: match.matchFormat.getEstimatedDuration(additionalEstimationDuration), courtsUnavailability: courtsUnavailability) let courtsUnavailable = courtsUnavailable(startDate: rotationStartDate, duration: match.matchFormat.getEstimatedDuration(additionalEstimationDuration), courtsUnavailability: courtsUnavailability)
print("courtsUnavailable \(courtsUnavailable)") print("courtsUnavailable \(courtsUnavailable)")
if courtPosition >= availableCourts - courtsUnavailable.count { if courtsUnavailable.contains(courtPosition) {
return false return false
} }

@ -221,10 +221,6 @@ final class PlayerRegistration: ModelObject, Storable {
} }
} }
func getRank() -> Int {
computedRank
}
@MainActor @MainActor
func updateRank(from sources: [CSVParser], lastRank: Int) async throws { func updateRank(from sources: [CSVParser], lastRank: Int) async throws {
if let dataFound = try await history(from: sources) { if let dataFound = try await history(from: sources) {
@ -586,4 +582,8 @@ extension PlayerRegistration: PlayerHolder {
func getProgression() -> Int { func getProgression() -> Int {
0 0
} }
func getComputedRank() -> Int? {
computedRank
}
} }

@ -208,6 +208,7 @@ final class TeamRegistration: ModelObject, Storable {
} }
func teamLabel(_ displayStyle: DisplayStyle = .wide, twoLines: Bool = false) -> String { func teamLabel(_ displayStyle: DisplayStyle = .wide, twoLines: Bool = false) -> String {
if let name { return name }
return players().map { $0.playerLabel(displayStyle) }.joined(separator: twoLines ? "\n" : " & ") return players().map { $0.playerLabel(displayStyle) }.joined(separator: twoLines ? "\n" : " & ")
} }

@ -1522,13 +1522,27 @@ defer {
return Double(selectedPlayers.filter { $0.hasPaid() }.count) / Double(selectedPlayers.count) return Double(selectedPlayers.filter { $0.hasPaid() }.count) / Double(selectedPlayers.count)
} }
func presenceStatus() -> Double {
let selectedPlayers = selectedPlayers()
if selectedPlayers.isEmpty { return 0 }
return Double(selectedPlayers.filter { $0.hasArrived }.count) / Double(selectedPlayers.count)
}
typealias TournamentStatus = (label:String, completion: String) typealias TournamentStatus = (label:String, completion: String)
func cashierStatus() async -> TournamentStatus { func cashierStatus() async -> TournamentStatus {
let selectedPlayers = selectedPlayers() let selectedPlayers = selectedPlayers()
let paid = selectedPlayers.filter({ $0.hasPaid() }) var filteredPlayers = [PlayerRegistration]()
var wording = ""
if isFree() {
wording = "présent"
filteredPlayers = selectedPlayers.filter({ $0.hasArrived })
} else {
wording = "encaissé"
filteredPlayers = selectedPlayers.filter({ $0.hasPaid() })
}
// let label = paid.count.formatted() + " / " + selectedPlayers.count.formatted() + " joueurs encaissés" // let label = paid.count.formatted() + " / " + selectedPlayers.count.formatted() + " joueurs encaissés"
let label = "\(paid.count.formatted()) / \(selectedPlayers.count.formatted()) joueurs encaissés" let label = "\(filteredPlayers.count.formatted()) / \(selectedPlayers.count.formatted()) joueurs \(wording)\(filteredPlayers.count.pluralSuffix)"
let completion = (Double(paid.count) / Double(selectedPlayers.count)) let completion = (Double(filteredPlayers.count) / Double(selectedPlayers.count))
let completionLabel = completion.isNaN ? "" : completion.formatted(.percent.precision(.fractionLength(0))) let completionLabel = completion.isNaN ? "" : completion.formatted(.percent.precision(.fractionLength(0)))
return TournamentStatus(label: label, completion: completionLabel) return TournamentStatus(label: label, completion: completionLabel)
} }
@ -2178,7 +2192,7 @@ extension Tournament: FederalTournamentHolder {
} }
extension Tournament: TournamentBuildHolder { extension Tournament: TournamentBuildHolder {
func buildHolderTitle() -> String { func buildHolderTitle(_ displayStyle: DisplayStyle) -> String {
tournamentTitle(.short) tournamentTitle(.short)
} }

@ -30,7 +30,7 @@ protocol TournamentBuildHolder: Identifiable {
var category: TournamentCategory { get } var category: TournamentCategory { get }
var level: TournamentLevel { get } var level: TournamentLevel { get }
var age: FederalTournamentAge { get } var age: FederalTournamentAge { get }
func buildHolderTitle() -> String func buildHolderTitle(_ displayStyle: DisplayStyle) -> String
} }
struct TournamentBuild: TournamentBuildHolder, Hashable, Codable, Identifiable { struct TournamentBuild: TournamentBuildHolder, Hashable, Codable, Identifiable {
@ -43,29 +43,29 @@ struct TournamentBuild: TournamentBuildHolder, Hashable, Codable, Identifiable {
// var japFirstName: String? = nil // var japFirstName: String? = nil
// var japLastName: String? = nil // var japLastName: String? = nil
func buildHolderTitle() -> String { func buildHolderTitle(_ displayStyle: DisplayStyle) -> String {
computedLabel computedLabel(displayStyle)
} }
var identifier: String { var identifier: String {
level.localizedLevelLabel()+":"+category.localizedLabel()+":"+age.localizedLabel() level.localizedLevelLabel()+":"+category.localizedLabel()+":"+age.localizedLabel()
} }
var computedLabel: String { func computedLabel(_ displayStyle: DisplayStyle = .wide) -> String {
if age == .senior { return localizedLabel() } if age == .senior { return localizedLabel(displayStyle) }
return localizedLabel() + " " + localizedAge return localizedLabel(displayStyle) + " " + localizedAge(displayStyle)
} }
func localizedLabel(_ displayStyle: DisplayStyle = .wide) -> String { func localizedLabel(_ displayStyle: DisplayStyle = .wide) -> String {
level.localizedLevelLabel() + category.localizedLabel(.short) level.localizedLevelLabel(displayStyle) + " " + category.localizedLabel(displayStyle)
} }
var localizedTitle: String { func localizedTitle(_ displayStyle: DisplayStyle = .wide) -> String {
level.localizedLevelLabel() + " " + category.localizedLabel() level.localizedLevelLabel(displayStyle) + " " + category.localizedLabel(displayStyle)
} }
var localizedAge: String { func localizedAge(_ displayStyle: DisplayStyle = .wide) -> String {
age.tournamentDescriptionLabel age.localizedLabel(displayStyle)
} }
} }

@ -97,6 +97,33 @@ class FederalDataViewModel {
}) })
} }
func countForTournamentBuilds(from tournaments: [any FederalTournamentHolder]) -> Int {
tournaments.filter({ tournament in
(selectedClubs.isEmpty || selectedClubs.contains(tournament.codeClub!))
&&
(dayPeriod == .all || (dayPeriod != .all && dayPeriod == tournament.dayPeriod))
&&
(dayDuration == nil || (dayDuration != nil && dayDuration == tournament.dayDuration))
})
.flatMap { $0.tournaments }
.filter {
(levels.isEmpty || levels.contains($0.level))
&&
(categories.isEmpty || categories.contains($0.category))
&&
(ageCategories.isEmpty || ageCategories.contains($0.age))
}
.count
}
func buildIsValid(_ build: any TournamentBuildHolder) -> Bool {
(levels.isEmpty || levels.contains(build.level))
&&
(categories.isEmpty || categories.contains(build.category))
&&
(ageCategories.isEmpty || ageCategories.contains(build.age))
}
func isTournamentValidForFilters(_ tournament: Tournament) -> Bool { func isTournamentValidForFilters(_ tournament: Tournament) -> Bool {
if tournament.isDeleted { return false } if tournament.isDeleted { return false }
let firstPart = (levels.isEmpty || levels.contains(tournament.level)) let firstPart = (levels.isEmpty || levels.contains(tournament.level))

@ -124,7 +124,7 @@ struct MenuWarningView: View {
@ViewBuilder @ViewBuilder
func _teamActionView(_ team: TeamRegistration) -> some View { func _teamActionView(_ team: TeamRegistration) -> some View {
Menu("Toute l'équipe") { Menu(team.name ?? "Toute l'équipe") {
let players = team.players() let players = team.players()
_actionView(players: players) _actionView(players: players)
} }

@ -89,6 +89,7 @@ struct CashierDetailView: View {
let showTournamentTitle: Bool let showTournamentTitle: Bool
@State private var earnings: Double? = nil @State private var earnings: Double? = nil
@State private var paidCompletion: Double? = nil @State private var paidCompletion: Double? = nil
@State private var presence: Double? = nil
var body: some View { var body: some View {
Section { Section {
@ -99,11 +100,17 @@ struct CashierDetailView: View {
ProgressView() ProgressView()
} }
} label: { } label: {
Text("Encaissement") Text(tournament.isFree() ? "Présence" : "Encaissement")
if tournament.isFree() {
if let presence {
Text(presence.formatted(.percent.precision(.fractionLength(0)))).foregroundStyle(.secondary)
}
} else {
if let paidCompletion { if let paidCompletion {
Text(paidCompletion.formatted(.percent.precision(.fractionLength(0)))).foregroundStyle(.secondary) Text(paidCompletion.formatted(.percent.precision(.fractionLength(0)))).foregroundStyle(.secondary)
} }
} }
}
CashierDetailDisclosureView(tournament: tournament) CashierDetailDisclosureView(tournament: tournament)
} header: { } header: {
if showTournamentTitle { if showTournamentTitle {
@ -119,6 +126,10 @@ struct CashierDetailView: View {
if paidCompletion == nil { if paidCompletion == nil {
paidCompletion = tournament.paidCompletion() paidCompletion = tournament.paidCompletion()
} }
if presence == nil {
presence = tournament.presenceStatus()
}
} }
} }
} }

@ -24,6 +24,47 @@ struct CashierSettingsView: View {
var body: some View { var body: some View {
List { List {
Section {
RowButtonView("Tout le monde est arrivé", role: .destructive) {
for tournament in self.tournaments {
let players = tournament.selectedPlayers() // tournaments.flatMap({ $0.selectedPlayers() })
players.forEach { player in
player.hasArrived = true
}
do {
try tournament.tournamentStore.playerRegistrations.addOrUpdate(contentOfs: players)
} catch {
Logger.error(error)
}
}
}
} footer: {
Text("Indique tous les joueurs sont là")
}
Section {
RowButtonView("Personne n'est là", role: .destructive) {
for tournament in self.tournaments {
let players = tournament.selectedPlayers() // tournaments.flatMap({ $0.selectedPlayers() })
players.forEach { player in
player.hasArrived = false
}
do {
try tournament.tournamentStore.playerRegistrations.addOrUpdate(contentOfs: players)
} catch {
Logger.error(error)
}
}
}
} footer: {
Text("Indique qu'aucun joueur n'est arrivé")
}
if tournaments.count > 1 || tournaments.first?.isFree() == false {
Section { Section {
RowButtonView("Tout le monde a réglé", role: .destructive) { RowButtonView("Tout le monde a réglé", role: .destructive) {
@ -65,7 +106,7 @@ struct CashierSettingsView: View {
} footer: { } footer: {
Text("Remet à zéro le type d'encaissement de tous les joueurs") Text("Remet à zéro le type d'encaissement de tous les joueurs")
} }
}
} }
} }
} }

@ -57,6 +57,7 @@ class CashierViewModel: ObservableObject {
let id: UUID = UUID() let id: UUID = UUID()
@Published var sortOption: SortOption = .callDate @Published var sortOption: SortOption = .callDate
@Published var filterOption: FilterOption = .all @Published var filterOption: FilterOption = .all
@Published var presenceFilterOption: PresenceFilterOption = .all
@Published var sortOrder: SortOrder = .ascending @Published var sortOrder: SortOrder = .ascending
@Published var searchText: String = "" @Published var searchText: String = ""
@Published var isSearching: Bool = false @Published var isSearching: Bool = false
@ -69,9 +70,14 @@ class CashierViewModel: ObservableObject {
func _shouldDisplayPlayer(_ player: PlayerRegistration) -> Bool { func _shouldDisplayPlayer(_ player: PlayerRegistration) -> Bool {
if searchText.isEmpty == false { if searchText.isEmpty == false {
sortOption.shouldDisplayPlayer(player) && filterOption.shouldDisplayPlayer(player) && player.contains(searchText) sortOption.shouldDisplayPlayer(player)
&& filterOption.shouldDisplayPlayer(player)
&& presenceFilterOption.shouldDisplayPlayer(player)
&& player.contains(searchText)
} else { } else {
sortOption.shouldDisplayPlayer(player) && filterOption.shouldDisplayPlayer(player) sortOption.shouldDisplayPlayer(player)
&& filterOption.shouldDisplayPlayer(player)
&& presenceFilterOption.shouldDisplayPlayer(player)
} }
} }
@ -183,6 +189,37 @@ class CashierViewModel: ObservableObject {
} }
} }
enum PresenceFilterOption: Int, Identifiable, CaseIterable {
case all
case hasArrived
case hasNotArrived
var id: Int { self.rawValue }
func localizedLabel() -> String {
switch self {
case .all:
return "Tous"
case .hasArrived:
return "Présent"
case .hasNotArrived:
return "Absent"
}
}
func shouldDisplayPlayer(_ player: PlayerRegistration) -> Bool {
switch self {
case .all:
return true
case .hasArrived:
return player.hasArrived
case .hasNotArrived:
return player.hasArrived == false
}
}
}
} }
struct CashierView: View { struct CashierView: View {
@ -201,10 +238,35 @@ struct CashierView: View {
_players = .init(wrappedValue: teams.flatMap({ $0.unsortedPlayers() })) _players = .init(wrappedValue: teams.flatMap({ $0.unsortedPlayers() }))
} }
private func _isFree() -> Bool {
if tournaments.count == 1 {
return tournaments.first?.isFree() == true
} else {
return false
}
}
private func _editingOptions() -> [EditablePlayerView.PlayerEditingOption] {
if _isFree() {
return [.licenceId, .name, .presence]
} else {
return [.licenceId, .name, .payment]
}
}
var body: some View { var body: some View {
List { List {
if cashierViewModel.isSearching == false { if cashierViewModel.isSearching == false {
Section { Section {
Picker(selection: $cashierViewModel.presenceFilterOption) {
ForEach(CashierViewModel.PresenceFilterOption.allCases) { filterOption in
Text(filterOption.localizedLabel()).tag(filterOption)
}
} label: {
Text("Présence")
}
if _isFree() == false {
Picker(selection: $cashierViewModel.filterOption) { Picker(selection: $cashierViewModel.filterOption) {
ForEach(CashierViewModel.FilterOption.allCases) { filterOption in ForEach(CashierViewModel.FilterOption.allCases) { filterOption in
Text(filterOption.localizedLabel()).tag(filterOption) Text(filterOption.localizedLabel()).tag(filterOption)
@ -212,6 +274,7 @@ struct CashierView: View {
} label: { } label: {
Text("Statut du règlement") Text("Statut du règlement")
} }
}
Picker(selection: $cashierViewModel.sortOption) { Picker(selection: $cashierViewModel.sortOption) {
ForEach(CashierViewModel.SortOption.allCases) { sortOption in ForEach(CashierViewModel.SortOption.allCases) { sortOption in
@ -239,12 +302,12 @@ struct CashierView: View {
switch cashierViewModel.sortOption { switch cashierViewModel.sortOption {
case .teamRank: case .teamRank:
TeamRankView(teams: teams, displayTournamentTitle: tournaments.count > 1) TeamRankView(teams: teams, displayTournamentTitle: tournaments.count > 1, editingOptions: _editingOptions())
case .alphabeticalLastName, .alphabeticalFirstName, .playerRank, .age: case .alphabeticalLastName, .alphabeticalFirstName, .playerRank, .age:
PlayerCashierView(players: filteredPlayers, displayTournamentTitle: tournaments.count > 1) PlayerCashierView(players: filteredPlayers, displayTournamentTitle: tournaments.count > 1, editingOptions: _editingOptions())
case .callDate: case .callDate:
let _teams = teams.filter({ $0.callDate != nil }) let _teams = teams.filter({ $0.callDate != nil })
TeamCallDateView(teams: _teams, displayTournamentTitle: tournaments.count > 1) TeamCallDateView(teams: _teams, displayTournamentTitle: tournaments.count > 1, editingOptions: _editingOptions())
} }
} }
.onAppear { .onAppear {
@ -279,11 +342,12 @@ struct CashierView: View {
@EnvironmentObject var cashierViewModel: CashierViewModel @EnvironmentObject var cashierViewModel: CashierViewModel
let players: [PlayerRegistration] let players: [PlayerRegistration]
let displayTournamentTitle: Bool let displayTournamentTitle: Bool
let editingOptions: [EditablePlayerView.PlayerEditingOption]
var body: some View { var body: some View {
ForEach(players) { player in ForEach(players) { player in
Section { Section {
EditablePlayerView(player: player, editingOptions: [.licenceId, .name, .payment]) EditablePlayerView(player: player, editingOptions: editingOptions)
} header: { } header: {
if displayTournamentTitle, let tournamentTitle = player.tournament()?.tournamentTitle() { if displayTournamentTitle, let tournamentTitle = player.tournament()?.tournamentTitle() {
Text(tournamentTitle) Text(tournamentTitle)
@ -301,6 +365,7 @@ struct CashierView: View {
@EnvironmentObject var cashierViewModel: CashierViewModel @EnvironmentObject var cashierViewModel: CashierViewModel
let teams: [TeamRegistration] let teams: [TeamRegistration]
let displayTournamentTitle: Bool let displayTournamentTitle: Bool
let editingOptions: [EditablePlayerView.PlayerEditingOption]
var body: some View { var body: some View {
ForEach(teams) { team in ForEach(teams) { team in
@ -308,12 +373,18 @@ struct CashierView: View {
if players.isEmpty == false { if players.isEmpty == false {
Section { Section {
ForEach(players) { player in ForEach(players) { player in
EditablePlayerView(player: player, editingOptions: [.licenceId, .name, .payment]) EditablePlayerView(player: player, editingOptions: editingOptions)
} }
} header: { } header: {
HStack {
if let name = team.name {
Text(name)
}
if displayTournamentTitle, let tournamentTitle = team.tournamentObject()?.tournamentTitle() { if displayTournamentTitle, let tournamentTitle = team.tournamentObject()?.tournamentTitle() {
Spacer()
Text(tournamentTitle) Text(tournamentTitle)
} }
}
} footer: { } footer: {
if let callDate = team.callDate { if let callDate = team.callDate {
Text("convocation : ") + Text(callDate.localizedDate()) Text("convocation : ") + Text(callDate.localizedDate())
@ -329,6 +400,7 @@ struct CashierView: View {
@EnvironmentObject var cashierViewModel: CashierViewModel @EnvironmentObject var cashierViewModel: CashierViewModel
let teams: [TeamRegistration] let teams: [TeamRegistration]
let displayTournamentTitle: Bool let displayTournamentTitle: Bool
let editingOptions: [EditablePlayerView.PlayerEditingOption]
var body: some View { var body: some View {
let groupedTeams = Dictionary(grouping: teams) { team in let groupedTeams = Dictionary(grouping: teams) { team in
@ -343,10 +415,15 @@ struct CashierView: View {
if players.isEmpty == false { if players.isEmpty == false {
Section { Section {
ForEach(players) { player in ForEach(players) { player in
EditablePlayerView(player: player, editingOptions: [.licenceId, .name, .payment]) EditablePlayerView(player: player, editingOptions: editingOptions)
} }
} header: { } header: {
if let name = team.name {
Text(name)
}
if displayTournamentTitle, let tournamentTitle = team.tournamentObject()?.tournamentTitle() { if displayTournamentTitle, let tournamentTitle = team.tournamentObject()?.tournamentTitle() {
Spacer()
Text(tournamentTitle) Text(tournamentTitle)
} }
} footer: { } footer: {

@ -11,13 +11,15 @@ fileprivate let defaultConfirmationMessage = "Êtes-vous sûr de vouloir faire c
struct FooterButtonView: View { struct FooterButtonView: View {
var role: ButtonRole? = nil var role: ButtonRole? = nil
var systemImage: String? = nil
let title: String let title: String
let confirmationMessage: String let confirmationMessage: String
let action: () -> () let action: () -> ()
@State private var askConfirmation: Bool = false @State private var askConfirmation: Bool = false
init(_ title: String, role: ButtonRole? = nil, confirmationMessage: String? = nil, action: @escaping () -> Void) { init(_ title: String, role: ButtonRole? = nil, systemImage: String? = nil, confirmationMessage: String? = nil, action: @escaping () -> Void) {
self.title = title self.title = title
self.systemImage = systemImage
self.action = action self.action = action
self.role = role self.role = role
self.confirmationMessage = confirmationMessage ?? defaultConfirmationMessage self.confirmationMessage = confirmationMessage ?? defaultConfirmationMessage
@ -31,8 +33,16 @@ struct FooterButtonView: View {
action() action()
} }
} label: { } label: {
if let systemImage {
HStack {
Text(title) Text(title)
.underline() .underline()
Image(systemName: systemImage).font(.caption)
}
} else {
Text(title)
.underline()
}
} }
.buttonStyle(.borderless) .buttonStyle(.borderless)
.confirmationDialog("Confirmation", .confirmationDialog("Confirmation",

@ -40,9 +40,11 @@ struct GroupStageTeamView: View {
var body: some View { var body: some View {
List { List {
Section { Section {
if let name = team.name {
Text(name).foregroundStyle(.secondary)
}
ForEach(team.players()) { player in ForEach(team.players()) { player in
EditablePlayerView(player: player, editingOptions: [.licenceId, .name, .payment]) EditablePlayerView(player: player, editingOptions: [.licenceId, .name, .payment])
.environmentObject(tournament.tournamentStore)
} }
} }

@ -125,8 +125,8 @@ struct GroupStageView: View {
HStack { HStack {
VStack(alignment: .leading) { VStack(alignment: .leading) {
if let teamName = team.name { if let teamName = team.name {
Text(teamName).foregroundStyle(.secondary) Text(teamName).font(.title3)
} } else {
ForEach(team.players()) { player in ForEach(team.players()) { player in
Text(player.playerLabel()).lineLimit(1) Text(player.playerLabel()).lineLimit(1)
.overlay { .overlay {
@ -136,6 +136,7 @@ struct GroupStageView: View {
} }
} }
} }
}
Spacer() Spacer()
if let score = groupStage.scoreLabel(forGroupStagePosition: groupStagePosition, score: scores?.first(where: { $0.team.groupStagePosition == groupStagePosition })) { if let score = groupStage.scoreLabel(forGroupStagePosition: groupStagePosition, score: scores?.first(where: { $0.team.groupStagePosition == groupStagePosition })) {
VStack(alignment: .trailing) { VStack(alignment: .trailing) {

@ -54,7 +54,7 @@ struct GroupStageTeamReplacementView: View {
Section { Section {
Picker(selection: $selectedPlayer) { Picker(selection: $selectedPlayer) {
HStack { HStack {
Text("Toute l'équipe") Text(team.name ?? "Toute l'équipe")
Spacer() Spacer()
Text(team.weight.formatted()).bold() Text(team.weight.formatted()).bold()
} }

@ -93,7 +93,7 @@ struct MatchDateView: View {
.foregroundStyle(Color.master) .foregroundStyle(Color.master)
.underline() .underline()
} else { } else {
Text("en attente") Text("démarrer")
.foregroundStyle(Color.master) .foregroundStyle(Color.master)
.underline() .underline()
} }

@ -57,20 +57,22 @@ struct PlayerBlockView: View {
} }
if let name = team?.name { if let name = team?.name {
Text(name).foregroundStyle(.secondary) Text(name).font(.title3)
} } else {
ForEach(names, id: \.self) { name in ForEach(names, id: \.self) { name in
Text(name).lineLimit(1) Text(name).lineLimit(1)
} }
}
} else { } else {
ZStack(alignment: .leading) { ZStack(alignment: .leading) {
VStack { VStack {
if let name = team?.name { if let name = team?.name {
Text(name).foregroundStyle(.secondary) Text(name).font(.title3)
} } else {
Text("longLabelPlayerOne").lineLimit(1) Text("longLabelPlayerOne").lineLimit(1)
Text("longLabelPlayerTwo").lineLimit(1) Text("longLabelPlayerTwo").lineLimit(1)
} }
}
.opacity(0) .opacity(0)
Text(_defaultLabel()).foregroundStyle(.secondary).lineLimit(1) Text(_defaultLabel()).foregroundStyle(.secondary).lineLimit(1)
} }

@ -107,6 +107,7 @@ struct MatchDetailView: View {
} }
} }
if self.match.currentTournament()?.isFree() == false {
let players = self.match.teams().flatMap { $0.players() } let players = self.match.teams().flatMap { $0.players() }
let unpaid = players.filter({ $0.hasPaid() == false }) let unpaid = players.filter({ $0.hasPaid() == false })
@ -130,7 +131,7 @@ struct MatchDetailView: View {
} }
} }
} }
}
menuView menuView
} }
.sheet(isPresented: $showDetails) { .sheet(isPresented: $showDetails) {
@ -423,9 +424,9 @@ struct MatchDetailView: View {
let rotationDuration = match.getDuration() let rotationDuration = match.getDuration()
Picker(selection: $startDateSetup) { Picker(selection: $startDateSetup) {
if match.isReady() { if match.isReady() {
Text("Tout de suite").tag(MatchDateSetup.now)
Text("Dans 5 minutes").tag(MatchDateSetup.inMinutes(5)) Text("Dans 5 minutes").tag(MatchDateSetup.inMinutes(5))
Text("Dans 15 minutes").tag(MatchDateSetup.inMinutes(15)) Text("Dans 15 minutes").tag(MatchDateSetup.inMinutes(15))
Text("Tout de suite").tag(MatchDateSetup.now)
} }
Text("Précédente rotation").tag(MatchDateSetup.inMinutes(-rotationDuration)) Text("Précédente rotation").tag(MatchDateSetup.inMinutes(-rotationDuration))
Text("Prochaine rotation").tag(MatchDateSetup.inMinutes(rotationDuration)) Text("Prochaine rotation").tag(MatchDateSetup.inMinutes(rotationDuration))
@ -464,11 +465,7 @@ struct MatchDetailView: View {
Text("Au hasard parmi les libres").tag(MatchFieldSetup.random) Text("Au hasard parmi les libres").tag(MatchFieldSetup.random)
Text("Au hasard").tag(MatchFieldSetup.fullRandom) Text("Au hasard").tag(MatchFieldSetup.fullRandom)
//Text("Premier disponible").tag(MatchFieldSetup.firstAvailable) //Text("Premier disponible").tag(MatchFieldSetup.firstAvailable)
if let club = match.currentTournament()?.club() { if let tournament = match.currentTournament() {
ForEach(0..<club.courtCount, id: \.self) { courtIndex in
Text(club.courtName(atIndex: courtIndex)) .tag(MatchFieldSetup.field(courtIndex))
}
} else if let tournament = match.currentTournament() {
ForEach(0..<tournament.courtCount, id: \.self) { courtIndex in ForEach(0..<tournament.courtCount, id: \.self) { courtIndex in
Text(tournament.courtName(atIndex: courtIndex)) .tag(MatchFieldSetup.field(courtIndex)) Text(tournament.courtName(atIndex: courtIndex)) .tag(MatchFieldSetup.field(courtIndex))
} }

@ -93,11 +93,11 @@ struct CalendarView: View {
if federalDataViewModel.isFederalTournamentValidForFilters(tournament, build: build) { if federalDataViewModel.isFederalTournamentValidForFilters(tournament, build: build) {
if navigation.agendaDestination == .around { if navigation.agendaDestination == .around {
NavigationLink(build.buildHolderTitle()) { NavigationLink(build.buildHolderTitle(.wide)) {
TournamentSubscriptionView(federalTournament: tournament, build: build, user: dataStore.user) TournamentSubscriptionView(federalTournament: tournament, build: build, user: dataStore.user)
} }
} else { } else {
Button(build.buildHolderTitle()) { Button(build.buildHolderTitle(.wide)) {
_createOrShow(federalTournament: tournament, existingTournament: event(forTournament: tournament)?.existingBuild(build), build: build) _createOrShow(federalTournament: tournament, existingTournament: event(forTournament: tournament)?.existingBuild(build), build: build)
} }
} }
@ -144,7 +144,9 @@ struct CalendarView: View {
let filteredTournaments = tournaments let filteredTournaments = tournaments
let mappedItems = filteredTournaments.flatMap { tournamentHolder in let mappedItems = filteredTournaments.flatMap { tournamentHolder in
(0..<tournamentHolder.dayDuration).map({ dayDuration in (0..<tournamentHolder.dayDuration).map({ dayDuration in
(tournamentHolder.startDate.dayInt + dayDuration, tournamentHolder.tournaments.count) (tournamentHolder.startDate.dayInt + dayDuration, tournamentHolder.tournaments.filter({ build in
federalDataViewModel.buildIsValid(build)
}).count)
}) })
} }
counts = Dictionary(mappedItems, uniquingKeysWith: +) counts = Dictionary(mappedItems, uniquingKeysWith: +)

@ -33,7 +33,7 @@ struct EventListView: View {
HStack { HStack {
Text(section.monthYearFormatted) Text(section.monthYearFormatted)
Spacer() Spacer()
let count = _tournaments.map { $0.tournaments.count }.reduce(0,+) let count = federalDataViewModel.countForTournamentBuilds(from: _tournaments)
Text("\(count.formatted()) tournoi" + count.pluralSuffix) Text("\(count.formatted()) tournoi" + count.pluralSuffix)
} }
} }
@ -52,7 +52,7 @@ struct EventListView: View {
HStack { HStack {
Text(section.monthYearFormatted) Text(section.monthYearFormatted)
Spacer() Spacer()
let count = _tournaments.map { $0.tournaments.count }.reduce(0,+) let count = federalDataViewModel.countForTournamentBuilds(from: _tournaments)
Text("\(count.formatted()) tournoi" + count.pluralSuffix) Text("\(count.formatted()) tournoi" + count.pluralSuffix)
} }
} }

@ -96,7 +96,7 @@ struct TournamentSubscriptionView: View {
Text(federalTournament.clubLabel()) Text(federalTournament.clubLabel())
} }
LabeledContent("Épreuve") { LabeledContent("Épreuve") {
Text(build.buildHolderTitle()) Text(build.buildHolderTitle(.wide))
} }
LabeledContent("JAP") { LabeledContent("JAP") {
@ -292,24 +292,24 @@ struct TournamentSubscriptionView: View {
var messageBody: String { var messageBody: String {
let bonjourOuBonsoir = Date().timeOfDay.hello let bonjourOuBonsoir = Date().timeOfDay.hello
let bonneSoireeOuBonneJournee = Date().timeOfDay.goodbye let bonneSoireeOuBonneJournee = Date().timeOfDay.goodbye
let body = [["\(bonjourOuBonsoir),\n\nJe souhaiterais inscrire mon équipe au tournoi : ", build.buildHolderTitle(), "du", federalTournament.computedStartDate, "au", federalTournament.clubLabel() + ".\n"].compacted().joined(separator: " "), teamsString, "\nCordialement,\n", user.fullName() ?? bonneSoireeOuBonneJournee, "----------------------------------\nCe message a été préparé grâce à l'application Padel Club !\n\(URLs.appStore.rawValue)"].compactMap { $0 }.joined(separator: "\n") + "\n" let body = [["\(bonjourOuBonsoir),\n\nJe souhaiterais inscrire mon équipe au tournoi : ", build.buildHolderTitle(.wide), "du", federalTournament.computedStartDate, "au", federalTournament.clubLabel() + ".\n"].compacted().joined(separator: " "), teamsString, "\nCordialement,\n", user.fullName() ?? bonneSoireeOuBonneJournee, "----------------------------------\nCe message a été préparé grâce à l'application Padel Club !\n\(URLs.appStore.rawValue)"].compactMap { $0 }.joined(separator: "\n") + "\n"
return body return body
} }
var messageBodyShort: String { var messageBodyShort: String {
let bonjourOuBonsoir = Date().timeOfDay.hello let bonjourOuBonsoir = Date().timeOfDay.hello
let bonneSoireeOuBonneJournee = Date().timeOfDay.goodbye let bonneSoireeOuBonneJournee = Date().timeOfDay.goodbye
let body = [["\(bonjourOuBonsoir),\n\nJe souhaiterais inscrire mon équipe au tournoi : ", build.buildHolderTitle(), "du", federalTournament.computedStartDate, "au", federalTournament.clubLabel() + ".\n"].compacted().joined(separator: " "), teamsString, "\nCordialement,\n", user.fullName() ?? bonneSoireeOuBonneJournee, "----------------------------------\nCe message a été préparé grâce à l'application Padel Club !\n\(URLs.appStore.rawValue)"].compactMap { $0 }.joined(separator: "\n") + "\n" let body = [["\(bonjourOuBonsoir),\n\nJe souhaiterais inscrire mon équipe au tournoi : ", build.buildHolderTitle(.wide), "du", federalTournament.computedStartDate, "au", federalTournament.clubLabel() + ".\n"].compacted().joined(separator: " "), teamsString, "\nCordialement,\n", user.fullName() ?? bonneSoireeOuBonneJournee, "----------------------------------\nCe message a été préparé grâce à l'application Padel Club !\n\(URLs.appStore.rawValue)"].compactMap { $0 }.joined(separator: "\n") + "\n"
return body return body
} }
var noteCalendar: String { var noteCalendar: String {
let body = [[build.buildHolderTitle(), "du", federalTournament.computedStartDate, "au", federalTournament.clubLabel() + ".\n"].compacted().joined(separator: " "), teamsString, federalTournament.calendarNoteMessage()].compactMap { $0 }.joined(separator: "\n") + "\n" let body = [[build.buildHolderTitle(.wide), "du", federalTournament.computedStartDate, "au", federalTournament.clubLabel() + ".\n"].compacted().joined(separator: " "), teamsString, federalTournament.calendarNoteMessage()].compactMap { $0 }.joined(separator: "\n") + "\n"
return body return body
} }
var messageSubject: String { var messageSubject: String {
let subject = [build.buildHolderTitle(), federalTournament.clubLabel()].compacted().joined(separator: " ") let subject = [build.buildHolderTitle(.wide), federalTournament.clubLabel()].compacted().joined(separator: " ")
return subject return subject
} }

@ -240,9 +240,9 @@ struct PlanningSettingsView: View {
let value = tournament.getGroupStageChunkValue() let value = tournament.getGroupStageChunkValue()
if parallelType == false { if parallelType == false {
if value > 1 { if value > 1 {
Text("\(value.formatted()) poules commenceront en parallèle") Text("\(value.formatted()) poules en parallèle")
} else { } else {
Text("une poule sera jouer à la fois") Text("une poule sera jouée à la fois")
} }
} }
} }

@ -14,6 +14,7 @@ struct EditablePlayerView: View {
case payment case payment
case licenceId case licenceId
case name case name
case presence
} }
@EnvironmentObject var dataStore: DataStore @EnvironmentObject var dataStore: DataStore
@ -77,6 +78,13 @@ struct EditablePlayerView: View {
Logger.error(error) Logger.error(error)
} }
} }
.onChange(of: player.hasArrived) {
do {
try self.tournamentStore.playerRegistrations.addOrUpdate(instance: player)
} catch {
Logger.error(error)
}
}
} }
@ViewBuilder @ViewBuilder
@ -91,11 +99,6 @@ struct EditablePlayerView: View {
Menu { Menu {
Button { Button {
player.hasArrived.toggle() player.hasArrived.toggle()
do {
try self.tournamentStore.playerRegistrations.addOrUpdate(instance: player)
} catch {
Logger.error(error)
}
} label: { } label: {
Label("Présent", systemImage: player.hasArrived ? "checkmark.circle" : "circle") Label("Présent", systemImage: player.hasArrived ? "checkmark.circle" : "circle")
} }
@ -172,6 +175,11 @@ struct EditablePlayerView: View {
if editingOptions.contains(.payment) { if editingOptions.contains(.payment) {
Spacer() Spacer()
PlayerPayView(player: player) PlayerPayView(player: player)
} else if editingOptions.contains(.presence) {
Spacer()
FooterButtonView(player.hasArrived ? "Présent" : "Sur place ?", role: player.hasArrived ? nil : .cancel, systemImage: player.hasArrived ? "checkmark" : nil) {
player.hasArrived.toggle()
}
} }
} }
} }

@ -12,6 +12,9 @@ struct ImportedPlayerView: View {
var index: Int? = nil var index: Int? = nil
var showFemaleInMaleAssimilation: Bool = false var showFemaleInMaleAssimilation: Bool = false
var showProgression: Bool = false var showProgression: Bool = false
var isAnimation: Bool {
player.getComputedRank() == 0
}
var body: some View { var body: some View {
VStack(alignment: .leading) { VStack(alignment: .leading) {
@ -39,6 +42,7 @@ struct ImportedPlayerView: View {
} }
.font(.title3) .font(.title3)
.lineLimit(1) .lineLimit(1)
if isAnimation == false {
HStack { HStack {
HStack(alignment: .top, spacing: 0) { HStack(alignment: .top, spacing: 0) {
Text(player.formattedRank()).italic(player.isAssimilated) Text(player.formattedRank()).italic(player.isAssimilated)
@ -109,4 +113,5 @@ struct ImportedPlayerView: View {
} }
} }
} }
}
} }

@ -17,10 +17,6 @@ struct TeamRowView: View {
TeamWeightView(team: team, teamPosition: teamPosition) TeamWeightView(team: team, teamPosition: teamPosition)
} label: { } label: {
VStack(alignment: .leading) { VStack(alignment: .leading) {
if let name = team.name {
Text(name).foregroundStyle(.secondary)
}
if let groupStage = team.groupStageObject() { if let groupStage = team.groupStageObject() {
HStack { HStack {
Text(groupStage.groupStageTitle()) Text(groupStage.groupStageTitle())
@ -32,6 +28,12 @@ struct TeamRowView: View {
Text(round.roundTitle(.wide)) Text(round.roundTitle(.wide))
} }
if let name = team.name {
Text(name).font(.title3)
if team.players().isEmpty {
Text("Aucun joueur")
}
} else {
if team.players().isEmpty == false { if team.players().isEmpty == false {
ForEach(team.players()) { player in ForEach(team.players()) { player in
Text(player.playerLabel()) Text(player.playerLabel())
@ -41,6 +43,7 @@ struct TeamRowView: View {
Text("Place réservée") Text("Place réservée")
} }
} }
}
if displayCallDate { if displayCallDate {
if let callDate = team.callDate { if let callDate = team.callDate {
Text("Déjà convoquée \(callDate.localizedDate())") Text("Déjà convoquée \(callDate.localizedDate())")

@ -54,9 +54,15 @@ enum CashierDestination: Identifiable, Selectable, Equatable {
case .summary: case .summary:
return nil return nil
case .groupStage(let groupStage): case .groupStage(let groupStage):
if groupStage.tournamentObject()?.isFree() == true {
return groupStage.unsortedPlayers().filter({ $0.hasArrived == false }).count
}
return groupStage.unsortedPlayers().filter({ $0.hasPaid() == false }).count return groupStage.unsortedPlayers().filter({ $0.hasPaid() == false }).count
case .bracket(let round): case .bracket(let round):
let playerRegistrations: [PlayerRegistration] = round.seeds().flatMap { $0.unsortedPlayers() } let playerRegistrations: [PlayerRegistration] = round.seeds().flatMap { $0.unsortedPlayers() }
if round.tournamentObject()?.isFree() == true {
return playerRegistrations.filter({ $0.hasArrived == false }).count
}
return playerRegistrations.filter({ $0.hasPaid() == false }).count return playerRegistrations.filter({ $0.hasPaid() == false }).count
case .all(_): case .all(_):
return nil return nil
@ -156,7 +162,7 @@ struct TournamentCashierView: View {
.environmentObject(cashierViewModel) .environmentObject(cashierViewModel)
.navigationBarTitleDisplayMode(.inline) .navigationBarTitleDisplayMode(.inline)
.toolbarBackground(.visible, for: .navigationBar) .toolbarBackground(.visible, for: .navigationBar)
.navigationTitle("Encaissement") .navigationTitle(tournament.isFree() ? "Présence" : "Encaissement")
} }
} }

@ -11,6 +11,7 @@ import LeStorage
struct TournamentCellView: View { struct TournamentCellView: View {
@EnvironmentObject var dataStore: DataStore @EnvironmentObject var dataStore: DataStore
@Environment(NavigationViewModel.self) private var navigation @Environment(NavigationViewModel.self) private var navigation
@Environment(FederalDataViewModel.self) var federalDataViewModel: FederalDataViewModel
let tournament: FederalTournamentHolder let tournament: FederalTournamentHolder
// let color: Color = .black // let color: Color = .black
@ -23,7 +24,9 @@ struct TournamentCellView: View {
var body: some View { var body: some View {
ForEach(tournament.tournaments, id: \.id) { build in ForEach(tournament.tournaments, id: \.id) { build in
if navigation.agendaDestination == .around, let federalTournament = tournament as? FederalTournament { if let federalTournament = tournament as? FederalTournament {
if federalDataViewModel.isFederalTournamentValidForFilters(federalTournament, build: build) {
if navigation.agendaDestination == .around {
NavigationLink { NavigationLink {
TournamentSubscriptionView(federalTournament: federalTournament, build: build, user: dataStore.user) TournamentSubscriptionView(federalTournament: federalTournament, build: build, user: dataStore.user)
} label: { } label: {
@ -33,6 +36,10 @@ struct TournamentCellView: View {
_buildView(build, existingTournament: event?.existingBuild(build)) _buildView(build, existingTournament: event?.existingBuild(build))
} }
} }
} else {
_buildView(build, existingTournament: event?.existingBuild(build))
}
}
} }
var teamCount: Int? { var teamCount: Int? {

@ -185,7 +185,7 @@ struct TournamentBuildView: View {
ProgressView() ProgressView()
} }
} label: { } label: {
Text("Encaissement") Text(tournament.isFree() ? "Présence" : "Encaissement")
if let tournamentStatus { if let tournamentStatus {
Text(tournamentStatus.label).lineLimit(1) Text(tournamentStatus.label).lineLimit(1)
} else { } else {

Loading…
Cancel
Save