fix registration online

online_reg
Raz 11 months ago
parent 768902e827
commit 7b06c8cefc
  1. 16
      PadelClub.xcodeproj/project.pbxproj
  2. 32
      PadelClub/Data/Tournament.swift
  3. 2
      PadelClub/PadelClubApp.swift
  4. 23
      PadelClub/Utils/Tips.swift
  5. 1
      PadelClub/ViewModel/Screen.swift
  6. 2
      PadelClub/Views/Cashier/Event/EventCreationView.swift
  7. 2
      PadelClub/Views/Cashier/Event/EventTournamentsView.swift
  8. 2
      PadelClub/Views/Navigation/Agenda/CalendarView.swift
  9. 2
      PadelClub/Views/Navigation/Agenda/EventListView.swift
  10. 10
      PadelClub/Views/Team/EditingTeamView.swift
  11. 67
      PadelClub/Views/Tournament/Screen/Components/TournamentGeneralSettingsView.swift
  12. 7
      PadelClub/Views/Tournament/Screen/InscriptionManagerView.swift
  13. 8
      PadelClub/Views/Tournament/Screen/RegistrationSetupView.swift
  14. 42
      PadelClub/Views/Tournament/Screen/TournamentRankView.swift
  15. 3
      PadelClub/Views/Tournament/Shared/TournamentCellView.swift
  16. 54
      PadelClub/Views/Tournament/TournamentView.swift

@ -798,9 +798,9 @@
FFBF41822BF73EB3001B24CB /* EventView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFBF41812BF73EB3001B24CB /* EventView.swift */; };
FFBF41842BF75ED7001B24CB /* EventTournamentsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFBF41832BF75ED7001B24CB /* EventTournamentsView.swift */; };
FFBF41862BF75FDA001B24CB /* EventSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFBF41852BF75FDA001B24CB /* EventSettingsView.swift */; };
FFBFC3912CEE3A0E000EBD8D /* RegisrationSetupView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFBFC3902CEE3A0E000EBD8D /* RegisrationSetupView.swift */; };
FFBFC3922CEE3A0E000EBD8D /* RegisrationSetupView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFBFC3902CEE3A0E000EBD8D /* RegisrationSetupView.swift */; };
FFBFC3932CEE3A0E000EBD8D /* RegisrationSetupView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFBFC3902CEE3A0E000EBD8D /* RegisrationSetupView.swift */; };
FFBFC3912CEE3A0E000EBD8D /* RegistrationSetupView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFBFC3902CEE3A0E000EBD8D /* RegistrationSetupView.swift */; };
FFBFC3922CEE3A0E000EBD8D /* RegistrationSetupView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFBFC3902CEE3A0E000EBD8D /* RegistrationSetupView.swift */; };
FFBFC3932CEE3A0E000EBD8D /* RegistrationSetupView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFBFC3902CEE3A0E000EBD8D /* RegistrationSetupView.swift */; };
FFBFC3952CF05CBB000EBD8D /* DateMenuView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFBFC3942CF05CBB000EBD8D /* DateMenuView.swift */; };
FFBFC3962CF05CBB000EBD8D /* DateMenuView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFBFC3942CF05CBB000EBD8D /* DateMenuView.swift */; };
FFBFC3972CF05CBB000EBD8D /* DateMenuView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFBFC3942CF05CBB000EBD8D /* DateMenuView.swift */; };
@ -1194,7 +1194,7 @@
FFBF41812BF73EB3001B24CB /* EventView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventView.swift; sourceTree = "<group>"; };
FFBF41832BF75ED7001B24CB /* EventTournamentsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventTournamentsView.swift; sourceTree = "<group>"; };
FFBF41852BF75FDA001B24CB /* EventSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventSettingsView.swift; sourceTree = "<group>"; };
FFBFC3902CEE3A0E000EBD8D /* RegisrationSetupView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegisrationSetupView.swift; sourceTree = "<group>"; };
FFBFC3902CEE3A0E000EBD8D /* RegistrationSetupView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegistrationSetupView.swift; sourceTree = "<group>"; };
FFBFC3942CF05CBB000EBD8D /* DateMenuView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateMenuView.swift; sourceTree = "<group>"; };
FFC1E1032BAC28C6008D6F59 /* ClubSearchView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClubSearchView.swift; sourceTree = "<group>"; };
FFC1E1072BAC29FC008D6F59 /* LocationManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationManager.swift; sourceTree = "<group>"; };
@ -1680,7 +1680,7 @@
isa = PBXGroup;
children = (
FF70916D2B9108C600AB08DA /* InscriptionManagerView.swift */,
FFBFC3902CEE3A0E000EBD8D /* RegisrationSetupView.swift */,
FFBFC3902CEE3A0E000EBD8D /* RegistrationSetupView.swift */,
FF90FC1C2C44FB3E009339B2 /* AddTeamView.swift */,
FF8F26422BADFE5B00650388 /* TournamentSettingsView.swift */,
FF8F26532BAE1E4400650388 /* TableStructureView.swift */,
@ -2436,7 +2436,7 @@
C45BAE442BCA753E002EEC8A /* Purchase.swift in Sources */,
FF6EC8FE2B94792300EA7F5A /* Screen.swift in Sources */,
FF967CEE2BAECBD700A9A3BD /* Round.swift in Sources */,
FFBFC3922CEE3A0E000EBD8D /* RegisrationSetupView.swift in Sources */,
FFBFC3922CEE3A0E000EBD8D /* RegistrationSetupView.swift in Sources */,
FF5BAF6E2BE0B3C8008B4B7E /* FederalDataViewModel.swift in Sources */,
FF3F74FF2B91A2D4004CFE0E /* AgendaDestination.swift in Sources */,
FF3795622B9396D0004EA093 /* PadelClubApp.xcdatamodeld in Sources */,
@ -2723,7 +2723,7 @@
FF4CBFB92C996C0600151637 /* Purchase.swift in Sources */,
FF4CBFBA2C996C0600151637 /* Screen.swift in Sources */,
FF4CBFBB2C996C0600151637 /* Round.swift in Sources */,
FFBFC3912CEE3A0E000EBD8D /* RegisrationSetupView.swift in Sources */,
FFBFC3912CEE3A0E000EBD8D /* RegistrationSetupView.swift in Sources */,
FF4CBFBC2C996C0600151637 /* FederalDataViewModel.swift in Sources */,
FF4CBFBD2C996C0600151637 /* AgendaDestination.swift in Sources */,
FF4CBFBE2C996C0600151637 /* PadelClubApp.xcdatamodeld in Sources */,
@ -2989,7 +2989,7 @@
FF70FB382C90584900129CC2 /* Purchase.swift in Sources */,
FF70FB392C90584900129CC2 /* Screen.swift in Sources */,
FF70FB3A2C90584900129CC2 /* Round.swift in Sources */,
FFBFC3932CEE3A0E000EBD8D /* RegisrationSetupView.swift in Sources */,
FFBFC3932CEE3A0E000EBD8D /* RegistrationSetupView.swift in Sources */,
FF70FB3B2C90584900129CC2 /* FederalDataViewModel.swift in Sources */,
FF70FB3C2C90584900129CC2 /* AgendaDestination.swift in Sources */,
FF70FB3D2C90584900129CC2 /* PadelClubApp.xcdatamodeld in Sources */,

