Replace PostHog integration with AnalyticsManager architecture
Remove old PostHogAnalytics singleton and replace with guide-based two-file architecture: AnalyticsManager (singleton wrapper with super properties, session replay, opt-out, subscription funnel) and AnalyticsEvent (type-safe enum with associated values). Key changes: - New API key, self-hosted analytics endpoint - All 19 events ported to type-safe AnalyticsEvent enum - Screen tracking via AnalyticsManager.Screen enum + SwiftUI modifier - Remove all identify() calls — fully anonymous analytics - Add lifecycle hooks: flush on background, update super properties on foreground - Add privacy opt-out toggle in Settings - Subscription funnel methods ready for IAP integration Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -73,12 +73,12 @@ class DocumentViewModelWrapper: ObservableObject {
|
||||
Task {
|
||||
do {
|
||||
let result = try await APILayer.shared.getDocuments(
|
||||
residenceId: residenceId != nil ? KotlinInt(int: residenceId!) : nil,
|
||||
residenceId: residenceId.asKotlin,
|
||||
documentType: documentType,
|
||||
category: category,
|
||||
contractorId: contractorId != nil ? KotlinInt(int: contractorId!) : nil,
|
||||
isActive: isActive != nil ? KotlinBoolean(bool: isActive!) : nil,
|
||||
expiringSoon: expiringSoon != nil ? KotlinInt(int: expiringSoon!) : nil,
|
||||
contractorId: contractorId.asKotlin,
|
||||
isActive: isActive.asKotlin,
|
||||
expiringSoon: expiringSoon.asKotlin,
|
||||
tags: tags,
|
||||
search: search,
|
||||
forceRefresh: false
|
||||
@@ -88,8 +88,10 @@ class DocumentViewModelWrapper: ObservableObject {
|
||||
if let success = result as? ApiResultSuccess<NSArray> {
|
||||
let documents = success.data as? [Document] ?? []
|
||||
self.documentsState = DocumentStateSuccess(documents: documents)
|
||||
} else if let error = result as? ApiResultError {
|
||||
} else if let error = ApiResultBridge.error(from: result) {
|
||||
self.documentsState = DocumentStateError(message: error.message)
|
||||
} else {
|
||||
self.documentsState = DocumentStateError(message: "Failed to load documents")
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
@@ -112,8 +114,10 @@ class DocumentViewModelWrapper: ObservableObject {
|
||||
await MainActor.run {
|
||||
if let success = result as? ApiResultSuccess<Document>, let document = success.data {
|
||||
self.documentDetailState = DocumentDetailStateSuccess(document: document)
|
||||
} else if let error = result as? ApiResultError {
|
||||
} else if let error = ApiResultBridge.error(from: result) {
|
||||
self.documentDetailState = DocumentDetailStateError(message: error.message)
|
||||
} else {
|
||||
self.documentDetailState = DocumentDetailStateError(message: "Failed to load document")
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
@@ -179,8 +183,10 @@ class DocumentViewModelWrapper: ObservableObject {
|
||||
self.updateState = UpdateStateSuccess(document: document)
|
||||
// Also refresh the detail state
|
||||
self.documentDetailState = DocumentDetailStateSuccess(document: document)
|
||||
} else if let error = result as? ApiResultError {
|
||||
} else if let error = ApiResultBridge.error(from: result) {
|
||||
self.updateState = UpdateStateError(message: error.message)
|
||||
} else {
|
||||
self.updateState = UpdateStateError(message: "Failed to update document")
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
@@ -203,8 +209,10 @@ class DocumentViewModelWrapper: ObservableObject {
|
||||
await MainActor.run {
|
||||
if result is ApiResultSuccess<KotlinUnit> {
|
||||
self.deleteState = DeleteStateSuccess()
|
||||
} else if let error = result as? ApiResultError {
|
||||
} else if let error = ApiResultBridge.error(from: result) {
|
||||
self.deleteState = DeleteStateError(message: error.message)
|
||||
} else {
|
||||
self.deleteState = DeleteStateError(message: "Failed to delete document")
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
@@ -239,8 +247,10 @@ class DocumentViewModelWrapper: ObservableObject {
|
||||
await MainActor.run {
|
||||
if result is ApiResultSuccess<KotlinUnit> {
|
||||
self.deleteImageState = DeleteImageStateSuccess()
|
||||
} else if let error = result as? ApiResultError {
|
||||
} else if let error = ApiResultBridge.error(from: result) {
|
||||
self.deleteImageState = DeleteImageStateError(message: error.message)
|
||||
} else {
|
||||
self.deleteImageState = DeleteImageStateError(message: "Failed to delete image")
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
|
||||
Reference in New Issue
Block a user