Skip to content

Commit b92bafd

Browse files
committed
Simplify note update by staying on the edit screen
1 parent faccab8 commit b92bafd

File tree

5 files changed

+88
-89
lines changed

5 files changed

+88
-89
lines changed

Modules/Sources/Yosemite/Stores/BookingStore.swift

Lines changed: 19 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -347,44 +347,27 @@ private extension BookingStore {
347347
note: String,
348348
onCompletion: @escaping (Error?) -> Void
349349
) {
350-
updateBookingNoteLocally(
351-
siteID: siteID,
352-
bookingID: bookingID,
353-
note: note
354-
) { [weak self] previousNote in
355-
guard let self else {
356-
return onCompletion(UpdateBookingStatusError.undefinedState)
357-
}
358-
359-
Task { @MainActor in
360-
do {
361-
if let remoteBooking = try await self.remote.updateBooking(
362-
from: siteID,
363-
bookingID: bookingID,
364-
attendanceStatus: nil,
365-
bookingStatus: nil,
366-
note: note,
367-
) {
368-
await self.upsertStoredBookingsInBackground(
369-
readOnlyBookings: [remoteBooking],
370-
readOnlyOrders: [],
371-
siteID: siteID
372-
)
350+
Task { @MainActor in
351+
do {
352+
if let remoteBooking = try await self.remote.updateBooking(
353+
from: siteID,
354+
bookingID: bookingID,
355+
attendanceStatus: nil,
356+
bookingStatus: nil,
357+
note: note,
358+
) {
359+
await self.upsertStoredBookingsInBackground(
360+
readOnlyBookings: [remoteBooking],
361+
readOnlyOrders: [],
362+
siteID: siteID
363+
)
373364

374-
onCompletion(nil)
375-
} else {
376-
return onCompletion(UpdateBookingStatusError.missingRemoteBooking)
377-
}
378-
} catch {
379-
/// Revert Optimistic Update
380-
self.updateBookingNoteLocally(
381-
siteID: siteID,
382-
bookingID: bookingID,
383-
note: note
384-
) { _ in
385-
onCompletion(error)
386-
}
365+
onCompletion(nil)
366+
} else {
367+
return onCompletion(UpdateBookingStatusError.missingRemoteBooking)
387368
}
369+
} catch {
370+
return onCompletion(error)
388371
}
389372
}
390373
}
@@ -417,33 +400,6 @@ private extension BookingStore {
417400
}, on: .main)
418401
}
419402

420-
func updateBookingNoteLocally(
421-
siteID: Int64,
422-
bookingID: Int64,
423-
note: String?,
424-
onCompletion: @escaping (String?) -> Void
425-
) {
426-
storageManager.performAndSave({ storage -> String? in
427-
guard let booking = storage.loadBooking(
428-
siteID: siteID,
429-
bookingID: bookingID
430-
) else {
431-
return note
432-
}
433-
434-
let oldNote = booking.note
435-
booking.note = note
436-
return oldNote
437-
}, completion: { result in
438-
switch result {
439-
case .success(let status):
440-
onCompletion(status)
441-
case .failure:
442-
onCompletion(note)
443-
}
444-
}, on: .main)
445-
}
446-
447403
/// Cancels a booking by updating its status to cancelled.
448404
func cancelBooking(
449405
siteID: Int64,

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

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -252,22 +252,30 @@ extension BookingDetailsViewModel {
252252
stores.dispatch(action)
253253
}
254254

255-
func updateNote(to newNote: String) {
256-
let action = BookingAction.updateBookingNote(
257-
siteID: booking.siteID,
258-
bookingID: booking.bookingID,
259-
note: newNote
260-
) { [weak self] error in
261-
if let error, let self {
262-
DDLogError("⛔️ Error updating booking note: \(error)")
263-
displayErrorNotice(
264-
messageFormat: Localization.bookingNoteUpdateFailedMessage
265-
) { [weak self] in
266-
self?.updateNote(to: newNote)
255+
@MainActor
256+
func updateNote(to newNote: String) async -> MultilineCommitResult {
257+
await withCheckedContinuation { continuation in
258+
let action = BookingAction.updateBookingNote(
259+
siteID: booking.siteID,
260+
bookingID: booking.bookingID,
261+
note: newNote
262+
) { [booking] error in
263+
if let error {
264+
DDLogError("⛔️ Error updating booking note: \(error)")
265+
let message = String.localizedStringWithFormat(
266+
Localization.bookingNoteUpdateFailedMessage,
267+
booking.bookingID
268+
)
269+
270+
continuation.resume(returning: .failure(message: message))
271+
return
267272
}
273+
274+
continuation.resume(returning: .success)
268275
}
276+
277+
stores.dispatch(action)
269278
}
270-
stores.dispatch(action)
271279
}
272280

273281
private func displayErrorNotice(
@@ -283,8 +291,7 @@ extension BookingDetailsViewModel {
283291
message: text,
284292
feedbackType: .error,
285293
actionTitle: Localization.retryActionTitle
286-
) { [weak self] in
287-
guard let self else { return }
294+
) {
288295
retry()
289296
}
290297
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ private extension BookingDetailsView {
245245
MultilineEditableTextRow(value: viewModel.note,
246246
placeholder: Localization.bookingNotesRowText,
247247
detailTitle: Localization.bookingNoteNavbarText) { newNote in
248-
viewModel.updateNote(to: newNote)
248+
return await viewModel.updateNote(to: newNote)
249249
}
250250
}
251251
}

WooCommerce/Classes/ViewRelated/ReusableViews/SwiftUI Components/MultilineEditableTextRow/MultilineEditableTextDetailView.swift

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,25 @@
11
import SwiftUI
22

3+
enum MultilineCommitResult {
4+
case success
5+
case failure(message: String)
6+
}
7+
38
struct MultilineEditableTextDetailView: View {
49
@Environment(\.dismiss) private var dismiss
510

611
@Binding var text: String
712
@State private var editedText: String
813
@State private var showDiscardChangesDialog = false
914
@FocusState private var isFocused: Bool
15+
@State private var notice: Notice?
16+
@State private var isSaving = false
17+
@State private var errorMessage: String?
1018

1119
let title: String?
12-
let onCommit: ((String) -> Void)?
20+
let onCommit: (String) async -> MultilineCommitResult
1321

14-
init(text: Binding<String>, title: String? = nil, onCommit: ((String) -> Void)? = nil) {
22+
init(text: Binding<String>, title: String? = nil, onCommit: @escaping (String) async -> MultilineCommitResult) {
1523
self._text = text
1624
self._editedText = State(initialValue: text.wrappedValue)
1725
self.title = title
@@ -31,6 +39,7 @@ struct MultilineEditableTextDetailView: View {
3139
.toolbar { toolbar }
3240
.wooNavigationBarStyle()
3341
.onAppear { isFocused = true }
42+
.notice($notice)
3443
}
3544

3645
private var toolbar: some ToolbarContent {
@@ -54,17 +63,42 @@ struct MultilineEditableTextDetailView: View {
5463

5564
if editedText != text {
5665
ToolbarItem(placement: .primaryAction) {
57-
Button(Localization.doneButtonTitle) {
58-
text = editedText
59-
onCommit?(editedText)
60-
dismiss()
66+
if isSaving {
67+
ProgressView()
68+
} else {
69+
Button(Localization.doneButtonTitle) {
70+
Task {
71+
await handleDoneTapped()
72+
}
73+
}
74+
.fontWeight(.medium)
75+
.disabled(isSaving)
6176
}
62-
.fontWeight(.medium)
6377
}
6478
}
6579
}
6680
}
6781

82+
private func handleDoneTapped() async {
83+
guard !isSaving else { return }
84+
85+
isSaving = true
86+
let newText = editedText
87+
switch await onCommit(newText) {
88+
case .success:
89+
text = newText
90+
isSaving = false
91+
dismiss()
92+
case .failure(let message):
93+
isSaving = false
94+
95+
notice = Notice(
96+
message: message,
97+
feedbackType: .error,
98+
)
99+
}
100+
}
101+
68102
private func handleBackButtonTap() {
69103
if editedText != text {
70104
showDiscardChangesDialog = true

WooCommerce/Classes/ViewRelated/ReusableViews/SwiftUI Components/MultilineEditableTextRow/MultilineEditableTextRow.swift

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@ struct MultilineEditableTextRow: View {
44
@State var value: String
55
let placeholder: String
66
let detailTitle: String?
7-
let onCommit: ((String) -> Void)?
7+
let onCommit: (String) async -> MultilineCommitResult
88

99
init(value: String,
1010
placeholder: String,
1111
detailTitle: String? = nil,
12-
onCommit: ((String) -> Void)? = nil
12+
onCommit: @escaping (String) async -> MultilineCommitResult
1313
) {
1414
self._value = State(initialValue: value)
1515
self.placeholder = placeholder
@@ -64,7 +64,9 @@ fileprivate extension MultilineEditableTextRow {
6464
@Previewable @State var text: String = ""
6565

6666
NavigationStack {
67-
MultilineEditableTextRow(value: text, placeholder: "Add note")
67+
MultilineEditableTextRow(value: text, placeholder: "Add note") { _ in
68+
return .success
69+
}
6870
.padding(.horizontal, 16)
6971
}
7072
.preferredColorScheme(.dark)

0 commit comments

Comments
 (0)