working on calendar slot issue

This commit is contained in:
umer
2025-04-30 22:49:39 +05:00
parent 88b392e5e2
commit 00058c440c
22 changed files with 1159 additions and 273 deletions
@@ -7,6 +7,8 @@
objects = { objects = {
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
AC136A092DB96847009D478F /* ObjectMapper in Frameworks */ = {isa = PBXBuildFile; productRef = AC136A082DB96847009D478F /* ObjectMapper */; };
AC53DEAA2DB9476D003445AD /* Alamofire in Frameworks */ = {isa = PBXBuildFile; productRef = AC53DEA92DB9476D003445AD /* Alamofire */; };
ACAC2DEB2D9F2C1900869E5C /* CalendarKit in Frameworks */ = {isa = PBXBuildFile; productRef = ACAC2DEA2D9F2C1900869E5C /* CalendarKit */; }; ACAC2DEB2D9F2C1900869E5C /* CalendarKit in Frameworks */ = {isa = PBXBuildFile; productRef = ACAC2DEA2D9F2C1900869E5C /* CalendarKit */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
@@ -27,7 +29,9 @@
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
AC136A092DB96847009D478F /* ObjectMapper in Frameworks */,
ACAC2DEB2D9F2C1900869E5C /* CalendarKit in Frameworks */, ACAC2DEB2D9F2C1900869E5C /* CalendarKit in Frameworks */,
AC53DEAA2DB9476D003445AD /* Alamofire in Frameworks */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@@ -71,6 +75,8 @@
name = "Club Portal"; name = "Club Portal";
packageProductDependencies = ( packageProductDependencies = (
ACAC2DEA2D9F2C1900869E5C /* CalendarKit */, ACAC2DEA2D9F2C1900869E5C /* CalendarKit */,
AC53DEA92DB9476D003445AD /* Alamofire */,
AC136A082DB96847009D478F /* ObjectMapper */,
); );
productName = "Club Portal"; productName = "Club Portal";
productReference = ACAC2DCF2D9F271300869E5C /* Club Portal.app */; productReference = ACAC2DCF2D9F271300869E5C /* Club Portal.app */;
@@ -102,6 +108,8 @@
minimizedProjectReferenceProxies = 1; minimizedProjectReferenceProxies = 1;
packageReferences = ( packageReferences = (
ACAC2DE92D9F2C1900869E5C /* XCRemoteSwiftPackageReference "CalendarKit" */, ACAC2DE92D9F2C1900869E5C /* XCRemoteSwiftPackageReference "CalendarKit" */,
AC53DEA82DB9476D003445AD /* XCRemoteSwiftPackageReference "Alamofire" */,
AC136A072DB96847009D478F /* XCRemoteSwiftPackageReference "ObjectMapper" */,
); );
preferredProjectObjectVersion = 77; preferredProjectObjectVersion = 77;
productRefGroup = ACAC2DD02D9F271300869E5C /* Products */; productRefGroup = ACAC2DD02D9F271300869E5C /* Products */;
@@ -343,6 +351,22 @@
/* End XCConfigurationList section */ /* End XCConfigurationList section */
/* Begin XCRemoteSwiftPackageReference section */ /* Begin XCRemoteSwiftPackageReference section */
AC136A072DB96847009D478F /* XCRemoteSwiftPackageReference "ObjectMapper" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/tristanhimmelman/ObjectMapper.git";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 4.4.3;
};
};
AC53DEA82DB9476D003445AD /* XCRemoteSwiftPackageReference "Alamofire" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/Alamofire/Alamofire.git";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 5.10.2;
};
};
ACAC2DE92D9F2C1900869E5C /* XCRemoteSwiftPackageReference "CalendarKit" */ = { ACAC2DE92D9F2C1900869E5C /* XCRemoteSwiftPackageReference "CalendarKit" */ = {
isa = XCRemoteSwiftPackageReference; isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/richardtop/CalendarKit"; repositoryURL = "https://github.com/richardtop/CalendarKit";
@@ -354,6 +378,16 @@
/* End XCRemoteSwiftPackageReference section */ /* End XCRemoteSwiftPackageReference section */
/* Begin XCSwiftPackageProductDependency section */ /* Begin XCSwiftPackageProductDependency section */
AC136A082DB96847009D478F /* ObjectMapper */ = {
isa = XCSwiftPackageProductDependency;
package = AC136A072DB96847009D478F /* XCRemoteSwiftPackageReference "ObjectMapper" */;
productName = ObjectMapper;
};
AC53DEA92DB9476D003445AD /* Alamofire */ = {
isa = XCSwiftPackageProductDependency;
package = AC53DEA82DB9476D003445AD /* XCRemoteSwiftPackageReference "Alamofire" */;
productName = Alamofire;
};
ACAC2DEA2D9F2C1900869E5C /* CalendarKit */ = { ACAC2DEA2D9F2C1900869E5C /* CalendarKit */ = {
isa = XCSwiftPackageProductDependency; isa = XCSwiftPackageProductDependency;
package = ACAC2DE92D9F2C1900869E5C /* XCRemoteSwiftPackageReference "CalendarKit" */; package = ACAC2DE92D9F2C1900869E5C /* XCRemoteSwiftPackageReference "CalendarKit" */;
@@ -1,6 +1,15 @@
{ {
"originHash" : "67a1c5e835fc1360427d7e9a548368960eed766e429f7c9f11a95a0e99d682d9", "originHash" : "60390f3252b346980a2b0f96582e92fec2c37e9487d7b684f3d58a001c214046",
"pins" : [ "pins" : [
{
"identity" : "alamofire",
"kind" : "remoteSourceControl",
"location" : "https://github.com/Alamofire/Alamofire.git",
"state" : {
"revision" : "513364f870f6bfc468f9d2ff0a95caccc10044c5",
"version" : "5.10.2"
}
},
{ {
"identity" : "calendarkit", "identity" : "calendarkit",
"kind" : "remoteSourceControl", "kind" : "remoteSourceControl",
@@ -9,6 +18,15 @@
"revision" : "89e02a1472e9ad815ae72b62fd15430144fd1c4c", "revision" : "89e02a1472e9ad815ae72b62fd15430144fd1c4c",
"version" : "1.1.11" "version" : "1.1.11"
} }
},
{
"identity" : "objectmapper",
"kind" : "remoteSourceControl",
"location" : "https://github.com/tristanhimmelman/ObjectMapper.git",
"state" : {
"revision" : "6021c6035e83a306047348666f6400dc61445d3b",
"version" : "4.4.3"
}
} }
], ],
"version" : 3 "version" : 3
@@ -8,7 +8,7 @@
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint"> BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent <BreakpointContent
uuid = "D5681314-32C1-4998-BEBF-D4691C886BC2" uuid = "D5681314-32C1-4998-BEBF-D4691C886BC2"
shouldBeEnabled = "Yes" shouldBeEnabled = "No"
ignoreCount = "0" ignoreCount = "0"
continueAfterRunningActions = "No" continueAfterRunningActions = "No"
filePath = "Club Portal/ViewModels/DashViewModel.swift" filePath = "Club Portal/ViewModels/DashViewModel.swift"
@@ -88,7 +88,7 @@
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint"> BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent <BreakpointContent
uuid = "9DDEE31F-4183-4E3A-8568-5DBD8C04570A" uuid = "9DDEE31F-4183-4E3A-8568-5DBD8C04570A"
shouldBeEnabled = "Yes" shouldBeEnabled = "No"
ignoreCount = "0" ignoreCount = "0"
continueAfterRunningActions = "No" continueAfterRunningActions = "No"
filePath = "Club Portal/ViewModels/DashViewModel.swift" filePath = "Club Portal/ViewModels/DashViewModel.swift"
@@ -152,7 +152,7 @@
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint"> BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent <BreakpointContent
uuid = "002CCE4B-DBB4-4BE0-82C0-03D8524CC2DA" uuid = "002CCE4B-DBB4-4BE0-82C0-03D8524CC2DA"
shouldBeEnabled = "Yes" shouldBeEnabled = "No"
ignoreCount = "0" ignoreCount = "0"
continueAfterRunningActions = "No" continueAfterRunningActions = "No"
filePath = "Club Portal/ViewModels/DashViewModel.swift" filePath = "Club Portal/ViewModels/DashViewModel.swift"
@@ -196,22 +196,6 @@
landmarkType = "7"> landmarkType = "7">
</BreakpointContent> </BreakpointContent>
</BreakpointProxy> </BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
uuid = "E284DADA-1EA8-4DBD-89DA-714E86264DCF"
shouldBeEnabled = "Yes"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "Club Portal/UI/DailySecheduler/ScheduleView.swift"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "76"
endingLineNumber = "76"
landmarkName = "body"
landmarkType = "24">
</BreakpointContent>
</BreakpointProxy>
<BreakpointProxy <BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint"> BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent <BreakpointContent
@@ -232,7 +216,7 @@
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint"> BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent <BreakpointContent
uuid = "1D973B51-0BF4-4CAE-9D3D-08BB2000E001" uuid = "1D973B51-0BF4-4CAE-9D3D-08BB2000E001"
shouldBeEnabled = "Yes" shouldBeEnabled = "No"
ignoreCount = "0" ignoreCount = "0"
continueAfterRunningActions = "No" continueAfterRunningActions = "No"
filePath = "Club Portal/UI/Dashboard/DashboardView.swift" filePath = "Club Portal/UI/Dashboard/DashboardView.swift"
@@ -264,7 +248,7 @@
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint"> BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent <BreakpointContent
uuid = "692D9FC1-2C27-4BD9-BF6C-1817B389E36A" uuid = "692D9FC1-2C27-4BD9-BF6C-1817B389E36A"
shouldBeEnabled = "Yes" shouldBeEnabled = "No"
ignoreCount = "0" ignoreCount = "0"
continueAfterRunningActions = "No" continueAfterRunningActions = "No"
filePath = "Club Portal/ViewModels/AuthViewModel1.swift" filePath = "Club Portal/ViewModels/AuthViewModel1.swift"
@@ -276,5 +260,85 @@
landmarkType = "7"> landmarkType = "7">
</BreakpointContent> </BreakpointContent>
</BreakpointProxy> </BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
uuid = "9F0229B2-427C-4F86-BB4B-02C7B32822AA"
shouldBeEnabled = "No"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "Club Portal/Network/Api_Stuff/APIError.swift"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "60"
endingLineNumber = "60"
landmarkName = "request(_:responseType:)"
landmarkType = "7">
</BreakpointContent>
</BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
uuid = "D4FFED32-06EF-4269-A4CC-2E38B7C48467"
shouldBeEnabled = "No"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "Club Portal/Network/Api_Stuff/APIError.swift"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "57"
endingLineNumber = "57"
landmarkName = "request(_:responseType:)"
landmarkType = "7">
</BreakpointContent>
</BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
uuid = "D6562595-44F2-4161-B839-AB9E5F01BC4A"
shouldBeEnabled = "No"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "Club Portal/UI/DailySecheduler/FilterView1.swift"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "65"
endingLineNumber = "65"
landmarkName = "body"
landmarkType = "24">
</BreakpointContent>
</BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
uuid = "2F83466D-D868-4502-8601-E4770581F3EB"
shouldBeEnabled = "Yes"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "Club Portal/UI/DailySecheduler/ScheduleView.swift"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "241"
endingLineNumber = "241"
landmarkName = "eventOverlay(for:)"
landmarkType = "7">
</BreakpointContent>
</BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
uuid = "EDD74E11-A7AD-4B5F-919B-B2DEB378DD99"
shouldBeEnabled = "Yes"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "Club Portal/UI/DailySecheduler/ScheduleView.swift"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "239"
endingLineNumber = "239"
landmarkName = "eventOverlay(for:)"
landmarkType = "7">
</BreakpointContent>
</BreakpointProxy>
</Breakpoints> </Breakpoints>
</Bucket> </Bucket>
@@ -1,6 +1,7 @@
import Foundation import Foundation
import SwiftUI import SwiftUI
import Alamofire
enum APIError: Error, CustomStringConvertible { enum APIError: Error, CustomStringConvertible {
case invalidURL case invalidURL
@@ -55,6 +56,8 @@ final class APIService {
if let responseString = String(data: data, encoding: .utf8) { if let responseString = String(data: data, encoding: .utf8) {
print("Response: \(responseString)") print("Response: \(responseString)")
// let resp = ProfileDetailResponse(JSONString: responseString)
// print(resp)
} else { } else {
print("Failed to convert response data to string") print("Failed to convert response data to string")
} }
@@ -78,6 +81,99 @@ final class APIService {
} }
} }
func requestReservation<T: Decodable>(_ endpoint: Endpoint, responseType: T.Type) async throws -> ReservationResponse? {
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 = ReservationResponse(JSONString: responseString) {
print(resp)
return resp
}
}
return nil
} catch {
throw APIError.decodingError(error)
}
}
func requestProfile<T: Decodable>(_ endpoint: Endpoint, responseType: T.Type) async throws -> ProfileDetailResponse? {
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 = ProfileDetailResponse(JSONString: responseString) {
print(resp)
return resp
}
}
return nil
} catch {
throw APIError.decodingError(error)
}
}
private func uploadMultipart<T: Decodable>(endpoint: Endpoint, responseType: T.Type) async throws -> T { private func uploadMultipart<T: Decodable>(endpoint: Endpoint, responseType: T.Type) async throws -> T {
guard var request = endpoint.urlRequest else { throw APIError.invalidURL } guard var request = endpoint.urlRequest else { throw APIError.invalidURL }
@@ -115,6 +211,72 @@ final class APIService {
} }
// func requestWithAlamofire<T: Decodable>(_ endpoint: Endpoint, responseType: T.Type) async throws -> T {
// guard let urlRequest = endpoint.urlRequest else {
// throw APIError.invalidURL
// }
//
// let response = await AF.request(urlRequest, interceptor: .retryPolicy)
// .validate()
// .serializingDecodable(T.self)
// .response
//
// debugPrint(response)
//
// switch response.result {
// case .success(let value):
// return value
// case .failure(let error):
// if let data = response.data {
//
// if let responseString = String(data: data, encoding: .utf8) {
// print("Response: \(responseString)")
// // let resp = ProfileDetailResponse(map: responseString)
// } else {
// print("Failed to convert response data to string")
// }
//
// } else {
// throw APIError.invalidResponse(response.response?.statusCode ?? 0, error.localizedDescription)
// }
// }
// }
// MARK: - Alamofire Multipart Upload with Swift Concurrency
func uploadMultipartWithAlamofire<T: Decodable>(_ endpoint: Endpoint, responseType: T.Type) async throws -> T {
guard let url = endpoint.urlRequest?.url else {
throw APIError.invalidURL
}
let response = await AF.upload(multipartFormData: { multipartFormData in
// Append your multipart form data here
// Example:
// multipartFormData.append(data, withName: "file", fileName: "file.jpg", mimeType: "image/jpeg")
}, to: url)
.validate()
.serializingDecodable(T.self)
.response
debugPrint(response)
switch response.result {
case .success(let value):
return value
case .failure(let error):
if let data = response.data,
let errorResponse = try? JSONDecoder().decode(ErrorResponse.self, from: data) {
if errorResponse.message == "TOKEN_EXPIRED" {
throw APIError.logout
} else {
throw APIError.serverError(errorResponse.message)
}
} else {
throw APIError.invalidResponse(response.response?.statusCode ?? 0, error.localizedDescription)
}
}
}
} }
struct ErrorResponse: Codable { struct ErrorResponse: Codable {
@@ -33,6 +33,8 @@ struct ClubStatisticsEndpoint: Endpoint {
var isMultipart: Bool { false } var isMultipart: Bool { false }
} }
struct GetClubEndpoint: Endpoint { struct GetClubEndpoint: Endpoint {
var path: String { var path: String {
"/v3/api/custom/courtmatchup/user/club/\(clubId)" "/v3/api/custom/courtmatchup/user/club/\(clubId)"
@@ -8,9 +8,8 @@ import SwiftUI
struct ReservationListEndpoint: Endpoint { struct ReservationListEndpoint: Endpoint {
var urlQueryItems: [URLQueryItem] = [] var urlQueryItems: [URLQueryItem] = []
var path: String { var path: String {
"/v4/api/records/reservation?join=booking|booking_id&join=user|user_id&join=buddy|buddy_id&join=clubs|club_id&order=id,desc&filter=courtmatchup_booking.date,cs,\(clubID)" "/v4/api/records/reservation?join=booking|booking_id&join=user|user_id&join=buddy|buddy_id&join=clubs|club_id&order=id,desc&filter=courtmatchup_booking.court_id,eq,163"
} }
var method: HTTPMethod { .get } var method: HTTPMethod { .get }
@@ -17,7 +17,7 @@ struct ClubDetailsResponse: Codable {
// MARK: - Club Details Model // MARK: - Club Details Model
struct ClubDetailsModel: Codable { struct ClubDetailsModel: Codable {
let user: ClubUser let user: ClubUser
let club: Club let club: ClubSport
let courts: [Court] let courts: [Court]
let sports: [Sport] let sports: [Sport]
let pricing: [Pricing] let pricing: [Pricing]
@@ -9,7 +9,7 @@ import Foundation
struct ClubDetail: Codable { struct ClubDetail: Codable {
let error: Bool? let error: Bool?
let model: Model? let model: Model?
let sports: [Club]? let sports: [Club1]?
let courts: [Court]? let courts: [Court]?
let pricing: [Pricing]? let pricing: [Pricing]?
} }
@@ -0,0 +1,95 @@
import Foundation
import ObjectMapper
class ClubMap : Mappable {
var id : Int?
var name : String?
var slug : String?
var title : String?
var description : String?
var user_id : Int?
var completed : Int?
var bio : String?
var opening_time : String?
var closing_time : String?
var times : String?
var splash_screen : String?
var show_clinic : Int?
var show_notification : Int?
var club_logo : String?
var fee_settings : String?
var custom_fields : String?
var home_image : String?
var show_buddy : Int?
var exceptions : String?
var club_location : String?
var show_coach : Int?
var show_groups : Int?
var show_court : Int?
var buddy_description : String?
var court_description : String?
var coach_description : String?
var clinic_description : String?
var lesson_description : String?
var custom_request_threshold : Int?
var club_fee : Int?
var service_fee : Int?
var max_players : Int?
var account_details : String?
var account_settings : String?
var membership_settings : String?
var daily_breaks : String?
var days_off : String?
var create_at : String?
var update_at : String?
required init?(map: Map) {
}
func mapping(map: Map) {
id <- map["id"]
name <- map["name"]
slug <- map["slug"]
title <- map["title"]
description <- map["description"]
user_id <- map["user_id"]
completed <- map["completed"]
bio <- map["bio"]
opening_time <- map["opening_time"]
closing_time <- map["closing_time"]
times <- map["times"]
splash_screen <- map["splash_screen"]
show_clinic <- map["show_clinic"]
show_notification <- map["show_notification"]
club_logo <- map["club_logo"]
fee_settings <- map["fee_settings"]
custom_fields <- map["custom_fields"]
home_image <- map["home_image"]
show_buddy <- map["show_buddy"]
exceptions <- map["exceptions"]
club_location <- map["club_location"]
show_coach <- map["show_coach"]
show_groups <- map["show_groups"]
show_court <- map["show_court"]
buddy_description <- map["buddy_description"]
court_description <- map["court_description"]
coach_description <- map["coach_description"]
clinic_description <- map["clinic_description"]
lesson_description <- map["lesson_description"]
custom_request_threshold <- map["custom_request_threshold"]
club_fee <- map["club_fee"]
service_fee <- map["service_fee"]
max_players <- map["max_players"]
account_details <- map["account_details"]
account_settings <- map["account_settings"]
membership_settings <- map["membership_settings"]
daily_breaks <- map["daily_breaks"]
days_off <- map["days_off"]
create_at <- map["create_at"]
update_at <- map["update_at"]
}
}
@@ -0,0 +1,41 @@
import Foundation
import ObjectMapper
class CourtsMap: Mappable, Identifiable, Hashable {
var id: Int?
var club_id: Int?
var name: String?
var sport_id: Int?
var type: String?
var surface_id: Int?
var sub_type: String?
var availability: String?
var create_at: String?
var update_at: String?
required init?(map: Map) {}
func mapping(map: Map) {
id <- map["id"]
club_id <- map["club_id"]
name <- map["name"]
sport_id <- map["sport_id"]
type <- map["type"]
surface_id <- map["surface_id"]
sub_type <- map["sub_type"]
availability <- map["availability"]
create_at <- map["create_at"]
update_at <- map["update_at"]
}
// MARK: - Hashable
static func == (lhs: CourtsMap, rhs: CourtsMap) -> Bool {
return lhs.id == rhs.id
}
func hash(into hasher: inout Hasher) {
hasher.combine(id)
}
}
@@ -0,0 +1,25 @@
import Foundation
import ObjectMapper
class ModelMap : Mappable {
var user : UserMap?
var club : ClubMap?
var courts : [CourtsMap]?
var sports : [SportsMap]?
var pricing : [PricingMap]?
required init?(map: Map) {
}
func mapping(map: Map) {
user <- map["user"]
club <- map["club"]
courts <- map["courts"]
sports <- map["sports"]
pricing <- map["pricing"]
}
}
@@ -0,0 +1,39 @@
import Foundation
import ObjectMapper
class PricingMap : Mappable {
var id : Int?
var surface_id : String?
var club_id : Int?
var type : String?
var subtype : String?
var sport_id : Int?
var status : Int?
var is_general : Int?
var general_rate : Int?
var price_by_hours : String?
var create_at : String?
var update_at : String?
required init?(map: Map) {
}
func mapping(map: Map) {
id <- map["id"]
surface_id <- map["surface_id"]
club_id <- map["club_id"]
type <- map["type"]
subtype <- map["subtype"]
sport_id <- map["sport_id"]
status <- map["status"]
is_general <- map["is_general"]
general_rate <- map["general_rate"]
price_by_hours <- map["price_by_hours"]
create_at <- map["create_at"]
update_at <- map["update_at"]
}
}
@@ -0,0 +1,19 @@
import Foundation
import ObjectMapper
class ProfileDetailResponse : Mappable {
var error : Bool?
var model : ModelMap?
required init?(map: Map) {
}
func mapping(map: Map) {
error <- map["error"]
model <- map["model"]
}
}
@@ -0,0 +1,22 @@
import Foundation
import ObjectMapper
class Sport_types : Mappable {
var type : String?
var subtype : [String]?
var club_sport_type_id : String?
required init?(map: Map) {
}
func mapping(map: Map) {
type <- map["type"]
subtype <- map["subtype"]
club_sport_type_id <- map["club_sport_type_id"]
}
}
@@ -0,0 +1,25 @@
import Foundation
import ObjectMapper
class SportsMap : Mappable {
var id : Int?
var status : Int?
var name : String?
var club_id : Int?
var sport_types : [Sport_types]?
required init?(map: Map) {
}
func mapping(map: Map) {
id <- map["id"]
status <- map["status"]
name <- map["name"]
club_id <- map["club_id"]
sport_types <- map["sport_types"]
}
}
@@ -0,0 +1,67 @@
import Foundation
import ObjectMapper
class UserMap : Mappable {
var id : Int?
var oauth : String?
var role : String?
var first_name : String?
var last_name : String?
var email : String?
var password : String?
var type : Int?
var alternative_phone : String?
var age_group : String?
var family_role : String?
var default_payment_method : String?
var guardian : Int?
var password_login : Int?
var verify : Int?
var club_id : String?
var phone : String?
var photo : String?
var bio : String?
var refer : String?
var stripe_uid : String?
var paypal_uid : String?
var two_factor_authentication : String?
var status : Int?
var create_at : String?
var update_at : String?
required init?(map: Map) {
}
func mapping(map: Map) {
id <- map["id"]
oauth <- map["oauth"]
role <- map["role"]
first_name <- map["first_name"]
last_name <- map["last_name"]
email <- map["email"]
password <- map["password"]
type <- map["type"]
alternative_phone <- map["alternative_phone"]
age_group <- map["age_group"]
family_role <- map["family_role"]
default_payment_method <- map["default_payment_method"]
guardian <- map["guardian"]
password_login <- map["password_login"]
verify <- map["verify"]
club_id <- map["club_id"]
phone <- map["phone"]
photo <- map["photo"]
bio <- map["bio"]
refer <- map["refer"]
stripe_uid <- map["stripe_uid"]
paypal_uid <- map["paypal_uid"]
two_factor_authentication <- map["two_factor_authentication"]
status <- map["status"]
create_at <- map["create_at"]
update_at <- map["update_at"]
}
}
@@ -1,146 +1,360 @@
import Foundation import Foundation
import ObjectMapper
class ReservationResponse : Mappable {
var list : [ReservationList]?
required init?(map: Map) {
// MARK: - Root
struct ReservationRsp: Codable {
let list: [Reservation]
} }
// MARK: - Reservation func mapping(map: Map) {
struct Reservation: Codable {
let id: Int list <- map["list"]
let bookingID: Int
let buddyID: Int?
let spaceAssigned: String
let userID: Int
let clubID: Int
let reservationType: Int?
let status: Int
let checkIn: Int
let recurring: Int
let notes: String
let createAt: String
let updateAt: String
let booking: Booking
let user: User
let buddy: [String?]
let clubs: Club
} }
// MARK: - Booking
struct Booking: Codable {
let id: Int
let userID: Int
let sportID: Int
let type: String
let receiptID: String
let subtype: String
let status: Int
let clinicID: Int?
let minNtrp: Int
let maxNtrp: Int
let coachID: Int?
let reservationType: Int
let courtID: Int
let courtIDs: String
let customRequest: Int
let price: Double
let clubFee: Double
let serviceFee: Double
let clinicFee: Double
let last4: Int
let clubID: Int?
let coachFee: Double
let lessonID: Int?
let duration: Int
let paymentIntent: String?
let notes: String?
let spaceAssigned: String?
let playerIDs: String
let courtFee: Double?
let playerID: Int?
let date: String
let startTime: String
let endTime: String
let createAt: String
let updateAt: String
let coachIDs: String
} }
// MARK: - User
struct User: Codable { class ReservationList : Mappable, Identifiable {
let id: Int var id : Int?
let oauth: String? var booking_id : Int?
let role: String var buddy_id : String?
let firstName: String var space_assigned : String?
let lastName: String var user_id : Int?
let email: String var club_id : Int?
let password: String var reservation_type : String?
let type: Int var status : Int?
let alternativePhone: String? var check_in : Int?
let ageGroup: String? var recurring : Int?
let familyRole: String? var notes : String?
let defaultPaymentMethod: String? var create_at : String?
let guardian: Int var update_at : String?
let passwordLogin: String var booking : Booking?
let verify: Int var user : ObjUser?
let clubID: Int? var buddy : Buddy?
let phone: String? var clubs : Clubs?
let photo: String?
let bio: String? required init?(map: Map) {
let refer: String?
let stripeUID: String?
let paypalUID: String?
let twoFactorAuthentication: String?
let status: Int
let createAt: String
let updateAt: String
} }
// MARK: - Buddy func mapping(map: Map) {
struct Buddy: Codable {
// Add properties if needed id <- map["id"]
booking_id <- map["booking_id"]
buddy_id <- map["buddy_id"]
space_assigned <- map["space_assigned"]
user_id <- map["user_id"]
club_id <- map["club_id"]
reservation_type <- map["reservation_type"]
status <- map["status"]
check_in <- map["check_in"]
recurring <- map["recurring"]
notes <- map["notes"]
create_at <- map["create_at"]
update_at <- map["update_at"]
booking <- map["booking"]
user <- map["user"]
buddy <- map["buddy"]
clubs <- map["clubs"]
}
}
class Booking : Mappable, Identifiable {
var id : Int?
var user_id : Int?
var sport_id : Int?
var type : String?
var receipt_id : String?
var subtype : String?
var status : Int?
var clinic_id : String?
var min_ntrp : Int?
var max_ntrp : Int?
var coach_id : String?
var reservation_type : Int?
var court_id : Int?
var court_ids : String?
var custom_request : Int?
var price : Int?
var club_fee : Int?
var service_fee : Int?
var clinic_fee : Int?
var last_4 : Int?
var club_id : Int?
var coach_fee : Int?
var lesson_id : String?
var duration : Int?
var payment_intent : String?
var notes : String?
var space_assigned : String?
var player_ids : String?
var court_fee : String?
var player_id : Int?
var date : String?
var start_time : String?
var end_time : String?
var create_at : String?
var update_at : String?
var coach_ids : String?
required init?(map: Map) {
}
func mapping(map: Map) {
id <- map["id"]
user_id <- map["user_id"]
sport_id <- map["sport_id"]
type <- map["type"]
receipt_id <- map["receipt_id"]
subtype <- map["subtype"]
status <- map["status"]
clinic_id <- map["clinic_id"]
min_ntrp <- map["min_ntrp"]
max_ntrp <- map["max_ntrp"]
coach_id <- map["coach_id"]
reservation_type <- map["reservation_type"]
court_id <- map["court_id"]
court_ids <- map["court_ids"]
custom_request <- map["custom_request"]
price <- map["price"]
club_fee <- map["club_fee"]
service_fee <- map["service_fee"]
clinic_fee <- map["clinic_fee"]
last_4 <- map["last_4"]
club_id <- map["club_id"]
coach_fee <- map["coach_fee"]
lesson_id <- map["lesson_id"]
duration <- map["duration"]
payment_intent <- map["payment_intent"]
notes <- map["notes"]
space_assigned <- map["space_assigned"]
player_ids <- map["player_ids"]
court_fee <- map["court_fee"]
player_id <- map["player_id"]
date <- map["date"]
start_time <- map["start_time"]
end_time <- map["end_time"]
create_at <- map["create_at"]
update_at <- map["update_at"]
coach_ids <- map["coach_ids"]
}
}
class Buddy : Mappable {
var id : String?
var sport_id : String?
var type : String?
var sub_type : String?
var ntrp : String?
var surface_id : String?
var reservation_id : String?
var num_players : String?
var max_ntrp : String?
var slots : String?
var num_needed : String?
var need_coach : String?
var notes : String?
var player_ids : String?
var date : String?
var start_time : String?
var end_time : String?
var create_at : String?
var update_at : String?
var user_id : String?
required init?(map: Map) {
}
func mapping(map: Map) {
id <- map["id"]
sport_id <- map["sport_id"]
type <- map["type"]
sub_type <- map["sub_type"]
ntrp <- map["ntrp"]
surface_id <- map["surface_id"]
reservation_id <- map["reservation_id"]
num_players <- map["num_players"]
max_ntrp <- map["max_ntrp"]
slots <- map["slots"]
num_needed <- map["num_needed"]
need_coach <- map["need_coach"]
notes <- map["notes"]
player_ids <- map["player_ids"]
date <- map["date"]
start_time <- map["start_time"]
end_time <- map["end_time"]
create_at <- map["create_at"]
update_at <- map["update_at"]
user_id <- map["user_id"]
}
}
class Clubs : Mappable {
var id : Int?
var name : String?
var slug : String?
var title : String?
var description : String?
var user_id : Int?
var completed : Int?
var bio : String?
var opening_time : String?
var closing_time : String?
var times : String?
var splash_screen : String?
var show_clinic : Int?
var show_notification : Int?
var club_logo : String?
var fee_settings : String?
var custom_fields : String?
var home_image : String?
var show_buddy : Int?
var exceptions : String?
var club_location : String?
var show_coach : Int?
var show_groups : Int?
var show_court : Int?
var buddy_description : String?
var court_description : String?
var coach_description : String?
var clinic_description : String?
var lesson_description : String?
var custom_request_threshold : Int?
var club_fee : Int?
var service_fee : Int?
var max_players : Int?
var account_details : String?
var account_settings : String?
var membership_settings : String?
var daily_breaks : String?
var days_off : String?
var create_at : String?
var update_at : String?
required init?(map: Map) {
}
func mapping(map: Map) {
id <- map["id"]
name <- map["name"]
slug <- map["slug"]
title <- map["title"]
description <- map["description"]
user_id <- map["user_id"]
completed <- map["completed"]
bio <- map["bio"]
opening_time <- map["opening_time"]
closing_time <- map["closing_time"]
times <- map["times"]
splash_screen <- map["splash_screen"]
show_clinic <- map["show_clinic"]
show_notification <- map["show_notification"]
club_logo <- map["club_logo"]
fee_settings <- map["fee_settings"]
custom_fields <- map["custom_fields"]
home_image <- map["home_image"]
show_buddy <- map["show_buddy"]
exceptions <- map["exceptions"]
club_location <- map["club_location"]
show_coach <- map["show_coach"]
show_groups <- map["show_groups"]
show_court <- map["show_court"]
buddy_description <- map["buddy_description"]
court_description <- map["court_description"]
coach_description <- map["coach_description"]
clinic_description <- map["clinic_description"]
lesson_description <- map["lesson_description"]
custom_request_threshold <- map["custom_request_threshold"]
club_fee <- map["club_fee"]
service_fee <- map["service_fee"]
max_players <- map["max_players"]
account_details <- map["account_details"]
account_settings <- map["account_settings"]
membership_settings <- map["membership_settings"]
daily_breaks <- map["daily_breaks"]
days_off <- map["days_off"]
create_at <- map["create_at"]
update_at <- map["update_at"]
}
}
class ObjUser : Mappable {
var id : Int?
var oauth : String?
var role : String?
var first_name : String?
var last_name : String?
var email : String?
var password : String?
var type : Int?
var alternative_phone : String?
var age_group : String?
var family_role : String?
var default_payment_method : String?
var guardian : Int?
var password_login : String?
var verify : Int?
var club_id : String?
var phone : String?
var photo : String?
var bio : String?
var refer : String?
var stripe_uid : String?
var paypal_uid : String?
var two_factor_authentication : String?
var status : Int?
var create_at : String?
var update_at : String?
required init?(map: Map) {
}
func mapping(map: Map) {
id <- map["id"]
oauth <- map["oauth"]
role <- map["role"]
first_name <- map["first_name"]
last_name <- map["last_name"]
email <- map["email"]
password <- map["password"]
type <- map["type"]
alternative_phone <- map["alternative_phone"]
age_group <- map["age_group"]
family_role <- map["family_role"]
default_payment_method <- map["default_payment_method"]
guardian <- map["guardian"]
password_login <- map["password_login"]
verify <- map["verify"]
club_id <- map["club_id"]
phone <- map["phone"]
photo <- map["photo"]
bio <- map["bio"]
refer <- map["refer"]
stripe_uid <- map["stripe_uid"]
paypal_uid <- map["paypal_uid"]
two_factor_authentication <- map["two_factor_authentication"]
status <- map["status"]
create_at <- map["create_at"]
update_at <- map["update_at"]
} }
// MARK: - Club
struct Club: Codable {
let id: Int
let name: String
let slug: String
let title: String
let description: String
let userID: Int
let completed: Int
let bio: String?
let openingTime: String
let closingTime: String
let times: String
let splashScreen: String
let showClinic: Int
let showNotification: Int
let clubLogo: String
let feeSettings: String
let customFields: String
let homeImage: String
let showBuddy: Int
let exceptions: String
let clubLocation: String
let showCoach: Int
let showGroups: Int
let showCourt: Int
let buddyDescription: String
let courtDescription: String
let coachDescription: String
let clinicDescription: String
let lessonDescription: String
let customRequestThreshold: Int
let clubFee: Double
let serviceFee: Double
let maxPlayers: Int
let accountDetails: String
let accountSettings: String
let membershipSettings: String
let dailyBreaks: String
let daysOff: String
let createAt: String
let updateAt: String
} }
@@ -9,15 +9,16 @@
import SwiftUI import SwiftUI
import SwiftUI
struct ScheduleFilterView: View { struct ScheduleFilterView: View {
@Environment(\.dismiss) var dismiss @Environment(\.dismiss) var dismiss
@Binding var navigationPaths: [String] @Binding var navigationPaths: [String]
@State private var isClubExpanded = true @State private var isClubExpanded = true
@State private var selectedClubs: Set<String> = [] // For storing selected clubs @State private var selectedClub: String? = nil // Single selection
@State var filterBlock: ((Int) -> Void)? @State var filterBlock: ((CourtsMap) -> Void)?
@EnvironmentObject var dasModel: DashViewModel @EnvironmentObject var dasModel: DashViewModel
var body: some View { var body: some View {
@@ -27,15 +28,14 @@ struct ScheduleFilterView: View {
// Club Filter Section // Club Filter Section
DisclosureGroup(isExpanded: $isClubExpanded) { DisclosureGroup(isExpanded: $isClubExpanded) {
VStack(spacing: 10) { VStack(spacing: 10) {
if let clubs = dasModel.club?.courts { if let clubs = dasModel.profile?.model?.courts {
ForEach(clubs, id: \.self) { court in ForEach(clubs, id: \.self) { court in
if let clubName = court.name { if let clubName = court.name {
ClubCheckboxRow(clubName: clubName, isSelected: selectedClubs.contains(clubName)) { ClubCheckboxRow(
if selectedClubs.contains(clubName) { clubName: clubName,
selectedClubs.remove(clubName) isSelected: selectedClub == clubName
} else { ) {
selectedClubs.insert(clubName) selectedClub = (selectedClub == clubName) ? nil : clubName
}
} }
} }
} }
@@ -60,7 +60,11 @@ struct ScheduleFilterView: View {
Spacer() Spacer()
Button(action: { Button(action: {
// Handle apply logic if let selectedClub = selectedClub,
let court = dasModel.profile?.model?.courts?.first(where: { $0.name == selectedClub }),
let id = court.id {
filterBlock?(court)
}
self.navigationPaths.removeLast() self.navigationPaths.removeLast()
}) { }) {
Text("Apply and close") Text("Apply and close")
@@ -72,9 +76,6 @@ struct ScheduleFilterView: View {
.cornerRadius(10) .cornerRadius(10)
.padding(.horizontal) .padding(.horizontal)
} }
.padding(.vertical, 10)
.background(Color.white)
}
.navigationTitle("Filter") .navigationTitle("Filter")
.navigationBarTitleDisplayMode(.inline) .navigationBarTitleDisplayMode(.inline)
.background(Color(.systemGray6).ignoresSafeArea()) .background(Color(.systemGray6).ignoresSafeArea())
@@ -104,3 +105,4 @@ struct ClubCheckboxRow: View {
} }
} }
} }
}
@@ -1,21 +1,15 @@
import SwiftUI import SwiftUI
struct Event: Identifiable {
let id = UUID()
let title: String
let startTime: Date
let endTime: Date
let color: Color
}
struct ScheduleView: View { struct ScheduleView: View {
@State var navigationPaths: [String] = [] @State var navigationPaths: [String] = []
@State private var selectedDate = Date() @State private var selectedDate = Date()
@State private var displayedMonth = Date() @State private var displayedMonth = Date()
@State private var events: [Event] = [] // @State private var events: [ReservationList] = []
@Binding var presentSideMenu: Bool // Optional for side menu @Binding var presentSideMenu: Bool // Optional for side menu
@State var courtName = ""
let hours = Array(8...20) let hours = Array(4...20)
let calendar = Calendar.current let calendar = Calendar.current
@EnvironmentObject var viewModel : DashViewModel @EnvironmentObject var viewModel : DashViewModel
@@ -47,11 +41,17 @@ struct ScheduleView: View {
Divider() Divider()
HStack {
Spacer()
Text(courtName)
Spacer()
}
// Time Slots with Events // Time Slots with Events
ScrollView { ScrollView {
VStack(spacing: 0) { VStack(spacing: 0) {
ForEach(hours, id: \.self) { hour in ForEach(hours, id: \.self) { hour in
timeSlotRow(hour: hour) timeSlotRow(hour: hour)
} }
} }
.padding(.horizontal) .padding(.horizontal)
@@ -62,18 +62,20 @@ struct ScheduleView: View {
} }
.onAppear { .onAppear {
// loadDummyEvents() // loadDummyEvents()
viewModel.getDailySched(clubId: 10)
if let club = self.viewModel.club { if let club = self.viewModel.profile {
print(club.courts?.count) print(club.model?.courts?.count)
// viewModel.getDailySched(clubId: club.model?.courts?.first?.id ?? 0)
}else { }else {
viewModel.getClubProfile() viewModel.getProfile()
} }
} }
.navigationDestination(for: String.self) { value in .navigationDestination(for: String.self) { value in
if value == "DailyFilterView" { if value == "DailyFilterView" {
ScheduleFilterView(navigationPaths: $navigationPaths) { filter in ScheduleFilterView(navigationPaths: $navigationPaths) { filter in
viewModel.getDailySched(clubId: filter) self.courtName = filter.name ?? ""
viewModel.getDailySched(clubId: filter.id ?? 0)
} }
}else if value == "ReservationDetailsView" { }else if value == "ReservationDetailsView" {
ReservationDetailsView() ReservationDetailsView()
@@ -201,6 +203,7 @@ struct ScheduleView: View {
Text(timeLabel(for: hour)) Text(timeLabel(for: hour))
.font(.caption) .font(.caption)
.frame(width: 50, alignment: .leading) .frame(width: 50, alignment: .leading)
.padding(.top)
ZStack(alignment: .topLeading) { ZStack(alignment: .topLeading) {
Rectangle() Rectangle()
@@ -216,21 +219,40 @@ struct ScheduleView: View {
func eventOverlay(for hour: Int) -> some View { func eventOverlay(for hour: Int) -> some View {
VStack(spacing: 4) { VStack(spacing: 4) {
ForEach(events.filter { ForEach(
calendar.isDate($0.startTime, inSameDayAs: selectedDate) viewModel.dailyReservations.filter({ event in
&& calendar.component(.hour, from: $0.startTime) == hour guard let eventDateString = event.booking?.date,
}) { event in let startTimeString = event.booking?.start_time,
let _ = event.booking?.end_time else {
return false
}
// Format selectedDate as "yyyy-MM-dd"
let selectedDateStr = DateFormatter.bookingDateFormatter.string(from: selectedDate)
// Debug print
print("Event Date: \(eventDateString), Selected: \(selectedDateStr), StartTime: \(startTimeString)")
// Match event date to selected date string
guard eventDateString == selectedDateStr else { return false }
// Compare the 12-hour formatted string labels
let startTimeLabel = startTimeString.to12HourFormat()
let currentHourLabel = timeLabel(for: hour)
return startTimeLabel == currentHourLabel
}),
id: \.id
) { event in
VStack(alignment: .leading, spacing: 2) { VStack(alignment: .leading, spacing: 2) {
Text(event.title) Text(event.booking?.type ?? "- -")
.font(.subheadline) .font(.subheadline)
.bold() .bold()
Text("\(timeOnly(event.startTime)) - \(timeOnly(event.endTime))") Text("\(event.booking!.start_time!.to12HourFormat()) - \(event.booking!.end_time!.to12HourFormat())")
.font(.caption) .font(.caption)
.foregroundColor(.gray) .foregroundColor(.gray)
} }
.padding(8) .padding(8)
.background(event.color.opacity(0.2)) .background(Colorr.greenColor.opacity(0.2))
.foregroundColor(event.color) .foregroundColor(Colorr.greenColor.opacity(0.8))
.cornerRadius(12) .cornerRadius(12)
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading) .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading)
.background(Color.clear) .background(Color.clear)
@@ -245,23 +267,23 @@ struct ScheduleView: View {
// MARK: - Utility // MARK: - Utility
func loadDummyEvents() { // func loadDummyEvents() {
let baseDate = calendar.startOfDay(for: Date()) // let baseDate = calendar.startOfDay(for: Date())
events = [ // events = [
Event( // Event(
title: "Court reserved", // title: "Court reserved",
startTime: calendar.date(bySettingHour: 9, minute: 0, second: 0, of: baseDate)!, // startTime: calendar.date(bySettingHour: 9, minute: 0, second: 0, of: baseDate)!,
endTime: calendar.date(bySettingHour: 10, minute: 0, second: 0, of: baseDate)!, // endTime: calendar.date(bySettingHour: 10, minute: 0, second: 0, of: baseDate)!,
color: .green // color: .green
), // ),
Event( // Event(
title: "Clinic", // title: "Clinic",
startTime: calendar.date(bySettingHour: 11, minute: 30, second: 0, of: baseDate)!, // startTime: calendar.date(bySettingHour: 11, minute: 30, second: 0, of: baseDate)!,
endTime: calendar.date(bySettingHour: 13, minute: 0, second: 0, of: baseDate)!, // endTime: calendar.date(bySettingHour: 13, minute: 0, second: 0, of: baseDate)!,
color: .purple // color: .purple
) // )
] // ]
} // }
func getDatesForMonth(from date: Date) -> [Date] { func getDatesForMonth(from date: Date) -> [Date] {
let range = calendar.range(of: .day, in: .month, for: date)! let range = calendar.range(of: .day, in: .month, for: date)!
@@ -296,7 +318,7 @@ struct ScheduleView: View {
func timeLabel(for hour: Int) -> String { func timeLabel(for hour: Int) -> String {
let date = calendar.date(bySettingHour: hour, minute: 0, second: 0, of: Date())! let date = calendar.date(bySettingHour: hour, minute: 0, second: 0, of: Date())!
let formatter = DateFormatter() let formatter = DateFormatter()
formatter.dateFormat = "h a" formatter.dateFormat = "h:mm a"
return formatter.string(from: date) return formatter.string(from: date)
} }
@@ -304,3 +326,39 @@ struct ScheduleView: View {
calendar.isDate(a, inSameDayAs: b) calendar.isDate(a, inSameDayAs: b)
} }
} }
extension DateFormatter {
static var isoFormatter: DateFormatter {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ"
formatter.locale = Locale(identifier: "en_US_POSIX")
return formatter
}
}
extension DateFormatter {
static var bookingDateFormatter: DateFormatter {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd"
// formatter.locale = Locale(identifier: "en_US_POSIX")
return formatter
}
}
extension String {
func to12HourFormat() -> String {
let inputFormatter = DateFormatter()
inputFormatter.dateFormat = "HH:mm:ss"
// inputFormatter.locale = Locale(identifier: "en_US_POSIX")
let outputFormatter = DateFormatter()
outputFormatter.dateFormat = "h:mm a"
// outputFormatter.locale = Locale(identifier: "en_US_POSIX")
if let date = inputFormatter.date(from: self) {
return outputFormatter.string(from: date)
} else {
return self // Return original if parsing fails
}
}
}
@@ -68,7 +68,7 @@ struct SummaryView: View {
} }
} }
// viewModel.getClubProfile() // viewModel.getClubProfile()
// viewModel.getProfile() viewModel.getProfile()
} }
@@ -167,33 +167,33 @@ extension String {
} }
} }
func to12HourFormat() -> String? { // func to12HourFormat() -> String? {
let inputDateFormatter = DateFormatter() // let inputDateFormatter = DateFormatter()
inputDateFormatter.dateFormat = "HH:mm:ss" // Input format (24-hour) // inputDateFormatter.dateFormat = "HH:mm:ss" // Input format (24-hour)
//
let outputDateFormatter = DateFormatter() // let outputDateFormatter = DateFormatter()
outputDateFormatter.dateFormat = "hh:mm a" // Output format (12-hour with AM/PM) // outputDateFormatter.dateFormat = "hh:mm a" // Output format (12-hour with AM/PM)
//
// Split the range into start and end times // // Split the range into start and end times
let timeComponents = self.components(separatedBy: "-") // let timeComponents = self.components(separatedBy: "-")
//
if timeComponents.count == 2 { // if timeComponents.count == 2 {
let startTime = inputDateFormatter.date(from: timeComponents[0]) // let startTime = inputDateFormatter.date(from: timeComponents[0])
let endTime = inputDateFormatter.date(from: timeComponents[1]) // let endTime = inputDateFormatter.date(from: timeComponents[1])
//
let start12Hour = outputDateFormatter.string(from: startTime!) // let start12Hour = outputDateFormatter.string(from: startTime!)
let end12Hour = outputDateFormatter.string(from: endTime!) // let end12Hour = outputDateFormatter.string(from: endTime!)
//
return "\(start12Hour) - \(end12Hour)" // return "\(start12Hour) - \(end12Hour)"
}else { // }else {
let startTime = inputDateFormatter.date(from: self) // let startTime = inputDateFormatter.date(from: self)
let start12Hour = outputDateFormatter.string(from: startTime!) // let start12Hour = outputDateFormatter.string(from: startTime!)
//
return start12Hour // return start12Hour
} // }
//
// Return nil if conversion fails // // Return nil if conversion fails
} // }
@@ -12,11 +12,11 @@ class DashViewModel: ObservableObject {
@Published var dashboardfilters = "" @Published var dashboardfilters = ""
@Published var statResponse : ClubStatisticsModel? @Published var statResponse : ClubStatisticsModel?
@Published var dailyReservations : [Reservation]? @Published var dailyReservations : [ReservationList] = []
@Published var availRsp : AvailabliltyRsp? @Published var availRsp : AvailabliltyRsp?
@Published var club : ClubDetail? @Published var club : ClubDetail?
@Published var clubDetail : ClubDetailsResponse? @Published var clubDetail : ClubDetailsResponse?
@Published var profile : ProfileRsp? @Published var profile : ProfileDetailResponse?
@Published var sessionExpired = false @Published var sessionExpired = false
func getStats(completion: @escaping () -> ()) { func getStats(completion: @escaping () -> ()) {
@@ -51,9 +51,9 @@ class DashViewModel: ObservableObject {
let endpoint = ReservationListEndpoint(clubID: clubId) let endpoint = ReservationListEndpoint(clubID: clubId)
Task { Task {
do { do {
let result = try await APIService.shared.request(endpoint, responseType: ReservationRsp.self) let result = try await APIService.shared.requestReservation(endpoint, responseType: ProfileRsp.self)
dailyReservations = result.list dailyReservations = result?.list ?? []
print("Reservations:", result.list) print("Reservations:", result?.list)
} catch { } catch {
print("Error fetching reservations:", error) print("Error fetching reservations:", error)
} }
@@ -78,11 +78,11 @@ class DashViewModel: ObservableObject {
Task { Task {
do { do {
let result = try await APIService.shared.request(endpoint, responseType: ProfileRsp.self) let result = try await APIService.shared.requestProfile(endpoint, responseType: ProfileRsp.self)
profile = result profile = result
AppSettings.clubId = result.model?.club?.id ?? 0 AppSettings.clubId = result?.model?.club?.id ?? 0
AppSettings.clubName = result.model?.club?.name ?? "" AppSettings.clubName = result?.model?.club?.name ?? ""
AppSettings.clubName = result.model?.user?.email ?? "" AppSettings.clubName = result?.model?.user?.email ?? ""
} catch { } catch {
print("Error fetching reservations:", error) print("Error fetching reservations:", error)
@@ -91,7 +91,7 @@ class DashViewModel: ObservableObject {
} }
func getClubProfile(){ func getClubProfile(){
let endpoint = GetClubEndpoint(clubId: "10") let endpoint = GetClubEndpoint(clubId: "\(AppSettings.clubId)")
Task { Task {
do { do {
let result = try await APIService.shared.request(endpoint, responseType: ClubDetail.self) let result = try await APIService.shared.request(endpoint, responseType: ClubDetail.self)