Bug 1850407 - Add nimbus flag for review checker product recommendations

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

@ -199,6 +199,9 @@ shopping-experience:
enabled: enabled:
type: boolean type: boolean
description: "if true, the shopping experience feature is shown to the user." 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: splash-screen:
description: "A feature that extends splash screen duration, allowing additional data fetching time for the app's initial run." description: "A feature that extends splash screen duration, allowing additional data fetching time for the app's initial run."
hasExposure: true hasExposure: true

@ -346,6 +346,10 @@ features:
description: if true, the shopping experience feature is shown to the user. description: if true, the shopping experience feature is shown to the user.
type: Boolean type: Boolean
default: false 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: defaults:
- channel: developer - channel: developer
value: value:

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

@ -86,9 +86,13 @@ class ReviewQualityCheckPreferencesMiddleware(
ReviewQualityCheckAction.ToggleProductRecommendation -> { ReviewQualityCheckAction.ToggleProductRecommendation -> {
scope.launch { scope.launch {
reviewQualityCheckPreferences.setProductRecommendationsEnabled( val productRecommendationsEnabled =
!reviewQualityCheckPreferences.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. * 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( data class UpdateUserPreferences(
val hasUserOptedIn: Boolean, val hasUserOptedIn: Boolean,
val isProductRecommendationsEnabled: Boolean, val isProductRecommendationsEnabled: Boolean?,
) : UpdateAction ) : UpdateAction
/** /**

@ -29,11 +29,12 @@ sealed interface ReviewQualityCheckState : State {
* *
* @property productReviewState The state of the product the user is browsing. * @property productReviewState The state of the product the user is browsing.
* @property productRecommendationsPreference User preference whether to show product * @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( data class OptedIn(
val productReviewState: ProductReviewState = ProductReviewState.Loading, val productReviewState: ProductReviewState = ProductReviewState.Loading,
val productRecommendationsPreference: Boolean, val productRecommendationsPreference: Boolean?,
) : ReviewQualityCheckState { ) : ReviewQualityCheckState {
/** /**

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

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

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

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

@ -90,6 +90,30 @@ class ReviewQualityCheckStoreTest {
assertEquals(expected, tested.state) 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 @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`() = 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 { runTest {
@ -213,12 +237,12 @@ class ReviewQualityCheckStoreTest {
private class FakeReviewQualityCheckPreferences( private class FakeReviewQualityCheckPreferences(
private val isEnabled: Boolean = false, private val isEnabled: Boolean = false,
private val isProductRecommendationsEnabled: Boolean = false, private val isProductRecommendationsEnabled: Boolean? = false,
private val updateCFRCallback: () -> Unit = { }, private val updateCFRCallback: () -> Unit = { },
) : ReviewQualityCheckPreferences { ) : ReviewQualityCheckPreferences {
override suspend fun enabled(): Boolean = isEnabled override suspend fun enabled(): Boolean = isEnabled
override suspend fun productRecommendationsEnabled(): Boolean = isProductRecommendationsEnabled override suspend fun productRecommendationsEnabled(): Boolean? = isProductRecommendationsEnabled
override suspend fun setEnabled(isEnabled: Boolean) { override suspend fun setEnabled(isEnabled: Boolean) {
} }

Loading…
Cancel
Save