Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion RELEASE-NOTES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

23.4
-----

- [*] Order details: Fixes broken country selector navigation and "Non editable banner" width. [https://github.com/woocommerce/woocommerce-ios/pull/16171]

23.3
-----
Expand Down
221 changes: 120 additions & 101 deletions WooCommerce/Classes/ViewRelated/Orders/Order Creation/OrderForm.swift
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,8 @@ struct OrderForm: View {

@State private var shouldShowGiftCardForm = false

@State private var bannerWidth: CGFloat = 0

@Environment(\.adaptiveModalContainerPresentationStyle) var presentationStyle

@Environment(\.horizontalSizeClass) var horizontalSizeClass
Expand All @@ -239,6 +241,12 @@ struct OrderForm: View {
viewModel.saveInFlightOrderNotes()
viewModel.saveInflightCustomerDetails()
}
.background(
GeometryReader { geometryProxy in
Color.clear
.preference(key: WidthPreferenceKey.self, value: geometryProxy.size.width)
}
)
}

private func updateSelectionSyncApproach(for presentationStyle: AdaptiveModalContainerPresentationStyle?) {
Expand All @@ -251,137 +259,139 @@ struct OrderForm: View {
}

@ViewBuilder private func orderFormSummary(_ presentProductSelector: (() -> Void)?) -> some View {
GeometryReader { geometry in
ScrollViewReader { scroll in
ScrollView {
Group {
VStack(spacing: Layout.noSpacing) {
Spacer(minLength: Layout.sectionSpacing)
ScrollViewReader { scroll in
ScrollView {
Group {
VStack(spacing: Layout.noSpacing) {
Spacer(minLength: Layout.sectionSpacing)

if viewModel.shouldShowNonEditableIndicators {
Group {
Divider() // Needed because `NonEditableOrderBanner` does not have a top divider
NonEditableOrderBanner(width: geometry.size.width)
NonEditableOrderBanner(width: bannerWidth)
}
.renderedIf(viewModel.shouldShowNonEditableIndicators)

Group {
OrderStatusSection(viewModel: viewModel, topDivider: !viewModel.shouldShowNonEditableIndicators)
Spacer(minLength: Layout.sectionSpacing)
}
.renderedIf(flow == .editing)

ProductsSection(scroll: scroll,
flow: flow,
presentProductSelector: presentProductSelector,
viewModel: viewModel,
navigationButtonID: $navigationButtonID,
isLoading: isLoading)
.disabled(viewModel.shouldShowNonEditableIndicators)
}

Group {
Divider()
Spacer(minLength: Layout.sectionSpacing)
Divider()
}
.renderedIf(viewModel.shouldSplitProductsAndCustomAmountsSections)
Group {
OrderStatusSection(viewModel: viewModel, topDivider: !viewModel.shouldShowNonEditableIndicators)
Spacer(minLength: Layout.sectionSpacing)
}
.renderedIf(flow == .editing)

OrderCustomAmountsSection(viewModel: viewModel, sectionViewModel: viewModel.customAmountsSectionViewModel)
.disabled(viewModel.shouldShowNonEditableIndicators)
ProductsSection(scroll: scroll,
flow: flow,
presentProductSelector: presentProductSelector,
viewModel: viewModel,
navigationButtonID: $navigationButtonID,
isLoading: isLoading)
.disabled(viewModel.shouldShowNonEditableIndicators)

Group {
Divider()

Spacer(minLength: Layout.sectionSpacing)
Divider()
}
.renderedIf(viewModel.shouldSplitProductsAndCustomAmountsSections)

Group {
OrderShippingSection(viewModel: viewModel.shippingLineViewModel)
.disabled(viewModel.shouldShowNonEditableIndicators)
Spacer(minLength: Layout.sectionSpacing)
}
.renderedIf(viewModel.shippingLineViewModel.shippingLineRows.isNotEmpty)

Group {
OrderCouponSectionView(viewModel: viewModel, couponViewModel: viewModel.couponLineViewModel)
.disabled(viewModel.shouldShowNonEditableIndicators)
Spacer(minLength: Layout.sectionSpacing)
}
.renderedIf(viewModel.couponLineViewModel.couponLineRows.isNotEmpty)

AddOrderComponentsSection(
viewModel: viewModel.paymentDataViewModel,
shippingLineViewModel: viewModel.shippingLineViewModel,
couponLineViewModel: viewModel.couponLineViewModel,
shouldShowCouponsInfoTooltip: $shouldShowInformationalCouponTooltip,
shouldShowGiftCardForm: $shouldShowGiftCardForm)
.addingTopAndBottomDividers()
OrderCustomAmountsSection(viewModel: viewModel, sectionViewModel: viewModel.customAmountsSectionViewModel)
.disabled(viewModel.shouldShowNonEditableIndicators)

Divider()

Spacer(minLength: Layout.sectionSpacing)

Group {
OrderShippingSection(viewModel: viewModel.shippingLineViewModel)
.disabled(viewModel.shouldShowNonEditableIndicators)
Spacer(minLength: Layout.sectionSpacing)
}
.renderedIf(viewModel.shippingLineViewModel.shippingLineRows.isNotEmpty)

VStack(spacing: Layout.noSpacing) {
Group {
NewTaxRateSection(text: viewModel.taxRateRowText) {
viewModel.onSetNewTaxRateTapped()
switch viewModel.taxRateRowAction {
case .storedTaxRateSheet:
shouldShowStoredTaxRateSheet = true
viewModel.onStoredTaxRateBottomSheetAppear()
case .taxSelector:
shouldShowNewTaxRateSelector = true
}
Group {
OrderCouponSectionView(viewModel: viewModel, couponViewModel: viewModel.couponLineViewModel)
.disabled(viewModel.shouldShowNonEditableIndicators)
Spacer(minLength: Layout.sectionSpacing)
}
.renderedIf(viewModel.couponLineViewModel.couponLineRows.isNotEmpty)

AddOrderComponentsSection(
viewModel: viewModel.paymentDataViewModel,
shippingLineViewModel: viewModel.shippingLineViewModel,
couponLineViewModel: viewModel.couponLineViewModel,
shouldShowCouponsInfoTooltip: $shouldShowInformationalCouponTooltip,
shouldShowGiftCardForm: $shouldShowGiftCardForm)
.addingTopAndBottomDividers()
.disabled(viewModel.shouldShowNonEditableIndicators)

Spacer(minLength: Layout.sectionSpacing)
}

}
.sheet(isPresented: $shouldShowNewTaxRateSelector) {
NewTaxRateSelectorView(viewModel: NewTaxRateSelectorViewModel(siteID: viewModel.siteID,
onTaxRateSelected: { taxRate in
viewModel.onTaxRateSelected(taxRate)
}),
taxEducationalDialogViewModel: viewModel.paymentDataViewModel.taxEducationalDialogViewModel,
onDismissWpAdminWebView: viewModel.paymentDataViewModel.onDismissWpAdminWebViewClosure,
storeSelectedTaxRate: viewModel.shouldStoreTaxRateInSelectorByDefault)
}
.sheet(isPresented: $shouldShowStoredTaxRateSheet) {
if #available(iOS 16.0, *) {
storedTaxRateBottomSheetContent
.presentationDetents([.medium])
.presentationDragIndicator(.visible)
} else {
storedTaxRateBottomSheetContent
}
VStack(spacing: Layout.noSpacing) {
Group {
NewTaxRateSection(text: viewModel.taxRateRowText) {
viewModel.onSetNewTaxRateTapped()
switch viewModel.taxRateRowAction {
case .storedTaxRateSheet:
shouldShowStoredTaxRateSheet = true
viewModel.onStoredTaxRateBottomSheetAppear()
case .taxSelector:
shouldShowNewTaxRateSelector = true
}

Spacer(minLength: Layout.sectionSpacing)
}
.renderedIf(viewModel.shouldShowNewTaxRateSection)

Divider()

if ServiceLocator.featureFlagService.isFeatureFlagEnabled(.subscriptionsInOrderCreationCustomers) {
OrderCustomerSection(viewModel: viewModel.customerSectionViewModel)
} else {
LegacyOrderCustomerSection(viewModel: viewModel, addressFormViewModel: viewModel.addressFormViewModel)
.sheet(isPresented: $shouldShowNewTaxRateSelector) {
NewTaxRateSelectorView(viewModel: NewTaxRateSelectorViewModel(siteID: viewModel.siteID,
onTaxRateSelected: { taxRate in
viewModel.onTaxRateSelected(taxRate)
}),
taxEducationalDialogViewModel: viewModel.paymentDataViewModel.taxEducationalDialogViewModel,
onDismissWpAdminWebView: viewModel.paymentDataViewModel.onDismissWpAdminWebViewClosure,
storeSelectedTaxRate: viewModel.shouldStoreTaxRateInSelectorByDefault)
}
.sheet(isPresented: $shouldShowStoredTaxRateSheet) {
if #available(iOS 16.0, *) {
storedTaxRateBottomSheetContent
.presentationDetents([.medium])
.presentationDragIndicator(.visible)
} else {
storedTaxRateBottomSheetContent
}
}

Group {
Divider()
Spacer(minLength: Layout.sectionSpacing)
}
.renderedIf(viewModel.shouldShowNewTaxRateSection)

Spacer(minLength: Layout.sectionSpacing)
Divider()

Divider()
}
.renderedIf(viewModel.shouldSplitCustomerAndNoteSections)
if ServiceLocator.featureFlagService.isFeatureFlagEnabled(.subscriptionsInOrderCreationCustomers) {
OrderCustomerSection(viewModel: viewModel.customerSectionViewModel)
} else {
LegacyOrderCustomerSection(viewModel: viewModel, addressFormViewModel: viewModel.addressFormViewModel)
}

Group {
Divider()

CustomerNoteSection(viewModel: viewModel)
Spacer(minLength: Layout.sectionSpacing)

Divider()
}
.renderedIf(viewModel.shouldSplitCustomerAndNoteSections)

CustomerNoteSection(viewModel: viewModel)

Divider()
}
.disabled(viewModel.disabled)
}
.accessibilityIdentifier(Accessibility.orderFormScrollViewIdentifier)
.background(Color(.listBackground).ignoresSafeArea())
.ignoresSafeArea(.container, edges: [.horizontal])
.disabled(viewModel.disabled)
}
.accessibilityIdentifier(Accessibility.orderFormScrollViewIdentifier)
.background(Color(.listBackground).ignoresSafeArea())
.ignoresSafeArea(.container, edges: [.horizontal])
}
.onPreferenceChange(WidthPreferenceKey.self) { newWidth in
bannerWidth = newWidth
}
.safeAreaInset(edge: .bottom) {
VStack {
Expand Down Expand Up @@ -863,6 +873,15 @@ private extension OrderForm {
}
}

private extension OrderForm {
struct WidthPreferenceKey: PreferenceKey {
static var defaultValue: CGFloat = .zero
static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
value = max(value, nextValue())
}
}
}

struct OrderForm_Previews: PreviewProvider {
static var previews: some View {
let viewModel = EditableOrderViewModel(siteID: 123)
Expand Down