added search

Signed-off-by: Matt Bruce <mbrucedogs@gmail.com>
This commit is contained in:
Matt Bruce 2025-03-17 09:17:34 -05:00
parent 0e138544a7
commit d4a98106a3

View File

@ -29,37 +29,29 @@ public struct EmployeeDirectoryList: View {
@State public var path = NavigationPath() @State public var path = NavigationPath()
@State private var selectedEmployees = Set<Employee.ID>() @State private var selectedEmployees = Set<Employee.ID>()
@State private var editMode: EditMode = .inactive @State private var editMode: EditMode = .inactive
@State private var searchText = ""
init(viewModel: EmployeesViewModel? = nil) { init(viewModel: EmployeesViewModel? = nil) {
_viewModel = .init(wrappedValue: viewModel ?? .init(service: EmployeeService())) _viewModel = .init(wrappedValue: viewModel ?? .init(service: EmployeeService()))
} }
var filteredEmployees: [Employee] {
if searchText.isEmpty {
return viewModel.employees
} else {
return viewModel.employees.filter { employee in
employee.firstName.lowercased().contains(searchText.lowercased()) ||
employee.lastName.lowercased().contains(searchText.lowercased())
}
}
}
public var body: some View { public var body: some View {
NavigationStack(path: $path) { NavigationStack(path: $path) {
List(selection: $selectedEmployees) { List(selection: $selectedEmployees) {
ForEach(viewModel.employees, id: \.id) { employee in ForEach(filteredEmployees, id: \.id) { employee in
let employeeViewModel = EmployeeViewModel(employee: employee) let employeeViewModel = EmployeeViewModel(employee: employee)
HStack(spacing: 10) { EmployeeListItem(employeeViewModel: employeeViewModel)
ProfileImageView(urlString: employeeViewModel.smallPhoto, size: 51)
VStack(alignment: .leading, spacing: 5) {
Text(employeeViewModel.fullName)
.font(.headline)
if let bio = employeeViewModel.biography {
Text(bio)
.font(.footnote)
.foregroundColor(.gray)
.lineLimit(2)
}
Label("Email: \(employeeViewModel.emailAddress)", systemImage: "envelope.fill")
.foregroundColor(.gray)
.font(.caption)
if let phoneNumber = employeeViewModel.phoneNumber {
Label("Call: \(phoneNumber)", systemImage: "phone.fill")
.foregroundColor(.gray)
.font(.caption)
}
}
}
.onTapGesture { .onTapGesture {
if editMode != .active { if editMode != .active {
path.append(employee) path.append(employee)
@ -92,6 +84,7 @@ public struct EmployeeDirectoryList: View {
await viewModel.refresh() await viewModel.refresh()
} }
} }
.searchable(text: $searchText, prompt: "Search employees by name")
.navigationTitle("Employee Directory") .navigationTitle("Employee Directory")
.navigationDestination(for: Employee.self) { employee in .navigationDestination(for: Employee.self) { employee in
EmployeeDetailView(viewModel: .init(employee: employee)) EmployeeDetailView(viewModel: .init(employee: employee))
@ -136,6 +129,40 @@ public struct EmployeeDirectoryList: View {
} }
} }
public struct EmployeeListItem: View {
public let employeeViewModel: EmployeeViewModel
public var body: some View {
HStack(spacing: 10) {
ProfileImageView(urlString: employeeViewModel.smallPhoto, size: 51)
VStack(alignment: .leading, spacing: 5) {
Text(employeeViewModel.fullName)
.font(.headline)
if let bio = employeeViewModel.biography {
Text(bio)
.font(.footnote)
.foregroundColor(.gray)
.lineLimit(2)
}
Label("Email: \(employeeViewModel.emailAddress)", systemImage: "envelope.fill")
.foregroundColor(.gray)
.font(.caption)
if let phoneNumber = employeeViewModel.phoneNumber {
Label("Call: \(phoneNumber)", systemImage: "phone.fill")
.foregroundColor(.gray)
.font(.caption)
}
}
Spacer()
}
.contentShape(Rectangle())
}
}
#Preview("EmployeeListItem") {
EmployeeListItem(employeeViewModel: .init(employee: MockEmployeeService.sample))
}
public struct EmployeeDetailView: View { public struct EmployeeDetailView: View {
public let viewModel: EmployeeViewModel public let viewModel: EmployeeViewModel