// // ContentView.swift // minimum-working-example // // Created by Joe on 8/12/23. // import SwiftUI import Foundation struct ContentView: View { //@StateObject var participantListViewModel: ParticipantListViewModel = ParticipantListViewModel() var participants: [Participant] = [Participant.sampleParticipant,Participant.sampleParticipant] //@StateObject var portalUserViewModel: PortalUserViewModel = PortalUserViewModel() var portalUser: PortalUser = PortalUser.emptyUser @AppStorage("lastUpdated") var lastUpdated = Date.distantFuture.timeIntervalSince1970 @State var isSidebarOpened = false @State private var filterParticipantListBy: ApprovalStatus = ApprovalStatus.All @State var isLoading = false var filteredParticipants: [Participant] { participants.filter{ participant in (filterParticipantListBy == ApprovalStatus.All || participant.approved == filterParticipantListBy) } } var body: some View { NavigationView{ ZStack{ //NavigationView{ VStack{ List{ Picker("Show only", selection: $filterParticipantListBy) { Text("Show All").tag(ApprovalStatus.All) Text("Approved").tag(ApprovalStatus.Approved) Text("Denied").tag(ApprovalStatus.Denied) Text("Pending").tag(ApprovalStatus.Pending) } ForEach(filteredParticipants) { participant in NavigationLink{ ParticipantDetail(participant:participant) }label:{ ParticipantRow(participant:participant) } } } .navigationTitle("Participants") .toolbar(content: toolbarContent) /*.refreshable { participantListViewModel.getParticipants(authString: Auth.shared.getAccessToken()!) }*/ //ProgressView().opacity(1) } //} Spacer() Sidebar( isSidebarVisible: $isSidebarOpened, /*participantListViewModel: participantListViewModel, portalUserViewModel: portalUserViewModel*/ participants:participants, portalUser:portalUser ) } } /*.onAppear(perform: { participantListViewModel.getParticipants(authString: Auth.shared.getAccessToken()!) portalUserViewModel.getUser(authString: Auth.shared.getAccessToken()!) })*/ } } struct Participant: Hashable, Codable, Identifiable { var id: String var approved: ApprovalStatus var active: Bool var firstName: String var lastName: String var dob: Date var programStart: Date var address1: String var address2: String var city: String var state: String var zip: String enum CodingKeys: String, CodingKey { case id = "record_id" case approved case active case firstName = "first_name" case lastName = "last_name" case dob case programStart = "program_start" case address1 = "address_1" case address2 = "address_2" case city case state case zip } } extension Participant { static var emptyParticipant: Participant = Participant(id: "a", approved: ApprovalStatus.Denied, active: false, firstName: "", lastName: "", dob: Date(), programStart: Date(), address1: "", address2: "", city: "", state: "", zip: "") static let sampleParticipant: Participant = Participant(id: "e", approved: ApprovalStatus.Pending, active: false, firstName: "Sample", lastName: "Participant", dob: Date(), programStart: Date(), address1: "10 Sample Ln", address2: "Apt 10", city: "Las Vegas", state: "NV", zip: "89123") } enum ApprovalStatus: String, Codable{ case Approved = "Approved" case Denied = "Denied" case Pending = "Pending" case All = "All" } struct PortalUser: Hashable, Codable, Identifiable { var id: String var firstName: String var lastName: String var email: String var emailConfirmed: Bool var profileImage: String enum CodingKeys: String, CodingKey { case id = "record_id" case firstName = "first_name" case lastName = "last_name" case email case emailConfirmed = "email_confirmed" case profileImage = "profile_image" } } extension PortalUser { static var emptyUser: PortalUser = PortalUser(id: "", firstName: "Sample", lastName: "User", email: "sample@test.test", emailConfirmed: false, profileImage: "https://picsum.photos/100") } struct ParticipantDetail: View { var participant: Participant var body: some View { VStack(alignment:.leading){ HStack{ Spacer() Text("Date of Birth: ") Text(participant.dob,style: .date) Spacer() } HStack{ Spacer() Text("Program Start Date: ").font(.title3) Text(participant.programStart,style: .date) Spacer() } }.navigationTitle(participant.firstName + " " + participant.lastName) } } struct ParticipantRow: View { var participant: Participant var body: some View { HStack{ Text(participant.firstName + " " + participant.lastName) Spacer() if participant.approved == ApprovalStatus.Approved{ Image(systemName: "person.crop.circle.badge.checkmark") .padding(.trailing,20) .foregroundColor(.teal) } else if participant.approved == ApprovalStatus.Pending{ Image(systemName: "list.clipboard") .padding(.trailing,20) .foregroundColor(.yellow) } else{ Image(systemName: "checkmark.circle.badge.xmark") .padding(.trailing,20) .foregroundColor(.red) } } } } extension ContentView { @ToolbarContentBuilder func toolbarContent() -> some ToolbarContent { ToolbarItem(placement: .navigationBarLeading){ SidebarButton{ isSidebarOpened.toggle() } } } } struct SidebarButton: View { var action: () -> Void = {} var body: some View { Button(action: action) { Image(systemName: "menucard") .symbolRenderingMode(.monochrome) .foregroundColor(.primary) } } } struct Sidebar: View { @Binding var isSidebarVisible: Bool var sidebarWidth = UIScreen.main.bounds.size.width * 0.7 var bgColor: Color = Color(.init(red:200/255,green:200/255,blue:200/255,alpha:1)) /*var participantListViewModel: ParticipantListViewModel var portalUserViewModel: PortalUserViewModel*/ var participants: [Participant] var portalUser: PortalUser var body: some View { ZStack { GeometryReader { _ in EmptyView() } .background(.black.opacity(0.6)) .opacity(isSidebarVisible ? 1 : 0) .animation(.easeInOut.delay(0.2), value: isSidebarVisible) .onTapGesture { isSidebarVisible.toggle() } SidebarContent( bgColor: bgColor, isSidebarVisible: isSidebarVisible, sidebarWidth: sidebarWidth, /*participantListViewModel: participantListViewModel, portalUserViewModel: portalUserViewModel*/ participants: participants, portalUser: portalUser ).zIndex(200) } .edgesIgnoringSafeArea(.all) .zIndex(160) } } struct SidebarContent: View { var bgColor: Color var isSidebarVisible: Bool var sidebarWidth: CGFloat /*var participantListViewModel: ParticipantListViewModel var portalUserViewModel: PortalUserViewModel*/ var participants: [Participant] var portalUser: PortalUser var body: some View { HStack(alignment: .top) { ZStack(alignment: .top) { bgColor List{ VStack(alignment: .leading, spacing: 20) { UserProfile( imgURL: portalUser.profileImage, firstName: portalUser.firstName, lastName: portalUser.lastName, email: portalUser.email ) } .padding(.top, 30) .padding(.horizontal, 10) VStack { NavigationLink{ EnrollParticipantScreen() }label:{ Text("EnrollParticipant") } } HStack { Text("Logout") Spacer() } /*.onTapGesture { participantListViewModel.logout() }*/ } } .frame(width: sidebarWidth) .offset(x: isSidebarVisible ? 0 : -sidebarWidth) .animation(.default, value: isSidebarVisible) Spacer() } } } struct UserProfile: View { var imgURL: String var firstName: String var lastName: String var email: String var body: some View { VStack(alignment: .leading) { HStack { AsyncImage( url: URL( string: imgURL)) { image in image .resizable() .frame(width: 50, height: 50, alignment: .center) .clipShape(Circle()) .overlay { Circle().stroke(.blue, lineWidth: 2) } } placeholder: { ProgressView() } .aspectRatio(3 / 2, contentMode: .fill) .shadow(radius: 4) .padding(.trailing, 18) VStack(alignment: .leading, spacing: 6) { Text("\(firstName) \(lastName)") .foregroundColor(.primary) .bold() .font(.title3) Text(verbatim: "\(email)") .foregroundColor(.secondary) .font(.caption) } } .padding(.bottom, 20) } } } struct EnrollParticipantScreen: View { var body: some View { Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/) } }