diff --git a/WooCommerce/Classes/POS/Presentation/Settings/POSSettingsLocalCatalogDetailView.swift b/WooCommerce/Classes/POS/Presentation/Settings/POSSettingsLocalCatalogDetailView.swift new file mode 100644 index 00000000000..11a9356c49d --- /dev/null +++ b/WooCommerce/Classes/POS/Presentation/Settings/POSSettingsLocalCatalogDetailView.swift @@ -0,0 +1,192 @@ +import SwiftUI + +struct POSSettingsLocalCatalogDetailView: View { + // TODO: WOOMOB-1335 - implement full sync cellular data setting functionality + @State private var allowFullSyncOnCellular: Bool = true + + var body: some View { + NavigationStack { + VStack(spacing: POSSpacing.none) { + POSPageHeaderView(title: Localization.localCatalogTitle) + .foregroundColor(.posSurface) + .accessibilityAddTraits(.isHeader) + + ScrollView { + VStack(spacing: POSSpacing.medium) { + catalogStatus + managingDataUsage + manualCatalogUpdate + } + } + .background(Style.backgroundColor) + } + } + } +} + +private extension POSSettingsLocalCatalogDetailView { + @ViewBuilder + var catalogStatus: some View { + VStack(spacing: POSSpacing.none) { + sectionHeaderView(title: Localization.catalogStatus) + + VStack(spacing: POSSpacing.medium) { + // TODO: WOOMOB-1100 - replace with catalog data + fieldRowView(label: Localization.catalogSize, value: "1,250 products, 3,420 variations") + fieldRowView(label: Localization.lastIncrementalUpdate, value: "5 minutes ago") + fieldRowView(label: Localization.lastFullSync, value: "Today at 2:34 PM") + } + .padding(.bottom, POSPadding.medium) + } + } + + @ViewBuilder + var managingDataUsage: some View { + VStack(spacing: POSSpacing.none) { + sectionHeaderView(title: Localization.managingDataUsage) + + VStack(spacing: POSSpacing.medium) { + toggleRowView(label: Localization.allowFullSyncOnCellular, isOn: $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: { + // Handle refresh catalog action + }) { + Text(Localization.refreshCatalog) + } + .buttonStyle(POSFilledButtonStyle(size: .normal)) + } + .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 { + enum Style { + static let backgroundColor = Color.posOnSecondaryContainer + } + + enum Localization { + static let localCatalogTitle = NSLocalizedString( + "posSettingsLocalCatalogDetailView.title", + value: "Catalog Settings", + 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", + value: "Managing data usage", + comment: "Section title for managing data usage in Point of Sale settings." + ) + + static let lastIncrementalUpdate = NSLocalizedString( + "posSettingsLocalCatalogDetailView.lastIncrementalUpdate", + value: "Last incremental update", + comment: "Label for last incremental update field in Point of Sale settings." + ) + + static let lastFullSync = NSLocalizedString( + "posSettingsLocalCatalogDetailView.lastFullSync", + 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", + comment: "Label for catalog size field in Point of Sale settings." + ) + + + static let allowFullSyncOnCellular = NSLocalizedString( + "posSettingsLocalCatalogDetailView.allowFullSyncOnCellular", + value: "Allow full sync on cellular data", + comment: "Label for allow full sync on cellular data toggle in Point of Sale settings." + ) + + + static let manualCatalogUpdate = NSLocalizedString( + "posSettingsLocalCatalogDetailView.manualCatalogUpdate", + value: "Manual 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." + ) + + static let refreshCatalog = NSLocalizedString( + "posSettingsLocalCatalogDetailView.refreshCatalog", + value: "Refresh catalog", + comment: "Button text for refreshing the catalog manually." + ) + } +} + +#if DEBUG +#Preview { + POSSettingsLocalCatalogDetailView() +} +#endif diff --git a/WooCommerce/Classes/POS/Presentation/Settings/PointOfSaleSettingsView.swift b/WooCommerce/Classes/POS/Presentation/Settings/PointOfSaleSettingsView.swift index 2106b8030af..a7898ed4810 100644 --- a/WooCommerce/Classes/POS/Presentation/Settings/PointOfSaleSettingsView.swift +++ b/WooCommerce/Classes/POS/Presentation/Settings/PointOfSaleSettingsView.swift @@ -53,6 +53,17 @@ extension PointOfSaleSettingsView { } ) + // TODO: WOOMOB-1287 - integrate with local catalog feature eligibility + if ServiceLocator.featureFlagService.isFeatureFlagEnabled(.pointOfSaleLocalCatalogi1) { + PointOfSaleSettingsCard( + item: .localCatalog, + isSelected: selection == .localCatalog, + onTap: { + selection = .localCatalog + } + ) + } + Spacer() PointOfSaleSettingsCard( @@ -76,6 +87,8 @@ extension PointOfSaleSettingsView { PointOfSaleSettingsStoreDetailView(viewModel: settingsController.storeViewModel) case .hardware: PointOfSaleSettingsHardwareDetailView(settingsController: settingsController) + case .localCatalog: + POSSettingsLocalCatalogDetailView() case .help: PointOfSaleSettingsHelpDetailView() default: @@ -141,6 +154,7 @@ extension PointOfSaleSettingsView { enum SidebarNavigation: String, CaseIterable, Identifiable { case store case hardware + case localCatalog case help var id: Self { self } @@ -149,6 +163,7 @@ extension PointOfSaleSettingsView { switch self { case .store: return Localization.sidebarNavigationStoreTitle case .hardware: return Localization.sidebarNavigationHardwareTitle + case .localCatalog: return Localization.sidebarNavigationLocalCatalogTitle case .help: return Localization.sidebarNavigationHelpTitle } } @@ -157,6 +172,7 @@ extension PointOfSaleSettingsView { switch self { case .store: return Localization.sidebarNavigationStoreSubtitle case .hardware: return Localization.sidebarNavigationHardwareSubtitle + case .localCatalog: return Localization.sidebarNavigationLocalCatalogSubtitle case .help: return Localization.sidebarNavigationHelpSubtitle } } @@ -165,6 +181,7 @@ extension PointOfSaleSettingsView { switch self { case .store: return "bag" case .hardware: return "wrench.and.screwdriver" + case .localCatalog: return "internaldrive" case .help: return "questionmark.circle" } } @@ -207,6 +224,18 @@ extension PointOfSaleSettingsView { comment: "Description of the settings to be found within the Hardware section." ) + static let sidebarNavigationLocalCatalogTitle = NSLocalizedString( + "pointOfSaleSettingsView.sidebarNavigationLocalCatalogTitle", + value: "Catalog", + comment: "Title of the Local catalog section within Point of Sale settings." + ) + + static let sidebarNavigationLocalCatalogSubtitle = NSLocalizedString( + "pointOfSaleSettingsView.sidebarNavigationLocalCatalogSubtitle", + value: "Manage catalog settings", + comment: "Description of the settings to be found within the Local catalog section." + ) + static let sidebarNavigationHelpSubtitle = NSLocalizedString( "pointOfSaleSettingsView.sidebarNavigationHelpSubtitle", value: "Get help and support", diff --git a/WooCommerce/WooCommerce.xcodeproj/project.pbxproj b/WooCommerce/WooCommerce.xcodeproj/project.pbxproj index c2437e8c1c1..3381029f1ed 100644 --- a/WooCommerce/WooCommerce.xcodeproj/project.pbxproj +++ b/WooCommerce/WooCommerce.xcodeproj/project.pbxproj @@ -269,6 +269,7 @@ 023D69442588C6BD00F7DA72 /* ShippingLabelPaperSizeListSelectorCommandTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 023D69432588C6BD00F7DA72 /* ShippingLabelPaperSizeListSelectorCommandTests.swift */; }; 023D69BC2589BF5900F7DA72 /* PrintShippingLabelCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 023D69BB2589BF5900F7DA72 /* PrintShippingLabelCoordinator.swift */; }; 023D877925EC8BCB00625963 /* UIScrollView+LargeTitleWorkaround.swift in Sources */ = {isa = PBXBuildFile; fileRef = 023D877825EC8BCB00625963 /* UIScrollView+LargeTitleWorkaround.swift */; }; + 023DE6262E73FE4600FF6562 /* POSSettingsLocalCatalogDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 023DE6252E73FE4600FF6562 /* POSSettingsLocalCatalogDetailView.swift */; }; 023EC2E024DA87460021DA91 /* ProductInventorySettingsViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 023EC2DF24DA87460021DA91 /* ProductInventorySettingsViewModelTests.swift */; }; 023EC2E224DA8BAB0021DA91 /* MockProductSKUValidationStoresManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 023EC2E124DA8BAB0021DA91 /* MockProductSKUValidationStoresManager.swift */; }; 023EC2E424DA95DB0021DA91 /* ProductInventorySettingsViewModel+VariationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 023EC2E324DA95DB0021DA91 /* ProductInventorySettingsViewModel+VariationTests.swift */; }; @@ -3495,6 +3496,7 @@ 023D69432588C6BD00F7DA72 /* ShippingLabelPaperSizeListSelectorCommandTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShippingLabelPaperSizeListSelectorCommandTests.swift; sourceTree = ""; }; 023D69BB2589BF5900F7DA72 /* PrintShippingLabelCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrintShippingLabelCoordinator.swift; sourceTree = ""; }; 023D877825EC8BCB00625963 /* UIScrollView+LargeTitleWorkaround.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIScrollView+LargeTitleWorkaround.swift"; sourceTree = ""; }; + 023DE6252E73FE4600FF6562 /* POSSettingsLocalCatalogDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = POSSettingsLocalCatalogDetailView.swift; sourceTree = ""; }; 023EC2DF24DA87460021DA91 /* ProductInventorySettingsViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProductInventorySettingsViewModelTests.swift; sourceTree = ""; }; 023EC2E124DA8BAB0021DA91 /* MockProductSKUValidationStoresManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockProductSKUValidationStoresManager.swift; sourceTree = ""; }; 023EC2E324DA95DB0021DA91 /* ProductInventorySettingsViewModel+VariationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ProductInventorySettingsViewModel+VariationTests.swift"; sourceTree = ""; }; @@ -10023,6 +10025,7 @@ 68707A152E570E7D00500CD8 /* Settings */ = { isa = PBXGroup; children = ( + 023DE6252E73FE4600FF6562 /* POSSettingsLocalCatalogDetailView.swift */, 683D41172E4D9B570024CFE4 /* PointOfSaleSettingsView.swift */, 68707A1A2E570F2200500CD8 /* PointOfSaleSettingsStoreDetailView.swift */, 685A30602E60908B001E667B /* POSSettingsStoreViewModel.swift */, @@ -15731,6 +15734,7 @@ D89CFFDD25B44468000E4683 /* ULAccountMismatchViewController.swift in Sources */, 03E471C6293A2E95001A58AD /* CardPresentModalTapToPayReaderCheckingDeviceSupport.swift in Sources */, B687940C27699D420092BCA0 /* RefundFeesCalculationUseCase.swift in Sources */, + 023DE6262E73FE4600FF6562 /* POSSettingsLocalCatalogDetailView.swift in Sources */, 02EA6BF82435E80600FFF90A /* ImageDownloader.swift in Sources */, CECC758623D21AC200486676 /* AggregateOrderItem.swift in Sources */, 453326FA2C3C38ED000E4862 /* ProductCreationAIBarProgressStyle.swift in Sources */,