diff --git a/ios/escape/escape/Views/Components/Badge/BadgeComponents.swift b/ios/escape/escape/Views/Components/Badge/BadgeComponents.swift index ddd9786..00ededc 100644 --- a/ios/escape/escape/Views/Components/Badge/BadgeComponents.swift +++ b/ios/escape/escape/Views/Components/Badge/BadgeComponents.swift @@ -307,6 +307,7 @@ struct BadgeItemView: View { .simultaneousGesture( TapGesture() .onEnded { _ in + HapticFeedback.shared.lightImpact() showingDetail = true } ) @@ -322,6 +323,12 @@ struct BadgeItemView: View { .sheet(isPresented: $showingDetail) { BadgeDetailView(badge: badge) } + .onChange(of: showingDetail) { oldValue, newValue in + // Haptic feedback when sheet is dismissed + if oldValue && !newValue { + HapticFeedback.shared.lightImpact() + } + } } // Fallback view when no image is available @@ -396,6 +403,7 @@ struct BadgeCardButton: View { var body: some View { Button(action: { + HapticFeedback.shared.lightImpact() showingDetail = true }) { VStack(spacing: 8) { @@ -475,6 +483,12 @@ struct BadgeCardButton: View { .sheet(isPresented: $showingDetail) { BadgeDetailView(badge: badge) } + .onChange(of: showingDetail) { oldValue, newValue in + // Haptic feedback when sheet is dismissed + if oldValue && !newValue { + HapticFeedback.shared.lightImpact() + } + } } } @@ -486,6 +500,7 @@ struct Simple3DBadgeView: View { var body: some View { Button(action: { + HapticFeedback.shared.lightImpact() showingDetail = true }) { VStack(spacing: 4) { @@ -570,6 +585,12 @@ struct Simple3DBadgeView: View { .sheet(isPresented: $showingDetail) { BadgeDetailView(badge: badge) } + .onChange(of: showingDetail) { oldValue, newValue in + // Haptic feedback when sheet is dismissed + if oldValue && !newValue { + HapticFeedback.shared.lightImpact() + } + } } // Fallback view when no image is available diff --git a/ios/escape/escape/Views/Components/Badge/BadgeDetailView.swift b/ios/escape/escape/Views/Components/Badge/BadgeDetailView.swift index 7ec0f00..22eb1bf 100644 --- a/ios/escape/escape/Views/Components/Badge/BadgeDetailView.swift +++ b/ios/escape/escape/Views/Components/Badge/BadgeDetailView.swift @@ -162,6 +162,7 @@ struct RotatableBadgeView: View { } .rotation3DEffect(.degrees(rotationAngle), axis: (x: 0, y: 1, z: 0)) .onTapGesture { + HapticFeedback.shared.mediumImpact() withAnimation(.easeInOut(duration: 0.8)) { rotationAngle += 180 isFlipped.toggle() diff --git a/ios/escape/escape/Views/Components/Group/GroupBottomSheetView.swift b/ios/escape/escape/Views/Components/Group/GroupBottomSheetView.swift index 68b2c87..28216bc 100644 --- a/ios/escape/escape/Views/Components/Group/GroupBottomSheetView.swift +++ b/ios/escape/escape/Views/Components/Group/GroupBottomSheetView.swift @@ -265,6 +265,7 @@ struct GroupCardView: View { Button(action: { Task { await groupViewModel.selectGroup(group) + HapticFeedback.shared.lightImpact() showingGroupDetail = true } }) { @@ -324,6 +325,12 @@ struct GroupCardView: View { .sheet(isPresented: $showingGroupDetail) { GroupDetailView(groupViewModel: groupViewModel) } + .onChange(of: showingGroupDetail) { oldValue, newValue in + // Haptic feedback when sheet is dismissed + if oldValue && !newValue { + HapticFeedback.shared.lightImpact() + } + } } } diff --git a/ios/escape/escape/Views/Components/Group/GroupDetailView.swift b/ios/escape/escape/Views/Components/Group/GroupDetailView.swift index 3a1d106..f5ea729 100644 --- a/ios/escape/escape/Views/Components/Group/GroupDetailView.swift +++ b/ios/escape/escape/Views/Components/Group/GroupDetailView.swift @@ -358,6 +358,12 @@ struct MemberRowView: View { UserProfileBottomSheetView(userId: member.user.id) .presentationDetents([.medium, .large]) } + .onChange(of: showUserProfile) { oldValue, newValue in + // Haptic feedback when sheet is dismissed + if oldValue && !newValue { + HapticFeedback.shared.lightImpact() + } + } } } diff --git a/ios/escape/escape/Views/Components/Home/MissionSection.swift b/ios/escape/escape/Views/Components/Home/MissionSection.swift index ebfa656..c27751f 100644 --- a/ios/escape/escape/Views/Components/Home/MissionSection.swift +++ b/ios/escape/escape/Views/Components/Home/MissionSection.swift @@ -41,6 +41,7 @@ struct MissionSection: View { .padding(.horizontal) } else { MissionCardView(mission: missionViewModel.todaysMission) { + HapticFeedback.shared.lightImpact() showingMissionDetail = true } .padding(.horizontal) @@ -60,6 +61,12 @@ struct MissionSection: View { isPresented: $showingMissionDetail ) } + .onChange(of: showingMissionDetail) { oldValue, newValue in + // Haptic feedback when sheet is dismissed + if oldValue && !newValue { + HapticFeedback.shared.lightImpact() + } + } } private func loadCurrentMission() { diff --git a/ios/escape/escape/Views/Components/Ranking/NationalRankingView.swift b/ios/escape/escape/Views/Components/Ranking/NationalRankingView.swift index 68a4170..739c818 100644 --- a/ios/escape/escape/Views/Components/Ranking/NationalRankingView.swift +++ b/ios/escape/escape/Views/Components/Ranking/NationalRankingView.swift @@ -8,7 +8,7 @@ import SwiftUI // Wrapper to make UUID work with .sheet(item:) -private struct IdentifiableUUID: Identifiable { +private struct IdentifiableUUID: Identifiable, Equatable { let id: UUID } @@ -89,6 +89,12 @@ struct NationalRankingView: View { UserProfileBottomSheetView(userId: identifiableUserId.id) .presentationDetents([.medium, .large]) } + .onChange(of: selectedUserId) { oldValue, newValue in + // Haptic feedback when sheet is dismissed + if oldValue != nil && newValue == nil { + HapticFeedback.shared.lightImpact() + } + } .task { await loadRankings() startAnimations() @@ -96,6 +102,7 @@ struct NationalRankingView: View { } private func handleUserTap(userId: UUID) { + HapticFeedback.shared.lightImpact() selectedUserId = IdentifiableUUID(id: userId) } diff --git a/ios/escape/escape/Views/Components/Ranking/TeamRankingView.swift b/ios/escape/escape/Views/Components/Ranking/TeamRankingView.swift index da498e4..cf546b4 100644 --- a/ios/escape/escape/Views/Components/Ranking/TeamRankingView.swift +++ b/ios/escape/escape/Views/Components/Ranking/TeamRankingView.swift @@ -8,7 +8,7 @@ import SwiftUI // Wrapper to make UUID work with .sheet(item:) -private struct IdentifiableUUID: Identifiable { +private struct IdentifiableUUID: Identifiable, Equatable { let id: UUID } @@ -90,6 +90,12 @@ struct TeamRankingView: View { UserProfileBottomSheetView(userId: identifiableUserId.id) .presentationDetents([.medium, .large]) } + .onChange(of: selectedUserId) { oldValue, newValue in + // Haptic feedback when sheet is dismissed + if oldValue != nil && newValue == nil { + HapticFeedback.shared.lightImpact() + } + } .task { await loadTeamRankings() startAnimations() @@ -97,6 +103,7 @@ struct TeamRankingView: View { } private func handleUserTap(userId: UUID) { + HapticFeedback.shared.lightImpact() selectedUserId = IdentifiableUUID(id: userId) }