Laurent 1 year ago
commit a84ddc539f
  1. 4
      PadelClub.xcodeproj/project.pbxproj
  2. 6
      PadelClub/Data/Club.swift
  3. 2
      PadelClub/Data/Federal/FederalTournament.swift
  4. 5
      PadelClub/Data/GroupStage.swift
  5. 7
      PadelClub/Data/MatchScheduler.swift
  6. 2
      PadelClub/Data/Tournament.swift
  7. 3
      PadelClub/Views/Calling/GroupStageCallingView.swift
  8. 16
      PadelClub/Views/Cashier/Event/EventCreationView.swift
  9. 28
      PadelClub/Views/Club/ClubDetailView.swift
  10. 5
      PadelClub/Views/Club/ClubRowView.swift
  11. 14
      PadelClub/Views/Club/ClubSearchView.swift
  12. 14
      PadelClub/Views/Club/ClubsView.swift
  13. 22
      PadelClub/Views/Club/CreateClubView.swift
  14. 21
      PadelClub/Views/Navigation/MainView.swift
  15. 4
      PadelClub/Views/Navigation/Umpire/UmpireView.swift
  16. 2
      PadelClub/Views/Subscription/Guard.swift

@ -1908,7 +1908,7 @@
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_ENTITLEMENTS = PadelClub/PadelClub.entitlements; CODE_SIGN_ENTITLEMENTS = PadelClub/PadelClub.entitlements;
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 61; CURRENT_PROJECT_VERSION = 66;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEFINES_MODULE = YES; DEFINES_MODULE = YES;
DEVELOPMENT_ASSET_PATHS = "\"PadelClub/Preview Content\""; DEVELOPMENT_ASSET_PATHS = "\"PadelClub/Preview Content\"";
@ -1949,7 +1949,7 @@
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_ENTITLEMENTS = PadelClub/PadelClub.entitlements; CODE_SIGN_ENTITLEMENTS = PadelClub/PadelClub.entitlements;
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 61; CURRENT_PROJECT_VERSION = 66;
DEFINES_MODULE = YES; DEFINES_MODULE = YES;
DEVELOPMENT_ASSET_PATHS = "\"PadelClub/Preview Content\""; DEVELOPMENT_ASSET_PATHS = "\"PadelClub/Preview Content\"";
DEVELOPMENT_TEAM = BQ3Y44M3Q6; DEVELOPMENT_TEAM = BQ3Y44M3Q6;

