Issue #395

Prefer static enum to avoid repetition and error. The Log should have methods with all required fields so the call site is as simple as possible. How to format and assign parameters is encapsulated in this Analytics.

import Foundation
import Firebase
import FirebaseAnalytics

struct Analytics {
    enum Parameter: String {
        case studentId = "student_id"
        case classId = "class_id"
        case url = "url"
    }

    enum Property: String {
        case grantLocation = "grant_location"
    }

    enum Name: String {
        case login
        case logOut = "log_out"
        case enroll
    }

    struct Log {
        private func log(_ name: Name, parameters: [Parameter: String] = [:]) {
            let mapped: [String: String] = Dictionary(uniqueKeysWithValues: parameters.map({ key, value in
                return (key.rawValue, value)
            }))

            FirebaseAnalytics.Analytics.logEvent(name.rawValue, parameters: mapped)
        }

        private func set(userId: String?) {
            FirebaseAnalytics.Analytics.setUserID(userId)
        }

        private func setProperty(_ property: Property, value: String) {
            FirebaseAnalytics.Analytics.setUserProperty(value, forName: property.rawValue)
        }
    }

    let log = Log()
}

extension Analytics.Log {
    func grantLocation(hasGranted: Bool) {
        setProperty(.grantLocation, value: hasGranted.toString())
    }

    func login(userId: String) {
        log(.login)
        set(userId: userId)
    }

    func logOut() {
        log(.logOut)
        set(userId: nil)
    }

    func enroll(classId: String) {
        log(.enroll, parameters: [
            .classId: classId
        ])
    }
}

private extension Bool {
    func toString() -> String {
        return self ? "yes": "no"
    }
}