club_update
Razmig Sarkissian 1 year ago
parent fc8c69d224
commit 3647d20b1f
  1. 6
      PadelClub/Data/Club.swift
  2. 7
      PadelClub/Data/Event.swift
  3. 17
      PadelClub/Data/TeamRegistration.swift
  4. 24
      PadelClub/Data/Tournament.swift
  5. 2
      PadelClub/Utils/PadelRule.swift
  6. 105
      PadelClub/Views/GroupStage/Components/GroupStageTeamView.swift
  7. 16
      PadelClub/Views/GroupStage/GroupStageSettingsView.swift
  8. 4
      PadelClub/Views/GroupStage/Shared/GroupStageTeamReplacementView.swift
  9. 1
      PadelClub/Views/Match/Components/MatchTeamDetailView.swift
  10. 2
      PadelClub/Views/Match/MatchDetailView.swift
  11. 6
      PadelClub/Views/Player/Components/EditablePlayerView.swift
  12. 6
      PadelClub/Views/Player/Components/PlayerPayView.swift
  13. 8
      PadelClub/Views/Tournament/FileImportView.swift
  14. 2
      PadelClub/Views/Tournament/Screen/Components/InscriptionInfoView.swift
  15. 128
      PadelClub/Views/Tournament/Screen/InscriptionManagerView.swift

@ -81,7 +81,11 @@ final class Club : ModelObject, Storable, Hashable {
} }
override func deleteDependencies() throws { override func deleteDependencies() throws {
DataStore.shared.courts.deleteDependencies(self.customizedCourts) let customizedCourts = self.customizedCourts
for customizedCourt in customizedCourts {
try customizedCourt.deleteDependencies()
}
DataStore.shared.courts.deleteDependencies(customizedCourts)
} }
enum CodingKeys: String, CodingKey { enum CodingKeys: String, CodingKey {

@ -38,7 +38,12 @@ final class Event: ModelObject, Storable {
} }
DataStore.shared.tournaments.deleteDependencies(tournaments) DataStore.shared.tournaments.deleteDependencies(tournaments)
DataStore.shared.dateIntervals.deleteDependencies(self.courtsUnavailability)
let courtsUnavailabilities = self.courtsUnavailability
for courtsUnavailability in courtsUnavailabilities {
try courtsUnavailability.deleteDependencies()
}
DataStore.shared.dateIntervals.deleteDependencies(courtsUnavailabilities)
} }
// MARK: - Computed dependencies // MARK: - Computed dependencies

