setup final clubs management

multistore
Razmig Sarkissian 2 years ago
parent 963d110f23
commit a61e16123c
  1. 2
      PadelClub.xcodeproj/project.pbxproj
  2. 38
      PadelClub/Data/Club.swift
  3. 2
      PadelClub/Data/Event.swift
  4. 17
      PadelClub/Data/Federal/FederalTournament.swift
  5. 6
      PadelClub/Data/Tournament.swift
  6. 9
      PadelClub/Data/User.swift
  7. 1
      PadelClub/Utils/DisplayContext.swift
  8. 6
      PadelClub/ViewModel/MatchScheduler.swift
  9. 3
      PadelClub/ViewModel/NavigationViewModel.swift
  10. 10
      PadelClub/ViewModel/TabDestination.swift
  11. 44
      PadelClub/Views/Calling/CallMessageCustomizationView.swift
  12. 124
      PadelClub/Views/Club/ClubDetailView.swift
  13. 3
      PadelClub/Views/Club/ClubRowView.swift
  14. 31
      PadelClub/Views/Club/ClubSearchView.swift
  15. 37
      PadelClub/Views/Club/ClubsView.swift
  16. 24
      PadelClub/Views/Club/CreateClubView.swift
  17. 25
      PadelClub/Views/Event/EventCreationView.swift
  18. 47
      PadelClub/Views/Navigation/Agenda/ActivityView.swift
  19. 6
      PadelClub/Views/Navigation/Agenda/CalendarView.swift
  20. 5
      PadelClub/Views/Navigation/Agenda/EventListView.swift
  21. 32
      PadelClub/Views/Navigation/MainView.swift
  22. 4
      PadelClub/Views/Navigation/Ongoing/OngoingView.swift
  23. 2
      PadelClub/Views/Navigation/Toolbox/PadelClubView.swift
  24. 7
      PadelClub/Views/Navigation/Toolbox/ToolboxView.swift
  25. 48
      PadelClub/Views/Navigation/Umpire/UmpireView.swift
  26. 2
      PadelClub/Views/Planning/PlanningSettingsView.swift
  27. 33
      PadelClub/Views/Shared/TournamentFilterView.swift
  28. 16
      PadelClub/Views/Tournament/Screen/Components/TournamentClubSettingsView.swift
  29. 24
      PadelClub/Views/Tournament/Screen/InscriptionManagerView.swift

@ -896,7 +896,6 @@
isa = PBXGroup;
children = (
FF59FFB62B90EFBF0061EFF9 /* MainView.swift */,
FFD783FE2B91BA42000F62A6 /* PadelClubView.swift */,
FFD783FB2B91B919000F62A6 /* Agenda */,
FF3F74FA2B91A04B004CFE0E /* Organizer */,
FF3F74FB2B91A060004CFE0E /* Toolbox */,
@ -963,6 +962,7 @@
FF025AE62BD1111000A86CF8 /* GlobalSettingsView.swift */,
FF025AEE2BD1AE9400A86CF8 /* DurationSettingsView.swift */,
FF025AF02BD1AEBD00A86CF8 /* MatchFormatStorageView.swift */,
FFD783FE2B91BA42000F62A6 /* PadelClubView.swift */,
);
path = Toolbox;
sourceTree = "<group>";

@ -111,4 +111,42 @@ extension Club {
guard let code else { return nil }
return URL(string: "https://tenup.fft.fr/club/\(code)")
}
func update(fromClub club: Club) {
self.acronym = club.acronym
self.name = club.name
self.phone = club.phone
self.code = club.code
self.address = club.address
self.city = club.city
self.zipCode = club.zipCode
self.latitude = club.latitude
self.longitude = club.longitude
}
func hasBeenCreated(by creatorId: String?) -> Bool {
guard let creatorId else { return false }
guard let creator else { return false }
return creatorId == creator
}
func isFavorite() -> Bool {
DataStore.shared.user?.clubs?.contains(where: { $0 == id }) == true
}
static func findOrCreate(name: String, code: String?, city: String? = nil, zipCode: String? = nil) -> Club {
/*
identify a club : code, name, ??
*/
let clubs: [Club] = Store.main.filter(isIncluded: { (code == nil && $0.name == name && $0.city == city && $0.zipCode == zipCode) || $0.code == code })
if clubs.isEmpty == false {
return clubs.first!
} else {
return Club(creator: DataStore.shared.user?.id, name: name, code: code)
}
}
}

