98 lines
3.4 KiB
Swift
98 lines
3.4 KiB
Swift
//
|
|
// EmployeesViewModel.swift
|
|
// EmployeeDirectory
|
|
//
|
|
// Created by Matt Bruce on 1/20/25.
|
|
//
|
|
|
|
import Foundation
|
|
import Combine
|
|
|
|
/// ViewModel that will be bound to an Employees model and used
|
|
/// specifically with the EmployeesViewController.
|
|
@MainActor
|
|
public class EmployeesViewModel: ObservableObject {
|
|
private var serviceMode: EmployeeServiceMode = .production
|
|
private var employeeService: EmployeeServiceProtocol = EmployeeService.shared
|
|
@Published public private(set) var employees: [Employee] = []
|
|
@Published public private(set) var errorMessage: String? = nil
|
|
@Published public private(set) var isLoading: Bool = false
|
|
@Published public private(set) var hasMorePages: Bool = true
|
|
|
|
@Published public var sortField: EmployeeSortField = .fullName
|
|
@Published public var sortOrder: EmployeeSortOrder = .ascending
|
|
private var cancellables = Set<AnyCancellable>()
|
|
|
|
private var currentPage = 1
|
|
private let perPage = 10
|
|
private var totalEmployees = 0
|
|
|
|
public init() {
|
|
observeSortingChanges()
|
|
}
|
|
|
|
/// Observe changes to sortField and sortOrder and debounce fetch calls
|
|
private func observeSortingChanges() {
|
|
Publishers.CombineLatest($sortField, $sortOrder)
|
|
.debounce(for: .milliseconds(300), scheduler: DispatchQueue.main)
|
|
.sink { [weak self] _, _ in
|
|
self?.resetAndFetchEmployees()
|
|
}
|
|
.store(in: &cancellables)
|
|
}
|
|
|
|
/// Fetch employees for the given page
|
|
public func fetchEmployees(page: Int = 1) {
|
|
// Prevent duplicate calls
|
|
guard !isLoading else { return }
|
|
isLoading = true
|
|
|
|
Task {
|
|
do {
|
|
// Fetch employees using the paginated API
|
|
let wrapper = try await employeeService.getEmployees(serviceMode, page: page,
|
|
perPage: perPage,
|
|
sortField: sortField,
|
|
sortOrder: sortOrder)
|
|
|
|
// Update published properties
|
|
if page == 1 {
|
|
employees = wrapper.employees // Replace list for the first page
|
|
} else {
|
|
employees.append(contentsOf: wrapper.employees) // Append for subsequent pages
|
|
}
|
|
|
|
totalEmployees = wrapper.total
|
|
currentPage = page
|
|
hasMorePages = employees.count < totalEmployees
|
|
isLoading = false
|
|
|
|
} catch {
|
|
// Handle errors
|
|
isLoading = false
|
|
errorMessage = "An unexpected error occurred, please try to refresh."
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Load the next page of employees
|
|
public func loadNextPage() {
|
|
guard hasMorePages else { return }
|
|
fetchEmployees(page: currentPage + 1)
|
|
}
|
|
|
|
/// Change the service mode (e.g., production, malformed, empty)
|
|
public func changeMode(to mode: EmployeeServiceMode) {
|
|
serviceMode = mode
|
|
resetAndFetchEmployees()
|
|
}
|
|
|
|
/// Resets the current employee list and fetches data from page 1
|
|
private func resetAndFetchEmployees() {
|
|
currentPage = 1
|
|
employees = []
|
|
hasMorePages = true
|
|
fetchEmployees(page: 1)
|
|
}
|
|
}
|