diff --git a/Club_portal/Club Portal/Club Portal.xcodeproj/project.pbxproj b/Club_portal/Club Portal/Club Portal.xcodeproj/project.pbxproj index 54b38b2..408343a 100644 --- a/Club_portal/Club Portal/Club Portal.xcodeproj/project.pbxproj +++ b/Club_portal/Club Portal/Club Portal.xcodeproj/project.pbxproj @@ -9,6 +9,8 @@ /* Begin PBXBuildFile section */ AC136A092DB96847009D478F /* ObjectMapper in Frameworks */ = {isa = PBXBuildFile; productRef = AC136A082DB96847009D478F /* ObjectMapper */; }; AC53DEAA2DB9476D003445AD /* Alamofire in Frameworks */ = {isa = PBXBuildFile; productRef = AC53DEA92DB9476D003445AD /* Alamofire */; }; + AC8826F32E6F5A6700ECEF0D /* CropViewController in Frameworks */ = {isa = PBXBuildFile; productRef = AC8826F22E6F5A6700ECEF0D /* CropViewController */; }; + AC8826F52E6F5A6700ECEF0D /* TOCropViewController in Frameworks */ = {isa = PBXBuildFile; productRef = AC8826F42E6F5A6700ECEF0D /* TOCropViewController */; }; ACAC2DEB2D9F2C1900869E5C /* CalendarKit in Frameworks */ = {isa = PBXBuildFile; productRef = ACAC2DEA2D9F2C1900869E5C /* CalendarKit */; }; /* End PBXBuildFile section */ @@ -30,6 +32,8 @@ buildActionMask = 2147483647; files = ( AC136A092DB96847009D478F /* ObjectMapper in Frameworks */, + AC8826F52E6F5A6700ECEF0D /* TOCropViewController in Frameworks */, + AC8826F32E6F5A6700ECEF0D /* CropViewController in Frameworks */, ACAC2DEB2D9F2C1900869E5C /* CalendarKit in Frameworks */, AC53DEAA2DB9476D003445AD /* Alamofire in Frameworks */, ); @@ -77,6 +81,8 @@ ACAC2DEA2D9F2C1900869E5C /* CalendarKit */, AC53DEA92DB9476D003445AD /* Alamofire */, AC136A082DB96847009D478F /* ObjectMapper */, + AC8826F22E6F5A6700ECEF0D /* CropViewController */, + AC8826F42E6F5A6700ECEF0D /* TOCropViewController */, ); productName = "Club Portal"; productReference = ACAC2DCF2D9F271300869E5C /* Club Portal.app */; @@ -110,6 +116,7 @@ ACAC2DE92D9F2C1900869E5C /* XCRemoteSwiftPackageReference "CalendarKit" */, AC53DEA82DB9476D003445AD /* XCRemoteSwiftPackageReference "Alamofire" */, AC136A072DB96847009D478F /* XCRemoteSwiftPackageReference "ObjectMapper" */, + AC8826F12E6F5A6700ECEF0D /* XCRemoteSwiftPackageReference "TOCropViewController" */, ); preferredProjectObjectVersion = 77; productRefGroup = ACAC2DD02D9F271300869E5C /* Products */; @@ -267,16 +274,18 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 3; + CURRENT_PROJECT_VERSION = 4; DEVELOPMENT_ASSET_PATHS = "\"Club Portal/Preview Content\""; DEVELOPMENT_TEAM = BSGYUG5U29; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = "Club-Portal-Info.plist"; + INFOPLIST_KEY_CFBundleDisplayName = "Club Portal"; INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchScreen_Generation = YES; - INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; - INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations = UIInterfaceOrientationPortrait; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -300,16 +309,18 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 3; + CURRENT_PROJECT_VERSION = 4; DEVELOPMENT_ASSET_PATHS = "\"Club Portal/Preview Content\""; DEVELOPMENT_TEAM = BSGYUG5U29; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = "Club-Portal-Info.plist"; + INFOPLIST_KEY_CFBundleDisplayName = "Club Portal"; INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchScreen_Generation = YES; - INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; - INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations = UIInterfaceOrientationPortrait; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -367,6 +378,14 @@ minimumVersion = 5.10.2; }; }; + AC8826F12E6F5A6700ECEF0D /* XCRemoteSwiftPackageReference "TOCropViewController" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/TimOliver/TOCropViewController"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 2.7.4; + }; + }; ACAC2DE92D9F2C1900869E5C /* XCRemoteSwiftPackageReference "CalendarKit" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/richardtop/CalendarKit"; @@ -388,6 +407,16 @@ package = AC53DEA82DB9476D003445AD /* XCRemoteSwiftPackageReference "Alamofire" */; productName = Alamofire; }; + AC8826F22E6F5A6700ECEF0D /* CropViewController */ = { + isa = XCSwiftPackageProductDependency; + package = AC8826F12E6F5A6700ECEF0D /* XCRemoteSwiftPackageReference "TOCropViewController" */; + productName = CropViewController; + }; + AC8826F42E6F5A6700ECEF0D /* TOCropViewController */ = { + isa = XCSwiftPackageProductDependency; + package = AC8826F12E6F5A6700ECEF0D /* XCRemoteSwiftPackageReference "TOCropViewController" */; + productName = TOCropViewController; + }; ACAC2DEA2D9F2C1900869E5C /* CalendarKit */ = { isa = XCSwiftPackageProductDependency; package = ACAC2DE92D9F2C1900869E5C /* XCRemoteSwiftPackageReference "CalendarKit" */; diff --git a/Club_portal/Club Portal/Club Portal.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Club_portal/Club Portal/Club Portal.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index b6006bc..1b06acb 100644 --- a/Club_portal/Club Portal/Club Portal.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Club_portal/Club Portal/Club Portal.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,5 +1,5 @@ { - "originHash" : "60390f3252b346980a2b0f96582e92fec2c37e9487d7b684f3d58a001c214046", + "originHash" : "b1b0353358422b4fa2ea090c1b3ed8788cceebbcf36fc271f832e564b41e6da4", "pins" : [ { "identity" : "alamofire", @@ -27,6 +27,15 @@ "revision" : "6021c6035e83a306047348666f6400dc61445d3b", "version" : "4.4.3" } + }, + { + "identity" : "tocropviewcontroller", + "kind" : "remoteSourceControl", + "location" : "https://github.com/TimOliver/TOCropViewController", + "state" : { + "revision" : "a634cb7cdfd580006e79a6e74e64417fe9e9783b", + "version" : "2.7.4" + } } ], "version" : 3 diff --git a/Club_portal/Club Portal/Club Portal/Network/Api_Stuff/APIConstants.swift b/Club_portal/Club Portal/Club Portal/Network/Api_Stuff/APIConstants.swift index e752b5f..3e6a2b7 100644 --- a/Club_portal/Club Portal/Club Portal/Network/Api_Stuff/APIConstants.swift +++ b/Club_portal/Club Portal/Club Portal/Network/Api_Stuff/APIConstants.swift @@ -7,7 +7,7 @@ enum APIConstants { - static let baseURL = "https://courtmatchup.mkdlabs.com" + static let baseURL = "http://199.241.139.243:3048" //"https://courtmatchup.mkdlabs.com" static let xProject = "Y291cnRtYXRjaHVwOmczbmp1OTlpZjR3enk4Z3V0bHEwYmUwZDI1Nzk1MTNsbTg=" static var commonHeaders: [String: String] { var headers = ["Content-Type": "application/json", diff --git a/Club_portal/Club Portal/Club Portal/Network/Api_Stuff/EndPoints/ReservationListEndpoint.swift b/Club_portal/Club Portal/Club Portal/Network/Api_Stuff/EndPoints/ReservationListEndpoint.swift index a948cdd..a466499 100644 --- a/Club_portal/Club Portal/Club Portal/Network/Api_Stuff/EndPoints/ReservationListEndpoint.swift +++ b/Club_portal/Club Portal/Club Portal/Network/Api_Stuff/EndPoints/ReservationListEndpoint.swift @@ -35,3 +35,21 @@ struct ReservationListEndpoint: Endpoint { var isMultipart: Bool { false } } + +// MARK: - Search reservations by user first name (contains) +struct ReservationSearchEndpoint: Endpoint { + var urlQueryItems: [URLQueryItem] = [] + var path: String { + "/v4/api/records/reservation?join=booking|booking_id&join=user|user_id&join=buddy|buddy_id&join=clubs|club_id&join=clinics|clinic_id&order=id,desc&filter=courtmatchup_user.first_name,cs,\(query)" + } + + var method: HTTPMethod { .get } + + let query: String + + var customHeaders: [String: String]? { nil } + + var body: Data? { nil } + + var isMultipart: Bool { false } +} diff --git a/Club_portal/Club Portal/Club Portal/Network/Api_Stuff/Response/AvailabliltyRsp.swift b/Club_portal/Club Portal/Club Portal/Network/Api_Stuff/Response/AvailabliltyRsp.swift index d3ec5ce..ffadcf1 100644 --- a/Club_portal/Club Portal/Club Portal/Network/Api_Stuff/Response/AvailabliltyRsp.swift +++ b/Club_portal/Club Portal/Club Portal/Network/Api_Stuff/Response/AvailabliltyRsp.swift @@ -24,14 +24,19 @@ struct AvailabliltyRsp: Codable { // MARK: - Coaches struct Coaches: Codable { + // legacy shape let available: [CoachesAvailable]? let unavailable: [CoachesAvailable]? let total: Int? + // new shape + let items: [CoachesAvailable]? + let counts: JSONAny? + let pagination: JSONAny? } // MARK: - CoachesAvailable struct CoachesAvailable: Codable , Identifiable, Hashable { - let id = UUID().uuidString + let id: Int? let coachID, userID: Int? let bio, hourlyRate, availability, firstName: String? let lastName, phone, email: String? @@ -114,9 +119,14 @@ struct Sport: Codable, Identifiable, Hashable{ // MARK: - Courts struct Courts: Codable { + // Old payload support let available: [CourtsAvailable]? let unavailable: [JSONAny]? let total: Int? + // New payload support + let items: [CourtsAvailable]? + let counts: JSONAny? + let pagination: JSONAny? } // MARK: - CourtsAvailable @@ -127,6 +137,9 @@ struct CourtsAvailable: Codable, Identifiable , Hashable{ let availability, sportName: String? let surfaceName: String? let availabilityData: AvailabilityData? + // New payload fields + let availabilitySlots: [Availability]? + let unavailabilitySlots: [JSONAny]? enum CodingKeys: String, CodingKey { case id, name, type, subtype @@ -136,6 +149,8 @@ struct CourtsAvailable: Codable, Identifiable , Hashable{ case sportName = "sport_name" case surfaceName = "surface_name" case availabilityData + case availabilitySlots = "availability_slots" + case unavailabilitySlots = "unavailability_slots" } func hash(into hasher: inout Hasher) { hasher.combine(id) @@ -153,15 +168,53 @@ struct Range: Codable { // MARK: - Hours struct Hours: Codable { - let available: [String]? - let total: Int? + // New payload fields + let available: [HourSlot]? // e.g., [{start:"11:00:00", end:"11:30:00"}] + let unavailable: [UnavailableHour]? let range: Range? + let unavailableRange: Range? let byDate: [ByDate]? + let unavailableByDate: [ByDateUnavailable]? + // Legacy support + let total: Int? + + enum CodingKeys: String, CodingKey { + case available, unavailable, range, byDate + case unavailableRange = "unavailable_range" + case unavailableByDate = "unavailable_byDate" + case total + } +} + +// MARK: - HourSlot +struct HourSlot: Codable, Hashable { + let start: String? + let end: String? +} + +// MARK: - UnavailableHour +struct UnavailableHour: Codable, Hashable { + let start: String? + let end: String? + let reason: String? } // MARK: - ByDate struct ByDate: Codable { let date: String? + let ranges: [HourSlot]? + let slots: [String]? + let from, until: String? + + enum CodingKeys: String, CodingKey { + case date, ranges, slots, from, until + } +} + +// MARK: - ByDateUnavailable +struct ByDateUnavailable: Codable { + let date: String? + let ranges: [UnavailableHour]? let slots: [String]? let from, until: String? } @@ -169,9 +222,14 @@ struct ByDate: Codable { // MARK: - Staff struct Staff: Codable, Identifiable, Hashable { var id: Int? + // legacy let available: [StaffAvailable]? let unavailable: [JSONAny]? let total: Int? + // new + let items: [StaffAvailable]? + let counts: JSONAny? + let pagination: JSONAny? static func == (lhs: Staff, rhs: Staff) -> Bool { lhs.id == rhs.id diff --git a/Club_portal/Club Portal/Club Portal/UI/Availbility/AvailabilityCardView.swift b/Club_portal/Club Portal/Club Portal/UI/Availbility/AvailabilityCardView.swift index 39e88cc..582bb85 100644 --- a/Club_portal/Club Portal/Club Portal/UI/Availbility/AvailabilityCardView.swift +++ b/Club_portal/Club Portal/Club Portal/UI/Availbility/AvailabilityCardView.swift @@ -9,7 +9,7 @@ import SwiftUI struct AvailabilityCardView: View { var tab: AvailabilityTab var courts: [CourtsAvailable] = [] - var hours: [String]? + var hours: [HourSlot]? var coaches: [CoachesAvailable]? var stsff: [StaffAvailable]? @State var name : String = "" @@ -44,7 +44,7 @@ struct AvailabilityCardView: View { } case .hours: ForEach(hours ?? [] , id: \.self) { hour in - Text("\(hour)") + Text("\(hour.start ?? "") - \(hour.end ?? "")") .onTapGesture { showSheet.toggle() } diff --git a/Club_portal/Club Portal/Club Portal/UI/Availbility/AvailabilityScreen.swift b/Club_portal/Club Portal/Club Portal/UI/Availbility/AvailabilityScreen.swift index 4ad21b3..e184639 100644 --- a/Club_portal/Club Portal/Club Portal/UI/Availbility/AvailabilityScreen.swift +++ b/Club_portal/Club Portal/Club Portal/UI/Availbility/AvailabilityScreen.swift @@ -28,10 +28,10 @@ struct AvailabilityScreen: View { ScrollView { AvailabilityCardView( tab: selectedTab, - courts: viewModel.availRsp?.courts?.available ?? [] , + courts: viewModel.availRsp?.courts?.items ?? viewModel.availRsp?.courts?.available ?? [] , hours: viewModel.availRsp?.hours?.available ?? [] , - coaches: viewModel.availRsp?.coaches?.available ?? [], - stsff: viewModel.availRsp?.staff?.available ?? [] + coaches: viewModel.availRsp?.coaches?.items ?? viewModel.availRsp?.coaches?.available ?? [], + stsff: viewModel.availRsp?.staff?.items ?? viewModel.availRsp?.staff?.available ?? [] ) } diff --git a/Club_portal/Club Portal/Club Portal/UI/DailySecheduler/ScheduleView.swift b/Club_portal/Club Portal/Club Portal/UI/DailySecheduler/ScheduleView.swift index f235e92..62bd161 100644 --- a/Club_portal/Club Portal/Club Portal/UI/DailySecheduler/ScheduleView.swift +++ b/Club_portal/Club Portal/Club Portal/UI/DailySecheduler/ScheduleView.swift @@ -14,6 +14,7 @@ struct ScheduleView: View { @State private var selectedCourtName: String? = nil @State private var selectedCourtId: Int? = nil + @State private var searchQuery: String = "" @EnvironmentObject var viewModel : DashViewModel @@ -173,8 +174,12 @@ struct ScheduleView: View { Image(systemName: "magnifyingglass") .foregroundColor(.gray) - TextField("search player", text: .constant("")) + TextField("Search player", text: $searchQuery) .foregroundColor(.primary) + .submitLabel(.search) + .onSubmit { + viewModel.searchDailySched(query: searchQuery) + } } .padding(5) .background(Color(.white)) @@ -184,6 +189,13 @@ struct ScheduleView: View { .stroke(Color(.systemGray4), lineWidth: 1) ) //.padding(.horizontal) + .onChange(of: searchQuery) { newVal in + let q = newVal.trimmingCharacters(in: .whitespacesAndNewlines) + if q.isEmpty { + // restore list for selected court when clearing search + if let cid = selectedCourtId { viewModel.getDailySched(clubId: cid) } + } + } Button(action: { diff --git a/Club_portal/Club Portal/Club Portal/UI/Dashboard/DashboardView.swift b/Club_portal/Club Portal/Club Portal/UI/Dashboard/DashboardView.swift index 1dd4f70..b6b59bf 100644 --- a/Club_portal/Club Portal/Club Portal/UI/Dashboard/DashboardView.swift +++ b/Club_portal/Club Portal/Club Portal/UI/Dashboard/DashboardView.swift @@ -101,7 +101,7 @@ struct SummaryView: View { } } // viewModel.getClubProfile() - // viewModel.getProfile() + viewModel.getProfile() } diff --git a/Club_portal/Club Portal/Club Portal/UI/SideMenu/SideMenuView.swift b/Club_portal/Club Portal/Club Portal/UI/SideMenu/SideMenuView.swift index 5b2eeef..fcd552e 100644 --- a/Club_portal/Club Portal/Club Portal/UI/SideMenu/SideMenuView.swift +++ b/Club_portal/Club Portal/Club Portal/UI/SideMenu/SideMenuView.swift @@ -126,7 +126,7 @@ struct SideMenuView: View { func ProfileHead() -> some View { VStack(alignment: .leading) { HStack { - ProfileImageView(imageUrl: AppSettings.photo, size: 50) + ProfileImageView(imageUrl: AppSettings.photo.isEmpty ? AppSettings.clubLogo : AppSettings.photo, size: 50) .padding(.leading) Spacer() diff --git a/Club_portal/Club Portal/Club Portal/Utliz/PhotoPickerWithCrop.swift b/Club_portal/Club Portal/Club Portal/Utliz/PhotoPickerWithCrop.swift new file mode 100644 index 0000000..3df0931 --- /dev/null +++ b/Club_portal/Club Portal/Club Portal/Utliz/PhotoPickerWithCrop.swift @@ -0,0 +1,75 @@ +// +// PhotoPickerWithCrop.swift +// Club Portal +// +// Created by Umer Tahir on 23/05/2025. +// + + +// +// PhotoPickerWithCrop.swift +// Club Portal +// +// Created by Umer Tahir on 23/05/2025. +// + +import SwiftUI +import PhotosUI +import TOCropViewController + +struct PhotoPickerWithCrop: UIViewControllerRepresentable { + @Binding var selectedImage: UIImage? + + func makeCoordinator() -> Coordinator { + Coordinator(self) + } + + func makeUIViewController(context: Context) -> PHPickerViewController { + var config = PHPickerConfiguration() + config.filter = .images + config.selectionLimit = 1 + + let picker = PHPickerViewController(configuration: config) + picker.delegate = context.coordinator + return picker + } + + func updateUIViewController(_ uiViewController: PHPickerViewController, context: Context) {} + + class Coordinator: NSObject, PHPickerViewControllerDelegate, TOCropViewControllerDelegate { + var parent: PhotoPickerWithCrop + var imageToCrop: UIImage? + + init(_ parent: PhotoPickerWithCrop) { + self.parent = parent + } + + func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) { + picker.dismiss(animated: true) + + guard let provider = results.first?.itemProvider, + provider.canLoadObject(ofClass: UIImage.self) else { return } + + provider.loadObject(ofClass: UIImage.self) { [weak self] object, _ in + guard let self = self, let image = object as? UIImage else { return } + self.imageToCrop = image + + DispatchQueue.main.async { + guard let root = UIApplication.shared.windows.first?.rootViewController else { return } + let cropVC = TOCropViewController(image: image) + cropVC.delegate = self + root.present(cropVC, animated: true) + } + } + } + + func cropViewController(_ cropViewController: TOCropViewController, didCropTo image: UIImage, with cropRect: CGRect, angle: Int) { + cropViewController.dismiss(animated: true) + parent.selectedImage = image + } + + func cropViewControllerDidCancel(_ cropViewController: TOCropViewController) { + cropViewController.dismiss(animated: true) + } + } +} diff --git a/Club_portal/Club Portal/Club Portal/ViewModels/DashViewModel.swift b/Club_portal/Club Portal/Club Portal/ViewModels/DashViewModel.swift index 2f1f3c8..1908512 100644 --- a/Club_portal/Club Portal/Club Portal/ViewModels/DashViewModel.swift +++ b/Club_portal/Club Portal/Club Portal/ViewModels/DashViewModel.swift @@ -71,6 +71,20 @@ class DashViewModel: ObservableObject { } } + func searchDailySched(query: String){ + guard !query.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty else { return } + let endpoint = ReservationSearchEndpoint(query: query) + Task { + do { + let result = try await APIService.shared.requestReservation(endpoint, responseType: ProfileRsp.self) + dailyReservations = result?.list ?? [] + print("Search Reservations:", result?.list) + } catch { + print("Error searching reservations:", error) + } + } + } + func getAvailability( startDate: String? = "2024-10-25", endDate: String? = "2024-11-25", diff --git a/Club_portal/Club Portal/Club-Portal-Info.plist b/Club_portal/Club Portal/Club-Portal-Info.plist new file mode 100644 index 0000000..6a6654d --- /dev/null +++ b/Club_portal/Club Portal/Club-Portal-Info.plist @@ -0,0 +1,11 @@ + + + + + NSAppTransportSecurity + + NSAllowsArbitraryLoads + + + +