Skip to content

Commit

Permalink
[Woo POS][Design System] Use page header component in cart/cash/recei…
Browse files Browse the repository at this point in the history
…pt views (#15171)
  • Loading branch information
jaclync authored Feb 19, 2025
2 parents 06b9022 + 3964af5 commit aae0ac7
Show file tree
Hide file tree
Showing 6 changed files with 120 additions and 175 deletions.
57 changes: 14 additions & 43 deletions WooCommerce/Classes/POS/Presentation/CartView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,38 +18,18 @@ struct CartView: View {

var body: some View {
VStack {
DynamicHStack(spacing: Constants.cartHeaderSpacing) {
HStack(spacing: Constants.cartHeaderElementSpacing) {
backAddMoreButton
.disabled(shouldPreventCartEditing)
.shimmering(active: shouldPreventCartEditing)

HStack {
Text(Localization.cartTitle)
.font(Constants.primaryFont)
POSPageHeaderView(title: Localization.cartTitle,
backButtonConfiguration: backButtonConfiguration,
trailingContent: {
DynamicHStack(horizontalAlignment: .trailing, verticalAlignment: .center, spacing: Constants.cartHeaderElementSpacing) {
if let itemsInCartLabel = viewHelper.itemsInCartLabel(for: posModel.cart.count) {
Text(itemsInCartLabel)
.font(Constants.itemsFont)
.lineLimit(1)
.minimumScaleFactor(0.5)
.dynamicTypeSize(...DynamicTypeSize.accessibility2)
.foregroundColor(.posOnSurface)
.accessibilityAddTraits(.isHeader)

Spacer()

if let itemsInCartLabel = viewHelper.itemsInCartLabel(for: posModel.cart.count) {
Text(itemsInCartLabel)
.font(Constants.itemsFont)
.lineLimit(1)
.minimumScaleFactor(0.5)
.dynamicTypeSize(...DynamicTypeSize.accessibility2)
.foregroundColor(Color.posOnSurfaceVariantLowest)
}
.foregroundColor(Color.posOnSurfaceVariantLowest)
}
.accessibilityElement(children: .combine)
}

HStack {
Spacer()
.renderedIf(dynamicTypeSize.isAccessibilitySize)

Button {
posModel.removeAllItemsFromCart()
Expand All @@ -59,10 +39,7 @@ struct CartView: View {
.buttonStyle(POSOutlinedButtonStyle(size: .extraSmall))
.renderedIf(shouldShowClearCartButton)
}
}
.frame(maxWidth: .infinity, alignment: .leading)
.padding(.horizontal, POSHeaderLayoutConstants.sectionHorizontalPadding)
.padding(.vertical, POSHeaderLayoutConstants.sectionVerticalPadding)
})
.if(shouldApplyHeaderBottomShadow, transform: { $0.applyBottomShadow(backgroundColor: backgroundColor) })

if posModel.cart.isNotEmpty {
Expand Down Expand Up @@ -210,7 +187,6 @@ private extension CartView {
static let scrollViewCoordinateSpaceIdentifier: String = "CartScrollView"
static let emptyViewImageTextSpacing: CGFloat = 30 // This should be 40 by designs, but the overlay technique means we have to tweak it
static let cartHeaderSpacing: CGFloat = 8
static let backButtonSymbol: String = "chevron.backward"
static let cartHeaderElementSpacing: CGFloat = 16
static let cartAnimation: Animation = .spring(duration: 0.2)
static let checkoutButtonVerticalPadding: CGFloat = 16
Expand Down Expand Up @@ -253,21 +229,16 @@ private extension CartView {
.buttonStyle(POSFilledButtonStyle(size: .normal))
}

@ViewBuilder
var backAddMoreButton: some View {
var backButtonConfiguration: POSPageHeaderBackButtonConfiguration? {
switch posModel.orderStage {
case .building:
EmptyView()
return nil
case .finalizing:
Button {
let state: POSPageHeaderBackButtonConfiguration.State = shouldPreventCartEditing ? .shimmering : .enabled
return .init(state: state, action: {
ServiceLocator.analytics.track(.pointOfSaleBackToCartTapped)
posModel.addMoreToCart()
} label: {
Image(systemName: Constants.backButtonSymbol)
.font(.posBodyLargeBold)
.dynamicTypeSize(...DynamicTypeSize.accessibility2)
.foregroundColor(.posOnSurface)
}
})
}
}

Expand Down
2 changes: 1 addition & 1 deletion WooCommerce/Classes/POS/Presentation/ItemListView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ private extension ItemListView {
static let bannerVerticalPadding: CGFloat = 26
static let bannerTextSpacing: CGFloat = 4
static let bannerTitleSpacing: CGFloat = 8
static let infoIconInset: EdgeInsets = .init(top: 8, leading: 6, bottom: 8, trailing: 6)
static let infoIconInset: EdgeInsets = .init(top: 0, leading: 6, bottom: 0, trailing: 6)
static let iconPadding: CGFloat = 26
static let itemListPadding: CGFloat = 16
static let bannerCardPadding: CGFloat = 16
Expand Down
119 changes: 44 additions & 75 deletions WooCommerce/Classes/POS/Presentation/PointOfSaleCollectCashView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,63 +28,60 @@ struct PointOfSaleCollectCashView: View {
var body: some View {
ScrollView {
VStack(alignment: .center, spacing: conditionalPadding(8)) {
HStack {
POSPageHeaderView(title: Localization.backNavigationTitle,
subtitle: formattedOrderTotal,
backButtonConfiguration: .init(state: isLoading ? .disabled: .enabled,
action: {
Task { @MainActor in
await posModel.cancelCashPayment()
isTextFieldFocused = false
}
}))

VStack(alignment: .center, spacing: conditionalPadding(8)) {
FormattableAmountTextField(viewModel: textFieldViewModel, style: .pos)
.focused($isTextFieldFocused)
.dynamicTypeSize(...DynamicTypeSize.accessibility1)
.onSubmit {
Task { @MainActor in
await submitCashAmount()
}
}
.onChange(of: textFieldViewModel.amount) { newValue in
textFieldAmountInput = newValue
updateChangeDueMessage()
}

if let changeDue = changeDueMessage {
Text(changeDue)
.font(.posBodyLargeRegular())
.foregroundColor(.posOnSurfaceVariantHighest)
}

if let errorMessage = errorMessage {
Text(errorMessage)
.font(POSFontStyle.posBodyLargeRegular())
.foregroundColor(.red)
.padding(.bottom, Constants.errorMessagePadding)
}

Button(action: {
Task { @MainActor in
await posModel.cancelCashPayment()
isTextFieldFocused = false
await submitCashAmount()
}
}, label: {
navigationHeader
Text(Localization.markPaymentCompletedButtonTitle)
})
.disabled(isLoading)
Spacer()
.renderedIf(!dynamicTypeSize.isAccessibilitySize)
}

FormattableAmountTextField(viewModel: textFieldViewModel, style: .pos)
.focused($isTextFieldFocused)
.buttonStyle(POSFilledButtonStyle(size: .normal, isLoading: isLoading))
.frame(maxWidth: .infinity)
.dynamicTypeSize(...DynamicTypeSize.accessibility1)
.onSubmit {
Task { @MainActor in
await submitCashAmount()
}
}
.onChange(of: textFieldViewModel.amount) { newValue in
textFieldAmountInput = newValue
updateChangeDueMessage()
}

if let changeDue = changeDueMessage {
Text(changeDue)
.font(.posBodyLargeRegular())
.foregroundColor(.posOnSurfaceVariantHighest)
}
.disabled(isLoading)

if let errorMessage = errorMessage {
Text(errorMessage)
.font(POSFontStyle.posBodyLargeRegular())
.foregroundColor(.red)
.padding(.bottom, Constants.errorMessagePadding)
Spacer()
}

Button(action: {
Task { @MainActor in
await submitCashAmount()
}
}, label: {
Text(Localization.markPaymentCompletedButtonTitle)
})
.buttonStyle(POSFilledButtonStyle(size: .normal, isLoading: isLoading))
.frame(maxWidth: .infinity)
.dynamicTypeSize(...DynamicTypeSize.accessibility1)
.disabled(isLoading)

Spacer()
.padding([.horizontal, .bottom])
}
.background(backgroundColor)
.padding(.top, conditionalPadding(Constants.navigationHeaderTopPadding))
.padding([.horizontal, .bottom])
.animation(.easeInOut, value: errorMessage)
.animation(.easeInOut, value: changeDueMessage)
.onChange(of: textFieldAmountInput) { _ in
Expand All @@ -98,30 +95,6 @@ struct PointOfSaleCollectCashView: View {
}
}

@available(iOS 17.0, *)
private extension PointOfSaleCollectCashView {
@ViewBuilder
var navigationHeader: some View {
HStack(alignment: .top) {
Image(systemName: "chevron.backward")
.font(.posBodyLargeBold)
.dynamicTypeSize(...DynamicTypeSize.accessibility2)
DynamicVStack(horizontalAlignment: .leading, spacing: Constants.navigationButtonSpacing) {
Text(Localization.backNavigationTitle)
.font(.posHeading)
.accessibilityAddTraits(.isHeader)
if dynamicTypeSize.isAccessibilitySize {
Spacer()
}
Text(formattedOrderTotal)
.font(.posBodyLargeRegular())
}
.padding(.top, -Constants.navigationButtonSpacing)
}
.foregroundColor(navigationForegroundColor)
}
}

@available(iOS 17.0, *)
private extension PointOfSaleCollectCashView {
private func submitCashAmount() async {
Expand Down Expand Up @@ -171,10 +144,6 @@ private extension PointOfSaleCollectCashView {
.posSurface
}

private var navigationForegroundColor: Color {
isLoading ? .posDisabledContainer : .primary
}

enum Localization {
static let backNavigationTitle = NSLocalizedString(
"pointOfSale.cashview.back.navigation.title",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ struct POSPageHeaderView<TrailingContent: View>: View {
.lineLimit(1)
.minimumScaleFactor(0.5)
.dynamicTypeSize(...DynamicTypeSize.accessibility2)
.foregroundColor(.posOnSurfaceVariantHighest)
.foregroundColor(.posOnSurface)
}
}

Expand All @@ -85,7 +85,7 @@ struct POSPageHeaderView<TrailingContent: View>: View {
.foregroundColor(configuration.state == .disabled ? .posOnSurfaceVariantLowest : .posOnSurface)
.padding(.horizontal, Constants.backButtonHorizontalPadding)
}
.disabled(configuration.state == .disabled)
.disabled(configuration.state == .disabled || configuration.state == .shimmering)
.if(configuration.state == .shimmering) { view in
view.shimmering()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,61 +18,51 @@ struct POSSendReceiptView: View {

var body: some View {
VStack(alignment: .center, spacing: conditionalPadding(8)) {
HStack {
Button(action: {
withAnimation {
isShowingSendReceiptView = false
isTextFieldFocused = false
}
}, label: {
HStack {
Image(systemName: "chevron.backward")
Text(Localization.emailReceiptNavigationText)
POSPageHeaderView(title: Localization.emailReceiptNavigationText,
backButtonConfiguration: .init(state: isLoading ? .disabled: .enabled,
action: {
withAnimation {
isShowingSendReceiptView = false
isTextFieldFocused = false
}
}))

VStack(alignment: .center, spacing: conditionalPadding(8)) {
TextField(Localization.textfieldPlaceholder, text: $textFieldInput)
.dynamicTypeSize(...DynamicTypeSize.accessibility1)
.keyboardType(.emailAddress)
.textInputAutocapitalization(.never)
.autocorrectionDisabled()
.multilineTextAlignment(.center)
.font(POSFontStyle.posBodyXLarge)
.focused()
.focused($isTextFieldFocused)
.padding()
.onSubmit {
sendReceipt()
}
.font(.posHeading)
.foregroundColor(.posOnSurface)
.dynamicTypeSize(...DynamicTypeSize.accessibility3)
.accessibilityAddTraits(.isHeader)
})
Spacer()
}
.buttonStyle(.plain)
.disabled(isLoading)

TextField(Localization.textfieldPlaceholder, text: $textFieldInput)
.dynamicTypeSize(...DynamicTypeSize.accessibility1)
.keyboardType(.emailAddress)
.textInputAutocapitalization(.never)
.autocorrectionDisabled()
.multilineTextAlignment(.center)
.font(POSFontStyle.posBodyXLarge)
.focused()
.focused($isTextFieldFocused)
.padding()
.onSubmit {
sendReceipt()
if let errorMessage = errorMessage {
Text(errorMessage)
.font(POSFontStyle.posBodyLargeRegular())
.foregroundColor(.red)
.padding(.bottom, Constants.errorMessagePadding)
}

if let errorMessage = errorMessage {
Text(errorMessage)
.font(POSFontStyle.posBodyLargeRegular())
.foregroundColor(.red)
.padding(.bottom, Constants.errorMessagePadding)
}

Button(action: {
sendReceipt()
}, label: {
Text(Localization.buttonTitle)
})
.buttonStyle(POSFilledButtonStyle(size: .normal, isLoading: isLoading))
.dynamicTypeSize(...DynamicTypeSize.accessibility3)
.frame(maxWidth: .infinity)
.disabled(isLoading)
Button(action: {
sendReceipt()
}, label: {
Text(Localization.buttonTitle)
})
.buttonStyle(POSFilledButtonStyle(size: .normal, isLoading: isLoading))
.dynamicTypeSize(...DynamicTypeSize.accessibility3)
.frame(maxWidth: .infinity)
.disabled(isLoading)

Spacer()
Spacer()
}
.padding([.horizontal, .bottom])
}
.padding([.horizontal, .bottom])
.animation(.easeInOut, value: errorMessage)
.onChange(of: textFieldInput) { _ in
errorMessage = nil
Expand Down
Loading

0 comments on commit aae0ac7

Please sign in to comment.