Skip to content

Commit 5c2c923

Browse files
committed
Set product details label for variations explicitly
1 parent add1b67 commit 5c2c923

File tree

5 files changed

+47
-20
lines changed

5 files changed

+47
-20
lines changed

WooCommerce/Classes/ViewRelated/Orders/Order Creation/NewOrderViewModel.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,12 +183,13 @@ final class NewOrderViewModel: ObservableObject {
183183
}
184184

185185
if item.variationID != 0, let variation = allProductVariations.first(where: { $0.productVariationID == item.variationID }) {
186+
let attributes = ProductVariationFormatter().generateAttributes(for: variation, from: product.attributes)
186187
return ProductRowViewModel(id: item.id,
187188
productVariation: variation,
188189
name: product.name,
189190
quantity: item.quantity,
190191
canChangeQuantity: canChangeQuantity,
191-
attributes: ProductVariationFormatter().generateAttributes(for: variation, from: product.attributes))
192+
displayMode: .attributes(attributes))
192193
} else {
193194
return ProductRowViewModel(id: item.id, product: product, quantity: item.quantity, canChangeQuantity: canChangeQuantity)
194195
}

WooCommerce/Classes/ViewRelated/Orders/Order Creation/ProductsSection/AddProductVariationToOrderViewModel.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,10 @@ final class AddProductVariationToOrderViewModel: ObservableObject {
4545
///
4646
var productVariationRows: [ProductRowViewModel] {
4747
return productVariations.map {
48-
.init(productVariation: $0, name: ProductVariationFormatter().generateName(for: $0, from: productAttributes), canChangeQuantity: false)
48+
.init(productVariation: $0,
49+
name: ProductVariationFormatter().generateName(for: $0, from: productAttributes),
50+
canChangeQuantity: false,
51+
displayMode: .stock)
4952
}
5053
}
5154

WooCommerce/Classes/ViewRelated/Orders/Order Creation/ProductsSection/ProductRowViewModel.swift

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -49,15 +49,15 @@ final class ProductRowViewModel: ObservableObject, Identifiable {
4949
///
5050
private let manageStock: Bool
5151

52-
/// Product variation attributes
52+
/// Display mode for a product variation.
53+
/// Determines which details to display in the product details label.
5354
///
54-
private let variationAttributes: [VariationAttributeViewModel]?
55+
private let variationDisplayMode: VariationDisplayMode?
5556

5657
/// Label showing product details. Can include stock status or attributes, price, and variations (if any).
5758
///
5859
var productDetailsLabel: String {
59-
// When provided, the variation attributes should replace the stock status
60-
let stockOrAttributesLabel = variationAttributes != nil ? createAttributesText() : createStockText()
60+
let stockOrAttributesLabel = createStockOrAttributesText()
6161
let priceLabel = createPriceText()
6262
let variationsLabel = createVariationsText()
6363

@@ -105,7 +105,7 @@ final class ProductRowViewModel: ObservableObject, Identifiable {
105105
canChangeQuantity: Bool,
106106
imageURL: URL?,
107107
numberOfVariations: Int = 0,
108-
variationAttributes: [VariationAttributeViewModel]? = nil,
108+
variationDisplayMode: VariationDisplayMode? = nil,
109109
currencyFormatter: CurrencyFormatter = CurrencyFormatter(currencySettings: ServiceLocator.currencySettings)) {
110110
self.id = id ?? productOrVariationID.description
111111
self.productOrVariationID = productOrVariationID
@@ -120,7 +120,7 @@ final class ProductRowViewModel: ObservableObject, Identifiable {
120120
self.imageURL = imageURL
121121
self.currencyFormatter = currencyFormatter
122122
self.numberOfVariations = numberOfVariations
123-
self.variationAttributes = variationAttributes
123+
self.variationDisplayMode = variationDisplayMode
124124
}
125125

126126
/// Initialize `ProductRowViewModel` with a `Product`
@@ -160,7 +160,7 @@ final class ProductRowViewModel: ObservableObject, Identifiable {
160160
name: String,
161161
quantity: Decimal = 1,
162162
canChangeQuantity: Bool,
163-
attributes: [VariationAttributeViewModel]? = nil,
163+
displayMode: VariationDisplayMode,
164164
currencyFormatter: CurrencyFormatter = CurrencyFormatter(currencySettings: ServiceLocator.currencySettings)) {
165165
let imageURL: URL?
166166
if let encodedImageURLString = productVariation.image?.src.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) {
@@ -180,10 +180,32 @@ final class ProductRowViewModel: ObservableObject, Identifiable {
180180
quantity: quantity,
181181
canChangeQuantity: canChangeQuantity,
182182
imageURL: imageURL,
183-
variationAttributes: attributes,
183+
variationDisplayMode: displayMode,
184184
currencyFormatter: currencyFormatter)
185185
}
186186

187+
/// Determines which product variation details to display.
188+
///
189+
enum VariationDisplayMode {
190+
/// Displays the variation's stock status
191+
case stock
192+
193+
/// Displays the provided list of variation attributes
194+
case attributes([VariationAttributeViewModel])
195+
}
196+
197+
/// Creates the stock or variation attributes text.
198+
/// Returns stock text for non-variations; uses variation display mode to determine the text for variations.
199+
///
200+
private func createStockOrAttributesText() -> String {
201+
switch variationDisplayMode {
202+
case .attributes(let attributes):
203+
return createAttributesText(from: attributes)
204+
default:
205+
return createStockText()
206+
}
207+
}
208+
187209
/// Create the stock text based on a product's stock status/quantity.
188210
///
189211
private func createStockText() -> String {
@@ -202,10 +224,7 @@ final class ProductRowViewModel: ObservableObject, Identifiable {
202224

203225
/// Create the attributes text based on the provided product variation attributes.
204226
///
205-
private func createAttributesText() -> String? {
206-
guard let attributes = variationAttributes else {
207-
return nil
208-
}
227+
private func createAttributesText(from attributes: [VariationAttributeViewModel]) -> String {
209228
return attributes.map { $0.nameOrValue }.joined(separator: ", ")
210229
}
211230

WooCommerce/WooCommerceTests/ViewRelated/Orders/Order Creation/NewOrderViewModelTests.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,11 @@ class NewOrderViewModelTests: XCTestCase {
258258
let productRow = viewModel.createProductRowViewModel(for: newOrderItem, canChangeQuantity: false)
259259

260260
// Then
261-
let expectedProductRow = ProductRowViewModel(productVariation: productVariation, name: product.name, quantity: 2, canChangeQuantity: false)
261+
let expectedProductRow = ProductRowViewModel(productVariation: productVariation,
262+
name: product.name,
263+
quantity: 2,
264+
canChangeQuantity: false,
265+
displayMode: .stock)
262266
XCTAssertEqual(productRow?.name, expectedProductRow.name)
263267
XCTAssertEqual(productRow?.skuLabel, expectedProductRow.skuLabel)
264268
XCTAssertEqual(productRow?.quantity, expectedProductRow.quantity)

WooCommerce/WooCommerceTests/ViewRelated/Orders/Order Creation/ProductRowViewModelTests.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ class ProductRowViewModelTests: XCTestCase {
4646
image: ProductImage.fake().copy(src: imageURLString))
4747

4848
// When
49-
let viewModel = ProductRowViewModel(id: rowID, productVariation: productVariation, name: name, canChangeQuantity: false)
49+
let viewModel = ProductRowViewModel(id: rowID, productVariation: productVariation, name: name, canChangeQuantity: false, displayMode: .stock)
5050

5151
// Then
5252
XCTAssertEqual(viewModel.id, rowID)
@@ -156,13 +156,13 @@ class ProductRowViewModelTests: XCTestCase {
156156
XCTAssertEqual(viewModel.productDetailsLabel, expectedProductDetailsLabel)
157157
}
158158

159-
func test_view_model_creates_expected_label_for_variation_with_provided_attributes() {
159+
func test_view_model_creates_expected_label_for_variation_with_attributes_display_mode() {
160160
// Given
161161
let variation = ProductVariation.fake().copy(attributes: [ProductVariationAttribute(id: 1, name: "Color", option: "Blue")], stockStatus: .inStock)
162162
let attributes = [VariationAttributeViewModel(name: "Color", value: "Blue"), VariationAttributeViewModel(name: "Size")]
163163

164164
// When
165-
let viewModel = ProductRowViewModel(productVariation: variation, name: "", canChangeQuantity: false, attributes: attributes)
165+
let viewModel = ProductRowViewModel(productVariation: variation, name: "", canChangeQuantity: false, displayMode: .attributes(attributes))
166166

167167
// Then
168168
let expectedAttributesText = "Blue, Any Size"
@@ -172,12 +172,12 @@ class ProductRowViewModelTests: XCTestCase {
172172
XCTAssertFalse(viewModel.productDetailsLabel.contains(unexpectedStockText))
173173
}
174174

175-
func test_view_model_creates_expected_label_for_variation_without_provided_attributes() {
175+
func test_view_model_creates_expected_label_for_variation_with_stock_display_mode() {
176176
// Given
177177
let variation = ProductVariation.fake().copy(attributes: [ProductVariationAttribute(id: 1, name: "Color", option: "Blue")], stockStatus: .inStock)
178178

179179
// When
180-
let viewModel = ProductRowViewModel(productVariation: variation, name: "", canChangeQuantity: false)
180+
let viewModel = ProductRowViewModel(productVariation: variation, name: "", canChangeQuantity: false, displayMode: .stock)
181181

182182
// Then
183183
let expectedStockText = "In stock"

0 commit comments

Comments
 (0)