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.
203 lines
8.6 KiB
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())
|
|
//}
|
|
|