multistore
Razmig Sarkissian 1 year ago
parent 92f623c2b4
commit f97531a767
  1. 4
      PadelClub.xcodeproj/project.pbxproj
  2. 8
      PadelClub/Data/Tournament.swift
  3. 12
      PadelClub/Extensions/String+Extensions.swift
  4. 1
      PadelClub/PadelClubApp.swift
  5. 8
      PadelClub/Utils/ContactManager.swift
  6. 8
      PadelClub/Views/Calling/CallMessageCustomizationView.swift
  7. 7
      PadelClub/Views/Calling/CallSettingsView.swift
  8. 4
      PadelClub/Views/Calling/SendToAllView.swift
  9. 2
      PadelClub/Views/Cashier/CashierView.swift
  10. 2
      PadelClub/Views/Navigation/Agenda/CalendarView.swift
  11. 2
      PadelClub/Views/Navigation/Ongoing/OngoingView.swift
  12. 2
      PadelClub/Views/Shared/LearnMoreSheetView.swift
  13. 48
      PadelClub/Views/Tournament/Screen/Components/TournamentGeneralSettingsView.swift
  14. 16
      PadelClub/Views/Tournament/Screen/InscriptionManagerView.swift
  15. 2
      PadelClub/Views/Tournament/Screen/TournamentSettingsView.swift
  16. 2
      PadelClub/Views/Tournament/TournamentView.swift

@ -1919,7 +1919,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 16;
CURRENT_PROJECT_VERSION = 17;
DEFINES_MODULE = YES;
DEVELOPMENT_ASSET_PATHS = "\"PadelClub/Preview Content\"";
DEVELOPMENT_TEAM = BQ3Y44M3Q6;
@ -1957,7 +1957,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 16;
CURRENT_PROJECT_VERSION = 17;
DEFINES_MODULE = YES;
DEVELOPMENT_ASSET_PATHS = "\"PadelClub/Preview Content\"";
DEVELOPMENT_TEAM = BQ3Y44M3Q6;

