added paging

Signed-off-by: Matt Bruce <mbrucedogs@gmail.com>
This commit is contained in:
Matt Bruce 2025-01-21 11:49:09 -06:00
parent 427e862b6b
commit 7e0c2fd310
2 changed files with 75 additions and 21 deletions

View File

@ -31,6 +31,9 @@ class EmployeesViewController: UIViewController {
/// Will show specific state of the viewModel
private var footerView: TableFooterView?
// Prevents multiple calls during rapid scrolling
private var isFetchingNextPage: Bool = false
// MARK: - Public Methods
public override func viewDidLoad() {
@ -49,6 +52,7 @@ class EmployeesViewController: UIViewController {
// Configure TableView
tableView.register(EmployeeTableViewCell.self, forCellReuseIdentifier: EmployeeTableViewCell.identifier)
tableView.dataSource = self
tableView.delegate = self
view.addSubview(tableView)
tableView.frame = view.bounds
@ -98,26 +102,55 @@ class EmployeesViewController: UIViewController {
/// Show state in specific use-cases for the EmployeesViewModel
private func updateFooter() {
var message: String? {
guard !viewModel.isLoading else { return nil }
return viewModel.errorMessage ?? (viewModel.employees.isEmpty ? "No employees found, please try to refresh." : nil)
var footerMessage: String?
// Check for error messages or empty state first
if let message = viewModel.errorMessage ?? (viewModel.employees.isEmpty && !viewModel.isLoading ? "No employees found, please try to refresh." : nil) {
footerMessage = message
}
// Show loading footer if there are more pages to load
else if (viewModel.isLoading || isFetchingNextPage) && viewModel.hasMorePages {
footerMessage = "Loading more employees..."
}
if let message, !viewModel.isLoading {
if let footerMessage {
// Lazy initialize footerView if needed
if footerView == nil {
footerView = TableFooterView(message: message)
} else { // Update the message
footerView?.update(message: message)
footerView = TableFooterView(message: footerMessage)
} else {
footerView?.update(message: footerMessage)
}
footerView?.frame = CGRect(x: 0, y: 0, width: tableView.frame.width, height: 150)
tableView.tableFooterView = footerView
} else {
tableView.tableFooterView = nil
}
}
}
// MARK: - UITableViewDelegate
extension EmployeesViewController: UITableViewDelegate {
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let offsetY = scrollView.contentOffset.y
let contentHeight = scrollView.contentSize.height
let scrollViewHeight = scrollView.frame.size.height
if offsetY > contentHeight - scrollViewHeight - 100 && !isFetchingNextPage {
isFetchingNextPage = true
updateFooter()
viewModel.loadNextPage()
// Reset the flag after a short delay to allow new fetches
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { [weak self] in
self?.isFetchingNextPage = false
}
}
}
}
// Mark: - Objective-C Methods
extension EmployeesViewController {

View File

@ -16,36 +16,57 @@ public class EmployeesViewModel: ObservableObject {
@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
private var currentPage = 1
private let perPage = 10
private var totalEmployees = 0
public init() {}
public func fetchEmployees() {
// resetting values out the values before fetching new data
errorMessage = nil
/// 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 async method
let wrapper = try await EmployeeService.shared.getEmployees(serviceMode)
// Fetch employees using the paginated API
let wrapper = try await MockEmployeeService.shared.getEmployees(.empty ,page: page, perPage: perPage)
// Update published properties
employees = wrapper.employees
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
employees = []
isLoading = false
errorMessage = "An unexpected error occurred, please try to refresh"
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
fetchEmployees()
currentPage = 1
employees = []
hasMorePages = true
fetchEmployees(page: 1)
}
}