TP-86113 | Narayan | Old Select bank screen code removal (#12791)
This commit is contained in:
committed by
GitHub
parent
41c131d5dc
commit
03ba2d0833
@@ -15,8 +15,6 @@ import com.navi.base.deeplink.DeepLinkManager
|
||||
import com.navi.base.model.CtaData
|
||||
import com.navi.base.sharedpref.PreferenceManager
|
||||
import com.navi.base.utils.EMPTY
|
||||
import com.navi.common.upi.ACCOUNT_TYPE
|
||||
import com.navi.common.upi.IS_FRESH_ON_BOARDING
|
||||
import com.navi.common.upi.PIN_ACTION
|
||||
import com.navi.common.upi.PMS
|
||||
import com.navi.common.upi.SEND_MONEY_SCREEN_SOURCE
|
||||
@@ -39,7 +37,6 @@ import com.navi.pay.destinations.OrderHistoryScreenDestination
|
||||
import com.navi.pay.destinations.PayToContactsScreenDestination
|
||||
import com.navi.pay.destinations.QrScannerScreenDestination
|
||||
import com.navi.pay.destinations.SavedBeneficiaryScreenDestination
|
||||
import com.navi.pay.destinations.SelectBankScreenDestination
|
||||
import com.navi.pay.destinations.SendMoneyScreenDestination
|
||||
import com.navi.pay.destinations.SendMoneyScreenV2Destination
|
||||
import com.navi.pay.destinations.SetPinConfirmationScreenDestination
|
||||
@@ -51,7 +48,6 @@ import com.navi.pay.entry.NaviPayActivity
|
||||
import com.navi.pay.management.common.sendmoney.model.view.SendMoneyScreenSource
|
||||
import com.navi.pay.management.common.sendmoney.model.view.UpiTransactionType
|
||||
import com.navi.pay.management.moneytransfer.scanpay.util.getPayeeEntity
|
||||
import com.navi.pay.onboarding.account.add.model.view.AccountType
|
||||
import com.navi.pay.onboarding.account.linked.model.view.LinkedAccountsScreenSource
|
||||
import com.navi.pay.utils.ACTION_PIN_SET
|
||||
import com.navi.pay.utils.BANK_ACCOUNT_UNIQUE_ID
|
||||
@@ -153,15 +149,6 @@ object NaviPayRouter {
|
||||
SetPinConfirmationScreenDestination(source = sourceScreenName)
|
||||
NaviPayScreenType.NAVI_PAY_TO_CONTACTS.name ->
|
||||
PayToContactsScreenDestination(openSearchState = false)
|
||||
NaviPayScreenType.SELECT_BANK_SCREEN_ONBOARDING.name -> {
|
||||
val isFreshOnBoardingCase = bundle.getBoolean(IS_FRESH_ON_BOARDING, true)
|
||||
val accountType =
|
||||
AccountType.getAccountType(bundle.getString(ACCOUNT_TYPE).orEmpty())
|
||||
SelectBankScreenDestination(
|
||||
isFreshOnBoardingCase = isFreshOnBoardingCase,
|
||||
accountType = accountType
|
||||
)
|
||||
}
|
||||
NaviPayScreenType.NAVI_PAY_SEND_MONEY_SCREEN.name -> {
|
||||
val payeeEntity =
|
||||
Uri.parse(bundle.getString(NAVI_PAY_UPI_URI_KEY)).getPayeeEntity(true)
|
||||
|
||||
@@ -65,6 +65,7 @@ import com.navi.pay.common.theme.color.NaviPayColor
|
||||
import com.navi.pay.common.ui.NaviPayModalBottomSheetLayout
|
||||
import com.navi.pay.common.ui.ThemeRoundedButton
|
||||
import com.navi.pay.common.utils.NaviPayCommonUtils.launchPermissionSettingsScreen
|
||||
import com.navi.pay.common.utils.launchOnboardingSDK
|
||||
import com.navi.pay.entry.NaviPayActivity
|
||||
import com.navi.pay.management.common.paymentsummary.model.view.BottomBarCtaStateForRewards
|
||||
import com.navi.pay.management.common.paymentsummary.model.view.PaymentSummaryBottomSheetUIState
|
||||
@@ -225,6 +226,18 @@ fun PaymentSummaryScreenV2(
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
paymentSummaryViewModel.onboardingSdkAction.collect {
|
||||
paymentSummaryViewModel.clearOnboardingSdkReplayCache()
|
||||
if (it != null) {
|
||||
naviPayActivity.launchOnboardingSDK(
|
||||
action = it.action,
|
||||
enabledAccountTypes = it.enabledAccountTypes
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
paymentSummaryViewModel.updateAreNotificationsEnabled(
|
||||
areNotificationsEnabled = areNotificationsEnabled(context = naviPayActivity)
|
||||
|
||||
@@ -91,6 +91,7 @@ import com.navi.pay.common.ui.NaviPayModalBottomSheetLayout
|
||||
import com.navi.pay.common.ui.ThemeRoundedButton
|
||||
import com.navi.pay.common.ui.TitleDescriptionWithLinearProgressBar
|
||||
import com.navi.pay.common.utils.NaviPayCommonUtils.launchPermissionSettingsScreen
|
||||
import com.navi.pay.common.utils.launchOnboardingSDK
|
||||
import com.navi.pay.entry.NaviPayActivity
|
||||
import com.navi.pay.management.common.paymentsummary.model.view.PaymentSummaryBottomSheetUIStateV2
|
||||
import com.navi.pay.management.common.paymentsummary.model.view.PaymentSummaryScreenState
|
||||
@@ -303,6 +304,18 @@ fun PaymentSummaryScreenV3(
|
||||
)
|
||||
}
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
paymentSummaryViewModel.onboardingSdkAction.collect {
|
||||
paymentSummaryViewModel.clearOnboardingSdkReplayCache()
|
||||
if (it != null) {
|
||||
naviPayActivity.launchOnboardingSDK(
|
||||
action = it.action,
|
||||
enabledAccountTypes = it.enabledAccountTypes
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
paymentSummaryViewModel.navigateToNextScreenFromHelpCta.collect {
|
||||
it?.let { NaviPayRouter.onCtaClick(naviPayActivity = naviPayActivity, ctaData = it) }
|
||||
|
||||
@@ -45,7 +45,6 @@ import com.navi.pay.common.utils.NaviPayCommonUtils
|
||||
import com.navi.pay.common.utils.combine
|
||||
import com.navi.pay.common.viewmodel.NaviPayBaseVM
|
||||
import com.navi.pay.common.widget.NaviPayWidgetManager
|
||||
import com.navi.pay.destinations.SelectBankScreenDestination
|
||||
import com.navi.pay.management.common.paymentsummary.model.view.BottomBarCtaStateForRewards
|
||||
import com.navi.pay.management.common.paymentsummary.model.view.PaymentSummaryBottomSheetStateHolder
|
||||
import com.navi.pay.management.common.paymentsummary.model.view.PaymentSummaryBottomSheetUIState
|
||||
@@ -65,7 +64,10 @@ import com.navi.pay.onboarding.account.add.model.view.AccountType
|
||||
import com.navi.pay.onboarding.account.add.model.view.AccountType.Companion.isAccountOfTypeCreditCardOrCreditLine
|
||||
import com.navi.pay.onboarding.account.add.repository.BankRepository
|
||||
import com.navi.pay.onboarding.account.detail.model.view.LinkedAccountEntity
|
||||
import com.navi.pay.onboardingV2.model.view.NaviPayOnboardingActionsV2Type
|
||||
import com.navi.pay.onboardingV2.model.view.OnboardingIntentData
|
||||
import com.navi.pay.permission.utils.PermissionStateProvider
|
||||
import com.navi.pay.utils.CREDIT_CARD_ONLY_ENABLED_ACCOUNTS
|
||||
import com.navi.pay.utils.ConfigKey
|
||||
import com.navi.pay.utils.DATE_TIME_FORMAT_DATE_MONTH_NAME_YEAR
|
||||
import com.navi.pay.utils.KEY_IS_FIRST_TRANSACTION_SUCCESSFUL
|
||||
@@ -90,6 +92,7 @@ import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import javax.inject.Inject
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
@@ -200,6 +203,9 @@ constructor(
|
||||
FirebaseRemoteConfigHelper.NAVI_PAY_POST_PAYMENT_SCREEN_BANNER_VIEW_LIMIT,
|
||||
)
|
||||
|
||||
private val _onboardingSdkAction = MutableSharedFlow<OnboardingIntentData?>(replay = 1)
|
||||
val onboardingSdkAction = _onboardingSdkAction.asSharedFlow()
|
||||
|
||||
private val isUpiNumberLinked: MutableStateFlow<Boolean?> = MutableStateFlow(null)
|
||||
|
||||
private val _widgetsRenderingOrder = MutableStateFlow<Map<String, Int>>(emptyMap())
|
||||
@@ -389,11 +395,16 @@ constructor(
|
||||
isEnabled = !isRccAccountPresent(linkedAccounts = linkedAccounts),
|
||||
onClickAction = {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
updateNavigationToNextScreen(
|
||||
direction =
|
||||
SelectBankScreenDestination(
|
||||
isFreshOnBoardingCase = false,
|
||||
accountType = AccountType.CREDIT
|
||||
_onboardingSdkAction.emit(
|
||||
value =
|
||||
OnboardingIntentData(
|
||||
action =
|
||||
NaviPayOnboardingActionsV2Type.ACCOUNT_ADDITION.name,
|
||||
enabledAccountTypes = CREDIT_CARD_ONLY_ENABLED_ACCOUNTS,
|
||||
addAccountSuccessDescription = "",
|
||||
selectedAccountId = "",
|
||||
preferredBankCode = "",
|
||||
source = NaviPayAnalytics.NAVI_PAY_PAYMENT_STATUS
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -414,11 +425,17 @@ constructor(
|
||||
isEnabled = false,
|
||||
onClickAction = {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
updateNavigationToNextScreen(
|
||||
direction =
|
||||
SelectBankScreenDestination(
|
||||
isFreshOnBoardingCase = false,
|
||||
accountType = AccountType.CREDIT
|
||||
_onboardingSdkAction.emit(
|
||||
value =
|
||||
OnboardingIntentData(
|
||||
action =
|
||||
NaviPayOnboardingActionsV2Type.ACCOUNT_ADDITION
|
||||
.name,
|
||||
enabledAccountTypes = CREDIT_CARD_ONLY_ENABLED_ACCOUNTS,
|
||||
addAccountSuccessDescription = "",
|
||||
selectedAccountId = "",
|
||||
preferredBankCode = "",
|
||||
source = NaviPayAnalytics.NAVI_PAY_PAYMENT_STATUS
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -652,6 +669,11 @@ constructor(
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
fun clearOnboardingSdkReplayCache() {
|
||||
_onboardingSdkAction.resetReplayCache()
|
||||
}
|
||||
|
||||
private fun fetchLitmusExperimentData() {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
val experimentData =
|
||||
|
||||
@@ -44,7 +44,6 @@ import com.navi.pay.common.utils.NaviPayCommonUtils
|
||||
import com.navi.pay.common.utils.combine
|
||||
import com.navi.pay.common.viewmodel.NaviPayBaseVM
|
||||
import com.navi.pay.common.widget.NaviPayWidgetManager
|
||||
import com.navi.pay.destinations.SelectBankScreenDestination
|
||||
import com.navi.pay.management.common.paymentsummary.model.view.PaymentSummaryBottomSheetStateHolderV2
|
||||
import com.navi.pay.management.common.paymentsummary.model.view.PaymentSummaryBottomSheetUIStateV2
|
||||
import com.navi.pay.management.common.paymentsummary.model.view.PaymentSummaryRewardsGratificationUIStateV2
|
||||
@@ -64,7 +63,10 @@ import com.navi.pay.onboarding.account.add.model.view.AccountType
|
||||
import com.navi.pay.onboarding.account.add.model.view.AccountType.Companion.isAccountOfTypeCreditCardOrCreditLine
|
||||
import com.navi.pay.onboarding.account.add.repository.BankRepository
|
||||
import com.navi.pay.onboarding.account.detail.model.view.LinkedAccountEntity
|
||||
import com.navi.pay.onboardingV2.model.view.NaviPayOnboardingActionsV2Type
|
||||
import com.navi.pay.onboardingV2.model.view.OnboardingIntentData
|
||||
import com.navi.pay.permission.utils.PermissionStateProvider
|
||||
import com.navi.pay.utils.CREDIT_CARD_ONLY_ENABLED_ACCOUNTS
|
||||
import com.navi.pay.utils.ConfigKey
|
||||
import com.navi.pay.utils.KEY_IS_FIRST_TRANSACTION_SUCCESSFUL
|
||||
import com.navi.pay.utils.NAVI_PAY_AUTO_POPUP_SCRATCH_CARD_COUNTER
|
||||
@@ -87,6 +89,7 @@ import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import javax.inject.Inject
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
@@ -210,6 +213,9 @@ constructor(
|
||||
FirebaseRemoteConfigHelper.NAVI_PAY_POST_PAYMENT_SCREEN_BANNER_VIEW_LIMIT,
|
||||
)
|
||||
|
||||
private val _onboardingSdkAction = MutableSharedFlow<OnboardingIntentData?>(replay = 1)
|
||||
val onboardingSdkAction = _onboardingSdkAction.asSharedFlow()
|
||||
|
||||
private val isUpiNumberLinked: MutableStateFlow<Boolean?> = MutableStateFlow(null)
|
||||
|
||||
private val _widgetsRenderingOrder = MutableStateFlow<Map<String, Int>>(emptyMap())
|
||||
@@ -399,11 +405,16 @@ constructor(
|
||||
isEnabled = !isRccAccountPresent(linkedAccounts = linkedAccounts),
|
||||
onClickAction = {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
updateNavigationToNextScreen(
|
||||
direction =
|
||||
SelectBankScreenDestination(
|
||||
isFreshOnBoardingCase = false,
|
||||
accountType = AccountType.CREDIT
|
||||
_onboardingSdkAction.emit(
|
||||
value =
|
||||
OnboardingIntentData(
|
||||
action =
|
||||
NaviPayOnboardingActionsV2Type.ACCOUNT_ADDITION.name,
|
||||
enabledAccountTypes = CREDIT_CARD_ONLY_ENABLED_ACCOUNTS,
|
||||
addAccountSuccessDescription = "",
|
||||
selectedAccountId = "",
|
||||
preferredBankCode = "",
|
||||
source = NaviPayAnalytics.NAVI_PAY_PAYMENT_STATUS
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -424,11 +435,17 @@ constructor(
|
||||
isEnabled = false,
|
||||
onClickAction = {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
updateNavigationToNextScreen(
|
||||
direction =
|
||||
SelectBankScreenDestination(
|
||||
isFreshOnBoardingCase = false,
|
||||
accountType = AccountType.CREDIT
|
||||
_onboardingSdkAction.emit(
|
||||
value =
|
||||
OnboardingIntentData(
|
||||
action =
|
||||
NaviPayOnboardingActionsV2Type.ACCOUNT_ADDITION
|
||||
.name,
|
||||
enabledAccountTypes = CREDIT_CARD_ONLY_ENABLED_ACCOUNTS,
|
||||
addAccountSuccessDescription = "",
|
||||
selectedAccountId = "",
|
||||
preferredBankCode = "",
|
||||
source = NaviPayAnalytics.NAVI_PAY_PAYMENT_STATUS
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -769,6 +786,11 @@ constructor(
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
fun clearOnboardingSdkReplayCache() {
|
||||
_onboardingSdkAction.resetReplayCache()
|
||||
}
|
||||
|
||||
private fun fetchLitmusExperimentData() {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
val experimentData =
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright © 2023 by Navi Technologies Limited
|
||||
* * All rights reserved. Strictly confidential
|
||||
*
|
||||
*/
|
||||
|
||||
package com.navi.pay.onboarding.account.add.model.view
|
||||
|
||||
import com.navi.pay.onboarding.account.add.viewmodel.SelectBankScreenBottomSheetUIState
|
||||
|
||||
data class SelectBankScreenBottomSheetHandler(
|
||||
val showBottomSheet: Boolean,
|
||||
val bottomSheetStateChange: Boolean,
|
||||
val bottomSheetUIState: SelectBankScreenBottomSheetUIState
|
||||
)
|
||||
@@ -1,382 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright © 2022-2024 by Navi Technologies Limited
|
||||
* * All rights reserved. Strictly confidential
|
||||
*
|
||||
*/
|
||||
|
||||
package com.navi.pay.onboarding.account.add.ui
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
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.layout.width
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.Divider
|
||||
import androidx.compose.material.ModalBottomSheetState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableIntStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.navi.common.R as CommonR
|
||||
import com.navi.design.font.FontWeightEnum
|
||||
import com.navi.design.theme.getFontWeight
|
||||
import com.navi.design.theme.ttComposeFontFamily
|
||||
import com.navi.naviwidgets.extensions.NaviText
|
||||
import com.navi.pay.NavGraphs
|
||||
import com.navi.pay.R
|
||||
import com.navi.pay.analytics.NaviPayAnalytics
|
||||
import com.navi.pay.common.theme.color.NaviPayColor
|
||||
import com.navi.pay.common.ui.BottomSheetContentWithIconHeaderDescButton
|
||||
import com.navi.pay.common.ui.BottomSheetContentWithIconHeaderPrimarySecondaryButtonCtaLoader
|
||||
import com.navi.pay.common.ui.BottomSheetLoadingScreen
|
||||
import com.navi.pay.common.ui.ImageWithBackground
|
||||
import com.navi.pay.common.ui.NaviPayRadioButton
|
||||
import com.navi.pay.common.ui.ThemeRoundedButton
|
||||
import com.navi.pay.destinations.NaviPayLauncherScreenDestination
|
||||
import com.navi.pay.onboarding.account.add.model.view.AccountType
|
||||
import com.navi.pay.onboarding.account.add.viewmodel.SelectBankScreenBottomSheetUIState
|
||||
import com.navi.pay.onboarding.account.detail.model.view.LinkedAccountEntity
|
||||
import com.navi.pay.onboardingV2.utils.getDescriptionTextIdForNoLinkedAccountsAsPerAccountType
|
||||
import com.navi.pay.onboardingV2.utils.getHeaderTextIdForNoLinkedAccountsAsPerAccountType
|
||||
import com.navi.pay.utils.clearBackStackUpToAndNavigate
|
||||
import com.navi.pay.utils.clickableDebounce
|
||||
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
|
||||
|
||||
@Composable
|
||||
fun SelectBankAccountBottomSheet(
|
||||
bottomSheetState: ModalBottomSheetState,
|
||||
selectBankScreenBottomSheetUIState: SelectBankScreenBottomSheetUIState,
|
||||
naviPayAnalytics: NaviPayAnalytics.NaviPaySelectBank,
|
||||
onAccountSearchNoAccountFoundButtonClicked: () -> Unit,
|
||||
onAccountSelected: (LinkedAccountEntity) -> Unit,
|
||||
onLinkAccountClicked: () -> Unit,
|
||||
onAddAccountRetry: () -> Unit,
|
||||
navigator: DestinationsNavigator,
|
||||
accountType: AccountType,
|
||||
onAddAccountErrorDismiss: () -> Unit,
|
||||
onNpciRecommendationCtaClicked: (LinkedAccountEntity?) -> Unit,
|
||||
onDismissClicked: () -> Unit
|
||||
) {
|
||||
|
||||
when (selectBankScreenBottomSheetUIState) {
|
||||
is SelectBankScreenBottomSheetUIState.Searching -> {
|
||||
if (bottomSheetState.isVisible) {
|
||||
naviPayAnalytics.onBankAccountsSearchStarted()
|
||||
}
|
||||
BottomSheetLoadingScreen(
|
||||
headerTextId = R.string.searching_accounts,
|
||||
descriptionTextId = R.string.searching_accounts_desc
|
||||
)
|
||||
}
|
||||
is SelectBankScreenBottomSheetUIState.NotFound -> {
|
||||
if (bottomSheetState.isVisible) {
|
||||
naviPayAnalytics.onBankAccountsNotFound()
|
||||
}
|
||||
BottomSheetContentWithIconHeaderDescButton(
|
||||
iconId = CommonR.drawable.ic_exclamation_red_border,
|
||||
headerTextId =
|
||||
getHeaderTextIdForNoLinkedAccountsAsPerAccountType(accountType = accountType),
|
||||
descriptionTextId =
|
||||
getDescriptionTextIdForNoLinkedAccountsAsPerAccountType(
|
||||
accountType = accountType
|
||||
),
|
||||
buttonTextId = R.string.np_okay_got_it,
|
||||
isPrimaryTypeButton = true,
|
||||
onButtonClicked = { onAccountSearchNoAccountFoundButtonClicked.invoke() }
|
||||
)
|
||||
}
|
||||
is SelectBankScreenBottomSheetUIState.Found -> {
|
||||
if (bottomSheetState.isVisible) {
|
||||
naviPayAnalytics.onBankAccountsFound(
|
||||
selectBankScreenBottomSheetUIState.accountEntities
|
||||
)
|
||||
}
|
||||
BankAccountFoundView(
|
||||
accountEntities = selectBankScreenBottomSheetUIState.accountEntities,
|
||||
onAccountSelected = onAccountSelected,
|
||||
onLinkAccountClick = onLinkAccountClicked,
|
||||
accountType = accountType,
|
||||
onDismissClicked = onDismissClicked
|
||||
)
|
||||
}
|
||||
is SelectBankScreenBottomSheetUIState.ReBind -> {
|
||||
naviPayAnalytics.onBankAccountsReBind()
|
||||
BottomSheetContentWithIconHeaderDescButton(
|
||||
iconId = CommonR.drawable.ic_exclamation_red_border,
|
||||
headerTextId = R.string.no_banks_found,
|
||||
descriptionTextId = R.string.no_banks_found_desc,
|
||||
buttonTextId = R.string.try_again,
|
||||
onButtonClicked = {
|
||||
navigator.clearBackStackUpToAndNavigate(
|
||||
destination = NaviPayLauncherScreenDestination,
|
||||
popUpTo = NavGraphs.root,
|
||||
inclusive = true
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
is SelectBankScreenBottomSheetUIState.AddAccountError -> {
|
||||
if (bottomSheetState.isVisible) {
|
||||
naviPayAnalytics.onBankLinkFailure(selectBankScreenBottomSheetUIState.title)
|
||||
}
|
||||
BottomSheetContentWithIconHeaderPrimarySecondaryButtonCtaLoader(
|
||||
header = selectBankScreenBottomSheetUIState.title,
|
||||
description = selectBankScreenBottomSheetUIState.description,
|
||||
primaryButton = stringResource(id = R.string.retry),
|
||||
secondaryButton = stringResource(id = R.string.cancel),
|
||||
onPrimaryButtonClicked = { onAddAccountRetry.invoke() },
|
||||
onSecondaryButtonClicked = onAddAccountErrorDismiss
|
||||
)
|
||||
}
|
||||
is SelectBankScreenBottomSheetUIState.NpciRecommendation -> {
|
||||
val connectedAccount = selectBankScreenBottomSheetUIState.connectedAccount
|
||||
NpciRecommendationBottomSheet(
|
||||
onNpciRecommendationCtaClicked = {
|
||||
onNpciRecommendationCtaClicked(connectedAccount)
|
||||
}
|
||||
)
|
||||
}
|
||||
else -> {
|
||||
Box(modifier = Modifier.fillMaxWidth())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun BankAccountFoundView(
|
||||
accountEntities: List<LinkedAccountEntity>,
|
||||
onAccountSelected: (LinkedAccountEntity) -> Unit,
|
||||
onLinkAccountClick: () -> Unit,
|
||||
accountType: AccountType,
|
||||
onDismissClicked: () -> Unit
|
||||
) {
|
||||
Column(modifier = Modifier.fillMaxWidth().verticalScroll(state = rememberScrollState())) {
|
||||
Row(
|
||||
modifier = Modifier.padding(16.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.Center,
|
||||
) {
|
||||
NaviText(
|
||||
text =
|
||||
stringResource(
|
||||
id =
|
||||
if (accountType != AccountType.CREDIT) R.string.select_bank_acc
|
||||
else R.string.select_your_credit_card
|
||||
),
|
||||
fontSize = 16.sp,
|
||||
fontFamily = ttComposeFontFamily,
|
||||
fontWeight = getFontWeight(FontWeightEnum.NAVI_BODY_DEMI_BOLD),
|
||||
color = NaviPayColor.textPrimary
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
|
||||
Image(
|
||||
painter = painterResource(id = CommonR.drawable.ic_close_black),
|
||||
contentDescription = null,
|
||||
modifier = Modifier.clickableDebounce { onDismissClicked.invoke() },
|
||||
)
|
||||
}
|
||||
|
||||
Divider(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
color = NaviPayColor.borderAlt,
|
||||
thickness = 1.dp
|
||||
)
|
||||
|
||||
var selectedItemPosition by remember { mutableIntStateOf(0) }
|
||||
|
||||
Column(verticalArrangement = Arrangement.spacedBy(16.dp)) {
|
||||
repeat(accountEntities.size) { position ->
|
||||
val accountEntity = accountEntities[position]
|
||||
|
||||
BankAccountEntityItem(
|
||||
bankAccountEntity = accountEntity,
|
||||
onSelected = {
|
||||
selectedItemPosition = position
|
||||
onAccountSelected.invoke(accountEntity)
|
||||
},
|
||||
isSelected = selectedItemPosition == position
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Divider(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
color = NaviPayColor.borderAlt,
|
||||
thickness = 1.dp
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
|
||||
ThemeRoundedButton(
|
||||
modifier = Modifier.fillMaxWidth().padding(16.dp),
|
||||
text = stringResource(id = R.string.continue_text),
|
||||
cornerRadius = 4.dp
|
||||
) {
|
||||
onLinkAccountClick()
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(32.dp))
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun BankAccountEntityItem(
|
||||
bankAccountEntity: LinkedAccountEntity,
|
||||
onSelected: (LinkedAccountEntity) -> Unit,
|
||||
isSelected: Boolean
|
||||
) {
|
||||
Column(
|
||||
modifier =
|
||||
Modifier.fillMaxWidth()
|
||||
.background(
|
||||
shape = RoundedCornerShape(1.dp),
|
||||
color = if (isSelected) NaviPayColor.bgLightGreen else NaviPayColor.ctaWhite
|
||||
)
|
||||
.clickableDebounce { onSelected(bankAccountEntity) }
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth().padding(16.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.Center
|
||||
) {
|
||||
ImageWithBackground(
|
||||
boxSize = 40.dp,
|
||||
backgroundColor = NaviPayColor.ctaWhite,
|
||||
backgroundCornerRadius = 4.dp,
|
||||
imageUrl = bankAccountEntity.bankIconImageUrl,
|
||||
imageSize = 36.dp
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.width(14.dp))
|
||||
|
||||
Column {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
NaviText(
|
||||
text = bankAccountEntity.bankNameAccountNumber,
|
||||
fontSize = 16.sp,
|
||||
fontFamily = ttComposeFontFamily,
|
||||
fontWeight = getFontWeight(FontWeightEnum.NAVI_HEADLINE_REGULAR),
|
||||
color = NaviPayColor.textPrimary
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
|
||||
Image(
|
||||
painter = painterResource(id = R.drawable.upi_logo_colored),
|
||||
contentDescription = null
|
||||
)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(2.dp))
|
||||
|
||||
NaviText(
|
||||
text = bankAccountEntity.accountTypeFormatted,
|
||||
fontSize = 12.sp,
|
||||
fontFamily = ttComposeFontFamily,
|
||||
fontWeight = getFontWeight(FontWeightEnum.NAVI_BODY_REGULAR),
|
||||
color = NaviPayColor.textTertiary
|
||||
)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
|
||||
NaviPayRadioButton(
|
||||
isSelected = isSelected,
|
||||
onCheckedChange = { onSelected(bankAccountEntity) }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun NpciRecommendationBottomSheet(onNpciRecommendationCtaClicked: () -> Unit) {
|
||||
Column(
|
||||
modifier =
|
||||
Modifier.fillMaxWidth().padding(start = 16.dp, end = 16.dp, top = 16.dp, bottom = 32.dp)
|
||||
) {
|
||||
NaviText(
|
||||
text = stringResource(id = R.string.navi_pay_npci_recommendation_header),
|
||||
fontSize = 18.sp,
|
||||
fontFamily = ttComposeFontFamily,
|
||||
fontWeight = getFontWeight(FontWeightEnum.NAVI_HEADLINE_REGULAR),
|
||||
color = NaviPayColor.textPrimary
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
|
||||
NpciRecommendationBottomSheetDescriptionItem(
|
||||
imageId = R.drawable.ic_np_npci_recommendation_verify_sender_id,
|
||||
descriptionId = R.string.navi_pay_npci_recommendation_verify_sender_id
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
|
||||
NpciRecommendationBottomSheetDescriptionItem(
|
||||
imageId = R.drawable.ic_np_npci_recommendation_change_pin,
|
||||
descriptionId = R.string.navi_pay_npci_recommendation_change_pin
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
|
||||
NpciRecommendationBottomSheetDescriptionItem(
|
||||
imageId = R.drawable.ic_np_npci_recommendation_donot_share_pin,
|
||||
descriptionId = R.string.navi_pay_npci_recommendation_donot_share_pin
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
|
||||
NpciRecommendationBottomSheetDescriptionItem(
|
||||
imageId = R.drawable.ic_np_npci_recommendation_collect_request_mandate,
|
||||
descriptionId = R.string.navi_pay_npci_recommendation_collect_request_mandate
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
|
||||
ThemeRoundedButton(
|
||||
text = stringResource(id = R.string.np_okay_got_it),
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
onClick = onNpciRecommendationCtaClicked
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun NpciRecommendationBottomSheetDescriptionItem(imageId: Int, descriptionId: Int) {
|
||||
Row(modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
|
||||
Image(
|
||||
painter = painterResource(id = imageId),
|
||||
contentDescription = null,
|
||||
modifier = Modifier.size(16.dp)
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.width(14.dp))
|
||||
|
||||
NaviText(
|
||||
text = stringResource(id = descriptionId),
|
||||
fontSize = 14.sp,
|
||||
fontFamily = ttComposeFontFamily,
|
||||
fontWeight = getFontWeight(FontWeightEnum.NAVI_BODY_REGULAR),
|
||||
color = NaviPayColor.textSecondary
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,918 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright © 2022-2024 by Navi Technologies Limited
|
||||
* * All rights reserved. Strictly confidential
|
||||
*
|
||||
*/
|
||||
|
||||
package com.navi.pay.onboarding.account.add.ui
|
||||
|
||||
import android.view.WindowManager
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.foundation.BorderStroke
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
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.layout.width
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.grid.GridCells
|
||||
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
|
||||
import androidx.compose.foundation.lazy.grid.items
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.text.KeyboardActions
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material.IconButton
|
||||
import androidx.compose.material.ModalBottomSheetValue
|
||||
import androidx.compose.material.OutlinedTextField
|
||||
import androidx.compose.material.TextFieldDefaults
|
||||
import androidx.compose.material.rememberModalBottomSheetState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.runtime.snapshotFlow
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalFocusManager
|
||||
import androidx.compose.ui.platform.LocalLifecycleOwner
|
||||
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
|
||||
import androidx.compose.ui.platform.LocalView
|
||||
import androidx.compose.ui.platform.SoftwareKeyboardController
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.SpanStyle
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.buildAnnotatedString
|
||||
import androidx.compose.ui.text.input.ImeAction
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextDecoration
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleEventObserver
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import androidx.paging.compose.LazyPagingItems
|
||||
import androidx.paging.compose.collectAsLazyPagingItems
|
||||
import androidx.paging.compose.itemKey
|
||||
import coil.compose.AsyncImage
|
||||
import com.airbnb.lottie.compose.LottieAnimation
|
||||
import com.airbnb.lottie.compose.LottieCompositionSpec
|
||||
import com.airbnb.lottie.compose.animateLottieCompositionAsState
|
||||
import com.airbnb.lottie.compose.rememberLottieComposition
|
||||
import com.navi.common.R as CommonR
|
||||
import com.navi.common.upi.NaviPayAction
|
||||
import com.navi.common.upi.UPI_RESULT_CODE
|
||||
import com.navi.design.font.FontWeightEnum
|
||||
import com.navi.design.theme.getFontWeight
|
||||
import com.navi.design.theme.ttComposeFontFamily
|
||||
import com.navi.design.utils.clickableWithNoGesture
|
||||
import com.navi.design.utils.maxScrollFlingBehavior
|
||||
import com.navi.naviwidgets.extensions.NaviText
|
||||
import com.navi.pay.NavGraphs
|
||||
import com.navi.pay.R
|
||||
import com.navi.pay.analytics.NaviPayAnalytics
|
||||
import com.navi.pay.common.model.view.SetPinResult
|
||||
import com.navi.pay.common.setup.NaviPayRouter
|
||||
import com.navi.pay.common.setup.model.NaviPayCustomerStatus
|
||||
import com.navi.pay.common.theme.color.NaviPayColor
|
||||
import com.navi.pay.common.ui.ImageWithBackground
|
||||
import com.navi.pay.common.ui.LoadingScreen
|
||||
import com.navi.pay.common.ui.NaviPayCreditCardSponsorView
|
||||
import com.navi.pay.common.ui.NaviPayCreditLineSponsorView
|
||||
import com.navi.pay.common.ui.NaviPayHeader
|
||||
import com.navi.pay.common.ui.NaviPayModalBottomSheetLayout
|
||||
import com.navi.pay.common.ui.NaviPaySponsorView
|
||||
import com.navi.pay.common.ui.RenderAPIResultScreen
|
||||
import com.navi.pay.common.utils.ErrorEventHandler
|
||||
import com.navi.pay.common.utils.NaviPayCommonUtils.closeKeyboardOnScroll
|
||||
import com.navi.pay.common.utils.NaviPayEventBus
|
||||
import com.navi.pay.common.utils.NaviPayMediaPlayer
|
||||
import com.navi.pay.common.utils.NaviPaySdkUtils
|
||||
import com.navi.pay.destinations.LinkedAccountVerifyScreenDestination
|
||||
import com.navi.pay.destinations.LinkedAccountsScreenV2Destination
|
||||
import com.navi.pay.entry.NaviPayActivity
|
||||
import com.navi.pay.onboarding.account.add.model.view.AccountType
|
||||
import com.navi.pay.onboarding.account.add.model.view.BankEntity
|
||||
import com.navi.pay.onboarding.account.add.viewmodel.SelectBankScreenBottomSheetUIState
|
||||
import com.navi.pay.onboarding.account.add.viewmodel.SelectBankScreenStates
|
||||
import com.navi.pay.onboarding.account.add.viewmodel.SelectBankViewModel
|
||||
import com.navi.pay.onboarding.account.detail.model.view.LinkedAccountEntity
|
||||
import com.navi.pay.onboarding.account.linked.model.view.LinkedAccountsScreenSource
|
||||
import com.navi.pay.utils.ACTION_PIN_SET
|
||||
import com.navi.pay.utils.BANK_NAME
|
||||
import com.navi.pay.utils.DEEPLINK_URL
|
||||
import com.navi.pay.utils.NAVI_PAY_ADD_ACCOUNT_REWARDS_LOTTIE
|
||||
import com.navi.pay.utils.NAVI_PAY_LOADER
|
||||
import com.navi.pay.utils.NAVI_PAY_SUCCESS_LOTTIE
|
||||
import com.navi.pay.utils.PHONE_NUMBER_LENGTH
|
||||
import com.navi.pay.utils.UPI_NUMBER_LINK
|
||||
import com.navi.pay.utils.VPA
|
||||
import com.navi.pay.utils.clearBackStackUpToAndNavigate
|
||||
import com.navi.pay.utils.clickableDebounce
|
||||
import com.navi.pay.utils.customHide
|
||||
import com.navi.pay.utils.getImageRequestBuilder
|
||||
import com.navi.pay.utils.hideSheet
|
||||
import com.navi.pay.utils.isEmpty
|
||||
import com.ramcosta.composedestinations.annotation.Destination
|
||||
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
|
||||
import com.ramcosta.composedestinations.result.ResultRecipient
|
||||
import java.lang.ref.WeakReference
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@Destination
|
||||
@Composable
|
||||
fun SelectBankScreen(
|
||||
naviPayActivity: NaviPayActivity,
|
||||
selectBankViewModel: SelectBankViewModel = hiltViewModel(),
|
||||
isFreshOnBoardingCase: Boolean = true,
|
||||
accountType: AccountType = AccountType.SAVINGS,
|
||||
resultRecipient: ResultRecipient<LinkedAccountVerifyScreenDestination, SetPinResult>,
|
||||
navigator: DestinationsNavigator,
|
||||
naviPayAnalytics: NaviPayAnalytics.NaviPaySelectBank =
|
||||
NaviPayAnalytics.INSTANCE.NaviPaySelectBank(),
|
||||
isIntentOfSelfTransfer: Boolean = false,
|
||||
) {
|
||||
|
||||
val lifecycleOwner = LocalLifecycleOwner.current
|
||||
DisposableEffect(key1 = lifecycleOwner) {
|
||||
val observer = LifecycleEventObserver { _, event ->
|
||||
if (event == Lifecycle.Event.ON_START) {
|
||||
naviPayActivity.window.setSoftInputMode(
|
||||
WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING
|
||||
)
|
||||
} else if (event == Lifecycle.Event.ON_STOP) {
|
||||
naviPayActivity.window.setSoftInputMode(
|
||||
WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE
|
||||
)
|
||||
}
|
||||
}
|
||||
lifecycleOwner.lifecycle.addObserver(observer)
|
||||
onDispose {
|
||||
naviPayActivity.window.setSoftInputMode(
|
||||
WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE
|
||||
)
|
||||
lifecycleOwner.lifecycle.removeObserver(observer)
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(Unit) { naviPayAnalytics.onNaviPaySelectBankLanded(accountType.name) }
|
||||
|
||||
val uiState by selectBankViewModel.uiState.collectAsStateWithLifecycle()
|
||||
val bottomSheetStateHolder by
|
||||
selectBankViewModel.bottomSheetStateHolder.collectAsStateWithLifecycle()
|
||||
val popularBanks by selectBankViewModel.popularBanks.collectAsStateWithLifecycle()
|
||||
val allBanks = selectBankViewModel.allBankListPager.collectAsLazyPagingItems()
|
||||
val searchQuery by selectBankViewModel.searchQuery.collectAsStateWithLifecycle()
|
||||
val rewardsNudgeDetailEntity by
|
||||
selectBankViewModel.rewardsNudgeDetailEntity.collectAsStateWithLifecycle()
|
||||
val shouldShowSponsor by selectBankViewModel.shouldShowSponsor.collectAsStateWithLifecycle()
|
||||
|
||||
val customerMobileNumber = remember { selectBankViewModel.customerPhoneNumber }
|
||||
val isTrailingIconEnabled by
|
||||
selectBankViewModel.isTrailingIconEnabled.collectAsStateWithLifecycle()
|
||||
val bottomSheetState =
|
||||
rememberModalBottomSheetState(
|
||||
initialValue = ModalBottomSheetValue.Hidden,
|
||||
confirmValueChange = { bottomSheetStateHolder.bottomSheetStateChange }
|
||||
)
|
||||
|
||||
val scope = rememberCoroutineScope()
|
||||
val keyboardController = LocalSoftwareKeyboardController.current
|
||||
val focusManager = LocalFocusManager.current
|
||||
val context = LocalContext.current
|
||||
val view = LocalView.current
|
||||
|
||||
BackHandler(
|
||||
(bottomSheetState.isVisible && bottomSheetStateHolder.bottomSheetStateChange) ||
|
||||
naviPayActivity.viewModel.isWithoutOnBoardingFlow(naviPayActivity.intent)
|
||||
) {
|
||||
if (bottomSheetState.isVisible && bottomSheetStateHolder.bottomSheetStateChange) {
|
||||
scope.launch { bottomSheetState.hideSheet() }
|
||||
} else {
|
||||
naviPayActivity.setResult(
|
||||
UPI_RESULT_CODE,
|
||||
NaviPaySdkUtils.getErrorResponseIntent(
|
||||
if (isFreshOnBoardingCase) NaviPayAction.ONBOARDING.name
|
||||
else NaviPayAction.ADD_BANK_ACCOUNT.name
|
||||
)
|
||||
)
|
||||
naviPayActivity.finish()
|
||||
}
|
||||
}
|
||||
|
||||
val onBackClick: () -> Unit = {
|
||||
if (naviPayActivity.viewModel.isWithoutOnBoardingFlow(naviPayActivity.intent)) {
|
||||
naviPayActivity.setResult(
|
||||
UPI_RESULT_CODE,
|
||||
NaviPaySdkUtils.getErrorResponseIntent(
|
||||
if (isFreshOnBoardingCase) NaviPayAction.ONBOARDING.name
|
||||
else NaviPayAction.ADD_BANK_ACCOUNT.name
|
||||
)
|
||||
)
|
||||
naviPayActivity.finish()
|
||||
} else if (isFreshOnBoardingCase) {
|
||||
naviPayActivity.onBackPressed()
|
||||
} else {
|
||||
navigator.navigateUp()
|
||||
}
|
||||
}
|
||||
|
||||
val finishActivityWithResult: () -> Unit = {
|
||||
naviPayActivity.setResult(
|
||||
UPI_RESULT_CODE,
|
||||
NaviPaySdkUtils.getOnboardingSuccessIntent(
|
||||
linkedAccountsEntity = selectBankViewModel.linkedAccounts,
|
||||
customerStatusAfterOnboarding = NaviPayCustomerStatus.LINKED_VPA.name,
|
||||
type =
|
||||
if (isFreshOnBoardingCase) NaviPayAction.ONBOARDING.name
|
||||
else NaviPayAction.ADD_BANK_ACCOUNT.name
|
||||
)
|
||||
)
|
||||
naviPayActivity.finish()
|
||||
}
|
||||
|
||||
LaunchedEffect(key1 = bottomSheetStateHolder.showBottomSheet) {
|
||||
when (bottomSheetStateHolder.showBottomSheet) {
|
||||
true -> scope.launch { bottomSheetState.show() }
|
||||
false -> scope.launch { bottomSheetState.hide() }
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
snapshotFlow { bottomSheetState.currentValue }
|
||||
.collect {
|
||||
if (it == ModalBottomSheetValue.Hidden) {
|
||||
selectBankViewModel.updateBottomSheetUIState(showBottomSheet = false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
selectBankViewModel.navigateToNextScreenFromHelpCta.collect {
|
||||
it?.let { NaviPayRouter.onCtaClick(naviPayActivity = naviPayActivity, ctaData = it) }
|
||||
}
|
||||
}
|
||||
|
||||
val navigateToNextScreen = {
|
||||
naviPayAnalytics.onNavigationToNextScreen(isFreshOnBoardingCase)
|
||||
if (isFreshOnBoardingCase) {
|
||||
// After account addition, redirect user to screen which he clicked on home screen
|
||||
val nextScreenUrl =
|
||||
naviPayActivity.viewModel.getSourceScreenUrl(naviPayActivity.intent?.data)
|
||||
if (naviPayActivity.viewModel.isHomeScreenDestination(nextScreenUrl)) {
|
||||
naviPayActivity.finish()
|
||||
} else if (naviPayActivity.viewModel.isWithoutOnBoardingFlow(naviPayActivity.intent)) {
|
||||
finishActivityWithResult.invoke()
|
||||
} else {
|
||||
val nextDestination =
|
||||
NaviPayRouter.getDirectionFromCtaUrl(
|
||||
url = nextScreenUrl,
|
||||
sourceScreenName = NaviPayAnalytics.NAVI_PAY_ADD_ACCOUNT
|
||||
) ?: NavGraphs.root
|
||||
navigator.clearBackStackUpToAndNavigate(
|
||||
destination = nextDestination,
|
||||
popUpTo = NavGraphs.root,
|
||||
inclusive = true
|
||||
)
|
||||
}
|
||||
} else if (naviPayActivity.viewModel.isWithoutOnBoardingFlow(naviPayActivity.intent)) {
|
||||
finishActivityWithResult.invoke()
|
||||
} else {
|
||||
if (selectBankViewModel.upiNumberBottomSheetNeedToShow.value) {
|
||||
naviPayActivity.intent.putExtra(VPA, selectBankViewModel.vpa)
|
||||
naviPayActivity.intent.putExtra(BANK_NAME, selectBankViewModel.bankName)
|
||||
naviPayActivity.intent.putExtra(DEEPLINK_URL, UPI_NUMBER_LINK)
|
||||
}
|
||||
navigator.navigateUp()
|
||||
}
|
||||
Unit
|
||||
}
|
||||
|
||||
val onAddAccountSuccess = { connectedAccount: LinkedAccountEntity? ->
|
||||
connectedAccount?.let {
|
||||
naviPayAnalytics.onAddAccountSuccess(
|
||||
account = connectedAccount,
|
||||
rewardNudgeShown =
|
||||
if (!isFreshOnBoardingCase && rewardsNudgeDetailEntity != null) "Y" else "N"
|
||||
)
|
||||
if (isIntentOfSelfTransfer && connectedAccount.isMPinSet) {
|
||||
navigator.navigate(
|
||||
LinkedAccountsScreenV2Destination(
|
||||
isFromAddBankAccount = true,
|
||||
linkedAccountsScreenSourceFromNavigation =
|
||||
LinkedAccountsScreenSource.SelfTransfer
|
||||
)
|
||||
)
|
||||
} else if (connectedAccount.isMPinSet) {
|
||||
navigateToNextScreen()
|
||||
} else {
|
||||
naviPayActivity.shouldFinishAfterResult = false
|
||||
navigator.navigate(
|
||||
LinkedAccountVerifyScreenDestination(
|
||||
bankAccountUniqueId = connectedAccount.accountId,
|
||||
actionName = ACTION_PIN_SET
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resultRecipient.onNavResult { result ->
|
||||
naviPayAnalytics.onPinSetCallback(result)
|
||||
// if intent of self pay and user doesn't set pin then navigate to self pay screen
|
||||
if (isIntentOfSelfTransfer) {
|
||||
navigator.navigate(
|
||||
LinkedAccountsScreenV2Destination(
|
||||
linkedAccountsScreenSourceFromNavigation =
|
||||
LinkedAccountsScreenSource.SelfTransfer
|
||||
)
|
||||
)
|
||||
}
|
||||
// Navigation to next screen no matter pin set was successful or not as user can set pin
|
||||
// later in send money
|
||||
else {
|
||||
navigateToNextScreen()
|
||||
}
|
||||
}
|
||||
|
||||
val onTrailingIconClicked = {
|
||||
selectBankViewModel.updateSearchQueryStringState(searchQuery = "")
|
||||
}
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
selectBankViewModel.navigateToNextScreen.collect {
|
||||
if (!bottomSheetState.isVisible) {
|
||||
onAddAccountSuccess(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
ErrorEventHandler.errorCtaClickEvent.collect {
|
||||
NaviPayEventBus.resetEventBus()
|
||||
if (it.errorConfig.tag == "onBankAccountsFailure") {
|
||||
naviPayAnalytics.onBankAccountsFailure()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NaviPayModalBottomSheetLayout(
|
||||
sheetState = bottomSheetState,
|
||||
sheetContent = {
|
||||
SelectBankAccountBottomSheet(
|
||||
bottomSheetState = bottomSheetState,
|
||||
selectBankScreenBottomSheetUIState = bottomSheetStateHolder.bottomSheetUIState,
|
||||
naviPayAnalytics = naviPayAnalytics,
|
||||
onAccountSearchNoAccountFoundButtonClicked = {
|
||||
scope.launch {
|
||||
selectBankViewModel.updateBottomSheetUIState(showBottomSheet = false)
|
||||
}
|
||||
},
|
||||
onAccountSelected = selectBankViewModel::onAccountSelected,
|
||||
onLinkAccountClicked = selectBankViewModel::linkAccount,
|
||||
onAddAccountRetry = {
|
||||
selectBankViewModel.selectedBank?.let {
|
||||
keyboardController?.customHide(context = context, view = view)
|
||||
selectBankViewModel.onBankSelected(bankEntity = it)
|
||||
}
|
||||
},
|
||||
navigator = navigator,
|
||||
accountType = accountType,
|
||||
onAddAccountErrorDismiss = {
|
||||
scope.launch {
|
||||
selectBankViewModel.updateBottomSheetUIState(showBottomSheet = false)
|
||||
}
|
||||
},
|
||||
onNpciRecommendationCtaClicked = { onAddAccountSuccess(it) },
|
||||
onDismissClicked = {
|
||||
scope.launch {
|
||||
selectBankViewModel.updateBottomSheetUIState(showBottomSheet = false)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
) {
|
||||
when (uiState) {
|
||||
SelectBankScreenStates.Loader -> LoadingScreen()
|
||||
SelectBankScreenStates.SelectBank -> {
|
||||
RenderSelectBankScreen(
|
||||
popularBanks = popularBanks,
|
||||
allBanks = allBanks,
|
||||
keyboardController = keyboardController,
|
||||
accountType = accountType,
|
||||
onBankSelected = {
|
||||
keyboardController?.customHide(context = context, view = view)
|
||||
focusManager.clearFocus()
|
||||
naviPayAnalytics.onBankClicked(it)
|
||||
selectBankViewModel.onBankSelected(bankEntity = it)
|
||||
},
|
||||
searchQuery = searchQuery,
|
||||
onSearchInputValueChange = {
|
||||
selectBankViewModel.updateSearchQueryStringState(searchQuery = it)
|
||||
naviPayAnalytics.onSearchBank(it)
|
||||
},
|
||||
customerMobileNumber = customerMobileNumber,
|
||||
isTrailingIconEnabled = isTrailingIconEnabled,
|
||||
onTrailingIconClicked = onTrailingIconClicked,
|
||||
helpCtaText = selectBankViewModel.helpCtaData?.title,
|
||||
onHelpCtaClicked = selectBankViewModel::onHelpClicked,
|
||||
onBackClick = onBackClick,
|
||||
shouldShowSponsor = shouldShowSponsor
|
||||
)
|
||||
}
|
||||
is SelectBankScreenStates.AddBankSuccess -> {
|
||||
// This check is here to avoid showing success animation again after coming back
|
||||
// from another screen i.e. set pin
|
||||
if (selectBankViewModel.isAddBankSuccessShown) {
|
||||
return@NaviPayModalBottomSheetLayout
|
||||
}
|
||||
|
||||
val connectedAccount =
|
||||
(uiState as SelectBankScreenStates.AddBankSuccess).connectedAccount
|
||||
|
||||
val composition by
|
||||
rememberLottieComposition(
|
||||
LottieCompositionSpec.Asset(
|
||||
if (!isFreshOnBoardingCase && rewardsNudgeDetailEntity != null)
|
||||
NAVI_PAY_ADD_ACCOUNT_REWARDS_LOTTIE
|
||||
else NAVI_PAY_SUCCESS_LOTTIE
|
||||
)
|
||||
)
|
||||
val mediaPlayer = remember {
|
||||
NaviPayMediaPlayer(activityRef = WeakReference(naviPayActivity))
|
||||
}
|
||||
val progress by animateLottieCompositionAsState(composition)
|
||||
var isAnimationAudioCompleted by remember { mutableStateOf(false) }
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
mediaPlayer.start(
|
||||
fileNameResId = R.raw.navi_pay_bank_account_success,
|
||||
onFinish = { isAnimationAudioCompleted = true }
|
||||
)
|
||||
}
|
||||
|
||||
if (progress == 1.0f && isAnimationAudioCompleted) {
|
||||
LaunchedEffect(Unit) {
|
||||
selectBankViewModel.onAddAccountSuccess(connectedAccount)
|
||||
}
|
||||
}
|
||||
|
||||
Column(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
|
||||
LottieAnimation(
|
||||
composition = composition,
|
||||
modifier = Modifier.size(140.dp),
|
||||
iterations = 1,
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
|
||||
NaviText(
|
||||
modifier = Modifier.padding(horizontal = 16.dp),
|
||||
text = stringResource(id = R.string.account_added_successfully),
|
||||
fontSize = 16.sp,
|
||||
fontFamily = ttComposeFontFamily,
|
||||
color = NaviPayColor.textPrimary,
|
||||
fontWeight = getFontWeight(FontWeightEnum.NAVI_HEADLINE_REGULAR),
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
|
||||
if (isFreshOnBoardingCase) {
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
|
||||
Row(
|
||||
modifier =
|
||||
Modifier.clickableDebounce {
|
||||
scope.launch {
|
||||
selectBankViewModel.updateBottomSheetUIState(
|
||||
selectBankScreenBottomSheetUIState =
|
||||
SelectBankScreenBottomSheetUIState
|
||||
.NpciRecommendation(connectedAccount),
|
||||
allowStateChange = false,
|
||||
showBottomSheet = true
|
||||
)
|
||||
}
|
||||
}
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource(id = R.drawable.ic_np_white_info_grey_bg),
|
||||
contentDescription = "",
|
||||
modifier = Modifier.size(16.dp)
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.width(4.dp))
|
||||
|
||||
NaviText(
|
||||
text =
|
||||
stringResource(id = R.string.navi_pay_npci_how_to_use_header),
|
||||
fontSize = 12.sp,
|
||||
fontFamily = ttComposeFontFamily,
|
||||
color = NaviPayColor.textTertiary,
|
||||
fontWeight = getFontWeight(FontWeightEnum.NAVI_HEADLINE_REGULAR),
|
||||
textDecoration = TextDecoration.Underline
|
||||
)
|
||||
}
|
||||
} else if (rewardsNudgeDetailEntity != null) {
|
||||
val addAccountRewardsMessage = buildAnnotatedString {
|
||||
val text =
|
||||
stringResource(id = R.string.np_add_account_rewards_message) +
|
||||
stringResource(
|
||||
id = R.string.np_rewards_won_suffix,
|
||||
"${rewardsNudgeDetailEntity?.formattedAmount}"
|
||||
)
|
||||
val highlightedText =
|
||||
stringResource(
|
||||
id = R.string.np_rewards_won_suffix,
|
||||
"${rewardsNudgeDetailEntity?.formattedAmount}"
|
||||
)
|
||||
|
||||
append(text = text)
|
||||
|
||||
addStyle(
|
||||
style =
|
||||
SpanStyle(
|
||||
fontFamily = ttComposeFontFamily,
|
||||
fontWeight =
|
||||
getFontWeight(FontWeightEnum.NAVI_BODY_REGULAR),
|
||||
fontSize = 14.sp,
|
||||
color = NaviPayColor.textTertiary
|
||||
),
|
||||
start = 0,
|
||||
end = text.length
|
||||
)
|
||||
|
||||
addStyle(
|
||||
style =
|
||||
SpanStyle(
|
||||
fontFamily = ttComposeFontFamily,
|
||||
fontWeight =
|
||||
getFontWeight(FontWeightEnum.NAVI_HEADLINE_REGULAR),
|
||||
fontSize = 14.sp,
|
||||
color = NaviPayColor.textTertiary
|
||||
),
|
||||
start = text.indexOf(highlightedText),
|
||||
end = text.length
|
||||
)
|
||||
}
|
||||
|
||||
NaviText(text = addAccountRewardsMessage, textAlign = TextAlign.Center)
|
||||
}
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
}
|
||||
}
|
||||
SelectBankScreenStates.AddBankInProgress -> {
|
||||
RenderAPIResultScreen(
|
||||
lottieFileName = NAVI_PAY_LOADER,
|
||||
titleText = stringResource(id = R.string.account_adding_in_progress_header),
|
||||
descriptionText =
|
||||
stringResource(id = R.string.account_adding_in_progress_description),
|
||||
showLottieInfiniteTimes = true
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun RenderSelectBankScreen(
|
||||
popularBanks: List<BankEntity>,
|
||||
allBanks: LazyPagingItems<BankEntity>,
|
||||
keyboardController: SoftwareKeyboardController?,
|
||||
accountType: AccountType,
|
||||
onBankSelected: (BankEntity) -> Unit,
|
||||
searchQuery: String,
|
||||
onSearchInputValueChange: (String) -> Unit,
|
||||
customerMobileNumber: String,
|
||||
isTrailingIconEnabled: Boolean,
|
||||
onTrailingIconClicked: () -> Unit,
|
||||
helpCtaText: String?,
|
||||
onHelpCtaClicked: () -> Unit,
|
||||
onBackClick: () -> Unit,
|
||||
shouldShowSponsor: Boolean
|
||||
) {
|
||||
|
||||
val scope = rememberCoroutineScope()
|
||||
val context = LocalContext.current
|
||||
val view = LocalView.current
|
||||
|
||||
Column(
|
||||
modifier =
|
||||
Modifier.fillMaxSize()
|
||||
.nestedScroll(
|
||||
closeKeyboardOnScroll(
|
||||
scope = scope,
|
||||
context = context,
|
||||
view = view,
|
||||
keyboardController = keyboardController
|
||||
)
|
||||
),
|
||||
) {
|
||||
NaviPayHeader(
|
||||
title = stringResource(R.string.select_bank),
|
||||
onNavigationIconClick = onBackClick,
|
||||
actionIconText = helpCtaText,
|
||||
onActionClick = onHelpCtaClicked,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
LazyColumn(modifier = Modifier.fillMaxSize(), flingBehavior = maxScrollFlingBehavior()) {
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
|
||||
NaviText(
|
||||
text =
|
||||
getAddAccountText(
|
||||
accountType = accountType,
|
||||
customerMobileNumber = customerMobileNumber
|
||||
),
|
||||
fontFamily = ttComposeFontFamily,
|
||||
fontSize = 18.sp,
|
||||
fontWeight = getFontWeight(FontWeightEnum.NAVI_HEADLINE_REGULAR),
|
||||
color = NaviPayColor.textPrimary,
|
||||
modifier = Modifier.padding(horizontal = 16.dp)
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
|
||||
BankSearchField(
|
||||
modifier = Modifier.padding(horizontal = 16.dp),
|
||||
keyboardController = keyboardController,
|
||||
searchQuery = searchQuery,
|
||||
onSearchInputValueChange = onSearchInputValueChange,
|
||||
isTrailingIconEnabled = isTrailingIconEnabled,
|
||||
onTrailingIconClicked = onTrailingIconClicked
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(32.dp))
|
||||
}
|
||||
|
||||
if (
|
||||
accountType == AccountType.SAVINGS &&
|
||||
popularBanks.isNotEmpty() &&
|
||||
searchQuery.isEmpty()
|
||||
) {
|
||||
item {
|
||||
PopularBankSection(popularBanks = popularBanks, onBankSelected = onBankSelected)
|
||||
}
|
||||
}
|
||||
|
||||
if (allBanks.itemCount > 0) {
|
||||
item {
|
||||
NaviText(
|
||||
text = stringResource(id = R.string.all_banks_in_the_town),
|
||||
fontFamily = ttComposeFontFamily,
|
||||
fontSize = 14.sp,
|
||||
fontWeight = getFontWeight(FontWeightEnum.NAVI_HEADLINE_REGULAR),
|
||||
color = NaviPayColor.textTertiary,
|
||||
modifier = Modifier.padding(horizontal = 16.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
items(count = allBanks.itemCount, key = allBanks.itemKey { it.code }) { index ->
|
||||
val bankEntityItem = allBanks[index]
|
||||
bankEntityItem?.let {
|
||||
RegularBankView(bankEntity = it, onBankSelected = onBankSelected)
|
||||
}
|
||||
}
|
||||
|
||||
if (allBanks.isEmpty()) {
|
||||
item {
|
||||
NaviText(
|
||||
text = stringResource(id = R.string.couldnt_find_this_bank),
|
||||
fontFamily = ttComposeFontFamily,
|
||||
fontWeight = getFontWeight(FontWeightEnum.NAVI_BODY_REGULAR),
|
||||
fontSize = 12.sp,
|
||||
color = NaviPayColor.textSecondary,
|
||||
modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (!allBanks.isEmpty() && searchQuery.isEmpty() && shouldShowSponsor) {
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
|
||||
when (accountType.name) {
|
||||
AccountType.CREDIT.name -> {
|
||||
NaviPayCreditCardSponsorView(modifier = Modifier.fillMaxWidth())
|
||||
}
|
||||
AccountType.UPICREDIT.name -> {
|
||||
NaviPayCreditLineSponsorView(modifier = Modifier.fillMaxWidth())
|
||||
}
|
||||
else -> {
|
||||
NaviPaySponsorView(modifier = Modifier.fillMaxWidth())
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(32.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun BankSearchField(
|
||||
modifier: Modifier,
|
||||
keyboardController: SoftwareKeyboardController?,
|
||||
searchQuery: String,
|
||||
onSearchInputValueChange: (String) -> Unit,
|
||||
isTrailingIconEnabled: Boolean,
|
||||
onTrailingIconClicked: () -> Unit
|
||||
) {
|
||||
|
||||
val context = LocalContext.current
|
||||
val view = LocalView.current
|
||||
|
||||
OutlinedTextField(
|
||||
value = searchQuery,
|
||||
onValueChange = { onSearchInputValueChange.invoke(it) },
|
||||
singleLine = true,
|
||||
maxLines = 1,
|
||||
colors =
|
||||
TextFieldDefaults.outlinedTextFieldColors(
|
||||
focusedBorderColor = NaviPayColor.ctaPrimary,
|
||||
unfocusedBorderColor = NaviPayColor.borderAlt,
|
||||
backgroundColor = NaviPayColor.transparent
|
||||
),
|
||||
textStyle =
|
||||
TextStyle(
|
||||
fontSize = 14.sp,
|
||||
fontFamily = ttComposeFontFamily,
|
||||
fontWeight = getFontWeight(FontWeightEnum.NAVI_HEADLINE_REGULAR),
|
||||
color = NaviPayColor.inputFieldFilled
|
||||
),
|
||||
keyboardOptions = KeyboardOptions(autoCorrect = false, imeAction = ImeAction.Search),
|
||||
keyboardActions =
|
||||
KeyboardActions(
|
||||
onSearch = { keyboardController?.customHide(context = context, view = view) }
|
||||
),
|
||||
modifier = modifier.fillMaxWidth().background(color = NaviPayColor.bgDefault),
|
||||
placeholder = {
|
||||
NaviText(
|
||||
text = stringResource(id = R.string.search_bank_here),
|
||||
fontSize = 14.sp,
|
||||
fontFamily = ttComposeFontFamily,
|
||||
fontWeight = getFontWeight(FontWeightEnum.NAVI_BODY_REGULAR),
|
||||
color = NaviPayColor.textTertiary
|
||||
)
|
||||
},
|
||||
trailingIcon = {
|
||||
if (isTrailingIconEnabled) {
|
||||
IconButton(onClick = { onTrailingIconClicked.invoke() }) {
|
||||
Image(
|
||||
painter = painterResource(id = CommonR.drawable.ic_close_black),
|
||||
contentDescription = null,
|
||||
modifier = Modifier.size(24.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun PopularBankSection(popularBanks: List<BankEntity>, onBankSelected: (BankEntity) -> Unit) {
|
||||
NaviText(
|
||||
text = stringResource(id = R.string.np_popular_banks),
|
||||
fontFamily = ttComposeFontFamily,
|
||||
fontSize = 14.sp,
|
||||
fontWeight = getFontWeight(FontWeightEnum.NAVI_HEADLINE_REGULAR),
|
||||
color = NaviPayColor.textTertiary,
|
||||
modifier = Modifier.padding(horizontal = 16.dp)
|
||||
)
|
||||
|
||||
// 1 row can contain max 3 banks
|
||||
// height of 1 row is 110.dp including spacer = 56 + 8 + 22 + 24
|
||||
val gridTotalHeight =
|
||||
remember(popularBanks) {
|
||||
val numberOfRows = (popularBanks.size + 2) / 3
|
||||
(numberOfRows * 110).dp + 16.dp + 8.dp
|
||||
}
|
||||
|
||||
LazyVerticalGrid(
|
||||
modifier = Modifier.fillMaxWidth().height(gridTotalHeight),
|
||||
contentPadding = PaddingValues(start = 16.dp, end = 16.dp, top = 16.dp, bottom = 32.dp),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
columns = GridCells.Fixed(3),
|
||||
verticalArrangement = Arrangement.spacedBy(24.dp),
|
||||
userScrollEnabled = false
|
||||
) {
|
||||
items(items = popularBanks, key = { it.code }) {
|
||||
PopularBankView(bankEntity = it, onBankSelected = onBankSelected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun PopularBankView(
|
||||
bankEntity: BankEntity,
|
||||
onBankSelected: (BankEntity) -> Unit,
|
||||
) {
|
||||
|
||||
Column(
|
||||
verticalArrangement = Arrangement.Center,
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
modifier =
|
||||
Modifier.clickableWithNoGesture { onBankSelected(bankEntity) }
|
||||
.padding(horizontal = 4.dp)
|
||||
) {
|
||||
ImageWithBackground(
|
||||
boxSize = 56.dp,
|
||||
backgroundCornerRadius = 2.dp,
|
||||
imageUrl = bankEntity.iconUrl,
|
||||
imageSize = 40.dp,
|
||||
backgroundColor = NaviPayColor.bgAlt
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
|
||||
NaviText(
|
||||
text = bankEntity.name,
|
||||
fontSize = 12.sp,
|
||||
fontFamily = ttComposeFontFamily,
|
||||
fontWeight = getFontWeight(FontWeightEnum.NAVI_BODY_REGULAR),
|
||||
color = NaviPayColor.textPrimary,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun RegularBankView(
|
||||
bankEntity: BankEntity,
|
||||
onBankSelected: (BankEntity) -> Unit,
|
||||
) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier =
|
||||
Modifier.fillMaxWidth().clickableDebounce { onBankSelected(bankEntity) }.padding(16.dp)
|
||||
) {
|
||||
Box(
|
||||
contentAlignment = Alignment.Center,
|
||||
modifier =
|
||||
Modifier.size(32.dp)
|
||||
.border(
|
||||
border = BorderStroke(width = 1.dp, color = NaviPayColor.borderAlt),
|
||||
shape = RoundedCornerShape(2.dp)
|
||||
)
|
||||
.background(color = NaviPayColor.bgDefault)
|
||||
) {
|
||||
AsyncImage(
|
||||
model = LocalContext.current.getImageRequestBuilder(data = bankEntity.iconUrl),
|
||||
contentDescription = "",
|
||||
modifier = Modifier.size(24.dp).align(Alignment.Center),
|
||||
fallback = painterResource(id = CommonR.drawable.ic_upi_bbps_default_bank_logo),
|
||||
placeholder = painterResource(id = CommonR.drawable.ic_upi_bbps_default_bank_logo),
|
||||
error = painterResource(id = CommonR.drawable.ic_upi_bbps_default_bank_logo),
|
||||
)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.width(12.dp))
|
||||
|
||||
NaviText(
|
||||
text = bankEntity.name,
|
||||
fontSize = 14.sp,
|
||||
fontFamily = ttComposeFontFamily,
|
||||
fontWeight = getFontWeight(FontWeightEnum.NAVI_BODY_REGULAR),
|
||||
color = NaviPayColor.textPrimary,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun getAddAccountText(accountType: AccountType, customerMobileNumber: String): String {
|
||||
val resId =
|
||||
when (accountType) {
|
||||
AccountType.SAVINGS -> R.string.add_a_bank_account
|
||||
AccountType.CREDIT -> R.string.select_credit_card_bank_header
|
||||
AccountType.UPICREDIT -> R.string.select_credit_line_header
|
||||
}
|
||||
return stringResource(id = resId, customerMobileNumber.takeLast(PHONE_NUMBER_LENGTH))
|
||||
}
|
||||
@@ -1,551 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright © 2022-2024 by Navi Technologies Limited
|
||||
* * All rights reserved. Strictly confidential
|
||||
*
|
||||
*/
|
||||
|
||||
package com.navi.pay.onboarding.account.add.viewmodel
|
||||
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.paging.Pager
|
||||
import androidx.paging.PagingConfig
|
||||
import androidx.paging.PagingData
|
||||
import androidx.paging.cachedIn
|
||||
import com.navi.base.model.CtaData
|
||||
import com.navi.base.utils.BaseUtils
|
||||
import com.navi.common.firebaseremoteconfig.FirebaseRemoteConfigHelper
|
||||
import com.navi.common.model.common.NudgeDetailEntity
|
||||
import com.navi.common.network.models.isSuccess
|
||||
import com.navi.common.network.models.isSuccessWithData
|
||||
import com.navi.common.usecase.RewardsNudgeEntityFetchUseCase
|
||||
import com.navi.pay.analytics.NaviPayAnalytics
|
||||
import com.navi.pay.common.connectivity.NaviPayNetworkConnectivity
|
||||
import com.navi.pay.common.model.view.NaviPayScreenType
|
||||
import com.navi.pay.common.model.view.NaviPayVmData
|
||||
import com.navi.pay.common.repository.SharedPreferenceRepository
|
||||
import com.navi.pay.common.setup.NaviPayCustomerStatusHandler
|
||||
import com.navi.pay.common.setup.model.NaviPayCustomerStatus
|
||||
import com.navi.pay.common.usecase.LinkedAccountsUseCase
|
||||
import com.navi.pay.common.usecase.RefreshBankListUseCase
|
||||
import com.navi.pay.common.usecase.RefreshLinkedAccountsUseCase
|
||||
import com.navi.pay.common.utils.DeviceInfoProvider
|
||||
import com.navi.pay.common.utils.NaviPayCommonUtils
|
||||
import com.navi.pay.common.utils.NaviPayCommonUtils.getHelpCtaData
|
||||
import com.navi.pay.common.viewmodel.NaviPayBaseVM
|
||||
import com.navi.pay.management.upinumber.list.model.network.UpiNumbersListRequest
|
||||
import com.navi.pay.onboarding.account.add.model.network.AccountItemResponse
|
||||
import com.navi.pay.onboarding.account.add.model.network.AddAccountRequest
|
||||
import com.navi.pay.onboarding.account.add.model.network.FetchAccountsRequest
|
||||
import com.navi.pay.onboarding.account.add.model.network.toLinkedAccountEntity
|
||||
import com.navi.pay.onboarding.account.add.model.view.AccountType
|
||||
import com.navi.pay.onboarding.account.add.model.view.BankEntity
|
||||
import com.navi.pay.onboarding.account.add.model.view.SelectBankScreenBottomSheetHandler
|
||||
import com.navi.pay.onboarding.account.add.repository.BankRepository
|
||||
import com.navi.pay.onboarding.account.detail.model.view.LinkedAccountEntity
|
||||
import com.navi.pay.utils.NAVI_PAY_ENCRYPT_SHARED_PREF_DATA_KEYS
|
||||
import com.navi.pay.utils.NAVI_PAY_NON_ENCRYPT_SHARED_PREF_DATA_KEYS
|
||||
import com.navi.pay.utils.PHONE_NUMBER_LENGTH
|
||||
import com.navi.pay.utils.UPI_NUMBER_STATUS_ACTIVE
|
||||
import com.navi.pay.utils.getBankNameAccountNumberText
|
||||
import com.navi.pay.utils.refresh
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.FlowPreview
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.asSharedFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.debounce
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.flatMapLatest
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@HiltViewModel
|
||||
class SelectBankViewModel
|
||||
@Inject
|
||||
constructor(
|
||||
private val bankRepository: BankRepository,
|
||||
private val deviceInfoProvider: DeviceInfoProvider,
|
||||
private val sharedPreferenceRepository: SharedPreferenceRepository,
|
||||
private val refreshLinkedAccountsUseCase: RefreshLinkedAccountsUseCase,
|
||||
private val linkedAccountsUseCase: LinkedAccountsUseCase,
|
||||
private val refreshBankListUseCase: RefreshBankListUseCase,
|
||||
private val naviPayCustomerStatusHandler: NaviPayCustomerStatusHandler,
|
||||
private val naviPayNetworkConnectivity: NaviPayNetworkConnectivity,
|
||||
savedStateHandle: SavedStateHandle,
|
||||
private val rewardsNudgeEntityFetchUseCase: RewardsNudgeEntityFetchUseCase
|
||||
) : NaviPayBaseVM(NaviPayVmData(screenName = NaviPayAnalytics.NAVI_PAY_ADD_ACCOUNT)) {
|
||||
|
||||
private val naviPayAnalytics: NaviPayAnalytics.NaviPaySelectBank =
|
||||
NaviPayAnalytics.INSTANCE.NaviPaySelectBank()
|
||||
|
||||
private val MAX_ACCOUNT_SEARCH_RETRY_COUNT = 3
|
||||
|
||||
private val isFreshOnBoardingCase = savedStateHandle.get<Boolean>("isFreshOnBoardingCase")!!
|
||||
private val accountType = savedStateHandle.get<AccountType>("accountType")!!
|
||||
var linkedAccounts: List<LinkedAccountEntity>? = null
|
||||
private var noBankFoundCount = 0
|
||||
|
||||
private val _searchQuery = MutableStateFlow("")
|
||||
val searchQuery = _searchQuery.asStateFlow()
|
||||
|
||||
private var fetchAccountsJob: Job? = null
|
||||
|
||||
var isAddBankSuccessShown = false
|
||||
|
||||
private val _upiNumberBottomSheetNeedToShow = MutableStateFlow(false)
|
||||
val upiNumberBottomSheetNeedToShow = _upiNumberBottomSheetNeedToShow.asStateFlow()
|
||||
var vpa = ""
|
||||
var bankName = ""
|
||||
|
||||
private val _rewardsNudgeDetailEntity = MutableStateFlow<NudgeDetailEntity?>(null)
|
||||
val rewardsNudgeDetailEntity = _rewardsNudgeDetailEntity.asStateFlow()
|
||||
|
||||
private val _shouldShowSponsor = MutableStateFlow(false)
|
||||
val shouldShowSponsor = _shouldShowSponsor.asStateFlow()
|
||||
|
||||
val isTrailingIconEnabled =
|
||||
searchQuery
|
||||
.map { it.isNotEmpty() }
|
||||
.stateIn(
|
||||
scope = viewModelScope,
|
||||
started = SharingStarted.WhileSubscribed(),
|
||||
initialValue = false
|
||||
)
|
||||
|
||||
@OptIn(FlowPreview::class, ExperimentalCoroutinesApi::class)
|
||||
val allBankListPager: Flow<PagingData<BankEntity>> =
|
||||
searchQuery
|
||||
.debounce(300)
|
||||
.distinctUntilChanged()
|
||||
.flatMapLatest { query ->
|
||||
Pager(
|
||||
config = PagingConfig(pageSize = 20, enablePlaceholders = false),
|
||||
pagingSourceFactory = {
|
||||
when (accountType) {
|
||||
AccountType.CREDIT -> {
|
||||
bankRepository.getAllCreditCardBanksForQueryString(
|
||||
queryString = query
|
||||
)
|
||||
}
|
||||
AccountType.SAVINGS -> {
|
||||
bankRepository.getAllNonCreditCardBanksForQueryString(
|
||||
queryString = query
|
||||
)
|
||||
}
|
||||
AccountType.UPICREDIT -> {
|
||||
bankRepository.getAllCreditLineBanksForQueryString(
|
||||
queryString = query
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
.flow
|
||||
}
|
||||
.cachedIn(viewModelScope)
|
||||
|
||||
private val _popularBanks = MutableStateFlow<List<BankEntity>>(emptyList())
|
||||
val popularBanks = _popularBanks.asStateFlow()
|
||||
|
||||
private val _bottomSheetStateHolder =
|
||||
MutableStateFlow(
|
||||
SelectBankScreenBottomSheetHandler(
|
||||
showBottomSheet = false,
|
||||
bottomSheetStateChange = true,
|
||||
bottomSheetUIState = SelectBankScreenBottomSheetUIState.Searching
|
||||
)
|
||||
)
|
||||
val bottomSheetStateHolder = _bottomSheetStateHolder.asStateFlow()
|
||||
|
||||
var selectedBank: BankEntity? = null
|
||||
private var selectedAccount: LinkedAccountEntity? = null
|
||||
|
||||
private val _uiState = MutableStateFlow<SelectBankScreenStates>(SelectBankScreenStates.Loader)
|
||||
val uiState = _uiState.asStateFlow()
|
||||
|
||||
private val accountsResponse = mutableListOf<AccountItemResponse>()
|
||||
|
||||
private val _navigateToNextScreen = MutableSharedFlow<LinkedAccountEntity?>()
|
||||
val navigateToNextScreen = _navigateToNextScreen.asSharedFlow()
|
||||
|
||||
val customerPhoneNumber = BaseUtils.getPhoneNumber()?.takeLast(PHONE_NUMBER_LENGTH) ?: ""
|
||||
val helpCtaData = getHelpCtaData(NaviPayScreenType.NAVI_PAY_BANK_SELECTION_BOTTOM_SHEET.name)
|
||||
|
||||
private val _navigateToNextScreenFromHelpCta = MutableSharedFlow<CtaData?>()
|
||||
val navigateToNextScreenFromHelpCta = _navigateToNextScreenFromHelpCta.asSharedFlow()
|
||||
|
||||
init {
|
||||
fetchBankListAndUpdateUIState()
|
||||
updateRewardsNudgeEntity()
|
||||
updateSponsorVisibility(isVisible = true)
|
||||
}
|
||||
|
||||
private fun fetchBankListAndUpdateUIState() {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
refreshBankListUseCase.execute()
|
||||
updatePopularBankList()
|
||||
updateUIState(state = SelectBankScreenStates.SelectBank)
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateSponsorVisibility(isVisible: Boolean) {
|
||||
viewModelScope.launch {
|
||||
delay(1000) // Added delay to wait for list to finish rendering
|
||||
_shouldShowSponsor.update { isVisible }
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateRewardsNudgeEntity() {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
_rewardsNudgeDetailEntity.update { rewardsNudgeEntityFetchUseCase.execute() }
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun updatePopularBankList() {
|
||||
_popularBanks.update { bankRepository.getAllPopularBanks() }
|
||||
}
|
||||
|
||||
fun updateSearchQueryStringState(searchQuery: String = "") {
|
||||
_searchQuery.update { searchQuery }
|
||||
}
|
||||
|
||||
fun updateBottomSheetUIState(
|
||||
selectBankScreenBottomSheetUIState: SelectBankScreenBottomSheetUIState? = null,
|
||||
allowStateChange: Boolean? = null,
|
||||
showBottomSheet: Boolean
|
||||
) {
|
||||
|
||||
_bottomSheetStateHolder.update {
|
||||
SelectBankScreenBottomSheetHandler(
|
||||
showBottomSheet = showBottomSheet,
|
||||
bottomSheetStateChange = allowStateChange ?: it.bottomSheetStateChange,
|
||||
bottomSheetUIState = selectBankScreenBottomSheetUIState ?: it.bottomSheetUIState
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateSelectedAccount(selectedAccount: LinkedAccountEntity?) {
|
||||
this.selectedAccount = selectedAccount
|
||||
}
|
||||
|
||||
private fun updateSelectedBank(selectedBank: BankEntity?) {
|
||||
this.selectedBank = selectedBank
|
||||
}
|
||||
|
||||
private suspend fun fetchBankAccounts(bankEntity: BankEntity) {
|
||||
|
||||
if (!naviPayNetworkConnectivity.isInternetConnected()) {
|
||||
notifyError(getNoInternetErrorConfig())
|
||||
return
|
||||
}
|
||||
|
||||
if (naviPayNetworkConnectivity.isAirplaneModeOn()) {
|
||||
notifyError(getAirplaneModeOnErrorConfig())
|
||||
return
|
||||
}
|
||||
|
||||
val currentSimInfoList = naviPayNetworkConnectivity.getCurrentSimInfoList()
|
||||
val simInfoValidationResult =
|
||||
NaviPayCommonUtils.validateSimInfo(
|
||||
currentSimInfoList = currentSimInfoList,
|
||||
deviceInfoProvider = deviceInfoProvider
|
||||
)
|
||||
|
||||
if (!simInfoValidationResult) {
|
||||
notifyError(getSimFailureErrorConfig(isNoSimPresent = currentSimInfoList.isEmpty()))
|
||||
return
|
||||
}
|
||||
|
||||
updateBottomSheetUIState(
|
||||
selectBankScreenBottomSheetUIState = SelectBankScreenBottomSheetUIState.Searching,
|
||||
allowStateChange = false,
|
||||
showBottomSheet = true
|
||||
)
|
||||
|
||||
val fetchBankAccountAPIResponse =
|
||||
bankRepository.fetchBankAccounts(
|
||||
fetchAccountsRequest =
|
||||
FetchAccountsRequest(
|
||||
bankCode = bankEntity.code,
|
||||
deviceData = deviceInfoProvider.getDeviceData(),
|
||||
merchantCustomerId = deviceInfoProvider.getMerchantCustomerId(),
|
||||
accountType =
|
||||
if (
|
||||
AccountType.isAccountOfTypeCreditCardOrCreditLine(
|
||||
type = accountType.name
|
||||
)
|
||||
)
|
||||
accountType.name
|
||||
else null
|
||||
)
|
||||
)
|
||||
|
||||
if (!fetchBankAccountAPIResponse.isSuccessWithData()) {
|
||||
updateBottomSheetUIState(showBottomSheet = false)
|
||||
notifyError(response = fetchBankAccountAPIResponse, tag = "onBankAccountsFailure")
|
||||
return
|
||||
}
|
||||
|
||||
val fetchBankAccountsList = fetchBankAccountAPIResponse.data!!.accounts
|
||||
|
||||
if (fetchBankAccountsList.isEmpty()) {
|
||||
noBankFoundCount++
|
||||
|
||||
if (noBankFoundCount == MAX_ACCOUNT_SEARCH_RETRY_COUNT && isFreshOnBoardingCase) {
|
||||
sharedPreferenceRepository.clearKeyBasedSessionPreferenceData(
|
||||
encryptedDataKeys = NAVI_PAY_ENCRYPT_SHARED_PREF_DATA_KEYS,
|
||||
nonEncryptedDataKeys = NAVI_PAY_NON_ENCRYPT_SHARED_PREF_DATA_KEYS
|
||||
)
|
||||
updateBottomSheetUIState(
|
||||
selectBankScreenBottomSheetUIState = SelectBankScreenBottomSheetUIState.ReBind,
|
||||
allowStateChange = false,
|
||||
showBottomSheet = true
|
||||
)
|
||||
} else {
|
||||
updateBottomSheetUIState(
|
||||
selectBankScreenBottomSheetUIState =
|
||||
SelectBankScreenBottomSheetUIState.NotFound,
|
||||
allowStateChange = true,
|
||||
showBottomSheet = true
|
||||
)
|
||||
}
|
||||
} else {
|
||||
noBankFoundCount = 0
|
||||
accountsResponse.refresh(fetchBankAccountsList)
|
||||
val accountEntities =
|
||||
accountsResponse.map { it.toLinkedAccountEntity(selectedBank = selectedBank) }
|
||||
updateSelectedAccount(selectedAccount = accountEntities[0])
|
||||
|
||||
if (accountEntities.size == 1) {
|
||||
linkAccount()
|
||||
} else {
|
||||
updateBottomSheetUIState(
|
||||
selectBankScreenBottomSheetUIState =
|
||||
SelectBankScreenBottomSheetUIState.Found(accountEntities),
|
||||
allowStateChange = true,
|
||||
showBottomSheet = true
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun getLinkedAccount(bankAccountUniqueId: String): LinkedAccountEntity? {
|
||||
linkedAccounts = linkedAccountsUseCase.execute().first()
|
||||
return linkedAccounts?.singleOrNull { it.accountId == bankAccountUniqueId }
|
||||
}
|
||||
|
||||
fun onBankSelected(bankEntity: BankEntity) {
|
||||
if (fetchAccountsJob?.isActive == true) {
|
||||
naviPayAnalytics.onBankClickFetchBankRunning(bank = bankEntity)
|
||||
return
|
||||
}
|
||||
|
||||
fetchAccountsJob =
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
updateSelectedBank(selectedBank = bankEntity)
|
||||
updateSelectedAccount(selectedAccount = null)
|
||||
fetchBankAccounts(bankEntity = bankEntity)
|
||||
}
|
||||
}
|
||||
|
||||
fun onAccountSelected(bankAccountEntity: LinkedAccountEntity) {
|
||||
selectedAccount = bankAccountEntity
|
||||
}
|
||||
|
||||
fun linkAccount() {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
val selectedAccount =
|
||||
accountsResponse.firstOrNull {
|
||||
it.bankAccountUniqueId == selectedAccount?.accountId
|
||||
} ?: return@launch
|
||||
|
||||
val selectedVpa =
|
||||
if (selectedAccount.vpaSuggestions.isNotEmpty()) selectedAccount.vpaSuggestions[0]
|
||||
else ""
|
||||
|
||||
updateBottomSheetUIState(showBottomSheet = false)
|
||||
updateUIState(state = SelectBankScreenStates.AddBankInProgress)
|
||||
|
||||
val addBankAPIResponse =
|
||||
bankRepository.addBankAccount(
|
||||
addAccountRequest =
|
||||
AddAccountRequest(
|
||||
deviceData = deviceInfoProvider.getDeviceData(),
|
||||
bankAccountUniqueId = selectedAccount.bankAccountUniqueId,
|
||||
accountType = accountType.name,
|
||||
customerVpa = selectedVpa,
|
||||
merchantCustomerId = deviceInfoProvider.getMerchantCustomerId(),
|
||||
creditLineAccSubType = selectedAccount.creditLineAccSubType,
|
||||
creditLineAllowedMCC = selectedAccount.creditLineAllowedMCC,
|
||||
creditLineNotAllowedMCC = selectedAccount.creditLineNotAllowedMCC
|
||||
)
|
||||
)
|
||||
|
||||
if (addBankAPIResponse.isSuccess()) {
|
||||
naviPayCustomerStatusHandler.updateCustomerStatus(
|
||||
NaviPayCustomerStatus.LINKED_VPA.name
|
||||
)
|
||||
naviPayAnalytics.onSelectedBankAccountSelected(selectedAccount = selectedAccount)
|
||||
refreshLinkedAccountsUseCase.execute()
|
||||
updateUIState(
|
||||
state =
|
||||
SelectBankScreenStates.AddBankSuccess(
|
||||
connectedAccount =
|
||||
getLinkedAccount(
|
||||
bankAccountUniqueId = selectedAccount.bankAccountUniqueId
|
||||
)
|
||||
)
|
||||
)
|
||||
if (
|
||||
!isFreshOnBoardingCase &&
|
||||
!AccountType.isAccountOfTypeCreditCardOrCreditLine(type = accountType.name)
|
||||
) {
|
||||
fetchUpiNumberLinkedAccounts()
|
||||
}
|
||||
} else {
|
||||
updateSearchQueryStringState() // resetting search query
|
||||
updateUIState(state = SelectBankScreenStates.SelectBank)
|
||||
val error = getError(response = addBankAPIResponse)
|
||||
updateBottomSheetUIState(
|
||||
selectBankScreenBottomSheetUIState =
|
||||
SelectBankScreenBottomSheetUIState.AddAccountError(
|
||||
title = error.title,
|
||||
description = error.description
|
||||
),
|
||||
allowStateChange = true,
|
||||
showBottomSheet = true
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun fetchUpiNumberLinkedAccounts() {
|
||||
if (FirebaseRemoteConfigHelper.getBoolean(FirebaseRemoteConfigHelper.UPI_NUMBER_DISABLED))
|
||||
return
|
||||
|
||||
val response =
|
||||
bankRepository.fetchUpiNumbers(
|
||||
UpiNumbersListRequest(
|
||||
deviceData = deviceInfoProvider.getDeviceData(),
|
||||
merchantCustomerId = deviceInfoProvider.getMerchantCustomerId()
|
||||
)
|
||||
)
|
||||
if (response.isSuccessWithData()) {
|
||||
val phoneNumber = deviceInfoProvider.getPhoneNumber().takeLast(PHONE_NUMBER_LENGTH)
|
||||
var upiNumberLinked = false
|
||||
var alternativeVpa = ""
|
||||
var alternativeBankName = ""
|
||||
response.data?.accounts?.forEach { upiNumberAccountResponseItem ->
|
||||
upiNumberAccountResponseItem.customerVpas?.forEach {
|
||||
upiNumberCustomerVpaResponseItem ->
|
||||
if (
|
||||
upiNumberAccountResponseItem.isAccountPrimary &&
|
||||
upiNumberCustomerVpaResponseItem.primary
|
||||
) {
|
||||
vpa = upiNumberCustomerVpaResponseItem.vpa
|
||||
bankName =
|
||||
getBankNameAccountNumberText(
|
||||
bankName = upiNumberAccountResponseItem.bankName,
|
||||
maskedAccountNumber =
|
||||
upiNumberAccountResponseItem.maskedAccountNumber
|
||||
)
|
||||
}
|
||||
alternativeVpa = upiNumberCustomerVpaResponseItem.vpa
|
||||
alternativeBankName =
|
||||
getBankNameAccountNumberText(
|
||||
bankName = upiNumberAccountResponseItem.bankName,
|
||||
maskedAccountNumber = upiNumberAccountResponseItem.maskedAccountNumber
|
||||
)
|
||||
upiNumberCustomerVpaResponseItem.upiNumbers?.forEach { upiNumberResponseItem ->
|
||||
if (
|
||||
upiNumberResponseItem.status == UPI_NUMBER_STATUS_ACTIVE &&
|
||||
upiNumberResponseItem.number == phoneNumber
|
||||
) {
|
||||
upiNumberLinked = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (upiNumberLinked.not()) {
|
||||
if (vpa.isEmpty()) {
|
||||
vpa = alternativeVpa
|
||||
bankName = alternativeBankName
|
||||
}
|
||||
_upiNumberBottomSheetNeedToShow.update { true }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun updateNavigateToNextScreen(connectedAccount: LinkedAccountEntity?) {
|
||||
_navigateToNextScreen.emit(value = connectedAccount)
|
||||
}
|
||||
|
||||
fun onAddAccountSuccess(connectedAccount: LinkedAccountEntity?) {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
if (isFreshOnBoardingCase) {
|
||||
delay(2000)
|
||||
}
|
||||
|
||||
updateNavigateToNextScreen(connectedAccount = connectedAccount)
|
||||
|
||||
isAddBankSuccessShown = true
|
||||
}
|
||||
}
|
||||
|
||||
fun updateUIState(state: SelectBankScreenStates) {
|
||||
_uiState.update { state }
|
||||
}
|
||||
|
||||
private suspend fun updateNavigateToNextScreenOnHelpCtaClicked(ctaData: CtaData?) {
|
||||
_navigateToNextScreenFromHelpCta.emit(ctaData)
|
||||
}
|
||||
|
||||
fun onHelpClicked() {
|
||||
viewModelScope.launch(Dispatchers.Default) {
|
||||
updateNavigateToNextScreenOnHelpCtaClicked(helpCtaData)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sealed class SelectBankScreenStates {
|
||||
data object Loader : SelectBankScreenStates()
|
||||
|
||||
data object SelectBank : SelectBankScreenStates()
|
||||
|
||||
data object AddBankInProgress : SelectBankScreenStates()
|
||||
|
||||
data class AddBankSuccess(val connectedAccount: LinkedAccountEntity?) :
|
||||
SelectBankScreenStates()
|
||||
}
|
||||
|
||||
sealed class SelectBankScreenBottomSheetUIState {
|
||||
data object Searching : SelectBankScreenBottomSheetUIState()
|
||||
|
||||
data class Found(val accountEntities: List<LinkedAccountEntity>) :
|
||||
SelectBankScreenBottomSheetUIState()
|
||||
|
||||
data object NotFound : SelectBankScreenBottomSheetUIState()
|
||||
|
||||
data object ReBind : SelectBankScreenBottomSheetUIState()
|
||||
|
||||
data class AddAccountError(val title: String, val description: String) :
|
||||
SelectBankScreenBottomSheetUIState()
|
||||
|
||||
data class NpciRecommendation(val connectedAccount: LinkedAccountEntity?) :
|
||||
SelectBankScreenBottomSheetUIState()
|
||||
|
||||
data object Default : SelectBankScreenBottomSheetUIState()
|
||||
}
|
||||
@@ -39,7 +39,6 @@ import com.navi.pay.common.viewmodel.NaviPayBaseVM
|
||||
import com.navi.pay.destinations.LinkedAccountBalanceScreenDestination
|
||||
import com.navi.pay.destinations.LinkedAccountDetailScreenDestination
|
||||
import com.navi.pay.destinations.LinkedAccountVerifyScreenDestination
|
||||
import com.navi.pay.destinations.SelectBankScreenDestination
|
||||
import com.navi.pay.destinations.SendMoneyScreenDestination
|
||||
import com.navi.pay.destinations.SendMoneyScreenV2Destination
|
||||
import com.navi.pay.destinations.SetPinConfirmationScreenDestination
|
||||
@@ -63,9 +62,7 @@ import com.navi.pay.onboarding.account.linked.model.view.LinkedAccountsScreenSou
|
||||
import com.navi.pay.onboarding.account.linked.model.view.LinkedAccountsScreenSource.Companion.getLinkedAccountsScreenName
|
||||
import com.navi.pay.onboardingV2.model.view.NaviPayOnboardingActionsV2Type
|
||||
import com.navi.pay.onboardingV2.model.view.OnboardingIntentData
|
||||
import com.navi.pay.utils.ACCOUNT_TYPE
|
||||
import com.navi.pay.utils.ACTION_PIN_SET
|
||||
import com.navi.pay.utils.ADD_ACCOUNT_LINK
|
||||
import com.navi.pay.utils.AVAILABILITY_ACTION_CHECK
|
||||
import com.navi.pay.utils.AVAILABILITY_ACTION_PORT
|
||||
import com.navi.pay.utils.BANK_NAME
|
||||
@@ -790,19 +787,6 @@ constructor(
|
||||
allowStateChange = true
|
||||
)
|
||||
}
|
||||
ADD_ACCOUNT_LINK -> {
|
||||
viewModelScope.launch {
|
||||
val accountType =
|
||||
AccountType.getAccountType(data.getStringExtra(ACCOUNT_TYPE).orEmpty())
|
||||
_navigateToNextScreen.emit(
|
||||
value =
|
||||
SelectBankScreenDestination(
|
||||
isFreshOnBoardingCase = false,
|
||||
accountType = accountType
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
data.removeExtra(DEEPLINK_URL)
|
||||
}
|
||||
|
||||
@@ -68,7 +68,6 @@ import com.navi.payment.nativepayment.components.MPSLoadingShimmer
|
||||
import com.navi.payment.nativepayment.components.MPSNonOnboardedView
|
||||
import com.navi.payment.nativepayment.components.MPSOnboardedView
|
||||
import com.navi.payment.nativepayment.dataprovider.getMpinSetAction
|
||||
import com.navi.payment.nativepayment.dataprovider.getUpiOnboardingAction
|
||||
import com.navi.payment.nativepayment.screens.destinations.TransactionPollingScreenDestination
|
||||
import com.navi.payment.nativepayment.utils.MPSScreenUtils
|
||||
import com.navi.payment.nativepayment.utils.toGenericError
|
||||
@@ -92,7 +91,6 @@ import com.ramcosta.composedestinations.annotation.Destination
|
||||
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
|
||||
import kotlinx.coroutines.launch
|
||||
import org.json.JSONException
|
||||
import org.json.JSONObject
|
||||
|
||||
@Destination
|
||||
@Composable
|
||||
@@ -354,9 +352,11 @@ fun MPSScreen(
|
||||
|
||||
val onPayButtonClick: () -> Unit = {
|
||||
try {
|
||||
var payButtonClickEventName = "navi_pmt_mps_pay_now"
|
||||
var entryPoint = UpiIntent.SEND_MONEY.name
|
||||
if (mpsViewModel.shouldTriggerDelayedOnboarding()) {
|
||||
if (mpsViewModel.isUserOnboarded().not()) {
|
||||
paymentViewModel.sendEvent(
|
||||
"navi_pmt_pay_via_navi_upi",
|
||||
mapOf("is_discount_applied" to isDiscountApplied.toString())
|
||||
)
|
||||
mpsViewModel.updateBottomSheetUIState(false)
|
||||
naviPaymentActivity.launchOnboardingSDK(
|
||||
action = NaviPayOnboardingActionsV2Type.E2E_ONBOARDING.name,
|
||||
@@ -364,34 +364,24 @@ fun MPSScreen(
|
||||
launcher = upiResultLauncher,
|
||||
source = "MPS"
|
||||
)
|
||||
} else {
|
||||
val data: JSONObject? =
|
||||
if (mpsViewModel.isNaviUpiOnboarded.value.not()) {
|
||||
payButtonClickEventName = "navi_pmt_pay_via_navi_upi"
|
||||
entryPoint = UpiIntent.ONBOARDING.name
|
||||
getUpiOnboardingAction()
|
||||
} else if (selectedBankAccount?.isMPinSet.orFalse().not()) {
|
||||
payButtonClickEventName = "navi_pmt_set_upi_pin_btn_click"
|
||||
entryPoint = UpiIntent.SET_PIN.name
|
||||
getMpinSetAction(selectedBankAccount?.accountId.orEmpty())
|
||||
} else {
|
||||
null
|
||||
}
|
||||
} else if (selectedBankAccount?.isMPinSet.orFalse().not()) {
|
||||
paymentViewModel.sendEvent(
|
||||
payButtonClickEventName,
|
||||
"navi_pmt_set_upi_pin_btn_click",
|
||||
mapOf("is_discount_applied" to isDiscountApplied.toString())
|
||||
)
|
||||
|
||||
if (data.isNotNull()) {
|
||||
paymentViewModel.sendEvent(
|
||||
"navi_pmt_redirection_to_upi",
|
||||
mapOf("entry_point" to entryPoint)
|
||||
)
|
||||
mpsViewModel.updateBottomSheetUIState(mpsViewModel.isNaviUpiOnboarded.value)
|
||||
mpsViewModel.startAction(naviPaymentActivity, upiResultLauncher, data!!)
|
||||
} else {
|
||||
mpsViewModel.startPayAmount()
|
||||
}
|
||||
val data = getMpinSetAction(selectedBankAccount?.accountId.orEmpty())
|
||||
paymentViewModel.sendEvent(
|
||||
"navi_pmt_redirection_to_upi",
|
||||
mapOf("entry_point" to UpiIntent.SET_PIN.name)
|
||||
)
|
||||
mpsViewModel.updateBottomSheetUIState(mpsViewModel.isNaviUpiOnboarded.value)
|
||||
mpsViewModel.startAction(naviPaymentActivity, upiResultLauncher, data)
|
||||
} else {
|
||||
paymentViewModel.sendEvent(
|
||||
"navi_pmt_mps_pay_now",
|
||||
mapOf("is_discount_applied" to isDiscountApplied.toString())
|
||||
)
|
||||
mpsViewModel.startPayAmount()
|
||||
}
|
||||
} catch (exception: JSONException) {
|
||||
exception.log()
|
||||
|
||||
@@ -550,8 +550,8 @@ constructor(
|
||||
}
|
||||
}
|
||||
|
||||
fun shouldTriggerDelayedOnboarding(): Boolean {
|
||||
return naviPayManager.isUserOnboarded().not()
|
||||
fun isUserOnboarded(): Boolean {
|
||||
return naviPayManager.isUserOnboarded()
|
||||
}
|
||||
|
||||
fun onDiscountClicked(isDiscountApplied: Boolean) {
|
||||
|
||||
Reference in New Issue
Block a user