Laurent 2 years ago
commit 4b4f2c74be
  1. 4
      PadelClub.xcodeproj/project.pbxproj
  2. 11
      PadelClub/Data/Federal/FederalTournament.swift
  3. 10
      PadelClub/Data/Tournament.swift
  4. 193
      PadelClub/Extensions/Date+Extensions.swift
  5. 58
      PadelClub/Views/Club/ClubSearchView.swift
  6. 7
      PadelClub/Views/Club/CreateClubView.swift
  7. 7
      PadelClub/Views/Navigation/Umpire/UmpireView.swift
  8. 2
      PadelClub/Views/Tournament/Screen/BroadcastView.swift
  9. 4
      PadelClub/Views/Tournament/Screen/Components/TournamentStatusView.swift
  10. 2
      PadelClub/Views/Tournament/Screen/InscriptionManagerView.swift
  11. 3
      PadelClub/Views/Tournament/TournamentView.swift

@ -1830,7 +1830,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 7; CURRENT_PROJECT_VERSION = 8;
DEFINES_MODULE = YES; DEFINES_MODULE = YES;
DEVELOPMENT_ASSET_PATHS = "\"PadelClub/Preview Content\""; DEVELOPMENT_ASSET_PATHS = "\"PadelClub/Preview Content\"";
DEVELOPMENT_TEAM = BQ3Y44M3Q6; DEVELOPMENT_TEAM = BQ3Y44M3Q6;
@ -1868,7 +1868,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 7; CURRENT_PROJECT_VERSION = 8;
DEFINES_MODULE = YES; DEFINES_MODULE = YES;
DEVELOPMENT_ASSET_PATHS = "\"PadelClub/Preview Content\""; DEVELOPMENT_ASSET_PATHS = "\"PadelClub/Preview Content\"";
DEVELOPMENT_TEAM = BQ3Y44M3Q6; DEVELOPMENT_TEAM = BQ3Y44M3Q6;