@ -170,7 +170,7 @@ class Club : ModelObject, Storable, Hashable {
extension Club { extension Club {
var isValid: Bool { var isValid: Bool {
name.isEmpty == false && acronym.isEmpty == false name.isEmpty == false && name.count > 3
} }
func automaticShortName() -> String { func automaticShortName() -> String {
@ -216,7 +216,7 @@ extension Club {
} }
func hasBeenCreated(by creatorId: String?) -> Bool { func hasBeenCreated(by creatorId: String?) -> Bool {
return creatorId == creator return creatorId == creator || creator == nil
} }
func isFavorite() -> Bool { func isFavorite() -> Bool {
@ -235,7 +235,7 @@ extension Club {
if clubs.isEmpty == false { if clubs.isEmpty == false {
return clubs.first! return clubs.first!
} else { } else {
return Club(name: name, code: code, city: city, zipCode: zipCode) return Club(creator: Store.main.userId, name: name, code: code, city: city, zipCode: zipCode)
} }
} }

@ -20,7 +20,7 @@ struct FederalTournament: Identifiable, Codable {
let club = DataStore.shared.user.clubsObjects().first(where: { $0.code == codeClub }) let club = DataStore.shared.user.clubsObjects().first(where: { $0.code == codeClub })
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: Store.main.userId, club: club?.id, name: libelle, tenupId: id.string)
do { do {
try DataStore.shared.events.addOrUpdate(instance: event!) try DataStore.shared.events.addOrUpdate(instance: event!)
} catch { } catch {

@ -166,6 +166,11 @@ class GroupStage: ModelObject, Storable {
return _matches().filter { matchIndexes.contains($0.index) } return _matches().filter { matchIndexes.contains($0.index) }
} }
func initialStartDate(forTeam team: TeamRegistration) -> Date? {
guard let groupStagePosition = team.groupStagePosition else { return nil }
return matches(forGroupStagePosition: groupStagePosition).compactMap({ $0.startDate }).sorted().first ?? startDate
}
func matchPlayed(by groupStagePosition: Int, againstPosition: Int) -> Match? { func matchPlayed(by groupStagePosition: Int, againstPosition: Int) -> Match? {
if groupStagePosition == againstPosition { return nil } if groupStagePosition == againstPosition { return nil }
let combos = Array((0..<size).combinations(ofCount: 2)) let combos = Array((0..<size).combinations(ofCount: 2))

@ -85,7 +85,7 @@ class MatchScheduler : ModelObject, Storable {
@discardableResult @discardableResult
func updateGroupStageSchedule(tournament: Tournament) -> Date { func updateGroupStageSchedule(tournament: Tournament) -> Date {
let computedGroupStageChunkCount = groupStageChunkCount ?? 1 let computedGroupStageChunkCount = groupStageChunkCount ?? tournament.getGroupStageChunkValue()
let groupStages: [GroupStage] = tournament.groupStages() let groupStages: [GroupStage] = tournament.groupStages()
let numberOfCourtsAvailablePerRotation: Int = tournament.courtCount let numberOfCourtsAvailablePerRotation: Int = tournament.courtCount
@ -677,7 +677,10 @@ class MatchScheduler : ModelObject, Storable {
} }
func updateSchedule(tournament: Tournament) -> Bool { func updateSchedule(tournament: Tournament) -> Bool {
let lastDate = updateGroupStageSchedule(tournament: tournament) var lastDate = tournament.startDate
if tournament.groupStageCount > 0 {
lastDate = updateGroupStageSchedule(tournament: tournament)
}
return updateBracketSchedule(tournament: tournament, fromRoundId: nil, fromMatchId: nil, startDate: lastDate) return updateBracketSchedule(tournament: tournament, fromRoundId: nil, fromMatchId: nil, startDate: lastDate)
} }
} }

@ -1762,7 +1762,7 @@ class Tournament : ModelObject, Storable {
} }
func getGroupStageChunkValue() -> Int { func getGroupStageChunkValue() -> Int {
if teamsPerGroupStage >= 2 { if groupStageCount > 0 && teamsPerGroupStage >= 2 {
let result = courtCount / (teamsPerGroupStage / 2) let result = courtCount / (teamsPerGroupStage / 2)
let remainder = courtCount % (teamsPerGroupStage / 2) let remainder = courtCount % (teamsPerGroupStage / 2)
let value = remainder == 0 ? result : result + 1 let value = remainder == 0 ? result : result + 1

@ -70,8 +70,8 @@ struct GroupStageCallingView: View {
private func _groupStageView(groupStage: GroupStage) -> some View { private func _groupStageView(groupStage: GroupStage) -> some View {
let teams = groupStage.teams() let teams = groupStage.teams()
List { List {
if let startDate = groupStage.startDate {
ForEach(teams) { team in ForEach(teams) { team in
if let startDate = groupStage.initialStartDate(forTeam: team) {
Section { Section {
CallView.TeamView(team: team) CallView.TeamView(team: team)
} header: { } header: {
@ -80,7 +80,6 @@ struct GroupStageCallingView: View {
CallView(teams: [team], callDate: startDate, matchFormat: groupStage.matchFormat, roundLabel: "poule") CallView(teams: [team], callDate: startDate, matchFormat: groupStage.matchFormat, roundLabel: "poule")
} }
} }
} }
} }
.overlay { .overlay {

@ -130,10 +130,6 @@ struct EventCreationView: View {
private func _validate() { private func _validate() {
let event = Event(creator: Store.main.userId, name: eventName) let event = Event(creator: Store.main.userId, name: eventName)
event.club = selectedClub?.id
tournaments.forEach { tournament in
tournament.event = event.id
}
do { do {
try dataStore.events.addOrUpdate(instance: event) try dataStore.events.addOrUpdate(instance: event)
@ -142,6 +138,7 @@ struct EventCreationView: View {
} }
tournaments.forEach { tournament in tournaments.forEach { tournament in
tournament.event = event.id
tournament.courtCount = selectedClub?.courtCount ?? 2 tournament.courtCount = selectedClub?.courtCount ?? 2
tournament.startDate = startingDate tournament.startDate = startingDate
tournament.dayDuration = duration tournament.dayDuration = duration
@ -154,6 +151,17 @@ struct EventCreationView: View {
Logger.error(error) Logger.error(error)
} }
if let selectedClub, let verifiedSelectedClubId = dataStore.clubs.first(where: { selectedClub.id == $0.id })?.id {
event.club = verifiedSelectedClubId
do {
try dataStore.events.addOrUpdate(instance: event)
} catch {
Logger.error(error)
}
}
dismiss() dismiss()
navigation.path.append(tournaments.first!) navigation.path.append(tournaments.first!)
} }

@ -43,6 +43,7 @@ struct ClubDetailView: View {
dataStore.user.clubs.append(club.id) dataStore.user.clubs.append(club.id)
} }
self.dataStore.saveUser() self.dataStore.saveUser()
dismiss()
} }
} footer: { } footer: {
if displayContext == .lockedForEditing { if displayContext == .lockedForEditing {
@ -52,7 +53,7 @@ struct ClubDetailView: View {
} }
Section { Section {
TextField("Nom du club", text: $club.name) TextField("Nom du club (4 lettres mini)", text: $club.name)
.autocorrectionDisabled() .autocorrectionDisabled()
.keyboardType(.alphabet) .keyboardType(.alphabet)
.frame(maxWidth: .infinity) .frame(maxWidth: .infinity)
@ -186,31 +187,6 @@ struct ClubDetailView: View {
} }
} }
if displayContext == .addition {
Section {
} header: {
HStack {
VStack {
Divider()
}
Text("ou")
VStack {
Divider()
}
}
}
Section {
NavigationLink {
ClubSearchView(displayContext: .edition, club: club)
} label: {
Label("Chercher dans la base fédérale", systemImage: "magnifyingglass")
}
} footer: {
Text("Vous pouvez chercher un club dans la base fédérale et importer les informations directement.")
}
}
ClubCourtSetupView(club: club, displayContext: displayContext, selectedCourt: $selectedCourt, hideLockForEditingMessage: true) ClubCourtSetupView(club: club, displayContext: displayContext, selectedCourt: $selectedCourt, hideLockForEditingMessage: true)
if displayContext == .edition { if displayContext == .edition {

@ -19,7 +19,12 @@ struct ClubRowView: View {
// .foregroundStyle(club.isFavorite() ? .green : .logoRed) // .foregroundStyle(club.isFavorite() ? .green : .logoRed)
// } // }
} label: { } label: {
HStack {
Text(club.name) Text(club.name)
Spacer()
}
.frame(maxWidth: .infinity)
.contentShape(Rectangle())
} }
} }
} }

@ -303,7 +303,7 @@ struct ClubSearchView: View {
} }
private func _importClub(clubToEdit: Club, clubMarker: ClubMarker) { private func _importClub(clubToEdit: Club, clubMarker: ClubMarker) {
if clubToEdit.creator == dataStore.user.id { if clubToEdit.hasBeenCreated(by: Store.main.userId) {
if clubToEdit.name.isEmpty { if clubToEdit.name.isEmpty {
clubToEdit.name = clubMarker.nom.capitalized clubToEdit.name = clubMarker.nom.capitalized
clubToEdit.acronym = clubToEdit.automaticShortName().capitalized clubToEdit.acronym = clubToEdit.automaticShortName().capitalized
@ -314,17 +314,19 @@ struct ClubSearchView: View {
clubToEdit.city = clubMarker.ville clubToEdit.city = clubMarker.ville
} }
if displayContext == .addition { if displayContext == .addition && clubToEdit.hasBeenCreated(by: Store.main.userId) {
do { do {
try dataStore.clubs.addOrUpdate(instance: clubToEdit) 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 { } catch {
Logger.error(error) Logger.error(error)
} }
} }
if dataStore.user.clubs.contains(where: { $0 == clubToEdit.id }) == false {
dataStore.user.clubs.append(clubToEdit.id)
self.dataStore.saveUser()
}
dismiss() dismiss()
selection?(clubToEdit) selection?(clubToEdit)
} }

@ -27,6 +27,20 @@ struct ClubsView: View {
var body: some View { var body: some View {
List { List {
#if DEBUG
Section {
RowButtonView("Delete unexisted clubs", action: {
var ids = dataStore.user.clubs
ids.forEach { clubId in
if dataStore.clubs.findById(clubId) == nil {
dataStore.user.clubs.removeAll(where: { $0 == clubId })
}
}
dataStore.saveUser()
})
}
#endif
let clubs : [Club] = dataStore.user.clubsObjects(includeCreated: false) let clubs : [Club] = dataStore.user.clubsObjects(includeCreated: false)
let onlyCreatedClubs : [Club] = dataStore.user.createdClubsObjectsNotFavorite() let onlyCreatedClubs : [Club] = dataStore.user.createdClubsObjectsNotFavorite()

@ -30,6 +30,10 @@ struct CreateClubView: View {
ProgressView() ProgressView()
} else { } else {
ButtonValidateView { ButtonValidateView {
if club.acronym.isEmpty {
club.acronym = club.name.canonicalVersion.replaceCharactersFromSet(characterSet: .whitespacesAndNewlines).acronym()
}
validationInProgress = true validationInProgress = true
} }
.disabled(club.isValid == false) .disabled(club.isValid == false)
@ -45,27 +49,25 @@ struct CreateClubView: View {
Logger.error(error) Logger.error(error)
} }
let club = Club.findOrCreate(name: club.name, code: club.code, city: club.city, zipCode: club.zipCode) let newClub = Club.findOrCreate(name: club.name, code: club.code, city: club.city, zipCode: club.zipCode)
club.creator = Store.main.userId
//update existing club if rights ok / freshly created club with data input from user //update existing club if rights ok / freshly created club with data input from user
if club.hasBeenCreated(by: Store.main.userId) { if newClub.hasBeenCreated(by: Store.main.userId) {
club.update(fromClub: club) newClub.update(fromClub: club)
}
do { do {
try dataStore.clubs.addOrUpdate(instance: club) try dataStore.clubs.addOrUpdate(instance: newClub)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
}
//save into user //save into user
if dataStore.user.clubs.contains(where: { $0 == club.id }) == false { if dataStore.user.clubs.contains(where: { $0 == newClub.id }) == false {
dataStore.user.clubs.append(club.id) dataStore.user.clubs.append(newClub.id)
self.dataStore.saveUser() self.dataStore.saveUser()
} }
dismiss() dismiss()
selection?(club) selection?(newClub)
} }
} }
} }

@ -92,6 +92,27 @@ struct MainView: View {
.environmentObject(dataStore) .environmentObject(dataStore)
.task { .task {
await self._checkSourceFileAvailability() await self._checkSourceFileAvailability()
if Store.main.hasToken() {
do {
try await dataStore.clubs.loadDataFromServerIfAllowed()
} catch {
Logger.error(error)
}
let ids = dataStore.user.clubs
var save = false
ids.forEach { clubId in
if dataStore.clubs.findById(clubId) == nil {
dataStore.user.clubs.removeAll(where: { $0 == clubId })
save = true
}
}
if save {
dataStore.saveUser()
}
}
} }
// .refreshable { // .refreshable {
// Task { // Task {

@ -193,13 +193,15 @@ struct UmpireView: View {
user.licenceId = player.license user.licenceId = player.license
if user.clubsObjects().contains(where: { $0.code == player.clubCode }) == false { if user.clubsObjects().contains(where: { $0.code == player.clubCode }) == false {
let userClub = Club.findOrCreate(name: player.clubName!, code: player.clubCode) let userClub = Club.findOrCreate(name: player.clubName!, code: player.clubCode)
if userClub.hasBeenCreated(by: Store.main.userId) {
do { do {
try dataStore.clubs.addOrUpdate(instance: userClub) try dataStore.clubs.addOrUpdate(instance: userClub)
user.setUserClub(userClub)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
} }
user.setUserClub(userClub)
}
self.dataStore.saveUser() self.dataStore.saveUser()
} }
}) })

@ -140,7 +140,7 @@ import LeStorage
} }
var currentPlan: StoreItem? { var currentPlan: StoreItem? {
// return .monthlyUnlimited return .monthlyUnlimited
// #if DEBUG // #if DEBUG
// return .monthlyUnlimited // return .monthlyUnlimited
// #else // #else

Loading…
Cancel
Save