From d168d93aa4d79364708b08378ec8dbade4ddcc0b Mon Sep 17 00:00:00 2001 From: Sangyoon Date: Fri, 7 Nov 2025 00:16:16 +0900 Subject: [PATCH 1/3] =?UTF-8?q?[FEAT]=20=EB=8C=80=EC=8B=9C=EB=B3=B4?= =?UTF-8?q?=EB=93=9C=20api=20=EC=97=B0=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- SampoomManagement/App/ContentView.swift | 2 +- .../Core/DI/AppDependencies.swift | 21 ++++++++ .../Core/Resources/StringResources.swift | 3 ++ .../Data/Mappers/DashboardMappers.swift | 22 ++++++++ .../Data/Remote/API/DashboardAPI.swift | 28 ++++++++++ .../Remote/DTO/DashboardResponseDTO.swift | 8 +++ .../Remote/DTO/WeeklySummaryResponseDTO.swift | 7 +++ .../Repository/DashboardRepositoryImpl.swift | 27 ++++++++++ .../Dashboard/Domain/Models/Dashboard.swift | 8 +++ .../Domain/Models/WeeklySummary.swift | 7 +++ .../Repository/DashboardRepository.swift | 6 +++ .../Domain/UseCase/GetDashboardUseCase.swift | 13 +++++ .../UseCase/GetWeeklySummaryUseCase.swift | 13 +++++ .../Dashboard/UI/DashboardUiState.swift | 10 ++++ .../Features/Dashboard/UI/DashboardView.swift | 51 +++++++++++++++++-- .../Dashboard/UI/DashboardViewModel.swift | 48 ++++++++++++++--- .../block.imageset/Contents.json | 12 +++++ .../Assets.xcassets/block.imageset/block.svg | 1 + .../car.imageset/Contents.json | 12 +++++ .../Assets.xcassets/car.imageset/car.svg | 1 + 20 files changed, 287 insertions(+), 13 deletions(-) create mode 100644 SampoomManagement/Features/Dashboard/Data/Mappers/DashboardMappers.swift create mode 100644 SampoomManagement/Features/Dashboard/Data/Remote/API/DashboardAPI.swift create mode 100644 SampoomManagement/Features/Dashboard/Data/Remote/DTO/DashboardResponseDTO.swift create mode 100644 SampoomManagement/Features/Dashboard/Data/Remote/DTO/WeeklySummaryResponseDTO.swift create mode 100644 SampoomManagement/Features/Dashboard/Data/Repository/DashboardRepositoryImpl.swift create mode 100644 SampoomManagement/Features/Dashboard/Domain/Models/Dashboard.swift create mode 100644 SampoomManagement/Features/Dashboard/Domain/Models/WeeklySummary.swift create mode 100644 SampoomManagement/Features/Dashboard/Domain/Repository/DashboardRepository.swift create mode 100644 SampoomManagement/Features/Dashboard/Domain/UseCase/GetDashboardUseCase.swift create mode 100644 SampoomManagement/Features/Dashboard/Domain/UseCase/GetWeeklySummaryUseCase.swift create mode 100644 SampoomManagement/Resources/Assets.xcassets/block.imageset/Contents.json create mode 100644 SampoomManagement/Resources/Assets.xcassets/block.imageset/block.svg create mode 100644 SampoomManagement/Resources/Assets.xcassets/car.imageset/Contents.json create mode 100644 SampoomManagement/Resources/Assets.xcassets/car.imageset/car.svg diff --git a/SampoomManagement/App/ContentView.swift b/SampoomManagement/App/ContentView.swift index a90ec76..6e49bfc 100644 --- a/SampoomManagement/App/ContentView.swift +++ b/SampoomManagement/App/ContentView.swift @@ -29,7 +29,7 @@ struct ContentView: View { init(dependencies: AppDependencies) { self.dependencies = dependencies _partViewModel = StateObject(wrappedValue: dependencies.makePartViewModel()) - _dashboardViewModel = StateObject(wrappedValue: DashboardViewModel(getOrderUseCase: dependencies.getOrderUseCase)) + _dashboardViewModel = StateObject(wrappedValue: dependencies.makeDashboardViewModel()) } // MARK: - Body diff --git a/SampoomManagement/Core/DI/AppDependencies.swift b/SampoomManagement/Core/DI/AppDependencies.swift index bb3be03..55b9bfa 100644 --- a/SampoomManagement/Core/DI/AppDependencies.swift +++ b/SampoomManagement/Core/DI/AppDependencies.swift @@ -67,6 +67,12 @@ class AppDependencies { let receiveOrderUseCase: ReceiveOrderUseCase let cancelOrderUseCase: CancelOrderUseCase + // MARK: - Dashboard + let dashboardAPI: DashboardAPI + let dashboardRepository: DashboardRepository + let getDashboardUseCase: GetDashboardUseCase + let getWeeklySummaryUseCase: GetWeeklySummaryUseCase + init() { // Global Message Handler globalMessageHandler = GlobalMessageHandler.shared @@ -140,6 +146,12 @@ class AppDependencies { completeOrderUseCase = CompleteOrderUseCase(repository: orderRepository) receiveOrderUseCase = ReceiveOrderUseCase(repository: orderRepository) cancelOrderUseCase = CancelOrderUseCase(repository: orderRepository) + + // Dashboard + dashboardAPI = DashboardAPI(networkManager: networkManager) + dashboardRepository = DashboardRepositoryImpl(api: dashboardAPI, authPreferences: authPreferences) + getDashboardUseCase = GetDashboardUseCase(repository: dashboardRepository) + getWeeklySummaryUseCase = GetWeeklySummaryUseCase(repository: dashboardRepository) } // MARK: - ViewModel Factories @@ -224,5 +236,14 @@ class AppDependencies { globalMessageHandler: globalMessageHandler ) } + + func makeDashboardViewModel() -> DashboardViewModel { + return DashboardViewModel( + getOrderUseCase: getOrderUseCase, + getDashboardUseCase: getDashboardUseCase, + getWeeklySummaryUseCase: getWeeklySummaryUseCase, + messageHandler: globalMessageHandler + ) + } } diff --git a/SampoomManagement/Core/Resources/StringResources.swift b/SampoomManagement/Core/Resources/StringResources.swift index 83a9074..b2b7615 100644 --- a/SampoomManagement/Core/Resources/StringResources.swift +++ b/SampoomManagement/Core/Resources/StringResources.swift @@ -25,6 +25,9 @@ struct StringResources { static let shortageOfParts = "부족 부품" static let orderAmount = "주문 금액" static let recentOrdersTitle = "최근 주문" + static let weeklySummaryTitle = "이번 주 요약" + static let weeklySummaryInStock = "입고 부품" + static let weeklySummaryOutStock = "출고 부품" } // MARK: - Tabs diff --git a/SampoomManagement/Features/Dashboard/Data/Mappers/DashboardMappers.swift b/SampoomManagement/Features/Dashboard/Data/Mappers/DashboardMappers.swift new file mode 100644 index 0000000..ffdf8ef --- /dev/null +++ b/SampoomManagement/Features/Dashboard/Data/Mappers/DashboardMappers.swift @@ -0,0 +1,22 @@ +import Foundation + +extension DashboardResponseDTO { + func toModel() -> Dashboard { + return Dashboard( + totalParts: totalParts, + outOfStockParts: outOfStockParts, + lowStockParts: lowStockParts, + totalQuantity: totalQuantity + ) + } +} + +extension WeeklySummaryResponseDTO { + func toModel() -> WeeklySummary { + return WeeklySummary( + inStockParts: inStockParts, + outStockParts: outStockParts, + weekPeriod: weekPeriod + ) + } +} diff --git a/SampoomManagement/Features/Dashboard/Data/Remote/API/DashboardAPI.swift b/SampoomManagement/Features/Dashboard/Data/Remote/API/DashboardAPI.swift new file mode 100644 index 0000000..e71a007 --- /dev/null +++ b/SampoomManagement/Features/Dashboard/Data/Remote/API/DashboardAPI.swift @@ -0,0 +1,28 @@ +import Foundation +import Alamofire + +class DashboardAPI { + private let networkManager: NetworkManager + + init(networkManager: NetworkManager) { + self.networkManager = networkManager + } + + func getDashboard(agencyId: Int) async throws -> APIResponse { + let endpoint = "agency/\(agencyId)/dashboard" + return try await networkManager.request( + endpoint: endpoint, + method: .get, + responseType: DashboardResponseDTO.self + ) + } + + func getWeeklySummary(agencyId: Int) async throws -> APIResponse { + let endpoint = "agency/\(agencyId)/weekly-summary" + return try await networkManager.request( + endpoint: endpoint, + method: .get, + responseType: WeeklySummaryResponseDTO.self + ) + } +} diff --git a/SampoomManagement/Features/Dashboard/Data/Remote/DTO/DashboardResponseDTO.swift b/SampoomManagement/Features/Dashboard/Data/Remote/DTO/DashboardResponseDTO.swift new file mode 100644 index 0000000..3b78ba1 --- /dev/null +++ b/SampoomManagement/Features/Dashboard/Data/Remote/DTO/DashboardResponseDTO.swift @@ -0,0 +1,8 @@ +import Foundation + +struct DashboardResponseDTO: Codable { + let totalParts: Int + let outOfStockParts: Int + let lowStockParts: Int + let totalQuantity: Int +} diff --git a/SampoomManagement/Features/Dashboard/Data/Remote/DTO/WeeklySummaryResponseDTO.swift b/SampoomManagement/Features/Dashboard/Data/Remote/DTO/WeeklySummaryResponseDTO.swift new file mode 100644 index 0000000..88060e0 --- /dev/null +++ b/SampoomManagement/Features/Dashboard/Data/Remote/DTO/WeeklySummaryResponseDTO.swift @@ -0,0 +1,7 @@ +import Foundation + +struct WeeklySummaryResponseDTO: Codable { + let inStockParts: Int + let outStockParts: Int + let weekPeriod: String +} diff --git a/SampoomManagement/Features/Dashboard/Data/Repository/DashboardRepositoryImpl.swift b/SampoomManagement/Features/Dashboard/Data/Repository/DashboardRepositoryImpl.swift new file mode 100644 index 0000000..4ef4e80 --- /dev/null +++ b/SampoomManagement/Features/Dashboard/Data/Repository/DashboardRepositoryImpl.swift @@ -0,0 +1,27 @@ +import Foundation + +class DashboardRepositoryImpl: DashboardRepository { + private let api: DashboardAPI + private let authPreferences: AuthPreferences + + init(api: DashboardAPI, authPreferences: AuthPreferences) { + self.api = api + self.authPreferences = authPreferences + } + + func getDashboard() async throws -> Dashboard { + guard let user = try authPreferences.getStoredUser() else { throw NetworkError.unauthorized } + let response = try await api.getDashboard(agencyId: user.agencyId) + if !response.success { throw NetworkError.serverError(response.status, message: response.message) } + guard let data = response.data else { throw NetworkError.noData } + return data.toModel() + } + + func getWeeklySummary() async throws -> WeeklySummary { + guard let user = try authPreferences.getStoredUser() else { throw NetworkError.unauthorized } + let response = try await api.getWeeklySummary(agencyId: user.agencyId) + if !response.success { throw NetworkError.serverError(response.status, message: response.message) } + guard let data = response.data else { throw NetworkError.noData } + return data.toModel() + } +} diff --git a/SampoomManagement/Features/Dashboard/Domain/Models/Dashboard.swift b/SampoomManagement/Features/Dashboard/Domain/Models/Dashboard.swift new file mode 100644 index 0000000..651897c --- /dev/null +++ b/SampoomManagement/Features/Dashboard/Domain/Models/Dashboard.swift @@ -0,0 +1,8 @@ +import Foundation + +struct Dashboard: Equatable { + let totalParts: Int + let outOfStockParts: Int + let lowStockParts: Int + let totalQuantity: Int +} diff --git a/SampoomManagement/Features/Dashboard/Domain/Models/WeeklySummary.swift b/SampoomManagement/Features/Dashboard/Domain/Models/WeeklySummary.swift new file mode 100644 index 0000000..83ad0f2 --- /dev/null +++ b/SampoomManagement/Features/Dashboard/Domain/Models/WeeklySummary.swift @@ -0,0 +1,7 @@ +import Foundation + +struct WeeklySummary: Equatable { + let inStockParts: Int + let outStockParts: Int + let weekPeriod: String +} diff --git a/SampoomManagement/Features/Dashboard/Domain/Repository/DashboardRepository.swift b/SampoomManagement/Features/Dashboard/Domain/Repository/DashboardRepository.swift new file mode 100644 index 0000000..d9c3ef6 --- /dev/null +++ b/SampoomManagement/Features/Dashboard/Domain/Repository/DashboardRepository.swift @@ -0,0 +1,6 @@ +import Foundation + +protocol DashboardRepository { + func getDashboard() async throws -> Dashboard + func getWeeklySummary() async throws -> WeeklySummary +} diff --git a/SampoomManagement/Features/Dashboard/Domain/UseCase/GetDashboardUseCase.swift b/SampoomManagement/Features/Dashboard/Domain/UseCase/GetDashboardUseCase.swift new file mode 100644 index 0000000..57aa2a1 --- /dev/null +++ b/SampoomManagement/Features/Dashboard/Domain/UseCase/GetDashboardUseCase.swift @@ -0,0 +1,13 @@ +import Foundation + +struct GetDashboardUseCase { + private let repository: DashboardRepository + + init(repository: DashboardRepository) { + self.repository = repository + } + + func execute() async throws -> Dashboard { + return try await repository.getDashboard() + } +} diff --git a/SampoomManagement/Features/Dashboard/Domain/UseCase/GetWeeklySummaryUseCase.swift b/SampoomManagement/Features/Dashboard/Domain/UseCase/GetWeeklySummaryUseCase.swift new file mode 100644 index 0000000..92b4dac --- /dev/null +++ b/SampoomManagement/Features/Dashboard/Domain/UseCase/GetWeeklySummaryUseCase.swift @@ -0,0 +1,13 @@ +import Foundation + +struct GetWeeklySummaryUseCase { + private let repository: DashboardRepository + + init(repository: DashboardRepository) { + self.repository = repository + } + + func execute() async throws -> WeeklySummary { + return try await repository.getWeeklySummary() + } +} diff --git a/SampoomManagement/Features/Dashboard/UI/DashboardUiState.swift b/SampoomManagement/Features/Dashboard/UI/DashboardUiState.swift index 3d4f100..bb56029 100644 --- a/SampoomManagement/Features/Dashboard/UI/DashboardUiState.swift +++ b/SampoomManagement/Features/Dashboard/UI/DashboardUiState.swift @@ -9,26 +9,36 @@ import Foundation struct DashboardUiState: Equatable { let orderList: [Order] + let dashboard: Dashboard? + let weeklySummary: WeeklySummary? let dashboardLoading: Bool let dashboardError: String? init( orderList: [Order] = [], + dashboard: Dashboard? = nil, + weeklySummary: WeeklySummary? = nil, dashboardLoading: Bool = false, dashboardError: String? = nil ) { self.orderList = orderList + self.dashboard = dashboard + self.weeklySummary = weeklySummary self.dashboardLoading = dashboardLoading self.dashboardError = dashboardError } func copy( orderList: [Order]? = nil, + dashboard: Dashboard?? = nil, + weeklySummary: WeeklySummary?? = nil, dashboardLoading: Bool? = nil, dashboardError: String? = nil ) -> DashboardUiState { return DashboardUiState( orderList: orderList ?? self.orderList, + dashboard: dashboard ?? self.dashboard, + weeklySummary: weeklySummary ?? self.weeklySummary, dashboardLoading: dashboardLoading ?? self.dashboardLoading, dashboardError: dashboardError ?? self.dashboardError ) diff --git a/SampoomManagement/Features/Dashboard/UI/DashboardView.swift b/SampoomManagement/Features/Dashboard/UI/DashboardView.swift index 6abda9e..2228032 100644 --- a/SampoomManagement/Features/Dashboard/UI/DashboardView.swift +++ b/SampoomManagement/Features/Dashboard/UI/DashboardView.swift @@ -45,6 +45,7 @@ struct DashboardView: View { titleSection buttonSection orderListSection + weeklySummarySection Spacer(minLength: 100) } .padding(.horizontal, 16) @@ -79,17 +80,18 @@ struct DashboardView: View { } private var buttonSection: some View { - VStack(spacing: 16) { + let dash = viewModel.uiState.dashboard + return VStack(spacing: 16) { if userRole.isAdmin { buttonCard(iconName: "employee", valueText: "45", subText: StringResources.Dashboard.employee, bordered: true) {} } HStack(spacing: 16) { - buttonCard(iconName: "parts", valueText: "1234", subText: StringResources.Dashboard.partsOnHand) {} - buttonCard(iconName: "orders", valueText: "23", subText: StringResources.Dashboard.partsInProgress) {} + buttonCard(iconName: "car", valueText: String(dash?.totalParts ?? 0), subText: StringResources.Dashboard.partsOnHand) {} + buttonCard(iconName: "block", valueText: String(dash?.outOfStockParts ?? 0), subText: StringResources.Dashboard.shortageOfParts) {} } HStack(spacing: 16) { - buttonCard(iconName: "warning", valueText: "19", subText: StringResources.Dashboard.shortageOfParts) {} - buttonCard(iconName: "money", valueText: "4,123,200", subText: StringResources.Dashboard.orderAmount) {} + buttonCard(iconName: "warning", valueText: String(dash?.lowStockParts ?? 0), subText: StringResources.Dashboard.shortageOfParts) {} + buttonCard(iconName: "parts", valueText: String(dash?.totalQuantity ?? 0), subText: StringResources.Dashboard.partsOnHand) {} } } .padding(.bottom, 16) @@ -127,6 +129,7 @@ struct DashboardView: View { HStack { Text(StringResources.Dashboard.recentOrdersTitle) .font(.gmarketTitle2) + .fontWeight(.bold) .foregroundColor(.text) Spacer() Button(action: { onNavigateOrderList() }) { @@ -156,6 +159,44 @@ struct DashboardView: View { } } } + + private var weeklySummarySection: some View { + let weekly = viewModel.uiState.weeklySummary + return VStack(alignment: .leading, spacing: 16) { + Text(StringResources.Dashboard.weeklySummaryTitle) + .font(.gmarketTitle2) + .fontWeight(.bold) + .foregroundColor(.text) + + HStack(spacing: 0) { + VStack(spacing: 8) { + Text(String(weekly?.inStockParts ?? 0)) + .font(.gmarketTitle2) + .fontWeight(.bold) + .foregroundColor(.green) + Text(StringResources.Dashboard.weeklySummaryInStock) + .font(.gmarketBody) + .foregroundColor(.textSecondary) + } + .frame(maxWidth: .infinity) + + VStack(spacing: 8) { + Text(String(weekly?.outStockParts ?? 0)) + .font(.gmarketTitle2) + .fontWeight(.bold) + .foregroundColor(.red) + Text(StringResources.Dashboard.weeklySummaryOutStock) + .font(.gmarketBody) + .foregroundColor(.textSecondary) + } + .frame(maxWidth: .infinity) + } + } + .frame(maxWidth: .infinity) + .padding(16) + .background(Color.backgroundCard) + .clipShape(RoundedRectangle(cornerRadius: 16)) + } } diff --git a/SampoomManagement/Features/Dashboard/UI/DashboardViewModel.swift b/SampoomManagement/Features/Dashboard/UI/DashboardViewModel.swift index f278418..7a8f993 100644 --- a/SampoomManagement/Features/Dashboard/UI/DashboardViewModel.swift +++ b/SampoomManagement/Features/Dashboard/UI/DashboardViewModel.swift @@ -14,37 +14,71 @@ class DashboardViewModel: ObservableObject { @Published var uiState = DashboardUiState() private let getOrderUseCase: GetOrderUseCase + private let getDashboardUseCase: GetDashboardUseCase + private let getWeeklySummaryUseCase: GetWeeklySummaryUseCase + private let messageHandler: GlobalMessageHandler - init(getOrderUseCase: GetOrderUseCase) { + init( + getOrderUseCase: GetOrderUseCase, + getDashboardUseCase: GetDashboardUseCase, + getWeeklySummaryUseCase: GetWeeklySummaryUseCase, + messageHandler: GlobalMessageHandler + ) { self.getOrderUseCase = getOrderUseCase - loadOrderList() + self.getDashboardUseCase = getDashboardUseCase + self.getWeeklySummaryUseCase = getWeeklySummaryUseCase + self.messageHandler = messageHandler + loadAll() } func onEvent(_ event: DashboardUiEvent) { switch event { case .loadDashboard, .retryDashboard: - loadOrderList() + loadAll() } } + private func loadAll() { + loadOrderList() + Task { await loadDashboard() } + Task { await loadWeeklySummary() } + } + private func loadOrderList() { Task { uiState = uiState.copy(dashboardLoading: true, dashboardError: nil) do { let orderList = try await getOrderUseCase.execute() uiState = uiState.copy( - orderList: Array(orderList.items.prefix(5)), - dashboardLoading: false, - dashboardError: nil + orderList: Array(orderList.items.prefix(5)) ) } catch { uiState = uiState.copy( - dashboardLoading: false, dashboardError: error.localizedDescription ) } } } + + private func loadDashboard() async { + do { + let dashboard = try await getDashboardUseCase.execute() + uiState = uiState.copy(dashboard: dashboard, dashboardLoading: false, dashboardError: nil) + } catch { + messageHandler.showMessage(error.localizedDescription, isError: true) + uiState = uiState.copy(dashboardLoading: false, dashboardError: error.localizedDescription) + } + } + + private func loadWeeklySummary() async { + do { + let weekly = try await getWeeklySummaryUseCase.execute() + uiState = uiState.copy(weeklySummary: weekly, dashboardLoading: false, dashboardError: nil) + } catch { + messageHandler.showMessage(error.localizedDescription, isError: true) + uiState = uiState.copy(dashboardLoading: false, dashboardError: error.localizedDescription) + } + } } diff --git a/SampoomManagement/Resources/Assets.xcassets/block.imageset/Contents.json b/SampoomManagement/Resources/Assets.xcassets/block.imageset/Contents.json new file mode 100644 index 0000000..9fbef6a --- /dev/null +++ b/SampoomManagement/Resources/Assets.xcassets/block.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "block.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/SampoomManagement/Resources/Assets.xcassets/block.imageset/block.svg b/SampoomManagement/Resources/Assets.xcassets/block.imageset/block.svg new file mode 100644 index 0000000..6ff1c81 --- /dev/null +++ b/SampoomManagement/Resources/Assets.xcassets/block.imageset/block.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/SampoomManagement/Resources/Assets.xcassets/car.imageset/Contents.json b/SampoomManagement/Resources/Assets.xcassets/car.imageset/Contents.json new file mode 100644 index 0000000..d059f1a --- /dev/null +++ b/SampoomManagement/Resources/Assets.xcassets/car.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "car.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/SampoomManagement/Resources/Assets.xcassets/car.imageset/car.svg b/SampoomManagement/Resources/Assets.xcassets/car.imageset/car.svg new file mode 100644 index 0000000..9ac9add --- /dev/null +++ b/SampoomManagement/Resources/Assets.xcassets/car.imageset/car.svg @@ -0,0 +1 @@ + \ No newline at end of file From fc23eccf4fe19b16da7990393d94e977e9db0890 Mon Sep 17 00:00:00 2001 From: Sangyoon Date: Fri, 7 Nov 2025 14:19:44 +0900 Subject: [PATCH 2/3] =?UTF-8?q?[FIX]=20=EC=BD=94=EB=93=9C=20=EB=9E=98?= =?UTF-8?q?=EB=B9=97=20=EB=A6=AC=EB=B7=B0=20=EC=82=AC=ED=95=AD=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Dashboard/UI/DashboardUiState.swift | 16 ++++++++-- .../Features/Dashboard/UI/DashboardView.swift | 9 +----- .../Dashboard/UI/DashboardViewModel.swift | 32 +++++++++++++------ 3 files changed, 37 insertions(+), 20 deletions(-) diff --git a/SampoomManagement/Features/Dashboard/UI/DashboardUiState.swift b/SampoomManagement/Features/Dashboard/UI/DashboardUiState.swift index bb56029..cb08ed9 100644 --- a/SampoomManagement/Features/Dashboard/UI/DashboardUiState.swift +++ b/SampoomManagement/Features/Dashboard/UI/DashboardUiState.swift @@ -13,19 +13,25 @@ struct DashboardUiState: Equatable { let weeklySummary: WeeklySummary? let dashboardLoading: Bool let dashboardError: String? + let weeklySummaryLoading: Bool + let weeklySummaryError: String? init( orderList: [Order] = [], dashboard: Dashboard? = nil, weeklySummary: WeeklySummary? = nil, dashboardLoading: Bool = false, - dashboardError: String? = nil + dashboardError: String? = nil, + weeklySummaryLoading: Bool = false, + weeklySummaryError: String? = nil ) { self.orderList = orderList self.dashboard = dashboard self.weeklySummary = weeklySummary self.dashboardLoading = dashboardLoading self.dashboardError = dashboardError + self.weeklySummaryLoading = weeklySummaryLoading + self.weeklySummaryError = weeklySummaryError } func copy( @@ -33,14 +39,18 @@ struct DashboardUiState: Equatable { dashboard: Dashboard?? = nil, weeklySummary: WeeklySummary?? = nil, dashboardLoading: Bool? = nil, - dashboardError: String? = nil + dashboardError: String? = nil, + weeklySummaryLoading: Bool? = nil, + weeklySummaryError: String? = nil ) -> DashboardUiState { return DashboardUiState( orderList: orderList ?? self.orderList, dashboard: dashboard ?? self.dashboard, weeklySummary: weeklySummary ?? self.weeklySummary, dashboardLoading: dashboardLoading ?? self.dashboardLoading, - dashboardError: dashboardError ?? self.dashboardError + dashboardError: dashboardError ?? self.dashboardError, + weeklySummaryLoading: weeklySummaryLoading ?? self.weeklySummaryLoading, + weeklySummaryError: weeklySummaryError ?? self.weeklySummaryError ) } } diff --git a/SampoomManagement/Features/Dashboard/UI/DashboardView.swift b/SampoomManagement/Features/Dashboard/UI/DashboardView.swift index 2228032..d8e5ceb 100644 --- a/SampoomManagement/Features/Dashboard/UI/DashboardView.swift +++ b/SampoomManagement/Features/Dashboard/UI/DashboardView.swift @@ -139,14 +139,7 @@ struct DashboardView: View { } } - if viewModel.uiState.dashboardLoading { - HStack { Spacer(); ProgressView(); Spacer() } - .padding(.vertical, 32) - } else if let error = viewModel.uiState.dashboardError { - VStack { Text(error).foregroundColor(.red) } - .frame(maxWidth: .infinity) - .padding(.vertical, 32) - } else if viewModel.uiState.orderList.isEmpty { + if viewModel.uiState.orderList.isEmpty { VStack { Text(StringResources.Order.emptyList).foregroundColor(.textSecondary) } .frame(maxWidth: .infinity) .padding(.vertical, 32) diff --git a/SampoomManagement/Features/Dashboard/UI/DashboardViewModel.swift b/SampoomManagement/Features/Dashboard/UI/DashboardViewModel.swift index 7a8f993..3b130ab 100644 --- a/SampoomManagement/Features/Dashboard/UI/DashboardViewModel.swift +++ b/SampoomManagement/Features/Dashboard/UI/DashboardViewModel.swift @@ -46,37 +46,51 @@ class DashboardViewModel: ObservableObject { private func loadOrderList() { Task { - uiState = uiState.copy(dashboardLoading: true, dashboardError: nil) do { let orderList = try await getOrderUseCase.execute() uiState = uiState.copy( - orderList: Array(orderList.items.prefix(5)) + orderList: Array(orderList.items.prefix(5)), + dashboardLoading: false ) } catch { - uiState = uiState.copy( - dashboardError: error.localizedDescription - ) + messageHandler.showMessage(error.localizedDescription, isError: true) } } } private func loadDashboard() async { + uiState = uiState.copy(dashboardLoading: true, dashboardError: nil) do { let dashboard = try await getDashboardUseCase.execute() - uiState = uiState.copy(dashboard: dashboard, dashboardLoading: false, dashboardError: nil) + uiState = uiState.copy( + dashboard: dashboard, + dashboardLoading: false, + dashboardError: nil + ) } catch { messageHandler.showMessage(error.localizedDescription, isError: true) - uiState = uiState.copy(dashboardLoading: false, dashboardError: error.localizedDescription) + uiState = uiState.copy( + dashboardLoading: false, + dashboardError: error.localizedDescription + ) } } private func loadWeeklySummary() async { + uiState = uiState.copy(weeklySummaryLoading: true, weeklySummaryError: nil) do { let weekly = try await getWeeklySummaryUseCase.execute() - uiState = uiState.copy(weeklySummary: weekly, dashboardLoading: false, dashboardError: nil) + uiState = uiState.copy( + weeklySummary: weekly, + weeklySummaryLoading: false, + weeklySummaryError: nil + ) } catch { messageHandler.showMessage(error.localizedDescription, isError: true) - uiState = uiState.copy(dashboardLoading: false, dashboardError: error.localizedDescription) + uiState = uiState.copy( + weeklySummaryLoading: false, + weeklySummaryError: error.localizedDescription + ) } } } From eaa9240acf554d262b4016ef337d4778ecebe33a Mon Sep 17 00:00:00 2001 From: Sangyoon Date: Fri, 7 Nov 2025 14:30:37 +0900 Subject: [PATCH 3/3] =?UTF-8?q?[FIX]=20=EC=BD=94=EB=93=9C=20=EB=9E=98?= =?UTF-8?q?=EB=B9=97=20=EB=A6=AC=EB=B7=B0=20=EC=82=AC=ED=95=AD=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Features/Dashboard/UI/DashboardUiState.swift | 4 ++-- .../Features/Dashboard/UI/DashboardViewModel.swift | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/SampoomManagement/Features/Dashboard/UI/DashboardUiState.swift b/SampoomManagement/Features/Dashboard/UI/DashboardUiState.swift index cb08ed9..a3bde4b 100644 --- a/SampoomManagement/Features/Dashboard/UI/DashboardUiState.swift +++ b/SampoomManagement/Features/Dashboard/UI/DashboardUiState.swift @@ -39,9 +39,9 @@ struct DashboardUiState: Equatable { dashboard: Dashboard?? = nil, weeklySummary: WeeklySummary?? = nil, dashboardLoading: Bool? = nil, - dashboardError: String? = nil, + dashboardError: String?? = nil, weeklySummaryLoading: Bool? = nil, - weeklySummaryError: String? = nil + weeklySummaryError: String?? = nil ) -> DashboardUiState { return DashboardUiState( orderList: orderList ?? self.orderList, diff --git a/SampoomManagement/Features/Dashboard/UI/DashboardViewModel.swift b/SampoomManagement/Features/Dashboard/UI/DashboardViewModel.swift index 3b130ab..2de2522 100644 --- a/SampoomManagement/Features/Dashboard/UI/DashboardViewModel.swift +++ b/SampoomManagement/Features/Dashboard/UI/DashboardViewModel.swift @@ -59,37 +59,37 @@ class DashboardViewModel: ObservableObject { } private func loadDashboard() async { - uiState = uiState.copy(dashboardLoading: true, dashboardError: nil) + uiState = uiState.copy(dashboardLoading: true, dashboardError: .some(nil)) do { let dashboard = try await getDashboardUseCase.execute() uiState = uiState.copy( dashboard: dashboard, dashboardLoading: false, - dashboardError: nil + dashboardError: .some(nil) ) } catch { messageHandler.showMessage(error.localizedDescription, isError: true) uiState = uiState.copy( dashboardLoading: false, - dashboardError: error.localizedDescription + dashboardError: .some(error.localizedDescription) ) } } private func loadWeeklySummary() async { - uiState = uiState.copy(weeklySummaryLoading: true, weeklySummaryError: nil) + uiState = uiState.copy(weeklySummaryLoading: true, weeklySummaryError: .some(nil)) do { let weekly = try await getWeeklySummaryUseCase.execute() uiState = uiState.copy( weeklySummary: weekly, weeklySummaryLoading: false, - weeklySummaryError: nil + weeklySummaryError: .some(nil) ) } catch { messageHandler.showMessage(error.localizedDescription, isError: true) uiState = uiState.copy( weeklySummaryLoading: false, - weeklySummaryError: error.localizedDescription + weeklySummaryError: .some(error.localizedDescription) ) } }