Repository: govuk-one-login/mobile-android-cri-orchestrator
Pull request #257: refactor: make select passport code consistent with select brp
Author: login: emanuel-gds
Created: 2025-04-01T14:33:10Z | Merged: 2025-04-01T16:18:28Z

# Refactor Select Passport to make is consistent with BRP

There are some inconsistencies and also applied the some changes based on feedback from https://github.com/govuk-one-login/mobile-android-cri-orchestrator/pull/236

Changes:
- Rename confirm destination to `ConfirmPassport`
- Remove state from view model. This was being used for the yes/no list items but it was not storing the selected state in the view model. Changed it to be a constant just like the other text fields
- Remove static string parameters from `SelectPassportScreenContent` composable and referenced the `SelectPassportConstants` directly
- Replace the extension function with a `setup()` method on the `SelectPassportAnalyticsTest`


[//]: # (Screenshots / uploaded videos go here)

## Checklist

- [ ] Check against acceptance criteria
- [ ] Add automated tests
- [x] Self-review code



Diff:
diff --git a/features/select-doc/internal-api/src/main/kotlin/uk/gov/onelogin/criorchestrator/features/selectdoc/internalapi/nav/SelectDocumentDestinations.kt b/features/select-doc/internal-api/src/main/kotlin/uk/gov/onelogin/criorchestrator/features/selectdoc/internalapi/nav/SelectDocumentDestinations.kt
index f565694eb..e3589ca3e 100644
--- a/features/select-doc/internal-api/src/main/kotlin/uk/gov/onelogin/criorchestrator/features/selectdoc/internalapi/nav/SelectDocumentDestinations.kt
+++ b/features/select-doc/internal-api/src/main/kotlin/uk/gov/onelogin/criorchestrator/features/selectdoc/internalapi/nav/SelectDocumentDestinations.kt
@@ -17,5 +17,5 @@ sealed interface SelectDocumentDestinations : ProveYourIdentityDestinations {
     data object TypesOfPhotoID : SelectDocumentDestinations
 
     @Serializable
-    data object Confirm : SelectDocumentDestinations
+    data object ConfirmPassport : SelectDocumentDestinations
 }
diff --git a/features/select-doc/internal/src/main/kotlin/uk/gov/onelogin/criorchestrator/features/selectdoc/internal/SelectDocumentNavGraphProvider.kt b/features/select-doc/internal/src/main/kotlin/uk/gov/onelogin/criorchestrator/features/selectdoc/internal/SelectDocumentNavGraphProvider.kt
index c32176373..8c0247cd1 100644
--- a/features/select-doc/internal/src/main/kotlin/uk/gov/onelogin/criorchestrator/features/selectdoc/internal/SelectDocumentNavGraphProvider.kt
+++ b/features/select-doc/internal/src/main/kotlin/uk/gov/onelogin/criorchestrator/features/selectdoc/internal/SelectDocumentNavGraphProvider.kt
@@ -50,7 +50,7 @@ class SelectDocumentNavGraphProvider
                 )
             }
 
-            composable<SelectDocumentDestinations.Confirm> {
+            composable<SelectDocumentDestinations.ConfirmPassport> {
                 ConfirmDocumentScreen()
             }
         }
diff --git a/features/select-doc/internal/src/main/kotlin/uk/gov/onelogin/criorchestrator/features/selectdoc/internal/passport/SelectPassportConstants.kt b/features/select-doc/internal/src/main/kotlin/uk/gov/onelogin/criorchestrator/features/selectdoc/internal/passport/SelectPassportConstants.kt
index 78210c66b..45c96fd82 100644
--- a/features/select-doc/internal/src/main/kotlin/uk/gov/onelogin/criorchestrator/features/selectdoc/internal/passport/SelectPassportConstants.kt
+++ b/features/select-doc/internal/src/main/kotlin/uk/gov/onelogin/criorchestrator/features/selectdoc/internal/passport/SelectPassportConstants.kt
@@ -1,12 +1,23 @@
 package uk.gov.onelogin.criorchestrator.features.selectdoc.internal.passport
 
 import androidx.annotation.StringRes
