Skip to content

Commit

Permalink
[Shipping labels] Display origin address selection sheet from "Ship f…
Browse files Browse the repository at this point in the history
…rom" address (#14824)
  • Loading branch information
rachelmcr authored Jan 9, 2025
2 parents f456995 + a3611c5 commit 93a514a
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ final class WooShippingOriginAddressListViewModel: ObservableObject {
let addresses: [WooShippingOriginAddress]
@Published private(set) var selectedAddressID: String?

/// Closure (set externally) called when an address is selected.
var onSelect: ((WooShippingOriginAddress) -> Void)?

init(addresses: [WooShippingOriginAddress],
selectedAddressID: String? = nil) {
self.addresses = addresses
Expand All @@ -22,6 +25,7 @@ final class WooShippingOriginAddressListViewModel: ObservableObject {
return
}
selectedAddressID = address.id
onSelect?(address)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ struct WooShippingCreateLabelsView: View {
/// Whether the shipment details bottom sheet is expanded.
@State private var isShipmentDetailsExpanded = false

/// Whether the origin address list sheet is presented.
@State private var isOriginAddressListPresented = false

var body: some View {
NavigationStack {
ScrollView {
Expand Down Expand Up @@ -111,10 +114,20 @@ struct WooShippingCreateLabelsView: View {
HStack(alignment: .firstTextBaseline, spacing: Layout.bottomSheetSpacing) {
Text(Localization.BottomSheet.shipFrom)
.trackSize(size: $shipmentDetailsShipFromSize)
Text(viewModel.originAddress)
.lineLimit(1)
.truncationMode(.tail)
.frame(maxWidth: .infinity, alignment: .leading)
Button {
isOriginAddressListPresented = true
} label: {
HStack {
Text(viewModel.originAddress)
.lineLimit(1)
.truncationMode(.tail)
.frame(maxWidth: .infinity, alignment: .leading)
Image(systemName: "ellipsis")
.frame(width: Layout.ellipsisWidth)
.bold()
}
}
.buttonStyle(TextButtonStyle())
}
.padding(Layout.bottomSheetPadding)
Divider()
Expand Down Expand Up @@ -157,6 +170,11 @@ struct WooShippingCreateLabelsView: View {
.padding([.bottom, .horizontal], Layout.bottomSheetPadding)
}
.ignoresSafeArea(edges: .horizontal)
.sheet(isPresented: $isOriginAddressListPresented) {
WooShippingOriginAddressListView(viewModel: viewModel.originAddresses)
.presentationDetents([.medium, .large])
.presentationDragIndicator(.visible)
}
}
.shippingWeightUnit(viewModel.weightUnit)
.shippingDimensionsUnit(viewModel.dimensionsUnit)
Expand Down Expand Up @@ -271,6 +289,7 @@ private extension WooShippingCreateLabelsView {
static let iconSize: CGFloat = 32
static let rowHeight: CGFloat = 32
static let chevronSize: CGFloat = 30
static let ellipsisWidth: CGFloat = 22
static let bottomSheetSpacing: CGFloat = 16
static let bottomSheetPadding: CGFloat = 16
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ final class WooShippingCreateLabelsViewModel: ObservableObject {
private let currencyFormatter: CurrencyFormatter
private let order: Order
private let itemsDataSource: WooShippingItemsDataSource
private var originAddresses: [WooShippingOriginAddress] = []
private let destinationAddress: ShippingLabelAddress?
private let stores: StoresManager
private var subscriptions: Set<AnyCancellable> = []
Expand Down Expand Up @@ -52,6 +51,9 @@ final class WooShippingCreateLabelsViewModel: ObservableObject {
/// Selected shipping rate when creating a shipping label.
@Published private var selectedRate: WooShippingSelectedRate?

/// View model for a list of origin addresses to ship from.
private(set) var originAddresses = WooShippingOriginAddressListViewModel(addresses: [])

/// Address to ship from (store address).
@Published private var selectedOriginAddress: WooShippingOriginAddress?

Expand Down Expand Up @@ -242,8 +244,12 @@ private extension WooShippingCreateLabelsViewModel {
guard let self else { return }
switch result {
case .success(let addresses):
originAddresses = addresses
selectedOriginAddress = addresses.first(where: \.defaultAddress)
originAddresses = WooShippingOriginAddressListViewModel(addresses: addresses,
selectedAddressID: selectedOriginAddress?.id)
originAddresses.onSelect = { [weak self] selectedAddress in
self?.selectedOriginAddress = selectedAddress
}
case .failure(let error):
DDLogError("⛔️ Error loading origin addresses for Woo Shipping labels: \(error)")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,24 @@ final class WooShippingCreateLabelsViewModelTests: XCTestCase {
XCTAssertEqual(viewModel.shippingRates.count, 1)
}

func test_origin_addresses_fetched_and_converted_to_originAddresses_view_model() {
// Given
let originAddress = WooShippingOriginAddress.fake().copy(id: "default", defaultAddress: true)
let stores = MockStoresManager(sessionManager: .testingInstance)
stores.whenReceivingAction(ofType: WooShippingAction.self) { action in
if case let .loadOriginAddresses(_, completion) = action {
completion(.success([originAddress]))
}
}

// When
let viewModel = WooShippingCreateLabelsViewModel(order: Order.fake(), stores: stores)

// Then
XCTAssertEqual(viewModel.originAddresses.addresses.count, 1)
XCTAssertEqual(viewModel.originAddresses.selectedAddressID, originAddress.id)
}

func test_default_origin_address_fetched_and_converted_to_formatted_originAddress() {
// Given
let originAddresses = [WooShippingOriginAddress.fake(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,22 @@ final class WooShippingOriginAddressListViewModelTests: XCTestCase {
XCTAssertEqual(viewModel.selectedAddressID, addressToSelect.id)
}

func test_select_calls_onSelect_closure() {
// Given
let addressToSelect = WooShippingOriginAddress.fake().copy(id: "1")
let addresses = [addressToSelect, WooShippingOriginAddress.fake().copy(id: "2")]
let viewModel = WooShippingOriginAddressListViewModel(addresses: addresses, selectedAddressID: nil)

// When
let selectedAddress = waitFor { promise in
viewModel.onSelect = { address in
promise(address)
}
viewModel.select(addressToSelect)
}

// Then
XCTAssertEqual(selectedAddress, addressToSelect)
}

}

0 comments on commit 93a514a

Please sign in to comment.