fix: add hasCompleted guard to prevent double-completion race condition
If a user confirms cash payment AND a beacon triggers auto-complete at the same time, two completion calls could fire. Added @State hasCompleted flag that gates all completion paths (manual complete, beacon auto-complete, and cash collection). Resets on error/cancel so user can retry. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
db7fe31b8a
commit
54923ba341
1 changed files with 10 additions and 1 deletions
|
|
@ -28,6 +28,7 @@ struct TaskDetailScreen: View {
|
|||
@State private var showCancelOrderAlert = false
|
||||
@State private var isCancelingOrder = false
|
||||
@State private var taskAccepted = false // Track if task was just accepted
|
||||
@State private var hasCompleted = false // Guard against double-completion
|
||||
@State private var customerAvatarUrl: String? // Fetched separately if not in task details
|
||||
|
||||
// Rating dialog
|
||||
|
|
@ -100,6 +101,7 @@ struct TaskDetailScreen: View {
|
|||
} else if result == "cancelled" || result == "error" {
|
||||
autoCompleting = false
|
||||
beaconDetected = false
|
||||
hasCompleted = false
|
||||
beaconScanner?.resetSamples()
|
||||
beaconScanner?.startScanning()
|
||||
}
|
||||
|
|
@ -629,6 +631,7 @@ struct TaskDetailScreen: View {
|
|||
}
|
||||
.buttonStyle(.borderedProminent)
|
||||
.tint(Color(red: 0.13, green: 0.55, blue: 0.13))
|
||||
.disabled(hasCompleted)
|
||||
} else {
|
||||
Button { showCompleteAlert = true } label: {
|
||||
Label("Complete Task", systemImage: "checkmark.circle.fill")
|
||||
|
|
@ -637,6 +640,7 @@ struct TaskDetailScreen: View {
|
|||
}
|
||||
.buttonStyle(.borderedProminent)
|
||||
.tint(.green)
|
||||
.disabled(hasCompleted)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -723,9 +727,10 @@ struct TaskDetailScreen: View {
|
|||
let scanner = BeaconScanner(
|
||||
targetServicePointId: servicePointId,
|
||||
onBeaconDetected: { [self] _ in
|
||||
if !beaconDetected && !autoCompleting {
|
||||
if !beaconDetected && !autoCompleting && !hasCompleted {
|
||||
beaconDetected = true
|
||||
autoCompleting = true
|
||||
hasCompleted = true
|
||||
beaconScanner?.stopScanning()
|
||||
showAutoCompleteDialog = true
|
||||
}
|
||||
|
|
@ -760,6 +765,8 @@ struct TaskDetailScreen: View {
|
|||
}
|
||||
|
||||
private func completeTask() {
|
||||
guard !hasCompleted else { return }
|
||||
hasCompleted = true
|
||||
Task {
|
||||
do {
|
||||
try await APIService.shared.completeTask(taskId: task.taskId)
|
||||
|
|
@ -768,9 +775,11 @@ struct TaskDetailScreen: View {
|
|||
if case .ratingRequired = apiError {
|
||||
showRatingDialog = true
|
||||
} else {
|
||||
hasCompleted = false
|
||||
self.error = apiError.localizedDescription
|
||||
}
|
||||
} catch {
|
||||
hasCompleted = false
|
||||
self.error = error.localizedDescription
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue