Bug 1850407 - Add nimbus flag for review checker product recommendations

fenix/119.0
rahulsainani 10 months ago committed by mergify[bot]
parent 0e0596121e
commit 8eb81afee5

@ -199,6 +199,9 @@ shopping-experience:
enabled:
type: boolean
description: "if true, the shopping experience feature is shown to the user."
product-recommendations:
type: boolean
description: "if true, recommended products feature is enabled to be shown to the user based on their preference."
splash-screen:
description: "A feature that extends splash screen duration, allowing additional data fetching time for the app's initial run."
hasExposure: true

@ -346,6 +346,10 @@ features:
description: if true, the shopping experience feature is shown to the user.
type: Boolean
default: false
product-recommendations:
description: if true, recommended products feature is enabled to be shown to the user based on their preference.
type: Boolean
default: false
defaults:
- channel: developer
value:

@ -6,6 +6,7 @@ package org.mozilla.fenix.shopping.middleware
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.mozilla.fenix.nimbus.FxNimbus
import org.mozilla.fenix.utils.Settings
/**
@ -18,9 +19,10 @@ interface ReviewQualityCheckPreferences {
suspend fun enabled(): Boolean
/**
* Returns true if the user has enabled product recommendations.
* Returns true if the user has turned on product recommendations, false if turned off by the
* user, null if the product recommendations feature is disabled.
*/
suspend fun productRecommendationsEnabled(): Boolean
suspend fun productRecommendationsEnabled(): Boolean?
/**
* Sets whether the user has opted in to the review quality check feature.
@ -28,7 +30,7 @@ interface ReviewQualityCheckPreferences {
suspend fun setEnabled(isEnabled: Boolean)
/**
* Sets whether the user has enabled product recommendations.
* Sets user preference to turn on/off product recommendations.
*/
suspend fun setProductRecommendationsEnabled(isEnabled: Boolean)
@ -52,8 +54,12 @@ class ReviewQualityCheckPreferencesImpl(
settings.isReviewQualityCheckEnabled
}
override suspend fun productRecommendationsEnabled(): Boolean = withContext(Dispatchers.IO) {
settings.isReviewQualityCheckProductRecommendationsEnabled
override suspend fun productRecommendationsEnabled(): Boolean? = withContext(Dispatchers.IO) {
if (FxNimbus.features.shoppingExperience.value().productRecommendations) {
settings.isReviewQualityCheckProductRecommendationsEnabled
} else {
null
}
}
override suspend fun setEnabled(isEnabled: Boolean) {

@ -86,9 +86,13 @@ class ReviewQualityCheckPreferencesMiddleware(
ReviewQualityCheckAction.ToggleProductRecommendation -> {
scope.launch {
reviewQualityCheckPreferences.setProductRecommendationsEnabled(
!reviewQualityCheckPreferences.productRecommendationsEnabled(),
)
val productRecommendationsEnabled =
reviewQualityCheckPreferences.productRecommendationsEnabled()
if (productRecommendationsEnabled != null) {
reviewQualityCheckPreferences.setProductRecommendationsEnabled(
!productRecommendationsEnabled,
)
}
}
}
}

@ -54,10 +54,14 @@ sealed interface ReviewQualityCheckAction : Action {
/**
* Triggered as a result of a [PreferencesMiddlewareAction] to update the state.
*
* @property hasUserOptedIn True when user has opted in for shopping experience.
* @property isProductRecommendationsEnabled Reflects the user preference update to display
* recommended product. Null when product recommendations feature is disabled.
*/
data class UpdateUserPreferences(
val hasUserOptedIn: Boolean,
val isProductRecommendationsEnabled: Boolean,
val isProductRecommendationsEnabled: Boolean?,
) : UpdateAction
/**

@ -29,11 +29,12 @@ sealed interface ReviewQualityCheckState : State {
*
* @property productReviewState The state of the product the user is browsing.
* @property productRecommendationsPreference User preference whether to show product
* recommendations. True if product recommendations should be shown.
* recommendations. True if product recommendations should be shown. Null indicates that product
* recommendations are disabled.
*/
data class OptedIn(
val productReviewState: ProductReviewState = ProductReviewState.Loading,
val productRecommendationsPreference: Boolean,
val productRecommendationsPreference: Boolean?,
) : ReviewQualityCheckState {
/**

@ -58,7 +58,7 @@ private fun mapStateForUpdateAction(
}
ReviewQualityCheckAction.ToggleProductRecommendation -> {
if (state is ReviewQualityCheckState.OptedIn) {
if (state is ReviewQualityCheckState.OptedIn && state.productRecommendationsPreference != null) {
state.copy(productRecommendationsPreference = !state.productRecommendationsPreference)
} else {
state

@ -58,7 +58,7 @@ import org.mozilla.fenix.theme.FirefoxTheme
@Composable
@Suppress("LongParameterList")
fun ProductAnalysis(
productRecommendationsEnabled: Boolean,
productRecommendationsEnabled: Boolean?,
productAnalysis: AnalysisPresent,
onOptOutClick: () -> Unit,
onReanalyzeClick: () -> Unit,

@ -29,7 +29,7 @@ import org.mozilla.fenix.theme.FirefoxTheme
*/
@Composable
fun ProductAnalysisError(
productRecommendationsEnabled: Boolean,
productRecommendationsEnabled: Boolean?,
onReviewGradeLearnMoreClick: (String) -> Unit,
onOptOutClick: () -> Unit,
onProductRecommendationsEnabledStateChange: (Boolean) -> Unit,

@ -33,7 +33,7 @@ import org.mozilla.fenix.theme.FirefoxTheme
*/
@Composable
fun ReviewQualityCheckSettingsCard(
productRecommendationsEnabled: Boolean,
productRecommendationsEnabled: Boolean?,
onProductRecommendationsEnabledStateChange: (Boolean) -> Unit,
onTurnOffReviewQualityCheckClick: () -> Unit,
modifier: Modifier = Modifier,
@ -53,7 +53,7 @@ fun ReviewQualityCheckSettingsCard(
@Composable
private fun SettingsContent(
productRecommendationsEnabled: Boolean,
productRecommendationsEnabled: Boolean?,
onProductRecommendationsEnabledStateChange: (Boolean) -> Unit,
onTurnOffReviewQualityCheckClick: () -> Unit,
modifier: Modifier = Modifier,
@ -61,13 +61,15 @@ private fun SettingsContent(
Column(modifier = modifier) {
Spacer(modifier = Modifier.height(8.dp))
SwitchWithLabel(
checked = productRecommendationsEnabled,
onCheckedChange = onProductRecommendationsEnabledStateChange,
label = stringResource(R.string.review_quality_check_settings_recommended_products),
)
if (productRecommendationsEnabled != null) {
SwitchWithLabel(
checked = productRecommendationsEnabled,
onCheckedChange = onProductRecommendationsEnabledStateChange,
label = stringResource(R.string.review_quality_check_settings_recommended_products),
)
Spacer(modifier = Modifier.height(16.dp))
Spacer(modifier = Modifier.height(16.dp))
}
SecondaryButton(
text = stringResource(R.string.review_quality_check_settings_turn_off),

@ -90,6 +90,30 @@ class ReviewQualityCheckStoreTest {
assertEquals(expected, tested.state)
}
@Test
fun `GIVEN the user has opted in the feature and product recommendations feature is disabled THEN state should reflect that`() =
runTest {
val tested = ReviewQualityCheckStore(
middleware = provideReviewQualityCheckMiddleware(
reviewQualityCheckPreferences = FakeReviewQualityCheckPreferences(
isEnabled = true,
isProductRecommendationsEnabled = null,
),
),
)
tested.waitUntilIdle()
dispatcher.scheduler.advanceUntilIdle()
tested.waitUntilIdle()
val expected = ReviewQualityCheckState.OptedIn(productRecommendationsPreference = null)
assertEquals(expected, tested.state)
// Even if toggle action is dispatched, state is not changed
tested.dispatch(ReviewQualityCheckAction.ToggleProductRecommendation).joinBlocking()
tested.waitUntilIdle()
assertEquals(expected, tested.state)
}
@Test
fun `GIVEN the user has opted in the feature and product recommendations are off WHEN the user turns on product recommendations THEN state should reflect that`() =
runTest {
@ -213,12 +237,12 @@ class ReviewQualityCheckStoreTest {
private class FakeReviewQualityCheckPreferences(
private val isEnabled: Boolean = false,
private val isProductRecommendationsEnabled: Boolean = false,
private val isProductRecommendationsEnabled: Boolean? = false,
private val updateCFRCallback: () -> Unit = { },
) : ReviewQualityCheckPreferences {
override suspend fun enabled(): Boolean = isEnabled
override suspend fun productRecommendationsEnabled(): Boolean = isProductRecommendationsEnabled
override suspend fun productRecommendationsEnabled(): Boolean? = isProductRecommendationsEnabled
override suspend fun setEnabled(isEnabled: Boolean) {
}

Loading…
Cancel
Save