Skip to content

Commit

Permalink
Refactor how product categorization and filtering is done to make it …
Browse files Browse the repository at this point in the history
…clearer.
  • Loading branch information
hafizrahman committed Jun 11, 2024
1 parent 34442d1 commit f1b37ed
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 78 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ struct AddProductWithAIActionSheet: View {
}
}
} else {
ManualProductTypeOptions(productTypes: productTypes, onOptionSelected: onProductTypeOption)
ManualProductTypeOptions(supportedProductTypes: productTypes, onOptionSelected: onProductTypeOption)
}

Spacer()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,26 @@ import SwiftUI
/// View to show the manual product type creation options.
///
struct ManualProductTypeOptions: View {
private let productTypes: [BottomSheetProductType]
private let supportedProductTypes: [BottomSheetProductType]
private let onOptionSelected: (BottomSheetProductType) -> Void

/// Grouped product types based on their product category
private let groupedProductTypes: [(BottomSheetProductType.ProductCreationCategory, [BottomSheetProductType])]
private let supportedProductCategories: [BottomSheetProductCategory]

@ScaledMetric private var scale: CGFloat = 1.0

init(productTypes: [BottomSheetProductType],
init(supportedProductTypes: [BottomSheetProductType],
onOptionSelected: @escaping (BottomSheetProductType) -> Void) {
self.productTypes = productTypes
self.supportedProductTypes = supportedProductTypes
self.onOptionSelected = onOptionSelected

self.groupedProductTypes = Constants.productCategoriesOrder.compactMap { category in
let currentCategoryProductTypes = productTypes.filter { $0.productCreationCategory == category }
return currentCategoryProductTypes.isEmpty ? nil : (category, currentCategoryProductTypes)
self.supportedProductCategories = BottomSheetProductCategory.allCases.filter { category in
// Only show a product category if at least one of its product types can be found in `supportedProductTypes`
category.productTypes.first { supportedProductTypes.contains($0) } != nil
}
}

var body: some View {
ForEach(groupedProductTypes, id: \.0) { (category, productTypes) in
ForEach(supportedProductCategories, id: \.self) { category in
VStack {
Text(category.label)
.subheadlineStyle()
Expand All @@ -32,30 +31,31 @@ struct ManualProductTypeOptions: View {
.padding(.bottom, Constants.categoryVerticalSpacing)
.padding(.horizontal, Constants.horizontalSpacing)

ForEach(productTypes) { productType in
HStack(alignment: .top, spacing: Constants.margin) {
Image(uiImage: productType.actionSheetImage.withRenderingMode(.alwaysTemplate))
.resizable()
.frame(width: Constants.productTypeIconSize, height: Constants.productTypeIconSize)
.foregroundStyle(.primary)
.padding(.top, Constants.productIconTopSpacing)
ForEach(category.productTypes) { productType in
if supportedProductTypes.contains(productType) {
HStack(alignment: .top, spacing: Constants.margin) {
Image(uiImage: productType.actionSheetImage.withRenderingMode(.alwaysTemplate))
.resizable()
.frame(width: Constants.productTypeIconSize, height: Constants.productTypeIconSize)
.foregroundStyle(.primary)
.padding(.top, Constants.productIconTopSpacing)

VStack(alignment: .leading, spacing: Constants.verticalSpacing) {
Text(productType.actionSheetTitle)
.bodyStyle()
Text(productType.actionSheetDescription)
.subheadlineStyle()
VStack(alignment: .leading, spacing: Constants.verticalSpacing) {
Text(productType.actionSheetTitle)
.bodyStyle()
Text(productType.actionSheetDescription)
.subheadlineStyle()
}
.padding(.bottom, Constants.productBottomSpacing)
Spacer()
}
.padding(.horizontal, Constants.horizontalSpacing)
.onTapGesture {
onOptionSelected(productType)
}
.padding(.bottom, Constants.productBottomSpacing)
Spacer()
}
.padding(.horizontal, Constants.horizontalSpacing)
.onTapGesture {
onOptionSelected(productType)
}

}
if category != Constants.productCategoriesOrder.last {
if category != supportedProductCategories.last {
Divider()
.padding(.vertical, Constants.categoryVerticalSpacing)
}
Expand All @@ -66,8 +66,6 @@ struct ManualProductTypeOptions: View {

private extension ManualProductTypeOptions {
enum Constants {
// List of product categories. The ordering dictates how the categories are displayed.
static let productCategoriesOrder: [BottomSheetProductType.ProductCreationCategory] = [.standard, .subscription, .other]
static let verticalSpacing: CGFloat = 4
static let horizontalSpacing: CGFloat = 16
static let categoryVerticalSpacing: CGFloat = 8
Expand All @@ -80,7 +78,7 @@ private extension ManualProductTypeOptions {

#Preview {
ManualProductTypeOptions(
productTypes: [
supportedProductTypes: [
.simple(isVirtual: false),
.simple(isVirtual: true),
.subscription,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import Foundation

/// Product creation option's category.
/// Used to group the options on the product creation sheet.
///
enum BottomSheetProductCategory: CaseIterable {
case standard
case subscription
case other

/// Categorization for each available product types.
/// Depending on store configurations, some types will need to be excluded before being used in the UI.
var productTypes: [BottomSheetProductType] {
switch self {
case .standard:
return [.simple(isVirtual: false), .simple(isVirtual: true), .variable, .blank]
case .subscription:
return [.subscription, .variableSubscription]
case .other:
return [.custom("custom"), .grouped, .affiliate]
}
}

var label: String {
switch self {
case .standard:
return NSLocalizedString(
"productCreationCategory.standard",
value: "Standard",
comment: "Category label for standard product creation types"
)
case .subscription:
return NSLocalizedString(
"productCreationCategory.subscription",
value: "Subscription",
comment: "Category label for subscription product creation types"
)
case .other:
return NSLocalizedString(
"productCreationCategory.other",
value: "Other",
comment: "Category label for other product creation types"
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -198,19 +198,6 @@ public enum BottomSheetProductType: Hashable, Identifiable {
}
}

/// Product creation category (for UI purposes).
///
var productCreationCategory: ProductCreationCategory {
switch self {
case .simple, .blank, .variable:
return .standard
case .subscription, .variableSubscription:
return .subscription
case .custom, .grouped, .affiliate:
return .other
}
}

init(productType: ProductType, isVirtual: Bool) {
switch productType {
case .simple:
Expand All @@ -235,36 +222,4 @@ public enum BottomSheetProductType: Hashable, Identifiable {
self = .custom(string)
}
}

/// Product creation option's category.
/// Used to group the options on the product creation sheet.
///
enum ProductCreationCategory {
case standard
case subscription
case other

var label: String {
switch self {
case .standard:
return NSLocalizedString(
"bottomSheetProductType.productCreationCategory.standard",
value: "Standard",
comment: "Category label for standard product creation types"
)
case .subscription:
return NSLocalizedString(
"bottomSheetProductType.productCreationCategory.subscription",
value: "Subscription",
comment: "Category label for subscription product creation types"
)
case .other:
return NSLocalizedString(
"bottomSheetProductType.productCreationCategory.other",
value: "Other",
comment: "Category label for other product creation types"
)
}
}
}
}
4 changes: 4 additions & 0 deletions WooCommerce/WooCommerce.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -1612,6 +1612,7 @@
867B330F2B4D39B900DCBEA6 /* BlazeAddParameterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 867B330E2B4D39B900DCBEA6 /* BlazeAddParameterView.swift */; };
867EA0AC2B8F09280064BCA7 /* CustomerSelector+Filter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 867EA0AB2B8F09280064BCA7 /* CustomerSelector+Filter.swift */; };
867EA0AF2B8F15740064BCA7 /* CustomerFilter+Analytics.swift in Sources */ = {isa = PBXBuildFile; fileRef = 867EA0AE2B8F15740064BCA7 /* CustomerFilter+Analytics.swift */; };
868029532C184E6C00CB64A1 /* BottomSheetProductCategory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 868029522C184E6C00CB64A1 /* BottomSheetProductCategory.swift */; };
86967D812B4E21C600C20CA8 /* BlazeAddParameterViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 86967D802B4E21C600C20CA8 /* BlazeAddParameterViewModel.swift */; };
86967D832B4E3EC300C20CA8 /* BlazeAdUrlParameter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 86967D822B4E3EC300C20CA8 /* BlazeAdUrlParameter.swift */; };
8697AFBD2B60F56A00EFAF21 /* BlazeAdDestinationSettingViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8697AFBC2B60F56A00EFAF21 /* BlazeAdDestinationSettingViewModelTests.swift */; };
Expand Down Expand Up @@ -4485,6 +4486,7 @@
867B330E2B4D39B900DCBEA6 /* BlazeAddParameterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlazeAddParameterView.swift; sourceTree = "<group>"; };
867EA0AB2B8F09280064BCA7 /* CustomerSelector+Filter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CustomerSelector+Filter.swift"; sourceTree = "<group>"; };
867EA0AE2B8F15740064BCA7 /* CustomerFilter+Analytics.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CustomerFilter+Analytics.swift"; sourceTree = "<group>"; };
868029522C184E6C00CB64A1 /* BottomSheetProductCategory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BottomSheetProductCategory.swift; sourceTree = "<group>"; };
86967D802B4E21C600C20CA8 /* BlazeAddParameterViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlazeAddParameterViewModel.swift; sourceTree = "<group>"; };
86967D822B4E3EC300C20CA8 /* BlazeAdUrlParameter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlazeAdUrlParameter.swift; sourceTree = "<group>"; };
8697AFBC2B60F56A00EFAF21 /* BlazeAdDestinationSettingViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlazeAdDestinationSettingViewModelTests.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -6041,6 +6043,7 @@
4574745C24EA84D800CF49BC /* ProductTypeBottomSheetListSelectorCommand.swift */,
2676F4CB2908284800C7A15B /* ProductCreationTypeCommand.swift */,
860476E72B6CA0FC00AF0AEB /* BottomSheetProductType.swift */,
868029522C184E6C00CB64A1 /* BottomSheetProductCategory.swift */,
);
path = BottomSheetListSelector;
sourceTree = "<group>";
Expand Down Expand Up @@ -15473,6 +15476,7 @@
AEE9A880293A3E5500227C92 /* RefreshablePlainList.swift in Sources */,
02D4472C2A4D29930040D72D /* WooAnalyticsEvent+LocalAnnouncement.swift in Sources */,
2004E2ED2C0F5DD800D62521 /* CardPresentPaymentCollectOrderPaymentUseCaseAdaptor.swift in Sources */,
868029532C184E6C00CB64A1 /* BottomSheetProductCategory.swift in Sources */,
B55BC1F121A878A30011A0C0 /* String+HTML.swift in Sources */,
B56C721221B5B44000E5E85B /* PushNotificationsConfiguration.swift in Sources */,
26FE09DF24DB871100B9BDF5 /* SurveyViewControllersFactory.swift in Sources */,
Expand Down

0 comments on commit f1b37ed

Please sign in to comment.