fix club stuff, fix cashier stuff

multistore
Razmig Sarkissian 1 year ago
parent e5e01ba5b1
commit 3e7c442aa7
  1. 2
      PadelClub/Data/Club.swift
  2. 4
      PadelClub/Data/User.swift
  3. 248
      PadelClub/Views/Cashier/CashierView.swift
  4. 113
      PadelClub/Views/Club/ClubDetailView.swift
  5. 71
      PadelClub/Views/Club/ClubsView.swift
  6. 31
      PadelClub/Views/Club/CreateClubView.swift
  7. 5
      PadelClub/Views/Club/Shared/ClubCourtSetupView.swift
  8. 8
      PadelClub/Views/Navigation/MainView.swift
  9. 2
      PadelClub/Views/Navigation/Umpire/UmpireView.swift
  10. 69
      PadelClub/Views/Tournament/Screen/TournamentCashierView.swift

@ -215,7 +215,7 @@ extension Club {
identify a club : code, name, ??
*/
let clubs: [Club] = Store.main.filter(isIncluded: { (code == nil && $0.name == name && $0.city == city && $0.zipCode == zipCode) || $0.code == code })
let clubs: [Club] = Store.main.filter(isIncluded: { (code == nil && $0.name == name && $0.city == city && $0.zipCode == zipCode) || code != nil && $0.code == code })
if clubs.isEmpty == false {
return clubs.first!

@ -89,6 +89,10 @@ class User: ModelObject, UserBase, Storable {
return Store.main.filter(isIncluded: { (includeCreated && $0.creator == id) || clubs.contains($0.id) })
}
func createdClubsObjectsNotFavorite() -> [Club] {
return Store.main.filter(isIncluded: { ($0.creator == id) || clubs.contains($0.id) == false })
}
func saveMatchFormatsDefaultDuration(_ matchFormat: MatchFormat, estimatedDuration: Int) {
if estimatedDuration == matchFormat.defaultEstimatedDuration {
matchFormatsDefaultDuration?.removeValue(forKey: matchFormat)

@ -11,19 +11,18 @@ import Combine
struct ShareableObject {
let cashierViewModel: CashierViewModel
let teams: [TeamRegistration]
let players: [PlayerRegistration]
let fileName: String
func sharedData() async -> Data? {
let players = teams.filter({ cashierViewModel._shouldDisplayTeam($0) })
.flatMap({ $0.players().filter({ cashierViewModel._shouldDisplayPlayer($0) }) })
let _players = players.filter({ cashierViewModel._shouldDisplayPlayer($0) })
.map {
[$0.pasteData()]
.compacted()
.joined(separator: "\n")
}
.joined(separator: "\n\n")
return players.data(using: .utf8)
return _players.data(using: .utf8)
}
}
@ -43,6 +42,16 @@ extension ShareableObject: Transferable {
}
}
extension Array {
func sorted<T: Comparable>(by keyPath: KeyPath<Element, T>, order: SortOrder) -> [Element] {
switch order {
case .ascending:
return self.sorted { $0[keyPath: keyPath] < $1[keyPath: keyPath] }
case .descending:
return self.sorted { $0[keyPath: keyPath] > $1[keyPath: keyPath] }
}
}
}
class CashierViewModel: ObservableObject {
let id: UUID = UUID()
@ -60,12 +69,18 @@ class CashierViewModel: ObservableObject {
func _shouldDisplayPlayer(_ player: PlayerRegistration) -> Bool {
if searchText.isEmpty == false {
filterOption.shouldDisplayPlayer(player) && player.contains(searchText)
sortOption.shouldDisplayPlayer(player) && filterOption.shouldDisplayPlayer(player) && player.contains(searchText)
} else {
filterOption.shouldDisplayPlayer(player)
sortOption.shouldDisplayPlayer(player) && filterOption.shouldDisplayPlayer(player)
}
}
func _sortPlayers(_ players: [PlayerRegistration]) -> [PlayerRegistration] {
players
.filter({ _shouldDisplayPlayer($0) })
.sorted { sortOption.compare($0, $1, order: sortOrder) }
}
enum SortOption: Int, Identifiable, CaseIterable {
case teamRank
case alphabeticalLastName
@ -74,6 +89,50 @@ class CashierViewModel: ObservableObject {
case age
case callDate
var sortingKeyPath: AnyKeyPath {
switch self {
case .alphabeticalLastName:
return \PlayerRegistration.lastName
case .alphabeticalFirstName:
return \PlayerRegistration.firstName
case .playerRank, .teamRank, .callDate:
return \PlayerRegistration.computedRank
case .age:
return \PlayerRegistration.computedAge!
}
}
func compare(_ lhs: PlayerRegistration, _ rhs: PlayerRegistration, order: SortOrder) -> Bool {
switch self {
case .alphabeticalLastName:
return compare(lhs[keyPath: \.lastName], rhs[keyPath: \.lastName], order: order)
case .alphabeticalFirstName:
return compare(lhs[keyPath: \.firstName], rhs[keyPath: \.firstName], order: order)
case .playerRank, .teamRank, .callDate:
return compare(lhs[keyPath: \.computedRank], rhs[keyPath: \.computedRank], order: order)
case .age:
return compare(lhs[keyPath: \.computedAge!], rhs[keyPath: \.computedAge!], order: order)
}
}
private func compare<T: Comparable>(_ lhs: T, _ rhs: T, order: SortOrder) -> Bool {
switch order {
case .ascending:
return lhs < rhs
case .descending:
return lhs > rhs
}
}
func shouldDisplayPlayer(_ player: PlayerRegistration) -> Bool {
switch self {
case .age:
player.computedAge != nil
default:
true
}
}
var id: Int { self.rawValue }
func localizedLabel() -> String {
switch self {
@ -129,14 +188,16 @@ class CashierViewModel: ObservableObject {
struct CashierView: View {
@EnvironmentObject var dataStore: DataStore
@EnvironmentObject var cashierViewModel: CashierViewModel
var tournaments : [Tournament]
var teams: [TeamRegistration]
@State private var teams: [TeamRegistration]
@State private var players: [PlayerRegistration]
@State private var shareableObject: ShareableObject?
init(tournament: Tournament, teams: [TeamRegistration]) {
self.tournaments = [tournament]
self.teams = teams
_teams = .init(wrappedValue: teams)
_players = .init(wrappedValue: teams.flatMap({ $0.unsortedPlayers() }))
}
var body: some View {
@ -170,22 +231,21 @@ struct CashierView: View {
}
}
let filteredPlayers = cashierViewModel._sortPlayers(players)
if filteredPlayers.isEmpty {
_contentUnavailableView()
}
switch cashierViewModel.sortOption {
case .teamRank:
_byTeamRankView()
case .alphabeticalLastName:
_byPlayerLastName()
case .alphabeticalFirstName:
_byPlayerFirstName()
case .playerRank:
_byPlayerRank()
case .age:
_byPlayerAge()
TeamRankView(teams: teams, displayTournamentTitle: tournaments.count > 1)
case .alphabeticalLastName, .alphabeticalFirstName, .playerRank, .age:
PlayerCashierView(players: filteredPlayers, displayTournamentTitle: tournaments.count > 1)
case .callDate:
_byCallDateView()
let _teams = teams.filter({ $0.callDate != nil })
TeamCallDateView(teams: _teams, displayTournamentTitle: tournaments.count > 1)
}
}
.searchable(text: $cashierViewModel.searchText, isPresented: $cashierViewModel.isSearching, placement: .navigationBarDrawer(displayMode: .always), prompt: Text("Chercher un joueur"))
.onAppear {
cashierViewModel.searchText = ""
// if tournaments.count == 1 {
@ -196,7 +256,10 @@ struct CashierView: View {
if cashierViewModel.sortOption == .callDate && teams.first(where: { $0.callDate != nil }) == nil {
cashierViewModel.sortOption = .teamRank
}
self.shareableObject = ShareableObject(cashierViewModel: cashierViewModel, teams: teams, fileName: "Encaissement.txt")
self.shareableObject = ShareableObject(cashierViewModel: cashierViewModel, players: players, fileName: "Encaissement")
}
.onChange(of: cashierViewModel.sortOrder) {
teams = cashierViewModel.sortOrder == .ascending ? teams : teams.reversed()
}
.headerProminence(.increased)
.toolbar {
@ -210,120 +273,85 @@ struct CashierView: View {
}
}
}
struct PlayerCashierView: View {
@EnvironmentObject var cashierViewModel: CashierViewModel
let players: [PlayerRegistration]
let displayTournamentTitle: Bool
@ViewBuilder
private func _byPlayer(_ players: [PlayerRegistration]) -> some View {
let _players = cashierViewModel.sortOrder == .ascending ? players : players.reversed()
if _players.isEmpty {
_contentUnavailableView()
} else {
ForEach(_players) { player in
var body: some View {
ForEach(players) { player in
Section {
EditablePlayerView(player: player, editingOptions: [.licenceId, .name, .payment])
} header: {
HStack {
if let teamCallDate = player.team()?.callDate {
Text(teamCallDate.localizedDate())
}
Spacer()
Text(player.formattedRank())
if displayTournamentTitle, let tournamentTitle = player.tournament()?.tournamentTitle() {
Text(tournamentTitle)
}
} footer: {
if tournaments.count > 1, let tournamentTitle = player.tournament()?.tournamentTitle() {
Text(tournamentTitle)
if let teamCallDate = player.team()?.callDate {
Text("équipe convoqué") + Text(teamCallDate.localizedDate())
}
}
}
}
}
@ViewBuilder
private func _byPlayerRank() -> some View {
let players = teams.flatMap({ $0.unsortedPlayers() }).sorted(using: .keyPath(\.computedRank)).filter({ cashierViewModel._shouldDisplayPlayer($0) })
_byPlayer(players)
}
@ViewBuilder
private func _byPlayerAge() -> some View {
let players = teams.flatMap({ $0.unsortedPlayers() }).filter({ $0.computedAge != nil }).sorted(using: .keyPath(\.computedAge!)).filter({ cashierViewModel._shouldDisplayPlayer($0) })
_byPlayer(players)
}
@ViewBuilder
private func _byPlayerLastName() -> some View {
let players = teams.flatMap({ $0.unsortedPlayers() }).sorted(using: .keyPath(\.lastName)).filter({ cashierViewModel._shouldDisplayPlayer($0) })
_byPlayer(players)
}
@ViewBuilder
private func _byPlayerFirstName() -> some View {
let players = teams.flatMap({ $0.unsortedPlayers() }).sorted(using: .keyPath(\.firstName)).filter({ cashierViewModel._shouldDisplayPlayer($0) })
_byPlayer(players)
}
@ViewBuilder
private func _byTeamRankView() -> some View {
let _teams = cashierViewModel.sortOrder == .ascending ? teams : teams.reversed()
let _filteredTeams = _teams.filter({ cashierViewModel._shouldDisplayTeam($0) })
if _filteredTeams.isEmpty {
_contentUnavailableView()
} else {
ForEach(_filteredTeams) { team in
Section {
ForEach(team.players()) { player in
if cashierViewModel._shouldDisplayPlayer(player) {
struct TeamRankView: View {
@EnvironmentObject var cashierViewModel: CashierViewModel
let teams: [TeamRegistration]
let displayTournamentTitle: Bool
var body: some View {
ForEach(teams) { team in
let players = team.players().filter({ cashierViewModel._shouldDisplayPlayer($0) })
if players.isEmpty == false {
Section {
ForEach(players) { player in
EditablePlayerView(player: player, editingOptions: [.licenceId, .name, .payment])
}
}
} header: {
HStack {
if let callDate = team.callDate {
Text(callDate.localizedDate())
} header: {
if displayTournamentTitle, let tournamentTitle = team.tournamentObject()?.tournamentTitle() {
Text(tournamentTitle)
}
Spacer()
VStack(alignment: .trailing, spacing: 0) {
Text("Poids").font(.caption)
Text(team.weight.formatted())
} footer: {
if let callDate = team.callDate {
Text("convoqué") + Text(callDate.localizedDate())
}
}
} footer: {
if tournaments.count > 1, let tournamentTitle = team.tournamentObject()?.tournamentTitle() {
Text(tournamentTitle)
}
}
}
}
}
@ViewBuilder
private func _byCallDateView() -> some View {
let _teams = teams.filter({ $0.callDate != nil && cashierViewModel._shouldDisplayTeam($0) })
if _teams.isEmpty {
_contentUnavailableView()
}
let groupedTeams = Dictionary(grouping: _teams) { team in
team.callDate
}
let keys = cashierViewModel.sortOrder == .ascending ? groupedTeams.keys.compactMap { $0 }.sorted() : groupedTeams.keys.compactMap { $0 }.sorted().reversed()
struct TeamCallDateView: View {
@EnvironmentObject var cashierViewModel: CashierViewModel
let teams: [TeamRegistration]
let displayTournamentTitle: Bool
ForEach(keys, id: \.self) { key in
if let _teams = groupedTeams[key] {
ForEach(_teams) { team in
Section {
ForEach(team.players()) { player in
if cashierViewModel._shouldDisplayPlayer(player) {
EditablePlayerView(player: player, editingOptions: [.licenceId, .name, .payment])
var body: some View {
let groupedTeams = Dictionary(grouping: teams) { team in
team.callDate
}
let keys = cashierViewModel.sortOrder == .ascending ? groupedTeams.keys.compactMap { $0 }.sorted() : groupedTeams.keys.compactMap { $0 }.sorted().reversed()
ForEach(keys, id: \.self) { key in
if let _teams = groupedTeams[key] {
ForEach(_teams) { team in
let players = team.players().filter({ cashierViewModel._shouldDisplayPlayer($0) })
if players.isEmpty == false {
Section {
ForEach(players) { player in
EditablePlayerView(player: player, editingOptions: [.licenceId, .name, .payment])
}
} header: {
Text(key.localizedDate())
} footer: {
if displayTournamentTitle, let tournamentTitle = team.tournamentObject()?.tournamentTitle() {
Text(tournamentTitle)
}
}
}
} header: {
Text(key.localizedDate())
} footer: {
if tournaments.count > 1, let tournamentTitle = team.tournamentObject()?.tournamentTitle() {
Text(tournamentTitle)
}
}
}
}

@ -31,14 +31,43 @@ struct ClubDetailView: View {
var body: some View {
Form {
if displayContext == .edition || displayContext == .lockedForEditing {
let isFavorite = club.isFavorite()
Section {
RowButtonView(isFavorite ? "Retirer des favoris" : "Mettre en favori", role: isFavorite ? .destructive : nil) {
if isFavorite {
dataStore.user.clubs.removeAll(where: { $0 == club.id })
} else {
dataStore.user.clubs.append(club.id)
}
self.dataStore.saveUser()
}
} footer: {
if displayContext == .lockedForEditing {
Text("Édition impossible, vous n'êtes pas le créateur de ce club.").foregroundStyle(.logoRed)
}
}
}
Section {
TextField("Nom du club", text: $club.name, axis: .vertical)
.lineLimit(2)
TextField("Nom du club", text: $club.name)
.autocorrectionDisabled()
.keyboardType(.alphabet)
.frame(maxWidth: .infinity)
.focused($focusedField, equals: ._name)
.submitLabel( displayContext == .addition ? .next : .done)
.onSubmit(of: .text) {
if club.acronym.isEmpty {
club.acronym = club.name.canonicalVersion.replaceCharactersFromSet(characterSet: .whitespacesAndNewlines)
}
if displayContext == .edition && city.isEmpty == true {
focusedField = ._city
} else {
focusedField = nil
}
}
LabeledContent {
if acronymMode == .automatic || displayContext == .lockedForEditing {
Text(club.acronym)
@ -85,9 +114,7 @@ struct ClubDetailView: View {
}
}
} footer: {
if displayContext == .lockedForEditing {
Text("Édition impossible, vous n'êtes pas le créateur de ce club.").foregroundStyle(.logoRed)
} else {
if displayContext != .lockedForEditing {
Text("Vous pouvez personaliser le nom court ou laisser celui généré par défaut.")
}
}
@ -132,34 +159,29 @@ struct ClubDetailView: View {
.onTapGesture {
focusedField = ._zipCode
}
} footer: {
if displayContext == .lockedForEditing {
Text("Édition impossible, vous n'êtes pas le créateur de ce club.").foregroundStyle(.logoRed)
}
}
.disabled(displayContext == .lockedForEditing)
}
ClubCourtSetupView(club: club, displayContext: displayContext, selectedCourt: $selectedCourt)
if let padelClubLink = club.shareURL() {
Section {
Link(destination: padelClubLink) {
Text("Accéder au club sur le site Padel Club")
}
}
}
if let federalLink = club.federalLink() {
let federalLink = club.federalLink()
let padelClubLink = club.shareURL()
if federalLink != nil || padelClubLink != nil {
Section {
LabeledContent("Code Club") {
Text(club.code ?? "")
}
LabeledContent("Ville") {
Text(club.city ?? "")
if let federalLink {
LabeledContent("Code Club") {
Text(club.code ?? "")
}
LabeledContent("Ville") {
Text(club.city ?? "")
}
Link(destination: federalLink) {
Text("Accéder au club sur Tenup")
}
}
Link(destination: federalLink) {
Text("Voir la fiche du club sur tenup")
if let padelClubLink {
Link(destination: padelClubLink) {
Text("Accéder au club sur Padel Club")
}
}
}
}
@ -189,20 +211,7 @@ struct ClubDetailView: View {
}
}
if displayContext == .edition || displayContext == .lockedForEditing {
let isFavorite = club.isFavorite()
Section {
RowButtonView(isFavorite ? "Retirer des favoris" : "Mettre en favori", role: isFavorite ? .destructive : nil) {
if isFavorite {
dataStore.user.clubs.removeAll(where: { $0 == club.id })
} else {
dataStore.user.clubs.append(club.id)
}
self.dataStore.saveUser()
}
}
}
ClubCourtSetupView(club: club, displayContext: displayContext, selectedCourt: $selectedCourt, hideLockForEditingMessage: true)
if displayContext == .edition {
Section {
@ -211,6 +220,7 @@ struct ClubDetailView: View {
try dataStore.clubs.deleteById(club.id)
dataStore.user.clubs.removeAll(where: { $0 == club.id })
self.dataStore.saveUser()
dismiss()
} catch {
Logger.error(error)
}
@ -245,27 +255,6 @@ 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)
}
}
}
}
}
}

@ -27,31 +27,56 @@ struct ClubsView: View {
var body: some View {
List {
let clubs : [Club] = dataStore.user.clubsObjects(includeCreated: true)
ForEach(clubs) { club in
if let selection {
Button {
selection(club)
dismiss()
} label: {
ClubRowView(club: club, displayContext: .selection)
.frame(maxWidth: .infinity)
let clubs : [Club] = dataStore.user.clubsObjects(includeCreated: false)
Section {
ForEach(clubs) { club in
if let selection {
Button {
selection(club)
dismiss()
} label: {
ClubRowView(club: club, displayContext: .selection)
.frame(maxWidth: .infinity)
}
.contentShape(Rectangle())
.buttonStyle(.plain)
} else {
NavigationLink {
ClubDetailView(club: club, displayContext: club.hasBeenCreated(by: dataStore.user.id) ? .edition : .lockedForEditing)
} label: {
ClubRowView(club: club)
}
}
.contentShape(Rectangle())
.buttonStyle(.plain)
} else {
NavigationLink {
ClubDetailView(club: club, displayContext: club.hasBeenCreated(by: dataStore.user.id) ? .edition : .lockedForEditing)
} label: {
ClubRowView(club: club)
}
} header: {
Text("Clubs favoris")
}
let onlyCreatedClubs : [Club] = dataStore.user.createdClubsObjectsNotFavorite()
if onlyCreatedClubs.isEmpty == false {
Section {
ForEach(onlyCreatedClubs) { club in
if let selection {
Button {
selection(club)
dismiss()
} label: {
ClubRowView(club: club, displayContext: .selection)
.frame(maxWidth: .infinity)
}
.contentShape(Rectangle())
.buttonStyle(.plain)
} else {
NavigationLink {
ClubDetailView(club: club, displayContext: club.hasBeenCreated(by: dataStore.user.id) ? .edition : .lockedForEditing)
} label: {
ClubRowView(club: club)
}
}
}
// .swipeActions(edge: .trailing, allowsFullSwipe: true) {
// Button(role: .destructive) {
// try? dataStore.clubs.delete(instance: club)
// } label: {
// LabelDelete()
// }
// }
} header: {
Text("Clubs créés retirés des favoris")
}
}
}

@ -14,16 +14,11 @@ struct CreateClubView: View {
var club: Club
var selection: ((Club) -> ())? = nil
@State private var validationInProgress: Bool = false
var body: some View {
NavigationStack {
ClubDetailView(club: club, displayContext: .addition, selection: selection)
.task {
do {
try await dataStore.clubs.loadDataFromServerIfAllowed()
} catch {
Logger.error(error)
}
}
.toolbar {
ToolbarItem(placement: .cancellationAction) {
Button("Annuler", role: .cancel) {
@ -31,10 +26,27 @@ struct CreateClubView: View {
}
}
ToolbarItem(placement: .confirmationAction) {
ButtonValidateView {
if validationInProgress {
ProgressView()
} else {
ButtonValidateView {
validationInProgress = true
}
.disabled(club.isValid == false)
}
}
}
.onChange(of: validationInProgress) {
if validationInProgress {
Task {
do {
try await dataStore.clubs.loadDataFromServerIfAllowed()
} catch {
Logger.error(error)
}
let existingOrCreatedClub = Club.findOrCreate(name: club.name, code: club.code, city: club.city, zipCode: club.zipCode)
//update existing club if rights ok / freshly created club with data input from user
if existingOrCreatedClub.hasBeenCreated(by: dataStore.user.id) {
existingOrCreatedClub.update(fromClub: club)
@ -53,7 +65,6 @@ struct CreateClubView: View {
dismiss()
selection?(existingOrCreatedClub)
}
.disabled(club.isValid == false)
}
}
}

@ -13,7 +13,8 @@ struct ClubCourtSetupView: View {
@Bindable var club: Club
let displayContext: DisplayContext
@Binding var selectedCourt: Court?
var hideLockForEditingMessage: Bool = false
@ViewBuilder
var body: some View {
Section {
@ -41,7 +42,7 @@ struct ClubCourtSetupView: View {
// }
// }
} footer: {
if displayContext == .lockedForEditing {
if displayContext == .lockedForEditing && hideLockForEditingMessage == false {
Text("Édition impossible, vous n'êtes pas le créateur de ce club.").foregroundStyle(.logoRed)
}
}

@ -48,7 +48,9 @@ struct MainView: View {
dataStore.matches.filter({ $0.confirmed && $0.startDate != nil && $0.endDate == nil && $0.courtIndex != nil })
}
var badgeText: Text? = Store.main.userId == nil ? Text("!").font(.headline) : nil
var badgeText: Text? {
dataStore.user.username.isEmpty ? Text("!").font(.headline) : nil
}
var body: some View {
TabView(selection: selectedTabHandler) {
@ -67,8 +69,8 @@ struct MainView: View {
// PadelClubView()
// .tabItem(for: .padelClub)
}
.id(Store.main.userId)
.onChange(of: Store.main.userId) {
.id(dataStore.user.id)
.onChange(of: dataStore.user.id) {
navigation.path.removeLast(navigation.path.count)
}
.environmentObject(dataStore)

@ -109,7 +109,7 @@ struct UmpireView: View {
LabeledContent {
Text(dataStore.user.clubs.count.formatted())
} label: {
Label("Mes clubs", systemImage: "house.and.flag")
Label("Clubs favoris", systemImage: "house.and.flag")
}
}
} footer: {

@ -6,6 +6,7 @@
//
import SwiftUI
import Combine
enum CashierDestination: Identifiable, Selectable, Equatable {
@ -20,8 +21,10 @@ enum CashierDestination: Identifiable, Selectable, Equatable {
var id: String {
switch self {
case .summary, .all:
case .summary:
return String(describing: self)
case .all(let tournament):
return tournament.id
case .groupStage(let groupStage):
return groupStage.id
case .bracket(let round):
@ -80,15 +83,19 @@ struct TournamentCashierView: View {
var tournament: Tournament
@State private var selectedDestination: CashierDestination?
@StateObject private var cashierViewModel: CashierViewModel = CashierViewModel()
var allDestinations: [CashierDestination]
func allDestinations() -> [CashierDestination] {
init(tournament: Tournament) {
self.tournament = tournament
var allDestinations : [CashierDestination] = []
let tournamentHasEnded = tournament.hasEnded()
if tournamentHasEnded {
allDestinations.append(.summary)
}
allDestinations.append(.all(tournament))
let all = CashierDestination.all(tournament)
allDestinations.append(all)
let destinations : [CashierDestination] = tournament.groupStages().map { CashierDestination.groupStage($0) }
allDestinations.append(contentsOf: destinations)
@ -102,50 +109,49 @@ struct TournamentCashierView: View {
allDestinations.append(.summary)
}
return allDestinations
}
self.allDestinations = allDestinations
init(tournament: Tournament) {
self.tournament = tournament
if tournament.hasEnded() {
if tournament.players().anySatisfy({ $0.hasPaid() == false }) == false {
_selectedDestination = .init(wrappedValue: .summary)
} else {
_selectedDestination = .init(wrappedValue: .all(tournament))
_selectedDestination = .init(wrappedValue: all)
}
} else {
let gs = tournament.getActiveGroupStage()
if let gs {
_selectedDestination = State(wrappedValue: .groupStage(gs))
} else if let rs = tournament.getActiveRound(withSeeds: true) {
_selectedDestination = State(wrappedValue: .bracket(rs))
if let gs, let destination = allDestinations.first(where: { $0.id == gs.id }) {
_selectedDestination = State(wrappedValue: destination)
} else if let rs = tournament.getActiveRound(withSeeds: true), let destination = allDestinations.first(where: { $0.id == rs.id }) {
_selectedDestination = State(wrappedValue: destination)
}
}
}
var body: some View {
VStack(spacing: 0) {
GenericDestinationPickerView(selectedDestination: $selectedDestination, destinations: allDestinations(), nilDestinationIsValid: true)
GenericDestinationPickerView(selectedDestination: $selectedDestination, destinations: allDestinations, nilDestinationIsValid: true)
switch selectedDestination {
case .none:
CashierSettingsView(tournament: tournament)
case .some(let selectedCall):
switch selectedCall {
case .summary:
CashierDetailView(tournament: tournament)
CashierDetailView(tournament: tournament).id(selectedCall.id)
case .groupStage(let groupStage):
CashierView(tournament: tournament, teams: groupStage.teams())
.environmentObject(cashierViewModel)
CashierView(tournament: tournament, teams: groupStage.teams()).id(selectedCall.id)
.searchable(text: $cashierViewModel.searchText, isPresented: $cashierViewModel.isSearching, placement: .navigationBarDrawer(displayMode: .always), prompt: Text("Chercher un joueur"))
case .bracket(let round):
CashierView(tournament: tournament, teams: round.seeds())
.environmentObject(cashierViewModel)
CashierView(tournament: tournament, teams: round.seeds()).id(selectedCall.id)
.searchable(text: $cashierViewModel.searchText, isPresented: $cashierViewModel.isSearching, placement: .navigationBarDrawer(displayMode: .always), prompt: Text("Chercher un joueur"))
case .all(let tournament):
CashierView(tournament: tournament, teams: tournament.selectedSortedTeams())
.environmentObject(cashierViewModel)
CashierView(tournament: tournament, teams: tournament.selectedSortedTeams()).id(selectedCall.id)
.searchable(text: $cashierViewModel.searchText, isPresented: $cashierViewModel.isSearching, placement: .navigationBarDrawer(displayMode: .always), prompt: Text("Chercher un joueur"))
}
}
}
.environment(tournament)
.environmentObject(cashierViewModel)
.navigationBarTitleDisplayMode(.inline)
.toolbarBackground(.visible, for: .navigationBar)
.navigationTitle("Encaissement")
@ -155,3 +161,26 @@ struct TournamentCashierView: View {
#Preview {
TournamentCashierView(tournament: Tournament.mock())
}
//class DebouncedObject: ObservableObject {
// @Published var searchText: String = "" {
// didSet {
// debounceSearchTextPublisher.send(searchText)
// }
// }
//
// private var debounceSearchTextPublisher = PassthroughSubject<String, Never>()
// private var cancellables = Set<AnyCancellable>()
//
// init() {
// debounceSearchTextPublisher
// .debounce(for: .milliseconds(300), scheduler: RunLoop.main)
// .sink { [weak self] in self?.performSearch(with: $0) }
// .store(in: &cancellables)
// }
//
// private func performSearch(with text: String) {
// // Perform the search with the debounced text
// print("Performing search with text: \(text)")
// }
//}

Loading…
Cancel
Save