Skip to content

Commit 277fac2

Browse files
Merge pull request #14750 from woocommerce/issue/WOOMOB-1453_booking_details_refresh
[WOOMOB-1453] Booking details - refresh API call
2 parents 2f9b7b7 + e2ba38a commit 277fac2

File tree

10 files changed

+262
-24
lines changed

10 files changed

+262
-24
lines changed

WooCommerce/src/main/kotlin/com/woocommerce/android/ui/bookings/BookingsRepository.kt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,20 @@ class BookingsRepository @Inject constructor(
6060
bookingId = bookingId
6161
)
6262

63+
suspend fun fetchBooking(
64+
bookingId: Long
65+
): Result<Unit> {
66+
val result = bookingsStore.fetchBooking(
67+
site = selectedSite.get(),
68+
bookingId = bookingId
69+
)
70+
return if (result.isError) {
71+
Result.failure(WooException(result.error))
72+
} else {
73+
Result.success(Unit)
74+
}
75+
}
76+
6377
data class FetchResult(
6478
val bookings: List<Booking>,
6579
val hasMorePages: Boolean

WooCommerce/src/main/kotlin/com/woocommerce/android/ui/bookings/details/BookingDetailsFragment.kt

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,19 @@ import android.view.ViewGroup
77
import androidx.fragment.app.viewModels
88
import androidx.navigation.fragment.findNavController
99
import com.woocommerce.android.ui.base.BaseFragment
10+
import com.woocommerce.android.ui.base.UIMessageResolver
1011
import com.woocommerce.android.ui.compose.composeView
1112
import com.woocommerce.android.ui.main.AppBarStatus
13+
import com.woocommerce.android.viewmodel.MultiLiveEvent
1214
import dagger.hilt.android.AndroidEntryPoint
15+
import javax.inject.Inject
1316

1417
@AndroidEntryPoint
1518
class BookingDetailsFragment : BaseFragment() {
1619

20+
@Inject
21+
lateinit var uiMessageResolver: UIMessageResolver
22+
1723
private val viewModel: BookingDetailsViewModel by viewModels()
1824

1925
override val activityAppBarStatus: AppBarStatus
@@ -33,4 +39,19 @@ class BookingDetailsFragment : BaseFragment() {
3339
)
3440
}
3541
}
42+
43+
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
44+
super.onViewCreated(view, savedInstanceState)
45+
handleEvents()
46+
}
47+
48+
private fun handleEvents() {
49+
viewModel.event.observe(viewLifecycleOwner) { event ->
50+
when (event) {
51+
is MultiLiveEvent.Event.ShowSnackbar -> {
52+
uiMessageResolver.showSnack(event.message)
53+
}
54+
}
55+
}
56+
}
3657
}

WooCommerce/src/main/kotlin/com/woocommerce/android/ui/bookings/details/BookingDetailsScreen.kt

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,16 @@ import androidx.compose.material3.ExperimentalMaterial3Api
1717
import androidx.compose.material3.HorizontalDivider
1818
import androidx.compose.material3.MaterialTheme
1919
import androidx.compose.material3.Scaffold
20-
import androidx.compose.material3.Surface
20+
import androidx.compose.material3.pulltorefresh.rememberPullToRefreshState
2121
import androidx.compose.runtime.Composable
2222
import androidx.compose.runtime.getValue
2323
import androidx.compose.runtime.livedata.observeAsState
2424
import androidx.compose.runtime.mutableStateOf
2525
import androidx.compose.runtime.remember
2626
import androidx.compose.ui.Modifier
2727
import androidx.compose.ui.draw.shadow
28-
import androidx.compose.ui.res.colorResource
2928
import androidx.compose.ui.unit.dp
3029
import androidx.compose.ui.unit.times
31-
import com.woocommerce.android.R
3230
import com.woocommerce.android.ui.bookings.compose.BookingAppointmentDetails
3331
import com.woocommerce.android.ui.bookings.compose.BookingAppointmentDetailsModel
3432
import com.woocommerce.android.ui.bookings.compose.BookingAttendanceSection
@@ -43,6 +41,7 @@ import com.woocommerce.android.ui.bookings.compose.BookingSummary
4341
import com.woocommerce.android.ui.bookings.compose.BookingSummaryModel
4442
import com.woocommerce.android.ui.compose.animations.SkeletonView
4543
import com.woocommerce.android.ui.compose.component.Toolbar
44+
import com.woocommerce.android.ui.compose.component.WCPullToRefreshBox
4645
import com.woocommerce.android.ui.compose.preview.LightDarkThemePreviews
4746
import com.woocommerce.android.ui.compose.theme.WooThemeWithBackground
4847