+import kotlinx.collections.immutable.ImmutableList
+import kotlinx.collections.immutable.persistentListOf
 import uk.gov.onelogin.criorchestrator.features.selectdoc.internal.R
 
 internal object SelectPassportConstants {
-    @StringRes val titleId: Int = R.string.selectdocument_passport_title
+    @StringRes
+    val titleId: Int = R.string.selectdocument_passport_title
 
-    @StringRes val readMoreButtonTextId: Int = R.string.selectdocument_passport_readmore_button
+    @StringRes
+    val readMoreButtonTextId: Int = R.string.selectdocument_passport_readmore_button
 
-    @StringRes val buttonTextId: Int = R.string.selectdocument_passport_continuebutton
+    @StringRes
+    val buttonTextId: Int = R.string.selectdocument_passport_continuebutton
+
+    val options: ImmutableList<Int> =
+        persistentListOf(
+            R.string.selectdocument_passport_selection_yes,
+            R.string.selectdocument_passport_selection_no,
+        )
 }
diff --git a/features/select-doc/internal/src/main/kotlin/uk/gov/onelogin/criorchestrator/features/selectdoc/internal/passport/SelectPassportScreen.kt b/features/select-doc/internal/src/main/kotlin/uk/gov/onelogin/criorchestrator/features/selectdoc/internal/passport/SelectPassportScreen.kt
index 115629575..f51a9c661 100644
--- a/features/select-doc/internal/src/main/kotlin/uk/gov/onelogin/criorchestrator/features/selectdoc/internal/passport/SelectPassportScreen.kt
+++ b/features/select-doc/internal/src/main/kotlin/uk/gov/onelogin/criorchestrator/features/selectdoc/internal/passport/SelectPassportScreen.kt
@@ -18,9 +18,7 @@ import androidx.compose.ui.Modifier
 import androidx.compose.ui.res.painterResource
 import androidx.compose.ui.res.stringResource
 import androidx.compose.ui.text.style.TextAlign
-import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import androidx.navigation.NavController
-import kotlinx.collections.immutable.PersistentList
 import kotlinx.collections.immutable.toPersistentList
 import uk.gov.android.ui.componentsv2.button.ButtonType
 import uk.gov.android.ui.componentsv2.button.GdsButton
