Skip to content

Commit aae0ac7

Browse files
authored
[Woo POS][Design System] Use page header component in cart/cash/receipt views (#15171)
2 parents 06b9022 + 3964af5 commit aae0ac7

File tree

6 files changed

+120
-175
lines changed

6 files changed

+120
-175
lines changed

WooCommerce/Classes/POS/Presentation/CartView.swift

Lines changed: 14 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -18,38 +18,18 @@ struct CartView: View {
1818

1919
var body: some View {
2020
VStack {
21-
DynamicHStack(spacing: Constants.cartHeaderSpacing) {
22-
HStack(spacing: Constants.cartHeaderElementSpacing) {
23-
backAddMoreButton
24-
.disabled(shouldPreventCartEditing)
25-
.shimmering(active: shouldPreventCartEditing)
26-
27-
HStack {
28-
Text(Localization.cartTitle)
29-
.font(Constants.primaryFont)
21+
POSPageHeaderView(title: Localization.cartTitle,
22+
backButtonConfiguration: backButtonConfiguration,
23+
trailingContent: {
24+
DynamicHStack(horizontalAlignment: .trailing, verticalAlignment: .center, spacing: Constants.cartHeaderElementSpacing) {
25+
if let itemsInCartLabel = viewHelper.itemsInCartLabel(for: posModel.cart.count) {
26+
Text(itemsInCartLabel)
27+
.font(Constants.itemsFont)
3028
.lineLimit(1)
3129
.minimumScaleFactor(0.5)
3230
.dynamicTypeSize(...DynamicTypeSize.accessibility2)
33-
.foregroundColor(.posOnSurface)
34-
.accessibilityAddTraits(.isHeader)
35-
36-
Spacer()
37-
38-
if let itemsInCartLabel = viewHelper.itemsInCartLabel(for: posModel.cart.count) {
39-
Text(itemsInCartLabel)
40-
.font(Constants.itemsFont)
41-
.lineLimit(1)
42-
.minimumScaleFactor(0.5)
43-
.dynamicTypeSize(...DynamicTypeSize.accessibility2)
44-
.foregroundColor(Color.posOnSurfaceVariantLowest)
45-
}
31+
.foregroundColor(Color.posOnSurfaceVariantLowest)
4632
}
47-
.accessibilityElement(children: .combine)
48-
}
49-
50-
HStack {
51-
Spacer()
52-
.renderedIf(dynamicTypeSize.isAccessibilitySize)
5333

5434
Button {
5535
posModel.removeAllItemsFromCart()
@@ -59,10 +39,7 @@ struct CartView: View {
5939
.buttonStyle(POSOutlinedButtonStyle(size: .extraSmall))
6040
.renderedIf(shouldShowClearCartButton)
6141
}
62-
}
63-
.frame(maxWidth: .infinity, alignment: .leading)
64-
.padding(.horizontal, POSHeaderLayoutConstants.sectionHorizontalPadding)
65-
.padding(.vertical, POSHeaderLayoutConstants.sectionVerticalPadding)
42+
})
6643
.if(shouldApplyHeaderBottomShadow, transform: { $0.applyBottomShadow(backgroundColor: backgroundColor) })
6744

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

256-
@ViewBuilder
257-
var backAddMoreButton: some View {
232+
var backButtonConfiguration: POSPageHeaderBackButtonConfiguration? {
258233
switch posModel.orderStage {
259234
case .building:
260-
EmptyView()
235+
return nil
261236
case .finalizing:
262-
Button {
237+
let state: POSPageHeaderBackButtonConfiguration.State = shouldPreventCartEditing ? .shimmering : .enabled
238+
return .init(state: state, action: {
263239
ServiceLocator.analytics.track(.pointOfSaleBackToCartTapped)
264240
posModel.addMoreToCart()
265-
} label: {
266-
Image(systemName: Constants.backButtonSymbol)
267-
.font(.posBodyLargeBold)
268-
.dynamicTypeSize(...DynamicTypeSize.accessibility2)
269-
.foregroundColor(.posOnSurface)
270-
}
241+
})
271242
}
272243
}
273244

WooCommerce/Classes/POS/Presentation/ItemListView.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ private extension ItemListView {
180180
static let bannerVerticalPadding: CGFloat = 26
181181
static let bannerTextSpacing: CGFloat = 4
182182
static let bannerTitleSpacing: CGFloat = 8
183-
static let infoIconInset: EdgeInsets = .init(top: 8, leading: 6, bottom: 8, trailing: 6)
183+
static let infoIconInset: EdgeInsets = .init(top: 0, leading: 6, bottom: 0, trailing: 6)
184184
static let iconPadding: CGFloat = 26
185185
static let itemListPadding: CGFloat = 16
186186
static let bannerCardPadding: CGFloat = 16

WooCommerce/Classes/POS/Presentation/PointOfSaleCollectCashView.swift

Lines changed: 44 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -28,63 +28,60 @@ struct PointOfSaleCollectCashView: View {
2828
var body: some View {
2929
ScrollView {
3030
VStack(alignment: .center, spacing: conditionalPadding(8)) {
31-
HStack {
31+
POSPageHeaderView(title: Localization.backNavigationTitle,
32+
subtitle: formattedOrderTotal,
33+
backButtonConfiguration: .init(state: isLoading ? .disabled: .enabled,
34+
action: {
35+
Task { @MainActor in
36+
await posModel.cancelCashPayment()
37+
isTextFieldFocused = false
38+
}
39+
}))
40+
41+
VStack(alignment: .center, spacing: conditionalPadding(8)) {
42+
FormattableAmountTextField(viewModel: textFieldViewModel, style: .pos)
43+
.focused($isTextFieldFocused)
44+
.dynamicTypeSize(...DynamicTypeSize.accessibility1)
45+
.onSubmit {
46+
Task { @MainActor in
47+
await submitCashAmount()
48+
}
49+
}
50+
.onChange(of: textFieldViewModel.amount) { newValue in
51+
textFieldAmountInput = newValue
52+
updateChangeDueMessage()
53+
}
54+
55+
if let changeDue = changeDueMessage {
56+
Text(changeDue)
57+
.font(.posBodyLargeRegular())
58+
.foregroundColor(.posOnSurfaceVariantHighest)
59+
}
60+
61+
if let errorMessage = errorMessage {
62+
Text(errorMessage)
63+
.font(POSFontStyle.posBodyLargeRegular())
64+
.foregroundColor(.red)
65+
.padding(.bottom, Constants.errorMessagePadding)
66+
}
67+
3268
Button(action: {
3369
Task { @MainActor in
34-
await posModel.cancelCashPayment()
35-
isTextFieldFocused = false
70+
await submitCashAmount()
3671
}
3772
}, label: {
38-
navigationHeader
73+
Text(Localization.markPaymentCompletedButtonTitle)
3974
})
40-
.disabled(isLoading)
41-
Spacer()
42-
.renderedIf(!dynamicTypeSize.isAccessibilitySize)
43-
}
44-
45-
FormattableAmountTextField(viewModel: textFieldViewModel, style: .pos)
46-
.focused($isTextFieldFocused)
75+
.buttonStyle(POSFilledButtonStyle(size: .normal, isLoading: isLoading))
76+
.frame(maxWidth: .infinity)
4777
.dynamicTypeSize(...DynamicTypeSize.accessibility1)
48-
.onSubmit {
49-
Task { @MainActor in
50-
await submitCashAmount()
51-
}
52-
}
53-
.onChange(of: textFieldViewModel.amount) { newValue in
54-
textFieldAmountInput = newValue
55-
updateChangeDueMessage()
56-
}
57-
58-
if let changeDue = changeDueMessage {
59-
Text(changeDue)
60-
.font(.posBodyLargeRegular())
61-
.foregroundColor(.posOnSurfaceVariantHighest)
62-
}
78+
.disabled(isLoading)
6379

64-
if let errorMessage = errorMessage {
65-
Text(errorMessage)
66-
.font(POSFontStyle.posBodyLargeRegular())
67-
.foregroundColor(.red)
68-
.padding(.bottom, Constants.errorMessagePadding)
80+
Spacer()
6981
}
70-
71-
Button(action: {
72-
Task { @MainActor in
73-
await submitCashAmount()
74-
}
75-
}, label: {
76-
Text(Localization.markPaymentCompletedButtonTitle)
77-
})
78-
.buttonStyle(POSFilledButtonStyle(size: .normal, isLoading: isLoading))
79-
.frame(maxWidth: .infinity)
80-
.dynamicTypeSize(...DynamicTypeSize.accessibility1)
81-
.disabled(isLoading)
82-
83-
Spacer()
82+
.padding([.horizontal, .bottom])
8483
}
8584
.background(backgroundColor)
86-
.padding(.top, conditionalPadding(Constants.navigationHeaderTopPadding))
87-
.padding([.horizontal, .bottom])
8885
.animation(.easeInOut, value: errorMessage)
8986
.animation(.easeInOut, value: changeDueMessage)
9087
.onChange(of: textFieldAmountInput) { _ in
@@ -98,30 +95,6 @@ struct PointOfSaleCollectCashView: View {
9895
}
9996
}
10097

101-
@available(iOS 17.0, *)
102-
private extension PointOfSaleCollectCashView {
103-
@ViewBuilder
104-
var navigationHeader: some View {
105-
HStack(alignment: .top) {
106-
Image(systemName: "chevron.backward")
107-
.font(.posBodyLargeBold)
108-
.dynamicTypeSize(...DynamicTypeSize.accessibility2)
109-
DynamicVStack(horizontalAlignment: .leading, spacing: Constants.navigationButtonSpacing) {
110-
Text(Localization.backNavigationTitle)
111-
.font(.posHeading)
112-
.accessibilityAddTraits(.isHeader)
113-
if dynamicTypeSize.isAccessibilitySize {
114-
Spacer()
115-
}
116-
Text(formattedOrderTotal)
117-
.font(.posBodyLargeRegular())
118-
}
119-
.padding(.top, -Constants.navigationButtonSpacing)
120-
}
121-
.foregroundColor(navigationForegroundColor)
122-
}
123-
}
124-
12598
@available(iOS 17.0, *)
12699
private extension PointOfSaleCollectCashView {
127100
private func submitCashAmount() async {
@@ -171,10 +144,6 @@ private extension PointOfSaleCollectCashView {
171144
.posSurface
172145
}
173146

174-
private var navigationForegroundColor: Color {
175-
isLoading ? .posDisabledContainer : .primary
176-
}
177-
178147
enum Localization {
179148
static let backNavigationTitle = NSLocalizedString(
180149
"pointOfSale.cashview.back.navigation.title",

WooCommerce/Classes/POS/Presentation/Reusable Views/POSPageHeaderView.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ struct POSPageHeaderView<TrailingContent: View>: View {
6161
.lineLimit(1)
6262
.minimumScaleFactor(0.5)
6363
.dynamicTypeSize(...DynamicTypeSize.accessibility2)
64-
.foregroundColor(.posOnSurfaceVariantHighest)
64+
.foregroundColor(.posOnSurface)
6565
}
6666
}
6767

@@ -85,7 +85,7 @@ struct POSPageHeaderView<TrailingContent: View>: View {
8585
.foregroundColor(configuration.state == .disabled ? .posOnSurfaceVariantLowest : .posOnSurface)
8686
.padding(.horizontal, Constants.backButtonHorizontalPadding)
8787
}
88-
.disabled(configuration.state == .disabled)
88+
.disabled(configuration.state == .disabled || configuration.state == .shimmering)
8989
.if(configuration.state == .shimmering) { view in
9090
view.shimmering()
9191
}

WooCommerce/Classes/POS/Presentation/Reusable Views/POSSendReceiptView.swift

Lines changed: 39 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -18,61 +18,51 @@ struct POSSendReceiptView: View {
1818

1919
var body: some View {
2020
VStack(alignment: .center, spacing: conditionalPadding(8)) {
21-
HStack {
22-
Button(action: {
23-
withAnimation {
24-
isShowingSendReceiptView = false
25-
isTextFieldFocused = false
26-
}
27-
}, label: {
28-
HStack {
29-
Image(systemName: "chevron.backward")
30-
Text(Localization.emailReceiptNavigationText)
21+
POSPageHeaderView(title: Localization.emailReceiptNavigationText,
22+
backButtonConfiguration: .init(state: isLoading ? .disabled: .enabled,
23+
action: {
24+
withAnimation {
25+
isShowingSendReceiptView = false
26+
isTextFieldFocused = false
27+
}
28+
}))
29+
30+
VStack(alignment: .center, spacing: conditionalPadding(8)) {
31+
TextField(Localization.textfieldPlaceholder, text: $textFieldInput)
32+
.dynamicTypeSize(...DynamicTypeSize.accessibility1)
33+
.keyboardType(.emailAddress)
34+
.textInputAutocapitalization(.never)
35+
.autocorrectionDisabled()
36+
.multilineTextAlignment(.center)
37+
.font(POSFontStyle.posBodyXLarge)
38+
.focused()
39+
.focused($isTextFieldFocused)
40+
.padding()
41+
.onSubmit {
42+
sendReceipt()
3143
}
32-
.font(.posHeading)
33-
.foregroundColor(.posOnSurface)
34-
.dynamicTypeSize(...DynamicTypeSize.accessibility3)
35-
.accessibilityAddTraits(.isHeader)
36-
})
37-
Spacer()
38-
}
39-
.buttonStyle(.plain)
40-
.disabled(isLoading)
4144

42-
TextField(Localization.textfieldPlaceholder, text: $textFieldInput)
43-
.dynamicTypeSize(...DynamicTypeSize.accessibility1)
44-
.keyboardType(.emailAddress)
45-
.textInputAutocapitalization(.never)
46-
.autocorrectionDisabled()
47-
.multilineTextAlignment(.center)
48-
.font(POSFontStyle.posBodyXLarge)
49-
.focused()
50-
.focused($isTextFieldFocused)
51-
.padding()
52-
.onSubmit {
53-
sendReceipt()
45+
if let errorMessage = errorMessage {
46+
Text(errorMessage)
47+
.font(POSFontStyle.posBodyLargeRegular())
48+
.foregroundColor(.red)
49+
.padding(.bottom, Constants.errorMessagePadding)
5450
}
5551

56-
if let errorMessage = errorMessage {
57-
Text(errorMessage)
58-
.font(POSFontStyle.posBodyLargeRegular())
59-
.foregroundColor(.red)
60-
.padding(.bottom, Constants.errorMessagePadding)
61-
}
62-
63-
Button(action: {
64-
sendReceipt()
65-
}, label: {
66-
Text(Localization.buttonTitle)
67-
})
68-
.buttonStyle(POSFilledButtonStyle(size: .normal, isLoading: isLoading))
69-
.dynamicTypeSize(...DynamicTypeSize.accessibility3)
70-
.frame(maxWidth: .infinity)
71-
.disabled(isLoading)
52+
Button(action: {
53+
sendReceipt()
54+
}, label: {
55+
Text(Localization.buttonTitle)
56+
})
57+
.buttonStyle(POSFilledButtonStyle(size: .normal, isLoading: isLoading))
58+
.dynamicTypeSize(...DynamicTypeSize.accessibility3)
59+
.frame(maxWidth: .infinity)
60+
.disabled(isLoading)
7261

73-
Spacer()
62+
Spacer()
63+
}
64+
.padding([.horizontal, .bottom])
7465
}
75-
.padding([.horizontal, .bottom])
7666
.animation(.easeInOut, value: errorMessage)
7767
.onChange(of: textFieldInput) { _ in
7868
errorMessage = nil

0 commit comments

Comments
 (0)