updated reservation details screen and filter on available screen
This commit is contained in:
+8
-168
@@ -4,22 +4,6 @@
|
|||||||
type = "1"
|
type = "1"
|
||||||
version = "2.0">
|
version = "2.0">
|
||||||
<Breakpoints>
|
<Breakpoints>
|
||||||
<BreakpointProxy
|
|
||||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
|
||||||
<BreakpointContent
|
|
||||||
uuid = "D5681314-32C1-4998-BEBF-D4691C886BC2"
|
|
||||||
shouldBeEnabled = "No"
|
|
||||||
ignoreCount = "0"
|
|
||||||
continueAfterRunningActions = "No"
|
|
||||||
filePath = "Club Portal/ViewModels/DashViewModel.swift"
|
|
||||||
startingColumnNumber = "9223372036854775807"
|
|
||||||
endingColumnNumber = "9223372036854775807"
|
|
||||||
startingLineNumber = "56"
|
|
||||||
endingLineNumber = "56"
|
|
||||||
landmarkName = "getDailySched(clubId:)"
|
|
||||||
landmarkType = "7">
|
|
||||||
</BreakpointContent>
|
|
||||||
</BreakpointProxy>
|
|
||||||
<BreakpointProxy
|
<BreakpointProxy
|
||||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||||
<BreakpointContent
|
<BreakpointContent
|
||||||
@@ -52,22 +36,6 @@
|
|||||||
landmarkType = "14">
|
landmarkType = "14">
|
||||||
</BreakpointContent>
|
</BreakpointContent>
|
||||||
</BreakpointProxy>
|
</BreakpointProxy>
|
||||||
<BreakpointProxy
|
|
||||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
|
||||||
<BreakpointContent
|
|
||||||
uuid = "99B40998-6781-4339-ACB5-F75FF0BC38A7"
|
|
||||||
shouldBeEnabled = "No"
|
|
||||||
ignoreCount = "0"
|
|
||||||
continueAfterRunningActions = "No"
|
|
||||||
filePath = "Club Portal/ViewModels/DashViewModel.swift"
|
|
||||||
startingColumnNumber = "9223372036854775807"
|
|
||||||
endingColumnNumber = "9223372036854775807"
|
|
||||||
startingLineNumber = "69"
|
|
||||||
endingLineNumber = "69"
|
|
||||||
landmarkName = "getAvailability()"
|
|
||||||
landmarkType = "7">
|
|
||||||
</BreakpointContent>
|
|
||||||
</BreakpointProxy>
|
|
||||||
<BreakpointProxy
|
<BreakpointProxy
|
||||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||||
<BreakpointContent
|
<BreakpointContent
|
||||||
@@ -84,38 +52,6 @@
|
|||||||
landmarkType = "24">
|
landmarkType = "24">
|
||||||
</BreakpointContent>
|
</BreakpointContent>
|
||||||
</BreakpointProxy>
|
</BreakpointProxy>
|
||||||
<BreakpointProxy
|
|
||||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
|
||||||
<BreakpointContent
|
|
||||||
uuid = "9DDEE31F-4183-4E3A-8568-5DBD8C04570A"
|
|
||||||
shouldBeEnabled = "No"
|
|
||||||
ignoreCount = "0"
|
|
||||||
continueAfterRunningActions = "No"
|
|
||||||
filePath = "Club Portal/ViewModels/DashViewModel.swift"
|
|
||||||
startingColumnNumber = "9223372036854775807"
|
|
||||||
endingColumnNumber = "9223372036854775807"
|
|
||||||
startingLineNumber = "84"
|
|
||||||
endingLineNumber = "84"
|
|
||||||
landmarkName = "getProfile()"
|
|
||||||
landmarkType = "7">
|
|
||||||
</BreakpointContent>
|
|
||||||
</BreakpointProxy>
|
|
||||||
<BreakpointProxy
|
|
||||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
|
||||||
<BreakpointContent
|
|
||||||
uuid = "6A2DA2F1-CA9B-4BCE-8ACA-D6D14E858CDA"
|
|
||||||
shouldBeEnabled = "No"
|
|
||||||
ignoreCount = "0"
|
|
||||||
continueAfterRunningActions = "No"
|
|
||||||
filePath = "Club Portal/ViewModels/DashViewModel.swift"
|
|
||||||
startingColumnNumber = "9223372036854775807"
|
|
||||||
endingColumnNumber = "9223372036854775807"
|
|
||||||
startingLineNumber = "77"
|
|
||||||
endingLineNumber = "77"
|
|
||||||
landmarkName = "getProfile()"
|
|
||||||
landmarkType = "7">
|
|
||||||
</BreakpointContent>
|
|
||||||
</BreakpointProxy>
|
|
||||||
<BreakpointProxy
|
<BreakpointProxy
|
||||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||||
<BreakpointContent
|
<BreakpointContent
|
||||||
@@ -148,22 +84,6 @@
|
|||||||
landmarkType = "24">
|
landmarkType = "24">
|
||||||
</BreakpointContent>
|
</BreakpointContent>
|
||||||
</BreakpointProxy>
|
</BreakpointProxy>
|
||||||
<BreakpointProxy
|
|
||||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
|
||||||
<BreakpointContent
|
|
||||||
uuid = "002CCE4B-DBB4-4BE0-82C0-03D8524CC2DA"
|
|
||||||
shouldBeEnabled = "No"
|
|
||||||
ignoreCount = "0"
|
|
||||||
continueAfterRunningActions = "No"
|
|
||||||
filePath = "Club Portal/ViewModels/DashViewModel.swift"
|
|
||||||
startingColumnNumber = "9223372036854775807"
|
|
||||||
endingColumnNumber = "9223372036854775807"
|
|
||||||
startingLineNumber = "34"
|
|
||||||
endingLineNumber = "34"
|
|
||||||
landmarkName = "getStats(completion:)"
|
|
||||||
landmarkType = "7">
|
|
||||||
</BreakpointContent>
|
|
||||||
</BreakpointProxy>
|
|
||||||
<BreakpointProxy
|
<BreakpointProxy
|
||||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||||
<BreakpointContent
|
<BreakpointContent
|
||||||
@@ -180,38 +100,6 @@
|
|||||||
landmarkType = "24">
|
landmarkType = "24">
|
||||||
</BreakpointContent>
|
</BreakpointContent>
|
||||||
</BreakpointProxy>
|
</BreakpointProxy>
|
||||||
<BreakpointProxy
|
|
||||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
|
||||||
<BreakpointContent
|
|
||||||
uuid = "C120EA6E-E899-43F2-92E6-438C52F26A83"
|
|
||||||
shouldBeEnabled = "No"
|
|
||||||
ignoreCount = "0"
|
|
||||||
continueAfterRunningActions = "No"
|
|
||||||
filePath = "Club Portal/ViewModels/DashViewModel.swift"
|
|
||||||
startingColumnNumber = "9223372036854775807"
|
|
||||||
endingColumnNumber = "9223372036854775807"
|
|
||||||
startingLineNumber = "98"
|
|
||||||
endingLineNumber = "98"
|
|
||||||
landmarkName = "getClubProfile()"
|
|
||||||
landmarkType = "7">
|
|
||||||
</BreakpointContent>
|
|
||||||
</BreakpointProxy>
|
|
||||||
<BreakpointProxy
|
|
||||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
|
||||||
<BreakpointContent
|
|
||||||
uuid = "1047CF2A-7B0C-44CA-AB60-933AFFF88D49"
|
|
||||||
shouldBeEnabled = "No"
|
|
||||||
ignoreCount = "0"
|
|
||||||
continueAfterRunningActions = "No"
|
|
||||||
filePath = "Club Portal/ViewModels/DashViewModel.swift"
|
|
||||||
startingColumnNumber = "9223372036854775807"
|
|
||||||
endingColumnNumber = "9223372036854775807"
|
|
||||||
startingLineNumber = "41"
|
|
||||||
endingLineNumber = "41"
|
|
||||||
landmarkName = "getStats(completion:)"
|
|
||||||
landmarkType = "7">
|
|
||||||
</BreakpointContent>
|
|
||||||
</BreakpointProxy>
|
|
||||||
<BreakpointProxy
|
<BreakpointProxy
|
||||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||||
<BreakpointContent
|
<BreakpointContent
|
||||||
@@ -222,8 +110,8 @@
|
|||||||
filePath = "Club Portal/UI/Dashboard/DashboardView.swift"
|
filePath = "Club Portal/UI/Dashboard/DashboardView.swift"
|
||||||
startingColumnNumber = "9223372036854775807"
|
startingColumnNumber = "9223372036854775807"
|
||||||
endingColumnNumber = "9223372036854775807"
|
endingColumnNumber = "9223372036854775807"
|
||||||
startingLineNumber = "65"
|
startingLineNumber = "66"
|
||||||
endingLineNumber = "65"
|
endingLineNumber = "66"
|
||||||
landmarkName = "body"
|
landmarkName = "body"
|
||||||
landmarkType = "24">
|
landmarkType = "24">
|
||||||
</BreakpointContent>
|
</BreakpointContent>
|
||||||
@@ -260,38 +148,6 @@
|
|||||||
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
|
<BreakpointProxy
|
||||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||||
<BreakpointContent
|
<BreakpointContent
|
||||||
@@ -311,33 +167,17 @@
|
|||||||
<BreakpointProxy
|
<BreakpointProxy
|
||||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||||
<BreakpointContent
|
<BreakpointContent
|
||||||
uuid = "2F83466D-D868-4502-8601-E4770581F3EB"
|
uuid = "C3CB7FC3-4DA4-47C4-88EE-3AB6FBEC9D3D"
|
||||||
shouldBeEnabled = "Yes"
|
shouldBeEnabled = "Yes"
|
||||||
ignoreCount = "0"
|
ignoreCount = "0"
|
||||||
continueAfterRunningActions = "No"
|
continueAfterRunningActions = "No"
|
||||||
filePath = "Club Portal/UI/DailySecheduler/ScheduleView.swift"
|
filePath = "Club Portal/UI/Availbility/AvailabilityCardView.swift"
|
||||||
startingColumnNumber = "9223372036854775807"
|
startingColumnNumber = "9223372036854775807"
|
||||||
endingColumnNumber = "9223372036854775807"
|
endingColumnNumber = "9223372036854775807"
|
||||||
startingLineNumber = "241"
|
startingLineNumber = "58"
|
||||||
endingLineNumber = "241"
|
endingLineNumber = "58"
|
||||||
landmarkName = "eventOverlay(for:)"
|
landmarkName = "body"
|
||||||
landmarkType = "7">
|
landmarkType = "24">
|
||||||
</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>
|
</BreakpointContent>
|
||||||
</BreakpointProxy>
|
</BreakpointProxy>
|
||||||
</Breakpoints>
|
</Breakpoints>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
"images" : [
|
"images" : [
|
||||||
{
|
{
|
||||||
|
"filename" : "WhatsApp Image 2024-11-29 at 00.34.09 1.jpeg",
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"platform" : "ios",
|
"platform" : "ios",
|
||||||
"size" : "1024x1024"
|
"size" : "1024x1024"
|
||||||
@@ -12,6 +13,7 @@
|
|||||||
"value" : "dark"
|
"value" : "dark"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"filename" : "WhatsApp Image 2024-11-29 at 00.34.09 2.jpeg",
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"platform" : "ios",
|
"platform" : "ios",
|
||||||
"size" : "1024x1024"
|
"size" : "1024x1024"
|
||||||
@@ -23,6 +25,7 @@
|
|||||||
"value" : "tinted"
|
"value" : "tinted"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"filename" : "WhatsApp Image 2024-11-29 at 00.34.09.jpeg",
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"platform" : "ios",
|
"platform" : "ios",
|
||||||
"size" : "1024x1024"
|
"size" : "1024x1024"
|
||||||
|
|||||||
BIN
Binary file not shown.
|
After Width: | Height: | Size: 92 KiB |
BIN
Binary file not shown.
|
After Width: | Height: | Size: 92 KiB |
BIN
Binary file not shown.
|
After Width: | Height: | Size: 92 KiB |
@@ -210,6 +210,98 @@ final class APIService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func requestPlayers(_ endpoint: Endpoint) async throws -> Players? {
|
||||||
|
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 = Players(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
|
||||||
|
}
|
||||||
|
|
||||||
|
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 = CoacheList(JSONString: responseString) {
|
||||||
|
print(resp)
|
||||||
|
return resp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
|
||||||
|
|
||||||
|
} catch {
|
||||||
|
throw APIError.decodingError(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// func requestWithAlamofire<T: Decodable>(_ endpoint: Endpoint, responseType: T.Type) async throws -> T {
|
// func requestWithAlamofire<T: Decodable>(_ endpoint: Endpoint, responseType: T.Type) async throws -> T {
|
||||||
// guard let urlRequest = endpoint.urlRequest else {
|
// guard let urlRequest = endpoint.urlRequest else {
|
||||||
@@ -235,7 +327,7 @@ final class APIService {
|
|||||||
// } else {
|
// } else {
|
||||||
// print("Failed to convert response data to string")
|
// print("Failed to convert response data to string")
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// } else {
|
// } else {
|
||||||
// throw APIError.invalidResponse(response.response?.statusCode ?? 0, error.localizedDescription)
|
// throw APIError.invalidResponse(response.response?.statusCode ?? 0, error.localizedDescription)
|
||||||
// }
|
// }
|
||||||
|
|||||||
+61
-2
@@ -8,7 +8,6 @@
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
struct AvailabilityListEndpoint: Endpoint {
|
struct AvailabilityListEndpoint: Endpoint {
|
||||||
var urlQueryItems: [URLQueryItem] = []
|
|
||||||
|
|
||||||
var path: String {
|
var path: String {
|
||||||
"/v3/api/custom/courtmatchup/club/reservations/availability"
|
"/v3/api/custom/courtmatchup/club/reservations/availability"
|
||||||
@@ -16,7 +15,19 @@ struct AvailabilityListEndpoint: Endpoint {
|
|||||||
|
|
||||||
var method: HTTPMethod { .get }
|
var method: HTTPMethod { .get }
|
||||||
|
|
||||||
|
let startDate: String
|
||||||
|
let endDate: String
|
||||||
|
let startTime: String
|
||||||
|
let endTime: String
|
||||||
|
|
||||||
|
var urlQueryItems: [URLQueryItem] {
|
||||||
|
[
|
||||||
|
URLQueryItem(name: "from_time", value: startTime),
|
||||||
|
URLQueryItem(name: "until_time", value: endTime),
|
||||||
|
URLQueryItem(name: "from_date", value: startDate),
|
||||||
|
URLQueryItem(name: "until_date", value: endDate)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
var customHeaders: [String: String]? { nil }
|
var customHeaders: [String: String]? { nil }
|
||||||
|
|
||||||
@@ -24,3 +35,51 @@ struct AvailabilityListEndpoint: Endpoint {
|
|||||||
|
|
||||||
var isMultipart: Bool { false }
|
var isMultipart: Bool { false }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct GetPlayerListEndpoint: Endpoint {
|
||||||
|
var path: String {
|
||||||
|
"/v4/api/records/user?order=id,desc&filter=id,in,\(playerIds)&"
|
||||||
|
}
|
||||||
|
|
||||||
|
var method: HTTPMethod { .get }
|
||||||
|
|
||||||
|
|
||||||
|
var customHeaders: [String: String]? { nil }
|
||||||
|
|
||||||
|
var urlQueryItems: [URLQueryItem] {
|
||||||
|
[
|
||||||
|
|
||||||
|
]
|
||||||
|
}
|
||||||
|
var playerIds = ""
|
||||||
|
|
||||||
|
var body: Data? { nil }
|
||||||
|
|
||||||
|
var isMultipart: Bool { false }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
struct GetCoachListEndpoint: Endpoint {
|
||||||
|
var path: String {
|
||||||
|
"/v4/api/records/coach?join=user|user_id&order=id,desc&filter=id,in,\(playerIds)&"
|
||||||
|
}
|
||||||
|
|
||||||
|
var method: HTTPMethod { .get }
|
||||||
|
|
||||||
|
|
||||||
|
var customHeaders: [String: String]? { nil }
|
||||||
|
|
||||||
|
var urlQueryItems: [URLQueryItem] {
|
||||||
|
[
|
||||||
|
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
var playerIds = ""
|
||||||
|
|
||||||
|
var body: Data? { nil }
|
||||||
|
|
||||||
|
var isMultipart: Bool { false }
|
||||||
|
}
|
||||||
|
|||||||
+1
-1
@@ -9,7 +9,7 @@ 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.court_id,eq,163"
|
"/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,\(clubID)"
|
||||||
}
|
}
|
||||||
|
|
||||||
var method: HTTPMethod { .get }
|
var method: HTTPMethod { .get }
|
||||||
|
|||||||
+1
-1
@@ -31,7 +31,7 @@ struct Coaches: Codable {
|
|||||||
|
|
||||||
// MARK: - CoachesAvailable
|
// MARK: - CoachesAvailable
|
||||||
struct CoachesAvailable: Codable , Identifiable, Hashable {
|
struct CoachesAvailable: Codable , Identifiable, Hashable {
|
||||||
let id: Int?
|
let id = UUID().uuidString
|
||||||
let coachID, userID: Int?
|
let coachID, userID: Int?
|
||||||
let bio, hourlyRate, availability, firstName: String?
|
let bio, hourlyRate, availability, firstName: String?
|
||||||
let lastName, phone, email: String?
|
let lastName, phone, email: String?
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
//
|
||||||
|
// CoacheList.swift
|
||||||
|
// Club Portal
|
||||||
|
//
|
||||||
|
// Created by Umer Tahir on 07/05/2025.
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import ObjectMapper
|
||||||
|
|
||||||
|
class CoacheList : Mappable {
|
||||||
|
var list : [PlayerList]?
|
||||||
|
|
||||||
|
required init?(map: Map) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func mapping(map: Map) {
|
||||||
|
|
||||||
|
list <- map["list"]
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
//
|
||||||
|
// Players.swift
|
||||||
|
// Club Portal
|
||||||
|
//
|
||||||
|
// Created by Umer Tahir on 07/05/2025.
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Json4Swift.swift
|
||||||
|
// Club Portal
|
||||||
|
//
|
||||||
|
// Created by Umer Tahir on 06/05/2025.
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import ObjectMapper
|
||||||
|
|
||||||
|
class Players : Mappable {
|
||||||
|
var list : [UserMap]?
|
||||||
|
|
||||||
|
required init?(map: Map) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func mapping(map: Map) {
|
||||||
|
|
||||||
|
list <- map["list"]
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
struct PlayerList : Mappable {
|
||||||
|
var id : Int?
|
||||||
|
var user_id : Int?
|
||||||
|
var name : String?
|
||||||
|
var club_id : Int?
|
||||||
|
var hourly_rate : String?
|
||||||
|
var status : Int?
|
||||||
|
var not_paid_through_platform : Int?
|
||||||
|
var completed : Int?
|
||||||
|
var type : Int?
|
||||||
|
var experience : String?
|
||||||
|
var surface_id : Int?
|
||||||
|
var bio : String?
|
||||||
|
var sport_id : String?
|
||||||
|
var availability : String?
|
||||||
|
var default_availability : String?
|
||||||
|
var week_specific_availability : String?
|
||||||
|
var account_details : String?
|
||||||
|
var photo : String?
|
||||||
|
var is_public : Int?
|
||||||
|
var create_at : String?
|
||||||
|
var update_at : String?
|
||||||
|
var user : UserMap?
|
||||||
|
|
||||||
|
init?(map: Map) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
mutating func mapping(map: Map) {
|
||||||
|
|
||||||
|
id <- map["id"]
|
||||||
|
user_id <- map["user_id"]
|
||||||
|
name <- map["name"]
|
||||||
|
club_id <- map["club_id"]
|
||||||
|
hourly_rate <- map["hourly_rate"]
|
||||||
|
status <- map["status"]
|
||||||
|
not_paid_through_platform <- map["not_paid_through_platform"]
|
||||||
|
completed <- map["completed"]
|
||||||
|
type <- map["type"]
|
||||||
|
experience <- map["experience"]
|
||||||
|
surface_id <- map["surface_id"]
|
||||||
|
bio <- map["bio"]
|
||||||
|
sport_id <- map["sport_id"]
|
||||||
|
availability <- map["availability"]
|
||||||
|
default_availability <- map["default_availability"]
|
||||||
|
week_specific_availability <- map["week_specific_availability"]
|
||||||
|
account_details <- map["account_details"]
|
||||||
|
photo <- map["photo"]
|
||||||
|
is_public <- map["is_public"]
|
||||||
|
create_at <- map["create_at"]
|
||||||
|
update_at <- map["update_at"]
|
||||||
|
user <- map["user"]
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -51,16 +51,16 @@ struct AvailabilityCardView: View {
|
|||||||
Divider()
|
Divider()
|
||||||
}
|
}
|
||||||
case .coaches:
|
case .coaches:
|
||||||
ForEach(coaches ?? [], id: \.self) { coach in
|
ForEach(self.coaches ?? [], id: \.id) { coach in
|
||||||
HStack {
|
HStack {
|
||||||
ProfileImageView(imageUrl: coach.photo ?? "", size: 30)
|
ProfileImageView(imageUrl: coach.photo ?? "", size: 30)
|
||||||
|
|
||||||
Text(coach.firstName ?? "")
|
Text("\(coach.firstName ?? "") \(coach.lastName ?? "") ")
|
||||||
Spacer()
|
Spacer()
|
||||||
Image("send")
|
Image("send")
|
||||||
.foregroundColor(.gray)
|
.foregroundColor(.gray)
|
||||||
.onTapGesture {
|
.onTapGesture {
|
||||||
name = coach.firstName ?? ""
|
name = "\(coach.firstName ?? "") \(coach.lastName ?? "") "
|
||||||
email = coach.email ?? ""
|
email = coach.email ?? ""
|
||||||
phone = coach.phone ?? ""
|
phone = coach.phone ?? ""
|
||||||
showSheet.toggle()
|
showSheet.toggle()
|
||||||
@@ -70,10 +70,10 @@ struct AvailabilityCardView: View {
|
|||||||
Divider()
|
Divider()
|
||||||
}
|
}
|
||||||
case .staff:
|
case .staff:
|
||||||
ForEach(self.stsff ?? [], id: \.self) { coach in
|
ForEach(self.stsff ?? [], id: \.id) { coach in
|
||||||
HStack {
|
HStack {
|
||||||
ProfileImageView(imageUrl: coach.photo ?? "", size: 30)
|
ProfileImageView(imageUrl: coach.photo ?? "", size: 30)
|
||||||
Text( coach.firstName ?? "")
|
Text("\(coach.firstName ?? "") \(coach.lastName ?? "") ")
|
||||||
Spacer()
|
Spacer()
|
||||||
Image("send")
|
Image("send")
|
||||||
.foregroundColor(.gray)
|
.foregroundColor(.gray)
|
||||||
|
|||||||
@@ -13,13 +13,16 @@ struct AvailabilityScreen: View {
|
|||||||
@Binding var presentSideMenu: Bool // Optional for side menu
|
@Binding var presentSideMenu: Bool // Optional for side menu
|
||||||
|
|
||||||
@EnvironmentObject var viewModel : DashViewModel
|
@EnvironmentObject var viewModel : DashViewModel
|
||||||
|
@State var startDate: Date = Date()
|
||||||
|
@State var endDate: Date = Calendar.current.date(byAdding: .day, value: 1, to: Date()) ?? Date()
|
||||||
|
@State var startTime: Date = Date()
|
||||||
|
@State var endTime: Date = Calendar.current.date(byAdding: .hour, value: 1, to: Date()) ?? Date()
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack(spacing: 16) {
|
VStack(spacing: 16) {
|
||||||
HeaderView(presentSideMenu: $presentSideMenu)
|
HeaderView(presentSideMenu: $presentSideMenu)
|
||||||
|
|
||||||
DateSelectorView()
|
DateSelectorView(startDate: $startDate, endDate: $endDate, startTime: $startTime, endTime: $endTime)
|
||||||
|
|
||||||
TabSelectorView(selectedTab: $selectedTab)
|
TabSelectorView(selectedTab: $selectedTab)
|
||||||
ScrollView {
|
ScrollView {
|
||||||
@@ -36,7 +39,14 @@ struct AvailabilityScreen: View {
|
|||||||
}
|
}
|
||||||
.background(Color(.systemGray6).ignoresSafeArea())
|
.background(Color(.systemGray6).ignoresSafeArea())
|
||||||
.onAppear(){
|
.onAppear(){
|
||||||
viewModel.getAvailability()
|
viewModel.getAvailability(startDate: startDate.toCustomString, endDate: endDate.toCustomString, startTime: startTime.toTimeString, endTime: endTime.toTimeString)
|
||||||
}
|
}
|
||||||
|
.onChange(of: startDate) { _ in
|
||||||
|
viewModel.getAvailability(startDate: startDate.toCustomString, endDate: endDate.toCustomString, startTime: startTime.toTimeString, endTime: endTime.toTimeString)
|
||||||
|
}
|
||||||
|
.onChange(of: endDate) { _ in
|
||||||
|
viewModel.getAvailability(startDate: startDate.toCustomString, endDate: endDate.toCustomString, startTime: startTime.toTimeString, endTime: endTime.toTimeString)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,11 +9,11 @@ import SwiftUI
|
|||||||
|
|
||||||
|
|
||||||
struct DateSelectorView: View {
|
struct DateSelectorView: View {
|
||||||
@State private var startDate: Date = Date()
|
@Binding var startDate: Date
|
||||||
@State private var endDate: Date = Calendar.current.date(byAdding: .day, value: 1, to: Date()) ?? Date()
|
@Binding var endDate: Date
|
||||||
|
|
||||||
@State private var startTime: Date = Date()
|
@Binding var startTime: Date
|
||||||
@State private var endTime: Date = Calendar.current.date(byAdding: .hour, value: 1, to: Date()) ?? Date()
|
@Binding var endTime: Date
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack(spacing: 12) {
|
VStack(spacing: 12) {
|
||||||
|
|||||||
@@ -25,19 +25,21 @@ struct DetailRow: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct DetailsTab: View {
|
struct DetailsTab: View {
|
||||||
|
@EnvironmentObject var viewModel : DashViewModel
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ScrollView {
|
ScrollView {
|
||||||
VStack(alignment: .leading, spacing: 16) {
|
VStack(alignment: .leading, spacing: 16) {
|
||||||
Group {
|
Group {
|
||||||
DetailRow(title: "Reservation date", value: "16 April, 2024")
|
DetailRow(title: "Reservation date", value: viewModel.selectedReservation?.booking?.date ?? "16 April, 2024")
|
||||||
DetailRow(title: "Time", value: "9:00 AM – 10:00 AM")
|
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: "Event type", value: "Lesson")
|
||||||
DetailRow(title: "Sport/type", value: "Tennis • Indoors • Clay")
|
DetailRow(title: "Sport/type", value: "\(viewModel.selectedReservation?.booking?.sport_id ?? 1) • \(viewModel.selectedReservation?.booking?.type ?? "") • \(viewModel.selectedReservation?.booking?.subtype ?? "") ")
|
||||||
DetailRow(title: "Repeating", value: "Every week")
|
DetailRow(title: "Repeating", value: "Every week")
|
||||||
DetailRow(title: "Space assigned", value: "Court #5")
|
DetailRow(title: "Space assigned", value: "Court #5")
|
||||||
DetailRow(title: "Court fee", value: "$50.0")
|
DetailRow(title: "Court fee", value: "$\(viewModel.selectedReservation?.booking?.court_fee ?? "10")")
|
||||||
DetailRow(title: "Court fee status", value: "Paid")
|
DetailRow(title: "Court fee status", value: "Paid")
|
||||||
DetailRow(title: "Note", value: "{content.note}")
|
DetailRow(title: "Note", value: "\(viewModel.selectedReservation?.booking?.notes ?? "--")")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.padding()
|
.padding()
|
||||||
|
|||||||
@@ -8,6 +8,8 @@
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
struct PlayersTab: View {
|
struct PlayersTab: View {
|
||||||
|
@EnvironmentObject var viewModel : DashViewModel
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ScrollView {
|
ScrollView {
|
||||||
VStack(alignment: .leading, spacing: 12) {
|
VStack(alignment: .leading, spacing: 12) {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ struct ScheduleView: View {
|
|||||||
// @State private var events: [ReservationList] = []
|
// @State private var events: [ReservationList] = []
|
||||||
@Binding var presentSideMenu: Bool // Optional for side menu
|
@Binding var presentSideMenu: Bool // Optional for side menu
|
||||||
@State var courtName = ""
|
@State var courtName = ""
|
||||||
let hours = Array(4...20)
|
let hours = Array(0...23)
|
||||||
let calendar = Calendar.current
|
let calendar = Calendar.current
|
||||||
|
|
||||||
@EnvironmentObject var viewModel : DashViewModel
|
@EnvironmentObject var viewModel : DashViewModel
|
||||||
@@ -48,11 +48,49 @@ struct ScheduleView: View {
|
|||||||
}
|
}
|
||||||
// Time Slots with Events
|
// Time Slots with Events
|
||||||
ScrollView {
|
ScrollView {
|
||||||
VStack(spacing: 0) {
|
ZStack(alignment: .topLeading) {
|
||||||
ForEach(hours, id: \.self) { hour in
|
VStack(spacing: 0) {
|
||||||
timeSlotRow(hour: hour)
|
ForEach(hours, id: \.self) { hour in
|
||||||
|
timeSlotRow(hour: hour)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ForEach(viewModel.dailyReservations.filter { event in
|
||||||
|
let selectedDateStr = DateFormatter.bookingDateFormatter.string(from: selectedDate)
|
||||||
|
return event.booking?.date == selectedDateStr
|
||||||
|
}, id: \.id) { event in
|
||||||
|
if let startTime = DateFormatter.timeOnlyFormatter.date(from: event.booking?.start_time ?? ""),
|
||||||
|
let endTime = DateFormatter.timeOnlyFormatter.date(from: event.booking?.end_time ?? "") {
|
||||||
|
|
||||||
|
let startHour = calendar.component(.hour, from: startTime)
|
||||||
|
let endHour = calendar.component(.hour, from: endTime)
|
||||||
|
let yOffset = CGFloat(startHour - hours.first!) * 70
|
||||||
|
let height = max(CGFloat(endHour - startHour), 1) * 70
|
||||||
|
|
||||||
|
VStack(alignment: .leading, spacing: 2) {
|
||||||
|
HStack {
|
||||||
|
Text(event.booking?.type ?? "- -")
|
||||||
|
.font(.subheadline)
|
||||||
|
.bold()
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
|
Text("\(event.booking!.start_time!.to12HourFormat()) - \(event.booking!.end_time!.to12HourFormat())")
|
||||||
|
.font(.caption)
|
||||||
|
.foregroundColor(.gray)
|
||||||
|
}
|
||||||
|
.padding(8)
|
||||||
|
.frame(height: height)
|
||||||
|
.background(Colorr.greenColor.opacity(0.2))
|
||||||
|
.cornerRadius(12)
|
||||||
|
.foregroundColor(Colorr.greenColor.opacity(0.8))
|
||||||
|
.offset(y: yOffset)
|
||||||
|
.onTapGesture {
|
||||||
|
viewModel.selectedReservation = event
|
||||||
|
self.navigationPaths.append("ReservationDetailsView")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.padding(.leading, 60) // leave space for time labels
|
||||||
}
|
}
|
||||||
.padding(.horizontal)
|
.padding(.horizontal)
|
||||||
.padding(.bottom, 20)
|
.padding(.bottom, 20)
|
||||||
@@ -202,14 +240,13 @@ struct ScheduleView: View {
|
|||||||
HStack(alignment: .top) {
|
HStack(alignment: .top) {
|
||||||
Text(timeLabel(for: hour))
|
Text(timeLabel(for: hour))
|
||||||
.font(.caption)
|
.font(.caption)
|
||||||
.frame(width: 50, alignment: .leading)
|
.frame(width: 55, alignment: .leading)
|
||||||
.padding(.top)
|
.padding(.top)
|
||||||
|
|
||||||
ZStack(alignment: .topLeading) {
|
ZStack(alignment: .topLeading) {
|
||||||
Rectangle()
|
Rectangle()
|
||||||
.fill(Color(.systemGray6))
|
.fill(Color(.systemGray6))
|
||||||
.frame(height: 60)
|
.frame(height: 60)
|
||||||
eventOverlay(for: hour)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -242,23 +279,36 @@ struct ScheduleView: View {
|
|||||||
}),
|
}),
|
||||||
id: \.id
|
id: \.id
|
||||||
) { event in
|
) { event in
|
||||||
VStack(alignment: .leading, spacing: 2) {
|
let height: CGFloat = {
|
||||||
Text(event.booking?.type ?? "- -")
|
if let start = DateFormatter.timeOnlyFormatter.date(from: event.booking!.start_time!),
|
||||||
.font(.subheadline)
|
let end = DateFormatter.timeOnlyFormatter.date(from: event.booking!.end_time!) {
|
||||||
.bold()
|
let startHour = calendar.component(.hour, from: start)
|
||||||
Text("\(event.booking!.start_time!.to12HourFormat()) - \(event.booking!.end_time!.to12HourFormat())")
|
let endHour = calendar.component(.hour, from: end)
|
||||||
.font(.caption)
|
let duration = max(endHour - startHour, 1)
|
||||||
.foregroundColor(.gray)
|
return CGFloat(duration) * 60
|
||||||
}
|
}
|
||||||
.padding(8)
|
return 60
|
||||||
.background(Colorr.greenColor.opacity(0.2))
|
}()
|
||||||
.foregroundColor(Colorr.greenColor.opacity(0.8))
|
Color.clear
|
||||||
.cornerRadius(12)
|
.overlay(
|
||||||
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading)
|
VStack(alignment: .leading, spacing: 2) {
|
||||||
.background(Color.clear)
|
Text(event.booking?.type ?? "- -")
|
||||||
.onTapGesture {
|
.font(.subheadline)
|
||||||
self.navigationPaths.append("ReservationDetailsView")
|
.bold()
|
||||||
}
|
Text("\(event.booking!.start_time!.to12HourFormat()) - \(event.booking!.end_time!.to12HourFormat())")
|
||||||
|
.font(.caption)
|
||||||
|
.foregroundColor(.gray)
|
||||||
|
}
|
||||||
|
.padding(8)
|
||||||
|
.frame(height: height)
|
||||||
|
.background(Colorr.greenColor.opacity(0.2))
|
||||||
|
.cornerRadius(12)
|
||||||
|
.foregroundColor(Colorr.greenColor.opacity(0.8))
|
||||||
|
.onTapGesture {
|
||||||
|
self.navigationPaths.append("ReservationDetailsView")
|
||||||
|
},
|
||||||
|
alignment: .topLeading
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.padding(.top, 4)
|
.padding(.top, 4)
|
||||||
@@ -345,6 +395,14 @@ extension DateFormatter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension DateFormatter {
|
||||||
|
static var timeOnlyFormatter: DateFormatter {
|
||||||
|
let formatter = DateFormatter()
|
||||||
|
formatter.dateFormat = "HH:mm:ss"
|
||||||
|
return formatter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
extension String {
|
extension String {
|
||||||
func to12HourFormat() -> String {
|
func to12HourFormat() -> String {
|
||||||
let inputFormatter = DateFormatter()
|
let inputFormatter = DateFormatter()
|
||||||
|
|||||||
@@ -19,9 +19,9 @@ struct AnalyticsView: View {
|
|||||||
// SegmentedControlView()
|
// SegmentedControlView()
|
||||||
ScrollView {
|
ScrollView {
|
||||||
VStack(spacing: 15) {
|
VStack(spacing: 15) {
|
||||||
// PieChartCard(data: self.viewModel.statResponse?.revenueByModule ?? [])
|
PieChartCard(data: self.viewModel.statResponse?.revenueByModule ?? [])
|
||||||
// BarChartCard(data: self.viewModel.statResponse?.revenueHeatMap ?? [])
|
// BarChartCard(data: self.viewModel.statResponse?.revenueHeatMap ?? [])
|
||||||
PieChartCard1()
|
// PieChartCard1()
|
||||||
BarChartCard1()
|
BarChartCard1()
|
||||||
}
|
}
|
||||||
.padding(.horizontal)
|
.padding(.horizontal)
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ struct SummaryView: View {
|
|||||||
@EnvironmentObject var viewModel : DashViewModel
|
@EnvironmentObject var viewModel : DashViewModel
|
||||||
@Binding var presentSideMenu: Bool // Optional for side menu
|
@Binding var presentSideMenu: Bool // Optional for side menu
|
||||||
@State var filterCount = 0
|
@State var filterCount = 0
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
NavigationStack(path: $navigationPaths) {
|
NavigationStack(path: $navigationPaths) {
|
||||||
VStack {
|
VStack {
|
||||||
@@ -26,7 +27,7 @@ struct SummaryView: View {
|
|||||||
|
|
||||||
if selectedTab == 0 {
|
if selectedTab == 0 {
|
||||||
FilterView(navigationPaths: $navigationPaths, filterCount: $filterCount)
|
FilterView(navigationPaths: $navigationPaths, filterCount: $filterCount)
|
||||||
CourtUtilizationView()
|
CourtUtilizationView(utilization: "\(self.viewModel.statResponse?.courtUtilization.first?.utilization_percentage ?? 10.0)%" )
|
||||||
|
|
||||||
ScrollView {
|
ScrollView {
|
||||||
LazyVStack(spacing: 10) {
|
LazyVStack(spacing: 10) {
|
||||||
@@ -54,9 +55,9 @@ struct SummaryView: View {
|
|||||||
.navigationBarHidden(true)
|
.navigationBarHidden(true)
|
||||||
.navigationDestination(for: String.self) { value in
|
.navigationDestination(for: String.self) { value in
|
||||||
if value == "FilterScreen" {
|
if value == "FilterScreen" {
|
||||||
FilterScreen(navigationPaths: $navigationPaths) { filter, filterCount in
|
FilterScreen(navigationPaths: $navigationPaths) { startDate, endDate, startTime, endTime, filterCount in
|
||||||
self.filterCount = filterCount
|
self.filterCount = filterCount
|
||||||
viewModel.getStats(completion: {})
|
viewModel.getStats ( startDate: startDate, endDate: endDate, startTime: startTime, endTime: endTime, completion: {})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -68,7 +69,7 @@ struct SummaryView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// viewModel.getClubProfile()
|
// viewModel.getClubProfile()
|
||||||
viewModel.getProfile()
|
// viewModel.getProfile()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,16 +84,14 @@ struct HeaderView: View {
|
|||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
HStack {
|
HStack {
|
||||||
Image(systemName: "person.circle.fill")
|
ProfileImageView(imageUrl: AppSettings.clubLogo, size: 32)
|
||||||
.resizable()
|
.onTapGesture {
|
||||||
.frame(width: 32, height: 32)
|
|
||||||
.onTapGesture {
|
|
||||||
presentSideMenu.toggle()
|
presentSideMenu.toggle()
|
||||||
}
|
}
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
Text("The Royal Club")
|
Text(AppSettings.clubName)
|
||||||
.font(.headline)
|
.font(.headline)
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
@@ -199,13 +198,14 @@ struct FilterView: View {
|
|||||||
|
|
||||||
// MARK: - Court Utilization
|
// MARK: - Court Utilization
|
||||||
struct CourtUtilizationView: View {
|
struct CourtUtilizationView: View {
|
||||||
|
@State var utilization: String
|
||||||
var body: some View {
|
var body: some View {
|
||||||
HStack {
|
HStack {
|
||||||
Text("Court utilization")
|
Text("Court utilization")
|
||||||
.font(.subheadline)
|
.font(.subheadline)
|
||||||
.bold()
|
.bold()
|
||||||
Spacer()
|
Spacer()
|
||||||
Text("66%")
|
Text(utilization)
|
||||||
.font(.subheadline)
|
.font(.subheadline)
|
||||||
.bold()
|
.bold()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ struct FilterScreen: View {
|
|||||||
@State private var selectedDuration: String = "This Day"
|
@State private var selectedDuration: String = "This Day"
|
||||||
let durationOptions = ["This Day", "This Week", "This Month", "This Year"]
|
let durationOptions = ["This Day", "This Week", "This Month", "This Year"]
|
||||||
|
|
||||||
@State var filterBlock : ((String, Int) ->Void)?
|
@State var filterBlock : ((String, String, String, String, Int) ->Void)?
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
NavigationView {
|
NavigationView {
|
||||||
@@ -89,7 +89,7 @@ struct FilterScreen: View {
|
|||||||
print("Generated Filter Query: \(query)")
|
print("Generated Filter Query: \(query)")
|
||||||
print("Filter count: \(filterCount)")
|
print("Filter count: \(filterCount)")
|
||||||
|
|
||||||
self.filterBlock?(query, filterCount)
|
self.filterBlock?(startDateStr, endDateStr, startTimeStr, endTimeStr, filterCount)
|
||||||
self.navigationPaths.removeLast()
|
self.navigationPaths.removeLast()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,8 @@ struct SigninView: View {
|
|||||||
@State private var keepLoggedIn = false
|
@State private var keepLoggedIn = false
|
||||||
@State private var showPassword = false
|
@State private var showPassword = false
|
||||||
@EnvironmentObject var viewModel: AuthViewModel
|
@EnvironmentObject var viewModel: AuthViewModel
|
||||||
|
@EnvironmentObject var dashViewModel : DashViewModel
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
NavigationStack(path: $navigationPaths) {
|
NavigationStack(path: $navigationPaths) {
|
||||||
ScrollView {
|
ScrollView {
|
||||||
@@ -106,6 +107,7 @@ struct SigninView: View {
|
|||||||
Button(action: {
|
Button(action: {
|
||||||
viewModel.login {_ in
|
viewModel.login {_ in
|
||||||
// Navigate to the Dashboard on successful login
|
// Navigate to the Dashboard on successful login
|
||||||
|
dashViewModel.getProfile()
|
||||||
navigationPaths.removeAll()
|
navigationPaths.removeAll()
|
||||||
navigationPaths.append("Dashboard")
|
navigationPaths.append("Dashboard")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -138,12 +138,12 @@ struct SideMenuView: View {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Text("John Smith")
|
Text("\(AppSettings.fName) \(AppSettings.lastName)")
|
||||||
.padding(.leading)
|
.padding(.leading)
|
||||||
.font(.system(size: 18, weight: .bold))
|
.font(.system(size: 18, weight: .bold))
|
||||||
.foregroundColor(.black)
|
.foregroundColor(.black)
|
||||||
|
|
||||||
Text("John@gmail.com")
|
Text(AppSettings.email)
|
||||||
.padding(.leading)
|
.padding(.leading)
|
||||||
.font(.system(size: 14, weight: .semibold))
|
.font(.system(size: 14, weight: .semibold))
|
||||||
.foregroundColor(.gray)
|
.foregroundColor(.gray)
|
||||||
|
|||||||
@@ -353,3 +353,18 @@ extension String {
|
|||||||
return formatter.string(from: date)
|
return formatter.string(from: date)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
extension Date {
|
||||||
|
var toCustomString: String {
|
||||||
|
let formatter = DateFormatter()
|
||||||
|
formatter.dateFormat = "dd-MMM-yyyy"
|
||||||
|
return formatter.string(from: self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension Date {
|
||||||
|
var toTimeString: String {
|
||||||
|
let formatter = DateFormatter()
|
||||||
|
formatter.dateFormat = "hh:mm a"
|
||||||
|
return formatter.string(from: self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -71,7 +71,8 @@ class AuthViewModel: ObservableObject {
|
|||||||
// Save the token and user ID for the session
|
// Save the token and user ID for the session
|
||||||
AppSettings.token = response.token
|
AppSettings.token = response.token
|
||||||
AppSettings.userID = response.userId
|
AppSettings.userID = response.userId
|
||||||
AppSettings.lastName
|
|
||||||
|
|
||||||
// Update login state
|
// Update login state
|
||||||
self.isLoggedIn = true
|
self.isLoggedIn = true
|
||||||
completion(true) // Proceed to Dashboard
|
completion(true) // Proceed to Dashboard
|
||||||
|
|||||||
@@ -18,13 +18,21 @@ class DashViewModel: ObservableObject {
|
|||||||
@Published var clubDetail : ClubDetailsResponse?
|
@Published var clubDetail : ClubDetailsResponse?
|
||||||
@Published var profile : ProfileDetailResponse?
|
@Published var profile : ProfileDetailResponse?
|
||||||
@Published var sessionExpired = false
|
@Published var sessionExpired = false
|
||||||
|
@Published var selectedReservation : ReservationList?
|
||||||
|
@Published var players : [UserMap]?
|
||||||
|
@Published var coaches : [PlayerList]?
|
||||||
|
|
||||||
func getStats(completion: @escaping () -> ()) {
|
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(
|
let endpoint = ClubStatisticsEndpoint(
|
||||||
startDate: "2024-10-25",
|
startDate: startDate!,
|
||||||
endDate: "2024-11-25",
|
endDate: endDate!,
|
||||||
startTime: "17:30:20",
|
startTime: startTime!,
|
||||||
endTime: "19:20:30"
|
endTime: endTime!
|
||||||
)
|
)
|
||||||
|
|
||||||
Task {
|
Task {
|
||||||
@@ -60,8 +68,19 @@ class DashViewModel: ObservableObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getAvailability(){
|
func getAvailability(
|
||||||
let endpoint = AvailabilityListEndpoint()
|
startDate: String? = "2024-10-25",
|
||||||
|
endDate: String? = "2024-11-25",
|
||||||
|
startTime: String? = "17:30:20",
|
||||||
|
endTime: String? = "19:20:30"
|
||||||
|
){
|
||||||
|
let endpoint = AvailabilityListEndpoint(
|
||||||
|
startDate: startDate!,
|
||||||
|
endDate: endDate!,
|
||||||
|
startTime: startTime!,
|
||||||
|
endTime: endTime!
|
||||||
|
|
||||||
|
)
|
||||||
Task {
|
Task {
|
||||||
do {
|
do {
|
||||||
let result = try await APIService.shared.request(endpoint, responseType: AvailabliltyRsp.self)
|
let result = try await APIService.shared.request(endpoint, responseType: AvailabliltyRsp.self)
|
||||||
@@ -82,7 +101,11 @@ class DashViewModel: ObservableObject {
|
|||||||
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.email = result?.model?.user?.email ?? ""
|
||||||
|
AppSettings.photo = result?.model?.user?.photo ?? ""
|
||||||
|
AppSettings.fName = result?.model?.user?.first_name ?? ""
|
||||||
|
AppSettings.lastName = result?.model?.user?.last_name ?? ""
|
||||||
|
AppSettings.clubLogo = result?.model?.club?.club_logo ?? ""
|
||||||
|
|
||||||
} catch {
|
} catch {
|
||||||
print("Error fetching reservations:", error)
|
print("Error fetching reservations:", error)
|
||||||
@@ -101,4 +124,29 @@ class DashViewModel: ObservableObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func getPlayers(playerIds: String){
|
||||||
|
let endpoint = GetPlayerListEndpoint(playerIds: playerIds)
|
||||||
|
Task {
|
||||||
|
do {
|
||||||
|
let result = try await APIService.shared.requestPlayers(endpoint)
|
||||||
|
players = result?.list ?? []
|
||||||
|
} catch {
|
||||||
|
print("Error fetching reservations:", error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getCoaches(playerIds: String){
|
||||||
|
let endpoint = GetCoachListEndpoint(playerIds: playerIds)
|
||||||
|
Task {
|
||||||
|
do {
|
||||||
|
let result = try await APIService.shared.requestCoach(endpoint)
|
||||||
|
coaches = result?.list
|
||||||
|
} catch {
|
||||||
|
print("Error fetching reservations:", error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user