diff --git a/Modules/Sources/PointOfSale/Presentation/Settings/POSInformationCard.swift b/Modules/Sources/PointOfSale/Presentation/Settings/POSInformationCard.swift index 793f625ebbb..1ebfdeb988b 100644 --- a/Modules/Sources/PointOfSale/Presentation/Settings/POSInformationCard.swift +++ b/Modules/Sources/PointOfSale/Presentation/Settings/POSInformationCard.swift @@ -22,25 +22,36 @@ struct POSInformationCardFieldRow: View { case primary } + enum LabelStyle { + case regular + case bold + } + let label: String let value: String let showSeparator: Bool + let labelStyle: LabelStyle let buttonTitle: String? let buttonAction: (() -> Void)? let buttonStyle: ButtonStyle + let isLoading: Bool init(label: String, value: String, showSeparator: Bool = true, + labelStyle: LabelStyle = .regular, buttonTitle: String? = nil, buttonAction: (() -> Void)? = nil, - buttonStyle: ButtonStyle = .default) { + buttonStyle: ButtonStyle = .default, + isLoading: Bool = false) { self.label = label self.value = value self.showSeparator = showSeparator + self.labelStyle = labelStyle self.buttonTitle = buttonTitle self.buttonAction = buttonAction self.buttonStyle = buttonStyle + self.isLoading = isLoading } var body: some View { @@ -48,7 +59,7 @@ struct POSInformationCardFieldRow: View { HStack(alignment: .center, spacing: POSSpacing.medium) { VStack(alignment: .leading, spacing: POSPadding.small) { Text(label) - .font(.posBodyMediumRegular()) + .font(labelStyle == .bold ? .posBodyMediumBold : .posBodyMediumRegular()) Text(value) .font(.posBodyMediumRegular()) .foregroundStyle(.secondary) @@ -60,7 +71,8 @@ struct POSInformationCardFieldRow: View { Button(buttonTitle, action: buttonAction) .buttonStyle(POSInfoCardButtonStyle( size: .compact, - variant: buttonStyle == .primary ? .primary : .default + variant: buttonStyle == .primary ? .primary : .default, + isLoading: isLoading )) } } diff --git a/Modules/Sources/PointOfSale/Presentation/Settings/POSInformationCardFieldRowWithToggle.swift b/Modules/Sources/PointOfSale/Presentation/Settings/POSInformationCardFieldRowWithToggle.swift new file mode 100644 index 00000000000..28570c1ac81 --- /dev/null +++ b/Modules/Sources/PointOfSale/Presentation/Settings/POSInformationCardFieldRowWithToggle.swift @@ -0,0 +1,44 @@ +import SwiftUI + +struct POSInformationCardFieldRowWithToggle: View { + let label: String + let value: String + let showSeparator: Bool + @Binding var isOn: Bool + + init(label: String, + value: String, + showSeparator: Bool = true, + isOn: Binding) { + self.label = label + self.value = value + self.showSeparator = showSeparator + self._isOn = isOn + } + + var body: some View { + VStack(alignment: .leading, spacing: POSPadding.small) { + HStack(alignment: .center, spacing: POSSpacing.medium) { + VStack(alignment: .leading, spacing: POSPadding.small) { + Text(label) + .font(.posBodyMediumBold) + Text(value) + .font(.posBodyMediumRegular()) + .foregroundStyle(.secondary) + } + + Spacer() + + Toggle("", isOn: $isOn) + .toggleStyle(SwitchToggleStyle()) + .tint(Color.posPrimaryContainer) + } + + if showSeparator { + Divider() + .padding(.top, POSPadding.small) + } + } + .frame(maxWidth: .infinity, alignment: .leading) + } +} diff --git a/Modules/Sources/PointOfSale/Presentation/Settings/POSSettingsLocalCatalogDetailView.swift b/Modules/Sources/PointOfSale/Presentation/Settings/POSSettingsLocalCatalogDetailView.swift index 7db23a738c3..2eb15ba3e8d 100644 --- a/Modules/Sources/PointOfSale/Presentation/Settings/POSSettingsLocalCatalogDetailView.swift +++ b/Modules/Sources/PointOfSale/Presentation/Settings/POSSettingsLocalCatalogDetailView.swift @@ -1,7 +1,6 @@ import SwiftUI struct POSSettingsLocalCatalogDetailView: View { - // TODO: WOOMOB-1335 - implement full sync cellular data setting functionality private let viewModel: POSSettingsLocalCatalogViewModel init(viewModel: POSSettingsLocalCatalogViewModel) { @@ -35,96 +34,63 @@ struct POSSettingsLocalCatalogDetailView: View { private extension POSSettingsLocalCatalogDetailView { @ViewBuilder var catalogStatus: some View { - VStack(spacing: POSSpacing.none) { - sectionHeaderView(title: Localization.catalogStatus) - - VStack(spacing: POSSpacing.medium) { - fieldRowView(label: Localization.catalogSize, value: viewModel.catalogSize) - fieldRowView(label: Localization.lastIncrementalUpdate, value: viewModel.lastIncrementalSyncDate) - fieldRowView(label: Localization.lastFullSync, value: viewModel.lastFullSyncDate) + POSInformationCard { + VStack(spacing: POSSpacing.small) { + POSInformationCardFieldRow( + label: Localization.catalogSize, + value: viewModel.catalogSize + ) + POSInformationCardFieldRow( + label: Localization.lastIncrementalSync, + value: viewModel.lastIncrementalSyncDate + ) + POSInformationCardFieldRow( + label: Localization.lastFullSync, + value: viewModel.lastFullSyncDate, + showSeparator: false + ) } - .padding(.bottom, POSPadding.medium) - .redacted(reason: viewModel.isLoading ? .placeholder : []) - .shimmering(active: viewModel.isLoading) } + .redacted(reason: viewModel.isLoading ? .placeholder : []) + .shimmering(active: viewModel.isLoading) } @ViewBuilder var managingDataUsage: some View { @Bindable var viewModel = viewModel VStack(spacing: POSSpacing.none) { - sectionHeaderView(title: Localization.managingDataUsage) - - VStack(spacing: POSSpacing.medium) { - toggleRowView(label: Localization.allowFullSyncOnCellular, isOn: $viewModel.allowFullSyncOnCellular) + POSInformationCard { + POSInformationCardFieldRowWithToggle( + label: Localization.managingDataUsage, + value: Localization.allowSyncOnCellular, + showSeparator: false, + isOn: $viewModel.allowFullSyncOnCellular + ) } - .padding(.bottom, POSPadding.medium) } } @ViewBuilder var manualCatalogUpdate: some View { VStack(spacing: POSSpacing.none) { - sectionHeaderView(title: Localization.manualCatalogUpdate) - - VStack(spacing: POSSpacing.medium) { - Text(Localization.manualUpdateInfo) - .font(.posCaptionRegular) - .foregroundStyle(.secondary) - .frame(maxWidth: .infinity, alignment: .leading) - - Button(action: { - Task { - await viewModel.refreshCatalog() - } - }) { - Text(Localization.refreshCatalog) - } - .buttonStyle(POSFilledButtonStyle(size: .normal, isLoading: viewModel.isRefreshingCatalog)) + POSInformationCard { + POSInformationCardFieldRow( + label: Localization.manualCatalogUpdate, + value: Localization.manualUpdateInfo, + showSeparator: false, + labelStyle: .bold, + buttonTitle: Localization.updateCatalog, + buttonAction: { + Task { + await viewModel.refreshCatalog() + } + }, + buttonStyle: .primary, + isLoading: viewModel.isRefreshingCatalog + ) } - .padding(.horizontal, POSPadding.medium) - .padding(.bottom, POSPadding.medium) - } - } - - @ViewBuilder - func sectionHeaderView(title: String) -> some View { - ZStack { - Style.backgroundColor - Text(title) - .font(.posBodyLargeBold) - .foregroundColor(.posOnSurface) - .frame(maxWidth: .infinity, alignment: .leading) - .padding(.horizontal, POSPadding.medium) - .padding(.vertical, POSPadding.small) } } - - @ViewBuilder - func fieldRowView(label: String, value: String) -> some View { - VStack(alignment: .leading, spacing: POSPadding.small) { - Text(label) - .font(.posBodyMediumRegular()) - Text(value) - .font(.posBodyMediumRegular()) - .foregroundStyle(.secondary) - } - .frame(maxWidth: .infinity, alignment: .leading) - .padding(.horizontal, POSPadding.medium) - } - - @ViewBuilder - func toggleRowView(label: String, isOn: Binding) -> some View { - HStack { - Text(label) - .font(.posBodyMediumRegular()) - Spacer() - Toggle("", isOn: isOn) - .toggleStyle(SwitchToggleStyle()) - } - .frame(maxWidth: .infinity, alignment: .leading) - .padding(.horizontal, POSPadding.medium) - } } private extension POSSettingsLocalCatalogDetailView { @@ -134,65 +100,57 @@ private extension POSSettingsLocalCatalogDetailView { enum Localization { static let localCatalogTitle = NSLocalizedString( - "posSettingsLocalCatalogDetailView.title", - value: "Catalog Settings", + "posSettingsLocalCatalogDetailView.title.1", + value: "Product catalog", comment: "Navigation title for the local catalog details in POS settings." ) - static let catalogStatus = NSLocalizedString( - "posSettingsLocalCatalogDetailView.catalogStatus", - value: "Catalog Status", - comment: "Section title for catalog status in Point of Sale settings." - ) - static let managingDataUsage = NSLocalizedString( - "posSettingsLocalCatalogDetailView.managingDataUsage.1", - value: "Managing Data Usage", + "posSettingsLocalCatalogDetailView.managingDataUsage.2", + value: "Cellular data", comment: "Section title for managing data usage in Point of Sale settings." ) - static let lastIncrementalUpdate = NSLocalizedString( - "posSettingsLocalCatalogDetailView.lastIncrementalSync", - value: "Last update", - comment: "Label for last incremental update field in Point of Sale settings." + static let lastIncrementalSync = NSLocalizedString( + "posSettingsLocalCatalogDetailView.lastIncrementalSync.1", + value: "Last incremental sync", + comment: "Label for last incremental sync field in Point of Sale settings." ) static let lastFullSync = NSLocalizedString( - "posSettingsLocalCatalogDetailView.lastFullSync.1", - value: "Last full update", + "posSettingsLocalCatalogDetailView.lastFullSync.2", + value: "Last full sync", comment: "Label for last full sync field in Point of Sale settings." ) static let catalogSize = NSLocalizedString( - "posSettingsLocalCatalogDetailView.catalogSize", - value: "Catalog size", + "posSettingsLocalCatalogDetailView.catalogSize.1", + value: "Size", comment: "Label for catalog size field in Point of Sale settings." ) - - static let allowFullSyncOnCellular = NSLocalizedString( - "posSettingsLocalCatalogDetailView.allowFullSyncOnCellular.1", - value: "Allow full update on cellular data", - comment: "Label for allow full sync on cellular data toggle in Point of Sale settings." + static let allowSyncOnCellular = NSLocalizedString( + "posSettingsLocalCatalogDetailView.allowSyncOnCellular.2", + value: "Allow sync using cellular data", + comment: "Label for allow sync on cellular data toggle in Point of Sale settings." ) - static let manualCatalogUpdate = NSLocalizedString( - "posSettingsLocalCatalogDetailView.manualCatalogUpdate", - value: "Manual Catalog Update", + "posSettingsLocalCatalogDetailView.manualCatalogUpdate.1", + value: "Catalog update", comment: "Section title for manual catalog update in Point of Sale settings." ) static let manualUpdateInfo = NSLocalizedString( - "posSettingsLocalCatalogDetailView.manualUpdateInfo", - value: "Use this refresh only when something seems off - POS keeps data current automatically.", - comment: "Info text explaining when to use manual catalog update." + "posSettingsLocalCatalogDetailView.manualUpdateInfo.1", + value: "Update the catalog manually", + comment: "Info text explaining the usage of the manual catalog update button." ) - static let refreshCatalog = NSLocalizedString( - "posSettingsLocalCatalogDetailView.refreshCatalog", - value: "Refresh catalog", - comment: "Button text for refreshing the catalog manually." + static let updateCatalog = NSLocalizedString( + "posSettingsLocalCatalogDetailView.updateCatalog", + value: "Update catalog", + comment: "Button text for updating the catalog manually." ) } } diff --git a/Modules/Sources/PointOfSale/Presentation/Settings/POSSettingsLocalCatalogViewModel.swift b/Modules/Sources/PointOfSale/Presentation/Settings/POSSettingsLocalCatalogViewModel.swift index 34c4e71670e..c4e4be965c0 100644 --- a/Modules/Sources/PointOfSale/Presentation/Settings/POSSettingsLocalCatalogViewModel.swift +++ b/Modules/Sources/PointOfSale/Presentation/Settings/POSSettingsLocalCatalogViewModel.swift @@ -150,7 +150,7 @@ private extension POSSettingsLocalCatalogViewModel { enum Localization { static let catalogSizeFormat = NSLocalizedString( "posSettingsLocalCatalogViewModel.catalogSizeFormat", - value: "%1$d products, %2$ld variations", + value: "%1$d products and %2$ld variations", comment: "Format string for catalog size showing product count and variation count. " + "%1$d will be replaced by the product count, and %2$ld will be replaced by the variation count." ) diff --git a/Modules/Sources/PointOfSale/Presentation/Settings/POSSettingsView.swift b/Modules/Sources/PointOfSale/Presentation/Settings/POSSettingsView.swift index d002c1e30fb..169c8100ea5 100644 --- a/Modules/Sources/PointOfSale/Presentation/Settings/POSSettingsView.swift +++ b/Modules/Sources/PointOfSale/Presentation/Settings/POSSettingsView.swift @@ -195,8 +195,8 @@ extension POSSettingsView { ) static let sidebarNavigationLocalCatalogTitle = NSLocalizedString( - "pointOfSaleSettingsView.sidebarNavigationLocalCatalogTitle", - value: "Catalog", + "pointOfSaleSettingsView.sidebarNavigationLocalCatalogTitle.2", + value: "Product catalog", comment: "Title of the Local catalog section within Point of Sale settings." ) diff --git a/Modules/Tests/PointOfSaleTests/Presentation/Settings/POSSettingsLocalCatalogViewModelTests.swift b/Modules/Tests/PointOfSaleTests/Presentation/Settings/POSSettingsLocalCatalogViewModelTests.swift index e843cc49bb1..d575fd6eb44 100644 --- a/Modules/Tests/PointOfSaleTests/Presentation/Settings/POSSettingsLocalCatalogViewModelTests.swift +++ b/Modules/Tests/PointOfSaleTests/Presentation/Settings/POSSettingsLocalCatalogViewModelTests.swift @@ -49,7 +49,7 @@ struct POSSettingsLocalCatalogViewModelTests { await sut.loadCatalogData() // Then - #expect(sut.catalogSize == "150 products, 75 variations") + #expect(sut.catalogSize == "150 products and 75 variations") #expect(sut.lastFullSyncDate.contains("ago")) #expect(sut.lastIncrementalSyncDate.contains("ago")) #expect(sut.isLoading == false) @@ -81,7 +81,7 @@ struct POSSettingsLocalCatalogViewModelTests { await sut.loadCatalogData() // Then - #expect(sut.catalogSize == "100 products, 50 variations") + #expect(sut.catalogSize == "100 products and 50 variations") #expect(sut.lastFullSyncDate == "Not updated") #expect(sut.lastIncrementalSyncDate == "Not updated") } @@ -128,7 +128,7 @@ struct POSSettingsLocalCatalogViewModelTests { // Then #expect(catalogSyncCoordinator.performFullSyncInvocationCount == 1) #expect(catalogSyncCoordinator.performFullSyncSiteID == sampleSiteID) - #expect(sut.catalogSize == "200 products, 100 variations") + #expect(sut.catalogSize == "200 products and 100 variations") #expect(sut.isRefreshingCatalog == false) } @@ -198,7 +198,7 @@ struct POSSettingsLocalCatalogViewModelTests { await refreshTask.value // Then - #expect(sut.catalogSize == "100 products, 50 variations") + #expect(sut.catalogSize == "100 products and 50 variations") #expect(sut.isLoading == false) #expect(sut.isRefreshingCatalog == false) #expect(catalogSyncCoordinator.performFullSyncInvocationCount == 1)