multistore
Razmig Sarkissian 1 year ago
parent 30affc2de9
commit 11e3995a95
  1. 16
      PadelClub.xcodeproj/project.pbxproj
  2. 4
      PadelClub/Data/Event.swift
  3. 2
      PadelClub/Data/MatchScheduler.swift
  4. 7
      PadelClub/Data/Tournament.swift
  5. 6
      PadelClub/Utils/HtmlService.swift
  6. 2
      PadelClub/Views/Calling/CallMessageCustomizationView.swift
  7. 1
      PadelClub/Views/Cashier/CashierDetailView.swift
  8. 16
      PadelClub/Views/Cashier/Event/EventCreationView.swift
  9. 30
      PadelClub/Views/Cashier/Event/EventSettingsView.swift
  10. 3
      PadelClub/Views/Cashier/Event/EventTournamentsView.swift
  11. 3
      PadelClub/Views/Cashier/Event/EventView.swift
  12. 0
      PadelClub/Views/Cashier/Event/TournamentConfiguratorView.swift
  13. 31
      PadelClub/Views/Club/ClubDetailView.swift
  14. 6
      PadelClub/Views/Planning/PlanningSettingsView.swift
  15. 1
      PadelClub/Views/Planning/PlanningView.swift
  16. 6
      PadelClub/Views/Team/TeamRowView.swift
  17. 1
      PadelClub/Views/Tournament/Screen/TournamentCallView.swift
  18. 1
      PadelClub/Views/Tournament/Screen/TournamentCashierView.swift
  19. 1
      PadelClub/Views/Tournament/Screen/TournamentScheduleView.swift
  20. 11
      PadelClub/Views/Tournament/TournamentBuildView.swift
  21. 32
      PadelClub/Views/Tournament/TournamentInitView.swift
  22. 24
      PadelClub/Views/Tournament/TournamentInscriptionView.swift
  23. 14
      PadelClub/Views/Tournament/TournamentView.swift

