club_update
Razmig Sarkissian 1 year ago
parent fd92b3950e
commit 03069d9505
  1. 4
      PadelClub/Data/Tournament.swift
  2. 2
      PadelClub/Utils/URLs.swift
  3. 9
      PadelClub/Views/GroupStage/GroupStageView.swift
  4. 26
      PadelClub/Views/GroupStage/GroupStagesSettingsView.swift
  5. 47
      PadelClub/Views/GroupStage/GroupStagesView.swift
  6. 75
      PadelClub/Views/Navigation/Toolbox/ToolboxView.swift
  7. 45
      PadelClub/Views/Navigation/Umpire/UmpireView.swift
  8. 2
      PadelClub/Views/Tournament/Screen/InscriptionManagerView.swift
  9. 5
      PadelClub/Views/Tournament/TournamentBuildView.swift

@ -1065,7 +1065,7 @@ defer {
if state() == .build && groupStageCount > 0 && groupStageTeams().isEmpty {
setGroupStageTeams(randomize: groupStageSortMode == .random)
setGroupStage(randomize: groupStageSortMode == .random)
}
}
@ -1417,7 +1417,7 @@ defer {
}
func missingQualifiedFromGroupStages() -> [TeamRegistration] {
if groupStageAdditionalQualified > 0 {
if groupStageAdditionalQualified > 0 && groupStagesAreOver() {
return groupStages().filter { $0.hasEnded() }.compactMap { groupStage in
groupStage.teams(true)[safe: qualifiedPerGroupStage]
}

@ -17,7 +17,7 @@ enum URLs: String, Identifiable {
//case padelClub = "https://padelclub.app"
case tenup = "https://tenup.fft.fr"
case padelRules = "https://fft-site.cdn.prismic.io/fft-site/ZgLn3McYqOFdyF7n_LEGUIDEDELACOMPETITIONDEPADEL-MAJDECEMBRE2023.pdf"
case restingDischarge = "https://club.fft.fr/tennisfirmidecazeville/60120370_d/data_1/pdf/fo/formlairededechargederesponsabilitetournoidepadel.pdf"
var id: String { return self.rawValue }
var url: URL {

@ -16,11 +16,9 @@ struct GroupStageView: View {
@Bindable var groupStage: GroupStage
@State private var confirmGroupStageStart: Bool = false
@State private var sortingMode: GroupStageSortingMode
let playedMatches: [Match]
init(groupStage: GroupStage) {
self.groupStage = groupStage
self.playedMatches = groupStage.playedMatches()
_sortingMode = .init(wrappedValue: groupStage.hasEnded() ? .score : .weight)
}
@ -52,6 +50,7 @@ struct GroupStageView: View {
}
.headerProminence(.increased)
let playedMatches = groupStage.playedMatches()
let runningMatches = groupStage.runningMatches(playedMatches: playedMatches)
MatchListView(section: "en cours", matches: groupStage.runningMatches(playedMatches: playedMatches), hideWhenEmpty: true)
let availableToStart = groupStage.availableToStart(playedMatches: playedMatches, in: runningMatches)
@ -59,6 +58,12 @@ struct GroupStageView: View {
.listRowView(isActive: availableToStart.isEmpty == false, color: .green, hideColorVariation: true)
MatchListView(section: "à lancer", matches: groupStage.readyMatches(playedMatches: playedMatches), hideWhenEmpty: true)
MatchListView(section: "terminés", matches: groupStage.finishedMatches(playedMatches: playedMatches), isExpanded: false)
if playedMatches.isEmpty {
RowButtonView("Créer les matchs de poules") {
groupStage.buildMatches()
}
}
}
.toolbar {
ToolbarItem(placement: .topBarTrailing) {

@ -20,32 +20,6 @@ struct GroupStagesSettingsView: View {
var body: some View {
List {
if tournament.groupStageAdditionalQualified > 0 {
let missingQualifiedFromGroupStages = tournament.missingQualifiedFromGroupStages()
Section {
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)
}
}
}
}
.disabled(tournament.moreQualifiedToDraw() == 0 || missingQualifiedFromGroupStages.isEmpty)
} footer: {
if tournament.moreQualifiedToDraw() == 0 {
Text("Aucune équipe supplémentaire à qualifier. Vous pouvez en rajouter en modifier le paramètre dans structure.")
} else if missingQualifiedFromGroupStages.isEmpty {
Text("Aucune équipe supplémentaire à tirer au sort. Attendez la fin des poules.")
}
}
}
if tournament.shouldVerifyGroupStage {
Section {
let issues = tournament.groupStageTeamPlacementIssue()

@ -6,6 +6,7 @@
//
import SwiftUI
import LeStorage
struct GroupStagesView: View {
var tournament: Tournament
@ -16,7 +17,7 @@ struct GroupStagesView: View {
lhs.id == rhs.id
}
case all
case all(Tournament)
case groupStage(GroupStage)
var id: String {
@ -52,8 +53,12 @@ struct GroupStagesView: View {
func badgeImage() -> Badge? {
switch self {
case .all:
return nil
case .all(let tournament):
if tournament.groupStageAdditionalQualified > 0 && tournament.moreQualifiedToDraw() > 0 && tournament.missingQualifiedFromGroupStages().isEmpty == false {
return .custom(systemName: "exclamationmark.circle.fill", color: .logoBackground)
} else {
return nil
}
case .groupStage(let groupStage):
return groupStage.badgeImage()
}
@ -80,7 +85,7 @@ struct GroupStagesView: View {
}
func allDestinations() -> [GroupStageDestination] {
var allDestinations : [GroupStageDestination] = [.all]
var allDestinations : [GroupStageDestination] = [.all(tournament)]
let groupStageDestinations : [GroupStageDestination] = tournament.groupStages().map { GroupStageDestination.groupStage($0) }
allDestinations.append(contentsOf: groupStageDestinations)
return allDestinations
@ -94,6 +99,40 @@ struct GroupStagesView: View {
let finishedMatches = tournament.finishedMatches(allMatches)
List {
if tournament.groupStageAdditionalQualified > 0 {
let missingQualifiedFromGroupStages = tournament.missingQualifiedFromGroupStages()
Section {
let name = "\((tournament.qualifiedPerGroupStage + 1).ordinalFormatted())"
NavigationLink {
SpinDrawView(drawees: ["Qualification d'un \(name) de poule"], segments: missingQualifiedFromGroupStages) { results in
results.forEach { drawResult in
missingQualifiedFromGroupStages[drawResult.drawIndex].qualified = true
do {
try self.tournament.tournamentStore.teamRegistrations.addOrUpdate(instance: missingQualifiedFromGroupStages[drawResult.drawIndex])
} catch {
Logger.error(error)
}
}
}
} label: {
Label {
Text("Qualifier un \(name) de poule par tirage au sort")
} icon: {
Image(systemName: "exclamationmark.circle.fill")
.foregroundStyle(.logoBackground)
}
}
.disabled(tournament.moreQualifiedToDraw() == 0 || missingQualifiedFromGroupStages.isEmpty)
} footer: {
if tournament.moreQualifiedToDraw() == 0 {
Text("Aucune équipe supplémentaire à qualifier. Vous pouvez en rajouter en modifier le paramètre dans structure.")
} else if missingQualifiedFromGroupStages.isEmpty {
Text("Aucune équipe supplémentaire à tirer au sort. Attendez la fin des poules.")
}
}
}
let runningMatches = tournament.runningMatches(allMatches)
MatchListView(section: "en cours", matches: runningMatches, matchViewStyle: .standardStyle, isExpanded: false)
MatchListView(section: "prêt à démarrer", matches: tournament.availableToStart(allMatches, in: runningMatches), matchViewStyle: .standardStyle, isExpanded: false)

@ -14,6 +14,19 @@ struct ToolboxView: View {
@Environment(NavigationViewModel.self) private var navigation: NavigationViewModel
@State private var didResetApiCalls: Bool = false
var lastDataSource: String? {
dataStore.appSettings.lastDataSource
}
var _mostRecentDateAvailable: Date? {
SourceFileManager.shared.mostRecentDateAvailable
}
var _lastDataSourceDate: Date? {
guard let lastDataSource else { return nil }
return URL.importDateFormatter.date(from: lastDataSource)
}
var body: some View {
@Bindable var navigation = navigation
NavigationStack(path: $navigation.toolboxPath) {
@ -27,8 +40,14 @@ struct ToolboxView: View {
}
SupportButtonView(contentIsUnavailable: false)
Link(destination: URLs.main.url) {
Text("Accéder au site Padel Club")
}
.contextMenu {
ShareLink(item: URLs.main.url)
}
}
#if DEBUG
@ -107,45 +126,51 @@ struct ToolboxView: View {
#endif
Section {
Link(destination: URLs.main.url) {
Text("Accéder au site Padel Club")
NavigationLink {
PadelClubView()
} label: {
if let _lastDataSourceDate {
LabeledContent {
Image(systemName: "checkmark.circle.fill")
.foregroundStyle(.green)
} label: {
Text(_lastDataSourceDate.monthYearFormatted)
Text("Classement mensuel utilisé")
}
} else {
LabeledContent {
Image(systemName: "xmark.circle.fill")
.tint(.logoRed)
} label: {
if let _mostRecentDateAvailable {
Text(_mostRecentDateAvailable.monthYearFormatted)
} else {
Text("Aucun")
}
Text("Classement mensuel disponible")
}
}
}
}
Section {
NavigationLink {
SelectablePlayerListView()
} label: {
Label("Rechercher un joueur", systemImage: "person.fill.viewfinder")
}
}
Section {
NavigationLink {
RankCalculatorView()
} label: {
Label("Calculateur de points", systemImage: "scalemass")
}
}
Section {
NavigationLink {
GlobalSettingsView()
} label: {
Label("Formats de jeu par défaut", systemImage: "megaphone")
}
NavigationLink {
DurationSettingsView()
} label: {
Label("Définir les durées moyennes", systemImage: "deskclock")
}
} footer: {
Text("Vous pouvez définir vos propres estimations de durées de match en fonction du format de jeu.")
}
Section {
Link("Accéder au guide de la compétition de la FFT", destination: URLs.padelRules.url)
Link("Accéder au guide de la compétition", destination: URLs.padelRules.url)
Link("Formulaire de décharge des temps de repos", destination: URLs.restingDischarge.url)
} header: {
Text("Documents fédéraux")
}
}
.overlay(alignment: .bottom) {
if didResetApiCalls {

@ -18,19 +18,6 @@ struct UmpireView: View {
@State private var showSubscriptions: Bool = false
// @State var isConnected: Bool = false
var lastDataSource: String? {
dataStore.appSettings.lastDataSource
}
var _mostRecentDateAvailable: Date? {
SourceFileManager.shared.mostRecentDateAvailable
}
var _lastDataSourceDate: Date? {
guard let lastDataSource else { return nil }
return URL.importDateFormatter.date(from: lastDataSource)
}
enum UmpireScreen {
case login
@ -119,32 +106,20 @@ struct UmpireView: View {
Text("Il s'agit des clubs qui sont utilisés pour récupérer les tournois tenup.")
}
Section {
NavigationLink {
PadelClubView()
GlobalSettingsView()
} label: {
if let _lastDataSourceDate {
LabeledContent {
Image(systemName: "checkmark.circle.fill")
.foregroundStyle(.green)
} label: {
Text(_lastDataSourceDate.monthYearFormatted)
Text("Classement mensuel utilisé")
}
} else {
LabeledContent {
Image(systemName: "xmark.circle.fill")
.tint(.logoRed)
} label: {
if let _mostRecentDateAvailable {
Text(_mostRecentDateAvailable.monthYearFormatted)
} else {
Text("Aucun")
}
Text("Classement mensuel disponible")
}
}
Label("Formats de jeu par défaut", systemImage: "megaphone")
}
NavigationLink {
DurationSettingsView()
} label: {
Label("Définir les durées moyennes", systemImage: "deskclock")
}
} footer: {
Text("Vous pouvez définir vos propres estimations de durées de match en fonction du format de jeu.")
}
// Section {

@ -532,7 +532,7 @@ struct InscriptionManagerView: View {
.swipeActions(edge: .trailing, allowsFullSwipe: true) {
_teamDeleteButtonView(team)
}
.listRowView(isActive: true, color: team.initialRoundColor() ?? tournament.cutLabelColor(index: teamIndex, teamCount: selectedSortedTeams.count), hideColorVariation: true)
.listRowView(isActive: true, color: team.initialRoundColor() ?? tournament.cutLabelColor(index: teamIndex, teamCount: filterMode == .waiting ? 0 : selectedSortedTeams.count), hideColorVariation: true)
}
} header: {
if filterMode == .all {

@ -31,7 +31,10 @@ struct TournamentBuildView: View {
}
} label: {
Text("Poules")
if tournament.shouldVerifyGroupStage {
if tournament.groupStagesAreOver(), tournament.moreQualifiedToDraw() > 0 {
let moreQualifiedToDraw = tournament.moreQualifiedToDraw()
Text("Qualifié\(moreQualifiedToDraw.pluralSuffix) sortant\(moreQualifiedToDraw.pluralSuffix) manquant\(moreQualifiedToDraw.pluralSuffix)").foregroundStyle(.logoRed)
} else if tournament.shouldVerifyGroupStage {
Text("Vérifier les poules").foregroundStyle(.logoRed)
} else if let range = groupStageStatus?.1 {
HStack {

Loading…
Cancel
Save