@@ -42,8 +40,6 @@ internal fun SelectPassportScreen(
     navController: NavController,
     modifier: Modifier = Modifier,
 ) {
-    val state by viewModel.state.collectAsStateWithLifecycle()
-
     LaunchedEffect(Unit) {
         viewModel.onScreenStart()
 
@@ -56,7 +52,7 @@ internal fun SelectPassportScreen(
 
                 SelectPassportAction.NavigateToConfirmation ->
                     navController.navigate(
-                        SelectDocumentDestinations.Confirm,
+                        SelectDocumentDestinations.ConfirmPassport,
                     )
 
                 SelectPassportAction.NavigateToBrp ->
@@ -68,15 +64,8 @@ internal fun SelectPassportScreen(
     }
 
     SelectPassportScreenContent(
-        title = stringResource(SelectPassportConstants.titleId),
         modifier = modifier,
-        readMoreButtonTitle = stringResource(SelectPassportConstants.readMoreButtonTextId),
         onReadMoreClick = viewModel::onReadMoreClick,
-        items =
-            state.options
-                .map { stringResource(it) }
-                .toPersistentList(),
-        confirmButtonText = stringResource(SelectPassportConstants.buttonTextId),
         onConfirmSelection = viewModel::onConfirmSelection,
     )
 }
@@ -85,11 +74,7 @@ internal fun SelectPassportScreen(
 @Suppress("LongMethod", "LongParameterList")
 @Composable
 internal fun SelectPassportScreenContent(
-    title: String,
-    readMoreButtonTitle: String,
     onReadMoreClick: () -> Unit,
-    items: PersistentList<String>,
-    confirmButtonText: String,
     onConfirmSelection: (Int) -> Unit,
     modifier: Modifier = Modifier,
 ) {
@@ -101,7 +86,7 @@ internal fun SelectPassportScreenContent(
         LeftAlignedScreen(
             title = { horizontalPadding ->
                 GdsHeading(
-                    text = title,
+                    text = stringResource(SelectPassportConstants.titleId),
                     modifier = Modifier.padding(horizontal = horizontalPadding),
                 )
             },
@@ -128,7 +113,7 @@ internal fun SelectPassportScreenContent(
                 }
                 item {
                     GdsButton(
-                        text = readMoreButtonTitle,
+                        text = stringResource(SelectPassportConstants.readMoreButtonTextId),
                         buttonType = ButtonType.Secondary,
                         onClick = onReadMoreClick,
                         modifier = Modifier.padding(horizontal = horizontalPadding),
@@ -144,7 +129,10 @@ internal fun SelectPassportScreenContent(
                                 stringResource(R.string.selectdocument_passport_title),
                                 TitleType.Heading,
                             ),
-                        items = items,
+                        items =
+                            SelectPassportConstants.options
+                                .map { stringResource(it) }
+                                .toPersistentList(),
                         selectedItem = selectedItem,
                         onItemSelected = {
                             selectedItem = it
@@ -154,7 +142,7 @@ internal fun SelectPassportScreenContent(
             },
             primaryButton = {
                 GdsButton(
-                    text = confirmButtonText,
+                    text = stringResource(SelectPassportConstants.buttonTextId),
                     buttonType = ButtonType.Primary,
                     onClick = {
                         selectedItem?.let {
@@ -175,15 +163,7 @@ internal fun SelectPassportScreenContent(
 internal fun PreviewPassportSelectionScreen() {
     GdsTheme {
         SelectPassportScreenContent(
-            title = stringResource(R.string.selectdocument_passport_title),
-            readMoreButtonTitle = stringResource(R.string.selectdocument_passport_readmore_button),
             onReadMoreClick = { },
-            items =
-                listOf(
-                    R.string.selectdocument_passport_selection_yes,
-                    R.string.selectdocument_passport_selection_no,
-                ).map { stringResource(it) }.toPersistentList(),
-            confirmButtonText = stringResource(R.string.selectdocument_passport_continuebutton),
             onConfirmSelection = { },
         )
     }
diff --git a/features/select-doc/internal/src/main/kotlin/uk/gov/onelogin/criorchestrator/features/selectdoc/internal/passport/SelectPassportState.kt b/features/select-doc/internal/src/main/kotlin/uk/gov/onelogin/criorchestrator/features/selectdoc/internal/passport/SelectPassportState.kt
deleted file mode 100644
index 56c57e195..000000000
--- a/features/select-doc/internal/src/main/kotlin/uk/gov/onelogin/criorchestrator/features/selectdoc/internal/passport/SelectPassportState.kt
+++ /dev/null
@@ -1,7 +0,0 @@
-package uk.gov.onelogin.criorchestrator.features.selectdoc.internal.passport
-
-import kotlinx.collections.immutable.PersistentList
-
-data class SelectPassportState(
-    val options: PersistentList<Int>,
-)
diff --git a/features/select-doc/internal/src/main/kotlin/uk/gov/onelogin/criorchestrator/features/selectdoc/internal/passport/SelectPassportViewModel.kt b/features/select-doc/internal/src/main/kotlin/uk/gov/onelogin/criorchestrator/features/selectdoc/internal/passport/SelectPassportViewModel.kt
index 16a060e58..dd7b1c9a4 100644
--- a/features/select-doc/internal/src/main/kotlin/uk/gov/onelogin/criorchestrator/features/selectdoc/internal/passport/SelectPassportViewModel.kt
+++ b/features/select-doc/internal/src/main/kotlin/uk/gov/onelogin/criorchestrator/features/selectdoc/internal/passport/SelectPassportViewModel.kt
@@ -2,31 +2,15 @@ package uk.gov.onelogin.criorchestrator.features.selectdoc.internal.passport
 
 import androidx.lifecycle.ViewModel
 import androidx.lifecycle.viewModelScope
-import kotlinx.collections.immutable.persistentListOf
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.MutableSharedFlow
-import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.launch
-import uk.gov.onelogin.criorchestrator.features.selectdoc.internal.R
 import uk.gov.onelogin.criorchestrator.features.selectdoc.internal.analytics.SelectDocumentAnalytics
 import uk.gov.onelogin.criorchestrator.features.selectdoc.internal.analytics.SelectDocumentScreenId
 
 internal class SelectPassportViewModel(
     private val analytics: SelectDocumentAnalytics,
 ) : ViewModel() {
-    private val _state =
-        MutableStateFlow(
-            SelectPassportState(
-                options =
-                    persistentListOf(
-                        R.string.selectdocument_passport_selection_yes,
-                        R.string.selectdocument_passport_selection_no,
-                    ),
-            ),
-        )
-    val state: StateFlow<SelectPassportState> = _state
-
     private val _actions = MutableSharedFlow<SelectPassportAction>()
     val actions: Flow<SelectPassportAction> = _actions
 
@@ -47,7 +31,7 @@ internal class SelectPassportViewModel(
     fun onConfirmSelection(selectedIndex: Int) {
         analytics.trackFormSubmission(
             buttonText = SelectPassportConstants.buttonTextId,
-            response = state.value.options[selectedIndex],
+            response = SelectPassportConstants.options[selectedIndex],
         )
 
         viewModelScope.launch {
diff --git a/features/select-doc/internal/src/test/kotlin/uk/gov/onelogin/criorchestrator/features/selectdoc/internal/passport/SelectPassportScreenAnalyticsTest.kt b/features/select-doc/internal/src/test/kotlin/uk/gov/onelogin/criorchestrator/features/selectdoc/internal/passport/SelectPassportScreenAnalyticsTest.kt
index 2269fd523..bcef34c39 100644
--- a/features/select-doc/internal/src/test/kotlin/uk/gov/onelogin/criorchestrator/features/selectdoc/internal/passport/SelectPassportScreenAnalyticsTest.kt
+++ b/features/select-doc/internal/src/test/kotlin/uk/gov/onelogin/criorchestrator/features/selectdoc/internal/passport/SelectPassportScreenAnalyticsTest.kt
@@ -3,7 +3,6 @@ package uk.gov.onelogin.criorchestrator.features.selectdoc.internal.passport
 import android.content.Context
 import androidx.compose.ui.test.hasContentDescription
 import androidx.compose.ui.test.hasText
-import androidx.compose.ui.test.junit4.ComposeContentTestRule
 import androidx.compose.ui.test.junit4.createComposeRule
 import androidx.compose.ui.test.onParent
 import androidx.compose.ui.test.performClick
@@ -12,6 +11,7 @@ import androidx.compose.ui.test.swipeUp
 import androidx.navigation.compose.rememberNavController
 import androidx.test.core.app.ApplicationProvider
 import androidx.test.ext.junit.runners.AndroidJUnit4
+import org.junit.Before
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -57,6 +57,16 @@ class SelectPassportScreenAnalyticsTest {
             analytics = analytics,
         )
 
+    @Before
+    fun setup() {
+        composeTestRule.setContent {
+            SelectPassportScreen(
+                viewModel = viewModel,
+                navController = rememberNavController(),
+            )
+        }
+    }
+
     @Test
     fun `when screen is started, it tracks analytics`() {
         val expectedEvent =
@@ -66,14 +76,11 @@ class SelectPassportScreenAnalyticsTest {
                     name = context.getString(R.string.selectdocument_passport_title),
                     params = SelectDocumentAnalytics.requiredParameters,
                 ).asLegacyEvent()
-        composeTestRule.setSelectPassportScreenContent()
         assertContains(analyticsLogger.loggedEvents, expectedEvent)
     }
 
     @Test
     fun `given selection is made, when continue button is clicked, it tracks analytics`() {
-        composeTestRule.setSelectPassportScreenContent()
-
         swipeToAdditionalContent()
 
         composeTestRule
@@ -96,8 +103,6 @@ class SelectPassportScreenAnalyticsTest {
 
     @Test
     fun `when read more is clicked, it tracks analytics`() {
-        composeTestRule.setSelectPassportScreenContent()
-
         swipeToAdditionalContent()
 
         composeTestRule
@@ -113,15 +118,6 @@ class SelectPassportScreenAnalyticsTest {
         assertContains(analyticsLogger.loggedEvents, expectedEvent)
     }
 
-    private fun ComposeContentTestRule.setSelectPassportScreenContent() {
-        setContent {
-            SelectPassportScreen(
-                viewModel = viewModel,
-                navController = rememberNavController(),
-            )
-        }
-    }
-
     private fun swipeToAdditionalContent() {
         composeTestRule
             .onNode(
diff --git a/features/select-doc/internal/src/test/kotlin/uk/gov/onelogin/criorchestrator/features/selectdoc/internal/passport/SelectPassportScreenTest.kt b/features/select-doc/internal/src/test/kotlin/uk/gov/onelogin/criorchestrator/features/selectdoc/internal/passport/SelectPassportScreenTest.kt
index ba645e5a9..255e9faaa 100644
--- a/features/select-doc/internal/src/test/kotlin/uk/gov/onelogin/criorchestrator/features/selectdoc/internal/passport/SelectPassportScreenTest.kt
+++ b/features/select-doc/internal/src/test/kotlin/uk/gov/onelogin/criorchestrator/features/selectdoc/internal/passport/SelectPassportScreenTest.kt
@@ -151,7 +151,7 @@ class SelectPassportScreenTest {
             .assertIsEnabled()
             .performClick()
 
-        verify(navController).navigate(SelectDocumentDestinations.Confirm)
+        verify(navController).navigate(SelectDocumentDestinations.ConfirmPassport)
     }
 
     @Test


Reviews:
user: login: jonnyandrew
body: Thanks for doing this!
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-01T15:30:26Z
user: login: obinns-dd
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-01T15:33:55Z
user: login: JacksonJ2W
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-01T15:34:56Z
user: login: emanuel-gds
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-01T15:57:18Z

Review comments:
diff_hunk: @@ -50,7 +50,7 @@ class SelectDocumentNavGraphProvider
                 )
             }
 
-            composable<SelectDocumentDestinations.Confirm> {
+            composable<SelectDocumentDestinations.ConfirmPassport> {
                 ConfirmDocumentScreen()
             }
path: features/select-doc/internal/src/main/kotlin/uk/gov/onelogin/criorchestrator/features/selectdoc/internal/SelectDocumentNavGraphProvider.kt
user: login: jonnyandrew
body: This is doesn't look right at the moment but I assume `ConfirmDocumentScreen` will eventually become `ConfirmPassportScreen`? cc @JacksonJ2W 
created_at: 2025-04-01T15:30:02Z
author_association: CONTRIBUTOR
diff_hunk: @@ -50,7 +50,7 @@ class SelectDocumentNavGraphProvider
                 )
             }
 
-            composable<SelectDocumentDestinations.Confirm> {
+            composable<SelectDocumentDestinations.ConfirmPassport> {
                 ConfirmDocumentScreen()
             }
path: features/select-doc/internal/src/main/kotlin/uk/gov/onelogin/criorchestrator/features/selectdoc/internal/SelectDocumentNavGraphProvider.kt
user: login: JacksonJ2W
body: Yep this will change 
created_at: 2025-04-01T15:34:56Z
author_association: CONTRIBUTOR
diff_hunk: @@ -50,7 +50,7 @@ class SelectDocumentNavGraphProvider
                 )
             }
 
-            composable<SelectDocumentDestinations.Confirm> {
+            composable<SelectDocumentDestinations.ConfirmPassport> {
                 ConfirmDocumentScreen()
             }
path: features/select-doc/internal/src/main/kotlin/uk/gov/onelogin/criorchestrator/features/selectdoc/internal/SelectDocumentNavGraphProvider.kt
user: login: emanuel-gds
body: Good catch!
created_at: 2025-04-01T15:57:17Z
author_association: CONTRIBUTOR

PR comments:
user: login: github-actions[bot]
created_at: 2025-04-01T14:40:30Z
body: Analytics test report is [available to download].

[available to download]: https://github.com/govuk-one-login/mobile-android-cri-orchestrator/actions/runs/14200414766/artifacts/2860834427
author_association: NONE
user: login: sonarqubecloud[bot]
created_at: 2025-04-01T16:11:43Z
body: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=mobile-android-cri-orchestrator&pullRequest=257) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=mobile-android-cri-orchestrator&pullRequest=257&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=mobile-android-cri-orchestrator&pullRequest=257&issueStatuses=ACCEPTED)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=mobile-android-cri-orchestrator&pullRequest=257&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [90.0% Coverage on New Code](https://sonarcloud.io/component_measures?id=mobile-android-cri-orchestrator&pullRequest=257&metric=new_coverage&view=list)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=mobile-android-cri-orchestrator&pullRequest=257&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=mobile-android-cri-orchestrator&pullRequest=257)


author_association: NONE