Refactor iOS forms and integrate notification API with APILayer
- Refactored ContractorFormSheet to follow SwiftUI best practices - Moved Field enum outside struct and renamed to ContractorFormField - Extracted body into computed properties for better readability - Replaced deprecated NavigationView with NavigationStack - Fixed input field contrast in light mode by adding borders - Fixed force cast in loadContractorSpecialties - Refactored TaskFormView to eliminate screen flickering - Moved Field enum outside struct and renamed to TaskFormField - Fixed conditional view structure that caused flicker on load - Used ZStack with overlay instead of if/else for loading state - Changed to .task modifier for proper async initialization - Made loadLookups properly async and fixed force casts - Replaced deprecated NavigationView with NavigationStack - Integrated PushNotificationManager with APILayer - Updated registerDeviceWithBackend to use APILayer.shared.registerDevice() - Updated updateNotificationPreferences to use APILayer - Updated getNotificationPreferences to use APILayer - Added proper error handling with try-catch pattern - Added notification operations to APILayer - Added NotificationApi instance - Implemented registerDevice, unregisterDevice - Implemented getNotificationPreferences, updateNotificationPreferences - Implemented getNotificationHistory, markNotificationAsRead - Implemented markAllNotificationsAsRead, getUnreadCount - All methods follow consistent pattern with auth token handling 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
import UserNotifications
|
||||
import ComposeApp
|
||||
|
||||
@@ -8,8 +9,6 @@ class PushNotificationManager: NSObject, ObservableObject {
|
||||
@Published var deviceToken: String?
|
||||
@Published var notificationPermissionGranted = false
|
||||
|
||||
// private let notificationApi = NotificationApi()
|
||||
|
||||
override init() {
|
||||
super.init()
|
||||
}
|
||||
@@ -19,26 +18,25 @@ class PushNotificationManager: NSObject, ObservableObject {
|
||||
func requestNotificationPermission() async -> Bool {
|
||||
let center = UNUserNotificationCenter.current()
|
||||
|
||||
// do {
|
||||
// let granted = try await center.requestAuthorization(options: [.alert, .sound, .badge])
|
||||
// notificationPermissionGranted = granted
|
||||
//
|
||||
// if granted {
|
||||
// print("✅ Notification permission granted")
|
||||
// // Register for remote notifications on main thread
|
||||
// await MainActor.run {
|
||||
// UIApplication.shared.registerForRemoteNotifications()
|
||||
// }
|
||||
// } else {
|
||||
// print("❌ Notification permission denied")
|
||||
// }
|
||||
//
|
||||
// return granted
|
||||
// } catch {
|
||||
// print("❌ Error requesting notification permission: \(error)")
|
||||
// return false
|
||||
// }
|
||||
return true
|
||||
do {
|
||||
let granted = try await center.requestAuthorization(options: [.alert, .sound, .badge])
|
||||
notificationPermissionGranted = granted
|
||||
|
||||
if granted {
|
||||
print("✅ Notification permission granted")
|
||||
// Register for remote notifications on main thread
|
||||
await MainActor.run {
|
||||
UIApplication.shared.registerForRemoteNotifications()
|
||||
}
|
||||
} else {
|
||||
print("❌ Notification permission denied")
|
||||
}
|
||||
|
||||
return granted
|
||||
} catch {
|
||||
print("❌ Error requesting notification permission: \(error)")
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Token Management
|
||||
@@ -61,26 +59,29 @@ class PushNotificationManager: NSObject, ObservableObject {
|
||||
// MARK: - Backend Registration
|
||||
|
||||
private func registerDeviceWithBackend(token: String) async {
|
||||
guard let authToken = TokenStorage.shared.getToken() else {
|
||||
guard TokenStorage.shared.getToken() != nil else {
|
||||
print("⚠️ No auth token available, will register device after login")
|
||||
return
|
||||
}
|
||||
|
||||
// let request = DeviceRegistrationRequest(
|
||||
// registrationId: token,
|
||||
// platform: "ios"
|
||||
// )
|
||||
//
|
||||
// let result = await notificationApi.registerDevice(token: authToken, request: request)
|
||||
//
|
||||
// switch result {
|
||||
// case let success as ApiResultSuccess<DeviceRegistrationResponse>:
|
||||
// print("✅ Device registered successfully: \(success.data)")
|
||||
// case let error as ApiResultError:
|
||||
// print("❌ Failed to register device: \(error.message)")
|
||||
// default:
|
||||
// print("⚠️ Unexpected result type from device registration")
|
||||
// }
|
||||
let request = DeviceRegistrationRequest(
|
||||
registrationId: token,
|
||||
platform: "ios"
|
||||
)
|
||||
|
||||
do {
|
||||
let result = try await APILayer.shared.registerDevice(request: request)
|
||||
|
||||
if let success = result as? ApiResultSuccess<DeviceRegistrationResponse> {
|
||||
print("✅ Device registered successfully: \(success.data)")
|
||||
} else if let error = result as? ApiResultError {
|
||||
print("❌ Failed to register device: \(error.message)")
|
||||
} else {
|
||||
print("⚠️ Unexpected result type from device registration")
|
||||
}
|
||||
} catch {
|
||||
print("❌ Error registering device: \(error.localizedDescription)")
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Handle Notifications
|
||||
@@ -92,10 +93,10 @@ class PushNotificationManager: NSObject, ObservableObject {
|
||||
if let notificationId = userInfo["notification_id"] as? String {
|
||||
print("Notification ID: \(notificationId)")
|
||||
|
||||
// Mark as read when user taps notification
|
||||
Task {
|
||||
await markNotificationAsRead(notificationId: notificationId)
|
||||
}
|
||||
// // Mark as read when user taps notification
|
||||
// Task {
|
||||
// await markNotificationAsRead(notificationId: notificationId)
|
||||
// }
|
||||
}
|
||||
|
||||
if let type = userInfo["type"] as? String {
|
||||
@@ -129,80 +130,79 @@ class PushNotificationManager: NSObject, ObservableObject {
|
||||
}
|
||||
}
|
||||
|
||||
private func markNotificationAsRead(notificationId: String) async {
|
||||
guard let authToken = TokenStorage.shared.getToken(),
|
||||
let notificationIdInt = Int32(notificationId) else {
|
||||
return
|
||||
}
|
||||
|
||||
// let result = await notificationApi.markNotificationAsRead(
|
||||
// token: authToken,
|
||||
// notificationId: notificationIdInt
|
||||
// )
|
||||
//
|
||||
// switch result {
|
||||
// case is ApiResultSuccess<Notification>:
|
||||
// print("✅ Notification marked as read")
|
||||
// case let error as ApiResultError:
|
||||
// print("❌ Failed to mark notification as read: \(error.message)")
|
||||
// default:
|
||||
// break
|
||||
// private func markNotificationAsRead(notificationId: String) async {
|
||||
// guard TokenStorage.shared.getToken() != nil,
|
||||
// let notificationIdInt = Int32(notificationId) else {
|
||||
// return
|
||||
// }
|
||||
}
|
||||
//
|
||||
// do {
|
||||
// let result = try await APILayer.shared.markNotificationAsRead(notificationId: notificationIdInt)
|
||||
//
|
||||
// if result is ApiResultSuccess<Notification> {
|
||||
// print("✅ Notification marked as read")
|
||||
// } else if let error = result as? ApiResultError {
|
||||
// print("❌ Failed to mark notification as read: \(error.message)")
|
||||
// }
|
||||
// } catch {
|
||||
// print("❌ Error marking notification as read: \(error.localizedDescription)")
|
||||
// }
|
||||
// }
|
||||
|
||||
// MARK: - Notification Preferences
|
||||
|
||||
func updateNotificationPreferences(_ preferences: UpdateNotificationPreferencesRequest) async -> Bool {
|
||||
guard let authToken = TokenStorage.shared.getToken() else {
|
||||
guard TokenStorage.shared.getToken() != nil else {
|
||||
print("⚠️ No auth token available")
|
||||
return false
|
||||
}
|
||||
|
||||
// let result = await notificationApi.updateNotificationPreferences(
|
||||
// token: authToken,
|
||||
// request: preferences
|
||||
// )
|
||||
//
|
||||
// switch result {
|
||||
// case is ApiResultSuccess<NotificationPreference>:
|
||||
// print("✅ Notification preferences updated")
|
||||
// return true
|
||||
// case let error as ApiResultError:
|
||||
// print("❌ Failed to update preferences: \(error.message)")
|
||||
// return false
|
||||
// default:
|
||||
// return false
|
||||
// }
|
||||
return false
|
||||
do {
|
||||
let result = try await APILayer.shared.updateNotificationPreferences(request: preferences)
|
||||
|
||||
if result is ApiResultSuccess<NotificationPreference> {
|
||||
print("✅ Notification preferences updated")
|
||||
return true
|
||||
} else if let error = result as? ApiResultError {
|
||||
print("❌ Failed to update preferences: \(error.message)")
|
||||
return false
|
||||
}
|
||||
return false
|
||||
} catch {
|
||||
print("❌ Error updating notification preferences: \(error.localizedDescription)")
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func getNotificationPreferences() async -> NotificationPreference? {
|
||||
guard let authToken = TokenStorage.shared.getToken() else {
|
||||
guard TokenStorage.shared.getToken() != nil else {
|
||||
print("⚠️ No auth token available")
|
||||
return nil
|
||||
}
|
||||
|
||||
// let result = await notificationApi.getNotificationPreferences(token: authToken)
|
||||
//
|
||||
// switch result {
|
||||
// case let success as ApiResultSuccess<NotificationPreference>:
|
||||
// return success.data
|
||||
// case let error as ApiResultError:
|
||||
// print("❌ Failed to get preferences: \(error.message)")
|
||||
// return nil
|
||||
// default:
|
||||
// return nil
|
||||
// }
|
||||
return nil
|
||||
do {
|
||||
let result = try await APILayer.shared.getNotificationPreferences()
|
||||
|
||||
if let success = result as? ApiResultSuccess<NotificationPreference> {
|
||||
return success.data
|
||||
} else if let error = result as? ApiResultError {
|
||||
print("❌ Failed to get preferences: \(error.message)")
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
} catch {
|
||||
print("❌ Error getting notification preferences: \(error.localizedDescription)")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Badge Management
|
||||
|
||||
// func clearBadge() {
|
||||
// UIApplication.shared.applicationIconBadgeNumber = 0
|
||||
// }
|
||||
//
|
||||
// func setBadge(count: Int) {
|
||||
// UIApplication.shared.applicationIconBadgeNumber = count
|
||||
// }
|
||||
func clearBadge() {
|
||||
UIApplication.shared.applicationIconBadgeNumber = 0
|
||||
}
|
||||
|
||||
func setBadge(count: Int) {
|
||||
UIApplication.shared.applicationIconBadgeNumber = count
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user