Skip to content

Commit 0ffb257

Browse files
authored
[Woo POS][Barcodes] Set up flow test failure screen (#15903)
2 parents 954ea45 + 8dd20c3 commit 0ffb257

File tree

3 files changed

+167
-40
lines changed

3 files changed

+167
-40
lines changed

WooCommerce/Classes/POS/Presentation/Barcode Scanner Setup/PointOfSaleBarcodeScannerSetupFlow.swift

Lines changed: 111 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -7,46 +7,49 @@ class PointOfSaleBarcodeScannerSetupFlow {
77
private let scannerType: PointOfSaleBarcodeScannerType
88
private let onComplete: () -> Void
99
private let onBackToSelection: () -> Void
10-
private var currentStepIndex: Int = 0
10+
private var flowSteps: [PointOfSaleBarcodeScannerStepID: PointOfSaleBarcodeScannerSetupStep] = [:]
11+
private var currentStepKey: PointOfSaleBarcodeScannerStepID = .start
1112

1213
init(scannerType: PointOfSaleBarcodeScannerType,
1314
onComplete: @escaping () -> Void,
1415
onBackToSelection: @escaping () -> Void) {
1516
self.scannerType = scannerType
1617
self.onComplete = onComplete
1718
self.onBackToSelection = onBackToSelection
19+
self.flowSteps = createFlowSteps(for: scannerType)
1820
}
1921

2022
var currentStep: PointOfSaleBarcodeScannerSetupStep? {
21-
steps[safe: currentStepIndex]
23+
flowSteps[currentStepKey]
2224
}
2325

2426
var isComplete: Bool {
25-
currentStepIndex >= steps.count - 1
27+
currentStepKey == .complete
2628
}
2729

2830
var nextButtonTitle: String {
2931
isComplete ? Localization.doneButtonTitle : Localization.nextButtonTitle
3032
}
3133

3234
func nextStep() {
33-
if currentStepIndex < steps.count - 1 {
34-
currentStepIndex += 1
35-
} else {
36-
onComplete()
37-
}
35+
transition(to: .next)
3836
}
3937

4038
func previousStep() {
41-
if currentStepIndex > 0 {
42-
currentStepIndex -= 1
43-
} else {
44-
onBackToSelection()
39+
transition(to: .back) { [weak self] in
40+
// If no back transition is defined, go back to selection
41+
self?.onBackToSelection()
4542
}
4643
}
4744

4845
func restartFlow() {
49-
currentStepIndex = 0
46+
currentStepKey = .start
47+
}
48+
49+
// MARK: - Generic Transition Methods
50+
51+
func transition(to transitionType: PointOfSaleBarcodeScannerTransitionType) {
52+
self.transition(to: transitionType, fallback: nil)
5053
}
5154

5255
func getButtonConfiguration() -> PointOfSaleFlowButtonConfiguration {
@@ -64,7 +67,11 @@ class PointOfSaleBarcodeScannerSetupFlow {
6467
primaryButton: PointOfSaleFlowButtonConfiguration.ButtonConfig(
6568
title: nextButtonTitle,
6669
action: { [weak self] in
67-
self?.nextStep()
70+
if self?.isComplete == true {
71+
self?.onComplete()
72+
} else {
73+
self?.nextStep()
74+
}
6875
}
6976
),
7077
secondaryButton: PointOfSaleFlowButtonConfiguration.ButtonConfig(
@@ -76,51 +83,94 @@ class PointOfSaleBarcodeScannerSetupFlow {
7683
)
7784
}
7885

79-
private var steps: [PointOfSaleBarcodeScannerSetupStep] {
86+
// MARK: - Private Methods
87+
88+
private func transition(to transitionType: PointOfSaleBarcodeScannerTransitionType, fallback: (() -> Void)? = nil) {
89+
guard let currentStep = currentStep,
90+
let targetStep = currentStep.transitions[transitionType] else {
91+
fallback?()
92+
return
93+
}
94+
95+
currentStepKey = targetStep
96+
}
97+
98+
private func createFlowSteps(for scannerType: PointOfSaleBarcodeScannerType) -> [PointOfSaleBarcodeScannerStepID: PointOfSaleBarcodeScannerSetupStep] {
8099
switch scannerType {
81100
case .socketS720:
82101
return [
83-
createWelcomeStep(title: "Socket S720 Setup")
102+
.start: createWelcomeStep(title: "Socket S720 Setup")
84103
// TODO: Add more steps for Socket S720 WOOMOB-698
85104
]
86105
case .starBSH20B:
87106
return [
88-
PointOfSaleBarcodeScannerSetupStep(content: {
89-
PointOfSaleBarcodeScannerBarcodeView(
90-
title: String(format: Localization.starSetUpBarcodeStepTitleFormat, scannerType.name),
91-
instruction: Localization.setUpBarcodeStepInstruction,
92-
barcode: .starBsh20SetupBarcode)
93-
}),
94-
PointOfSaleBarcodeScannerSetupStep(content: {
95-
PointOfSaleBarcodeScannerPairingView(scanner: scannerType)
96-
}),
97-
PointOfSaleBarcodeScannerSetupStep(
107+
.start: PointOfSaleBarcodeScannerSetupStep(
108+
content: {
109+
PointOfSaleBarcodeScannerBarcodeView(
110+
title: String(format: Localization.starSetUpBarcodeStepTitleFormat, scannerType.name),
111+
instruction: Localization.setUpBarcodeStepInstruction,
112+
barcode: .starBsh20SetupBarcode)
113+
},
114+
transitions: [
115+
.next: .pairing
116+
]
117+
),
118+
.pairing: PointOfSaleBarcodeScannerSetupStep(
119+
content: {
120+
PointOfSaleBarcodeScannerPairingView(scanner: scannerType)
121+
},
122+
transitions: [
123+
.next: .test,
124+
.back: .start
125+
]
126+
),
127+
.test: PointOfSaleBarcodeScannerSetupStep(
98128
content: {
99129
PointOfSaleBarcodeScannerTestBarcodeView(
100130
scanTester: PointOfSaleBarcodeScannerSetupScanTester(
101131
onTestPass: { [weak self] in
102132
self?.nextStep()
103133
},
104-
onTestFailure: {},
134+
onTestFailure: { [weak self] in
135+
self?.transition(to: .error)
136+
},
105137
barcodeDefinition: .ean13)
106138
)
107139
},
108-
buttonCustomization: PointOfSaleBarcodeScannerBackOnlyButtonCustomization()
140+
buttonCustomization: PointOfSaleBarcodeScannerBackOnlyButtonCustomization(),
141+
transitions: [
142+
.next: .complete,
143+
.error: .testFailed,
144+
.back: .pairing
145+
]
109146
),
110-
PointOfSaleBarcodeScannerSetupStep(
147+
.complete: PointOfSaleBarcodeScannerSetupStep(
111148
content: {
112149
PointOfSaleBarcodeScannerSetupCompleteView()
113-
})
150+
},
151+
transitions: [
152+
.back: .test
153+
]),
154+
.testFailed: PointOfSaleBarcodeScannerSetupStep(
155+
content: {
156+
PointOfSaleBarcodeScannerErrorView()
157+
},
158+
buttonCustomization: PointOfSaleBarcodeScannerErrorButtonCustomization(),
159+
transitions: [
160+
.retry: .start,
161+
.back: .test
162+
]
163+
)
114164
// TODO: Add optional error step and documentation step for Star BSH-20B WOOMOB-696
115165
]
116166
case .tbcScanner:
117167
return [
118-
createWelcomeStep(title: "TBC Scanner Setup")
168+
.start: createWelcomeStep(title: "TBC Scanner Setup")
119169
// TODO: Add more steps for TBC Scanner WOOMOB-699
120170
]
121171
case .other:
122172
return [
123-
PointOfSaleBarcodeScannerSetupStep(
173+
.start: PointOfSaleBarcodeScannerSetupStep(
124174
title: "General Scanner Setup",
125175
content: { BarcodeScannerInformationContent() }
126176
)
@@ -158,6 +208,35 @@ struct PointOfSaleBarcodeScannerBackOnlyButtonCustomization: PointOfSaleBarcodeS
158208
}
159209
}
160210

211+
@available(iOS 17.0, *)
212+
struct PointOfSaleBarcodeScannerErrorButtonCustomization: PointOfSaleBarcodeScannerButtonCustomization {
213+
func customizeButtons(for flow: PointOfSaleBarcodeScannerSetupFlow) -> PointOfSaleFlowButtonConfiguration {
214+
return PointOfSaleFlowButtonConfiguration(
215+
primaryButton: PointOfSaleFlowButtonConfiguration.ButtonConfig(
216+
title: Localization.retryButtonTitle,
217+
action: { flow.transition(to: .retry) }
218+
),
219+
secondaryButton: PointOfSaleFlowButtonConfiguration.ButtonConfig(
220+
title: Localization.backButtonTitle,
221+
action: { flow.transition(to: .back) }
222+
)
223+
)
224+
}
225+
226+
private enum Localization {
227+
static let retryButtonTitle = NSLocalizedString(
228+
"pos.barcodeScannerSetup.error.retry.button.title",
229+
value: "Retry",
230+
comment: "Title for the retry button in barcode scanner setup error step"
231+
)
232+
static let backButtonTitle = NSLocalizedString(
233+
"pos.barcodeScannerSetup.error.back.button.title",
234+
value: "Back",
235+
comment: "Title for the back button in barcode scanner setup error step"
236+
)
237+
}
238+
}
239+
161240
// MARK: - Private Localization Extension
162241
@available(iOS 17.0, *)
163242
private extension PointOfSaleBarcodeScannerSetupFlow {

WooCommerce/Classes/POS/Presentation/Barcode Scanner Setup/PointOfSaleBarcodeScannerSetupModels.swift

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,27 +44,48 @@ enum PointOfSaleBarcodeScannerSetupFlowState {
4444
case setupFlow(PointOfSaleBarcodeScannerType)
4545
}
4646

47+
// MARK: - Step Identifiers
48+
enum PointOfSaleBarcodeScannerStepID: String, CaseIterable {
49+
case start
50+
case setupBarcode1
51+
case setupBarcode2
52+
case pairing
53+
case test
54+
case complete
55+
case testFailed
56+
case information
57+
}
58+
4759
// MARK: - Button Customization Protocol
4860
@available(iOS 17.0, *)
4961
protocol PointOfSaleBarcodeScannerButtonCustomization {
5062
func customizeButtons(for flow: PointOfSaleBarcodeScannerSetupFlow) -> PointOfSaleFlowButtonConfiguration
5163
}
5264

65+
// MARK: - Transition Types
66+
enum PointOfSaleBarcodeScannerTransitionType: Hashable {
67+
case next
68+
case error
69+
case retry
70+
case back
71+
}
72+
5373
// MARK: - Setup Step
5474
@available(iOS 17.0, *)
5575
struct PointOfSaleBarcodeScannerSetupStep {
5676
let title: String
5777
let content: any View
5878
let buttonCustomization: PointOfSaleBarcodeScannerButtonCustomization?
79+
let transitions: [PointOfSaleBarcodeScannerTransitionType: PointOfSaleBarcodeScannerStepID]
5980

60-
init(
61-
title: String = "",
62-
@ViewBuilder content: () -> any View,
63-
buttonCustomization: PointOfSaleBarcodeScannerButtonCustomization? = nil
64-
) {
81+
init(title: String = "",
82+
@ViewBuilder content: () -> any View,
83+
buttonCustomization: PointOfSaleBarcodeScannerButtonCustomization? = nil,
84+
transitions: [PointOfSaleBarcodeScannerTransitionType: PointOfSaleBarcodeScannerStepID] = [:]) {
6585
self.title = title
6686
self.content = content()
6787
self.buttonCustomization = buttonCustomization
88+
self.transitions = transitions
6889
}
6990
}
7091

WooCommerce/Classes/POS/Presentation/Barcode Scanner Setup/PointOfSaleBarcodeScannerSetupStepViews.swift

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ struct PointOfSaleBarcodeScannerBarcodeView: View {
3232
.accessibilityAddTraits(.isHeader)
3333

3434
Text(instruction)
35-
.font(.posBodyMediumRegular())
35+
.font(.posBodyLargeRegular())
3636
.foregroundColor(.posOnSurfaceVariantHighest)
3737
.multilineTextAlignment(.center)
3838
}
@@ -59,7 +59,7 @@ struct PointOfSaleBarcodeScannerPairingView: View {
5959
.accessibilityAddTraits(.isHeader)
6060

6161
Text(instruction)
62-
.font(.posBodyMediumRegular())
62+
.font(.posBodyLargeRegular())
6363
.foregroundColor(.posOnSurfaceVariantHighest)
6464
.multilineTextAlignment(.center)
6565
}
@@ -143,7 +143,7 @@ struct PointOfSaleBarcodeScannerSetupCompleteView: View {
143143
.accessibilityAddTraits(.isHeader)
144144

145145
Text(Localization.instruction)
146-
.font(.posBodyMediumRegular())
146+
.font(.posBodyLargeRegular())
147147
.foregroundColor(.posOnSurfaceVariantHighest)
148148
.multilineTextAlignment(.center)
149149
}
@@ -173,6 +173,33 @@ private extension PointOfSaleBarcodeScannerSetupCompleteView {
173173
}
174174
}
175175

176+
struct PointOfSaleBarcodeScannerErrorView: View {
177+
var body: some View {
178+
VStack(spacing: POSSpacing.xLarge) {
179+
POSErrorXMark()
180+
181+
VStack(alignment: .center, spacing: POSSpacing.small) {
182+
Text(Localization.title)
183+
.font(.posHeadingBold)
184+
.foregroundColor(.posOnSurface)
185+
.accessibilityAddTraits(.isHeader)
186+
187+
Text(Localization.instruction)
188+
.font(.posBodyLargeRegular())
189+
.foregroundColor(.posOnSurfaceVariantHighest)
190+
.multilineTextAlignment(.center)
191+
}
192+
}
193+
.padding(POSSpacing.xLarge)
194+
}
195+
196+
private enum Localization {
197+
static let title = "Scanning issue found"
198+
static let instruction = "Please check the scanner’s manual and reset it \n" +
199+
"to factory settings, then retry the set up flow."
200+
}
201+
}
202+
176203
// MARK: - Button Customizations
177204
@available(iOS 17.0, *)
178205
struct PointOfSaleBarcodeScannerWelcomeButtonCustomization: PointOfSaleBarcodeScannerButtonCustomization {

0 commit comments

Comments
 (0)