@ -2131,12 +2131,16 @@ defer {
}
}
func setupFederalSettings() {
func setupFederalSettings(fromEvent event: Event?) {
teamSorting = tournamentLevel.defaultTeamSortingType
groupStageMatchFormat = groupStageSmartMatchFormat()
loserBracketMatchFormat = loserBracketSmartMatchFormat(5)
matchFormat = roundSmartMatchFormat(5)
entryFee = tournamentLevel.entryFee
if event?.tenupId != nil {
enableOnlineRegistration = true
registrationDateLimit = deadline(for: .inscription)
}
}
func roundSmartMatchFormat(_ roundIndex: Int) -> MatchFormat {
@ -2504,6 +2508,32 @@ defer {
return .open
}
// MARK: - Status
func shouldTournamentBeOver() -> Bool {
#if _DEBUGING_TIME //DEBUGING TIME
let start = Date()
defer {
let duration = Duration.milliseconds(Date().timeIntervalSince(start) * 1_000)
print("func shouldTournamentBeOver()", id, duration.formatted(.units(allowed: [.seconds, .milliseconds])))
}
#endif
if isDeleted == false && hasEnded() == false && hasStarted() {
let allMatches = allMatches()
let remainingMatches = allMatches.filter({ $0.hasEnded() == false && $0.startDate != nil })
let calendar = Calendar.current
let anyTomorrow = remainingMatches.anySatisfy({ calendar.isDateInTomorrow($0.startDate!) })
if anyTomorrow == false, let endDate = allMatches.filter({ $0.hasEnded() }).sorted(by: \.endDate!, order: .ascending).last?.endDate, endDate.timeIntervalSinceNow <= -2 * 3600 {
return true
}
}
return false
}
// MARK: -
func insertOnServer() throws {

@ -102,7 +102,7 @@ print("Running in Release mode")
//try? Tips.resetDatastore()
try? Tips.configure([
.displayFrequency(.daily),
.displayFrequency(.immediate),
.datastoreLocation(.applicationDefault)
])
}

@ -572,6 +572,29 @@ struct PlayerTournamentSearchTip: Tip {
}
struct OnlineRegistrationTip: Tip {
var title: Text {
Text("Inscription en ligne")
}
var message: Text? {
Text("Facilitez les inscriptions à votre tournoi en activant l'inscription en ligne. Les joueurs pourront s'inscrire directement depuis l'application ou le site Padel Club.")
}
var image: Image? {
Image(systemName: "person.2.crop.square.stack")
}
var actions: [Action] {
Action(id: ActionKey.enableOnlineRegistration.rawValue, title: "Activer dans les réglages du tournoi")
}
enum ActionKey: String {
case enableOnlineRegistration = "enableOnlineRegistration"
}
}
struct TipStyleModifier: ViewModifier {
@Environment(\.colorScheme) var colorScheme
var tint: Color?

@ -21,4 +21,5 @@ enum Screen: String, Codable {
case event
case print
case restingTime
case stateSettings
}

@ -143,7 +143,7 @@ struct EventCreationView: View {
tournament.courtCount = selectedClub?.courtCount ?? 2
tournament.startDate = startingDate
tournament.dayDuration = duration
tournament.setupFederalSettings()
tournament.setupFederalSettings(fromEvent: event)
}
do {

@ -63,7 +63,7 @@ struct EventTournamentsView: View {
newTournament.courtCount = event.eventCourtCount()
newTournament.startDate = event.eventStartDate()
newTournament.dayDuration = event.eventDayDuration()
newTournament.setupFederalSettings()
newTournament.setupFederalSettings(fromEvent: event)
do {
try dataStore.tournaments.addOrUpdate(instance: newTournament)

@ -173,7 +173,7 @@ struct CalendarView: View {
newTournament.federalTournamentAge = build.age
newTournament.dayDuration = federalTournament.dayDuration
newTournament.startDate = federalTournament.startDate.atBeginningOfDay(hourInt: 9)
newTournament.setupFederalSettings()
newTournament.setupFederalSettings(fromEvent: event)
do {
try dataStore.tournaments.addOrUpdate(instance: newTournament)
} catch {

@ -37,7 +37,6 @@ struct EventListView: View {
Text("\(count.formatted()) tournoi" + count.pluralSuffix)
}
}
.id(sectionIndex)
.headerProminence(.increased)
}
}
@ -119,6 +118,7 @@ struct EventListView: View {
NavigationLink(value: tournament) {
TournamentCellView(tournament: tournament)
}
.listRowView(isActive: tournament.shouldTournamentBeOver(), color: .red, hideColorVariation: true, alignment: .leading)
.contextMenu {
if tournament.hasEnded() == false {
Button {

@ -53,6 +53,12 @@ struct EditingTeamView: View {
}
TeamDetailView(team: team)
} header: {
if team.hasRegisteredOnline() {
Text("Inscription en ligne")
} else {
Text("Inscription par vous-même")
}
} footer: {
HStack {
CopyPasteButtonView(pasteValue: team.playersPasteData())
@ -203,6 +209,10 @@ struct EditingTeamView: View {
}
dismiss()
}
} footer: {
if team.hasRegisteredOnline() {
Text("Attention, supprimer cette équipe notifiera par email que leur inscription a été annulée.")
}
}
}
.navigationBarBackButtonHidden(focusedField != nil)

@ -32,39 +32,6 @@ struct TournamentGeneralSettingsView: View {
var body: some View {
@Bindable var tournament = tournament
Form {
Section {
TextField("Nom du tournoi", text: $tournamentName, axis: .vertical)
.lineLimit(2)
.frame(maxWidth: .infinity)
.keyboardType(.alphabet)
.focused($focusedField, equals: ._name)
} header: {
Text("Nom du tournoi")
}
Section {
ZStack {
Text(tournamentInformation).opacity(0)
Text(ContactType.defaultCustomMessage).opacity(0)
TextEditor(text: $tournamentInformation)
.keyboardType(.alphabet)
.focused($focusedField, equals: ._information)
}
.frame(maxHeight: 200)
.overlay {
if tournamentInformation.isEmpty {
Text("Texte visible dans l'onglet informations sur Padel Club.").italic()
}
}
} header: {
Text("Description du tournoi")
} footer: {
FooterButtonView("Ajouter le prix de l'inscription") {
tournamentInformation.append("\n" + tournament.entryFeeMessage)
}
}
Section {
TournamentDatePickerView()
TournamentDurationManagerView()
@ -83,7 +50,7 @@ struct TournamentGeneralSettingsView: View {
Section {
NavigationLink {
RegisrationSetupView(tournament: tournament)
RegistrationSetupView(tournament: tournament)
} label: {
LabeledContent {
if tournament.enableOnlineRegistration {
@ -104,6 +71,38 @@ struct TournamentGeneralSettingsView: View {
Text("Paramétrez les possibilités d'inscription en ligne à votre tournoi via Padel Club")
}
Section {
TextField("Nom du tournoi", text: $tournamentName, axis: .vertical)
.lineLimit(2)
.frame(maxWidth: .infinity)
.keyboardType(.alphabet)
.focused($focusedField, equals: ._name)
} header: {
Text("Nom du tournoi")
}
Section {
ZStack {
Text(tournamentInformation).opacity(0)
Text(ContactType.defaultCustomMessage).opacity(0)
TextEditor(text: $tournamentInformation)
.keyboardType(.alphabet)
.focused($focusedField, equals: ._information)
}
.frame(maxHeight: 200)
.overlay {
if tournamentInformation.isEmpty {
Text("Texte visible dans l'onglet informations sur Padel Club.").italic()
}
}
} header: {
Text("Description du tournoi")
} footer: {
FooterButtonView("Ajouter le prix de l'inscription") {
tournamentInformation.append("\n" + tournament.entryFeeMessage)
}
}
Section {
TournamentLevelPickerView()
}

@ -23,6 +23,7 @@ let teamsExportTip = TeamsExportTip()
struct InscriptionManagerView: View {
@EnvironmentObject var dataStore: DataStore
@Environment(NavigationViewModel.self) var navigation: NavigationViewModel
@Environment(\.dismiss) var dismiss
@ -248,6 +249,10 @@ struct InscriptionManagerView: View {
RowButtonView("Rafraîchir la liste") {
await _refreshList()
}
} else {
RowButtonView("Inscription en ligne") {
navigation.path.append(Screen.settings)
}
}
}
}
@ -608,9 +613,11 @@ struct InscriptionManagerView: View {
} label: {
TeamRowView(team: team)
}
#if DEBUG
.swipeActions(edge: .trailing, allowsFullSwipe: true) {
_teamDeleteButtonView(team)
}
#endif
.listRowView(isActive: true, color: team.initialRoundColor() ?? tournament.cutLabelColor(index: teamIndex, teamCount: filterMode == .waiting ? 0 : selectedSortedTeams.count), hideColorVariation: true)
}
} header: {

@ -1,5 +1,5 @@
//
// RegisrationSetupView.swift
// RegistrationSetupView.swift
// PadelClub
//
// Created by razmig on 20/11/2024.
@ -8,7 +8,7 @@
import SwiftUI
import LeStorage
struct RegisrationSetupView: View {
struct RegistrationSetupView: View {
@EnvironmentObject var dataStore: DataStore
@Bindable var tournament: Tournament
@State private var enableOnlineRegistration: Bool
@ -89,7 +89,9 @@ struct RegisrationSetupView: View {
if enableOnlineRegistration {
if let shareURL = tournament.shareURL(.info) {
Section {
ShareLink(item: shareURL)
ShareLink(item: shareURL) {
Text(shareURL.absoluteString)
}
} header: {
Text("Page d'inscription")
} footer: {

@ -28,6 +28,14 @@ struct TournamentRankView: View {
}
}
var hideRankings: Binding<Bool> {
Binding {
tournament.publishRankings == false
} set: { value in
tournament.publishRankings = !value
}
}
var body: some View {
List {
@Bindable var tournament = tournament
@ -53,18 +61,17 @@ struct TournamentRankView: View {
}
//affiche l'onglet sur le site, car sur le broadcast c'est dispo automatiquement de toute façon
Toggle(isOn: $tournament.publishRankings) {
Text("Publier sur Padel Club")
if let url = tournament.shareURL(.rankings) {
Link(destination: url) {
Text("Accéder à la page")
}
if calculating {
ProgressView("Calcul en cours")
} else {
Text("Publier sur Padel Club")
}
}
.onChange(of: tournament.publishRankings) {
do {
try dataStore.tournaments.addOrUpdate(instance: tournament)
} catch {
Logger.error(error)
.disabled(calculating)
} footer: {
if let url = tournament.shareURL(.rankings) {
Link(destination: url) {
Text("Voir la page des classements sur Padel Club")
}
}
}
@ -88,6 +95,8 @@ struct TournamentRankView: View {
team.finalRanking = nil
team.pointsEarned = nil
}
tournament.publishRankings = false
_save()
}
}
@ -107,6 +116,13 @@ struct TournamentRankView: View {
}
}
.id(calculating)
.onChange(of: tournament.publishRankings) {
do {
try dataStore.tournaments.addOrUpdate(instance: tournament)
} catch {
Logger.error(error)
}
}
.alert("Position", isPresented: isEditingTeam) {
if let selectedTeam {
@Bindable var team = selectedTeam
@ -131,16 +147,12 @@ struct TournamentRankView: View {
}
}
}
.overlay(content: {
if calculating {
ProgressView()
}
})
.onAppear {
let rankingPublished = tournament.selectedSortedTeams().anySatisfy({ $0.finalRanking != nil })
if rankingPublished == false {
Task {
await _calculateRankings()
tournament.publishRankings = true
}
}
}

@ -160,6 +160,7 @@ struct TournamentCellView: View {
}
}
.font(.caption)
.listRowView(isActive: existingTournament != nil, color: .green, hideColorVariation: true, alignment: .leading)
}
private func _createOrShow(federalTournament: FederalTournament, existingTournament: Tournament?, build: any TournamentBuildHolder) {
@ -178,7 +179,7 @@ struct TournamentCellView: View {
newTournament.federalTournamentAge = build.age
newTournament.dayDuration = federalTournament.dayDuration
newTournament.startDate = federalTournament.startDate.atBeginningOfDay(hourInt: 9)
newTournament.setupFederalSettings()
newTournament.setupFederalSettings(fromEvent: event)
do {
try dataStore.tournaments.addOrUpdate(instance: newTournament)
} catch {

@ -18,6 +18,7 @@ struct TournamentView: View {
let tournamentSelectionTip: TournamentSelectionTip = TournamentSelectionTip()
let tournamentRunningTip: TournamentRunningTip = TournamentRunningTip()
let onlineRegistrationTip: OnlineRegistrationTip = OnlineRegistrationTip()
var selectedTournamentId: Binding<String> { Binding(
get: { tournament.id },
@ -59,17 +60,63 @@ struct TournamentView: View {
}
}
case .initial:
if tournament.enableOnlineRegistration == false {
TipView(onlineRegistrationTip) { actions in
navigation.path.append(Screen.settings)
}
.tipStyle(tint: .master, asSection: true)
}
Section {
TournamentInscriptionView(tournament: tournament)
}
TournamentInitView(tournament: tournament)
case .build:
if tournament.enableOnlineRegistration == false {
TipView(onlineRegistrationTip) { actions in
navigation.path.append(Screen.settings)
}
.tipStyle(tint: .master, asSection: true)
}
Section {
TournamentInscriptionView(tournament: tournament)
}
TournamentBuildView(tournament: tournament)
TournamentInitView(tournament: tournament)
case .running:
if tournament.shouldTournamentBeOver() {
Section {
Menu {
Button("Scores manquants") {
if let activeRound = tournament.getActiveRound() {
navigation.path.append(Screen.round)
} else if let activeGroupStage = tournament.getActiveGroupStage() {
navigation.path.append(Screen.groupStage)
}
}
Button {
navigation.path.append(Screen.stateSettings)
} label: {
Text("Annuler le tournoi")
}
} label: {
Label("Actions rapides", systemImage: "bolt.circle")
.foregroundColor(.white)
.frame(height: 32)
.font(.headline)
.frame(maxWidth: .infinity)
}
.menuStyle(.button)
.buttonStyle(.borderedProminent)
.tint(.logoYellow)
.listRowBackground(Color.clear)
.listRowInsets(EdgeInsets(.zero))
}
}
TournamentBuildView(tournament: tournament)
TournamentRunningView(tournament: tournament)
case .finished:
@ -113,6 +160,9 @@ struct TournamentView: View {
PrintSettingsView(tournament: tournament)
case .restingTime:
TeamRestingView()
case .stateSettings:
TournamentStatusView(tournament: tournament)
}
}
.environment(tournament)
@ -197,9 +247,7 @@ struct TournamentView: View {
Divider()
NavigationLink {
TournamentStatusView(tournament: tournament)
} label: {
NavigationLink(value: Screen.stateSettings) {
Text("Gestion du tournoi")
Text("Annuler, supprimer ou terminer le tournoi")
}

Loading…
Cancel
Save