Skip to content

Commit 6831645

Browse files
committed
Track barcode scanning success and failed events in barcode observer
- Calculate scan duration time in GameControllerBarcodeParser - Track the events in GameControllerBarcodeObserver
1 parent febfd48 commit 6831645

File tree

2 files changed

+86
-6
lines changed

2 files changed

+86
-6
lines changed

WooCommerce/Classes/POS/Presentation/Barcode Scanning/GameControllerBarcodeObserver.swift

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,12 @@ final class GameControllerBarcodeObserver {
8888
cleanupKeyboard()
8989

9090
coalescedKeyboard = keyboard
91-
barcodeParser = GameControllerBarcodeParser(configuration: configuration, onScan: onScan)
91+
barcodeParser = GameControllerBarcodeParser(
92+
configuration: configuration,
93+
onScan: { [weak self] result in
94+
self?.handleScanResult(result)
95+
}
96+
)
9297

9398
keyboard.keyboardInput?.keyChangedHandler = { [weak self] _, _, keyCode, pressed in
9499
guard let self = self else { return }
@@ -112,4 +117,29 @@ final class GameControllerBarcodeObserver {
112117
barcodeParser = nil
113118
isShiftPressed = false
114119
}
120+
121+
private func handleScanResult(_ result: HIDBarcodeParserResult) {
122+
trackAnalyticsEvent(for: result)
123+
onScan(result.asResult)
124+
}
125+
126+
private func trackAnalyticsEvent(for result: HIDBarcodeParserResult) {
127+
switch result {
128+
case .success(let barcode, let scanDurationMs):
129+
ServiceLocator.analytics.track(
130+
event: WooAnalyticsEvent.PointOfSale.barcodeScanningSuccess(
131+
scanDurationMs: scanDurationMs,
132+
barcodeLength: barcode.count
133+
)
134+
)
135+
case .failure(let error, let scanDurationMs):
136+
ServiceLocator.analytics.track(
137+
event: WooAnalyticsEvent.PointOfSale.barcodeScanningFailed(
138+
scanDurationMs: scanDurationMs,
139+
barcodeLength: error.barcode.count,
140+
failReason: error.analyticsReason
141+
)
142+
)
143+
}
144+
}
115145
}

WooCommerce/Classes/POS/Presentation/Barcode Scanning/GameControllerBarcodeParser.swift

Lines changed: 55 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,16 @@ final class GameControllerBarcodeParser {
88
/// Configuration for the barcode scanner
99
let configuration: HIDBarcodeParserConfiguration
1010
/// Callback that is triggered when a barcode scan completes (success or failure)
11-
let onScan: (Result<String, Error>) -> Void
11+
let onScan: (HIDBarcodeParserResult) -> Void
1212

1313
private let timeProvider: TimeProvider
1414

1515
private var buffer = ""
1616
private var lastKeyPressTime: Date?
17+
private var scanStartTime: Date?
1718

1819
init(configuration: HIDBarcodeParserConfiguration,
19-
onScan: @escaping (Result<String, Error>) -> Void,
20+
onScan: @escaping (HIDBarcodeParserResult) -> Void,
2021
timeProvider: TimeProvider = DefaultTimeProvider()) {
2122
self.configuration = configuration
2223
self.onScan = onScan
@@ -41,6 +42,12 @@ final class GameControllerBarcodeParser {
4142
} else {
4243
guard !excludedKeyCodes.contains(keyCode) else { return }
4344
checkForTimeoutBetweenKeystrokes()
45+
46+
// Start timing on first character
47+
if buffer.isEmpty {
48+
scanStartTime = timeProvider.now()
49+
}
50+
4451
buffer.append(character)
4552
}
4653
}
@@ -69,7 +76,10 @@ final class GameControllerBarcodeParser {
6976

7077
if let lastTime = lastKeyPressTime,
7178
currentTime.timeIntervalSince(lastTime) > configuration.maximumInterCharacterTime {
72-
onScan(.failure(HIDBarcodeParserError.timedOut(barcode: buffer)))
79+
let scanDurationMs = calculateScanDurationMs()
80+
let result = HIDBarcodeParserResult.failure(error: HIDBarcodeParserError.timedOut(barcode: buffer), scanDurationMs: scanDurationMs)
81+
82+
onScan(result)
7383
resetScan()
7484
}
7585

@@ -175,14 +185,24 @@ final class GameControllerBarcodeParser {
175185
private func resetScan() {
176186
buffer = ""
177187
lastKeyPressTime = nil
188+
scanStartTime = nil
189+
}
190+
191+
private func calculateScanDurationMs() -> Int {
192+
guard let startTime = scanStartTime else { return 0 }
193+
return Int(timeProvider.now().timeIntervalSince(startTime) * 1000)
178194
}
179195

180196
private func processScan() {
181197
checkForTimeoutBetweenKeystrokes()
198+
let scanDurationMs = calculateScanDurationMs()
199+
182200
if buffer.count >= configuration.minimumBarcodeLength {
183-
onScan(.success(buffer))
201+
let result = HIDBarcodeParserResult.success(barcode: buffer, scanDurationMs: scanDurationMs)
202+
onScan(result)
184203
} else {
185-
onScan(.failure(HIDBarcodeParserError.scanTooShort(barcode: buffer)))
204+
let result = HIDBarcodeParserResult.failure(error: HIDBarcodeParserError.scanTooShort(barcode: buffer), scanDurationMs: scanDurationMs)
205+
onScan(result)
186206
}
187207
resetScan()
188208
}
@@ -211,4 +231,34 @@ struct HIDBarcodeParserConfiguration {
211231
enum HIDBarcodeParserError: Error {
212232
case scanTooShort(barcode: String)
213233
case timedOut(barcode: String)
234+
235+
var analyticsReason: String {
236+
switch self {
237+
case .scanTooShort:
238+
return "too_short"
239+
case .timedOut:
240+
return "no_terminator"
241+
}
242+
}
243+
244+
var barcode: String {
245+
switch self {
246+
case .scanTooShort(let barcode), .timedOut(let barcode):
247+
return barcode
248+
}
249+
}
250+
}
251+
252+
enum HIDBarcodeParserResult {
253+
case success(barcode: String, scanDurationMs: Int)
254+
case failure(error: HIDBarcodeParserError, scanDurationMs: Int)
255+
256+
var asResult: Result<String, Error> {
257+
switch self {
258+
case .success(let barcode, _):
259+
return .success(barcode)
260+
case .failure(let error, _):
261+
return .failure(error)
262+
}
263+
}
214264
}

0 commit comments

Comments
 (0)