@ -17,16 +17,7 @@ enum DayPeriod {
struct FederalTournament: Identifiable, Codable { struct FederalTournament: Identifiable, Codable {
func getEvent() -> Event { func getEvent() -> Event {
var club = DataStore.shared.clubs.first(where: { $0.code == codeClub }) let club = DataStore.shared.user.clubsObjects().first(where: { $0.code == codeClub })
if club == nil {
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 }) var event = DataStore.shared.events.first(where: { $0.tenupId == id.string })
if event == nil { if event == nil {
event = Event(creator: DataStore.shared.user.id, club: club?.id, name: libelle, tenupId: id.string) event = Event(creator: DataStore.shared.user.id, club: club?.id, name: libelle, tenupId: id.string)

@ -306,7 +306,7 @@ class Tournament : ModelObject, Storable {
} }
func publishedGroupStagesDate() -> Date? { func publishedGroupStagesDate() -> Date? {
if let first = groupStages().flatMap({ $0.playedMatches() }).compactMap({ $0.startDate }).sorted().first?.atNine() { if let first = groupStages().flatMap({ $0.playedMatches() }).compactMap({ $0.startDate }).sorted().first?.atEightAM() {
if first.isEarlierThan(startDate) { if first.isEarlierThan(startDate) {
return startDate return startDate
} else { } else {
@ -327,7 +327,7 @@ class Tournament : ModelObject, Storable {
} }
func publishedBracketsDate() -> Date? { func publishedBracketsDate() -> Date? {
if let first = rounds().flatMap({ $0.playedMatches() }).compactMap({ $0.startDate }).sorted().first?.atNine() { if let first = rounds().flatMap({ $0.playedMatches() }).compactMap({ $0.startDate }).sorted().first?.atEightAM() {
if first.isEarlierThan(startDate) { if first.isEarlierThan(startDate) {
return startDate return startDate
} else { } else {
@ -1361,9 +1361,9 @@ class Tournament : ModelObject, Storable {
private func _defaultSorting() -> [MySortDescriptor<TeamRegistration>] { private func _defaultSorting() -> [MySortDescriptor<TeamRegistration>] {
switch teamSorting { switch teamSorting {
case .rank: case .rank:
[.keyPath(\TeamRegistration.initialWeight), .keyPath(\TeamRegistration.registrationDate!), .keyPath(\.canonicalName)] [.keyPath(\TeamRegistration.initialWeight), .keyPath(\TeamRegistration.registrationDate!)]
case .inscriptionDate: case .inscriptionDate:
[.keyPath(\TeamRegistration.registrationDate!), .keyPath(\TeamRegistration.initialWeight), .keyPath(\.canonicalName)] [.keyPath(\TeamRegistration.registrationDate!), .keyPath(\TeamRegistration.initialWeight)]
} }
} }
@ -1373,7 +1373,7 @@ class Tournament : ModelObject, Storable {
&& federalTournamentAge == build.age && federalTournamentAge == build.age
} }
private let _currentSelectionSorting : [MySortDescriptor<TeamRegistration>] = [.keyPath(\.weight), .keyPath(\.registrationDate!), .keyPath(\.canonicalName)] private let _currentSelectionSorting : [MySortDescriptor<TeamRegistration>] = [.keyPath(\.weight), .keyPath(\.registrationDate!)]
override func deleteDependencies() throws { override func deleteDependencies() throws {
try Store.main.deleteDependencies(items: self.unsortedTeams()) try Store.main.deleteDependencies(items: self.unsortedTeams())

@ -102,100 +102,100 @@ extension Date {
} }
static var firstDayOfWeek = Calendar.current.firstWeekday static var firstDayOfWeek = Calendar.current.firstWeekday
static var capitalizedFirstLettersOfWeekdays: [String] { static var capitalizedFirstLettersOfWeekdays: [String] {
let calendar = Calendar.current let calendar = Calendar.current
// let weekdays = calendar.shortWeekdaySymbols // let weekdays = calendar.shortWeekdaySymbols
// return weekdays.map { weekday in // return weekdays.map { weekday in
// guard let firstLetter = weekday.first else { return "" } // guard let firstLetter = weekday.first else { return "" }
// return String(firstLetter).capitalized // return String(firstLetter).capitalized
// } // }
// Adjusted for the different weekday starts // Adjusted for the different weekday starts
var weekdays = calendar.veryShortStandaloneWeekdaySymbols var weekdays = calendar.veryShortStandaloneWeekdaySymbols
if firstDayOfWeek > 1 { if firstDayOfWeek > 1 {
for _ in 1..<firstDayOfWeek { for _ in 1..<firstDayOfWeek {
if let first = weekdays.first { if let first = weekdays.first {
weekdays.append(first) weekdays.append(first)
weekdays.removeFirst() weekdays.removeFirst()
} }
} }
} }
return weekdays.map { $0.capitalized } return weekdays.map { $0.capitalized }
} }
static var fullMonthNames: [String] { static var fullMonthNames: [String] {
let dateFormatter = DateFormatter() let dateFormatter = DateFormatter()
dateFormatter.locale = Locale.current dateFormatter.locale = Locale.current
return (1...12).compactMap { month in return (1...12).compactMap { month in
dateFormatter.setLocalizedDateFormatFromTemplate("MMMM") dateFormatter.setLocalizedDateFormatFromTemplate("MMMM")
let date = Calendar.current.date(from: DateComponents(year: 2000, month: month, day: 1)) let date = Calendar.current.date(from: DateComponents(year: 2000, month: month, day: 1))
return date.map { dateFormatter.string(from: $0) } return date.map { dateFormatter.string(from: $0) }
} }
} }
var startOfMonth: Date { var startOfMonth: Date {
Calendar.current.dateInterval(of: .month, for: self)!.start Calendar.current.dateInterval(of: .month, for: self)!.start
} }
var endOfMonth: Date { var endOfMonth: Date {
let lastDay = Calendar.current.dateInterval(of: .month, for: self)!.end let lastDay = Calendar.current.dateInterval(of: .month, for: self)!.end
return Calendar.current.date(byAdding: .day, value: -1, to: lastDay)! return Calendar.current.date(byAdding: .day, value: -1, to: lastDay)!
} }
var startOfPreviousMonth: Date { var startOfPreviousMonth: Date {
let dayInPreviousMonth = Calendar.current.date(byAdding: .month, value: -1, to: self)! let dayInPreviousMonth = Calendar.current.date(byAdding: .month, value: -1, to: self)!
return dayInPreviousMonth.startOfMonth return dayInPreviousMonth.startOfMonth
} }
var numberOfDaysInMonth: Int { var numberOfDaysInMonth: Int {
Calendar.current.component(.day, from: endOfMonth) Calendar.current.component(.day, from: endOfMonth)
} }
// var sundayBeforeStart: Date { // var sundayBeforeStart: Date {
// let startOfMonthWeekday = Calendar.current.component(.weekday, from: startOfMonth) // let startOfMonthWeekday = Calendar.current.component(.weekday, from: startOfMonth)
// let numberFromPreviousMonth = startOfMonthWeekday - 1 // let numberFromPreviousMonth = startOfMonthWeekday - 1
// return Calendar.current.date(byAdding: .day, value: -numberFromPreviousMonth, to: startOfMonth)! // return Calendar.current.date(byAdding: .day, value: -numberFromPreviousMonth, to: startOfMonth)!
// } // }
// New to accomodate for different start of week days // New to accomodate for different start of week days
var firstWeekDayBeforeStart: Date { var firstWeekDayBeforeStart: Date {
let startOfMonthWeekday = Calendar.current.component(.weekday, from: startOfMonth) let startOfMonthWeekday = Calendar.current.component(.weekday, from: startOfMonth)
let numberFromPreviousMonth = startOfMonthWeekday - Self.firstDayOfWeek let numberFromPreviousMonth = startOfMonthWeekday - Self.firstDayOfWeek
return Calendar.current.date(byAdding: .day, value: -numberFromPreviousMonth, to: startOfMonth)! return Calendar.current.date(byAdding: .day, value: -numberFromPreviousMonth, to: startOfMonth)!
} }
var calendarDisplayDays: [Date] { var calendarDisplayDays: [Date] {
var days: [Date] = [] var days: [Date] = []
// Current month days // Current month days
for dayOffset in 0..<numberOfDaysInMonth { for dayOffset in 0..<numberOfDaysInMonth {
let newDay = Calendar.current.date(byAdding: .day, value: dayOffset, to: startOfMonth) let newDay = Calendar.current.date(byAdding: .day, value: dayOffset, to: startOfMonth)
days.append(newDay!) days.append(newDay!)
} }
// previous month days // previous month days
for dayOffset in 0..<startOfPreviousMonth.numberOfDaysInMonth { for dayOffset in 0..<startOfPreviousMonth.numberOfDaysInMonth {
let newDay = Calendar.current.date(byAdding: .day, value: dayOffset, to: startOfPreviousMonth) let newDay = Calendar.current.date(byAdding: .day, value: dayOffset, to: startOfPreviousMonth)
days.append(newDay!) days.append(newDay!)
} }
// Fixed to accomodate different weekday starts // Fixed to accomodate different weekday starts
return days.filter { $0 >= firstWeekDayBeforeStart && $0 <= endOfMonth }.sorted(by: <) return days.filter { $0 >= firstWeekDayBeforeStart && $0 <= endOfMonth }.sorted(by: <)
} }
var monthInt: Int { var monthInt: Int {
Calendar.current.component(.month, from: self) Calendar.current.component(.month, from: self)
} }
var yearInt: Int { var yearInt: Int {
Calendar.current.component(.year, from: self) Calendar.current.component(.year, from: self)
} }
var dayInt: Int { var dayInt: Int {
Calendar.current.component(.day, from: self) Calendar.current.component(.day, from: self)
} }
var startOfDay: Date { var startOfDay: Date {
Calendar.current.startOfDay(for: self) Calendar.current.startOfDay(for: self)
} }
func endOfDay() -> Date { func endOfDay() -> Date {
let calendar = Calendar.current let calendar = Calendar.current
@ -206,6 +206,11 @@ extension Date {
let calendar = Calendar.current let calendar = Calendar.current
return calendar.date(bySettingHour: 9, minute: 0, second: 0, of: self)! return calendar.date(bySettingHour: 9, minute: 0, second: 0, of: self)!
} }
func atEightAM() -> Date {
let calendar = Calendar.current
return calendar.date(bySettingHour: 8, minute: 0, second: 0, of: self)!
}
} }
extension Date { extension Date {

@ -83,30 +83,7 @@ struct ClubSearchView: View {
ForEach(_filteredClubs()) { clubMark in ForEach(_filteredClubs()) { clubMark in
Button { Button {
let clubToEdit = club ?? Club.findOrCreate(name: clubMark.nom, code: clubMark.clubID) let clubToEdit = club ?? Club.findOrCreate(name: clubMark.nom, code: clubMark.clubID)
_importClub(clubToEdit: clubToEdit, clubMarker: clubMark)
if clubToEdit.creator == dataStore.user.id {
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
}
if displayContext == .addition {
do {
try dataStore.clubs.addOrUpdate(instance: clubToEdit)
if dataStore.user.clubs.contains(where: { $0 == clubToEdit.id }) == false {
dataStore.user.clubs.append(clubToEdit.id)
self.dataStore.saveUser()
}
} catch {
Logger.error(error)
}
}
dismiss()
} label: { } label: {
clubView(clubMark) clubView(clubMark)
.frame(maxWidth: .infinity) .frame(maxWidth: .infinity)
@ -133,6 +110,13 @@ struct ClubSearchView: View {
} }
} }
} }
.task {
do {
try await dataStore.clubs.loadDataFromServerIfAllowed()
} catch {
Logger.error(error)
}
}
.listStyle(.grouped) .listStyle(.grouped)
.onChange(of: searchPresented) { .onChange(of: searchPresented) {
locationManager.lastError = nil locationManager.lastError = nil
@ -308,6 +292,32 @@ struct ClubSearchView: View {
} }
} }
private func _importClub(clubToEdit: Club, clubMarker: ClubMarker) {
if clubToEdit.creator == dataStore.user.id {
if clubToEdit.name.isEmpty {
clubToEdit.name = clubMarker.nom
clubToEdit.acronym = clubToEdit.automaticShortName()
}
clubToEdit.code = clubMarker.clubID
clubToEdit.latitude = clubMarker.lat
clubToEdit.longitude = clubMarker.lng
clubToEdit.city = clubMarker.ville
}
if displayContext == .addition {
do {
try dataStore.clubs.addOrUpdate(instance: clubToEdit)
if dataStore.user.clubs.contains(where: { $0 == clubToEdit.id }) == false {
dataStore.user.clubs.append(clubToEdit.id)
self.dataStore.saveUser()
}
} catch {
Logger.error(error)
}
}
dismiss()
}
private func _filteredClubs() -> [ClubMarker] { private func _filteredClubs() -> [ClubMarker] {
clubMarkers.filter({ _isClubValidForSearchedTerms(club: $0) }) clubMarkers.filter({ _isClubValidForSearchedTerms(club: $0) })
} }

@ -21,6 +21,13 @@ struct CreateClubView: View {
var body: some View { var body: some View {
NavigationStack { NavigationStack {
ClubDetailView(club: club, displayContext: .addition) ClubDetailView(club: club, displayContext: .addition)
.task {
do {
try await dataStore.clubs.loadDataFromServerIfAllowed()
} catch {
Logger.error(error)
}
}
.toolbar { .toolbar {
ToolbarItem(placement: .cancellationAction) { ToolbarItem(placement: .cancellationAction) {
Button("Annuler", role: .cancel) { Button("Annuler", role: .cancel) {

@ -189,6 +189,13 @@ struct UmpireView: View {
} }
}) })
} }
.task {
do {
try await dataStore.clubs.loadDataFromServerIfAllowed()
} catch {
Logger.error(error)
}
}
} }
} }
} }

@ -52,8 +52,8 @@ struct BroadcastView: View {
} else { } else {
Text("Publication prévue") Text("Publication prévue")
} }
Text("Les horaires de convocations ne seront pas publiés")
} }
Text("Les horaires de convocations ne seront pas publiés").foregroundStyle(.secondary)
} header: { } header: {
Text("Liste des équipes") Text("Liste des équipes")
} footer: { } footer: {

@ -17,10 +17,12 @@ struct TournamentStatusView: View {
var body: some View { var body: some View {
@Bindable var tournament = tournament @Bindable var tournament = tournament
Form { Form {
#if DEBUG
RowButtonView("debug: Un-delete le tournoi") { RowButtonView("debug: Un-delete le tournoi") {
tournament.endDate = nil tournament.endDate = nil
tournament.isDeleted.toggle() tournament.isDeleted.toggle()
} }
#endif
Section { Section {
if tournament.endDate == nil { if tournament.endDate == nil {
@ -71,7 +73,7 @@ struct TournamentStatusView: View {
Text("Tournoi privé") Text("Tournoi privé")
} }
} footer: { } footer: {
Text("Le tournoi sera masqué sur le site padelclub.app") Text(.init("Le tournoi sera masqué sur le site [Padel Club](\(URLs.main)"))
} }
} }
.toolbarBackground(.visible, for: .navigationBar) .toolbarBackground(.visible, for: .navigationBar)

@ -149,7 +149,7 @@ struct InscriptionManagerView: View {
rankingDateSourcePickerView(showDateInLabel: true) rankingDateSourcePickerView(showDateInLabel: true)
if tournament.teamSorting == .inscriptionDate { if tournament.teamSorting == .inscriptionDate {
Divider() Divider()
_prioritizeClubMembersButton() //_prioritizeClubMembersButton()
Button("Bloquer une place") { Button("Bloquer une place") {
_createTeam() _createTeam()

@ -10,6 +10,7 @@ import LeStorage
struct TournamentView: View { struct TournamentView: View {
@EnvironmentObject var dataStore: DataStore @EnvironmentObject var dataStore: DataStore
@Environment(NavigationViewModel.self) var navigation: NavigationViewModel
@Environment(Tournament.self) var tournament: Tournament @Environment(Tournament.self) var tournament: Tournament
var presentationContext: PresentationContext = .agenda var presentationContext: PresentationContext = .agenda
@ -126,7 +127,7 @@ struct TournamentView: View {
Menu { Menu {
if presentationContext == .agenda { if presentationContext == .agenda {
Button { Button {
navigation.openTournamentInOrganizer(tournament)
} label: { } label: {
Label("Voir dans le gestionnaire", systemImage: "line.diagonal.arrow") Label("Voir dans le gestionnaire", systemImage: "line.diagonal.arrow")
} }

Loading…
Cancel
Save