2026-07-07 22:53:20 +03:00
|
|
|
import Foundation
|
|
|
|
|
|
|
|
|
|
/// Deep links into the Analytics area — used by weekly/monthly report
|
|
|
|
|
/// notifications to route straight to the relevant report. Pure value type with
|
|
|
|
|
/// symmetric URL encode/decode so routing is testable without any UI.
|
|
|
|
|
///
|
|
|
|
|
/// Format: wenza://analytics → overview
|
|
|
|
|
/// wenza://analytics/weekly/<yyyy-MM-dd> → a weekly report
|
|
|
|
|
/// wenza://analytics/monthly/<yyyy-MM> → a monthly report
|
2026-07-07 23:36:45 +03:00
|
|
|
enum AnalyticsDeepLink: Equatable, Identifiable {
|
2026-07-07 22:53:20 +03:00
|
|
|
case overview
|
|
|
|
|
case weekly(weekStartKey: String)
|
|
|
|
|
case monthly(monthKey: String)
|
|
|
|
|
|
|
|
|
|
static let scheme = "wenza"
|
|
|
|
|
static let host = "analytics"
|
|
|
|
|
|
2026-07-07 23:36:45 +03:00
|
|
|
var id: String { stringValue }
|
|
|
|
|
|
2026-07-07 22:53:20 +03:00
|
|
|
/// Stable userInfo key carried on notifications.
|
|
|
|
|
static let userInfoKey = "kisani.analytics.deeplink"
|
|
|
|
|
|
|
|
|
|
var url: URL {
|
|
|
|
|
var c = URLComponents()
|
|
|
|
|
c.scheme = Self.scheme
|
|
|
|
|
c.host = Self.host
|
|
|
|
|
switch self {
|
|
|
|
|
case .overview: c.path = ""
|
|
|
|
|
case .weekly(let key): c.path = "/weekly/\(key)"
|
|
|
|
|
case .monthly(let key): c.path = "/monthly/\(key)"
|
|
|
|
|
}
|
|
|
|
|
return c.url!
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
init?(url: URL) {
|
|
|
|
|
guard url.scheme == Self.scheme, url.host == Self.host else { return nil }
|
|
|
|
|
let parts = url.path.split(separator: "/").map(String.init)
|
|
|
|
|
switch parts.first {
|
|
|
|
|
case nil:
|
|
|
|
|
self = .overview
|
|
|
|
|
case "weekly":
|
|
|
|
|
guard parts.count >= 2 else { return nil }
|
|
|
|
|
self = .weekly(weekStartKey: parts[1])
|
|
|
|
|
case "monthly":
|
|
|
|
|
guard parts.count >= 2 else { return nil }
|
|
|
|
|
self = .monthly(monthKey: parts[1])
|
|
|
|
|
default:
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Build/parse via a plain string (for notification userInfo payloads).
|
|
|
|
|
var stringValue: String { url.absoluteString }
|
|
|
|
|
init?(string: String) {
|
|
|
|
|
guard let url = URL(string: string) else { return nil }
|
|
|
|
|
self.init(url: url)
|
|
|
|
|
}
|
|
|
|
|
}
|