Skip to content

Commit

Permalink
Merge pull request #13220 from woocommerce/issue/13213-disable-notifi…
Browse files Browse the repository at this point in the history
…cations-api-request

Issue/13213 disable notifications api request
  • Loading branch information
JorgeMucientes authored Jan 7, 2025
2 parents 3cb2f4c + 0ae6499 commit 80d5ac7
Show file tree
Hide file tree
Showing 6 changed files with 139 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import com.woocommerce.android.ui.compose.composeView
import com.woocommerce.android.ui.main.AppBarStatus
import com.woocommerce.android.viewmodel.MultiLiveEvent
import com.woocommerce.android.viewmodel.MultiLiveEvent.Event.ExitWithResult
import com.woocommerce.android.viewmodel.MultiLiveEvent.Event.ShowDialog
import dagger.hilt.android.AndroidEntryPoint

@AndroidEntryPoint
Expand Down Expand Up @@ -40,6 +41,7 @@ class WooSitesVisibilityFragment : BaseFragment() {
when (event) {
is MultiLiveEvent.Event.Exit -> findNavController().navigateUp()
is ExitWithResult<*> -> navigateBackWithResult(WOO_SITES_VISIBILITY_UPDATED, event.data)
is ShowDialog -> event.showDialog()
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.CircularProgressIndicator
import androidx.compose.material.Divider
import androidx.compose.material.Icon
import androidx.compose.material.IconButton
Expand Down Expand Up @@ -74,13 +76,21 @@ fun WooSitesVisibilityScreen(
},
backgroundColor = colorResource(id = R.color.color_toolbar),
actions = {
TextButton(
onClick = onSaveTapped,
enabled = state.isSaveButtonEnabled
) {
Text(
text = stringResource(id = R.string.save).uppercase()
if (state.isLoading) {
CircularProgressIndicator(
modifier = Modifier
.size(width = 56.dp, height = 16.dp)
.padding(horizontal = 16.dp)
)
} else {
TextButton(
onClick = onSaveTapped,
enabled = state.isSaveButtonEnabled
) {
Text(
text = stringResource(id = R.string.save).uppercase()
)
}
}
},
elevation = 0.dp
Expand Down Expand Up @@ -228,6 +238,7 @@ fun StoreVisibilityScreenPreview() {

),
isSaveButtonEnabled = true,
isLoading = false,
currentSite = WooStoreUi(
siteName = "Current Store",
siteUrl = "https://myselectedSite.com",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ package com.woocommerce.android.ui.sitepicker.sitevisibility

import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.asLiveData
import com.woocommerce.android.R
import com.woocommerce.android.tools.SelectedSite
import com.woocommerce.android.ui.sitepicker.SitePickerRepository
import com.woocommerce.android.viewmodel.MultiLiveEvent.Event
import com.woocommerce.android.viewmodel.MultiLiveEvent.Event.Exit
import com.woocommerce.android.viewmodel.MultiLiveEvent.Event.ExitWithResult
import com.woocommerce.android.viewmodel.ScopedViewModel
Expand All @@ -12,33 +14,37 @@ import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
import org.wordpress.android.fluxc.model.SiteModel
import org.wordpress.android.fluxc.store.NotificationStore
import org.wordpress.android.fluxc.store.NotificationStore.SiteNotificationSetting
import javax.inject.Inject

@HiltViewModel
class WooSitesVisibilityViewModel @Inject constructor(
private val sitePickerRepository: SitePickerRepository,
private val selectedSite: SelectedSite,
private val visibleSitesDataStore: VisibleWooSitesDataStore,
private val notificationsStore: NotificationStore,
savedStateHandle: SavedStateHandle
) : ScopedViewModel(savedStateHandle) {
private var initiallySelectedSiteIds: List<Long> = emptyList()
private val _wooStores = MutableStateFlow(
private val _wooStoresState = MutableStateFlow(
WooStoresUiState(
wooStores = emptyList(),
currentSite = selectedSite.get().toWooStoreUi(isSiteVisible = false),
isSaveButtonEnabled = false
isSaveButtonEnabled = false,
isLoading = false
)
)
val viewState = _wooStores.asLiveData()
val viewState = _wooStoresState.asLiveData()

init {
launch {
_wooStores.value = _wooStores.value.copy(
_wooStoresState.value = _wooStoresState.value.copy(
wooStores = sitePickerRepository.getSites()
.filter { it.hasWooCommerce && it.siteId != selectedSite.get().siteId }
.map { it.toWooStoreUi(isSiteVisible(it.siteId)) }
)
initiallySelectedSiteIds = _wooStores.value.wooStores
initiallySelectedSiteIds = _wooStoresState.value.wooStores
.filter { it.isSelected }
.map { it.siteId }
}
Expand All @@ -49,26 +55,58 @@ class WooSitesVisibilityViewModel @Inject constructor(
}

fun onSaveTapped() {
_wooStoresState.value = _wooStoresState.value.copy(isLoading = true)
launch {
visibleSitesDataStore.updateSiteVisibilityStatus(
_wooStores.value.wooStores
.associate { it.siteId to it.isSelected }
)
triggerEvent(ExitWithResult(data = true))
notificationsStore.updateNotificationSettingsFor(
_wooStoresState.value.wooStores.map {
SiteNotificationSetting(
siteId = it.siteId,
newCommentEnabled = it.isSelected,
storeOrderEnabled = it.isSelected
)
}
).fold(
onSuccess = {
visibleSitesDataStore.updateSiteVisibilityStatus(
_wooStoresState.value.wooStores
.associate { it.siteId to it.isSelected }
)
triggerEvent(ExitWithResult(data = true))
},
onFailure = {
triggerEvent(
Event.ShowDialog(
titleId = R.string.site_picker_edit_store_list_error_title,
positiveButtonId = R.string.retry,
positiveBtnAction = { dialog, _ ->
dialog.dismiss()
onSaveTapped()
},
negativeButtonId = R.string.cancel,
negativeBtnAction = { dialog, _ ->
dialog.dismiss()
triggerEvent(Exit)
}
)
)
}
).also {
_wooStoresState.value = _wooStoresState.value.copy(isLoading = false)
}
}
}

fun onSiteTapped(wooStoreUi: WooStoreUi) {
_wooStores.value = _wooStores.value.copy(
wooStores = _wooStores.value.wooStores.map {
_wooStoresState.value = _wooStoresState.value.copy(
wooStores = _wooStoresState.value.wooStores.map {
when {
it.siteId == wooStoreUi.siteId -> it.copy(isSelected = !it.isSelected)
else -> it
}
}
)
_wooStores.value = _wooStores.value.copy(
isSaveButtonEnabled = _wooStores.value.wooStores
_wooStoresState.value = _wooStoresState.value.copy(
isSaveButtonEnabled = _wooStoresState.value.wooStores
.filter { it.isSelected }
.map { it.siteId } != initiallySelectedSiteIds
)
Expand All @@ -87,7 +125,8 @@ class WooSitesVisibilityViewModel @Inject constructor(
data class WooStoresUiState(
val wooStores: List<WooStoreUi>,
val currentSite: WooStoreUi,
val isSaveButtonEnabled: Boolean
val isSaveButtonEnabled: Boolean,
val isLoading: Boolean
)

data class WooStoreUi(
Expand Down
1 change: 1 addition & 0 deletions WooCommerce/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,7 @@
<string name="site_picker_edit_store_current_site_header">Current Store</string>
<string name="site_picker_edit_store_current_site_footer">Please switch to another store if you want to hide this one</string>
<string name="site_picker_edit_store_list_header">Other Stores</string>
<string name="site_picker_edit_store_list_error_title">There was an error when updating notification settings. Please try again</string>

<!--
My Store View
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import com.woocommerce.android.util.getOrAwaitValue
import com.woocommerce.android.util.runAndCaptureValues
import com.woocommerce.android.viewmodel.BaseUnitTest
import com.woocommerce.android.viewmodel.MultiLiveEvent.Event.ExitWithResult
import com.woocommerce.android.viewmodel.MultiLiveEvent.Event.ShowDialog
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.flowOf
import org.assertj.core.api.Assertions.assertThat
Expand All @@ -17,6 +18,13 @@ import org.mockito.kotlin.any
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.mock
import org.mockito.kotlin.verify
import org.mockito.kotlin.whenever
import org.wordpress.android.fluxc.store.NotificationStore
import org.wordpress.android.fluxc.store.NotificationStore.NotificationSettingErrorType
import org.wordpress.android.fluxc.store.NotificationStore.NotificationSettingsUpdateError
import org.wordpress.android.fluxc.store.NotificationStore.SiteNotificationSetting
import kotlin.test.assertFalse
import kotlin.test.assertTrue

@OptIn(ExperimentalCoroutinesApi::class)
class WooSitesVisibilityViewModelTest : BaseUnitTest() {
Expand Down Expand Up @@ -59,6 +67,8 @@ class WooSitesVisibilityViewModelTest : BaseUnitTest() {
onBlocking { isSiteVisible(any()) } doReturn flowOf(true)
}

private val notificationStore: NotificationStore = mock()

private lateinit var viewModel: WooSitesVisibilityViewModel

@Before
Expand All @@ -67,6 +77,7 @@ class WooSitesVisibilityViewModelTest : BaseUnitTest() {
sitePickerRepository = sitePickerRepository,
selectedSite = selectedSite,
visibleSitesDataStore = visibleWooSitesDataStore,
notificationsStore = notificationStore,
savedStateHandle = mock()
)
}
Expand All @@ -77,8 +88,8 @@ class WooSitesVisibilityViewModelTest : BaseUnitTest() {
viewModel.onSiteTapped(A_WOO_SITE_UI_MODEL)

val updatedState = viewModel.viewState.getOrAwaitValue()
assert(!updatedState.wooStores.last().isSelected)
assert(updatedState.isSaveButtonEnabled)
assertFalse(updatedState.wooStores.last().isSelected)
assertTrue(updatedState.isSaveButtonEnabled)
}

@Test
Expand All @@ -88,13 +99,15 @@ class WooSitesVisibilityViewModelTest : BaseUnitTest() {
viewModel.onSiteTapped(A_WOO_SITE_UI_MODEL)

val updatedState = viewModel.viewState.getOrAwaitValue()
assert(updatedState.wooStores.first().isSelected)
assert(!updatedState.isSaveButtonEnabled)
assertTrue(updatedState.wooStores.first().isSelected)
assertFalse(updatedState.isSaveButtonEnabled)
}

@Test
fun `given one site is unselected, when tapping save, then save site visibility status`() =
fun `given update notification settings succeeds, when tapping save, then save site's visibility locally`() =
testBlocking {
whenever(notificationStore.updateNotificationSettingsFor(any())).thenReturn(Result.success(Unit))

val hiddenSite = A_WOO_SITE_UI_MODEL
viewModel.onSiteTapped(hiddenSite)

Expand All @@ -106,12 +119,57 @@ class WooSitesVisibilityViewModelTest : BaseUnitTest() {
}

@Test
fun `when tapping save, then exit with result`() =
fun `given updating notification settings succeeds, when tapping save, then exit with result`() =
testBlocking {
val event = viewModel.event.runAndCaptureValues {
viewModel.onSaveTapped()
}.last()

assertThat(event).isEqualTo(ExitWithResult(data = true))
}

@Test
fun `given updating notification settings fails, when tapping save, then error dialog is shown`() =
testBlocking {
whenever(notificationStore.updateNotificationSettingsFor(any()))
.thenReturn(
Result.failure(
NotificationSettingsUpdateError(
type = NotificationSettingErrorType.ApiError("Any error")
)
)
)

val event = viewModel.event.runAndCaptureValues {
viewModel.onSaveTapped()
}.last()

assertThat(event).isInstanceOf(ShowDialog::class.java)
}

@Test
fun `when tapping save, then site notification settings are updated on the backend`() =
testBlocking {
viewModel.onSaveTapped()

verify(notificationStore).updateNotificationSettingsFor(
AVAILABLE_WOO_SITES_TO_HIDE.map {
SiteNotificationSetting(
siteId = it.siteId,
newCommentEnabled = it.isSelected,
storeOrderEnabled = it.isSelected
)
}
)
}

@Test
fun `given save was tapped, when loading is done, then hide loading state`() =
testBlocking {
viewModel.onSaveTapped()

val updatedState = viewModel.viewState.getOrAwaitValue()

assertFalse(updatedState.isLoading)
}
}
2 changes: 1 addition & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ stripe-terminal = '3.7.1'
tinder-statemachine = '0.2.0'
wiremock = '2.26.3'
wordpress-aztec = 'v2.1.4'
wordpress-fluxc = 'trunk-b329e031481c8653a57c0a41c4dedfc0ba6a510e'
wordpress-fluxc = 'trunk-8555e9eeea7c95dd5f96c900b62fdc5a7465a44b'
wordpress-login = '1.19.0'
wordpress-libaddressinput = '0.0.2'
wordpress-mediapicker = '0.3.1'
Expand Down

0 comments on commit 80d5ac7

Please sign in to comment.