Skip to content

Commit 35915c0

Browse files
committed
Perform booking attendance status update
1 parent 31d7d1d commit 35915c0

File tree

5 files changed

+142
-1
lines changed

5 files changed

+142
-1
lines changed

Modules/Sources/Networking/Remote/BookingsRemote.swift

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@ public protocol BookingsRemoteProtocol {
1717
func loadBooking(bookingID: Int64,
1818
siteID: Int64) async throws -> Booking?
1919

20+
func updateBooking(
21+
from siteID: Int64,
22+
bookingID: Int64,
23+
attendanceStatus: BookingAttendanceStatus
24+
) async throws -> Booking?
25+
2026
func fetchResource(resourceID: Int64,
2127
siteID: Int64) async throws -> BookingResource?
2228
}
@@ -88,6 +94,28 @@ public final class BookingsRemote: Remote, BookingsRemoteProtocol {
8894
return try await enqueue(request, mapper: mapper)
8995
}
9096

97+
public func updateBooking(
98+
from siteID: Int64,
99+
bookingID: Int64,
100+
attendanceStatus: BookingAttendanceStatus
101+
) async throws -> Booking? {
102+
let path = "\(Path.bookings)/\(bookingID)"
103+
let parameters = [
104+
ParameterKey.attendanceStatus: attendanceStatus.rawValue
105+
]
106+
let request = JetpackRequest(
107+
wooApiVersion: .wcBookings,
108+
method: .put,
109+
siteID: siteID,
110+
path: path,
111+
parameters: parameters,
112+
availableAsRESTRequest: true
113+
)
114+
115+
let mapper = BookingMapper(siteID: siteID)
116+
return try await enqueue(request, mapper: mapper)
117+
}
118+
91119
public func fetchResource(
92120
resourceID: Int64,
93121
siteID: Int64
@@ -132,5 +160,6 @@ public extension BookingsRemote {
132160
static let startDateAfter: String = "start_date_after"
133161
static let search: String = "search"
134162
static let order: String = "order"
163+
static let attendanceStatus = "attendance_status"
135164
}
136165
}

Modules/Sources/Yosemite/Actions/BookingAction.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,4 +52,16 @@ public enum BookingAction: Action {
5252
case fetchResource(siteID: Int64,
5353
resourceID: Int64,
5454
onCompletion: (Result<BookingResource, Error>) -> Void)
55+
56+
/// Updates a booking attendance status.
57+
///
58+
/// - Parameter siteID: The site ID of the booking.
59+
/// - Parameter bookingID: The ID of the booking to be updated.
60+
/// - Parameter status: The new attendance status.
61+
/// - Parameter onCompletion: called when update completes, returns an error in case of a failure.
62+
///
63+
case updateBookingAttendanceStatus(siteID: Int64,
64+
bookingID: Int64,
65+
status: BookingAttendanceStatus,
66+
onCompletion: (Error?) -> Void)
5567
}

Modules/Sources/Yosemite/Stores/BookingStore.swift

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,20 @@ public class BookingStore: Store {
6363
onCompletion: onCompletion)
6464
case let .fetchResource(siteID, resourceID, onCompletion):
6565
fetchResource(siteID: siteID, resourceID: resourceID, onCompletion: onCompletion)
66+
case .updateBookingAttendanceStatus(let siteID, let bookingID, let status, let onCompletion):
67+
performUpdateBookingAttendanceStatus(
68+
siteID: siteID,
69+
bookingID: bookingID,
70+
status: status,
71+
onCompletion: onCompletion
72+
)
6673
}
6774
}
6875
}
6976

77+
private enum UpdateBookingStatusError: Error {
78+
case undefinedState
79+
}
7080

7181
// MARK: - Services
7282
//
@@ -246,6 +256,78 @@ private extension BookingStore {
246256
}
247257
}
248258
}
259+
260+
func performUpdateBookingAttendanceStatus(
261+
siteID: Int64,
262+
bookingID: Int64,
263+
status: BookingAttendanceStatus,
264+
onCompletion: @escaping (Error?) -> Void
265+
) {
266+
updateBookingAttendanceStatusLocally(
267+
siteID: siteID,
268+
bookingID: bookingID,
269+
statusKey: status
270+
) { [weak self] previousStatusKey in
271+
guard let self else {
272+
return onCompletion(UpdateBookingStatusError.undefinedState)
273+
}
274+
275+
Task {
276+
do {
277+
if let remoteBooking = try await self.remote.updateBooking(
278+
from: siteID,
279+
bookingID: bookingID,
280+
attendanceStatus: status
281+
) {
282+
await self.upsertStoredBookingsInBackground(
283+
readOnlyBookings: [remoteBooking],
284+
readOnlyOrders: [],
285+
siteID: siteID
286+
)
287+
} else {
288+
onCompletion(nil)
289+
}
290+
} catch {
291+
/// Revert Optimistic Update
292+
self.updateBookingAttendanceStatusLocally(
293+
siteID: siteID,
294+
bookingID: bookingID,
295+
statusKey: previousStatusKey
296+
) { _ in
297+
onCompletion(error)
298+
}
299+
}
300+
}
301+
}
302+
}
303+
304+
/// Updates local (Storage) Booking attendance status
305+
func updateBookingAttendanceStatusLocally(
306+
siteID: Int64,
307+
bookingID: Int64,
308+
statusKey: BookingAttendanceStatus,
309+
onCompletion: @escaping (BookingAttendanceStatus) -> Void
310+
) {
311+
storageManager.performAndSave({ storage -> BookingAttendanceStatus in
312+
guard let booking = storage.loadBooking(
313+
siteID: siteID,
314+
bookingID: bookingID
315+
) else {
316+
return statusKey
317+
}
318+
319+
let oldStatus = booking.attendanceStatusKey
320+
booking.attendanceStatusKey = statusKey.rawValue
321+
return BookingAttendanceStatus(rawValue: oldStatus ?? "") ?? .unknown
322+
}, completion: { result in
323+
switch result {
324+
case .success(let status):
325+
onCompletion(status)
326+
case .failure:
327+
onCompletion(statusKey)
328+
}
329+
}, on: .main)
330+
}
249331
}
250332

251333

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

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,24 @@ extension BookingDetailsViewModel {
142142
}
143143
}
144144

145+
// MARK: Attendance status
146+
147+
extension BookingDetailsViewModel {
148+
func updateAttendanceStatus(to newStatus: BookingAttendanceStatus) {
149+
let action = BookingAction.updateBookingAttendanceStatus(
150+
siteID: booking.siteID,
151+
bookingID: booking.bookingID,
152+
status: newStatus
153+
) { error in
154+
if let error {
155+
DDLogError("⛔️ Error updating booking attendance status: \(error)")
156+
// TODO: Show an error notice to the user
157+
}
158+
}
159+
stores.dispatch(action)
160+
}
161+
}
162+
145163
private extension BookingDetailsViewModel {
146164
@MainActor
147165
func fetchResource() async -> BookingResource? {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ struct BookingDetailsView: View {
8585
}
8686
.sheet(isPresented: $showingStatusSheet) {
8787
UpdateAttendanceStatusView(selectedStatus: viewModel.bookingAttendanceStatus) { selectedStatus in
88-
print("Selected status: \(selectedStatus)")
88+
viewModel.updateAttendanceStatus(to: selectedStatus)
8989
}
9090
.padding(.top)
9191
.presentationDetents([.medium, .large])

0 commit comments

Comments
 (0)