fixed some issues

This commit is contained in:
umer
2025-05-20 02:48:06 +05:00
parent f1d04650b6
commit 154d1882c8
17 changed files with 550 additions and 153 deletions
@@ -267,7 +267,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
CURRENT_PROJECT_VERSION = 3;
DEVELOPMENT_ASSET_PATHS = "\"Club Portal/Preview Content\"";
DEVELOPMENT_TEAM = BSGYUG5U29;
ENABLE_PREVIEWS = YES;
@@ -300,7 +300,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
CURRENT_PROJECT_VERSION = 3;
DEVELOPMENT_ASSET_PATHS = "\"Club Portal/Preview Content\"";
DEVELOPMENT_TEAM = BSGYUG5U29;
ENABLE_PREVIEWS = YES;
@@ -100,22 +100,6 @@
landmarkType = "24">
</BreakpointContent>
</BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
uuid = "1D973B51-0BF4-4CAE-9D3D-08BB2000E001"
shouldBeEnabled = "No"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "Club Portal/UI/Dashboard/DashboardView.swift"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "66"
endingLineNumber = "66"
landmarkName = "body"
landmarkType = "24">
</BreakpointContent>
</BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
@@ -256,6 +256,52 @@ final class APIService {
}
}
func requestStatics(_ endpoint: Endpoint) async throws -> ClubStatisticsResponse? {
guard let request = endpoint.urlRequest else {
throw APIError.invalidURL
}
print("Request URL: \(request.url?.absoluteString ?? "Invalid URL")")
let (data, response) = try await URLSession.shared.data(for: request)
guard let httpResponse = response as? HTTPURLResponse else {
throw APIError.invalidResponse(0, "No HTTP response received")
}
print("HTTP Status Code: \(httpResponse.statusCode)")
if !(200..<300).contains(httpResponse.statusCode) {
if let errorResponse = try? JSONDecoder().decode(ErrorResponse.self, from: data) {
if errorResponse.message == "TOKEN_EXPIRED" {
// Perform logout
throw APIError.logout
}
throw APIError.serverError(errorResponse.message)
} else {
throw APIError.invalidResponse(httpResponse.statusCode, "Unknown server error")
}
}
do {
if let responseString = String(data: data, encoding: .utf8) {
print("Response: \(responseString)")
if let resp = ClubStatisticsResponse(JSONString: responseString) {
print(resp)
return resp
}
}
return nil
} catch {
throw APIError.decodingError(error)
}
}
func requestCoach(_ endpoint: Endpoint) async throws -> CoacheList? {
guard let request = endpoint.urlRequest else {
throw APIError.invalidURL
@@ -4,65 +4,314 @@
//
// Created by Umer Tahir on 11/04/2025.
//
import ObjectMapper
struct ClubStatisticsResponse: Decodable {
let error: Bool
let model: ClubStatisticsModel
class ClubStatisticsResponse : Mappable {
var error : Bool?
var model : ClubStatisticsModel?
required init?(map: Map) {
}
func mapping(map: Map) {
error <- map["error"]
model <- map["model"]
}
}
struct ClubStatisticsModel: Decodable {
let clinicReservations: [ReservationStats]
let coachReservations: [ReservationStats]
let totalReservations: [ReservationStats]
let revenueHeatMap: [RevenueHeatMap]
let revenueByDateRange: [RevenueByDateRange]
let revenueByModule: [RevenueByModule]
let buddyStatistics: [ReservationStats]
let totalExpenses: [ExpenseStats]
let totalRevenue: [RevenueStats]
let totalProfit: [ProfitStats]
let courtUtilization: [CourtUtilizationStats]
let lessonReservations: [ReservationStats]
class ClubStatisticsModel : Mappable {
var clinicReservations : [ClinicReservations]?
var coachReservations : [CoachReservations]?
var totalReservations : [TotalReservations]?
var revenueHeatMap : [RevenueHeatMap]?
var revenueByDateRange : [RevenueByDateRange]?
var revenueByModule : [RevenueByModule]?
var buddyStatistics : [BuddyStatistics]?
var totalExpenses : [TotalExpenses]?
var totalRevenue : [TotalRevenue]?
var totalProfit : [TotalProfit]?
var courtUtilization : [CourtUtilization]?
var lessonReservations : [LessonReservations]?
var revenueByDay : [RevenueByDay]?
var revenueBarChart : RevenueBarChart?
required init?(map: Map) {
}
func mapping(map: Map) {
clinicReservations <- map["clinicReservations"]
coachReservations <- map["coachReservations"]
totalReservations <- map["totalReservations"]
revenueHeatMap <- map["revenueHeatMap"]
revenueByDateRange <- map["revenueByDateRange"]
revenueByModule <- map["revenueByModule"]
buddyStatistics <- map["buddyStatistics"]
totalExpenses <- map["totalExpenses"]
totalRevenue <- map["totalRevenue"]
totalProfit <- map["totalProfit"]
courtUtilization <- map["courtUtilization"]
lessonReservations <- map["lessonReservations"]
revenueByDay <- map["revenueByDay"]
revenueBarChart <- map["revenueBarChart"]
}
}
struct ReservationStats: Decodable {
let total_hours: Double?
let total_revenue: Double?
class BuddyStatistics : Mappable {
var total_hours : String?
var total_revenue : String?
required init?(map: Map) {
}
func mapping(map: Map) {
total_hours <- map["total_hours"]
total_revenue <- map["total_revenue"]
}
}
struct RevenueHeatMap: Decodable {
let date: String
let total_revenue: Double
class ClinicReservations : Mappable {
var total_hours : String?
var total_revenue : String?
required init?(map: Map) {
}
func mapping(map: Map) {
total_hours <- map["total_hours"]
total_revenue <- map["total_revenue"]
}
}
struct RevenueByDateRange: Decodable {
// Add fields if needed
class CoachReservations : Mappable {
var total_hours : String?
var total_revenue : String?
required init?(map: Map) {
}
func mapping(map: Map) {
total_hours <- map["total_hours"]
total_revenue <- map["total_revenue"]
}
}
struct RevenueByModule: Decodable {
let module: String
let revenue: Double?
class CourtUtilization : Mappable {
var utilization_percentage : String?
var total_used_hours : String?
var total_available_hours : String?
required init?(map: Map) {
}
func mapping(map: Map) {
utilization_percentage <- map["utilization_percentage"]
total_used_hours <- map["total_used_hours"]
total_available_hours <- map["total_available_hours"]
}
}
struct ExpenseStats: Decodable {
let total_hours: Double?
let total_expense: Double?
class BarData : Mappable {
var clinic : [Int]?
var coach : [Double]?
required init?(map: Map) {
}
func mapping(map: Map) {
clinic <- map["clinic"]
coach <- map["coach"]
}
}
struct RevenueStats: Decodable {
let total_hours: Double?
let total_revenue: Double?
class LessonReservations : Mappable {
var total_hours : String?
var total_revenue : String?
required init?(map: Map) {
}
func mapping(map: Map) {
total_hours <- map["total_hours"]
total_revenue <- map["total_revenue"]
}
}
struct ProfitStats: Decodable {
let total_profit: Double?
let total_revenue: Double?
let total_expense: Double?
class RevenueBarChart : Mappable {
var days : [String]?
var data : BarData?
required init?(map: Map) {
}
func mapping(map: Map) {
days <- map["days"]
data <- map["data"]
}
}
struct CourtUtilizationStats: Decodable {
let utilization_percentage: Double?
let total_used_hours: Double?
let total_available_hours: Double?
class RevenueByDateRange : Mappable {
var date : String?
var clinic_revenue : String?
var coach_revenue : String?
required init?(map: Map) {
}
func mapping(map: Map) {
date <- map["date"]
clinic_revenue <- map["clinic_revenue"]
coach_revenue <- map["coach_revenue"]
}
}
class RevenueByDay : Mappable {
var day : String?
var module : String?
var revenue : Double?
required init?(map: Map) {
}
func mapping(map: Map) {
day <- map["day"]
module <- map["module"]
revenue <- map["revenue"]
}
}
class RevenueByModule : Mappable {
var module : String!
var revenue : Int!
required init?(map: Map) {
}
func mapping(map: Map) {
module <- map["module"]
revenue <- map["revenue"]
}
}
class RevenueHeatMap : Mappable {
var date : String?
var total_revenue : Double?
required init?(map: Map) {
}
func mapping(map: Map) {
date <- map["date"]
total_revenue <- map["total_revenue"]
}
}
class TotalExpenses : Mappable {
var total_hours : String?
var total_expense : String?
required init?(map: Map) {
}
func mapping(map: Map) {
total_hours <- map["total_hours"]
total_expense <- map["total_expense"]
}
}
class TotalProfit : Mappable {
var total_profit : Int?
var total_revenue : Double?
var total_expense : Double?
required init?(map: Map) {
}
func mapping(map: Map) {
total_profit <- map["total_profit"]
total_revenue <- map["total_revenue"]
total_expense <- map["total_expense"]
}
}
class TotalReservations : Mappable {
var total_hours : String?
var total_revenue : String?
required init?(map: Map) {
}
func mapping(map: Map) {
total_hours <- map["total_hours"]
total_revenue <- map["total_revenue"]
}
}
class TotalRevenue : Mappable {
var total_hours : String?
var total_revenue : String?
required init?(map: Map) {
}
func mapping(map: Map) {
total_hours <- map["total_hours"]
total_revenue <- map["total_revenue"]
}
}
@@ -101,6 +101,7 @@ class Booking : Mappable, Identifiable {
var create_at : String?
var update_at : String?
var coach_ids : String?
var sport_name : String?
required init?(map: Map) {
@@ -144,6 +145,8 @@ class Booking : Mappable, Identifiable {
create_at <- map["create_at"]
update_at <- map["update_at"]
coach_ids <- map["coach_ids"]
sport_name <- map["sport_name"]
}
}
@@ -47,6 +47,12 @@ struct AvailabilityScreen: View {
.onChange(of: endDate) { _ in
viewModel.getAvailability(startDate: startDate.toCustomString, endDate: endDate.toCustomString, startTime: startTime.toTimeString, endTime: endTime.toTimeString)
}
.onChange(of: startTime) { _ in
viewModel.getAvailability(startDate: startDate.toCustomString, endDate: endDate.toCustomString, startTime: startTime.toTimeString, endTime: endTime.toTimeString)
}
.onChange(of: endTime) { _ in
viewModel.getAvailability(startDate: startDate.toCustomString, endDate: endDate.toCustomString, startTime: startTime.toTimeString, endTime: endTime.toTimeString)
}
}
}
@@ -8,29 +8,47 @@
import SwiftUI
struct CoachesTab: View {
@EnvironmentObject var viewModel : DashViewModel
var body: some View {
ScrollView {
VStack(alignment: .leading, spacing: 12) {
ForEach(0..<3, id: \.self) { _ in
HStack(spacing: 12) {
ProfileImageView(imageUrl: "", size: 40)
VStack(alignment: .leading, spacing: 4) {
Text("Steve Jobs")
if let players = viewModel.coaches {
ForEach(players, id: \.id) { index in
HStack(spacing: 12) {
ProfileImageView(imageUrl: index.user?.photo ?? "", size: 40)
VStack(alignment: .leading, spacing: 2) {
Text("\(index.user?.first_name ?? "") \(index.user?.last_name ?? "" )")
.font(.headline)
Text("Hours playing: 9:00 AM 10:00 AM")
.font(.caption)
.foregroundColor(.secondary)
}
Spacer()
}
}
.padding()
.background(Color(.systemGray6))
.cornerRadius(10)
}
}
.padding()
.onAppear(){
if let ids = viewModel.selectedReservation?.booking?.coach_ids?.toCommaSeparated {
viewModel.getCoaches(playerIds: ids)
}
}
}
}
}
@@ -34,7 +34,7 @@ struct DetailsTab: View {
DetailRow(title: "Reservation date", value: viewModel.selectedReservation?.booking?.date ?? "16 April, 2024")
DetailRow(title: "Time", value: "\(viewModel.selectedReservation?.booking?.start_time ?? "16:00:00" ) - \(viewModel.selectedReservation?.booking?.end_time ?? "16:00:00" ) ")
DetailRow(title: "Event type", value: "Lesson")
DetailRow(title: "Sport/type", value: "\(viewModel.selectedReservation?.booking?.sport_id ?? 1)\(viewModel.selectedReservation?.booking?.type ?? "")\(viewModel.selectedReservation?.booking?.subtype ?? "") ")
DetailRow(title: "Sport/type", value: "\(viewModel.selectedReservation?.booking?.sport_name ?? "")\(viewModel.selectedReservation?.booking?.type ?? "")\(viewModel.selectedReservation?.booking?.subtype ?? "") ")
DetailRow(title: "Repeating", value: "Every week")
DetailRow(title: "Space assigned", value: "Court #5")
DetailRow(title: "Court fee", value: "$\(viewModel.selectedReservation?.booking?.court_fee ?? "10")")
@@ -43,7 +43,7 @@ struct ScheduleFilterView: View {
}
.padding(.top, 10)
} label: {
Text("Club")
Text("Courts")
.font(.headline)
}
.padding()
@@ -13,34 +13,44 @@ struct PlayersTab: View {
var body: some View {
ScrollView {
VStack(alignment: .leading, spacing: 12) {
ForEach(0..<5, id: \.self) { index in
if let players = viewModel.players {
ForEach(players, id: \.id) { index in
HStack(spacing: 12) {
ProfileImageView(imageUrl: "", size: 40)
ProfileImageView(imageUrl: index.photo, size: 40)
VStack(alignment: .leading, spacing: 2) {
Text("Steve Jobs")
Text("\(index.first_name ?? "") \(index.last_name ?? "" )")
.font(.headline)
if index == 0 {
Text("Guardian sign-in: Steve Jobs")
.font(.caption)
.foregroundColor(.gray)
}
// if index == 0 {
// Text("Guardian sign-in: Steve Jobs")
// .font(.caption)
// .foregroundColor(.gray)
// }
}
Spacer()
if index == 0 {
Image(systemName: "checkmark.seal.fill")
.foregroundColor(.green)
}
// if index == 0 {
// Image(systemName: "checkmark.seal.fill")
// .foregroundColor(.green)
// }
}
.padding()
.background(Color(.systemGray6))
.cornerRadius(10)
}
}
}
.padding()
.onAppear(){
if let ids = viewModel.selectedReservation?.booking?.player_ids?.toCommaSeparated {
viewModel.getPlayers(playerIds: ids)
}
}
}
}
}
@@ -12,6 +12,9 @@ struct ScheduleView: View {
let hours = Array(0...23)
let calendar = Calendar.current
@State private var selectedCourtName: String? = nil
@State private var selectedCourtId: Int? = nil
@EnvironmentObject var viewModel : DashViewModel
var body: some View {
@@ -43,7 +46,28 @@ struct ScheduleView: View {
HStack {
Spacer()
Text(courtName)
if let clubs = self.viewModel.profile?.model?.courts {
ScrollView(.horizontal, showsIndicators: false) {
HStack(spacing: 16) {
ForEach(clubs, id: \.self) { court in
if let clubName = court.name {
Button(action: {
selectedCourtName = clubName
selectedCourtId = court.id
viewModel.getDailySched(clubId: court.id ?? 0)
}) {
Text(clubName)
.padding(5)
.background(selectedCourtName == clubName ? Colorr.themeBlueColor : Color.gray.opacity(0.2))
.foregroundColor(selectedCourtName == clubName ? .white : .primary)
.cornerRadius(8)
}
}
}
}
.padding(.horizontal)
}
}
Spacer()
}
// Time Slots with Events
@@ -221,6 +245,7 @@ struct ScheduleView: View {
}
.onTapGesture {
selectedDate = date
viewModel.getDailySched(clubId: selectedCourtId ?? 0)
}
.id(calendar.startOfDay(for: date))
}
@@ -20,9 +20,9 @@ struct AnalyticsView: View {
ScrollView {
VStack(spacing: 15) {
PieChartCard(data: self.viewModel.statResponse?.revenueByModule ?? [])
// BarChartCard(data: self.viewModel.statResponse?.revenueHeatMap ?? [])
BarChartCard(data: self.viewModel.statResponse?.revenueHeatMap ?? [])
// PieChartCard1()
BarChartCard1()
// BarChartCard1()
}
.padding(.horizontal)
}
@@ -86,14 +86,14 @@ struct PieChartCard: View {
var body: some View {
let chartData = data.map {
(name: $0.module, value: $0.revenue ?? 0, color: randomColor())
(name: $0.module, value: $0.revenue ?? 0, color: randomColor(module: $0.module))
}
CardView(title: "% made through each module") {
VStack {
HStack {
ForEach(chartData, id: \.name) { item in
LegendView(color: item.color, text: item.name)
LegendView(color: item.color, text: item.name ?? "")
}
.padding(.top, 5)
}
@@ -111,9 +111,16 @@ struct PieChartCard: View {
}
}
func randomColor() -> Color {
let colors: [Color] = [Colorr.pieBlue, Colorr.pieGreen, .orange, .purple, .pink, .mint]
return colors.randomElement() ?? .blue
func randomColor(module: String) -> Color {
switch(module){
case "Clinics":
return Colorr.pieBlue
case "Coaching":
return Colorr.greenColor
default:
return .orange
}
}
}
@@ -156,10 +163,10 @@ struct BarChartCard: View {
var body: some View {
let barData: [ModuleRevenue] = data.map {
ModuleRevenue(day: $0.date.toWeekday()!, module: $0.date.toWeekday()!, value: $0.total_revenue )
ModuleRevenue(day: $0.date?.toWeekday()! ?? "", module: $0.date?.toWeekday() ?? "", value: $0.total_revenue ?? 0.0 )
}
CardView(title: "Revenue from each module") {
CardView(title: "Revenue from each day") {
Chart(barData) { data in
BarMark(
x: .value("Day", data.day),
@@ -27,20 +27,52 @@ struct SummaryView: View {
if selectedTab == 0 {
FilterView(navigationPaths: $navigationPaths, filterCount: $filterCount)
CourtUtilizationView(utilization: "\(self.viewModel.statResponse?.courtUtilization.first?.utilization_percentage ?? 10.0)%" )
CourtUtilizationView(utilization: "\(self.viewModel.statResponse?.courtUtilization?.first?.utilization_percentage ?? "10.0")%" )
ScrollView {
LazyVStack(spacing: 10) {
ReservationCard(title: "Court reservations", hours: "\(self.viewModel.statResponse?.coachReservations.first?.total_hours ?? 0 )", revenue: "$\(self.viewModel.statResponse?.coachReservations.first?.total_revenue ?? 0 )")
ReservationCard(title: "Clinic reservations", hours: "\(self.viewModel.statResponse?.clinicReservations.first?.total_hours ?? 0 )", revenue: "$\(self.viewModel.statResponse?.clinicReservations.first?.total_revenue ?? 0 )")
ReservationCard(title: "Find a Buddy", hours: "\(self.viewModel.statResponse?.buddyStatistics.first?.total_hours ?? 0 )", revenue: "$\(self.viewModel.statResponse?.buddyStatistics.first?.total_revenue ?? 0 )")
ReservationCard(title: "Lesson reservation", hours: "\(self.viewModel.statResponse?.lessonReservations.first?.total_hours ?? 0 )", revenue: "$\(self.viewModel.statResponse?.lessonReservations.first?.total_revenue ?? 0 )")
ReservationCard(
title: "Court reservations",
hours: String(format: "%.2f", self.viewModel.statResponse?.coachReservations?.first?.total_hours ?? 0),
revenue: "$" + String(format: "%.2f", self.viewModel.statResponse?.coachReservations?.first?.total_revenue ?? 0)
)
ReservationCard(title: "Total expenses", hours: "\(self.viewModel.statResponse?.totalExpenses.first?.total_hours ?? 0 )", revenue:"$\(self.viewModel.statResponse?.totalExpenses.first?.total_expense ?? 0 )")
ReservationCard(title: "Total profit", hours: "\(self.viewModel.statResponse?.totalProfit.first?.total_profit ?? 0 )", revenue: "$\(self.viewModel.statResponse?.totalProfit.first?.total_revenue ?? 0 )")
ReservationCard(title: "Total revenue", hours: "\(self.viewModel.statResponse?.totalRevenue.first?.total_hours ?? 0 )", revenue: "$\(self.viewModel.statResponse?.totalRevenue.first?.total_revenue ?? 0 )")
ReservationCard(
title: "Clinic reservations",
hours: String(format: "%.2f", self.viewModel.statResponse?.clinicReservations?.first?.total_hours ?? 0),
revenue: "$" + String(format: "%.2f", self.viewModel.statResponse?.clinicReservations?.first?.total_revenue ?? 0)
)
ReservationCard(
title: "Find a Buddy",
hours: String(format: "%.2f", self.viewModel.statResponse?.buddyStatistics?.first?.total_hours ?? 0),
revenue: "$" + String(format: "%.2f", self.viewModel.statResponse?.buddyStatistics?.first?.total_revenue ?? 0)
)
ReservationCard(
title: "Lesson reservation",
hours: String(format: "%.2f", self.viewModel.statResponse?.lessonReservations?.first?.total_hours ?? 0),
revenue: "$" + String(format: "%.2f", self.viewModel.statResponse?.lessonReservations?.first?.total_revenue ?? 0)
)
ReservationCard(
title: "Total expenses",
hours: String(format: "%.2f", self.viewModel.statResponse?.totalExpenses?.first?.total_hours ?? 0),
revenue: "$" + String(format: "%.2f", self.viewModel.statResponse?.totalExpenses?.first?.total_expense ?? 0)
)
ReservationCard(
title: "Total profit",
hours: String(format: "%.2f", self.viewModel.statResponse?.totalProfit?.first?.total_profit ?? 0),
revenue: "$" + String(format: "%.2f", self.viewModel.statResponse?.totalProfit?.first?.total_revenue ?? 0)
)
ReservationCard(
title: "Total revenue",
hours: String(format: "%.2f", self.viewModel.statResponse?.totalRevenue?.first?.total_hours ?? 0),
revenue: "$" + String(format: "%.2f", self.viewModel.statResponse?.totalRevenue?.first?.total_revenue ?? 0)
)
}
.padding(.horizontal)
@@ -57,7 +89,7 @@ struct SummaryView: View {
if value == "FilterScreen" {
FilterScreen(navigationPaths: $navigationPaths) { startDate, endDate, startTime, endTime, filterCount in
self.filterCount = filterCount
viewModel.getStats ( startDate: startDate, endDate: endDate, startTime: startTime, endTime: endTime, completion: {})
// viewModel.getStats ( startDate: startDate, endDate: endDate, startTime: startTime, endTime: endTime, completion: {})
}
}
}
@@ -109,7 +141,9 @@ struct HeaderView: View {
AppSettings.token = ""
}
Button("Cancel", role: .cancel) { }
Button("Cancel", role: .cancel) {
}
}
}
}
@@ -14,6 +14,7 @@ struct FilterScreen: View {
@State private var endTime: Date = Date()
@State private var startDate: Date = Date()
@State private var endDate: Date = Date()
@EnvironmentObject var viewModel : DashViewModel
@State private var selectedDuration: String = "This Day"
let durationOptions = ["This Day", "This Week", "This Month", "This Year"]
@@ -33,14 +34,14 @@ struct FilterScreen: View {
DatePicker("End Date", selection: $endDate, displayedComponents: .date)
}
Section(header: Text("Duration")) {
Picker("Duration", selection: $selectedDuration) {
ForEach(durationOptions, id: \.self) { duration in
Text(duration)
}
}
.pickerStyle(MenuPickerStyle())
}
// Section(header: Text("Duration")) {
// Picker("Duration", selection: $selectedDuration) {
// ForEach(durationOptions, id: \.self) { duration in
// Text(duration)
// }
// }
// .pickerStyle(MenuPickerStyle())
// }
Section {
Button(action: {
@@ -66,17 +67,17 @@ struct FilterScreen: View {
let timeFormatter = DateFormatter()
timeFormatter.dateFormat = "HH:mm:ss"
let startDateStr = dateFormatter.string(from: startDate)
let endDateStr = dateFormatter.string(from: endDate)
let startTimeStr = timeFormatter.string(from: startTime)
let endTimeStr = timeFormatter.string(from: endTime)
viewModel.dashStartDate = dateFormatter.string(from: startDate)
viewModel.dashEndDate = dateFormatter.string(from: endDate)
viewModel.dashStartTime = timeFormatter.string(from: startTime)
viewModel.dashEndTime = timeFormatter.string(from: endTime)
let query = """
start_date=\(startDateStr)&\
end_date=\(endDateStr)&\
start_time=\(startTimeStr)&\
end_time=\(endTimeStr)
"""
// let query = """
// start_date=\(startDateStr)&\
// end_date=\(endDateStr)&\
// start_time=\(startTimeStr)&\
// end_time=\(endTimeStr)
// """
// 🔢 Count how many filters are applied
var filterCount = 0
@@ -86,10 +87,10 @@ struct FilterScreen: View {
if !Calendar.current.isDate(endTime, equalTo: Date(), toGranularity: .minute) { filterCount += 1 }
if selectedDuration != "This Day" { filterCount += 1 }
print("Generated Filter Query: \(query)")
// print("Generated Filter Query: \(query)")
print("Filter count: \(filterCount)")
self.filterBlock?(startDateStr, endDateStr, startTimeStr, endTimeStr, filterCount)
// self.filterBlock?(startDateStr, endDateStr, startTimeStr, endTimeStr, filterCount)
self.navigationPaths.removeLast()
}
}
@@ -61,6 +61,7 @@ struct SideMenuView: View {
AppSettings.token = ""
presentSideMenu = false
}
})
}
@@ -368,3 +368,13 @@ extension Date {
return formatter.string(from: self)
}
}
extension String {
var toCommaSeparated: String {
self.trimmingCharacters(in: CharacterSet(charactersIn: "[]"))
.split(separator: ",")
.map { $0.trimmingCharacters(in: .whitespaces) }
.joined(separator: ",")
}
}
@@ -22,25 +22,28 @@ class DashViewModel: ObservableObject {
@Published var players : [UserMap]?
@Published var coaches : [PlayerList]?
@Published var dashStartDate : String = "2025-04-01"
@Published var dashEndDate : String = "2025-04-30"
@Published var dashStartTime : String = "08:30"
@Published var dashEndTime : String = "17:00"
func getStats(
startDate: String? = "2024-10-25",
endDate: String? = "2024-11-25",
startTime: String? = "17:30:20",
endTime: String? = "19:20:30",
completion: @escaping () -> ()) {
let endpoint = ClubStatisticsEndpoint(
startDate: startDate!,
endDate: endDate!,
startTime: startTime!,
endTime: endTime!
startDate: dashStartDate,
endDate: dashEndDate,
startTime: dashStartTime,
endTime: dashEndTime
)
Task {
do {
let response: ClubStatisticsResponse = try await APIService.shared.request(endpoint, responseType: ClubStatisticsResponse.self)
print("Statistics fetched: \(response.model)")
if !response.error {
self.statResponse = response.model
let result = try await APIService.shared.requestStatics(endpoint)
print("Statistics fetched: \(result?.model)")
if !result!.error! {
self.statResponse = result?.model
}
else {