@ -748,7 +748,6 @@
isa = PBXGroup;
children = (
FF39719B2B8DE04B004C4E75 /* Navigation */,
FF8F26392BAD526A00650388 /* Event */,
FF1DC54D2BAB34FA00FD8220 /* Club */,
FFC83D4B2BB807C200750834 /* Round */,
FF967CF92BAEE11500A9A3BD /* GroupStage */,
@ -1120,15 +1119,6 @@
path = Network;
sourceTree = "<group>";
};
FF8F26392BAD526A00650388 /* Event */ = {
isa = PBXGroup;
children = (
FF8F263A2BAD528600650388 /* EventCreationView.swift */,
FF8F263C2BAD627A00650388 /* TournamentConfiguratorView.swift */,
);
path = Event;
sourceTree = "<group>";
};
FF8F26522BAE0E4E00650388 /* Components */ = {
isa = PBXGroup;
children = (
@ -1219,6 +1209,8 @@
FFBF41812BF73EB3001B24CB /* EventView.swift */,
FFBF41832BF75ED7001B24CB /* EventTournamentsView.swift */,
FFBF41852BF75FDA001B24CB /* EventSettingsView.swift */,
FF8F263A2BAD528600650388 /* EventCreationView.swift */,
FF8F263C2BAD627A00650388 /* TournamentConfiguratorView.swift */,
);
name = Event;
path = Cashier/Event;
@ -1927,7 +1919,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 11;
CURRENT_PROJECT_VERSION = 12;
DEFINES_MODULE = YES;
DEVELOPMENT_ASSET_PATHS = "\"PadelClub/Preview Content\"";
DEVELOPMENT_TEAM = BQ3Y44M3Q6;
@ -1965,7 +1957,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 11;
CURRENT_PROJECT_VERSION = 12;
DEFINES_MODULE = YES;
DEVELOPMENT_ASSET_PATHS = "\"PadelClub/Preview Content\"";
DEVELOPMENT_TEAM = BQ3Y44M3Q6;

@ -71,8 +71,8 @@ class Event: ModelObject, Storable {
tournaments.first(where: { $0.isSameBuild(build) })
}
func tournamentsCourtsUsed() -> [DateInterval] {
tournaments.flatMap({ tournament in
func tournamentsCourtsUsed(exluding tournamentId: String) -> [DateInterval] {
tournaments.filter { $0.id != tournamentId }.flatMap({ tournament in
tournament.getPlayedMatchDateIntervals(in: self)
})
}

@ -69,7 +69,7 @@ class MatchScheduler : ModelObject, Storable {
var courtsUnavailability: [DateInterval]? {
guard let event = tournamentObject()?.eventObject() else { return nil }
return event.courtsUnavailability + event.tournamentsCourtsUsed()
return event.courtsUnavailability + event.tournamentsCourtsUsed(exluding: tournament)
}
var additionalEstimationDuration : Int {

@ -1398,7 +1398,7 @@ class Tournament : ModelObject, Storable {
}
private func _matchSchedulers() -> [MatchScheduler] {
Store.main.filter(isIncluded: { $0.id == self.id })
Store.main.filter(isIncluded: { $0.tournament == self.id })
}
func matchScheduler() -> MatchScheduler? {
@ -1427,6 +1427,11 @@ class Tournament : ModelObject, Storable {
courtNameIfAvailable(atIndex: courtIndex) ?? Court.courtIndexedTitle(atIndex: courtIndex)
}
func tournamentWinner() -> TeamRegistration? {
let final : Round? = Store.main.filter(isIncluded: { $0.index == 0 && $0.tournament == id && $0.parent == nil }).first
return final?.playedMatches().first?.winner()
}
// MARK: - Payments & Crypto
fileprivate var _currentPayment: TournamentPayment? = nil

@ -199,9 +199,9 @@ enum HtmlService {
}
var winnerName = ""
// if let tournamentWinner = tournament.winnerEntrant {
// winnerName = HtmlService.player(entrant: tournamentWinner).html(headName: headName, withRank: withRank, withScore: withScore)
// }
if let tournamentWinner = tournament.tournamentWinner() {
winnerName = HtmlService.player(entrant: tournamentWinner).html(headName: headName, withRank: withRank, withScore: withScore)
}
let winner = """
<ul class="round" scope="last">
<li class="spacer">&nbsp;</li>

@ -46,7 +46,7 @@ struct CallMessageCustomizationView: View {
var finalMessage: String? {
let localizedCalled = "convoqué" + (tournament.tournamentCategory == .women ? "e" : "") + "s"
return "Bonjour,\n\nVous êtes \(localizedCalled) pour jouer en \(RoundRule.roundName(fromRoundIndex: 2).lowercased()) du \(tournament.tournamentTitle()) au \(clubName) le \(tournament.startDate).formatted(Date.FormatStyle().weekday(.wide).day().month(.wide))) à \(tournament.startDate.formatted(Date.FormatStyle().hour().minute())).\n\n" + computedMessage + "\n\n\(customCallMessageSignature)"
return "Bonjour,\n\nVous êtes \(localizedCalled) pour jouer en \(RoundRule.roundName(fromRoundIndex: 2).lowercased()) du \(tournament.tournamentTitle()) au \(clubName) le \(tournament.startDate.formatted(Date.FormatStyle().weekday(.wide).day().month(.wide))) à \(tournament.startDate.formatted(Date.FormatStyle().hour().minute())).\n\n" + computedMessage + "\n\n\(customCallMessageSignature)"
}
var body: some View {

@ -37,7 +37,6 @@ struct CashierDetailView: View {
}
}
.headerProminence(.increased)
.navigationTitle("Bilan")
}
private func _tournamentCashierDetailView(_ tournament: Tournament) -> some View {

@ -20,6 +20,7 @@ struct EventCreationView: View {
@State private var eventName: String = ""
@State var tournaments: [Tournament] = []
@State var selectedClub: Club?
@FocusState private var textFieldIsFocus: Bool
let multiTournamentsEventTip = MultiTournamentsEventTip()
@ -65,11 +66,10 @@ struct EventCreationView: View {
TextField("Nom de l'événement", text: $eventName, axis: .vertical)
.lineLimit(2)
.autocorrectionDisabled()
.keyboardType(.alphabet)
.multilineTextAlignment(.leading)
.frame(maxWidth: .infinity)
.focused($textFieldIsFocus)
LabeledContent {
Text(tournaments.count.formatted())
} label: {
@ -125,6 +125,18 @@ struct EventCreationView: View {
}
}
.toolbar {
if textFieldIsFocus {
ToolbarItem(placement: .keyboard) {
HStack {
Spacer()
Button("Valider") {
textFieldIsFocus = false
}
.buttonStyle(.bordered)
}
}
}
ToolbarItem(placement: .cancellationAction) {
Button("Annuler", role: .cancel) {
dismiss()

@ -12,6 +12,7 @@ struct EventSettingsView: View {
@EnvironmentObject var dataStore: DataStore
@Bindable var event: Event
@State private var eventName: String = ""
@FocusState private var textFieldIsFocus: Bool
init(event: Event) {
self.event = event
@ -23,11 +24,27 @@ struct EventSettingsView: View {
Section {
TextField("Nom de l'événement", text: $eventName, axis: .vertical)
.lineLimit(2)
.autocorrectionDisabled()
.keyboardType(.alphabet)
.multilineTextAlignment(.leading)
.frame(maxWidth: .infinity)
.onSubmit {
.focused($textFieldIsFocus)
} footer: {
if eventName.isEmpty == false {
FooterButtonView("effacer le nom") {
eventName = ""
event.name = nil
_save()
}
}
}
}
.toolbar {
if textFieldIsFocus {
ToolbarItem(placement: .keyboard) {
HStack {
Spacer()
Button("Valider") {
textFieldIsFocus = false
if eventName.trimmed.isEmpty == false {
event.name = eventName.trimmed
} else {
@ -35,14 +52,7 @@ struct EventSettingsView: View {
}
_save()
}
} header: {
Text("Nom de l'événement")
} footer: {
if eventName.isEmpty == false {
FooterButtonView("effacer le nom") {
eventName = ""
event.name = nil
_save()
.buttonStyle(.bordered)
}
}
}

@ -46,9 +46,6 @@ struct EventTournamentsView: View {
}
}
.headerProminence(.increased)
.toolbarBackground(.visible, for: .navigationBar)
.navigationBarTitleDisplayMode(.inline)
.navigationTitle(event.eventTitle())
.sheet(isPresented: presentTournamentCreationView) {
if let newTournament {
NavigationStack {

@ -58,7 +58,6 @@ struct EventView: View {
switch selectedDestination {
case .none:
EventSettingsView(event: event)
.navigationTitle("Réglages")
case .some(let selectedEventDestination):
switch selectedEventDestination {
case .tournaments(let event):
@ -71,6 +70,6 @@ struct EventView: View {
.headerProminence(.increased)
.toolbarBackground(.visible, for: .navigationBar)
.navigationBarTitleDisplayMode(.inline)
.navigationTitle(event.eventTitle())
.navigationTitle("Gestion de l'événement")
}
}

@ -39,16 +39,6 @@ struct ClubDetailView: View {
.frame(maxWidth: .infinity)
.focused($focusedField, equals: ._name)
.submitLabel( displayContext == .addition ? .next : .done)
.onSubmit {
if club.acronym.isEmpty {
club.acronym = club.name.canonicalVersion.replaceCharactersFromSet(characterSet: .whitespacesAndNewlines)
focusedField = ._city
}
if displayContext == .addition {
focusedField = ._acronym
}
}
LabeledContent {
if acronymMode == .automatic || displayContext == .lockedForEditing {
Text(club.acronym)
@ -247,6 +237,27 @@ struct ClubDetailView: View {
}
}
}
.toolbar {
if focusedField == ._name {
ToolbarItem(placement: .keyboard) {
HStack {
Spacer()
Button("Valider") {
if club.acronym.isEmpty {
club.acronym = club.name.canonicalVersion.replaceCharactersFromSet(characterSet: .whitespacesAndNewlines)
}
if displayContext == .edition && city.isEmpty == true {
focusedField = ._city
} else {
focusedField = nil
}
}
.buttonStyle(.bordered)
}
}
}
}
}
}

@ -140,9 +140,6 @@ struct PlanningSettingsView: View {
.deferredRendering(for: .seconds(2))
}
}
.onChange(of: groupStageChunkCount) {
matchScheduler.groupStageChunkCount = groupStageChunkCount
}
.onChange(of: tournament.startDate) {
_save()
}
@ -159,6 +156,9 @@ struct PlanningSettingsView: View {
if tournament.groupStages().isEmpty == false {
Section {
TournamentFieldsManagerView(localizedStringKey: "Poule en parallèle", count: $groupStageChunkCount, max: tournament.groupStageCount)
.onChange(of: groupStageChunkCount) {
matchScheduler.groupStageChunkCount = groupStageChunkCount
}
} footer: {
Text("Vous pouvez indiquer le nombre de poule démarrant en même temps.")
}

@ -82,7 +82,6 @@ struct PlanningView: View {
}
}
}
.navigationTitle("Programmation")
}
private func _matchesCount(inDayInt dayInt: Int) -> Int {

@ -16,7 +16,11 @@ struct TeamRowView: View {
LabeledContent {
TeamWeightView(team: team, teamPosition: teamPosition)
} label: {
Text(team.teamLabel(.wide))
VStack(alignment: .leading) {
ForEach(team.players()) { player in
Text(player.playerLabel())
}
}
if let callDate = team.callDate, displayCallDate {
Text("Déjà convoquée \(callDate.localizedDate())")
.foregroundStyle(.red)

@ -86,7 +86,6 @@ struct TournamentCallView: View {
switch selectedDestination {
case .none:
CallSettingsView()
.navigationTitle("Réglages")
case .some(let selectedCall):
switch selectedCall {
case .groupStages:

@ -113,7 +113,6 @@ struct TournamentCashierView: View {
switch selectedDestination {
case .none:
CashierSettingsView(tournament: tournament)
.navigationTitle("Réglages")
case .some(let selectedCall):
switch selectedCall {
case .summary:

@ -75,7 +75,6 @@ struct TournamentScheduleView: View {
switch selectedScheduleDestination {
case .none:
PlanningSettingsView(tournament: tournament)
.navigationTitle("Réglages")
case .some(let selectedSchedule):
switch selectedSchedule {
case .scheduleGroupStage:

@ -34,6 +34,8 @@ struct TournamentBuildView: View {
}
}
}
if tournament.state() == .running || tournament.state() == .finished {
NavigationLink(value: Screen.cashier) {
let tournamentStatus = tournament.cashierStatus()
LabeledContent {
@ -44,6 +46,15 @@ struct TournamentBuildView: View {
}
}
}
}
if tournament.hasEnded() {
Section {
NavigationLink(value: Screen.rankings) {
Text("Classement")
}
}
}
Section {
if tournament.groupStages().isEmpty == false {

@ -13,13 +13,6 @@ struct TournamentInitView: View {
@ViewBuilder
var body: some View {
Section {
NavigationLink(value: Screen.broadcast) {
LabeledContent {
// Text(tournament.isPrivate ? "privée" : "publique")
} label: {
Text("Publication")
}
}
if let event = tournament.eventObject() {
let tournaments = event.tournaments
@ -31,6 +24,16 @@ struct TournamentInitView: View {
}
}
}
NavigationLink(value: Screen.structure) {
LabeledContent {
Text(tournament.structureDescriptionLocalizedLabel())
.tint(.master)
} label: {
LabelStructure()
}
}
NavigationLink(value: Screen.settings) {
LabeledContent {
Text(tournament.settingsDescriptionLocalizedLabel())
@ -39,8 +42,19 @@ struct TournamentInitView: View {
LabelSettings()
}
}
} footer: {
Text("La date, la catégorie, le niveau, le nombre de terrain, les formats, etc.")
NavigationLink(value: Screen.broadcast) {
LabeledContent {
Image(systemName: tournament.isPrivate ? "tv.slash" : "checkmark")
.foregroundStyle(tournament.isPrivate ? .logoRed : .green)
} label: {
Text("Publication")
}
}
NavigationLink(value: Screen.print) {
Text("Imprimer")
}
}
}
}

@ -32,30 +32,6 @@ struct TournamentInscriptionView: View {
Text("Date limite")
}
}
if tournament.state() != .running {
NavigationLink(value: Screen.structure) {
LabeledContent {
Text(tournament.structureDescriptionLocalizedLabel())
.tint(.master)
} label: {
LabelStructure()
}
}
}
} footer: {
if tournament.inscriptionClosed() == false && tournament.state() == .build && tournament.unsortedTeams().isEmpty == false && tournament.hasStarted() == false {
Button {
tournament.lockRegistration()
_save()
} label: {
Text("clôturer les inscriptions")
.underline()
}
.buttonStyle(.borderless)
} else if tournament.state() != .running {
Text("Nombre d'équipes, de poules, de qualifiés sortant, etc.")
}
}
}

@ -62,22 +62,10 @@ struct TournamentView: View {
case .build:
TournamentInscriptionView(tournament: tournament)
TournamentInitView(tournament: tournament)
Section {
NavigationLink(value: Screen.print) {
Label("Imprimer", systemImage: "printer")
}
}
TournamentBuildView(tournament: tournament)
case .running, .finished:
TournamentInscriptionView(tournament: tournament)
TournamentBuildView(tournament: tournament)
if tournament.hasEnded() {
Section {
NavigationLink(value: Screen.rankings) {
Text("Classement")
}
}
}
TournamentRunningView(tournament: tournament)
}
}
@ -168,7 +156,7 @@ struct TournamentView: View {
}
NavigationLink(value: Screen.broadcast) {
Text("Publication")
Label("Publication", systemImage: "airplayvideo")
}
NavigationLink(value: Screen.print) {

Loading…
Cancel
Save