Add push notification deep linking and sharing subscription checks

- Add deep link navigation from push notifications to specific task column on kanban board
- Fix subscription check in push notification handler to allow navigation when limitations disabled
- Add pendingNavigationTaskId to handle notifications when app isn't ready
- Add ScrollViewReader to AllTasksView for programmatic scrolling to task column
- Add canShareResidence() and canShareContractor() subscription checks (iOS & Android)
- Add test APNS file for simulator push notification testing

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Trey t
2025-12-10 23:17:28 -06:00
parent ed14a1c69e
commit cbe073aa21
21 changed files with 723 additions and 127 deletions

View File

@@ -32,6 +32,7 @@ struct ResidenceDetailView: View {
@State private var showDeleteConfirmation = false
@State private var isDeleting = false
@State private var showingUpgradePrompt = false
@State private var upgradeTriggerKey = ""
@State private var showShareSheet = false
@State private var shareFileURL: URL?
@StateObject private var subscriptionCache = SubscriptionCacheWrapper.shared
@@ -147,7 +148,7 @@ struct ResidenceDetailView: View {
}
}
.sheet(isPresented: $showingUpgradePrompt) {
UpgradePromptView(triggerKey: "add_11th_task", isPresented: $showingUpgradePrompt)
UpgradePromptView(triggerKey: upgradeTriggerKey.isEmpty ? "add_11th_task" : upgradeTriggerKey, isPresented: $showingUpgradePrompt)
}
.sheet(isPresented: $showShareSheet) {
if let url = shareFileURL {
@@ -359,7 +360,12 @@ private extension ResidenceDetailView {
// Share Residence button (owner only)
if let residence = viewModel.selectedResidence, isCurrentUserOwner(of: residence) {
Button {
shareResidence(residence)
if subscriptionCache.canShareResidence() {
shareResidence(residence)
} else {
upgradeTriggerKey = "share_residence"
showingUpgradePrompt = true
}
} label: {
if sharingManager.isGeneratingPackage {
ProgressView()
@@ -370,10 +376,25 @@ private extension ResidenceDetailView {
.disabled(sharingManager.isGeneratingPackage)
}
// Manage Users button (owner only)
if let residence = viewModel.selectedResidence, isCurrentUserOwner(of: residence) {
Button {
if subscriptionCache.canShareResidence() {
showManageUsers = true
} else {
upgradeTriggerKey = "share_residence"
showingUpgradePrompt = true
}
} label: {
Image(systemName: "person.2")
}
}
Button {
// Check LIVE task count before adding
let totalTasks = tasksResponse?.columns.reduce(0) { $0 + $1.tasks.count } ?? 0
if subscriptionCache.shouldShowUpgradePrompt(currentCount: totalTasks, limitKey: "tasks") {
upgradeTriggerKey = "add_11th_task"
showingUpgradePrompt = true
} else {
showAddTask = true