Skip to content

Commit 16d4466

Browse files
committed
Implement booking cancelling on the UI
1 parent 5439eda commit 16d4466

File tree

2 files changed

+72
-13
lines changed

2 files changed

+72
-13
lines changed

WooCommerce/Classes/ViewModels/Booking Details/BookingDetailsViewModel.swift

Lines changed: 52 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,39 @@ extension BookingDetailsViewModel {
262262
}
263263
}
264264

265+
/// Cancel booking
266+
extension BookingDetailsViewModel {
267+
var isBookingCancellable: Bool {
268+
let ineligibleStatuses: [BookingStatus] = [.cancelled, .complete, .unknown]
269+
return !ineligibleStatuses.contains(booking.bookingStatus)
270+
}
271+
272+
@MainActor
273+
func cancelBooking() async throws {
274+
try await withCheckedThrowingContinuation { (continuation: CheckedContinuation<Void, Error>) in
275+
stores.dispatch(BookingAction.cancelBooking(siteID: booking.siteID, bookingID: booking.bookingID) { error in
276+
if let error {
277+
continuation.resume(throwing: error)
278+
} else {
279+
continuation.resume(returning: ())
280+
}
281+
})
282+
}
283+
}
284+
285+
func displayBookingCancellationErrorNotice(onRetry: @escaping () -> Void) {
286+
let text = String.localizedStringWithFormat(
287+
Localization.bookingCancellationFailedMessage,
288+
booking.bookingID
289+
)
290+
self.notice = Notice(
291+
message: text,
292+
feedbackType: .error,
293+
actionTitle: Localization.retryActionTitle
294+
) { onRetry() }
295+
}
296+
}
297+
265298
private extension BookingDetailsViewModel {
266299
@MainActor
267300
func fetchResource() async -> BookingResource? {
@@ -302,22 +335,17 @@ private extension BookingDetailsViewModel {
302335

303336
extension BookingDetailsViewModel {
304337
var cancellationAlertMessage: String {
305-
let productName = booking.orderInfo?.productInfo?.name ?? ""
338+
let productName = booking.productName ?? ""
339+
let customerName = booking.customerName
306340

307-
let customerName: String = {
308-
guard let address = booking.orderInfo?.customerInfo?.billingAddress else {
309-
return ""
310-
}
311-
return [address.firstName, address.lastName]
312-
.compactMap { $0 }
313-
.joined(separator: " ")
314-
}()
341+
guard productName.isNotEmpty, customerName.isNotEmpty else {
342+
return Localization.cancelBookingAlertGenericMessage
343+
}
315344

316345
let date = booking.startDate.formatted(
317346
date: .long,
318347
time: .shortened
319348
)
320-
321349
return String(
322350
format: Localization.cancelBookingAlertMessage,
323351
customerName,
@@ -390,6 +418,12 @@ private extension BookingDetailsViewModel {
390418
comment: "Message for the booking cancellation confirmation alert. %1$@ is customer name, %2$@ is product name, %3$@ is booking date."
391419
)
392420

421+
static let cancelBookingAlertGenericMessage = NSLocalizedString(
422+
"BookingDetailsView.cancelation.alert.genericMessage",
423+
value: "Are you sure you want to cancel this booking?",
424+
comment: "Generic message for the booking cancellation confirmation alert."
425+
)
426+
393427
static let bookingAttendanceStatusUpdateFailedMessage = NSLocalizedString(
394428
"BookingDetailsView.attendanceStatus.updateFailed.message",
395429
value: "Unable to change attendance status of Booking #%1$d",
@@ -398,6 +432,14 @@ private extension BookingDetailsViewModel {
398432
+ "Parameters: %1$d - Booking number"
399433
)
400434

435+
static let bookingCancellationFailedMessage = NSLocalizedString(
436+
"BookingDetailsView.cancellation.failureMessage",
437+
value: "Unable to cancel Booking #%1$d",
438+
comment: "Content of error presented when cancelling a Booking fails. "
439+
+ "It reads: Unable cancel Booking #{Booking number}. "
440+
+ "Parameters: %1$d - Booking number"
441+
)
442+
401443
static let retryActionTitle = NSLocalizedString(
402444
"BookingDetailsView.retry.action",
403445
value: "Retry",

WooCommerce/Classes/ViewRelated/Bookings/Booking Details/BookingDetailsView.swift

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ struct BookingDetailsView: View {
77
@State private var showingOptions = false
88
@State private var showingStatusSheet = false
99
@State private var showingCancelAlert = false
10+
@State private var cancellingBooking = false
1011
@State private var notice: Notice?
1112

1213
@ObservedObject private var viewModel: BookingDetailsViewModel
@@ -67,8 +68,9 @@ struct BookingDetailsView: View {
6768
viewModel.navigateToOrderDetails()
6869
}
6970
Button(Localization.cancelBookingAction, role: .destructive) {
70-
print("On cancel booking tap")
71+
showingCancelAlert = true
7172
}
73+
.renderedIf(viewModel.isBookingCancellable)
7274
}
7375
}
7476
}
@@ -91,7 +93,7 @@ struct BookingDetailsView: View {
9193
) {
9294
Button(Localization.cancelBookingAlertCancelAction, role: .cancel) {}
9395
Button(Localization.cancelBookingAlertConfirmAction, role: .destructive) {
94-
print("On cancel booking confirmation tap")
96+
cancelBooking()
9597
}
9698
} message: {
9799
Text(viewModel.cancellationAlertMessage)
@@ -187,8 +189,9 @@ private extension BookingDetailsView {
187189
} label: {
188190
Text(Localization.cancelBooking)
189191
}
190-
.buttonStyle(SecondaryButtonStyle())
192+
.buttonStyle(SecondaryLoadingButtonStyle(isLoading: cancellingBooking))
191193
.padding(.vertical, Layout.contentVerticalPadding)
194+
.renderedIf(viewModel.isBookingCancellable)
192195
}
193196
}
194197

@@ -254,6 +257,20 @@ private extension BookingDetailsView {
254257
}
255258
}
256259

260+
extension BookingDetailsView {
261+
func cancelBooking() {
262+
Task { @MainActor in
263+
cancellingBooking = true
264+
do {
265+
try await viewModel.cancelBooking()
266+
} catch {
267+
viewModel.displayBookingCancellationErrorNotice(onRetry: cancelBooking)
268+
}
269+
cancellingBooking = false
270+
}
271+
}
272+
}
273+
257274
extension BookingDetailsView {
258275
enum Localization {
259276
static let markAsPaid = NSLocalizedString(

0 commit comments

Comments
 (0)