@ -762,6 +762,10 @@ class Tournament : ModelObject, Storable {
Store.main.filter { $0.tournament == self.id && $0.walkOut == false }
}
func walkoutTeams() -> [TeamRegistration] {
Store.main.filter { $0.tournament == self.id && $0.walkOut == true }
}
func duplicates(in players: [PlayerRegistration]) -> [PlayerRegistration] {
var duplicates = [PlayerRegistration]()
Set(players.compactMap({ $0.licenceId })).forEach { licenceId in
@ -1029,7 +1033,7 @@ class Tournament : ModelObject, Storable {
}
func tournamentTitle(_ displayStyle: DisplayStyle = .wide) -> String {
[tournamentLevel.localizedLabel(displayStyle), tournamentCategory.localizedLabel(displayStyle), name].compactMap({ $0 }).joined(separator: " ")
[tournamentLevel.localizedLabel(.wide) + " " + tournamentCategory.localizedLabel(.wide), displayStyle == .wide ? name : nil].compactMap({ $0 }).joined(separator: " - ")
}
func subtitle(_ displayStyle: DisplayStyle = .wide) -> String {
@ -1723,7 +1727,7 @@ extension Tournament: FederalTournamentHolder {
extension Tournament: TournamentBuildHolder {
func buildHolderTitle() -> String {
tournamentTitle()
tournamentTitle(.short)
}
var category: TournamentCategory {

@ -174,3 +174,15 @@ extension StringProtocol {
extension LosslessStringConvertible {
var string: String { .init(self) }
}
extension String {
func createTxtFile(_ withName: String = "temp") -> URL {
let url = FileManager.default.temporaryDirectory
.appendingPathComponent(withName)
.appendingPathExtension("txt")
let string = self
try? FileManager.default.removeItem(at: url)
try? string.write(to: url, atomically: true, encoding: .utf8)
return url
}
}

@ -22,6 +22,7 @@ struct PadelClubApp: App {
.environment(navigationViewModel)
.accentColor(.master)
.onAppear {
networkMonitor.checkConnection()
self._onAppear()
}
.task {

@ -31,7 +31,7 @@ enum ContactType: Identifiable {
extension ContactType {
static let defaultCustomMessage = "Il est conseillé de vous présenter 10 minutes avant de jouer.\nMerci de me confirmer votre présence avec votre nom et de prévenir votre partenaire."
static let defaultAvailablePaymentMethods = "Règlement possible par chèque ou espèce."
static let defaultAvailablePaymentMethods = "Règlement possible par chèque ou espèces."
static func callingCustomMessage(source: String? = nil, tournament: Tournament?, startDate: Date?, roundLabel: String) -> String {
let tournamentCustomMessage = source ?? DataStore.shared.user.summonsMessageBody ?? defaultCustomMessage
@ -41,7 +41,7 @@ extension ContactType {
let date = startDate ?? tournament?.startDate ?? Date()
if let tournament {
text = text.replacingOccurrences(of: "#titre", with: tournament.tournamentTitle())
text = text.replacingOccurrences(of: "#titre", with: tournament.tournamentTitle(.short))
text = text.replacingOccurrences(of: "#prix", with: tournament.entryFeeMessage)
}
@ -77,11 +77,11 @@ extension ContactType {
}
var computedMessage: String {
[entryFeeMessage, message].compacted().map { $0.trimmed }.joined(separator: "\n")
[entryFeeMessage, message].compacted().map { $0.trimmed }.joined(separator: "\n\n")
}
if let tournament {
return "Bonjour,\n\nVous êtes \(localizedCalled) pour jouer en \(roundLabel.lowercased()) du \(tournament.tournamentTitle()) au \(clubName) le \(date.formatted(Date.FormatStyle().weekday(.wide).day().month(.wide))) à \(date.formatted(Date.FormatStyle().hour().minute())).\n\n" + computedMessage + "\n\n\(signature)"
return "Bonjour,\n\nVous êtes \(localizedCalled) pour jouer en \(roundLabel.lowercased()) du \(tournament.tournamentTitle(.short)) au \(clubName) le \(date.formatted(Date.FormatStyle().weekday(.wide).day().month(.wide))) à \(date.formatted(Date.FormatStyle().hour().minute())).\n\n" + computedMessage + "\n\n\(signature)"
} else {
return "Bonjour,\n\nVous êtes \(localizedCalled) \(roundLabel) au \(clubName) le \(date.formatted(Date.FormatStyle().weekday(.wide).day().month(.wide))) à \(date.formatted(Date.FormatStyle().hour().minute())).\n\nMerci de confirmer en répondant à ce message et de prévenir votre partenaire !\n\n\(signature)"
}

@ -48,7 +48,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(.short)) 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 {
@ -103,9 +103,6 @@ struct CallMessageCustomizationView: View {
Spacer()
Button {
focusedField = nil
user.summonsMessageBody = customCallMessageBody
user.summonsMessageSignature = customCallMessageSignature
user.summonsAvailablePaymentMethods = summonsAvailablePaymentMethods
_save()
} label: {
Text("Valider")
@ -129,6 +126,9 @@ struct CallMessageCustomizationView: View {
}
private func _save() {
self.dataStore.user.summonsMessageBody = customCallMessageBody
self.dataStore.user.summonsMessageSignature = customCallMessageSignature
self.dataStore.user.summonsAvailablePaymentMethods = summonsAvailablePaymentMethods
self.dataStore.saveUser()
}

@ -34,7 +34,6 @@ struct CallSettingsView: View {
Section {
RowButtonView("Envoyer le lien du tournoi") {
addLink = true
showSendToAllView = true
}
.disabled(tournament.isPrivate)
} footer: {
@ -75,7 +74,11 @@ struct CallSettingsView: View {
#endif
}
.sheet(isPresented: $showSendToAllView) {
SendToAllView(addLink: addLink)
SendToAllView(addLink: false)
.tint(.master)
}
.sheet(isPresented: $addLink) {
SendToAllView(addLink: true)
.tint(.master)
}
}

@ -72,9 +72,9 @@ struct SendToAllView: View {
Section {
RowButtonView("Contacter \(_totalString())") {
if contactMethod == 0 {
contactType = .message(date: nil, recipients: _teams().flatMap { $0.unsortedPlayers() }.compactMap { $0.phoneNumber }, body: tournament.shareURL()?.absoluteString , tournamentBuild: nil)
contactType = .message(date: nil, recipients: _teams().flatMap { $0.unsortedPlayers() }.compactMap { $0.phoneNumber }, body: addLink ? tournament.shareURL()?.absoluteString : nil, tournamentBuild: nil)
} else {
contactType = .mail(date: nil, recipients: tournament.umpireMail(), bccRecipients: _teams().flatMap { $0.unsortedPlayers() }.compactMap { $0.email }, body: tournament.shareURL()?.absoluteString, subject: tournament.tournamentTitle(), tournamentBuild: nil)
contactType = .mail(date: nil, recipients: tournament.umpireMail(), bccRecipients: _teams().flatMap { $0.unsortedPlayers() }.compactMap { $0.email }, body: addLink ? tournament.shareURL()?.absoluteString : nil, subject: tournament.tournamentTitle(), tournamentBuild: nil)
}
}
}

@ -152,7 +152,7 @@ struct CashierView: View {
.searchable(text: $searchText, isPresented: $isSearching, prompt: Text("Chercher un joueur"))
.toolbar {
ToolbarItem(placement: .topBarTrailing) {
ShareLink(item: _sharedData())
ShareLink(item: _sharedData().createTxtFile("bilan"))
}
}
}

@ -85,7 +85,7 @@ struct CalendarView: View {
ForEach(tournamentsByDay, id: \.holderId) { tournamentHolder in
if let tournament = tournamentHolder as? Tournament {
Section {
Button(tournament.tournamentTitle()) {
Button(tournament.tournamentTitle(.short)) {
navigation.path.append(tournament)
}
} header: {

@ -32,7 +32,7 @@ struct OngoingView: View {
} header: {
if let tournament = match.currentTournament() {
HStack {
Text(tournament.tournamentTitle())
Text(tournament.tournamentTitle(.short))
Spacer()
if let club = tournament.club() {
Text("@" + club.clubTitle(.short))

@ -28,7 +28,7 @@ struct LearnMoreSheetView: View {
.foregroundStyle(.secondary)
ShareLink(item: tournament.pasteDataForImporting()) {
ShareLink(item: tournament.pasteDataForImporting().createTxtFile(tournament.tournamentTitle(.short))) {
HStack {
Spacer()
Text("Exporter les inscriptions")

@ -9,11 +9,18 @@ import SwiftUI
import LeStorage
struct TournamentGeneralSettingsView: View {
@Environment(Tournament.self) private var tournament: Tournament
@EnvironmentObject var dataStore: DataStore
var tournament: Tournament
@State private var tournamentName: String = ""
@FocusState private var textFieldIsFocus: Bool
@State private var entryFee: Double? = nil
@FocusState private var focusedField: Tournament.CodingKeys?
init(tournament: Tournament) {
self.tournament = tournament
_tournamentName = State(wrappedValue: tournament.name ?? "")
_entryFee = State(wrappedValue: tournament.entryFee)
}
var body: some View {
@Bindable var tournament = tournament
@ -29,44 +36,43 @@ struct TournamentGeneralSettingsView: View {
Section {
LabeledContent {
TextField(tournament.isFree() ? "Gratuite" : "Inscription", value: $tournament.entryFee, format: .currency(code: Locale.current.currency?.identifier ?? "EUR"))
TextField(tournament.isFree() ? "Gratuite" : "Inscription", value: $entryFee, format: .currency(code: Locale.current.currency?.identifier ?? "EUR"))
.keyboardType(.decimalPad)
.multilineTextAlignment(.trailing)
.frame(maxWidth: .infinity)
.focused($textFieldIsFocus)
.focused($focusedField, equals: ._entryFee)
} label: {
Text("Inscription")
}
}
Section {
LabeledContent {
TextField("Nom", text: $tournamentName)
.multilineTextAlignment(.trailing)
TextField("Nom du tournoi", text: $tournamentName, axis: .vertical)
.lineLimit(2)
.frame(maxWidth: .infinity)
.keyboardType(.alphabet)
.autocorrectionDisabled()
.onSubmit {
if tournamentName.trimmed.isEmpty {
tournament.name = nil
} else {
tournament.name = tournamentName
}
}
} label: {
Text("Nom du tournoi")
}
.focused($focusedField, equals: ._name)
}
}
.scrollDismissesKeyboard(.immediately)
.toolbarBackground(.visible, for: .navigationBar)
.toolbar {
if textFieldIsFocus {
if focusedField != nil {
ToolbarItem(placement: .keyboard) {
HStack {
Spacer()
Button("Valider") {
textFieldIsFocus = false
if focusedField == ._name {
if tournamentName.trimmed.isEmpty {
tournament.name = nil
} else {
tournament.name = tournamentName
}
} else if focusedField == ._entryFee {
tournament.entryFee = entryFee
}
focusedField = nil
}
.buttonStyle(.bordered)
}
@ -115,7 +121,3 @@ struct TournamentGeneralSettingsView: View {
}
}
}
#Preview {
TournamentGeneralSettingsView()
}

@ -249,7 +249,7 @@ struct InscriptionManagerView: View {
Label("Clôturer", systemImage: "lock")
}
Divider()
ShareLink(item: tournament.pasteDataForImporting()) {
ShareLink(item: tournament.pasteDataForImporting().createTxtFile(self.tournament.tournamentTitle(.short))) {
Label("Exporter les paires", systemImage: "square.and.arrow.up")
}
Button {
@ -531,15 +531,19 @@ struct InscriptionManagerView: View {
private func _informationView(count: Int) -> some View {
Section {
let unsortedTeamsWithoutWO = tournament.unsortedTeamsWithoutWO()
let unsortedTeams = tournament.unsortedTeams()
let walkoutTeams = tournament.walkoutTeams()
LabeledContent {
Text(unsortedTeamsWithoutWO.count.formatted() + "/" + tournament.teamCount.formatted())
Text(unsortedTeams.count.formatted() + "/" + tournament.teamCount.formatted()).font(.largeTitle)
} label: {
Text("Paires inscrites")
Text("Paire\(unsortedTeams.count.pluralSuffix) inscrite\(unsortedTeams.count.pluralSuffix)")
Text("dont \(walkoutTeams.count.pluralSuffix) forfaite\(walkoutTeams.count.pluralSuffix)")
}
let unsortedTeamsWithoutWO = tournament.unsortedTeamsWithoutWO()
LabeledContent {
Text(max(0, unsortedTeamsWithoutWO.count - tournament.teamCount).formatted())
Text(max(0, unsortedTeamsWithoutWO.count - tournament.teamCount).formatted()).font(.largeTitle)
} label: {
Text("Liste d'attente")
}
@ -549,7 +553,7 @@ struct InscriptionManagerView: View {
.environment(tournament)
} label: {
LabeledContent {
Text(tournament.registrationIssues().formatted())
Text(tournament.registrationIssues().formatted()).font(.largeTitle)
} label: {
Text("Problèmes détéctés")
if let closedRegistrationDate = tournament.closedRegistrationDate {

@ -67,7 +67,7 @@ struct TournamentSettingsView: View {
case .matchFormats:
TournamentMatchFormatsSettingsView()
case .general:
TournamentGeneralSettingsView()
TournamentGeneralSettingsView(tournament: tournament)
case .club:
TournamentClubSettingsView()
}

@ -121,7 +121,7 @@ struct TournamentView: View {
.toolbar {
ToolbarItem(placement: .principal) {
VStack(spacing: -4.0) {
Text(tournament.tournamentTitle()).font(.headline)
Text(tournament.tournamentTitle(.short)).font(.headline)
Text(tournament.formattedDate())
.font(.subheadline).foregroundStyle(.secondary)
}

Loading…
Cancel
Save