Using NotificationCenter to Pull UIViewController Up After Sending FCMessage

22 Views Asked by At

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
    }

}
0

There are 0 best solutions below