Skip to content

Commit 3ee7fe0

Browse files
authored
Shipping Labels: Handle HAZMAT category selection (#15400)
2 parents 40f79ff + 4d36e35 commit 3ee7fe0

File tree

5 files changed

+136
-34
lines changed

5 files changed

+136
-34
lines changed

WooCommerce/Classes/ViewRelated/Orders/Order Details/Shipping Labels/WooShipping Create Shipping Labels/WooShipping Hazmat Section/WooShippingHazmatDetailView.swift

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,13 @@ struct WooShippingHazmatDetailView: View {
1111

1212
@State private var isShowingCategoryList = false
1313

14-
init(isHazardous: Bool, selectedCategory: ShippingLabelHazmatCategory?) {
15-
self.isHazardous = isHazardous
14+
private let selectionHandler: (ShippingLabelHazmatCategory?) -> Void
15+
16+
init(selectedCategory: ShippingLabelHazmatCategory?,
17+
selectionHandler: @escaping (ShippingLabelHazmatCategory?) -> Void) {
18+
self.isHazardous = selectedCategory != nil
1619
self.selectedCategory = selectedCategory
20+
self.selectionHandler = selectionHandler
1721
}
1822

1923
var body: some View {
@@ -29,6 +33,7 @@ struct WooShippingHazmatDetailView: View {
2933
Toggle(isOn: $isHazardous) {
3034
Text(Localization.toggleLabel)
3135
}
36+
.tint(Color.accentColor)
3237

3338
Button(Localization.selectCategory) {
3439
isShowingCategoryList = true
@@ -65,7 +70,8 @@ struct WooShippingHazmatDetailView: View {
6570
.sheet(isPresented: $isShowingCategoryList) {
6671
WooShippingHazmatCategoryList(selectedItem: selectedCategory,
6772
selectionHandler: { category in
68-
// TODO: dismiss view
73+
selectionHandler(category)
74+
dismiss()
6975
})
7076
}
7177
}
@@ -177,6 +183,5 @@ private extension WooShippingHazmatDetailView {
177183
}
178184

179185
#Preview {
180-
WooShippingHazmatDetailView(isHazardous: true,
181-
selectedCategory: .airEligibleEthanol)
186+
WooShippingHazmatDetailView(selectedCategory: .airEligibleEthanol, selectionHandler: { _ in })
182187
}

WooCommerce/Classes/ViewRelated/Orders/Order Details/Shipping Labels/WooShipping Create Shipping Labels/WooShipping Hazmat Section/WooShippingHazmatRow.swift

Lines changed: 36 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,41 +4,53 @@ struct WooShippingHazmatRow: View {
44
/// Whether the interactions (navigation/setting selection) are enabled.
55
private let enabled: Bool
66

7-
@Binding private var isHazardous: Bool
8-
97
@Binding private var selectedCategory: ShippingLabelHazmatCategory?
108

119
@State private var isShowingDetailView = false
1210

13-
init(isHazardous: Binding<Bool>,
14-
selectedCategory: Binding<ShippingLabelHazmatCategory?>,
11+
init(selectedCategory: Binding<ShippingLabelHazmatCategory?>,
1512
enabled: Bool) {
16-
self._isHazardous = isHazardous
1713
self._selectedCategory = selectedCategory
1814
self.enabled = enabled
1915
}
2016

2117
var body: some View {
22-
Button(action: {
23-
isShowingDetailView = true
24-
}) {
25-
AdaptiveStack {
26-
Text(Localization.hazmatLabel)
27-
.bodyStyle()
28-
Spacer()
29-
Text(isHazardous ? Localization.yes : Localization.no)
30-
.secondaryBodyStyle()
31-
Image(uiImage: .chevronImage)
32-
.secondaryBodyStyle()
33-
.renderedIf(enabled)
18+
VStack {
19+
Button(action: {
20+
isShowingDetailView = true
21+
}) {
22+
AdaptiveStack {
23+
Text(Localization.hazmatLabel)
24+
.bodyStyle()
25+
Spacer()
26+
Text(selectedCategory != nil ? Localization.yes : Localization.no)
27+
.secondaryBodyStyle()
28+
Image(uiImage: .chevronImage)
29+
.secondaryBodyStyle()
30+
.renderedIf(enabled)
31+
}
32+
}
33+
.buttonStyle(.plain)
34+
.disabled(!enabled)
35+
36+
if let category = selectedCategory {
37+
Text(category.localizedName)
38+
.captionStyle()
39+
.frame(maxWidth: .infinity, alignment: .leading)
40+
.multilineTextAlignment(.leading)
41+
.padding(Layout.categoryPadding)
42+
.background(
43+
Color(.quaternarySystemFill)
44+
.clipShape(RoundedRectangle(cornerSize: .init(width: Layout.backgroundRadius,
45+
height: Layout.backgroundRadius)))
46+
)
3447
}
35-
.padding(.vertical, Layout.verticalPadding)
3648
}
37-
.buttonStyle(.plain)
38-
.disabled(!enabled)
49+
.padding(.vertical, Layout.verticalPadding)
3950
.sheet(isPresented: $isShowingDetailView) {
40-
WooShippingHazmatDetailView(isHazardous: isHazardous,
41-
selectedCategory: selectedCategory)
51+
WooShippingHazmatDetailView(selectedCategory: selectedCategory) { selectedCategory in
52+
self.selectedCategory = selectedCategory
53+
}
4254
}
4355
}
4456
}
@@ -47,6 +59,7 @@ private extension WooShippingHazmatRow {
4759
enum Layout {
4860
static let backgroundRadius: CGFloat = 8
4961
static let verticalPadding: CGFloat = 24
62+
static let categoryPadding: CGFloat = 16
5063
}
5164

5265
enum Localization {
@@ -67,8 +80,7 @@ private extension WooShippingHazmatRow {
6780
}
6881

6982
#Preview {
70-
WooShippingHazmatRow(isHazardous: .constant(false),
71-
selectedCategory: .constant(nil),
83+
WooShippingHazmatRow(selectedCategory: .constant(nil),
7284
enabled: true)
7385
.padding()
7486
}

WooCommerce/Classes/ViewRelated/Orders/Order Details/Shipping Labels/WooShipping Create Shipping Labels/WooShippingCreateLabelsView.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ struct WooShippingCreateLabelsView: View {
6060
}
6161
}
6262
.safeAreaInset(edge: .bottom) {
63-
if viewModel.state == .ready {
63+
if viewModel.state == .ready && viewModel.hazmatNotice == nil {
6464
expandableBottomSheet
6565
}
6666
}
@@ -92,6 +92,7 @@ struct WooShippingCreateLabelsView: View {
9292
WooShippingCustomsForm(viewModel: viewModel.customsFormViewModel)
9393
}
9494
.notice($viewModel.labelPurchaseErrorNotice, autoDismiss: false)
95+
.notice($viewModel.hazmatNotice)
9596
}
9697
}
9798
}
@@ -110,8 +111,7 @@ private extension WooShippingCreateLabelsView {
110111

111112
WooShippingItems(viewModel: viewModel.items)
112113

113-
WooShippingHazmatRow(isHazardous: $viewModel.containsHazardousMaterials,
114-
selectedCategory: $viewModel.hazmatCategory,
114+
WooShippingHazmatRow(selectedCategory: $viewModel.hazmatCategory,
115115
enabled: !viewModel.canViewLabel)
116116

117117
WooShippingCustomsRow(informationIsCompleted: viewModel.customsInformationIsCompleted,

WooCommerce/Classes/ViewRelated/Orders/Order Details/Shipping Labels/WooShipping Create Shipping Labels/WooShippingCreateLabelsViewModel.swift

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ final class WooShippingCreateLabelsViewModel: ObservableObject {
2121
private var subscriptions: Set<AnyCancellable> = []
2222
private var debounceDuration: Double = 1
2323

24-
@Published var containsHazardousMaterials = false
2524
@Published var hazmatCategory: ShippingLabelHazmatCategory?
25+
@Published var hazmatNotice: Notice?
2626

2727
@Published var labelPurchaseErrorNotice: Notice?
2828

@@ -229,6 +229,7 @@ final class WooShippingCreateLabelsViewModel: ObservableObject {
229229
observeSelectedPackage()
230230
observeForLabelRates()
231231
observeForCustomsForm()
232+
observeHAZMATChanges()
232233
Task {
233234
await loadRequiredData()
234235
}
@@ -571,6 +572,23 @@ private extension WooShippingCreateLabelsViewModel {
571572
.store(in: &subscriptions)
572573
}
573574

575+
func observeHAZMATChanges() {
576+
$hazmatCategory
577+
.dropFirst()
578+
.scan((nil, nil)) { (previous: (current: ShippingLabelHazmatCategory?,
579+
previous: ShippingLabelHazmatCategory?),
580+
newValue: ShippingLabelHazmatCategory?) in
581+
return (current: newValue, previous: previous.current)
582+
}
583+
.map { [weak self] (newValue, oldValue) in
584+
let noticeTitle = newValue != nil ? Localization.hazmatSet : Localization.hazmatRemoved
585+
return Notice(title: noticeTitle, actionTitle: Localization.undo, actionHandler: {
586+
self?.hazmatCategory = oldValue
587+
})
588+
}
589+
.assign(to: &$hazmatNotice)
590+
}
591+
574592
func observeForCustomsForm() {
575593
$selectedOriginAddress.combineLatest($destinationAddress)
576594
.map { (originAddress, destinationAddress) -> Bool in
@@ -633,7 +651,7 @@ private extension WooShippingCreateLabelsViewModel {
633651
height: Double(packageData.height) ?? 0,
634652
weight: weight,
635653
isLetter: WooShippingPackageType(rawValue: packageData.packageType) == .envelope,
636-
hazmatCategory: nil, // Hazmat support will be added in a future milestone
654+
hazmatCategory: hazmatCategory?.rawValue,
637655
customsForm: customsForm)
638656
}
639657
}
@@ -697,6 +715,24 @@ private extension WooShippingCreateLabelsViewModel {
697715
value: "Retry",
698716
comment: "Button to retry label purchase when an error occurs")
699717
}
718+
719+
static let hazmatSet = NSLocalizedString(
720+
"wooShipping.createLabels.hazmatSet",
721+
value: "Hazardous materials category set",
722+
comment: "Notice when a hazardous materials category is set on the shipping label creation screen"
723+
)
724+
725+
static let hazmatRemoved = NSLocalizedString(
726+
"wooShipping.createLabels.hazmatRemoved",
727+
value: "Remove hazardous materials category",
728+
comment: "Notice when a hazardous materials category is removed on the shipping label creation screen"
729+
)
730+
731+
static let undo = NSLocalizedString(
732+
"wooShipping.createLabels.undo",
733+
value: "Undo",
734+
comment: "Button to undo a change on the shipping label creation screen"
735+
)
700736
}
701737
}
702738

WooCommerce/WooCommerceTests/ViewRelated/Shipping Label/WooShipping Create Shipping Labels/WooShippingCreateLabelsViewModelTests.swift

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -743,6 +743,41 @@ final class WooShippingCreateLabelsViewModelTests: XCTestCase {
743743
XCTAssertFalse(viewModel.isPurchasingLabel)
744744
}
745745

746+
func test_purchaseLabel_sets_hazmat_category_correctly() {
747+
// Given
748+
var encodedHazmat: [String: Any]?
749+
let stores = MockStoresManager(sessionManager: .testingInstance)
750+
let viewModel = WooShippingCreateLabelsViewModel(order: Order.fake().copy(shippingAddress: Address.fake()),
751+
selectedOriginAddress: WooShippingOriginAddress.fake(),
752+
selectedPackage: samplePackageData(),
753+
selectedRate: sampleSelectedRate(),
754+
stores: stores)
755+
stores.whenReceivingAction(ofType: WooShippingAction.self) { action in
756+
switch action {
757+
case let .purchaseShippingLabel(_, _, _, _, package, _, _, _, completion):
758+
encodedHazmat = package.encodedHazmat()
759+
completion(.success(ShippingLabel.fake()))
760+
case let .loadLabelRates(_, _, _, _, packages, completion):
761+
completion(packages, .success([]))
762+
case .loadAccountSettings(_, let completion):
763+
completion(.success(self.settings))
764+
case .loadPackages, .loadOriginAddresses, .verifyDestinationAddress, .loadConfig:
765+
break
766+
default:
767+
XCTFail("Unexpected action: \(action)")
768+
}
769+
}
770+
771+
// When
772+
viewModel.hazmatCategory = .class3
773+
viewModel.purchaseLabel()
774+
775+
// Then
776+
let shipmentDetails = encodedHazmat?["shipment_0"] as? [String: Any]
777+
XCTAssertEqual(shipmentDetails?["isHazmat"] as? Bool, true)
778+
XCTAssertEqual(shipmentDetails?["category"] as? String, ShippingLabelHazmatCategory.class3.rawValue)
779+
}
780+
746781
func test_selectPackage_sets_selectedPackage_with_package_data() {
747782
// Given
748783
let viewModel = WooShippingCreateLabelsViewModel(order: Order.fake())
@@ -924,6 +959,20 @@ final class WooShippingCreateLabelsViewModelTests: XCTestCase {
924959
// Then
925960
XCTAssertNotNil(viewModel.addressToEdit)
926961
}
962+
963+
func test_hazmatNotice_is_updated_after_setting_new_hazmat_category() {
964+
// Given
965+
let viewModel = WooShippingCreateLabelsViewModel(order: Order.fake())
966+
XCTAssertNil(viewModel.hazmatNotice)
967+
968+
// When
969+
viewModel.hazmatCategory = .class1
970+
971+
// Then
972+
waitUntil {
973+
viewModel.hazmatNotice != nil
974+
}
975+
}
927976
}
928977

929978
private extension WooShippingCreateLabelsViewModelTests {

0 commit comments

Comments
 (0)