@@ -64,6 +63,7 @@ fun BookingDetailsScreen(
6463
}
6564
}
6665

66+
@OptIn(ExperimentalMaterial3Api::class)
6767
@Composable
6868
fun BookingDetailsScreen(
6969
viewState: BookingDetailsViewState,
@@ -80,14 +80,17 @@ fun BookingDetailsScreen(
8080
)
8181
}
8282
) { innerPadding ->
83-
Surface(
84-
color = colorResource(R.color.default_window_background),
85-
modifier = Modifier.fillMaxSize()
83+
WCPullToRefreshBox(
84+
isRefreshing = viewState.loadingState == BookingDetailsLoadingState.Refreshing,
85+
onRefresh = viewState.onRefresh,
86+
state = rememberPullToRefreshState(),
87+
modifier = Modifier
88+
.fillMaxSize()
89+
.padding(innerPadding)
8690
) {
8791
Column(
8892
modifier = Modifier
8993
.verticalScroll(rememberScrollState())
90-
.padding(innerPadding)
9194
) {
9295
when {
9396
viewState.shouldShowSkeleton -> BookingDetailsLoading()
@@ -102,14 +105,14 @@ fun BookingDetailsScreen(
102105
}
103106
}
104107
}
105-
if (showAttendanceSheet.value) {
106-
BookingAttendanceStatusBottomSheet(
107-
onSelect = { status ->
108-
viewState.onAttendanceStatusSelected(status)
109-
},
110-
onDismiss = { showAttendanceSheet.value = false }
111-
)
112-
}
108+
}
109+
if (showAttendanceSheet.value) {
110+
BookingAttendanceStatusBottomSheet(
111+
onSelect = { status ->
112+
viewState.onAttendanceStatusSelected(status)
113+
},
114+
onDismiss = { showAttendanceSheet.value = false }
115+
)
113116
}
114117
}
115118

WooCommerce/src/main/kotlin/com/woocommerce/android/ui/bookings/details/BookingDetailsViewModel.kt

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,49 +4,77 @@ import androidx.lifecycle.LiveData
44
import androidx.lifecycle.SavedStateHandle
55
import androidx.lifecycle.asLiveData
66
import com.woocommerce.android.R
7+
import com.woocommerce.android.tools.NetworkStatus
78
import com.woocommerce.android.ui.bookings.Booking
89
import com.woocommerce.android.ui.bookings.BookingMapper
910
import com.woocommerce.android.ui.bookings.BookingsRepository
1011
import com.woocommerce.android.ui.bookings.compose.BookingAttendanceStatus
12+
import com.woocommerce.android.viewmodel.MultiLiveEvent
1113
import com.woocommerce.android.viewmodel.ResourceProvider
1214
import com.woocommerce.android.viewmodel.ScopedViewModel
1315
import com.woocommerce.android.viewmodel.navArgs
1416
import dagger.hilt.android.lifecycle.HiltViewModel
1517
import kotlinx.coroutines.flow.MutableStateFlow
1618
import kotlinx.coroutines.flow.combine
19+
import kotlinx.coroutines.launch
1720
import javax.inject.Inject
1821

1922
@HiltViewModel
2023
class BookingDetailsViewModel @Inject constructor(
2124
savedState: SavedStateHandle,
22-
resourceProvider: ResourceProvider,
23-
bookingsRepository: BookingsRepository,
25+
private val resourceProvider: ResourceProvider,
26+
private val bookingsRepository: BookingsRepository,
2427
private val bookingMapper: BookingMapper,
28+
private val networkStatus: NetworkStatus,
2529
) : ScopedViewModel(savedState) {
2630

2731
private val navArgs: BookingDetailsFragmentArgs by savedState.navArgs()
2832

2933
private val booking = bookingsRepository.observeBooking(navArgs.bookingId)
3034

35+
private val loadingState = MutableStateFlow<BookingDetailsLoadingState>(BookingDetailsLoadingState.Idle)
36+
3137
// Temporary, the booking status should come from the stored object
3238
private val bookingAttendanceStatus = MutableStateFlow<BookingAttendanceStatus?>(null)
3339

3440
val state: LiveData<BookingDetailsViewState> = combine(
3541
booking,
36-
bookingAttendanceStatus
37-
) { booking, attendanceStatus ->
42+
bookingAttendanceStatus,
43+
loadingState
44+
) { booking, attendanceStatus, loadingState ->
3845
with(bookingMapper) {
3946
BookingDetailsViewState(
4047
toolbarTitle = booking?.id?.value?.let { id ->
4148
resourceProvider.getString(R.string.booking_details_title, id)
4249
} ?: "",
4350
bookingUiState = if (booking != null) buildBookingUiState(booking, attendanceStatus) else null,
51+
loadingState = loadingState,
4452
onCancelBooking = ::onCancelBooking,
45-
onAttendanceStatusSelected = ::onAttendanceStatusSelected
53+
onAttendanceStatusSelected = ::onAttendanceStatusSelected,
54+
onRefresh = ::fetchBooking,
4655
)
4756
}
4857
}.asLiveData()
4958

59+
init {
60+
fetchBooking(BookingDetailsLoadingState.Loading)
61+
}
62+
63+
private fun fetchBooking(state: BookingDetailsLoadingState = BookingDetailsLoadingState.Refreshing) {
64+
launch {
65+
if (!networkStatus.isConnected()) {
66+
triggerEvent(MultiLiveEvent.Event.ShowSnackbar(R.string.offline_error))
67+
return@launch
68+
}
69+
loadingState.value = state
70+
bookingsRepository.fetchBooking(navArgs.bookingId)
71+
.onFailure {
72+
triggerEvent(MultiLiveEvent.Event.ShowSnackbar(R.string.bookings_fetch_error))
73+
}
74+
loadingState.value = BookingDetailsLoadingState.Idle
75+
}
76+
}
77+
5078
private fun onAttendanceStatusSelected(status: BookingAttendanceStatus) {
5179
// Temporary, the booking status should come from the stored object
5280
bookingAttendanceStatus.value = status

WooCommerce/src/main/kotlin/com/woocommerce/android/ui/bookings/details/BookingDetailsViewState.kt

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,21 @@ import com.woocommerce.android.ui.bookings.compose.BookingCustomerDetailsModel
66
import com.woocommerce.android.ui.bookings.compose.BookingPaymentDetailsModel
77
import com.woocommerce.android.ui.bookings.compose.BookingSummaryModel
88

9+
sealed interface BookingDetailsLoadingState {
10+
data object Idle : BookingDetailsLoadingState
11+
data object Loading : BookingDetailsLoadingState
12+
data object Refreshing : BookingDetailsLoadingState
13+
}
14+
915
data class BookingDetailsViewState(
1016
val toolbarTitle: String = "",
1117
val bookingUiState: BookingUiState? = null,
18+
val loadingState: BookingDetailsLoadingState = BookingDetailsLoadingState.Idle,
1219
val onCancelBooking: () -> Unit = {},
13-
val onAttendanceStatusSelected: (BookingAttendanceStatus) -> Unit = { _ -> }
20+
val onAttendanceStatusSelected: (BookingAttendanceStatus) -> Unit = { _ -> },
21+
val onRefresh: () -> Unit = {},
1422
) {
15-
16-
val shouldShowSkeleton: Boolean = bookingUiState == null
23+
val shouldShowSkeleton: Boolean = bookingUiState == null && loadingState == BookingDetailsLoadingState.Refreshing
1724
}
1825

1926
data class BookingUiState(

WooCommerce/src/main/res/values/strings.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4233,6 +4233,8 @@
42334233
<string name="booking_payment_label_service">Service</string>
42344234
<string name="booking_payment_mark_as_paid">Mark as paid</string>
42354235
<string name="booking_payment_view_order">View order</string>
4236+
<string name="booking_fetch_error">Error fetching booking</string>
4237+
42364238
<string name="or_use_password" a8c-src-lib="module:login">Use password to sign in</string>
42374239
<string name="about_automattic_main_page_title">About %1$s</string>
42384240
<string name="about_automattic_legal_page_title">Legal and More</string>

0 commit comments

Comments
 (0)