Merge branch 'main' into sync3

sync3
Laurent 5 months ago
commit 57439e4a93
  1. 16
      PadelClub.xcodeproj/project.pbxproj
  2. 107
      PadelClub/Views/Cashier/Event/EventStatusView.swift
  3. 9
      PadelClub/Views/Cashier/Event/EventView.swift
  4. 27
      PadelClub/Views/GroupStage/Components/GroupStageTeamView.swift
  5. 8
      PadelClub/Views/Tournament/Screen/BroadcastView.swift
  6. 8
      PadelClub/Views/Tournament/TournamentView.swift

@ -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 = "<group>"; };
FF82CFC82B9132AF00B0CAF2 /* ActivityView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivityView.swift; sourceTree = "<group>"; };
FF8E1CE52C006E0200184680 /* Alphabet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Alphabet.swift; sourceTree = "<group>"; };
FF8E52332DF01D6100099B75 /* EventStatusView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventStatusView.swift; sourceTree = "<group>"; };
FF8F263A2BAD528600650388 /* EventCreationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventCreationView.swift; sourceTree = "<group>"; };
FF8F263C2BAD627A00650388 /* TournamentConfiguratorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TournamentConfiguratorView.swift; sourceTree = "<group>"; };
FF8F26402BADFC8700650388 /* TournamentInitView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TournamentInitView.swift; sourceTree = "<group>"; };
@ -1843,6 +1847,7 @@
FF8F263A2BAD528600650388 /* EventCreationView.swift */,
FFE103072C353B7600684FC9 /* EventClubSettingsView.swift */,
FF8F263C2BAD627A00650388 /* TournamentConfiguratorView.swift */,
FF8E52332DF01D6100099B75 /* EventStatusView.swift */,
);
name = Event;
path = Cashier/Event;
@ -2381,6 +2386,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 */,
@ -2643,6 +2649,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 */,
@ -2883,6 +2890,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 */,
@ -3120,7 +3128,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.2.33;
MARKETING_VERSION = 1.2.35;
PRODUCT_BUNDLE_IDENTIFIER = app.padelclub;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
@ -3166,7 +3174,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.2.33;
MARKETING_VERSION = 1.2.35;
PRODUCT_BUNDLE_IDENTIFIER = app.padelclub;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
@ -3285,7 +3293,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.2.33;
MARKETING_VERSION = 1.2.34;
PRODUCT_BUNDLE_IDENTIFIER = app.padelclub;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
@ -3330,7 +3338,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.2.33;
MARKETING_VERSION = 1.2.34;
PRODUCT_BUNDLE_IDENTIFIER = app.padelclub;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";

@ -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<T: Numeric & CustomStringConvertible>(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)
}
}

@ -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:

@ -106,6 +106,29 @@ struct GroupStageTeamView: View {
groupStage.matches().forEach({ $0.updateTeamScores() })
}
}
if let groupStagePosition = team.groupStagePosition {
Section {
RowButtonView("Forfait", role: .destructive) {
team.walkOut = true
let matches = groupStage.matches(forGroupStagePosition: groupStagePosition)
.filter({
$0.hasStarted() == false && $0.hasEnded() == false
})
matches
.forEach({
if let teamPosition = $0.teamPosition(for: team) {
$0.setWalkOut(teamPosition)
}
})
tournamentStore?.matches.addOrUpdate(contentOfs: matches)
_save()
}
} footer: {
Text("En indiquant cette équipe forfaite, le résultat des matchs restant dans la poule seront mis à \(defaultScore) pour leur adversaire.")
}
}
}
}
}
@ -184,6 +207,10 @@ struct GroupStageTeamView: View {
.navigationTitle("Détail de l'équipe")
}
private var defaultScore: String {
groupStage.matchFormat.defaultWalkOutScore(false).compactMap({ String($0) + "/0" }).joined(separator: " ")
}
private var _networkErrorMessage: String {
ContactManagerError.getNetworkErrorMessage(sentError: sentError, networkMonitorConnected: networkMonitor.connected)
}

@ -318,6 +318,14 @@ struct BroadcastView: View {
Text("Lien du tournoi à partager")
}
#if DEBUG
Section {
actionForURL(title: "La Boutique", url: URLs.main.url.appending(path: "shop"))
} header: {
Text("Lien de la boutique")
}
#endif
Section {
let club = tournament.club()
actionForURL(title: (club == nil) ? "Aucun club indiqué pour ce tournoi" : club!.clubTitle(), description: "Page du club", url: club?.shareURL())

@ -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 {

Loading…
Cancel
Save