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/ActivityView.swift

291 lines
12 KiB

//
// ActivityView.swift
// PadelClub
//
// Created by Razmig Sarkissian on 29/02/2024.
//
import SwiftUI
struct ActivityView: View {
@EnvironmentObject var dataStore: DataStore
@Environment(NavigationViewModel.self) private var navigation
@State private var federalDataViewModel : FederalDataViewModel = .shared
@State private var searchText: String = ""
@State private var presentFilterView: Bool = false
@State private var presentToolbar: Bool = false
@State private var newTournament: Tournament?
@State private var viewStyle: AgendaDestination.ViewStyle = .list
@State private var isGatheringFederalTournaments: Bool = false
@State private var error: Error?
@State private var uuid: UUID = UUID()
var runningTournaments: [FederalTournamentHolder] {
dataStore.tournaments.filter({ $0.endDate == nil })
.filter({ federalDataViewModel.isTournamentValidForFilters($0) })
}
var endedTournaments: [Tournament] {
dataStore.tournaments.filter({ $0.endDate != nil })
.filter({ federalDataViewModel.isTournamentValidForFilters($0) })
.sorted(using: SortDescriptor(\.startDate, order: .reverse))
}
func _activityStatus() -> String? {
let tournaments = tournaments
if tournaments.isEmpty && federalDataViewModel.areFiltersEnabled() == false {
return nil
} else {
let count = tournaments.map { $0.tournaments.count }.reduce(0,+)
return "\(count) tournoi" + count.pluralSuffix
}
}
var tournaments: [FederalTournamentHolder] {
switch navigation.agendaDestination! {
case .activity:
runningTournaments
case .history:
endedTournaments
case .tenup:
federalDataViewModel.filteredFederalTournaments
}
}
var body: some View {
@Bindable var navigation = navigation
NavigationStack(path: $navigation.path) {
VStack(spacing: 0) {
GenericDestinationPickerView(selectedDestination: $navigation.agendaDestination, destinations: AgendaDestination.allCases, nilDestinationIsValid: false)
List {
switch navigation.agendaDestination! {
case .activity:
EventListView(tournaments: runningTournaments, viewStyle: viewStyle)
case .history:
EventListView(tournaments: endedTournaments, viewStyle: viewStyle)
case .tenup:
EventListView(tournaments: federalDataViewModel.federalTournaments, viewStyle: viewStyle)
.id(uuid)
}
}
.environment(federalDataViewModel)
.overlay {
if let error, navigation.agendaDestination == .tenup {
ContentUnavailableView {
Label("Erreur", systemImage: "exclamationmark")
} description: {
Text(error.localizedDescription)
} actions: {
RowButtonView("D'accord.") {
self.error = nil
}
}
} else if isGatheringFederalTournaments {
ProgressView()
} else {
if tournaments.isEmpty && viewStyle == .list {
if searchText.isEmpty == false {
ContentUnavailableView.search(text: searchText)
} else if federalDataViewModel.areFiltersEnabled() {
ContentUnavailableView {
Text("Aucun résultat")
} description: {
Text(federalDataViewModel.filterStatus())
} actions: {
RowButtonView("supprimer le filtre") {
federalDataViewModel.removeFilters()
}
}
} else {
_dataEmptyView()
}
}
}
}
//.searchable(text: $searchText)
.onAppear { presentToolbar = true }
.onDisappear { presentToolbar = false }
.sheet(item: $newTournament) { tournament in
EventCreationView(tournaments: [tournament], selectedClub: federalDataViewModel.selectedClub())
.environment(navigation)
.tint(.master)
}
.refreshable {
if navigation.agendaDestination == .tenup {
federalDataViewModel.federalTournaments.removeAll()
NetworkFederalService.shared.formId = ""
_gatherFederalTournaments()
}
}
.task {
if navigation.agendaDestination == .tenup
&& dataStore.clubs.isEmpty == false
&& federalDataViewModel.federalTournaments.isEmpty {
_gatherFederalTournaments()
}
}
.onChange(of: navigation.agendaDestination) {
if navigation.agendaDestination == .tenup
&& dataStore.clubs.isEmpty == false
&& federalDataViewModel.federalTournaments.isEmpty {
_gatherFederalTournaments()
}
}
.toolbar {
if presentToolbar {
ToolbarItem(placement: .status) {
VStack(spacing: -2) {
if federalDataViewModel.areFiltersEnabled() {
Text(federalDataViewModel.filterStatus())
}
if let _activityStatus = _activityStatus() {
Text(_activityStatus)
.foregroundStyle(.secondary)
}
}
.font(.footnote)
}
ToolbarItemGroup(placement: .topBarLeading) {
Button {
switch viewStyle {
case .list:
viewStyle = .calendar
case .calendar:
viewStyle = .list
}
} label: {
Image(systemName: "calendar.circle")
.resizable()
.scaledToFit()
.frame(minHeight: 28)
}
.symbolVariant(viewStyle == .calendar ? .fill : .none)
Button {
presentFilterView.toggle()
} label: {
Image(systemName: "line.3.horizontal.decrease.circle")
.resizable()
.scaledToFit()
.frame(minHeight: 28)
}
.symbolVariant(federalDataViewModel.areFiltersEnabled() ? .fill : .none)
}
ToolbarItem(placement: .topBarTrailing) {
Button {
newTournament = Tournament.newEmptyInstance()
} label: {
Image(systemName: "plus.circle.fill")
.resizable()
.scaledToFit()
.frame(minHeight: 28)
}
}
}
}
.navigationTitle(TabDestination.activity.title)
.navigationDestination(for: Tournament.self) { tournament in
TournamentView()
.environment(tournament)
}
.sheet(isPresented: $presentFilterView) {
TournamentFilterView(federalDataViewModel: federalDataViewModel)
.environment(navigation)
.tint(.master)
}
}
}
}
private func _gatherFederalTournaments() {
isGatheringFederalTournaments = true
Task {
do {
try await federalDataViewModel.gatherTournaments(clubs: dataStore.clubs.filter { $0.code != nil }, startDate: .now.startOfMonth)
} catch {
self.error = error
}
isGatheringFederalTournaments = false
uuid = UUID()
}
}
@ViewBuilder
private func _dataEmptyView() -> some View {
switch navigation.agendaDestination! {
case .activity:
_runningEmptyView()
case .history:
_endedEmptyView()
case .tenup:
_tenupEmptyView()
}
}
private func _runningEmptyView() -> some View {
ContentUnavailableView {
Label {
Text("Bienvenue sur Padel Club")
.font(.largeTitle)
} icon: {
Image(.padelClubLogoFondclairTransparent)
.resizable()
.scaledToFit()
.frame(width: 128)
}
} description: {
Text("Aucun événement en cours ou à venir dans votre agenda.")
} actions: {
RowButtonView("Créer un nouvel événement") {
newTournament = Tournament.newEmptyInstance()
}
RowButtonView("Importer via Tenup") {
navigation.agendaDestination = .tenup
}
}
}
private func _endedEmptyView() -> some View {
ContentUnavailableView {
Label("Aucun tournoi terminé", systemImage: "shield.slash")
} description: {
Text("Vos tournois terminés seront listés ici.")
}
}
private func _tenupEmptyView() -> some View {
if dataStore.clubs.isEmpty {
ContentUnavailableView {
Label("Aucun tournoi", systemImage: "shield.slash")
} description: {
Text("Pour voir vos tournois tenup ici, indiquez vos clubs préférés.")
} actions: {
RowButtonView("Choisir mes clubs préférés") {
navigation.selectedTab = .umpire
}
}
} else {
ContentUnavailableView {
Label("Aucun tournoi", systemImage: "shield.slash")
} description: {
Text("Aucun tournoi n'a pu être récupéré via tenup.")
} actions: {
RowButtonView("Rafraîchir") {
NetworkFederalService.shared.formId = ""
_gatherFederalTournaments()
}
}
}
}
}
#Preview {
ActivityView()
}