@ -37,7 +37,7 @@ class Event: ModelObject, Storable {
// self.loserRoundFormat = loserRoundFormat
}
var clubObject: Club? {
func clubObject() -> Club? {
guard let club else { return nil }
return Store.main.findById(club)
}

@ -5,6 +5,7 @@
import Foundation
import CoreLocation
import LeStorage
enum DayPeriod {
case all
@ -18,14 +19,22 @@ struct FederalTournament: Identifiable, Codable {
func getEvent() -> Event {
var club = DataStore.shared.clubs.first(where: { $0.code == codeClub })
if club == nil {
club = Club(name: clubLabel(), code: codeClub)
try? DataStore.shared.clubs.addOrUpdate(instance: club!)
club = Club.findOrCreate(name: clubLabel(), code: codeClub)
do {
try DataStore.shared.clubs.addOrUpdate(instance: club!)
} catch {
Logger.error(error)
}
}
var event = DataStore.shared.events.first(where: { $0.tenupId == id.string })
if event == nil {
event = Event(club: club?.id, name: libelle, tenupId: id.string)
try? DataStore.shared.events.addOrUpdate(instance: event!)
event = Event(creator: DataStore.shared.user?.id, club: club?.id, name: libelle, tenupId: id.string)
do {
try DataStore.shared.events.addOrUpdate(instance: event!)
} catch {
Logger.error(error)
}
}
return event!
}

@ -290,7 +290,7 @@ class Tournament : ModelObject, Storable {
startDate <= Date()
}
var eventObject: Event? {
func eventObject() -> Event? {
guard let event else { return nil }
return Store.main.findById(event)
}
@ -301,7 +301,7 @@ class Tournament : ModelObject, Storable {
}
func club() -> Club? {
eventObject?.clubObject
eventObject()?.clubObject()
}
func locationLabel(_ displayStyle: DisplayStyle = .wide) -> String {
@ -656,7 +656,7 @@ class Tournament : ModelObject, Storable {
//todo
var clubName: String? {
eventObject?.clubObject?.name
eventObject()?.clubObject()?.name
}
//todo

@ -57,6 +57,15 @@ class User: UserBase, Storable {
return try? federalContext.fetch(fetchRequest).first
}
func hasClubs() -> Bool {
clubs?.isEmpty == false
}
func clubsObjects(includeCreated: Bool = false) -> [Club] {
guard let clubs else { return [] }
return Store.main.filter(isIncluded: { (includeCreated && $0.creator == id) || clubs.contains($0.id) })
}
enum CodingKeys: String, CodingKey {
case _id = "id"
case _username = "username"

@ -10,6 +10,7 @@ import Foundation
enum DisplayContext {
case addition
case edition
case lockedForEditing
}
enum DisplayStyle {

@ -99,7 +99,7 @@ class MatchScheduler {
let groupStageCourtCount = tournament.groupStageCourtCount ?? 1
let groupStages = tournament.groupStages()
let numberOfCourtsAvailablePerRotation: Int = tournament.courtCount
courtsUnavailability = tournament.eventObject?.courtsUnavailability
courtsUnavailability = tournament.eventObject()?.courtsUnavailability
let matches = groupStages.flatMap({ $0._matches() })
matches.forEach({
@ -502,7 +502,7 @@ class MatchScheduler {
}
func updateBracketSchedule(tournament: Tournament, fromRoundId roundId: String?, fromMatchId matchId: String?, startDate: Date) {
courtsUnavailability = tournament.eventObject?.courtsUnavailability
courtsUnavailability = tournament.eventObject()?.courtsUnavailability
let upperRounds = tournament.rounds()
let allMatches = tournament.allMatches()
@ -607,7 +607,7 @@ class MatchScheduler {
}
func updateSchedule(tournament: Tournament) {
courtsUnavailability = tournament.eventObject?.courtsUnavailability
courtsUnavailability = tournament.eventObject()?.courtsUnavailability
let lastDate = updateGroupStageSchedule(tournament: tournament)
updateBracketSchedule(tournament: tournament, fromRoundId: nil, fromMatchId: nil, startDate: lastDate)
}

@ -10,6 +10,9 @@ import SwiftUI
@Observable
class NavigationViewModel {
var path = NavigationPath()
var toolboxPath = NavigationPath()
var umpirePath = NavigationPath()
var ongoingPath = NavigationPath()
var selectedTab: TabDestination?
var agendaDestination: AgendaDestination? = .activity
var tournament: Tournament?

@ -13,19 +13,15 @@ enum TabDestination: CaseIterable, Identifiable {
}
case activity
case eventList
case toolbox
case tournamentOrganizer
case umpire
case padelClub
case ongoing
var title: String {
switch self {
case .activity:
return "Activité"
case .eventList:
return "Journal"
case .ongoing:
return "En cours"
case .toolbox:
@ -34,8 +30,6 @@ enum TabDestination: CaseIterable, Identifiable {
return "Gestionnaire"
case .umpire:
return "Juge-Arbitre"
case .padelClub:
return "Padel Club"
}
}
@ -43,8 +37,6 @@ enum TabDestination: CaseIterable, Identifiable {
switch self {
case .activity:
return "calendar.day.timeline.left"
case .eventList:
return "book.closed"
case .ongoing:
return "figure.tennis"
case .toolbox:
@ -53,8 +45,6 @@ enum TabDestination: CaseIterable, Identifiable {
return "squares.below.rectangle"
case .umpire:
return "person.bust"
case .padelClub:
return "shield"
}
}
}

@ -6,6 +6,7 @@
//
import SwiftUI
import LeStorage
struct CallMessageCustomizationView: View {
@EnvironmentObject var dataStore: DataStore
@ -69,20 +70,9 @@ struct CallMessageCustomizationView: View {
} header: {
Text("Signature du message")
}
Section {
TextField("Nom du club", text: $customClubName)
.autocorrectionDisabled()
.onSubmit {
if let eventClub = tournament.eventObject?.clubObject {
eventClub.name = customClubName
try? dataStore.clubs.addOrUpdate(instance: eventClub)
}
}
} header: {
Text("Nom du club")
}
_clubNameView()
Section {
if appSettings.callUseFullCustomMessage {
Text(self.computedFullCustomMessage())
@ -174,6 +164,32 @@ struct CallMessageCustomizationView: View {
private func _save() {
dataStore.updateSettings()
}
@ViewBuilder
private func _clubNameView() -> some View {
if let eventClub = tournament.eventObject()?.clubObject() {
let hasBeenCreated: Bool = eventClub.hasBeenCreated(by: dataStore.user?.id)
Section {
TextField("Nom du club", text: $customClubName)
.autocorrectionDisabled()
.onSubmit {
eventClub.name = customClubName
do {
try dataStore.clubs.addOrUpdate(instance: eventClub)
} catch {
Logger.error(error)
}
}
.disabled(hasBeenCreated == false)
} header: {
Text("Nom du club")
} footer: {
if hasBeenCreated == false {
Text("Édition impossible, vous n'êtes pas le créateur de ce club.").foregroundStyle(.logoRed)
}
}
}
}
func computedFullCustomMessage() -> String {
var text = customCallMessageBody.replacingOccurrences(of: "#titre", with: tournament.tournamentTitle())

@ -14,12 +14,15 @@ struct ClubDetailView: View {
@EnvironmentObject var dataStore: DataStore
@FocusState var focusedField: Club.CodingKeys?
@State private var acronymMode: Club.AcronymMode = .automatic
@State private var updateClubData: Bool = false
init(club: Club, displayContext: DisplayContext = .edition) {
@State private var city: String
@State private var zipCode: String
init(club: Club, displayContext: DisplayContext) {
_club = Bindable(club)
self.displayContext = displayContext
_acronymMode = State(wrappedValue: club.shortNameMode())
_city = State(wrappedValue: club.city ?? "")
_zipCode = State(wrappedValue: club.zipCode ?? "")
}
var body: some View {
@ -87,31 +90,51 @@ struct ClubDetailView: View {
club.acronym = ""
}
}
} footer: {
Text("Vous pouvez personaliser le nom court ou laisser celui généré par défaut. Le nom court est utile au niveau des liens de diffusions.")
}
if club.code == nil || updateClubData {
Section {
NavigationLink {
ClubSearchView(displayContext: .edition, club: club)
} label: {
Label("Chercher dans la base fédérale", systemImage: "magnifyingglass")
if club.code == nil {
VStack(alignment: .leading, spacing: 0) {
Text("Ville").foregroundStyle(.secondary).font(.caption)
TextField("Ville", text: $city)
.fixedSize()
.focused($focusedField, equals: ._city)
.submitLabel( displayContext == .addition ? .next : .done)
.onSubmit {
if displayContext == .addition {
focusedField = ._zipCode
}
club.city = city
}
}
} footer: {
if club.code != nil {
HStack {
Spacer()
Button("annuler", role: .cancel) {
updateClubData = false
.onTapGesture {
focusedField = ._city
}
VStack(alignment: .leading, spacing: 0) {
Text("Code Postal").foregroundStyle(.secondary).font(.caption)
TextField("Code Postal", text: $zipCode)
.fixedSize()
.focused($focusedField, equals: ._zipCode)
.submitLabel( displayContext == .addition ? .next : .done)
.onSubmit {
club.zipCode = zipCode
}
}
} else {
Text("Vous pouvez chercher un club dans la base fédérale et importer les informations directement.")
}
.onTapGesture {
focusedField = ._zipCode
}
}
} footer: {
if displayContext == .lockedForEditing {
Text("Édition impossible, vous n'êtes pas le créateur de ce club.").foregroundStyle(.logoRed)
} else {
Text("Vous pouvez personaliser le nom court ou laisser celui généré par défaut.")
}
} else if let federalLink = club.federalLink() {
}
.disabled(displayContext == .lockedForEditing)
if let federalLink = club.federalLink() {
Section {
LabeledContent("Code Club") {
Text(club.code ?? "")
@ -119,14 +142,24 @@ struct ClubDetailView: View {
LabeledContent("Ville") {
Text(club.city ?? "")
}
LabeledContent("Code Postal") {
Text(club.zipCode ?? "")
}
Link(destination: federalLink) {
Text("Fiche du club sur tenup")
}
} footer: {
HStack {
Spacer()
Button("modifier", role: .destructive) {
updateClubData = true
}
}
if displayContext == .edition {
Section {
RowButtonView("Supprimer ce club", role: .destructive) {
do {
try dataStore.clubs.deleteById(club.id)
dataStore.user?.clubs?.removeAll(where: { $0 == club.id })
try dataStore.userStorage.update()
} catch {
Logger.error(error)
}
}
}
@ -135,27 +168,36 @@ struct ClubDetailView: View {
.keyboardType(.alphabet)
.autocorrectionDisabled()
.defaultFocus($focusedField, ._name, priority: .automatic)
.navigationTitle(displayContext == .edition ? club.name : "Nouveau club")
.navigationTitle(displayContext == .addition ? "Nouveau club" : club.name)
.navigationBarTitleDisplayMode(.inline)
.toolbar(.visible, for: .navigationBar)
.toolbarBackground(.visible, for: .navigationBar)
.toolbar {
ToolbarItem(placement: .topBarTrailing) {
Button {
do {
dataStore.user?.clubs?.removeAll(where: { $0.id == club.id })
try dataStore.userStorage.update()
} catch {
Logger.error(error)
if displayContext == .edition || displayContext == .lockedForEditing {
let isFavorite = club.isFavorite()
ToolbarItem(placement: .topBarTrailing) {
BarButtonView("Favori", icon: isFavorite ? "start" : "star.fill") {
do {
if isFavorite {
dataStore.user?.clubs?.removeAll(where: { $0 == club.id })
} else {
dataStore.user?.clubs?.append(club.id)
}
try dataStore.userStorage.update()
} catch {
Logger.error(error)
}
}
} label: {
LabelDelete()
}
}
}
.onDisappear {
if displayContext == .edition {
try? dataStore.clubs.addOrUpdate(instance: club)
do {
try dataStore.clubs.addOrUpdate(instance: club)
} catch {
Logger.error(error)
}
}
}
.onAppear {
@ -169,5 +211,5 @@ struct ClubDetailView: View {
}
#Preview {
ClubDetailView(club: Club.mock())
ClubDetailView(club: Club.mock(), displayContext: .edition)
}

@ -12,7 +12,8 @@ struct ClubRowView: View {
var body: some View {
LabeledContent {
Image(systemName: club.isFavorite() ? "star.fill" : "star")
.foregroundStyle(club.isFavorite() ? .green : .logoRed)
} label: {
Text(club.name)
Text(club.acronym)

@ -9,6 +9,7 @@ import SwiftUI
import CoreLocation
import CoreLocationUI
import TipKit
import LeStorage
struct ClubSearchView: View {
@Environment(\.dismiss) private var dismiss
@ -81,17 +82,29 @@ struct ClubSearchView: View {
Section {
ForEach(_filteredClubs()) { clubMark in
Button {
let clubToEdit = club ?? Club(name: clubMark.nom)
if clubToEdit.name.isEmpty {
clubToEdit.name = clubMark.nom
clubToEdit.acronym = clubToEdit.automaticShortName()
let clubToEdit = club ?? Club.findOrCreate(name: clubMark.nom, code: clubMark.clubID)
if clubToEdit.creator == dataStore.user?.id && dataStore.user?.id != nil {
if clubToEdit.name.isEmpty {
clubToEdit.name = clubMark.nom
clubToEdit.acronym = clubToEdit.automaticShortName()
}
clubToEdit.code = clubMark.clubID
clubToEdit.latitude = clubMark.lat
clubToEdit.longitude = clubMark.lng
clubToEdit.city = clubMark.ville
}
clubToEdit.code = clubMark.clubID
clubToEdit.latitude = clubMark.lat
clubToEdit.longitude = clubMark.lng
clubToEdit.city = clubMark.ville
if displayContext == .addition {
try? dataStore.clubs.addOrUpdate(instance: clubToEdit)
do {
try dataStore.clubs.addOrUpdate(instance: clubToEdit)
if dataStore.user?.clubs?.contains(where: { $0 == clubToEdit.id }) == false {
dataStore.user?.clubs?.append(clubToEdit.id)
try dataStore.userStorage.update()
}
} catch {
Logger.error(error)
}
}
dismiss()
} label: {

@ -7,6 +7,7 @@
import SwiftUI
import TipKit
import LeStorage
struct ClubsView: View {
@EnvironmentObject var dataStore: DataStore
@ -18,15 +19,15 @@ struct ClubsView: View {
var body: some View {
List {
if dataStore.clubs.isEmpty == false && selection == nil {
Section {
TipView(tip)
.tipStyle(tint: nil)
}
}
ForEach(dataStore.clubs) { club in
//
// if dataStore.clubs.isEmpty == false && selection == nil {
// Section {
// TipView(tip)
// .tipStyle(tint: nil)
// }
// }
let clubs : [Club] = (dataStore.user?.clubsObjects(includeCreated: true)) ?? []
ForEach(clubs) { club in
if let selection {
Button {
selection(club)
@ -39,22 +40,22 @@ struct ClubsView: View {
.buttonStyle(.plain)
} else {
NavigationLink {
ClubDetailView(club: club)
ClubDetailView(club: club, displayContext: club.hasBeenCreated(by: dataStore.user?.id) ? .edition : .lockedForEditing)
} label: {
ClubRowView(club: club)
}
.swipeActions(edge: .trailing, allowsFullSwipe: true) {
Button(role: .destructive) {
try? dataStore.clubs.delete(instance: club)
} label: {
LabelDelete()
}
}
// .swipeActions(edge: .trailing, allowsFullSwipe: true) {
// Button(role: .destructive) {
// try? dataStore.clubs.delete(instance: club)
// } label: {
// LabelDelete()
// }
// }
}
}
}
.overlay {
if dataStore.clubs.isEmpty {
if dataStore.user == nil || dataStore.user?.hasClubs() == true {
ContentUnavailableView {
Label("Aucun club", systemImage: "house.and.flag.fill")
} description: {

@ -6,6 +6,7 @@
//
import SwiftUI
import LeStorage
struct CreateClubView: View {
@Bindable var club: Club
@ -28,7 +29,28 @@ struct CreateClubView: View {
}
ToolbarItem(placement: .confirmationAction) {
ButtonValidateView {
try? dataStore.clubs.addOrUpdate(instance: club)
let existingOrCreatedClub = Club.findOrCreate(name: club.name, code: club.code, city: club.city, zipCode: club.zipCode)
//update existing club if rights ok / freshly created club with data input from user
if existingOrCreatedClub.hasBeenCreated(by: dataStore.user?.id) {
existingOrCreatedClub.update(fromClub: club)
do {
try dataStore.clubs.addOrUpdate(instance: existingOrCreatedClub)
} catch {
Logger.error(error)
}
}
//save into user
do {
if dataStore.user?.clubs?.contains(where: { $0 == existingOrCreatedClub.id }) == false {
dataStore.user?.clubs?.append(existingOrCreatedClub.id)
try dataStore.userStorage.update()
}
} catch {
Logger.error(error)
}
dismiss()
}
.disabled(club.isValid == false)

@ -7,6 +7,7 @@
import SwiftUI
import TipKit
import LeStorage
struct EventCreationView: View {
@Environment(\.dismiss) private var dismiss
@ -89,15 +90,18 @@ struct EventCreationView: View {
Section {
RowButtonView("Valider") {
if tournaments.count > 1 || eventName.trimmed.isEmpty == false || selectedClub != nil {
let event = Event(name: eventName)
event.club = selectedClub?.id
tournaments.forEach { tournament in
tournament.event = event.id
}
try? dataStore.events.addOrUpdate(instance: event)
let event = Event(creator: dataStore.user?.id, name: eventName)
event.club = selectedClub?.id
tournaments.forEach { tournament in
tournament.event = event.id
}
do {
try dataStore.events.addOrUpdate(instance: event)
} catch {
Logger.error(error)
}
tournaments.forEach { tournament in
tournament.courtCount = selectedClub?.courts.count ?? 2
tournament.startDate = startingDate
@ -105,7 +109,12 @@ struct EventCreationView: View {
tournament.setupFederalSettings()
}
try? dataStore.tournaments.addOrUpdate(contentOfs: tournaments)
do {
try dataStore.tournaments.addOrUpdate(contentOfs: tournaments)
} catch {
Logger.error(error)
}
dismiss()
navigation.path.append(tournaments.first!)
}

@ -113,43 +113,45 @@ struct ActivityView: View {
.environment(navigation)
.tint(.master)
}
.refreshable {
if navigation.agendaDestination == .tenup {
federalDataViewModel.federalTournaments.removeAll()
NetworkFederalService.shared.formId = ""
_gatherFederalTournaments()
}
}
// .refreshable {
// if navigation.agendaDestination == .tenup {
// federalDataViewModel.federalTournaments.removeAll()
// NetworkFederalService.shared.formId = ""
// _gatherFederalTournaments()
// }
// }
.task {
if navigation.agendaDestination == .tenup
&& dataStore.clubs.isEmpty == false
&& dataStore.user?.hasClubs() == false
&& federalDataViewModel.federalTournaments.isEmpty {
_gatherFederalTournaments()
}
}
.onChange(of: navigation.agendaDestination) {
if navigation.agendaDestination == .tenup
&& dataStore.clubs.isEmpty == false
&& dataStore.user?.hasClubs() == 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)
let _activityStatus = _activityStatus()
if federalDataViewModel.areFiltersEnabled() || _activityStatus != nil {
ToolbarItem(placement: .status) {
VStack(spacing: -2) {
if federalDataViewModel.areFiltersEnabled() {
Text(federalDataViewModel.filterStatus())
}
if let _activityStatus {
Text(_activityStatus)
.foregroundStyle(.secondary)
}
}
.font(.footnote)
}
.font(.footnote)
}
ToolbarItemGroup(placement: .topBarLeading) {
Button {
switch viewStyle {
@ -212,7 +214,8 @@ struct ActivityView: View {
isGatheringFederalTournaments = true
Task {
do {
try await federalDataViewModel.gatherTournaments(clubs: dataStore.clubs.filter { $0.code != nil }, startDate: .now.startOfMonth)
let clubs : [Club] = (dataStore.user?.clubsObjects()) ?? []
try await federalDataViewModel.gatherTournaments(clubs: clubs.filter { $0.code != nil }, startDate: .now.startOfMonth)
} catch {
self.error = error
}
@ -250,7 +253,7 @@ struct ActivityView: View {
RowButtonView("Créer un nouvel événement") {
newTournament = Tournament.newEmptyInstance()
}
if dataStore.clubs.isEmpty {
if dataStore.user == nil || dataStore.user?.hasClubs() == true {
RowButtonView("Chercher l'un de vos clubs") {
presentClubSearchView = true
}
@ -271,7 +274,7 @@ struct ActivityView: View {
}
private func _tenupEmptyView() -> some View {
if dataStore.clubs.isEmpty {
if dataStore.user == nil || dataStore.user?.hasClubs() == true {
ContentUnavailableView {
Label("Aucun tournoi", systemImage: "shield.slash")
} description: {

@ -109,14 +109,14 @@ struct CalendarView: View {
} label: {
Text(day.formatted(.dateTime.day()))
.fontWeight(.bold)
.foregroundStyle(.white)
.foregroundStyle((counts[day.dayInt] != nil ? Color.white : Color.black))
.frame(maxWidth: .infinity, minHeight: 40)
.background(
Circle()
.foregroundStyle(
Date.now.startOfDay == day.startOfDay
? .green.opacity(counts[day.dayInt] != nil ? 0.8 : 0.3)
: color.opacity(counts[day.dayInt] != nil ? 0.8 : 0.3)
? (counts[day.dayInt] != nil ? Color.logoRed : Color.green)
: (counts[day.dayInt] != nil ? Color.master : Color.beige)
)
)
.overlay(alignment: .bottomTrailing) {

@ -51,7 +51,7 @@ struct EventListView: View {
.headerProminence(.increased)
.task {
if navigation.agendaDestination == .tenup
&& dataStore.clubs.isEmpty == false
&& dataStore.user?.hasClubs() == false
&& _tournaments.isEmpty {
_gatherFederalTournaments(startDate: section)
}
@ -64,7 +64,8 @@ struct EventListView: View {
// isGatheringFederalTournaments = true
Task {
do {
try await federalDataViewModel.gatherTournaments(clubs: dataStore.clubs.filter { $0.code != nil }, startDate: startDate, endDate: startDate.endOfMonth)
let clubs : [Club] = (dataStore.user?.clubsObjects()) ?? []
try await federalDataViewModel.gatherTournaments(clubs: clubs.filter { $0.code != nil }, startDate: startDate, endDate: startDate.endOfMonth)
} catch {
Logger.error(error)
// self.error = error

@ -20,16 +20,32 @@ struct MainView: View {
dataStore.appSettings.lastDataSource
}
@Environment(\.managedObjectContext) private var viewContext
@FetchRequest(
sortDescriptors: [],
animation: .default)
private var players: FetchedResults<ImportedPlayer>
var selectedTabHandler: Binding<TabDestination?> { Binding(
get: { navigation.selectedTab },
set: {
if $0 == navigation.selectedTab {
// switch navigation.selectedTab {
// case .activity:
// navigation.path.removeLast()
// case .toolbox:
// navigation.toolboxPath = NavigationPath()
// case .umpire:
// navigation.umpirePath = NavigationPath()
// case .ongoing:
// navigation.ongoingPath = NavigationPath()
// case .tournamentOrganizer:
// break
// case .none:
// break
// }
} else {
navigation.selectedTab = $0
}
}
)}
var body: some View {
@Bindable var navigation = navigation
TabView(selection: $navigation.selectedTab) {
TabView(selection: selectedTabHandler) {
ActivityView()
.tabItem(for: .activity)
TournamentOrganizerView()

@ -8,6 +8,7 @@
import SwiftUI
struct OngoingView: View {
@Environment(NavigationViewModel.self) private var navigation: NavigationViewModel
@EnvironmentObject var dataStore: DataStore
var matches: [Match] {
@ -15,7 +16,8 @@ struct OngoingView: View {
}
var body: some View {
NavigationStack {
@Bindable var navigation = navigation
NavigationStack(path: $navigation.ongoingPath) {
List {
ForEach(matches) { match in
MatchRowView(match: match, matchViewStyle: .feedStyle)

@ -96,7 +96,7 @@ struct PadelClubView: View {
}
}
.headerProminence(.increased)
.navigationTitle(TabDestination.padelClub.title)
.navigationTitle("Source des données fédérales")
}
@ViewBuilder

@ -8,10 +8,13 @@
import SwiftUI
struct ToolboxView: View {
@Environment(NavigationViewModel.self) private var navigation: NavigationViewModel
var body: some View {
NavigationStack {
@Bindable var navigation = navigation
NavigationStack(path: $navigation.toolboxPath) {
List {
Section {
Section {
NavigationLink {
SelectablePlayerListView()
} label: {

@ -7,8 +7,10 @@
import SwiftUI
import CoreLocation
import LeStorage
struct UmpireView: View {
@Environment(NavigationViewModel.self) private var navigation: NavigationViewModel
@EnvironmentObject var dataStore: DataStore
var lastDataSource: String? {
dataStore.appSettings.lastDataSource
@ -24,7 +26,8 @@ struct UmpireView: View {
}
var body: some View {
NavigationStack {
@Bindable var navigation = navigation
NavigationStack(path: $navigation.umpirePath) {
List {
PurchaseListView()
@ -57,14 +60,19 @@ struct UmpireView: View {
SelectablePlayerListView(allowSelection: 1, playerSelectionAction: { players in
if let player = players.first {
user.licenceId = player.license
let club = dataStore.clubs.first(where: { $0.code == player.clubCode }) ?? Club(name: player.clubName!, code: player.clubCode!)
try? dataStore.clubs.addOrUpdate(instance: club)
if user.clubs == nil {
user.clubs = [club.id]
} else {
user.clubs!.insert(club.id, at: 0)
let userClub = Club.findOrCreate(name: player.clubName!, code: player.clubCode)
do {
try dataStore.clubs.addOrUpdate(instance: userClub)
if user.clubs == nil {
user.clubs = [userClub.id]
} else {
user.clubs!.insert(userClub.id, at: 0)
}
try dataStore.userStorage.update()
} catch {
Logger.error(error)
}
dataStore.setUser(user)
}
})
} label: {
@ -81,24 +89,12 @@ struct UmpireView: View {
} else {
Button("supprimer", role: .destructive) {
user.licenceId = nil
dataStore.setUser(user)
}
}
}
if let clubs = user.clubs {
Section {
ForEach(clubs) { clubId in
if let club = dataStore.clubs.findById(clubId) {
NavigationLink {
ClubDetailView(club: club, displayContext: .edition)
} label: {
ClubRowView(club: club)
}
do {
try dataStore.userStorage.update()
} catch {
Logger.error(error)
}
}
} header: {
Text("Mes clubs")
}
}
}
@ -108,11 +104,13 @@ struct UmpireView: View {
ClubsView()
} label: {
LabeledContent {
Text(dataStore.clubs.count.formatted())
Text((dataStore.user?.clubs ?? []).count.formatted())
} label: {
Label("Mes clubs", systemImage: "house.and.flag.circle.fill")
}
}
} footer: {
Text("Il s'agit des clubs qui sont utilisés pour récupérer les tournois tenup.")
}
Section {

@ -64,7 +64,7 @@ struct PlanningSettingsView: View {
TournamentFieldsManagerView(localizedStringKey: "Terrains par poule", count: $groupStageCourtCount, max: tournament.maximumCourtsPerGroupSage())
}
if let event = tournament.eventObject {
if let event = tournament.eventObject() {
NavigationLink {
CourtAvailabilitySettingsView(event: event)
.environment(tournament)

@ -27,26 +27,29 @@ struct TournamentFilterView: View {
var body: some View {
NavigationView {
Form {
Section {
ForEach(dataStore.clubs.filter({ $0.code != nil })) { club in
LabeledContent {
Button {
if selectedClubs.contains(club.code!) {
selectedClubs.remove(club.code!)
} else {
selectedClubs.insert(club.code!)
let clubs : [Club] = (dataStore.user?.clubsObjects()) ?? []
if clubs.filter({ $0.code != nil }).isEmpty == false {
Section {
ForEach(clubs.filter({ $0.code != nil })) { club in
LabeledContent {
Button {
if selectedClubs.contains(club.code!) {
selectedClubs.remove(club.code!)
} else {
selectedClubs.insert(club.code!)
}
} label: {
if selectedClubs.contains(club.code!) {
Image(systemName: "checkmark.circle.fill")
}
}
} label: {
if selectedClubs.contains(club.code!) {
Image(systemName: "checkmark.circle.fill")
}
Text(club.clubTitle())
}
} label: {
Text(club.clubTitle())
}
} header: {
Text("Clubs")
}
} header: {
Text("Clubs")
}
Section {
ForEach(TournamentLevel.allCases) { level in

@ -16,12 +16,12 @@ struct TournamentClubSettingsView: View {
var body: some View {
@Bindable var tournament = tournament
List {
let event = tournament.eventObject
let selectedClub = event?.clubObject
let event = tournament.eventObject()
let selectedClub = event?.clubObject()
Section {
if let selectedClub {
NavigationLink {
ClubDetailView(club: selectedClub, displayContext: .edition)
ClubDetailView(club: selectedClub, displayContext: selectedClub.hasBeenCreated(by: dataStore.user?.id) ? .edition : .lockedForEditing)
} label: {
ClubRowView(club: selectedClub)
}
@ -30,11 +30,11 @@ struct TournamentClubSettingsView: View {
ClubsView() { club in
if let event {
event.club = club.id
try? dataStore.events.addOrUpdate(instance: event)
} else {
let event = Event(club: club.id)
tournament.event = event.id
try? dataStore.events.addOrUpdate(instance: event)
do {
try dataStore.events.addOrUpdate(instance: event)
} catch {
Logger.error(error)
}
}
}
} label: {

@ -689,13 +689,13 @@ struct InscriptionManagerView: View {
Divider()
NavigationLink {
ClubsView() { club in
if let event = tournament.eventObject {
if let event = tournament.eventObject() {
event.club = club.id
try? dataStore.events.addOrUpdate(instance: event)
} else {
let event = Event(club: club.id)
tournament.event = event.id
try? dataStore.events.addOrUpdate(instance: event)
do {
try dataStore.events.addOrUpdate(instance: event)
} catch {
Logger.error(error)
}
}
_save()
}
@ -710,13 +710,13 @@ struct InscriptionManagerView: View {
} else {
NavigationLink {
ClubsView() { club in
if let event = tournament.eventObject {
if let event = tournament.eventObject() {
event.club = club.id
try? dataStore.events.addOrUpdate(instance: event)
} else {
let event = Event(club: club.id)
tournament.event = event.id
try? dataStore.events.addOrUpdate(instance: event)
do {
try dataStore.events.addOrUpdate(instance: event)
} catch {
Logger.error(error)
}
}
_save()
}

Loading…
Cancel
Save