From e61b403aa9fb022d6e7d0dad9bc7f015f76878bf Mon Sep 17 00:00:00 2001 From: Anass Bouassaba Date: Tue, 26 Nov 2024 04:54:23 +0100 Subject: [PATCH] wip: sharing error handling --- .../Screens/Sharing/SharingGroupList.swift | 36 ++++++++---------- .../Sharing/SharingGroupPermission.swift | 30 ++++++++------- Sources/Screens/Sharing/SharingOverview.swift | 38 +++++++++++++------ Sources/Screens/Sharing/SharingStore.swift | 25 +++++++----- Sources/Screens/Sharing/SharingUserList.swift | 8 ++-- .../Sharing/SharingUserPermission.swift | 32 +++++++++------- 6 files changed, 99 insertions(+), 70 deletions(-) diff --git a/Sources/Screens/Sharing/SharingGroupList.swift b/Sources/Screens/Sharing/SharingGroupList.swift index 493d6c4..a2183d2 100644 --- a/Sources/Screens/Sharing/SharingGroupList.swift +++ b/Sources/Screens/Sharing/SharingGroupList.swift @@ -25,28 +25,24 @@ struct SharingGroupList: View { } var body: some View { - VStack { - if let groupPermissions = sharingStore.groupPermissions { - if groupPermissions.isEmpty { - Text("Not shared with any groups.") - } else { - List(groupPermissions, id: \.id) { groupPermission in - NavigationLink { - SharingGroupPermission( - fileIDs: [fileID], - sharingStore: sharingStore, - workspaceStore: workspaceStore, - predefinedGroup: groupPermission.group, - defaultPermission: groupPermission.permission, - enableRevoke: true - ) - } label: { - SharingGroupRow(groupPermission) - } + if let groupPermissions = sharingStore.groupPermissions { + if groupPermissions.isEmpty { + Text("Not shared with any groups.") + } else { + List(groupPermissions, id: \.id) { groupPermission in + NavigationLink { + SharingGroupPermission( + fileIDs: [fileID], + sharingStore: sharingStore, + workspaceStore: workspaceStore, + predefinedGroup: groupPermission.group, + defaultPermission: groupPermission.permission, + enableRevoke: true + ) + } label: { + SharingGroupRow(groupPermission) } } - } else { - ProgressView() } } } diff --git a/Sources/Screens/Sharing/SharingGroupPermission.swift b/Sources/Screens/Sharing/SharingGroupPermission.swift index 9b03023..ca067be 100644 --- a/Sources/Screens/Sharing/SharingGroupPermission.swift +++ b/Sources/Screens/Sharing/SharingGroupPermission.swift @@ -11,7 +11,7 @@ import SwiftUI import VoltaserveCore -struct SharingGroupPermission: View { +struct SharingGroupPermission: View, FormValidatable, ErrorPresentable { @ObservedObject private var sharingStore: SharingStore @ObservedObject private var workspaceStore: WorkspaceStore @Environment(\.dismiss) private var dismiss @@ -19,10 +19,7 @@ struct SharingGroupPermission: View { @State private var permission: VOPermission.Value? @State private var isGranting = false @State private var isRevoking = false - @State private var showRevoke = false - @State private var showError = false - @State private var errorTitle: String? - @State private var errorMessage: String? + @State private var revokeConfirmationIsPresented = false private let fileIDs: [String] private let predefinedGroup: VOGroup.Entity? private let defaultPermission: VOPermission.Value? @@ -79,7 +76,7 @@ struct SharingGroupPermission: View { if enableRevoke, fileIDs.count == 1 { Section(header: VOSectionHeader("Actions")) { Button(role: .destructive) { - showRevoke = true + revokeConfirmationIsPresented = true } label: { HStack { Text("Revoke Permission") @@ -90,7 +87,9 @@ struct SharingGroupPermission: View { } } .disabled(isRevoking) - .confirmationDialog("Revoke Permission", isPresented: $showRevoke, titleVisibility: .visible) { + .confirmationDialog( + "Revoke Permission", isPresented: $revokeConfirmationIsPresented, titleVisibility: .visible + ) { Button("Revoke", role: .destructive) { performRevoke() } @@ -129,7 +128,7 @@ struct SharingGroupPermission: View { permission = defaultPermission } } - .voErrorAlert(isPresented: $showError, title: errorTitle, message: errorMessage) + .voErrorSheet(isPresented: $errorIsPresented, message: errorMessage) } private var isProcessing: Bool { @@ -145,9 +144,8 @@ struct SharingGroupPermission: View { } success: { dismiss() } failure: { message in - errorTitle = "Error: Granting Group Permission" errorMessage = message - showError = true + errorIsPresented = true } anyways: { isGranting = false } @@ -162,15 +160,21 @@ struct SharingGroupPermission: View { } success: { dismiss() } failure: { message in - errorTitle = "Error: Revoking Group Permission" errorMessage = message - showError = true + errorIsPresented = true } anyways: { isRevoking = false } } - private func isValid() -> Bool { + // MARK: - ErrorPresentable + + @State var errorIsPresented: Bool = false + @State var errorMessage: String? + + // MARK: - FormValidatable + + func isValid() -> Bool { group != nil && permission != nil } } diff --git a/Sources/Screens/Sharing/SharingOverview.swift b/Sources/Screens/Sharing/SharingOverview.swift index 667ce36..785a5fc 100644 --- a/Sources/Screens/Sharing/SharingOverview.swift +++ b/Sources/Screens/Sharing/SharingOverview.swift @@ -11,7 +11,7 @@ import SwiftUI import VoltaserveCore -struct SharingOverview: View { +struct SharingOverview: View, ViewDataProvider, LoadStateProvider, TimerLifecycle, TokenDistributing { @EnvironmentObject private var tokenStore: TokenStore @StateObject private var sharingStore = SharingStore() @ObservedObject private var workspaceStore: WorkspaceStore @@ -111,29 +111,45 @@ struct SharingOverview: View { } } - private func onAppearOrChange() { + private enum Tag { + case users + case groups + } + + // MARK: - LoadStateProvider + + var isLoading: Bool { + sharingStore.userPermissionsIsLoadingFirstTime || sharingStore.groupPermissionsIsLoadingFirstTime + } + + var error: String? { + sharingStore.userPermissionsError ?? sharingStore.groupPermissionsError + } + + // MARK: - ViewDataProvider + + func onAppearOrChange() { fetchData() } - private func fetchData() { + func fetchData() { sharingStore.fetchUserPermissions() sharingStore.fetchGroupPermissions() } - private func startTimers() { + // MARK: - TimerLifecycle + + func startTimers() { sharingStore.startTimer() } - private func stopTimers() { + func stopTimers() { sharingStore.stopTimer() } - private func assignTokenToStores(_ token: VOToken.Value) { - sharingStore.token = token - } + // MARK: - TokenDistributing - enum Tag { - case users - case groups + func assignTokenToStores(_ token: VOToken.Value) { + sharingStore.token = token } } diff --git a/Sources/Screens/Sharing/SharingStore.swift b/Sources/Screens/Sharing/SharingStore.swift index 850f39e..99b1095 100644 --- a/Sources/Screens/Sharing/SharingStore.swift +++ b/Sources/Screens/Sharing/SharingStore.swift @@ -14,10 +14,13 @@ import VoltaserveCore class SharingStore: ObservableObject { @Published var userPermissions: [VOFile.UserPermission]? + @Published var userPermissionsIsLoading: Bool = false + var userPermissionsIsLoadingFirstTime: Bool { userPermissionsIsLoading && userPermissions == nil } + @Published var userPermissionsError: String? @Published var groupPermissions: [VOFile.GroupPermission]? - @Published var showError = false - @Published var errorTitle: String? - @Published var errorMessage: String? + @Published var groupPermissionsIsLoading: Bool = false + var groupPermissionsIsLoadingFirstTime: Bool { groupPermissionsIsLoading && groupPermissions == nil } + @Published var groupPermissionsError: String? private var timer: Timer? private var fileClient: VOFile? var fileID: String? @@ -51,12 +54,14 @@ class SharingStore: ObservableObject { withErrorHandling { userPermissions = try await self.fetchUserPermissions(fileID) return true + } before: { + self.userPermissionsIsLoading = true } success: { self.userPermissions = userPermissions } failure: { message in - self.errorTitle = "Error: Fetching User Permissions" - self.errorMessage = message - self.showError = true + self.userPermissionsError = message + } anyways: { + self.userPermissionsIsLoading = false } } @@ -71,12 +76,14 @@ class SharingStore: ObservableObject { withErrorHandling { groupPermissions = try await self.fetchGroupPermissions(fileID) return true + } before: { + self.groupPermissionsIsLoading = true } success: { self.groupPermissions = groupPermissions } failure: { message in - self.errorTitle = "Error: Fetching Group Permissions" - self.errorMessage = message - self.showError = true + self.groupPermissionsError = message + } anyways: { + self.groupPermissionsIsLoading = false } } diff --git a/Sources/Screens/Sharing/SharingUserList.swift b/Sources/Screens/Sharing/SharingUserList.swift index 582822a..2186d96 100644 --- a/Sources/Screens/Sharing/SharingUserList.swift +++ b/Sources/Screens/Sharing/SharingUserList.swift @@ -11,7 +11,7 @@ import SwiftUI import VoltaserveCore -struct SharingUserList: View { +struct SharingUserList: View, TokenDistributing { @EnvironmentObject private var tokenStore: TokenStore @ObservedObject private var sharingStore: SharingStore @ObservedObject private var workspaceStore: WorkspaceStore @@ -53,8 +53,6 @@ struct SharingUserList: View { } } } - } else { - ProgressView() } } .onAppear { @@ -72,7 +70,9 @@ struct SharingUserList: View { } } - private func assignTokenToStores(_ token: VOToken.Value) { + // MARK: - TokenDistributing + + func assignTokenToStores(_ token: VOToken.Value) { userStore.token = token } } diff --git a/Sources/Screens/Sharing/SharingUserPermission.swift b/Sources/Screens/Sharing/SharingUserPermission.swift index c05a9b2..b2b140d 100644 --- a/Sources/Screens/Sharing/SharingUserPermission.swift +++ b/Sources/Screens/Sharing/SharingUserPermission.swift @@ -11,16 +11,13 @@ import SwiftUI import VoltaserveCore -struct SharingUserPermission: View { +struct SharingUserPermission: View, FormValidatable, ErrorPresentable { @ObservedObject private var sharingStore: SharingStore @ObservedObject private var workspaceStore: WorkspaceStore @Environment(\.dismiss) private var dismiss @State private var user: VOUser.Entity? @State private var permission: VOPermission.Value? - @State private var showRevoke = false - @State private var showError = false - @State private var errorTitle: String? - @State private var errorMessage: String? + @State private var revokeConfirmationIsPresented = false @State private var isGranting = false @State private var isRevoking = false private let fileIDs: [String] @@ -82,7 +79,7 @@ struct SharingUserPermission: View { if enableRevoke, fileIDs.count == 1 { Section(header: VOSectionHeader("Actions")) { Button(role: .destructive) { - showRevoke = true + revokeConfirmationIsPresented = true } label: { HStack { Text("Revoke Permission") @@ -93,7 +90,9 @@ struct SharingUserPermission: View { } } .disabled(isRevoking) - .confirmationDialog("Revoke Permission", isPresented: $showRevoke, titleVisibility: .visible) { + .confirmationDialog( + "Revoke Permission", isPresented: $revokeConfirmationIsPresented, titleVisibility: .visible + ) { Button("Revoke", role: .destructive) { performRevoke() } @@ -132,7 +131,7 @@ struct SharingUserPermission: View { permission = defaultPermission } } - .voErrorAlert(isPresented: $showError, title: errorTitle, message: errorMessage) + .voErrorSheet(isPresented: $errorIsPresented, message: errorMessage) } private var isProcessing: Bool { @@ -142,15 +141,15 @@ struct SharingUserPermission: View { private func performGrant() { guard let user, let permission else { return } isGranting = true + withErrorHandling { try await sharingStore.grantUserPermission(ids: fileIDs, userID: user.id, permission: permission) return true } success: { dismiss() } failure: { message in - errorTitle = "Error: Granting User Permission" errorMessage = message - showError = true + errorIsPresented = true } anyways: { isGranting = false } @@ -159,21 +158,28 @@ struct SharingUserPermission: View { private func performRevoke() { guard let user, fileIDs.count == 1, let fileID = fileIDs.first else { return } isRevoking = true + withErrorHandling { try await sharingStore.revokeUserPermission(id: fileID, userID: user.id) return true } success: { dismiss() } failure: { message in - errorTitle = "Error: Revoking User Permission" errorMessage = message - showError = true + errorIsPresented = true } anyways: { isRevoking = false } } - private func isValid() -> Bool { + // MARK: - ErrorPresentable + + @State var errorIsPresented: Bool = false + @State var errorMessage: String? + + // MARK: - FormValidatable + + func isValid() -> Bool { user != nil && permission != nil } }