diff --git a/PadelClub.xcodeproj/project.pbxproj b/PadelClub.xcodeproj/project.pbxproj index 2745959..b2ab75d 100644 --- a/PadelClub.xcodeproj/project.pbxproj +++ b/PadelClub.xcodeproj/project.pbxproj @@ -653,6 +653,9 @@ FF82CFC52B911F5B00B0CAF2 /* OrganizedTournamentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF82CFC42B911F5B00B0CAF2 /* OrganizedTournamentView.swift */; }; FF82CFC92B9132AF00B0CAF2 /* ActivityView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF82CFC82B9132AF00B0CAF2 /* ActivityView.swift */; }; FF8E1CE62C006E0200184680 /* Alphabet.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF8E1CE52C006E0200184680 /* Alphabet.swift */; }; + FF8E52342DF01D6100099B75 /* EventStatusView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF8E52332DF01D6100099B75 /* EventStatusView.swift */; }; + FF8E52352DF01D6100099B75 /* EventStatusView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF8E52332DF01D6100099B75 /* EventStatusView.swift */; }; + FF8E52362DF01D6100099B75 /* EventStatusView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF8E52332DF01D6100099B75 /* EventStatusView.swift */; }; FF8F263B2BAD528600650388 /* EventCreationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF8F263A2BAD528600650388 /* EventCreationView.swift */; }; FF8F263D2BAD627A00650388 /* TournamentConfiguratorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF8F263C2BAD627A00650388 /* TournamentConfiguratorView.swift */; }; FF8F26412BADFC8700650388 /* TournamentInitView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF8F26402BADFC8700650388 /* TournamentInitView.swift */; }; @@ -1058,6 +1061,7 @@ FF82CFC42B911F5B00B0CAF2 /* OrganizedTournamentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OrganizedTournamentView.swift; sourceTree = ""; }; FF82CFC82B9132AF00B0CAF2 /* ActivityView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivityView.swift; sourceTree = ""; }; FF8E1CE52C006E0200184680 /* Alphabet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Alphabet.swift; sourceTree = ""; }; + FF8E52332DF01D6100099B75 /* EventStatusView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventStatusView.swift; sourceTree = ""; }; FF8F263A2BAD528600650388 /* EventCreationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventCreationView.swift; sourceTree = ""; }; FF8F263C2BAD627A00650388 /* TournamentConfiguratorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TournamentConfiguratorView.swift; sourceTree = ""; }; FF8F26402BADFC8700650388 /* TournamentInitView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TournamentInitView.swift; sourceTree = ""; }; @@ -1843,6 +1847,7 @@ FF8F263A2BAD528600650388 /* EventCreationView.swift */, FFE103072C353B7600684FC9 /* EventClubSettingsView.swift */, FF8F263C2BAD627A00650388 /* TournamentConfiguratorView.swift */, + FF8E52332DF01D6100099B75 /* EventStatusView.swift */, ); name = Event; path = Cashier/Event; @@ -2382,6 +2387,7 @@ FF4C7F022BBBD7150031B6A3 /* TabItemModifier.swift in Sources */, C49772042DC260D3005CD239 /* Round+Extensions.swift in Sources */, FFDDD40C2B93B2BB00C91A49 /* DeferredViewModifier.swift in Sources */, + FF8E52342DF01D6100099B75 /* EventStatusView.swift in Sources */, FFE8B63C2DACEAED00BDE966 /* ConfigurationService.swift in Sources */, FF0E0B6D2BC254C6005F00A9 /* TournamentScheduleView.swift in Sources */, FF025AF12BD1AEBD00A86CF8 /* MatchFormatStorageView.swift in Sources */, @@ -2644,6 +2650,7 @@ FF4CBFF82C996C0600151637 /* TabItemModifier.swift in Sources */, FF4CBFF92C996C0600151637 /* DeferredViewModifier.swift in Sources */, FF4CBFFA2C996C0600151637 /* TournamentScheduleView.swift in Sources */, + FF8E52362DF01D6100099B75 /* EventStatusView.swift in Sources */, FF4CBFFB2C996C0600151637 /* MatchFormatStorageView.swift in Sources */, FF4CBFFC2C996C0600151637 /* UmpireView.swift in Sources */, FF4CBFFE2C996C0600151637 /* MatchSummaryView.swift in Sources */, @@ -2884,6 +2891,7 @@ FF70FB772C90584900129CC2 /* TabItemModifier.swift in Sources */, FF70FB782C90584900129CC2 /* DeferredViewModifier.swift in Sources */, FF70FB792C90584900129CC2 /* TournamentScheduleView.swift in Sources */, + FF8E52352DF01D6100099B75 /* EventStatusView.swift in Sources */, FF70FB7A2C90584900129CC2 /* MatchFormatStorageView.swift in Sources */, FF70FB7B2C90584900129CC2 /* UmpireView.swift in Sources */, FF70FB7D2C90584900129CC2 /* MatchSummaryView.swift in Sources */, diff --git a/PadelClub/Views/Cashier/Event/EventStatusView.swift b/PadelClub/Views/Cashier/Event/EventStatusView.swift new file mode 100644 index 0000000..2cf1680 --- /dev/null +++ b/PadelClub/Views/Cashier/Event/EventStatusView.swift @@ -0,0 +1,107 @@ +// +// EventStatusView.swift +// PadelClub +// +// Created by Razmig Sarkissian on 04/06/2025. +// + +import SwiftUI +import PadelClubData + +struct EventStatusView: View { + @State private var teamsCount: Int? + + let tournaments: [Tournament] + + init(tournament: Tournament) { + self.tournaments = [tournament] + } + + init(event: Event) { + self.tournaments = event.confirmedTournaments() + } + + init(tournaments: [Tournament]) { + self.tournaments = tournaments + } + + private func _calculateTeamsCount() async { + Task { + self.teamsCount = tournaments.map({ $0.selectedSortedTeams().count }).reduce(0, +) + } + } + + private func _valueView(value: T, value2: T? = nil) -> some View { + if let value2 { + Text("\(value.description)/\(value2.description)") + .font(.title3) + } else { + Text("\(value.description)") + .font(.title3) + } + } + + private func _currencyView(value: Double, value2: Double? = nil) -> some View { + + let maps = [value, value2].compactMap({ $0 }).map { + $0.formatted(.currency(code: Locale.defaultCurrency()).precision(.fractionLength(0))) + } + + let string = maps.joined(separator: " / ") + return Text(string) + } + + + var body: some View { + List { + Section { + LabeledContent { + _valueView(value: tournaments.count) + } label: { + Text("Tournois") + } + + LabeledContent { + if let teamsCount { + _valueView(value: teamsCount, value2: tournaments.map({ $0.teamCount }).reduce(0, +)) + } else { + ProgressView() + } + } label: { + Text("Inscriptions") + } + + LabeledContent { + _currencyView(value: tournaments.map({ $0.earnings() }).reduce(0, +), value2: tournaments.map({ $0.totalIncome() }).reduce(0, +)) + } label: { + Text("Recettes") + } + } header: { + if let tournament = tournaments.first, tournaments.count == 1 { + Text(tournament.tournamentTitle()) + } else { + Text("Statistiques globales") + } + } + + if tournaments.count > 1 { + Section { + ForEach(tournaments) { tournament in + NavigationLink(destination: EventStatusView(tournament: tournament)) { + LabeledContent { + _valueView(value: tournament.selectedSortedTeams().count, value2: tournament.teamCount) + } label: { + Text(tournament.tournamentTitle()) + } + } + } + } + } + } + .task { + await self._calculateTeamsCount() + } + .toolbarBackground(.visible, for: .navigationBar) + .navigationBarTitleDisplayMode(.inline) + } +} diff --git a/PadelClub/Views/Cashier/Event/EventView.swift b/PadelClub/Views/Cashier/Event/EventView.swift index 365442d..e04154a 100644 --- a/PadelClub/Views/Cashier/Event/EventView.swift +++ b/PadelClub/Views/Cashier/Event/EventView.swift @@ -19,6 +19,7 @@ enum EventDestination: Identifiable, Selectable, Equatable { case tournaments(Event) case cashier case eventPlanning + case eventStatus var id: String { return String(describing: self) @@ -36,12 +37,14 @@ enum EventDestination: Identifiable, Selectable, Equatable { return "Finance" case .eventPlanning: return "Planning" + case .eventStatus: + return "Statut" } } func badgeValue() -> Int? { switch self { - case .links, .club: + case .links, .club, .eventStatus: return nil case .tournaments(let event): return event.tournaments.count @@ -80,7 +83,7 @@ struct EventView: View { } func allDestinations() -> [EventDestination] { - [.club(event), .eventPlanning, .tournaments(event), .cashier] + [.club(event), .eventStatus, .eventPlanning, .tournaments(event), .cashier] } var body: some View { @@ -91,6 +94,8 @@ struct EventView: View { EventSettingsView(event: event) case .some(let selectedEventDestination): switch selectedEventDestination { + case .eventStatus: + EventStatusView(event: event) case .club(let event): EventClubSettingsView(event: event) case .eventPlanning: diff --git a/PadelClub/Views/Tournament/TournamentView.swift b/PadelClub/Views/Tournament/TournamentView.swift index 0c84848..457f9d2 100644 --- a/PadelClub/Views/Tournament/TournamentView.swift +++ b/PadelClub/Views/Tournament/TournamentView.swift @@ -150,6 +150,9 @@ struct TournamentView: View { TournamentScheduleView(tournament: tournament) case .cashier: TournamentCashierView(tournament: tournament) + case .statistics: + EventStatusView(tournament: tournament) + .navigationTitle("Statistiques") case .call: TournamentCallView(tournament: tournament) case .rankings: @@ -265,6 +268,11 @@ struct TournamentView: View { Text(tournament.isFree() ? "Présence" : "Encaissement") } + NavigationLink(value: Screen.statistics) { + Text("Statistiques") + } + + NavigationLink(value: Screen.rankings) { LabeledContent { if tournament.publishRankings == false {