fix more stuff

multistore
Razmig Sarkissian 2 years ago
parent 4253ba2c31
commit 860eab9b76
  1. 2
      PadelClub/Data/GroupStage.swift
  2. 7
      PadelClub/Data/Match.swift
  3. 30
      PadelClub/Data/MatchScheduler.swift
  4. 6
      PadelClub/Data/Round.swift
  5. 65
      PadelClub/Data/Tournament.swift
  6. 2
      PadelClub/Utils/URLs.swift
  7. 42
      PadelClub/Views/Club/ClubDetailView.swift
  8. 1
      PadelClub/Views/Club/CourtView.swift
  9. 21
      PadelClub/Views/Planning/PlanningSettingsView.swift
  10. 2
      PadelClub/Views/Round/RoundSettingsView.swift
  11. 28
      PadelClub/Views/Round/RoundView.swift
  12. 132
      PadelClub/Views/Tournament/Screen/BroadcastView.swift
  13. 6
      PadelClubTests/ServerDataTests.swift

@ -79,7 +79,7 @@ class GroupStage: ModelObject, Storable {
var _matches = [Match]() var _matches = [Match]()
for i in 0..<_numberOfMatchesToBuild() { for i in 0..<_numberOfMatchesToBuild() {
let newMatch = Match(groupStage: id, index: i, matchFormat: matchFormat) let newMatch = Match(groupStage: id, index: i, matchFormat: matchFormat, name: localizedMatchUpLabel(for: i))
_matches.append(newMatch) _matches.append(newMatch)
} }

@ -13,6 +13,11 @@ class Match: ModelObject, Storable {
static func resourceName() -> String { "matches" } static func resourceName() -> String { "matches" }
static func tokenExemptedMethods() -> [HTTPMethod] { return [] } static func tokenExemptedMethods() -> [HTTPMethod] { return [] }
static func setServerTitle(upperRound: Round, matchIndex: Int) -> String {
if upperRound.index == 0 { return upperRound.roundTitle() }
return upperRound.roundTitle() + " #" + (matchIndex + 1).formatted()
}
var byeState: Bool = false var byeState: Bool = false
var id: String = Store.randomId() var id: String = Store.randomId()
@ -27,7 +32,7 @@ class Match: ModelObject, Storable {
var winningTeamId: String? var winningTeamId: String?
var losingTeamId: String? var losingTeamId: String?
//var broadcasted: Bool //var broadcasted: Bool
private var name: String? var name: String?
//var order: Int //var order: Int
var disabled: Bool = false var disabled: Bool = false
private(set) var courtIndex: Int? private(set) var courtIndex: Int?

@ -88,7 +88,35 @@ class MatchScheduler : ModelObject, Storable {
}) })
var lastDate : Date = tournament.startDate var lastDate : Date = tournament.startDate
groupStages.chunked(into: groupStageCourtCount).forEach { groups in let times = Set(groupStages.compactMap { $0.startDate }).sorted()
if let first = times.first {
if first.isEarlierThan(tournament.startDate) {
tournament.startDate = first
try? DataStore.shared.tournaments.addOrUpdate(instance: tournament)
}
}
times.forEach({ time in
lastDate = time
let groups = groupStages.filter({ $0.startDate == time })
let dispatch = groupStageDispatcher(numberOfCourtsAvailablePerRotation: numberOfCourtsAvailablePerRotation, groupStages: groups, startingDate: lastDate)
dispatch.timedMatches.forEach { matchSchedule in
if let match = matches.first(where: { $0.id == matchSchedule.matchID }) {
let estimatedDuration = match.matchFormat.getEstimatedDuration(tournament.additionalEstimationDuration)
let timeIntervalToAdd = (Double(matchSchedule.rotationIndex)) * Double(estimatedDuration) * 60
if let startDate = match.groupStageObject?.startDate {
let matchStartDate = startDate.addingTimeInterval(timeIntervalToAdd)
match.startDate = matchStartDate
lastDate = matchStartDate.addingTimeInterval(Double(estimatedDuration) * 60)
}
match.setCourt(matchSchedule.courtIndex)
}
}
})
groupStages.filter({ $0.startDate == nil || times.contains($0.startDate!) == false }).chunked(into: groupStageCourtCount).forEach { groups in
groups.forEach({ $0.startDate = lastDate }) groups.forEach({ $0.startDate = lastDate })
try? DataStore.shared.groupStages.addOrUpdate(contentOfs: groups) try? DataStore.shared.groupStages.addOrUpdate(contentOfs: groups)

@ -431,13 +431,9 @@ class Round: ModelObject, Storable {
let matches = (0..<matchCount).map { //0 is final match let matches = (0..<matchCount).map { //0 is final match
let roundIndex = RoundRule.roundIndex(fromMatchIndex: $0) let roundIndex = RoundRule.roundIndex(fromMatchIndex: $0)
let round = rounds[roundIndex] let round = rounds[roundIndex]
return Match(round: round.id, index: $0, matchFormat: loserBracketMatchFormat) return Match(round: round.id, index: $0, matchFormat: loserBracketMatchFormat, name: round.roundTitle())
} }
print(matches.map {
(RoundRule.roundName(fromMatchIndex: $0.index), RoundRule.matchIndexWithinRound(fromMatchIndex: $0.index))
})
try? DataStore.shared.matches.addOrUpdate(contentOfs: matches) try? DataStore.shared.matches.addOrUpdate(contentOfs: matches)
loserRounds().forEach { round in loserRounds().forEach { round in

@ -44,9 +44,8 @@ class Tournament : ModelObject, Storable {
var additionalEstimationDuration: Int = 0 var additionalEstimationDuration: Int = 0
var isDeleted: Bool = false var isDeleted: Bool = false
var isCanceled: Bool = false var isCanceled: Bool = false
var publishManually: Bool = false
var publishTeams: Bool = false var publishTeams: Bool = false
var publishWaitingList: Bool = false //var publishWaitingList: Bool = false
var publishSummons: Bool = false var publishSummons: Bool = false
var publishGroupStages: Bool = false var publishGroupStages: Bool = false
var publishBrackets: Bool = false var publishBrackets: Bool = false
@ -88,15 +87,14 @@ class Tournament : ModelObject, Storable {
case _isDeleted = "isDeleted" case _isDeleted = "isDeleted"
case _isCanceled = "localId" case _isCanceled = "localId"
case _payment = "globalId" case _payment = "globalId"
case _publishManually = "publishManually"
case _publishTeams = "publishTeams" case _publishTeams = "publishTeams"
case _publishWaitingList = "publishWaitingList" //case _publishWaitingList = "publishWaitingList"
case _publishSummons = "publishSummons" case _publishSummons = "publishSummons"
case _publishGroupStages = "publishGroupStages" case _publishGroupStages = "publishGroupStages"
case _publishBrackets = "publishBrackets" case _publishBrackets = "publishBrackets"
} }
internal init(event: String? = nil, name: String? = nil, startDate: Date = Date(), endDate: Date? = nil, creationDate: Date = Date(), isPrivate: Bool = false, groupStageFormat: MatchFormat? = nil, roundFormat: MatchFormat? = nil, loserRoundFormat: MatchFormat? = nil, groupStageSortMode: GroupStageOrderingMode, groupStageCount: Int = 4, rankSourceDate: Date? = nil, dayDuration: Int = 1, teamCount: Int = 24, teamSorting: TeamSortingType? = nil, federalCategory: TournamentCategory, federalLevelCategory: TournamentLevel, federalAgeCategory: FederalTournamentAge, groupStageCourtCount: Int? = nil, closedRegistrationDate: Date? = nil, groupStageAdditionalQualified: Int = 0, courtCount: Int = 2, prioritizeClubMembers: Bool = false, qualifiedPerGroupStage: Int = 1, teamsPerGroupStage: Int = 4, entryFee: Double? = nil, additionalEstimationDuration: Int = 0, isDeleted: Bool = false, publishManually: Bool = false, publishTeams: Bool = false, publishWaitingList: Bool = false, publishSummons: Bool = false, publishGroupStages: Bool = false, publishBrackets: Bool = false) { internal init(event: String? = nil, name: String? = nil, startDate: Date = Date(), endDate: Date? = nil, creationDate: Date = Date(), isPrivate: Bool = false, groupStageFormat: MatchFormat? = nil, roundFormat: MatchFormat? = nil, loserRoundFormat: MatchFormat? = nil, groupStageSortMode: GroupStageOrderingMode, groupStageCount: Int = 4, rankSourceDate: Date? = nil, dayDuration: Int = 1, teamCount: Int = 24, teamSorting: TeamSortingType? = nil, federalCategory: TournamentCategory, federalLevelCategory: TournamentLevel, federalAgeCategory: FederalTournamentAge, groupStageCourtCount: Int? = nil, closedRegistrationDate: Date? = nil, groupStageAdditionalQualified: Int = 0, courtCount: Int = 2, prioritizeClubMembers: Bool = false, qualifiedPerGroupStage: Int = 1, teamsPerGroupStage: Int = 4, entryFee: Double? = nil, additionalEstimationDuration: Int = 0, isDeleted: Bool = false, publishTeams: Bool = false, publishSummons: Bool = false, publishGroupStages: Bool = false, publishBrackets: Bool = false) {
self.event = event self.event = event
self.name = name self.name = name
self.startDate = startDate self.startDate = startDate
@ -125,6 +123,10 @@ class Tournament : ModelObject, Storable {
self.entryFee = entryFee self.entryFee = entryFee
self.additionalEstimationDuration = additionalEstimationDuration self.additionalEstimationDuration = additionalEstimationDuration
self.isDeleted = isDeleted self.isDeleted = isDeleted
self.publishTeams = publishTeams
self.publishSummons = publishSummons
self.publishBrackets = publishBrackets
self.publishGroupStages = publishGroupStages
} }
required init(from decoder: Decoder) throws { required init(from decoder: Decoder) throws {
@ -160,9 +162,7 @@ class Tournament : ModelObject, Storable {
additionalEstimationDuration = try container.decode(Int.self, forKey: ._additionalEstimationDuration) additionalEstimationDuration = try container.decode(Int.self, forKey: ._additionalEstimationDuration)
isDeleted = try container.decode(Bool.self, forKey: ._isDeleted) isDeleted = try container.decode(Bool.self, forKey: ._isDeleted)
isCanceled = try Tournament._decodeCanceled(container: container) isCanceled = try Tournament._decodeCanceled(container: container)
publishManually = try container.decodeIfPresent(Bool.self, forKey: ._publishManually) ?? false
publishTeams = try container.decodeIfPresent(Bool.self, forKey: ._publishTeams) ?? false publishTeams = try container.decodeIfPresent(Bool.self, forKey: ._publishTeams) ?? false
publishWaitingList = try container.decodeIfPresent(Bool.self, forKey: ._publishWaitingList) ?? false
publishSummons = try container.decodeIfPresent(Bool.self, forKey: ._publishSummons) ?? false publishSummons = try container.decodeIfPresent(Bool.self, forKey: ._publishSummons) ?? false
publishGroupStages = try container.decodeIfPresent(Bool.self, forKey: ._publishGroupStages) ?? false publishGroupStages = try container.decodeIfPresent(Bool.self, forKey: ._publishGroupStages) ?? false
publishBrackets = try container.decodeIfPresent(Bool.self, forKey: ._publishBrackets) ?? false publishBrackets = try container.decodeIfPresent(Bool.self, forKey: ._publishBrackets) ?? false
@ -295,6 +295,55 @@ class Tournament : ModelObject, Storable {
case canceled case canceled
} }
func publishedTeamsDate() -> Date {
startDate
}
func areTeamsPublished() -> Bool {
Date() >= startDate
}
func publishedGroupStagesDate() -> Date? {
if let first = groupStages().flatMap({ $0.playedMatches() }).compactMap({ $0.startDate }).sorted().first?.atNine() {
if first.isEarlierThan(startDate) {
return startDate
} else {
return first
}
} else {
return nil
}
}
func areGroupStagesPublished() -> Bool {
if let publishedGroupStagesDate = publishedGroupStagesDate() {
return Date() >= publishedGroupStagesDate
} else {
return false
}
}
func publishedBracketsDate() -> Date? {
if let first = rounds().flatMap({ $0.playedMatches() }).compactMap({ $0.startDate }).sorted().first?.atNine() {
if first.isEarlierThan(startDate) {
return startDate
} else {
return first
}
} else {
return nil
}
}
func areBracketsPublished() -> Bool {
if let publishedBracketsDate = publishedBracketsDate() {
return Date() >= publishedBracketsDate
} else {
return false
}
}
func shareURL() -> URL? { func shareURL() -> URL? {
return URLs.main.url.appending(path: "tournament/\(id)") return URLs.main.url.appending(path: "tournament/\(id)")
} }
@ -1096,7 +1145,7 @@ class Tournament : ModelObject, Storable {
let matches = (0..<matchCount).map { //0 is final match let matches = (0..<matchCount).map { //0 is final match
let roundIndex = RoundRule.roundIndex(fromMatchIndex: $0) let roundIndex = RoundRule.roundIndex(fromMatchIndex: $0)
let round = rounds[roundIndex] let round = rounds[roundIndex]
return Match(round: round.id, index: $0, matchFormat: matchFormat) return Match(round: round.id, index: $0, matchFormat: matchFormat, name: Match.setServerTitle(upperRound: round, matchIndex: RoundRule.matchIndexWithinRound(fromMatchIndex: $0)))
} }
print(matches.map { print(matches.map {

@ -11,7 +11,7 @@ enum URLs: String, Identifiable {
case subscriptions = "https://apple.co/2Th4vqI" case subscriptions = "https://apple.co/2Th4vqI"
case main = "https://xlr.alwaysdata.net/" case main = "https://xlr.alwaysdata.net/"
case beachPadel = "https://beach-padel.app.fft.fr/beachja/index/" case beachPadel = "https://beach-padel.app.fft.fr/beachja/index/"
case padelClub = "https://padelclub.app" //case padelClub = "https://padelclub.app"
var id: String { return self.rawValue } var id: String { return self.rawValue }

@ -27,21 +27,37 @@ struct ClubDetailView: View {
var body: some View { var body: some View {
Form { Form {
Section {
NavigationLink {
ClubSearchView(displayContext: .edition, club: club)
} label: {
Label("Chercher dans la base fédérale", systemImage: "magnifyingglass")
}
} footer: {
Text("Vous pouvez chercher un club dans la base fédérale et importer les informations directement.")
}
Section { Section {
VStack(alignment: .leading, spacing: 0) { LabeledContent {
Text("Nom du club").foregroundStyle(.secondary).font(.caption)
TextField("Nom du club", text: $club.name) TextField("Nom du club", text: $club.name)
.fixedSize() .autocorrectionDisabled()
.keyboardType(.alphabet)
.multilineTextAlignment(.trailing)
.frame(maxWidth: .infinity)
.focused($focusedField, equals: ._name) .focused($focusedField, equals: ._name)
.submitLabel( displayContext == .addition ? .next : .done) .submitLabel( displayContext == .addition ? .next : .done)
.onSubmit { .onSubmit {
if club.acronym.isEmpty { if club.acronym.isEmpty {
club.acronym = club.name.canonicalVersion.replaceCharactersFromSet(characterSet: .whitespacesAndNewlines) club.acronym = club.name.canonicalVersion.replaceCharactersFromSet(characterSet: .whitespacesAndNewlines)
focusedField = ._city
} }
if displayContext == .addition { if displayContext == .addition {
focusedField = ._acronym focusedField = ._acronym
} }
} }
} label: {
Text("Nom du club")
} }
.onTapGesture { .onTapGesture {
focusedField = ._name focusedField = ._name
@ -92,10 +108,12 @@ struct ClubDetailView: View {
} }
if club.code == nil { if club.code == nil {
VStack(alignment: .leading, spacing: 0) { LabeledContent {
Text("Ville").foregroundStyle(.secondary).font(.caption)
TextField("Ville", text: $city) TextField("Ville", text: $city)
.fixedSize() .autocorrectionDisabled()
.keyboardType(.alphabet)
.multilineTextAlignment(.trailing)
.frame(maxWidth: .infinity)
.focused($focusedField, equals: ._city) .focused($focusedField, equals: ._city)
.submitLabel( displayContext == .addition ? .next : .done) .submitLabel( displayContext == .addition ? .next : .done)
.onSubmit { .onSubmit {
@ -104,20 +122,26 @@ struct ClubDetailView: View {
} }
club.city = city club.city = city
} }
} label: {
Text("Ville")
} }
.onTapGesture { .onTapGesture {
focusedField = ._city focusedField = ._city
} }
VStack(alignment: .leading, spacing: 0) { LabeledContent {
Text("Code Postal").foregroundStyle(.secondary).font(.caption)
TextField("Code Postal", text: $zipCode) TextField("Code Postal", text: $zipCode)
.fixedSize() .autocorrectionDisabled()
.keyboardType(.alphabet)
.multilineTextAlignment(.trailing)
.frame(maxWidth: .infinity)
.focused($focusedField, equals: ._zipCode) .focused($focusedField, equals: ._zipCode)
.submitLabel( displayContext == .addition ? .next : .done) .submitLabel( displayContext == .addition ? .next : .done)
.onSubmit { .onSubmit {
club.zipCode = zipCode club.zipCode = zipCode
} }
} label: {
Text("Code Postal")
} }
.onTapGesture { .onTapGesture {
focusedField = ._zipCode focusedField = ._zipCode

@ -22,6 +22,7 @@ struct CourtView: View {
Section { Section {
LabeledContent { LabeledContent {
TextField("Nom", text: $name) TextField("Nom", text: $name)
.autocorrectionDisabled()
.keyboardType(.alphabet) .keyboardType(.alphabet)
.multilineTextAlignment(.trailing) .multilineTextAlignment(.trailing)
.frame(maxWidth: .infinity) .frame(maxWidth: .infinity)

@ -59,6 +59,14 @@ struct PlanningSettingsView: View {
Text("Préciser la disponibilité des terrains") Text("Préciser la disponibilité des terrains")
} }
} }
} footer: {
FooterButtonView((showOptions ? "masquer" : "voir") + " les réglages avancées") {
showOptions.toggle()
}
}
if showOptions {
_optionsView()
} }
Section { Section {
@ -68,17 +76,7 @@ struct PlanningSettingsView: View {
schedulingDone = true schedulingDone = true
} }
} footer: { } footer: {
Button { Text("Padel Club programmera tous les matchs de votre tournoi en fonction de différents paramètres, ") + Text("tout en tenant compte des horaires que vous avez fixé.").underline()
showOptions.toggle()
} label: {
Text((showOptions ? "masquer" : "voir") + " les réglages avancées")
.underline()
}
.buttonStyle(.borderless)
}
if showOptions {
_optionsView()
} }
Section { Section {
@ -101,6 +99,7 @@ struct PlanningSettingsView: View {
} }
} }
} }
.headerProminence(.increased)
.onAppear { .onAppear {
do { do {
try dataStore.matchSchedulers.addOrUpdate(instance: matchScheduler) try dataStore.matchSchedulers.addOrUpdate(instance: matchScheduler)

@ -42,7 +42,7 @@ struct RoundSettingsView: View {
let matchCount = RoundRule.numberOfMatches(forRoundIndex: roundIndex) let matchCount = RoundRule.numberOfMatches(forRoundIndex: roundIndex)
let matchStartIndex = RoundRule.matchIndex(fromRoundIndex: roundIndex) let matchStartIndex = RoundRule.matchIndex(fromRoundIndex: roundIndex)
let matches = (0..<matchCount).map { //0 is final match let matches = (0..<matchCount).map { //0 is final match
return Match(round: round.id, index: $0 + matchStartIndex, matchFormat: round.matchFormat) return Match(round: round.id, index: $0 + matchStartIndex, matchFormat: round.matchFormat, name: Match.setServerTitle(upperRound: round, matchIndex: $0))
} }
try? dataStore.rounds.addOrUpdate(instance: round) try? dataStore.rounds.addOrUpdate(instance: round)
try? dataStore.matches.addOrUpdate(contentOfs: matches) try? dataStore.matches.addOrUpdate(contentOfs: matches)

@ -52,9 +52,10 @@ struct RoundView: View {
print(spaceLeft[drawResult.drawIndex].matchTitle()) print(spaceLeft[drawResult.drawIndex].matchTitle())
availableQualifiedTeams[drawResult.drawee].setSeedPosition(inSpot: spaceLeft[drawResult.drawIndex], slot: nil, opposingSeeding: true) availableQualifiedTeams[drawResult.drawee].setSeedPosition(inSpot: spaceLeft[drawResult.drawIndex], slot: nil, opposingSeeding: true)
} }
try? dataStore.matches.addOrUpdate(contentOfs: spaceLeft) _save()
try? dataStore.teamRegistrations.addOrUpdate(contentOfs: availableQualifiedTeams) if tournament.availableSeeds().isEmpty && tournament.availableQualifiedTeams().isEmpty {
isEditingTournamentSeed.wrappedValue.toggle() self.isEditingTournamentSeed.wrappedValue = false
}
} }
} }
} else if let availableSeedGroup = tournament.seedGroupAvailable(atRoundIndex: round.index) { } else if let availableSeedGroup = tournament.seedGroupAvailable(atRoundIndex: round.index) {
@ -62,8 +63,8 @@ struct RoundView: View {
Section { Section {
RowButtonView("Placer \(availableSeedGroup.localizedLabel())" + ((availableSeedGroup.isFixed() == false) ? " au hasard" : "")) { RowButtonView("Placer \(availableSeedGroup.localizedLabel())" + ((availableSeedGroup.isFixed() == false) ? " au hasard" : "")) {
tournament.setSeeds(inRoundIndex: round.index, inSeedGroup: availableSeedGroup) tournament.setSeeds(inRoundIndex: round.index, inSeedGroup: availableSeedGroup)
if tournament.availableSeeds().isEmpty { _save()
_save() if tournament.availableSeeds().isEmpty && tournament.availableQualifiedTeams().isEmpty {
self.isEditingTournamentSeed.wrappedValue = false self.isEditingTournamentSeed.wrappedValue = false
} }
} }
@ -109,8 +110,10 @@ struct RoundView: View {
print(availableSeedSpot[drawResult.drawIndex].matchTitle()) print(availableSeedSpot[drawResult.drawIndex].matchTitle())
seeds[drawResult.drawee].setSeedPosition(inSpot: availableSeedSpot[drawResult.drawIndex], slot: nil, opposingSeeding: false) seeds[drawResult.drawee].setSeedPosition(inSpot: availableSeedSpot[drawResult.drawIndex], slot: nil, opposingSeeding: false)
} }
try? dataStore.matches.addOrUpdate(contentOfs: availableSeedSpot) _save()
try? dataStore.teamRegistrations.addOrUpdate(contentOfs: seeds) if tournament.availableSeeds().isEmpty && tournament.availableQualifiedTeams().isEmpty {
self.isEditingTournamentSeed.wrappedValue = false
}
} }
} }
} }
@ -129,7 +132,16 @@ struct RoundView: View {
} }
private func _save() { private func _save() {
try? dataStore.teamRegistrations.addOrUpdate(contentOfs: tournament.seeds()) try? dataStore.teamRegistrations.addOrUpdate(contentOfs: tournament.unsortedTeams())
//todo should be done server side
let rounds = tournament.rounds()
rounds.forEach { round in
let matches = round.playedMatches()
matches.forEach { match in
match.name = Match.setServerTitle(upperRound: round, matchIndex: match.indexInRound())
}
}
let allRoundMatches = tournament.allRoundMatches() let allRoundMatches = tournament.allRoundMatches()
try? DataStore.shared.matches.addOrUpdate(contentOfs: allRoundMatches) try? DataStore.shared.matches.addOrUpdate(contentOfs: allRoundMatches)
} }

@ -30,7 +30,7 @@ struct BroadcastView: View {
List { List {
Section { Section {
TipView(tournamentPublishingTip) { action in TipView(tournamentPublishingTip) { action in
UIApplication.shared.open(URLs.padelClub.url) UIApplication.shared.open(URLs.main.url)
} }
.tipStyle(tint: nil) .tipStyle(tint: nil)
} }
@ -39,67 +39,132 @@ struct BroadcastView: View {
.tipStyle(tint: nil) .tipStyle(tint: nil)
} }
if tournament.publishManually == false { Section {
Section { LabeledContent {
Text("En mode automatique, Padel Club détermine le meilleur moment pour publier les informations du tournoi.\n\n• La liste des équipes sera visible au maximum 2 jours après la clôture des inscriptions. À partir des p500, la liste d'attente à la clôture sera également publiée.\n\n• Les convocations ne seront visibles qu'à partir du premier jour du tournoi.\n\n• Les poules ne seront visibles qu'au premier jour des poules.\n\n• Le tableau ne sera visible qu'au premier jour du tableau.") if tournament.areTeamsPublished() {
} header: { Image(systemName:"checkmark").foregroundStyle(.green)
Text("Mode Automatique") } else {
} footer: { Text(tournament.publishedTeamsDate().formatted())
FooterButtonView("désactiver le mode automatique") { }
tournament.publishManually.toggle() } label: {
if tournament.areTeamsPublished() {
Text("Publiée")
} else {
Text("Publication prévue")
}
Text("Les horaires de convocations ne seront pas publiés")
}
} header: {
Text("Liste des équipes")
} footer: {
if tournament.publishedTeamsDate() < Date() {
FooterButtonView(tournament.publishTeams ? "masquer sur le site" : "publier maintenant") {
tournament.publishTeams.toggle()
} }
} }
} }
if tournament.publishManually == true { Section {
Section { LabeledContent {
Text("En mode manuel, vous devez indiquer à Padel Club le moment où vous souhaitez publier les informations du tournoi") if tournament.areTeamsPublished() {
Image(systemName:"checkmark").foregroundStyle(.green)
Toggle(isOn: $tournament.publishTeams) { } else {
Text("Publier la liste des équipes") Text(tournament.publishedTeamsDate().formatted())
Text("Les horaires de convocations ne seront pas publiés")
} }
Toggle(isOn: $tournament.publishWaitingList) { } label: {
Text("Inclure les équipes en liste d'attente") if tournament.areTeamsPublished() {
Text("Publiée")
} else {
Text("Publication prévue")
} }
Toggle(isOn: $tournament.publishSummons) { }
Text("Publier les convocations") } header: {
Text("Convocations")
} footer: {
if tournament.publishedTeamsDate() < Date() {
FooterButtonView(tournament.publishSummons ? "masquer sur le site" : "publier maintenant") {
tournament.publishSummons.toggle()
} }
Toggle(isOn: $tournament.publishGroupStages) { }
Text("Publier les poules") }
if let publishedGroupStagesDate = tournament.publishedGroupStagesDate() {
Section {
let areGroupStagesPublished = tournament.areGroupStagesPublished()
LabeledContent {
if areGroupStagesPublished {
Image(systemName:"checkmark").foregroundStyle(.green)
} else {
Text(publishedGroupStagesDate.formatted())
}
} label: {
if areGroupStagesPublished {
Text("Publiée")
} else {
Text("Publication prévue")
}
} }
Toggle(isOn: $tournament.publishBrackets) { } header: {
Text("Publier le tableau") Text("Poules")
} footer: {
if publishedGroupStagesDate < Date() {
FooterButtonView(tournament.publishGroupStages ? "masquer sur le site" : "publier maintenant") {
tournament.publishGroupStages.toggle()
}
}
}
}
if let publishedBracketsDate = tournament.publishedBracketsDate() {
Section {
let areBracketsPublished = tournament.areBracketsPublished()
LabeledContent {
if areBracketsPublished {
Image(systemName:"checkmark").foregroundStyle(.green)
} else {
Text(publishedBracketsDate.formatted())
}
} label: {
if areBracketsPublished {
Text("Publiée")
} else {
Text("Publication prévue")
}
} }
} header: { } header: {
Text("Mode Manuel") Text("Tableau")
} footer: { } footer: {
FooterButtonView("activer le mode automatique") { if publishedBracketsDate < Date() {
tournament.publishManually.toggle() FooterButtonView(tournament.publishBrackets ? "masquer sur le site" : "publier maintenant") {
tournament.publishBrackets.toggle()
}
} }
} }
} }
//todo waitinglist & info
Section { Section {
Toggle(isOn: $tournament.isPrivate) { Toggle(isOn: $tournament.isPrivate) {
Text("Tournoi privé") Text("Tournoi privé")
} }
} footer: { } footer: {
Text("Le tournoi sera masqué sur le site \(URLs.main.rawValue)") let footerString = "Le tournoi sera masqué sur le site [Padel Club]\(URLs.main.rawValue)"
Text(.init(footerString))
} }
Section { Section {
LabeledContent { LabeledContent {
actionForURL(URLs.main.url) actionForURL(URLs.main.url)
} label: { } label: {
Text("Lien Padel Club") Text("Padel Club")
} }
if let club = tournament.club(), let clubURL = club.shareURL() { if let club = tournament.club(), let clubURL = club.shareURL() {
LabeledContent { LabeledContent {
actionForURL(clubURL) actionForURL(clubURL)
} label: { } label: {
Text("Lien du club") Text("Club")
} }
} }
@ -107,7 +172,7 @@ struct BroadcastView: View {
LabeledContent { LabeledContent {
actionForURL(url) actionForURL(url)
} label: { } label: {
Text("Lien du tournoi") Text("Tournoi")
} }
} }
@ -115,7 +180,7 @@ struct BroadcastView: View {
LabeledContent { LabeledContent {
actionForURL(url) actionForURL(url)
} label: { } label: {
Text("Lien TV") Text("TV")
} }
} }
@ -185,8 +250,7 @@ struct BroadcastView: View {
} label: { } label: {
HStack { HStack {
Spacer() Spacer()
Text("lien") Image(systemName: "square.and.arrow.up")
.underline()
} }
} }
.frame(maxWidth: .infinity) .frame(maxWidth: .infinity)

@ -96,7 +96,7 @@ final class ServerDataTests: XCTestCase {
return return
} }
let tournament = Tournament(event: eventId, name: "RG Homme", startDate: Date(), endDate: nil, creationDate: Date(), isPrivate: false, groupStageFormat: MatchFormat.megaTie, roundFormat: MatchFormat.nineGames, loserRoundFormat: MatchFormat.nineGamesDecisivePoint, groupStageSortMode: GroupStageOrderingMode.snake, groupStageCount: 2, rankSourceDate: Date(), dayDuration: 5, teamCount: 3, teamSorting: TeamSortingType.rank, federalCategory: TournamentCategory.mix, federalLevelCategory: TournamentLevel.p1000, federalAgeCategory: FederalTournamentAge.a45, groupStageCourtCount: 6, closedRegistrationDate: Date(), groupStageAdditionalQualified: 4, courtCount: 9, prioritizeClubMembers: true, qualifiedPerGroupStage: 1, teamsPerGroupStage: 2, entryFee: 30.0, additionalEstimationDuration: 5, isDeleted: true) let tournament = Tournament(event: eventId, name: "RG Homme", startDate: Date(), endDate: nil, creationDate: Date(), isPrivate: false, groupStageFormat: MatchFormat.megaTie, roundFormat: MatchFormat.nineGames, loserRoundFormat: MatchFormat.nineGamesDecisivePoint, groupStageSortMode: GroupStageOrderingMode.snake, groupStageCount: 2, rankSourceDate: Date(), dayDuration: 5, teamCount: 3, teamSorting: TeamSortingType.rank, federalCategory: TournamentCategory.mix, federalLevelCategory: TournamentLevel.p1000, federalAgeCategory: FederalTournamentAge.a45, groupStageCourtCount: 6, closedRegistrationDate: Date(), groupStageAdditionalQualified: 4, courtCount: 9, prioritizeClubMembers: true, qualifiedPerGroupStage: 1, teamsPerGroupStage: 2, entryFee: 30.0, additionalEstimationDuration: 5, isDeleted: true, publishTeams: true, publishSummons: true, publishGroupStages: true, publishBrackets: true)
let t = try await Store.main.service().post(tournament) let t = try await Store.main.service().post(tournament)
assert(t.event == tournament.event) assert(t.event == tournament.event)
@ -127,6 +127,10 @@ final class ServerDataTests: XCTestCase {
assert(t.entryFee == tournament.entryFee) assert(t.entryFee == tournament.entryFee)
assert(t.additionalEstimationDuration == tournament.additionalEstimationDuration) assert(t.additionalEstimationDuration == tournament.additionalEstimationDuration)
assert(t.isDeleted == tournament.isDeleted) assert(t.isDeleted == tournament.isDeleted)
assert(t.publishTeams == tournament.publishTeams)
assert(t.publishSummons == tournament.publishSummons)
assert(t.publishGroupStages == tournament.publishGroupStages)
assert(t.publishBrackets == tournament.publishBrackets)
} }

Loading…
Cancel
Save