I'm trying to make it to where when a customer finds an available employee, they will send the employee a FCMessage through FindEmployeeJobRequestController using the matched employee's fcmToken, which I can achieve. Now I'm trying to pass the FCMessage into a NotificationCenter.default.post() so the employee can get the CustomerJobRequestController pulled up so they can accept or deny the job request. Right now I'm having trouble pulling up FindEmployeeJobRequestController when I add NotificationCenter.default.post(name: .didSendJobRequestNotification, object: nil) to my function findMatchingEmployee(). Do you have any tips to achieve this? Do I ned to only use NotificationCenter? Thanks!
// Service
// MARK: - CustomerService
struct CustomerService {
static func sendJobRequestNotification(to employee: Employee, jobRequest: JobRequest) {
let fcm = FCMService()
let timestampString = "\(jobRequest.timestamp.dateValue())"
let jobPayload: [String: Any] = [
"customerUid": jobRequest.customerUid ?? "",
"employeeUid": jobRequest.employeeUid ?? "",
"state": jobRequest.state?.rawValue ?? JobRequestState.requested.rawValue,
"fullname": jobRequest.fullname,
"username": jobRequest.username,
"profileImageUrl": jobRequest.profileImageUrl,
"businessName": jobRequest.businessName,
"businessId": jobRequest.businessId,
"address": jobRequest.address,
"firstDateAndTimes": jobRequest.firstDateAndTimes,
"secondDateAndTimes": jobRequest.secondDateAndTimes,
"thirdDateAndTimes": jobRequest.thirdDateAndTimes,
"timeConstraints": jobRequest.timeConstraints,
"jobDescription": jobRequest.jobDescription,
"timestamp": timestampString
]
fcm.sendNotification(to: employee.fcmToken, payload: jobPayload)
}
}
// FindEmployeeJobRequestController
class FindEmployeeJobRequestController: UIViewController {
// MARK: - Properties
deinit {
NotificationCenter.default.removeObserver(self)
}
// MARK: - Lifecycle
init(jobRequest: JobRequest) {
self.jobRequest = jobRequest
super.init(nibName: nil, bundle: nil)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
findMatchingEmployee()
}
// MARK: - API
func findMatchingEmployee() {
CustomerService.findMatchingEmployee(for: jobRequest) { employee in
if let employee = employee {
CustomerService.sendJobRequestNotification(to: employee, jobRequest: self.jobRequest)
NotificationCenter.default.post(name: .didSendJobRequestNotification, object: nil)
} else {
self.simpleAlert(title: "Alert", msg: "Failed to send to employee.")
}
}
}
}
extension Notification.Name {
static let didSendJobRequestNotification = Notification.Name("didSendJobRequestNotification")
static let didReceiveJobRequestNotification = Notification.Name("didReceiveJobRequestNotification")
}
// Employee AppDelegate
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
window = UIWindow(frame: UIScreen.main.bounds)
let navController = UINavigationController()
window?.rootViewController = navController
let rootViewController = ViewController()
navController.viewControllers = [rootViewController]
window?.makeKeyAndVisible()
FirebaseApp.configure()
UNUserNotificationCenter.current().delegate = self
UNUserNotificationCenter.current().delegate = self
let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
UNUserNotificationCenter.current().requestAuthorization(
options: authOptions,
completionHandler: {_, _ in })
application.registerForRemoteNotifications()
Messaging.messaging().delegate = self
Messaging.messaging().isAutoInitEnabled = true
return true
}
func application(_ application: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
Messaging.messaging().apnsToken = deviceToken
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any]) {
if let isJobRequestNotification = userInfo["isJobRequestNotification"] as? Bool, isJobRequestNotification {
NotificationCenter.default.post(name: .didSendJobRequestNotification, object: nil)
handleNotificationData(userInfo)
presentCustomerJobRequestController(with: userInfo)
}
}
}
// MARK: - UNUserNotificationCenterDelegate
extension AppDelegate: UNUserNotificationCenterDelegate {
func userNotificationCenter(_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
let userInfo = notification.request.content.userInfo
handleNotificationData(userInfo)
completionHandler([[.badge, .banner, .sound]])
}
func userNotificationCenter(_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler: @escaping () -> Void) {
let userInfo = response.notification.request.content.userInfo
handleNotificationData(userInfo)
completionHandler()
}
private func handleNotificationData(_ data: [AnyHashable: Any]) {
if let jobRequestData = data as? [String: Any],
let jobRequest = JobRequest(dictionary: jobRequestData) {
DispatchQueue.main.async {
let controller = self.findOrCreateCustomerJobRequestController()
controller.updateWithJobRequest(request: jobRequest)
self.presentController(controller)
}
}
}
func presentController(_ controller: UIViewController) {
// Assuming `window` is your main application window
if let rootVC = window?.rootViewController {
var currentVC = rootVC
// Find the topmost view controller
while let presentedVC = currentVC.presentedViewController {
currentVC = presentedVC
}
// Present the controller
currentVC.present(controller, animated: true, completion: nil)
}
}
func presentCustomerJobRequestController(with userInfo: [AnyHashable: Any]) {
DispatchQueue.main.async { [weak self] in
guard let strongSelf = self else { return }
let customerJobRequestVC = strongSelf.findOrCreateCustomerJobRequestController()
strongSelf.presentController(customerJobRequestVC)
}
}
func findOrCreateCustomerJobRequestController() -> CustomerJobRequestController {
if let existing = customerJobRequestController {
return existing
}
let newController = CustomerJobRequestController()
customerJobRequestController = newController
return newController
}
}
// MARK: - MessagingDelegate
extension AppDelegate: MessagingDelegate {
func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) {
print("Firebase registration token: \(String(describing: fcmToken))")
let dataDict: [String: String] = ["token": fcmToken ?? ""]
NotificationCenter.default.post(
name: Notification.Name("FCMToken"),
object: nil,
userInfo: dataDict
)
UserDefaults.standard.setValue(fcmToken, forKey: "fcmToken")
UserDefaults.standard.synchronize()
}
}
// CustomerJobRequestController
class CustomerJobRequestController: UIViewController {
// MARK: - Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self,
selector: #selector(handleJobRequestNotification),
name: .didReceiveJobRequestNotification,
object: nil)
}
// MARK: - Selectors
@objc func handleJobRequestNotification(_ notification: Notification) {
guard let jobRequestData = notification.userInfo as? [String : Any] else { return }
guard let jobRequest = JobRequest(dictionary: jobRequestData) else { return }
presentCustomerJobRequestController(with: jobRequest)
}
// MARK: - Helper Functions
func updateWithJobRequest(request: JobRequest) {
self.jobRequest = request
}
}