You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
PadelClub/PadelClub/Views/Navigation/Agenda/CalendarView.swift

188 lines
8.1 KiB

//
// CalendarView.swift
// PadelClub
//
// Created by Razmig Sarkissian on 01/03/2024.
//
import SwiftUI
import LeStorage
struct CalendarView: View {
@EnvironmentObject var dataStore: DataStore
@Environment(NavigationViewModel.self) var navigation: NavigationViewModel
@Environment(FederalDataViewModel.self) var federalDataViewModel: FederalDataViewModel
let date: Date
let tournaments: [FederalTournamentHolder]
let daysOfWeek = Date.capitalizedFirstLettersOfWeekdays
let columns = Array(repeating: GridItem(.flexible()), count: 7)
let color = Color.master
@State private var days: [Date] = []
@State private var counts = [Int : Int]()
@State private var newTournament: Tournament?
@ViewBuilder
var body: some View {
VStack {
HStack {
ForEach(daysOfWeek.indices, id: \.self) { index in
Text(daysOfWeek[index])
.fontWeight(.black)
.foregroundStyle(color)
.frame(maxWidth: .infinity)
}
}
LazyVGrid(columns: columns) {
ForEach(days, id: \.self) { day in
_dayView(day)
}
}
}
.sheet(item: $newTournament) { tournament in
EventCreationView(startingDate: tournament.startDate, tournaments: [tournament], selectedClub: federalDataViewModel.selectedClub())
.environment(navigation)
.tint(.master)
}
.onAppear {
days = date.calendarDisplayDays
setupCounts()
}
.onChange(of: date) {
days = date.calendarDisplayDays
setupCounts()
}
}
@ViewBuilder
private func _dayView(_ day: Date) -> some View {
if day.monthInt != date.monthInt {
Text("")
} else {
Menu {
Button("Créer un tournoi") {
let tournament = Tournament.newEmptyInstance()
tournament.startDate = day.atNine()
if federalDataViewModel.categories.isEmpty == false {
tournament.tournamentCategory = federalDataViewModel.categories.first!
}
if federalDataViewModel.levels.isEmpty == false {
tournament.tournamentLevel = federalDataViewModel.levels.first!
}
if federalDataViewModel.ageCategories.isEmpty == false {
tournament.federalTournamentAge = federalDataViewModel.ageCategories.first!
}
newTournament = tournament
}
Divider()
let tournamentsByDay = tournaments.filter { day.dayInt >= $0.startDate.dayInt && day.dayInt < $0.startDate.dayInt + $0.dayDuration }
ForEach(tournamentsByDay, id: \.holderId) { tournamentHolder in
if let tournament = tournamentHolder as? Tournament {
Section {
Button(tournament.tournamentTitle(.short)) {
navigation.path.append(tournament)
}
} header: {
Text("sur " + tournament.dayDuration.formatted() + " jour" + tournament.dayDuration.pluralSuffix)
}
} else if let tournament = tournamentHolder as? FederalTournament {
Menu {
ForEach(tournament.tournaments, id: \.id) { build in
if federalDataViewModel.isFederalTournamentValidForFilters(tournament, build: build) {
if navigation.agendaDestination == .around {
NavigationLink(build.buildHolderTitle()) {
TournamentSubscriptionView(federalTournament: tournament, build: build, user: dataStore.user)
}
} else {
Button(build.buildHolderTitle()) {
_createOrShow(federalTournament: tournament, existingTournament: event(forTournament: tournament)?.existingBuild(build), build: build)
}
}
}
}
} label: {
Text(tournament.clubLabel())
Text("sur " + tournament.dayDuration.formatted() + " jour" + tournament.dayDuration.pluralSuffix)
}
}
}
} label: {
Text(day.formatted(.dateTime.day()))
.fontWeight(.bold)
.foregroundStyle((counts[day.dayInt] != nil ? Color.white : Color.black))
.frame(maxWidth: .infinity, minHeight: 40)
.background(
Circle()
.foregroundStyle(
Date.now.startOfDay == day.startOfDay
? (counts[day.dayInt] != nil ? Color.logoRed : Color.green)
: (counts[day.dayInt] != nil ? Color.master : Color.beige)
)
)
.overlay(alignment: .bottomTrailing) {
if let count = counts[day.dayInt] {
Image(systemName: count <= 50 ? "\(count).circle.fill" : "plus.circle.fill")
.foregroundColor(.secondary)
.imageScale(.medium)
.background (
Color(.systemBackground)
.clipShape(.circle)
)
.offset(x: 5, y: 5)
}
}
}
.buttonStyle(.plain)
}
}
func setupCounts() {
let filteredTournaments = tournaments
let mappedItems = filteredTournaments.flatMap { tournamentHolder in
(0..<tournamentHolder.dayDuration).map({ dayDuration in
(tournamentHolder.startDate.dayInt + dayDuration, tournamentHolder.tournaments.count)
})
}
counts = Dictionary(mappedItems, uniquingKeysWith: +)
}
func event(forTournament tournament: FederalTournamentHolder) -> Event? {
guard let federalTournament = tournament as? FederalTournament else { return nil }
return dataStore.events.first(where: { $0.tenupId == federalTournament.id.string })
}
private func _createOrShow(federalTournament: FederalTournament, existingTournament: Tournament?, build: any TournamentBuildHolder) {
if let existingTournament {
navigation.agendaDestination = .activity
navigation.path.append(existingTournament)
} else {
let event = federalTournament.getEvent()
let newTournament = Tournament.newEmptyInstance()
newTournament.event = event.id
//todo
//newTournament.umpireMail()
//newTournament.jsonData = jsonData
newTournament.tournamentLevel = build.level
newTournament.tournamentCategory = build.category
newTournament.federalTournamentAge = build.age
newTournament.dayDuration = federalTournament.dayDuration
newTournament.startDate = federalTournament.startDate.atBeginningOfDay(hourInt: 9)
newTournament.setupFederalSettings()
do {
try dataStore.tournaments.addOrUpdate(instance: newTournament)
} catch {
Logger.error(error)
}
navigation.path.append(newTournament)
}
}
}
//#Preview {
// CalendarView(date: .now, tournaments: [])
//}