diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/vault/VaultActionCard.kt b/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/vault/VaultActionCard.kt new file mode 100644 index 0000000000..ba7fe48ee8 --- /dev/null +++ b/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/vault/VaultActionCard.kt @@ -0,0 +1,103 @@ +package com.x8bit.bitwarden.ui.vault.feature.vault + +import androidx.compose.material3.Icon +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import com.bitwarden.ui.platform.components.card.BitwardenActionCard +import com.bitwarden.ui.platform.components.util.rememberVectorPainter +import com.bitwarden.ui.platform.resource.BitwardenDrawable +import com.bitwarden.ui.platform.resource.BitwardenString +import com.bitwarden.ui.platform.theme.BitwardenTheme +import com.x8bit.bitwarden.ui.vault.feature.vault.handlers.VaultHandlers + +/** + * The action card for the vault screen. + */ +@Suppress("LongMethod") +@Composable +fun VaultActionCard( + actionCardState: VaultState.ActionCardState, + vaultHandlers: VaultHandlers, + modifier: Modifier = Modifier, +) { + when (actionCardState) { + VaultState.ActionCardState.UpgradedToPremium -> { + BitwardenActionCard( + cardTitle = stringResource(id = BitwardenString.upgraded_to_premium), + cardSubtitle = stringResource( + id = BitwardenString.you_now_have_access_to_all_advanced_security_features, + ), + actionText = stringResource(id = BitwardenString.learn_more), + isExternalLink = true, + leadingContent = { + Icon( + painter = rememberVectorPainter(id = BitwardenDrawable.ic_star), + contentDescription = null, + tint = BitwardenTheme.colorScheme.icon.secondary, + ) + }, + onActionClick = { vaultHandlers.actionCardClick(actionCardState) }, + onDismissClick = { vaultHandlers.dismissActionCardClick(actionCardState) }, + modifier = modifier, + ) + } + + VaultState.ActionCardState.UpgradePremium -> { + BitwardenActionCard( + cardTitle = stringResource( + id = BitwardenString.unlock_advanced_security_features, + ), + cardSubtitle = stringResource( + id = BitwardenString + .a_premium_plan_gives_you_more_tools_to_stay_secure_and_in_control, + ), + actionText = stringResource(id = BitwardenString.learn_more), + onActionClick = { vaultHandlers.actionCardClick(actionCardState) }, + onDismissClick = { vaultHandlers.dismissActionCardClick(actionCardState) }, + modifier = modifier, + ) + } + + VaultState.ActionCardState.PremiumNeedsAttention -> { + BitwardenActionCard( + cardTitle = stringResource(id = BitwardenString.your_subscription_needs_attention), + cardSubtitle = stringResource(id = BitwardenString.check_your_plan_for_details), + actionText = stringResource(id = BitwardenString.view_plan), + onActionClick = { vaultHandlers.actionCardClick(actionCardState) }, + modifier = modifier, + ) + } + + VaultState.ActionCardState.IntroducingArchive -> { + BitwardenActionCard( + cardTitle = stringResource(id = BitwardenString.introducing_archive), + cardSubtitle = stringResource( + id = BitwardenString.keep_items_you_dont_need_right_now_safe_but_out_sight, + ), + actionText = stringResource(id = BitwardenString.go_to_archive), + leadingContent = { + Icon( + painter = rememberVectorPainter(id = BitwardenDrawable.ic_archive), + contentDescription = null, + tint = BitwardenTheme.colorScheme.icon.secondary, + ) + }, + onActionClick = { vaultHandlers.actionCardClick(actionCardState) }, + onDismissClick = { vaultHandlers.dismissActionCardClick(actionCardState) }, + modifier = modifier, + ) + } + + VaultState.ActionCardState.ImportItems -> { + BitwardenActionCard( + cardTitle = stringResource(id = BitwardenString.import_saved_logins), + cardSubtitle = stringResource(id = BitwardenString.use_a_computer_to_import_logins), + actionText = stringResource(id = BitwardenString.get_started), + onActionClick = { vaultHandlers.actionCardClick(actionCardState) }, + onDismissClick = { vaultHandlers.dismissActionCardClick(actionCardState) }, + modifier = modifier, + ) + } + } +} diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/vault/VaultContent.kt b/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/vault/VaultContent.kt index 09b726a5f5..c8bea119b2 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/vault/VaultContent.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/vault/VaultContent.kt @@ -7,7 +7,6 @@ import androidx.compose.foundation.layout.navigationBarsPadding import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.itemsIndexed -import androidx.compose.material3.Icon import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -19,15 +18,12 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import com.bitwarden.ui.platform.base.util.standardHorizontalMargin import com.bitwarden.ui.platform.base.util.toListItemCardStyle -import com.bitwarden.ui.platform.components.card.BitwardenActionCard import com.bitwarden.ui.platform.components.dialog.BitwardenTwoButtonDialog import com.bitwarden.ui.platform.components.header.BitwardenListHeaderText import com.bitwarden.ui.platform.components.icon.model.IconData import com.bitwarden.ui.platform.components.model.CardStyle -import com.bitwarden.ui.platform.components.util.rememberVectorPainter import com.bitwarden.ui.platform.resource.BitwardenDrawable import com.bitwarden.ui.platform.resource.BitwardenString -import com.bitwarden.ui.platform.theme.BitwardenTheme import com.x8bit.bitwarden.ui.platform.components.dialog.BitwardenMasterPasswordDialog import com.x8bit.bitwarden.ui.platform.components.listitem.BitwardenGroupItem import com.x8bit.bitwarden.ui.vault.feature.itemlisting.model.ListingItemOverflowAction @@ -107,7 +103,7 @@ fun VaultContent( actionCardState?.let { item(key = "action_card") { - ActionCard( + VaultActionCard( actionCardState = it, vaultHandlers = vaultHandlers, modifier = Modifier @@ -561,80 +557,3 @@ fun VaultContent( } } } - -@Suppress("LongMethod") -@Composable -private fun ActionCard( - actionCardState: VaultState.ActionCardState, - vaultHandlers: VaultHandlers, - modifier: Modifier = Modifier, -) { - when (actionCardState) { - VaultState.ActionCardState.UpgradedToPremium -> { - BitwardenActionCard( - cardTitle = stringResource(id = BitwardenString.upgraded_to_premium), - cardSubtitle = stringResource( - id = BitwardenString.you_now_have_access_to_all_advanced_security_features, - ), - actionText = stringResource(id = BitwardenString.learn_more), - isExternalLink = true, - leadingContent = { - Icon( - painter = rememberVectorPainter(id = BitwardenDrawable.ic_star), - contentDescription = null, - tint = BitwardenTheme.colorScheme.icon.secondary, - ) - }, - onActionClick = { vaultHandlers.actionCardClick(actionCardState) }, - onDismissClick = { vaultHandlers.dismissActionCardClick(actionCardState) }, - modifier = modifier, - ) - } - - VaultState.ActionCardState.UpgradePremium -> { - BitwardenActionCard( - cardTitle = stringResource( - id = BitwardenString.unlock_advanced_security_features, - ), - cardSubtitle = stringResource( - id = BitwardenString - .a_premium_plan_gives_you_more_tools_to_stay_secure_and_in_control, - ), - actionText = stringResource(id = BitwardenString.learn_more), - onActionClick = { vaultHandlers.actionCardClick(actionCardState) }, - onDismissClick = { vaultHandlers.dismissActionCardClick(actionCardState) }, - modifier = modifier, - ) - } - - VaultState.ActionCardState.PremiumNeedsAttention -> { - BitwardenActionCard( - cardTitle = stringResource(id = BitwardenString.your_subscription_needs_attention), - cardSubtitle = stringResource(id = BitwardenString.check_your_plan_for_details), - actionText = stringResource(id = BitwardenString.view_plan), - onActionClick = { vaultHandlers.actionCardClick(actionCardState) }, - modifier = modifier, - ) - } - - VaultState.ActionCardState.IntroducingArchive -> { - BitwardenActionCard( - cardTitle = stringResource(id = BitwardenString.introducing_archive), - cardSubtitle = stringResource( - id = BitwardenString.keep_items_you_dont_need_right_now_safe_but_out_sight, - ), - actionText = stringResource(id = BitwardenString.go_to_archive), - leadingContent = { - Icon( - painter = rememberVectorPainter(id = BitwardenDrawable.ic_archive), - contentDescription = null, - tint = BitwardenTheme.colorScheme.icon.secondary, - ) - }, - onActionClick = { vaultHandlers.actionCardClick(actionCardState) }, - onDismissClick = { vaultHandlers.dismissActionCardClick(actionCardState) }, - modifier = modifier, - ) - } - } -} diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/vault/VaultScreen.kt b/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/vault/VaultScreen.kt index da50c62d4b..5aef95618a 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/vault/VaultScreen.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/vault/VaultScreen.kt @@ -39,7 +39,6 @@ import com.bitwarden.ui.platform.components.appbar.action.BitwardenSearchActionI import com.bitwarden.ui.platform.components.appbar.model.OverflowMenuItemData import com.bitwarden.ui.platform.components.appbar.model.TopAppBarDividerStyle import com.bitwarden.ui.platform.components.button.model.BitwardenButtonData -import com.bitwarden.ui.platform.components.card.BitwardenActionCard import com.bitwarden.ui.platform.components.card.actionCardExitAnimation import com.bitwarden.ui.platform.components.content.BitwardenErrorContent import com.bitwarden.ui.platform.components.content.BitwardenLoadingContent @@ -340,19 +339,14 @@ private fun VaultScreenScaffold( ) is VaultState.ViewState.NoItems -> { - AnimatedVisibility( - visible = state.showImportActionCard, + AnimateNullableContentVisibility( + targetState = state.actionCard, exit = actionCardExitAnimation(), label = "VaultNoItemsActionCard", - ) { - BitwardenActionCard( - cardTitle = stringResource(BitwardenString.import_saved_logins), - cardSubtitle = stringResource( - BitwardenString.use_a_computer_to_import_logins, - ), - actionText = stringResource(BitwardenString.get_started), - onActionClick = vaultHandlers.importActionCardClick, - onDismissClick = vaultHandlers.dismissImportActionCard, + ) { actionCard -> + VaultActionCard( + actionCardState = actionCard, + vaultHandlers = vaultHandlers, modifier = Modifier .fillMaxWidth() .standardHorizontalMargin() diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/vault/VaultViewModel.kt b/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/vault/VaultViewModel.kt index 6ab599184d..91cc21c3b9 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/vault/VaultViewModel.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/vault/VaultViewModel.kt @@ -358,8 +358,6 @@ class VaultViewModel @Inject constructor( } is VaultAction.Internal -> handleInternalAction(action) - VaultAction.DismissImportActionCard -> handleDismissImportActionCard() - VaultAction.ImportActionCardClick -> handleImportActionCardClick() VaultAction.LifecycleResumed -> handleLifecycleResumed() VaultAction.SelectAddItemType -> handleSelectAddItemType() VaultAction.DismissFlightRecorderSnackbar -> handleDismissFlightRecorderSnackbar() @@ -457,6 +455,12 @@ class VaultViewModel @Inject constructor( VaultState.ActionCardState.IntroducingArchive -> { settingsRepository.dismissIntroducingArchiveActionCard() } + + VaultState.ActionCardState.ImportItems -> { + firstTimeActionManager.storeShowImportLoginsSettingsBadge(showBadge = true) + if (!state.showImportActionCard) return + firstTimeActionManager.storeShowImportLogins(showImportLogins = false) + } } } @@ -477,9 +481,11 @@ class VaultViewModel @Inject constructor( VaultState.ActionCardState.IntroducingArchive -> { settingsRepository.dismissIntroducingArchiveActionCard() - sendEvent( - VaultEvent.NavigateToItemListing(VaultItemListingType.Archive), - ) + sendEvent(VaultEvent.NavigateToItemListing(VaultItemListingType.Archive)) + } + + VaultState.ActionCardState.ImportItems -> { + sendEvent(VaultEvent.NavigateToImportLogins) } } } @@ -526,16 +532,6 @@ class VaultViewModel @Inject constructor( } } - private fun handleImportActionCardClick() { - sendEvent(VaultEvent.NavigateToImportLogins) - } - - private fun handleDismissImportActionCard() { - firstTimeActionManager.storeShowImportLoginsSettingsBadge(true) - if (!state.showImportActionCard) return - firstTimeActionManager.storeShowImportLogins(false) - } - private fun handleIconLoadingSettingReceive( action: VaultAction.Internal.IconLoadingSettingReceive, ) { @@ -1789,16 +1785,30 @@ data class VaultState( * Indicates what action card to display. */ val actionCard: ActionCardState? - get() = (viewState as? ViewState.Content)?.let { - ActionCardState.UpgradedToPremium - .takeIf { isUpgradedToPremiumCardEligible } - ?: ActionCardState.UpgradePremium.takeIf { premiumCard == PremiumCard.UPGRADE } - ?: ActionCardState.PremiumNeedsAttention.takeIf { - premiumCard == PremiumCard.NEEDS_ATTENTION - } - ?: ActionCardState.IntroducingArchive.takeIf { - isPremium && !isIntroducingArchiveActionCardDismissed - } + get() = when (viewState) { + is ViewState.Content -> { + ActionCardState.UpgradedToPremium + .takeIf { isUpgradedToPremiumCardEligible } + ?: ActionCardState.UpgradePremium.takeIf { premiumCard == PremiumCard.UPGRADE } + ?: ActionCardState.PremiumNeedsAttention.takeIf { + premiumCard == PremiumCard.NEEDS_ATTENTION + } + ?: ActionCardState.IntroducingArchive.takeIf { + isPremium && !isIntroducingArchiveActionCardDismissed + } + } + + ViewState.NoItems -> { + ActionCardState.UpgradePremium.takeIf { premiumCard == PremiumCard.UPGRADE } + ?: ActionCardState.PremiumNeedsAttention.takeIf { + premiumCard == PremiumCard.NEEDS_ATTENTION + } + ?: ActionCardState.ImportItems.takeIf { showImportActionCard } + } + + is ViewState.Error, + ViewState.Loading, + -> null } /** @@ -2211,6 +2221,11 @@ data class VaultState( * Indicates that the archive feature is ready for use. */ data object IntroducingArchive : ActionCardState() + + /** + * Indicates that the import items card should be displayed. + */ + data object ImportItems : ActionCardState() } /** @@ -2599,16 +2614,6 @@ sealed class VaultAction { */ data object TryAgainClick : VaultAction() - /** - * The user has dismissed the import action card. - */ - data object DismissImportActionCard : VaultAction() - - /** - * The user has clicked the import action card. - */ - data object ImportActionCardClick : VaultAction() - /** * User clicked an overflow action. */ diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/vault/handlers/VaultHandlers.kt b/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/vault/handlers/VaultHandlers.kt index 23f338e7ab..2bb0288a29 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/vault/handlers/VaultHandlers.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/vault/handlers/VaultHandlers.kt @@ -44,8 +44,6 @@ data class VaultHandlers( String, ) -> Unit, val masterPasswordRepromptSubmit: (VaultState.ViewState.VaultItem, String) -> Unit, - val dismissImportActionCard: () -> Unit, - val importActionCardClick: () -> Unit, val flightRecorderGoToSettingsClick: () -> Unit, val dismissFlightRecorderSnackbar: () -> Unit, val onShareCipherDecryptionErrorClick: (selectedCipherId: String) -> Unit, @@ -131,12 +129,6 @@ data class VaultHandlers( ), ) }, - dismissImportActionCard = { - viewModel.trySendAction(VaultAction.DismissImportActionCard) - }, - importActionCardClick = { - viewModel.trySendAction(VaultAction.ImportActionCardClick) - }, flightRecorderGoToSettingsClick = { viewModel.trySendAction(VaultAction.FlightRecorderGoToSettingsClick) }, diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/vault/VaultScreenTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/vault/VaultScreenTest.kt index ddf1ddbc96..60e4dfb394 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/vault/VaultScreenTest.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/vault/VaultScreenTest.kt @@ -2498,7 +2498,7 @@ class VaultScreenTest : BitwardenComposeTest() { } @Test - fun `when import action card is showing, clicking it should send ImportLoginsClick action`() { + fun `when import action card is showing, clicking it should send ActionCardClick action`() { mutableStateFlow.update { it.copy( viewState = VaultState.ViewState.NoItems, @@ -2509,12 +2509,16 @@ class VaultScreenTest : BitwardenComposeTest() { .onNodeWithText("Get started") .performClick() - verify { viewModel.trySendAction(VaultAction.ImportActionCardClick) } + verify { + viewModel.trySendAction( + VaultAction.ActionCardClick(VaultState.ActionCardState.ImportItems), + ) + } } @Suppress("MaxLineLength") @Test - fun `when import action card is showing, dismissing it should send DismissImportActionCard action`() { + fun `when import action card is showing, dismissing it should send DismissActionCardClick action`() { mutableStateFlow.update { it.copy( viewState = VaultState.ViewState.NoItems, @@ -2524,7 +2528,11 @@ class VaultScreenTest : BitwardenComposeTest() { composeTestRule .onNodeWithContentDescription("Close") .performClick() - verify { viewModel.trySendAction(VaultAction.DismissImportActionCard) } + verify { + viewModel.trySendAction( + VaultAction.DismissActionCardClick(VaultState.ActionCardState.ImportItems), + ) + } } @Test diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/vault/VaultViewModelTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/vault/VaultViewModelTest.kt index 924a288e35..786af7446f 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/vault/VaultViewModelTest.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/vault/VaultViewModelTest.kt @@ -3950,9 +3950,11 @@ class VaultViewModelTest : BaseViewModelTest() { @Suppress("MaxLineLength") @Test - fun `when DismissImportActionCard is sent, repository called to showImportLogins to false and storeShowImportLoginsBadge to true`() { + fun `DismissActionCardClick with ImportItems should call storeShowImportLogins false and storeShowImportLoginsSettingsBadge true`() { val viewModel = createViewModel() - viewModel.trySendAction(VaultAction.DismissImportActionCard) + viewModel.trySendAction( + VaultAction.DismissActionCardClick(VaultState.ActionCardState.ImportItems), + ) verify(exactly = 1) { firstTimeActionManager.storeShowImportLogins(false) firstTimeActionManager.storeShowImportLoginsSettingsBadge(true) @@ -3961,7 +3963,7 @@ class VaultViewModelTest : BaseViewModelTest() { @Suppress("MaxLineLength") @Test - fun `when DismissImportActionCard is sent, repository is not called if value is already false`() { + fun `DismissActionCardClick with ImportItems should not call storeShowImportLogins if value is already false`() { mutableUserStateFlow.value = DEFAULT_USER_STATE.copy( accounts = DEFAULT_USER_STATE.accounts.map { it.copy( @@ -3972,18 +3974,25 @@ class VaultViewModelTest : BaseViewModelTest() { }, ) val viewModel = createViewModel() - viewModel.trySendAction(VaultAction.DismissImportActionCard) + viewModel.trySendAction( + VaultAction.DismissActionCardClick(VaultState.ActionCardState.ImportItems), + ) + verify(exactly = 1) { + firstTimeActionManager.storeShowImportLoginsSettingsBadge(true) + } verify(exactly = 0) { firstTimeActionManager.storeShowImportLogins(false) } } @Test - fun `when ImportActionCardClick is sent, NavigateToImportLogins event is sent`() = + fun `ActionCardClick with ImportItems should emit NavigateToImportLogins`() = runTest { val viewModel = createViewModel() viewModel.eventFlow.test { - viewModel.trySendAction(VaultAction.ImportActionCardClick) + viewModel.trySendAction( + VaultAction.ActionCardClick(VaultState.ActionCardState.ImportItems), + ) assertEquals(VaultEvent.NavigateToImportLogins, awaitItem()) } verify(exactly = 0) { @@ -3991,22 +4000,76 @@ class VaultViewModelTest : BaseViewModelTest() { } } + @Suppress("MaxLineLength") @Test - fun `when ImportActionCardClick is sent, repository is not called if value is already false`() { - mutableUserStateFlow.value = DEFAULT_USER_STATE.copy( - accounts = DEFAULT_USER_STATE.accounts.map { - it.copy( - firstTimeState = DEFAULT_FIRST_TIME_STATE.copy( - showImportLoginsCard = false, - ), - ) - }, + fun `actionCard should return ImportItems when NoItems is showing and showImportActionCard is true`() { + val state = createMockVaultState(viewState = VaultState.ViewState.NoItems).copy( + premiumCard = PremiumCard.NONE, + showImportActionCard = true, ) - val viewModel = createViewModel() - viewModel.trySendAction(VaultAction.ImportActionCardClick) - verify(exactly = 0) { - firstTimeActionManager.storeShowImportLogins(false) - } + + assertEquals( + VaultState.ActionCardState.ImportItems, + state.actionCard, + ) + } + + @Test + fun `actionCard should return UpgradePremium when NoItems is showing and eligible`() { + val state = createMockVaultState(viewState = VaultState.ViewState.NoItems).copy( + premiumCard = PremiumCard.UPGRADE, + showImportActionCard = true, + ) + + assertEquals( + VaultState.ActionCardState.UpgradePremium, + state.actionCard, + ) + } + + @Test + fun `actionCard should return PremiumNeedsAttention when NoItems is showing and eligible`() { + val state = createMockVaultState(viewState = VaultState.ViewState.NoItems).copy( + premiumCard = PremiumCard.NEEDS_ATTENTION, + showImportActionCard = true, + ) + + assertEquals( + VaultState.ActionCardState.PremiumNeedsAttention, + state.actionCard, + ) + } + + @Test + fun `actionCard should return null when NoItems is showing and not eligible for any card`() { + val state = createMockVaultState(viewState = VaultState.ViewState.NoItems).copy( + premiumCard = PremiumCard.NONE, + showImportActionCard = false, + ) + + assertNull(state.actionCard) + } + + @Test + fun `actionCard should return null when Loading is showing`() { + val state = createMockVaultState(viewState = VaultState.ViewState.Loading).copy( + premiumCard = PremiumCard.UPGRADE, + showImportActionCard = true, + ) + + assertNull(state.actionCard) + } + + @Test + fun `actionCard should return null when Error is showing`() { + val state = createMockVaultState( + viewState = VaultState.ViewState.Error(message = "error".asText()), + ).copy( + premiumCard = PremiumCard.UPGRADE, + showImportActionCard = true, + ) + + assertNull(state.actionCard) } @Test