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/Planning/CourtAvailabilitySettingsVi...

203 lines
8.6 KiB

//
// CourtAvailabilitySettingsView.swift
// PadelClub
//
// Created by Razmig Sarkissian on 19/04/2024.
//
import SwiftUI
import LeStorage
struct CourtAvailabilitySettingsView: View {
@Environment(Tournament.self) var tournament: Tournament
@EnvironmentObject var dataStore: DataStore
let event: Event
@State private var showingPopover: Bool = false
@State private var courtIndex: Int = 0
@State private var startDate: Date = Date()
@State private var endDate: Date = Date()
@State private var editingSlot: DateInterval?
var courtsUnavailability: [Int: [DateInterval]] {
let groupedBy = Dictionary(grouping: event.courtsUnavailability, by: { dateInterval in
return dateInterval.courtIndex
})
return groupedBy
}
var body: some View {
List {
let keys = courtsUnavailability.keys.sorted()
ForEach(keys, id: \.self) { key in
if let dates = courtsUnavailability[key] {
Section {
ForEach(dates) { dateInterval in
Menu {
Button("dupliquer") {
let duplicatedDateInterval = DateInterval(event: event.id, courtIndex: (courtIndex+1)%tournament.courtCount, startDate: dateInterval.startDate, endDate: dateInterval.endDate)
do {
try dataStore.dateIntervals.addOrUpdate(instance: duplicatedDateInterval)
} catch {
Logger.error(error)
}
}
Button("éditer") {
editingSlot = dateInterval
courtIndex = dateInterval.courtIndex
startDate = dateInterval.startDate
endDate = dateInterval.endDate
showingPopover = true
}
Button("effacer", role: .destructive) {
do {
try dataStore.dateIntervals.delete(instance: dateInterval)
} catch {
Logger.error(error)
}
}
} label: {
HStack {
VStack(alignment: .leading, spacing: 0) {
Text(dateInterval.startDate.localizedTime()).font(.largeTitle)
Text(dateInterval.startDate.localizedDay()).font(.caption)
}
Spacer()
VStack {
Image(systemName: "arrowshape.forward.fill")
.tint(.master)
Text("indisponible").foregroundStyle(.red).font(.caption)
}
Spacer()
VStack(alignment: .trailing, spacing: 0) {
Text(dateInterval.endDate.localizedTime()).font(.largeTitle)
Text(dateInterval.endDate.localizedDay()).font(.caption)
}
}
}
.swipeActions {
Button(role: .destructive) {
do {
try dataStore.dateIntervals.delete(instance: dateInterval)
} catch {
Logger.error(error)
}
} label: {
LabelDelete()
}
}
}
} header: {
HStack {
Text(Court.courtIndexedTitle(atIndex: key))
Spacer()
if let courtName = tournament.courtNameIfAvailable(atIndex: key) {
Text(courtName)
}
}
}
.headerProminence(.increased)
}
}
}
.overlay {
if courtsUnavailability.isEmpty {
ContentUnavailableView {
Label("Tous les terrains sont disponibles", systemImage: "checkmark.circle.fill").tint(.green)
} description: {
Text("Vous pouvez précisez l'indisponibilité d'une ou plusieurs terrains, que ce soit pour une journée entière ou un créneau précis.")
} actions: {
RowButtonView("Ajouter une indisponibilité", systemImage: "plus.circle.fill") {
startDate = tournament.startDate
endDate = tournament.startDate.addingTimeInterval(5400)
showingPopover = true
}
}
}
}
.toolbar {
ToolbarItem(placement: .topBarTrailing) {
BarButtonView("Ajouter une indisponibilité", icon: "plus.circle.fill") {
startDate = tournament.startDate
endDate = tournament.startDate.addingTimeInterval(5400)
showingPopover = true
}
}
}
.navigationBarTitleDisplayMode(.inline)
.toolbarBackground(.visible, for: .navigationBar)
.navigationTitle("Créneau indisponible")
.sheet(isPresented: $showingPopover) {
NavigationStack {
Form {
Section {
CourtPicker(title: "Terrain", selection: $courtIndex, maxCourt: tournament.courtCount)
}
Section {
DatePicker("Début", selection: $startDate)
DatePicker("Fin", selection: $endDate)
} footer: {
FooterButtonView("jour entier") {
startDate = startDate.startOfDay
endDate = startDate.endOfDay()
}
}
}
.toolbar {
ButtonValidateView {
if editingSlot == nil {
let dateInterval = DateInterval(event: event.id, courtIndex: courtIndex, startDate: startDate, endDate: endDate)
do {
try dataStore.dateIntervals.addOrUpdate(instance: dateInterval)
} catch {
Logger.error(error)
}
} else {
editingSlot?.courtIndex = courtIndex
editingSlot?.endDate = endDate
editingSlot?.startDate = startDate
do {
try dataStore.dateIntervals.addOrUpdate(instance: editingSlot!)
} catch {
Logger.error(error)
}
}
showingPopover = false
}
}
.navigationBarTitleDisplayMode(.inline)
.toolbarBackground(.visible, for: .navigationBar)
.navigationTitle("Nouveau créneau")
.tint(.master)
}
.onAppear {
UIDatePicker.appearance().minuteInterval = 5
}
.onDisappear {
UIDatePicker.appearance().minuteInterval = 1
}
}
}
}
struct CourtPicker: View {
@Environment(Tournament.self) var tournament: Tournament
let title: String
@Binding var selection: Int
let maxCourt: Int
var body: some View {
Picker(title, selection: $selection) {
ForEach(0..<maxCourt, id: \.self) {
Text(tournament.courtName(atIndex: $0))
}
}
}
}
//#Preview {
// CourtAvailabilitySettingsView(event: Event.mock())
//}