Skip to content

Commit f953944

Browse files
committed
Show errors when refreshing catalog from settings
1 parent 57dc91a commit f953944

File tree

4 files changed

+47
-2
lines changed

4 files changed

+47
-2
lines changed

Modules/Sources/PointOfSale/Models/PointOfSaleErrorState.swift

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import Foundation
22
import enum Alamofire.AFError
33

4-
struct PointOfSaleErrorState: Equatable {
4+
struct PointOfSaleErrorState: Equatable, Identifiable {
55
enum ErrorType: Equatable {
66
case initialCatalogSyncError
7+
case refreshCatalogSyncError
78
case productsLoadError
89
case variationsLoadError
910
case productsNextPageError
@@ -16,6 +17,7 @@ struct PointOfSaleErrorState: Equatable {
1617
case ordersNextPageError
1718
}
1819

20+
let id = UUID()
1921
let errorType: ErrorType
2022
let title: String
2123
let subtitle: String
@@ -117,6 +119,14 @@ struct PointOfSaleErrorState: Equatable {
117119
buttonText: Constants.retryButtonTitle)
118120
}
119121

122+
static func errorOnRefreshingCatalog(error: Error? = nil) -> Self {
123+
PointOfSaleErrorState(
124+
errorType: .refreshCatalogSyncError,
125+
title: Constants.failedToRefreshCatalogTitle,
126+
subtitle: subtitle(for: error),
127+
buttonText: Constants.retryButtonTitle)
128+
}
129+
120130
private static func subtitle(for error: Error?) -> String {
121131
if let error, error.isConnectivityError {
122132
return Constants.connectivityErrorSubtitle
@@ -141,6 +151,11 @@ struct PointOfSaleErrorState: Equatable {
141151
value: "Unable to sync catalog",
142152
comment: "Title appearing on the item list screen when there's an error syncing the catalog for the first time."
143153
)
154+
static let failedToRefreshCatalogTitle = NSLocalizedString(
155+
"pos.catalog.refreshFailedTitle",
156+
value: "Unable to refresh catalog",
157+
comment: "Title appearing in a modal when there's an error refreshing the catalog."
158+
)
144159
static let loadingCouponsErrorTitle = NSLocalizedString(
145160
"pos.itemList.loadingCouponsErrorTitle.2",
146161
value: "Unable to load coupons",

Modules/Sources/PointOfSale/Presentation/Settings/POSSettingsLocalCatalogDetailView.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ struct POSSettingsLocalCatalogDetailView: View {
88
}
99

1010
var body: some View {
11+
@Bindable var viewModel = viewModel
1112
NavigationStack {
1213
VStack(spacing: POSSpacing.none) {
1314
POSPageHeaderView(title: Localization.localCatalogTitle)
@@ -28,6 +29,13 @@ struct POSSettingsLocalCatalogDetailView: View {
2829
.task {
2930
await viewModel.loadCatalogData()
3031
}
32+
.posModal(item: $viewModel.catalogRefreshError) { errorState in
33+
POSListErrorView(error: errorState, onAction: {
34+
Task {
35+
await viewModel.refreshCatalog()
36+
}
37+
})
38+
}
3139
}
3240
}
3341

Modules/Sources/PointOfSale/Presentation/Settings/POSSettingsLocalCatalogViewModel.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ final class POSSettingsLocalCatalogViewModel {
1212
private(set) var isLoading: Bool = false
1313
private(set) var isRefreshingCatalog: Bool = false
1414

15+
var catalogRefreshError: PointOfSaleErrorState? = nil
16+
1517
private let siteID: Int64
1618
private let catalogSettingsService: POSCatalogSettingsServiceProtocol
1719
private let catalogSyncCoordinator: POSCatalogSyncCoordinatorProtocol
@@ -78,15 +80,16 @@ final class POSSettingsLocalCatalogViewModel {
7880
@MainActor
7981
func refreshCatalog() async {
8082
isRefreshingCatalog = true
83+
catalogRefreshError = nil
8184

8285
do {
8386
try await catalogSyncCoordinator.performFullSync(for: siteID, regenerateCatalog: true)
84-
// Sync completed synchronously - update UI
8587
isRefreshingCatalog = false
8688
await loadCatalogData()
8789
} catch {
8890
DDLogError("⛔️ POSSettingsLocalCatalog: Failed to refresh catalog: \(error)")
8991
isRefreshingCatalog = false
92+
catalogRefreshError = PointOfSaleErrorState.errorOnRefreshingCatalog(error: error)
9093
}
9194
}
9295

Modules/Tests/PointOfSaleTests/Presentation/Settings/POSSettingsLocalCatalogViewModelTests.swift

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ struct POSSettingsLocalCatalogViewModelTests {
3232
#expect(sut.lastIncrementalSyncDate == "")
3333
#expect(sut.isLoading == false)
3434
#expect(sut.isRefreshingCatalog == false)
35+
#expect(sut.catalogRefreshError == nil)
3536
}
3637

3738
// MARK: - `loadCatalogData` Tests
@@ -175,6 +176,24 @@ struct POSSettingsLocalCatalogViewModelTests {
175176
#expect(sut.isRefreshingCatalog == false)
176177
}
177178

179+
@Test func refreshCatalog_sets_refresh_error_state_when_sync_fails() async throws {
180+
// Given
181+
catalogSettingsService.catalogInfoResult = .success(POSCatalogInfo(
182+
productCount: 50,
183+
variationCount: 25,
184+
lastFullSyncDate: nil,
185+
lastIncrementalSyncDate: nil
186+
))
187+
catalogSyncCoordinator.performFullSyncResult = .failure(MockError.syncError)
188+
189+
// When
190+
await sut.refreshCatalog()
191+
192+
// Then
193+
let catalogRefreshError = try #require(sut.catalogRefreshError)
194+
#expect(catalogRefreshError.errorType == .refreshCatalogSyncError)
195+
}
196+
178197
// MARK: - Test Concurrent Operations
179198

180199
@Test func concurrent_loadCatalogData_and_refreshCatalog_operations_work_correctly() async throws {

0 commit comments

Comments
 (0)