@ -72,8 +72,17 @@ final class TeamRegistration: ModelObject, Storable {
// MARK: - // MARK: -
override func deleteDependencies() throws { override func deleteDependencies() throws {
self.tournamentStore.playerRegistrations.deleteDependencies(self.unsortedPlayers()) let unsortedPlayers = unsortedPlayers()
self.tournamentStore.teamScores.deleteDependencies(self.teamScores()) for player in unsortedPlayers {
try player.deleteDependencies()
}
self.tournamentStore.playerRegistrations.deleteDependencies(unsortedPlayers)
let teamScores = teamScores()
for teamScore in teamScores {
try teamScore.deleteDependencies()
}
self.tournamentStore.teamScores.deleteDependencies(teamScores)
} }
func hasArrived(isHere: Bool = false) { func hasArrived(isHere: Bool = false) {
@ -310,10 +319,6 @@ final class TeamRegistration: ModelObject, Storable {
} }
} }
func qualifiedFromGroupStage() -> Bool {
groupStagePosition != nil && bracketPosition != nil
}
typealias TeamRange = (left: TeamRegistration?, right: TeamRegistration?) typealias TeamRange = (left: TeamRegistration?, right: TeamRegistration?)
func replacementRange() -> TeamRange? { func replacementRange() -> TeamRange? {

@ -530,7 +530,7 @@ defer {
func pasteDataForImporting() -> String { func pasteDataForImporting() -> String {
let selectedSortedTeams = selectedSortedTeams() let selectedSortedTeams = selectedSortedTeams()
return (selectedSortedTeams.compactMap { $0.pasteData() } + ["Liste d'attente"] + waitingListTeams(in: selectedSortedTeams).compactMap { $0.pasteData() }).joined(separator: "\n\n") return (selectedSortedTeams.compactMap { $0.pasteData() } + ["Liste d'attente"] + waitingListTeams(in: selectedSortedTeams, includingWalkOuts: true).compactMap { $0.pasteData() }).joined(separator: "\n\n")
} }
func club() -> Club? { func club() -> Club? {
@ -804,12 +804,12 @@ defer {
func sortedTeams() -> [TeamRegistration] { func sortedTeams() -> [TeamRegistration] {
let teams = selectedSortedTeams() let teams = selectedSortedTeams()
return teams + waitingListTeams(in: teams) return teams + waitingListTeams(in: teams, includingWalkOuts: true)
} }
func waitingListSortedTeams() -> [TeamRegistration] { func waitingListSortedTeams() -> [TeamRegistration] {
let teams = selectedSortedTeams() let teams = selectedSortedTeams()
return waitingListTeams(in: teams) return waitingListTeams(in: teams, includingWalkOuts: false)
} }
@ -876,9 +876,15 @@ defer {
return _sortedTeams return _sortedTeams
} }
func waitingListTeams(in teams: [TeamRegistration]) -> [TeamRegistration] { func waitingListTeams(in teams: [TeamRegistration], includingWalkOuts: Bool) -> [TeamRegistration] {
let waitingList = Set(unsortedTeams()).subtracting(teams) let waitingList = Set(unsortedTeams()).subtracting(teams)
return waitingList.filter { $0.walkOut == false }.sorted(using: _defaultSorting(), order: .ascending) + waitingList.filter { $0.walkOut == true }.sorted(using: _defaultSorting(), order: .ascending) let waitings = waitingList.filter { $0.walkOut == false }.sorted(using: _defaultSorting(), order: .ascending)
let walkOuts = waitingList.filter { $0.walkOut == true }.sorted(using: _defaultSorting(), order: .ascending)
if includingWalkOuts {
return waitings + walkOuts
} else {
return waitings
}
} }
func bracketCut(teamCount: Int) -> Int { func bracketCut(teamCount: Int) -> Int {
@ -1062,7 +1068,7 @@ defer {
let inadequatePlayers : [PlayerRegistration] = inadequatePlayers(in: players) let inadequatePlayers : [PlayerRegistration] = inadequatePlayers(in: players)
let playersWithoutValidLicense : [PlayerRegistration] = playersWithoutValidLicense(in: players) let playersWithoutValidLicense : [PlayerRegistration] = playersWithoutValidLicense(in: players)
let playersMissing : [TeamRegistration] = selectedTeams.filter({ $0.unsortedPlayers().count < 2 }) let playersMissing : [TeamRegistration] = selectedTeams.filter({ $0.unsortedPlayers().count < 2 })
let waitingList : [TeamRegistration] = waitingListTeams(in: selectedTeams) let waitingList : [TeamRegistration] = waitingListTeams(in: selectedTeams, includingWalkOuts: true)
let waitingListInBracket = waitingList.filter({ $0.bracketPosition != nil }) let waitingListInBracket = waitingList.filter({ $0.bracketPosition != nil })
let waitingListInGroupStage = waitingList.filter({ $0.groupStage != nil }) let waitingListInGroupStage = waitingList.filter({ $0.groupStage != nil })
@ -1382,7 +1388,7 @@ defer {
} }
func qualifiedTeams() -> [TeamRegistration] { func qualifiedTeams() -> [TeamRegistration] {
return unsortedTeams().filter({ $0.qualifiedFromGroupStage() }) return unsortedTeams().filter({ $0.qualified })
} }
func moreQualifiedToDraw() -> Int { func moreQualifiedToDraw() -> Int {
@ -1392,9 +1398,9 @@ defer {
func missingQualifiedFromGroupStages() -> [TeamRegistration] { func missingQualifiedFromGroupStages() -> [TeamRegistration] {
if groupStageAdditionalQualified > 0 { if groupStageAdditionalQualified > 0 {
return groupStages().filter { $0.hasEnded() }.compactMap { groupStage in return groupStages().filter { $0.hasEnded() }.compactMap { groupStage in
groupStage.teams()[qualifiedPerGroupStage] groupStage.teams(true)[safe: qualifiedPerGroupStage]
} }
.filter({ $0.qualifiedFromGroupStage() == false }) .filter({ $0.qualified == false })
} else { } else {
return [] return []
} }

@ -753,7 +753,7 @@ enum TournamentCategory: Int, Hashable, Codable, CaseIterable, Identifiable {
var importingRawValue: String { var importingRawValue: String {
switch self { switch self {
case .unlisted: case .unlisted:
return "" return "messieurs"
case .men: case .men:
return "messieurs" return "messieurs"
case .women: case .women:

@ -12,8 +12,14 @@ struct GroupStageTeamView: View {
@EnvironmentObject var dataStore: DataStore @EnvironmentObject var dataStore: DataStore
@Environment(Tournament.self) var tournament: Tournament @Environment(Tournament.self) var tournament: Tournament
@EnvironmentObject var networkMonitor: NetworkMonitor
@Environment(\.dismiss) private var dismiss @Environment(\.dismiss) private var dismiss
@State private var contactType: ContactType? = nil
@State private var sentError: ContactManagerError? = nil
@State private var showSubscriptionView: Bool = false
let groupStage: GroupStage let groupStage: GroupStage
var team: TeamRegistration var team: TeamRegistration
@ -21,6 +27,16 @@ struct GroupStageTeamView: View {
return self.tournament.tournamentStore return self.tournament.tournamentStore
} }
var messageSentFailed: Binding<Bool> {
Binding {
sentError != nil
} set: { newValue in
if newValue == false {
sentError = nil
}
}
}
var body: some View { var body: some View {
List { List {
Section { Section {
@ -30,23 +46,6 @@ struct GroupStageTeamView: View {
} }
if groupStage.tournamentObject()?.hasEnded() == false { if groupStage.tournamentObject()?.hasEnded() == false {
// 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 { if team.qualified == false {
Section { Section {
NavigationLink { NavigationLink {
@ -86,10 +85,82 @@ struct GroupStageTeamView: View {
} }
} }
} }
.toolbar {
ToolbarItem(placement: .topBarTrailing) {
MenuWarningView(tournament: tournament, teams: [team], contactType: $contactType)
}
}
.alert("Un problème est survenu", isPresented: messageSentFailed) {
Button("OK") {
}
} message: {
Text(_getErrorMessage())
}
.sheet(item: $contactType) { contactType in
Group {
switch contactType {
case .message(_, let recipients, let body, _):
if Guard.main.paymentForNewTournament() != nil {
MessageComposeView(recipients: recipients, body: body) { result in
switch result {
case .cancelled:
break
case .failed:
self.sentError = .messageFailed
case .sent:
if networkMonitor.connected == false {
self.sentError = .messageNotSent
}
@unknown default:
break
}
}
} else {
SubscriptionView(isPresented: self.$showSubscriptionView, showLackOfPlanMessage: true)
.environment(\.colorScheme, .light)
}
case .mail(_, let recipients, let bccRecipients, let body, let subject, _):
if Guard.main.paymentForNewTournament() != nil {
MailComposeView(recipients: recipients, bccRecipients: bccRecipients, body: body, subject: subject) { result in
switch result {
case .cancelled, .saved:
self.contactType = nil
case .failed:
self.contactType = nil
self.sentError = .mailFailed
case .sent:
if networkMonitor.connected == false {
self.contactType = nil
self.sentError = .mailNotSent
}
@unknown default:
break
}
}
} else {
SubscriptionView(isPresented: self.$showSubscriptionView, showLackOfPlanMessage: true)
.environment(\.colorScheme, .light)
}
}
}
.tint(.master)
}
.toolbarBackground(.visible, for: .navigationBar) .toolbarBackground(.visible, for: .navigationBar)
.navigationTitle("Détail de l'équipe") .navigationTitle("Détail de l'équipe")
} }
private func _getErrorMessage() -> String {
let m1 : String? = (networkMonitor.connected == false ? "L'appareil n'est pas connecté à internet." : nil)
let m2 : String? = (sentError == .mailNotSent ? "Le mail est dans la boîte d'envoi de l'app Mail. Vérifiez son état dans l'app Mail avant d'essayer de le renvoyer." : nil)
let m3 : String? = ((sentError == .messageFailed || sentError == .messageNotSent) ? "Le SMS n'a pas été envoyé" : nil)
let m4 : String? = (sentError == .mailFailed ? "Le mail n'a pas été envoyé" : nil)
let message : String = [m1, m2, m3, m4].compacted().joined(separator: "\n")
return message
}
private func _save() { private func _save() {
do { do {
try tournamentStore.teamRegistrations.addOrUpdate(instance: team) try tournamentStore.teamRegistrations.addOrUpdate(instance: team)

@ -20,6 +20,22 @@ struct GroupStageSettingsView: View {
var body: some View { var body: some View {
List { List {
if tournament.moreQualifiedToDraw() > 0 {
let missingQualifiedFromGroupStages = tournament.missingQualifiedFromGroupStages()
let name = "\((tournament.groupStageAdditionalQualified + 1).ordinalFormatted())"
NavigationLink("Tirage au sort d'un \(name)") {
SpinDrawView(drawees: ["Qualification d'un \(name)"], segments: missingQualifiedFromGroupStages) { results in
results.forEach { drawResult in
missingQualifiedFromGroupStages[drawResult.drawIndex].qualified = true
do {
try self.tournamentStore.teamRegistrations.addOrUpdate(instance: missingQualifiedFromGroupStages[drawResult.drawIndex])
} catch {
Logger.error(error)
}
}
}
}
}
if tournament.shouldVerifyGroupStage { if tournament.shouldVerifyGroupStage {
Section { Section {

@ -89,9 +89,9 @@ struct GroupStageTeamReplacementView: View {
} }
} }
} header: { } header: {
Text("Même position en poule") Text("Même rang dans la liste")
} footer: { } footer: {
Text("Intervalle de poids d'équipe pour que le remplacement n'affecte pas les poules") Text("Intervalle de poids d'équipe pour que le remplacement n'affecte rien")
} }
} }
if let teamRangeExtended { if let teamRangeExtended {

@ -8,6 +8,7 @@
import SwiftUI import SwiftUI
struct MatchTeamDetailView: View { struct MatchTeamDetailView: View {
@EnvironmentObject var tournamentStore: TournamentStore
let match: Match let match: Match
var body: some View { var body: some View {

@ -116,6 +116,7 @@ struct MatchDetailView: View {
ForEach(unpaid) { player in ForEach(unpaid) { player in
LabeledContent { LabeledContent {
PlayerPayView(player: player) PlayerPayView(player: player)
.environmentObject(tournamentStore)
} label: { } label: {
Text(player.playerLabel()) Text(player.playerLabel())
} }
@ -134,6 +135,7 @@ struct MatchDetailView: View {
} }
.sheet(isPresented: $showDetails) { .sheet(isPresented: $showDetails) {
MatchTeamDetailView(match: match).tint(.master) MatchTeamDetailView(match: match).tint(.master)
.environmentObject(tournamentStore)
} }
.sheet(isPresented: self.$showSubscriptionView, content: { .sheet(isPresented: self.$showSubscriptionView, content: {
NavigationStack { NavigationStack {

@ -17,7 +17,7 @@ struct EditablePlayerView: View {
} }
@EnvironmentObject var dataStore: DataStore @EnvironmentObject var dataStore: DataStore
@Environment(Tournament.self) var tournament: Tournament @EnvironmentObject var tournamentStore: TournamentStore
@Bindable var player: PlayerRegistration @Bindable var player: PlayerRegistration
var editingOptions: [PlayerEditingOption] var editingOptions: [PlayerEditingOption]
@ -26,10 +26,6 @@ struct EditablePlayerView: View {
@State private var presentLastNameUpdate: Bool = false @State private var presentLastNameUpdate: Bool = false
@State private var presentFirstNameUpdate: Bool = false @State private var presentFirstNameUpdate: Bool = false
var tournamentStore: TournamentStore {
return self.tournament.tournamentStore
}
var body: some View { var body: some View {
computedPlayerView(player) computedPlayerView(player)
.alert("Numéro de licence", isPresented: $shouldPresentLicenceIdEdition) { .alert("Numéro de licence", isPresented: $shouldPresentLicenceIdEdition) {

@ -11,11 +11,7 @@ import LeStorage
struct PlayerPayView: View { struct PlayerPayView: View {
@Bindable var player: PlayerRegistration @Bindable var player: PlayerRegistration
@Environment(Tournament.self) var tournament: Tournament @EnvironmentObject var tournamentStore: TournamentStore
var tournamentStore: TournamentStore {
return self.tournament.tournamentStore
}
var body: some View { var body: some View {
Picker(selection: $player.paymentType) { Picker(selection: $player.paymentType) {

@ -232,11 +232,11 @@ struct FileImportView: View {
Section { Section {
Text("Aucune équipe \(tournament.tournamentCategory.importingRawValue) détectée mais \(teams.count) équipes sont dans le fichier") Text("Aucune équipe \(tournament.tournamentCategory.importingRawValue) détectée mais \(teams.count) équipes sont dans le fichier")
Picker(selection: $tournament.tournamentCategory) { Picker(selection: $tournament.tournamentCategory) {
ForEach(TournamentCategory.allCases) { category in ForEach([TournamentCategory.men, TournamentCategory.women, TournamentCategory.mix]) { category in
Text(category.importingRawValue).tag(category) Text(category.importingRawValue).tag(category)
} }
} label: { } label: {
Text("Modifier la catégorie du tournoi ?") Text("Modifier la catégorie")
} }
.onChange(of: tournament.tournamentCategory) { .onChange(of: tournament.tournamentCategory) {
_save() _save()
@ -271,13 +271,11 @@ struct FileImportView: View {
let tournamentFilteredTeams = self.filteredTeams(tournament: tournament) let tournamentFilteredTeams = self.filteredTeams(tournament: tournament)
Section { Section {
RowButtonView("Valider") { RowButtonView("Valider les \(tournamentFilteredTeams.count.formatted()) équipe\(tournamentFilteredTeams.count.pluralSuffix)") {
await _validate(tournament: tournament) await _validate(tournament: tournament)
} }
.disabled(validatedTournamentIds.contains(tournament.id)) .disabled(validatedTournamentIds.contains(tournament.id))
} header: { } header: {
Text("\(tournamentFilteredTeams.count.formatted()) équipe\(tournamentFilteredTeams.count.pluralSuffix)")
} footer: {
Text(tournament.tournamentTitle()) Text(tournament.tournamentTitle())
} }
} }

@ -205,7 +205,7 @@ struct InscriptionInfoView: View {
players = tournament.unsortedPlayers() players = tournament.unsortedPlayers()
selectedTeams = tournament.selectedSortedTeams() selectedTeams = tournament.selectedSortedTeams()
callDateIssue = selectedTeams.filter { $0.callDate != nil && tournament.isStartDateIsDifferentThanCallDate($0) } callDateIssue = selectedTeams.filter { $0.callDate != nil && tournament.isStartDateIsDifferentThanCallDate($0) }
waitingList = tournament.waitingListTeams(in: selectedTeams) waitingList = tournament.waitingListTeams(in: selectedTeams, includingWalkOuts: true)
duplicates = tournament.duplicates(in: players) duplicates = tournament.duplicates(in: players)
problematicPlayers = players.filter({ $0.sex == nil }) problematicPlayers = players.filter({ $0.sex == nil })
inadequatePlayers = tournament.inadequatePlayers(in: players) inadequatePlayers = tournament.inadequatePlayers(in: players)

@ -166,7 +166,7 @@ struct InscriptionManagerView: View {
self.tournament.shouldVerifyBracket = true self.tournament.shouldVerifyBracket = true
self.tournament.shouldVerifyGroupStage = true self.tournament.shouldVerifyGroupStage = true
let waitingList = self.tournament.waitingListTeams(in: selectedSortedTeams) let waitingList = self.tournament.waitingListTeams(in: selectedSortedTeams, includingWalkOuts: true)
waitingList.forEach { team in waitingList.forEach { team in
if team.bracketPosition != nil || team.groupStagePosition != nil { if team.bracketPosition != nil || team.groupStagePosition != nil {
team.resetPositions() team.resetPositions()
@ -185,7 +185,6 @@ struct InscriptionManagerView: View {
var body: some View { var body: some View {
VStack(spacing: 0) { VStack(spacing: 0) {
_managementView()
if _isEditingTeam() { if _isEditingTeam() {
_buildingTeamView() _buildingTeamView()
} else if sortedTeams.isEmpty { } else if sortedTeams.isEmpty {
@ -574,7 +573,7 @@ struct InscriptionManagerView: View {
Section { Section {
TeamDetailView(team: team) TeamDetailView(team: team)
} header: { } header: {
TeamHeaderView(team: team, teamIndex: teamIndex, tournament: tournament, teamCount: filterMode == .waiting ? 0 : selectedSortedTeams.count) TeamHeaderView(team: team, teamIndex: filterMode == .waiting ? nil : teamIndex, tournament: tournament, teamCount: filterMode == .waiting ? 0 : selectedSortedTeams.count)
} footer: { } footer: {
_teamFooterView(team) _teamFooterView(team)
} }
@ -586,21 +585,18 @@ struct InscriptionManagerView: View {
.autocorrectionDisabled() .autocorrectionDisabled()
} }
@MainActor @ViewBuilder
private func _managementView() -> some View { private func _managementView() -> some View {
HStack {
Button { Button {
presentPlayerCreation = true presentPlayerSearch = true
} label: { } label: {
HStack(spacing: 4) { Text("Rechercher dans la base fédérale")
Image(systemName: "person.fill.badge.plus")
.resizable()
.scaledToFit()
.frame(width: 20)
Text("Créer")
.font(.headline)
} }
.frame(maxWidth: .infinity)
Button {
presentPlayerCreation = true
} label: {
Text("Créer un non classé / non licencié")
} }
PasteButton(payloadType: String.self) { strings in PasteButton(payloadType: String.self) { strings in
@ -614,25 +610,6 @@ struct InscriptionManagerView: View {
} }
} }
} }
Button {
presentPlayerSearch = true
} label: {
HStack(spacing: 4) {
Image(systemName: "person.fill.viewfinder")
.resizable()
.scaledToFit()
.frame(width: 20)
Text("FFT")
.font(.headline)
}
.frame(maxWidth: .infinity)
}
}
.buttonStyle(.borderedProminent)
.tint(.master)
.fixedSize(horizontal: false, vertical: true)
.padding(16)
} }
@ -690,6 +667,8 @@ struct InscriptionManagerView: View {
} }
} }
_informationView()
Section { Section {
TipView(fileTip) { action in TipView(fileTip) { action in
@ -758,25 +737,36 @@ struct InscriptionManagerView: View {
} }
} }
@ViewBuilder
private func _informationView() -> some View { private func _informationView() -> some View {
Section { Section {
Button {
filterMode = .all
} label: {
LabeledContent { LabeledContent {
Text(unsortedTeamsWithoutWO.count.formatted() + "/" + tournament.teamCount.formatted()).font(.largeTitle) Text(unsortedTeamsWithoutWO.count.formatted() + "/" + tournament.teamCount.formatted())
} label: { } label: {
Text("Paire\(unsortedTeamsWithoutWO.count.pluralSuffix) inscrite\(unsortedTeamsWithoutWO.count.pluralSuffix)") Text("Paire\(unsortedTeamsWithoutWO.count.pluralSuffix) inscrite\(unsortedTeamsWithoutWO.count.pluralSuffix)")
} }
}
.buttonStyle(.plain)
LabeledContent { HStack {
Text(walkoutTeams.count.formatted()).font(.largeTitle) let waiting: Int = max(0, unsortedTeamsWithoutWO.count - tournament.teamCount)
} label: { FooterButtonView("\(waiting.formatted()) équipes en attente\(waiting.pluralSuffix)") {
Text("Forfait\(walkoutTeams.count.pluralSuffix)") filterMode = .waiting
} }
.disabled(filterMode == .waiting)
LabeledContent { Divider()
Text(max(0, unsortedTeamsWithoutWO.count - tournament.teamCount).formatted()).font(.largeTitle)
} label: { let wo = walkoutTeams.count
Text("Attente") FooterButtonView("\(wo.formatted()) équipes forfait\(wo.pluralSuffix)") {
filterMode = .walkOut
} }
.disabled(filterMode == .walkOut)
}
.fixedSize(horizontal: true, vertical: true)
NavigationLink { NavigationLink {
InscriptionInfoView() InscriptionInfoView()
@ -784,7 +774,7 @@ struct InscriptionManagerView: View {
} label: { } label: {
LabeledContent { LabeledContent {
if let registrationIssues { if let registrationIssues {
Text(registrationIssues.formatted()).font(.largeTitle) Text(registrationIssues.formatted())
} else { } else {
ProgressView() ProgressView()
} }
@ -792,7 +782,28 @@ struct InscriptionManagerView: View {
Text("Problèmes détéctés") Text("Problèmes détéctés")
} }
} }
} header: {
Text("Statut des inscriptions")
} footer: {
HStack {
Menu {
_managementView()
} label: {
Text("Complétez votre liste")
} }
Text("ou")
FooterButtonView("Importez un fichier") {
presentImportView = true
}
}
// if filterMode != .all {
// FooterButtonView("tout afficher") {
// filterMode = .all
// }
// }
}
.headerProminence(.increased)
} }
@ViewBuilder @ViewBuilder
@ -1016,6 +1027,31 @@ struct InscriptionManagerView: View {
} }
} }
} }
} header: {
let _currentSelection = _currentSelection()
let selectedSortedTeams = tournament.selectedSortedTeams()
let rank = _currentSelection.map {
$0.computedRank
}.reduce(0, +)
let teamIndex = selectedSortedTeams.firstIndex(where: { $0.weight >= rank }) ?? selectedSortedTeams.count
if _currentSelection.isEmpty == false, tournament.hideWeight() == false, rank > 0 {
HStack(spacing: 16.0) {
VStack(alignment: .leading, spacing: 0) {
Text("Rang").font(.caption)
Text("#" + (teamIndex + 1).formatted())
}
VStack(alignment: .leading, spacing: 0) {
Text("Poids").font(.caption)
Text(rank.formatted())
}
Spacer()
VStack(alignment: .trailing, spacing: 0) {
Text("").font(.caption)
Text(tournament.cutLabel(index: teamIndex, teamCount: selectedSortedTeams.count))
}
}
}
} }
if editedTeam == nil { if editedTeam == nil {
@ -1163,6 +1199,12 @@ struct InscriptionManagerView: View {
private func _teamMenuOptionView(_ team: TeamRegistration) -> some View { private func _teamMenuOptionView(_ team: TeamRegistration) -> some View {
Menu { Menu {
Section { Section {
NavigationLink {
GroupStageTeamReplacementView(team: team)
} label: {
Text("Chercher à remplacer")
}
MenuWarningView(tournament: tournament, teams: [team], contactType: $contactType) MenuWarningView(tournament: tournament, teams: [team], contactType: $contactType)
//Divider() //Divider()
Button("Copier") { Button("Copier") {

Loading…
Cancel
Save