fix scheduler stuff

add open organizer stuff
multistore
Razmig Sarkissian 2 years ago
parent cf44ce1310
commit cf0259e50b
  1. 12
      PadelClub/Data/MatchScheduler.swift
  2. 9
      PadelClub/Data/Tournament.swift
  3. 17
      PadelClub/ViewModel/NavigationViewModel.swift
  4. 2
      PadelClub/ViewModel/SearchViewModel.swift
  5. 2
      PadelClub/Views/Navigation/Agenda/EventListView.swift
  6. 18
      PadelClub/Views/Navigation/Organizer/TournamentButtonView.swift
  7. 18
      PadelClub/Views/Navigation/Organizer/TournamentOrganizerView.swift
  8. 16
      PadelClub/Views/Planning/PlanningSettingsView.swift
  9. 3
      PadelClubTests/ServerDataTests.swift

@ -26,7 +26,8 @@ class MatchScheduler : ModelObject, Storable {
var rotationDifferenceIsImportant: Bool
var shouldHandleUpperRoundSlice: Bool
var shouldEndRoundBeforeStartingNext: Bool
var groupStageChunkCount: Int?
init(tournament: String,
timeDifferenceLimit: Int = 5,
loserBracketRotationDifference: Int = 0,
@ -36,7 +37,8 @@ class MatchScheduler : ModelObject, Storable {
randomizeCourts: Bool = true,
rotationDifferenceIsImportant: Bool = false,
shouldHandleUpperRoundSlice: Bool = true,
shouldEndRoundBeforeStartingNext: Bool = true) {
shouldEndRoundBeforeStartingNext: Bool = true,
groupStageChunkCount: Int? = nil) {
self.tournament = tournament
self.timeDifferenceLimit = timeDifferenceLimit
self.loserBracketRotationDifference = loserBracketRotationDifference
@ -47,6 +49,7 @@ class MatchScheduler : ModelObject, Storable {
self.rotationDifferenceIsImportant = rotationDifferenceIsImportant
self.shouldHandleUpperRoundSlice = shouldHandleUpperRoundSlice
self.shouldEndRoundBeforeStartingNext = shouldEndRoundBeforeStartingNext
self.groupStageChunkCount = groupStageChunkCount
}
enum CodingKeys: String, CodingKey {
@ -61,6 +64,7 @@ class MatchScheduler : ModelObject, Storable {
case _rotationDifferenceIsImportant = "rotationDifferenceIsImportant"
case _shouldHandleUpperRoundSlice = "shouldHandleUpperRoundSlice"
case _shouldEndRoundBeforeStartingNext = "shouldEndRoundBeforeStartingNext"
case _groupStageChunkCount = "groupStageChunkCount"
}
var courtsUnavailability: [DateInterval]? {
@ -77,7 +81,7 @@ class MatchScheduler : ModelObject, Storable {
@discardableResult
func updateGroupStageSchedule(tournament: Tournament) -> Date {
let groupStageCourtCount = tournament.groupStageCourtCount ?? 1
let computedGroupStageChunkCount = groupStageChunkCount ?? 1
let groupStages = tournament.groupStages()
let numberOfCourtsAvailablePerRotation: Int = tournament.courtCount
@ -116,7 +120,7 @@ class MatchScheduler : ModelObject, Storable {
}
})
groupStages.filter({ $0.startDate == nil || times.contains($0.startDate!) == false }).chunked(into: groupStageCourtCount).forEach { groups in
groupStages.filter({ $0.startDate == nil || times.contains($0.startDate!) == false }).chunked(into: computedGroupStageChunkCount).forEach { groups in
groups.forEach({ $0.startDate = lastDate })
try? DataStore.shared.groupStages.addOrUpdate(contentOfs: groups)

@ -32,7 +32,6 @@ class Tournament : ModelObject, Storable {
var federalCategory: TournamentCategory
var federalLevelCategory: TournamentLevel
var federalAgeCategory: FederalTournamentAge
var groupStageCourtCount: Int?
var closedRegistrationDate: Date?
var groupStageAdditionalQualified: Int
var courtCount: Int = 2
@ -74,7 +73,6 @@ class Tournament : ModelObject, Storable {
case _federalCategory = "federalCategory"
case _federalLevelCategory = "federalLevelCategory"
case _federalAgeCategory = "federalAgeCategory"
case _groupStageCourtCount = "groupStageCourtCount"
case _seedCount = "seedCount"
case _closedRegistrationDate = "closedRegistrationDate"
case _groupStageAdditionalQualified = "groupStageAdditionalQualified"
@ -94,7 +92,7 @@ class Tournament : ModelObject, Storable {
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, publishTeams: 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, 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.name = name
self.startDate = startDate
@ -113,7 +111,6 @@ class Tournament : ModelObject, Storable {
self.federalCategory = federalCategory
self.federalLevelCategory = federalLevelCategory
self.federalAgeCategory = federalAgeCategory
self.groupStageCourtCount = groupStageCourtCount
self.closedRegistrationDate = closedRegistrationDate
self.groupStageAdditionalQualified = groupStageAdditionalQualified
self.courtCount = courtCount
@ -150,7 +147,6 @@ class Tournament : ModelObject, Storable {
federalCategory = try container.decode(TournamentCategory.self, forKey: ._federalCategory)
federalLevelCategory = try container.decode(TournamentLevel.self, forKey: ._federalLevelCategory)
federalAgeCategory = try container.decode(FederalTournamentAge.self, forKey: ._federalAgeCategory)
groupStageCourtCount = try container.decodeIfPresent(Int.self, forKey: ._groupStageCourtCount)
closedRegistrationDate = try container.decodeIfPresent(Date.self, forKey: ._closedRegistrationDate)
groupStageAdditionalQualified = try container.decode(Int.self, forKey: ._groupStageAdditionalQualified)
courtCount = try container.decode(Int.self, forKey: ._courtCount)
@ -222,7 +218,6 @@ class Tournament : ModelObject, Storable {
try container.encode(federalCategory, forKey: ._federalCategory)
try container.encode(federalLevelCategory, forKey: ._federalLevelCategory)
try container.encode(federalAgeCategory, forKey: ._federalAgeCategory)
try container.encodeIfPresent(groupStageCourtCount, forKey: ._groupStageCourtCount)
try container.encodeIfPresent(closedRegistrationDate, forKey: ._closedRegistrationDate)
try container.encode(groupStageAdditionalQualified, forKey: ._groupStageAdditionalQualified)
try container.encode(courtCount, forKey: ._courtCount)
@ -1637,7 +1632,7 @@ extension Tournament {
}
static func fake() -> Tournament {
return Tournament(event: "Roland Garros", name: "Magic P100", startDate: Date(), endDate: Date(), creationDate: Date(), isPrivate: false, groupStageFormat: .nineGames, roundFormat: nil, loserRoundFormat: nil, groupStageSortMode: .snake, groupStageCount: 4, rankSourceDate: nil, dayDuration: 2, teamCount: 24, teamSorting: .rank, federalCategory: .men, federalLevelCategory: .p100, federalAgeCategory: .a45, groupStageCourtCount: nil, closedRegistrationDate: nil, groupStageAdditionalQualified: 0, courtCount: 4, prioritizeClubMembers: false, qualifiedPerGroupStage: 2, teamsPerGroupStage: 4, entryFee: nil)
return Tournament(event: "Roland Garros", name: "Magic P100", startDate: Date(), endDate: Date(), creationDate: Date(), isPrivate: false, groupStageFormat: .nineGames, roundFormat: nil, loserRoundFormat: nil, groupStageSortMode: .snake, groupStageCount: 4, rankSourceDate: nil, dayDuration: 2, teamCount: 24, teamSorting: .rank, federalCategory: .men, federalLevelCategory: .p100, federalAgeCategory: .a45, closedRegistrationDate: nil, groupStageAdditionalQualified: 0, courtCount: 4, prioritizeClubMembers: false, qualifiedPerGroupStage: 2, teamsPerGroupStage: 4, entryFee: nil)
}
}

@ -16,4 +16,21 @@ class NavigationViewModel {
var selectedTab: TabDestination?
var agendaDestination: AgendaDestination? = .activity
var tournament: Tournament?
var organizerTournament: Tournament?
func isTournamentAlreadyOpenInOrganizer(_ tournament: Tournament) -> Bool {
organizerTournament?.id == tournament.id
}
func closeTournamentFromOrganizer(_ tournament: Tournament) {
tournament.navigationPath.removeAll()
organizerTournament = nil
}
func openTournamentInOrganizer(_ tournament: Tournament) {
organizerTournament = tournament
if selectedTab != .tournamentOrganizer {
selectedTab = .tournamentOrganizer
}
}
}

@ -69,7 +69,7 @@ class SearchViewModel: ObservableObject, Identifiable {
}
func codeClubs() -> [String] {
DataStore.shared.clubs.compactMap { $0.code }
DataStore.shared.user.clubsObjects().compactMap { $0.code }
}
func getCodeClub() -> String? {

@ -103,7 +103,7 @@ struct EventListView: View {
}
.contextMenu {
Button {
navigation.openTournamentInOrganizer(tournament)
} label: {
Label("Voir dans le gestionnaire", systemImage: "line.diagonal.arrow")
}

@ -8,21 +8,15 @@
import SwiftUI
struct TournamentButtonView: View {
@Environment(NavigationViewModel.self) private var navigation
let tournament: Tournament
@Binding var selectedId: String?
var body: some View {
Button {
if selectedId == tournament.id {
tournament.navigationPath.removeAll()
selectedId = nil
// if tournament.navigationPath.isEmpty {
// selectedId = nil
// } else {
// tournament.navigationPath.removeLast()
// }
if navigation.isTournamentAlreadyOpenInOrganizer(tournament) {
navigation.closeTournamentFromOrganizer(tournament)
} else {
selectedId = tournament.id
navigation.openTournamentInOrganizer(tournament)
}
} label: {
TournamentCellView(tournament: tournament, displayStyle: .short)
@ -34,7 +28,7 @@ struct TournamentButtonView: View {
.fixedSize(horizontal: false, vertical: true)
}
.overlay(alignment: .top) {
if selectedId == tournament.id {
if navigation.isTournamentAlreadyOpenInOrganizer(tournament) {
Image(systemName: "ellipsis")
.offset(y: -10)
}

@ -10,17 +10,13 @@ import LeStorage
struct TournamentOrganizerView: View {
@EnvironmentObject var dataStore: DataStore
@State private var selectedTournamentId: String?
@Environment(NavigationViewModel.self) private var navigation
var body: some View {
VStack(spacing: 0) {
ForEach(dataStore.tournaments) { tournament in
if tournament.id == selectedTournamentId {
OrganizedTournamentView(tournament: tournament)
}
}
if selectedTournamentId == nil {
if let tournament = navigation.organizerTournament {
OrganizedTournamentView(tournament: tournament)
} else {
NavigationStack {
let userClubsEmpty = dataStore.user.clubs.isEmpty
ContentUnavailableView(
@ -39,7 +35,7 @@ struct TournamentOrganizerView: View {
ScrollView(.horizontal) {
HStack {
ForEach(dataStore.tournaments) { tournament in
TournamentButtonView(tournament: tournament, selectedId: $selectedTournamentId)
TournamentButtonView(tournament: tournament)
}
}
.padding()
@ -48,7 +44,7 @@ struct TournamentOrganizerView: View {
}
}
.onChange(of: Store.main.currentUserUUID) {
selectedTournamentId = nil
navigation.organizerTournament = nil
}
}
}

@ -13,7 +13,7 @@ struct PlanningSettingsView: View {
@Bindable var tournament: Tournament
@Bindable var matchScheduler: MatchScheduler
@State private var groupStageCourtCount: Int
@State private var groupStageChunkCount: Int
@State private var isScheduling: Bool = false
@State private var schedulingDone: Bool = false
@State private var showOptions: Bool = false
@ -22,10 +22,11 @@ struct PlanningSettingsView: View {
self.tournament = tournament
if let matchScheduler = tournament.matchScheduler() {
self.matchScheduler = matchScheduler
self._groupStageChunkCount = State(wrappedValue: matchScheduler.groupStageChunkCount ?? 1)
} else {
self.matchScheduler = MatchScheduler(tournament: tournament.id)
self._groupStageChunkCount = State(wrappedValue: 1)
}
self._groupStageCourtCount = State(wrappedValue: tournament.groupStageCourtCount ?? 1)
}
var body: some View {
@ -48,7 +49,7 @@ struct PlanningSettingsView: View {
TournamentFieldsManagerView(localizedStringKey: "Terrains maximum", count: $tournament.courtCount)
if tournament.groupStages().isEmpty == false {
TournamentFieldsManagerView(localizedStringKey: "Nombre de poule en même temps", count: $groupStageCourtCount, max: tournament.groupStageCount)
TournamentFieldsManagerView(localizedStringKey: "Nombre de poule en même temps", count: $groupStageChunkCount, max: tournament.groupStageCount)
}
if let event = tournament.eventObject() {
@ -73,6 +74,7 @@ struct PlanningSettingsView: View {
RowButtonView("Horaire intelligent", role: .destructive) {
schedulingDone = false
await _setupSchedule()
_save()
schedulingDone = true
}
} footer: {
@ -114,9 +116,8 @@ struct PlanningSettingsView: View {
.deferredRendering(for: .seconds(2))
}
}
.onChange(of: groupStageCourtCount) {
tournament.groupStageCourtCount = groupStageCourtCount
_save()
.onChange(of: groupStageChunkCount) {
matchScheduler.groupStageChunkCount = groupStageChunkCount
}
.onChange(of: tournament.startDate) {
_save()
@ -124,9 +125,6 @@ struct PlanningSettingsView: View {
.onChange(of: tournament.courtCount) {
_save()
}
.onChange(of: tournament.groupStageCourtCount) {
_save()
}
.onChange(of: tournament.dayDuration) {
_save()
}

@ -96,7 +96,7 @@ final class ServerDataTests: XCTestCase {
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, publishTeams: true, publishSummons: true, publishGroupStages: true, publishBrackets: 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, 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)
assert(t.event == tournament.event)
@ -117,7 +117,6 @@ final class ServerDataTests: XCTestCase {
assert(t.federalCategory == tournament.federalCategory)
assert(t.federalLevelCategory == tournament.federalLevelCategory)
assert(t.federalAgeCategory == tournament.federalAgeCategory)
assert(t.groupStageCourtCount == tournament.groupStageCourtCount)
assert(t.closedRegistrationDate?.formatted() == tournament.closedRegistrationDate?.formatted())
assert(t.groupStageAdditionalQualified == tournament.groupStageAdditionalQualified)
assert(t.courtCount == tournament.courtCount)

Loading…
Cancel
Save