Compare commits

...

3 Commits

Author SHA1 Message Date
7b65685d1a added push for the details
Signed-off-by: Matt Bruce <mbrucedogs@gmail.com>
2025-02-06 15:17:57 -06:00
3a9399f076 initial cut for Details VC
Signed-off-by: Matt Bruce <mbrucedogs@gmail.com>
2025-02-06 15:17:38 -06:00
9102f8d3c6 created details viewmodel
Signed-off-by: Matt Bruce <mbrucedogs@gmail.com>
2025-02-06 15:17:20 -06:00
3 changed files with 159 additions and 0 deletions

View File

@ -0,0 +1,99 @@
//
// EmployeeDetailViewController.swift
// EmployeeDirectory
//
// Created by Matt Bruce on 2/6/25.
//
import UIKit
import Combine
public class EmployeeDetailViewController: UIViewController {
private let photoImageView = UIImageView()
private let nameLabel = UILabel()
private let emailLabel = UILabel()
private let teamLabel = UILabel()
private let employeeTypeLabel = UILabel()
private let phoneLabel = UILabel()
private let bioLabel = UILabel()
private let stackView = UIStackView()
private let scrollView = UIScrollView()
/// Used for grabbing the photo
private var largerPhotoSubscriber: AnyCancellable?
public var viewModel: EmployeeDetailViewModel?
public override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
// default image
photoImageView.image = UIImage(systemName: "person.crop.circle")
photoImageView.contentMode = .scaleAspectFit
// Configure stackView
stackView.axis = .vertical
stackView.spacing = 5
stackView.alignment = .top
stackView.distribution = .fill
stackView.translatesAutoresizingMaskIntoConstraints = false
// Add labels to stackView
stackView.addArrangedSubview(photoImageView)
stackView.addArrangedSubview(nameLabel)
stackView.addArrangedSubview(teamLabel)
stackView.addArrangedSubview(employeeTypeLabel)
stackView.addArrangedSubview(phoneLabel)
stackView.addArrangedSubview(emailLabel)
stackView.addArrangedSubview(bioLabel)
view.addSubview(stackView)
photoImageView.heightAnchor.constraint(equalToConstant: 200).isActive = true
photoImageView.widthAnchor.constraint(equalToConstant: 200).isActive = true
stackView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
stackView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor).isActive = true
stackView.leftAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leftAnchor, constant: 10).isActive = true
stackView.rightAnchor.constraint(equalTo: view.safeAreaLayoutGuide.rightAnchor, constant: -10).isActive = true
// Bind the image to the photoImageView
largerPhotoSubscriber = viewModel?.$largePhoto
.compactMap { $0 }
.receive(on: DispatchQueue.main)
.sink { [weak self] image in
self?.photoImageView.image = image
}
if let viewModel {
// Bind data to UI components
nameLabel.text = viewModel.fullName
emailLabel.text = viewModel.emailAddress
teamLabel.text = viewModel.team
employeeTypeLabel.text = viewModel.employeeType
phoneLabel.text = viewModel.phoneNumber
bioLabel.text = viewModel.biography
// Dynamically show or hide elements based on their content
phoneLabel.isHidden = viewModel.phoneNumber == nil
bioLabel.isHidden = viewModel.biography == nil
}
let phoneTap = UITapGestureRecognizer(target: self, action: #selector(didTapPhoneView(_:)))
phoneLabel.isUserInteractionEnabled = true
phoneLabel.addGestureRecognizer(phoneTap)
}
@objc func didTapPhoneView(_ sender: UITapGestureRecognizer) {
guard let phoneNumber = viewModel?.phoneNumber?.filter({ $0.isNumber }) else {
print("phone not there")
return
}
let numberUrl = URL(string: "tel://\(phoneNumber)")!
if UIApplication.shared.canOpenURL(numberUrl) {
UIApplication.shared.open(numberUrl)
}
print("print", phoneNumber)
}
}

View File

@ -73,6 +73,7 @@ class EmployeesViewController: UIViewController {
tableView.register(EmployeeTableViewCell.self, forCellReuseIdentifier: EmployeeTableViewCell.identifier)
view.addSubview(tableView)
tableView.frame = view.bounds
tableView.delegate = self
//add pull to refresh
tableView.refreshControl = UIRefreshControl()
@ -140,6 +141,15 @@ class EmployeesViewController: UIViewController {
}
}
extension EmployeesViewController: UITableViewDelegate{
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let employee = viewModel.employees[indexPath.row]
let details = EmployeeDetailViewController()
details.viewModel = .init(employee: employee)
navigationController?.pushViewController(details, animated: true)
}
}
// Mark: - Objective-C Methods
extension EmployeesViewController {

View File

@ -0,0 +1,50 @@
//
// EmployeeDetailsViewModel.swift
// EmployeeDirectory
//
// Created by Matt Bruce on 2/6/25.
//
import Foundation
import UIKit
/// ViewModel that will be used along with the EmployeeTableViewCell.
@MainActor
public class EmployeeDetailViewModel: ObservableObject {
// MARK: - Properties
private let employee: Employee
public private(set) var uuid: String
public private(set) var fullName: String
public private(set) var phoneNumber: String?
public private(set) var emailAddress: String
public private(set) var biography: String?
public private(set) var team: String
public private(set) var employeeType: String
@Published public private(set) var largePhoto: UIImage?
// MARK: - Initializer
public init(employee: Employee) {
self.employee = employee
// Initialize properties
uuid = employee.uuid.uuidString
fullName = employee.fullName
phoneNumber = employee.phoneNumber?.formatUSNumber()
emailAddress = employee.emailAddress
biography = employee.biography
team = employee.team
employeeType = employee.employeeType.description
// Fetch the image for the url if it exists
if let endpoint = employee.photoURLLarge {
Task{
if let photoURL = URL(string: endpoint) {
largePhoto = await ImageCacheService.shared.loadImage(from: photoURL)
}
}
}
}
}