NTP-2526 | AS | Rr/pan collection (#12655)

This commit is contained in:
Ayushman Sharma
2024-09-24 21:16:19 +05:30
committed by GitHub
parent 37285259fa
commit 33efd97899
6 changed files with 209 additions and 47 deletions

View File

@@ -8,13 +8,13 @@
package com.navi.coin.ui.compose.screen
import android.Manifest.permission.READ_CONTACTS
import android.app.Activity
import android.os.Bundle
import androidx.activity.compose.BackHandler
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
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
@@ -23,16 +23,18 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.hilt.navigation.compose.hiltViewModel
import com.google.accompanist.permissions.ExperimentalPermissionsApi
import com.google.accompanist.permissions.isGranted
import com.google.accompanist.permissions.rememberPermissionState
import com.navi.base.deeplink.DeepLinkManager
import com.navi.base.model.CtaData
import com.navi.base.model.CtaType
import com.navi.base.utils.isNotNull
import com.navi.base.utils.orFalse
import com.navi.coin.ui.activity.CoinBaseActivity
import com.navi.coin.ui.compose.common.Init
import com.navi.coin.utils.constant.Constants.IS_EXPERIMENT_ENABLED
import com.navi.coin.utils.constant.Constants.SCREENS.COINS_LOADING_SCREEN_SCREEN_NAME
import com.navi.coin.utils.constant.Constants.SCREEN_CONTENT
import com.navi.coin.vm.RedemptionStatusVM
@@ -55,80 +57,74 @@ import com.ramcosta.composedestinations.navigation.DestinationsNavigator
fun RedemptionStatusScreen(
bundle: Bundle? = null,
navigator: DestinationsNavigator,
redemptionStatusVM: RedemptionStatusVM = hiltViewModel(),
viewModel: RedemptionStatusVM = hiltViewModel(),
) {
val context = LocalContext.current as Activity
val context = LocalContext.current as CoinBaseActivity
val screenContent = remember {
getGsonBuilders().fromJson(bundle?.getString(SCREEN_CONTENT), ScreenDefinition::class.java)
}
var isDataReady by remember { mutableStateOf(false) }
var isLottiePlayed by remember { mutableStateOf(false) }
var isTransactionSuccessful by remember { mutableStateOf(false) }
var isExperimentEnabled by remember {
mutableStateOf(screenContent?.metaData?.get("isExperimentEnabled").toBoolean())
val isExperimentEnabled by remember {
mutableStateOf(screenContent?.metaData?.get(IS_EXPERIMENT_ENABLED).toBoolean())
}
val lifecycleOwner = LocalLifecycleOwner.current
Init(
screenName = COINS_LOADING_SCREEN_SCREEN_NAME,
activity = context,
viewModel = redemptionStatusVM,
viewModel = viewModel,
navigator = navigator
)
val contactsPermissionState = rememberPermissionState(permission = READ_CONTACTS)
LaunchedEffect(key1 = contactsPermissionState) {
if (isExperimentEnabled) {
redemptionStatusVM.isContactPermissionGranted = contactsPermissionState.status.isGranted
redemptionStatusVM.fetchUserData()
viewModel.isContactPermissionGranted = contactsPermissionState.status.isGranted
viewModel.fetchUserData()
}
}
BackHandler {}
DisposableEffect(key1 = lifecycleOwner) {
val lifecycleEventObserver = viewModel.initLifecycleObserver(context)
lifecycleOwner.lifecycle.addObserver(lifecycleEventObserver)
onDispose { lifecycleOwner.lifecycle.removeObserver(lifecycleEventObserver) }
}
LaunchedEffect(key1 = isDataReady, key2 = isLottiePlayed, key3 = isTransactionSuccessful) {
when {
isExperimentEnabled.not() && isLottiePlayed -> {
navigator.popBackStack()
val cta =
CtaAction(
ctaData =
CtaData(
url = COINS_HISTORY_BOTTOMSHEET_CTA,
type = CtaType.REDIRECTION_CTA.name
)
viewModel.nextScreenCtaData =
CtaData(
url = COINS_HISTORY_BOTTOMSHEET_CTA,
type = CtaType.REDIRECTION_CTA.name
)
cta.ctaData?.let {
DeepLinkManager.getDeepLinkListener()
?.navigateTo(context, it, finish = false, bundle = bundle)
if (viewModel.shouldShowOneProfile(screenContent)) {
viewModel.initiateOneProfile(context)
} else {
viewModel.navigateToNextScreen(context)
}
}
isExperimentEnabled && isLottiePlayed -> {
navigator.popBackStack()
val bundle = Bundle()
var cta =
CtaAction(
ctaData =
CtaData(
url = COINS_HISTORY_BOTTOMSHEET_CTA,
type = CtaType.REDIRECTION_CTA.name
)
viewModel.navigationBundle = Bundle()
viewModel.nextScreenCtaData =
CtaData(
url = COINS_HISTORY_BOTTOMSHEET_CTA,
type = CtaType.REDIRECTION_CTA.name
)
val listContact = redemptionStatusVM.getUserData()
val listContact = viewModel.getUserData()
if (isTransactionSuccessful && listContact.isNotNull()) {
bundle.putString(USER_DATA, listContact.toJson())
cta =
CtaAction(
ctaData =
CtaData(
url = COINS_HISTORY_CTA,
type = CtaType.REDIRECTION_CTA.name
)
)
viewModel.navigationBundle.putString(USER_DATA, listContact.toJson())
viewModel.nextScreenCtaData =
CtaData(url = COINS_HISTORY_CTA, type = CtaType.REDIRECTION_CTA.name)
}
cta.ctaData?.let {
DeepLinkManager.getDeepLinkListener()
?.navigateTo(context, it, finish = false, bundle = bundle)
if (viewModel.shouldShowOneProfile(screenContent)) {
viewModel.initiateOneProfile(context)
} else {
viewModel.navigateToNextScreen(context)
}
isDataReady = false
isLottiePlayed = false
@@ -137,7 +133,7 @@ fun RedemptionStatusScreen(
}
LaunchedEffect(Unit) {
redemptionStatusVM.screenActions.collect { action ->
viewModel.screenActions.collect { action ->
when (action) {
is CtaAction -> {
val url = action.ctaData?.url
@@ -158,9 +154,9 @@ fun RedemptionStatusScreen(
}
}
Box(modifier = Modifier.fillMaxSize().background(Color.White)) {
screenContent?.metaData?.get(SHARE_MESSAGE)?.let { redemptionStatusVM.shareMessage = it }
screenContent?.metaData?.get(SHARE_MESSAGE)?.let { viewModel.shareMessage = it }
screenContent?.screenStructure?.content?.widgets?.forEach { uiTronWidget ->
WidgetRenderer(widget = uiTronWidget, viewModel = redemptionStatusVM)
WidgetRenderer(widget = uiTronWidget, viewModel = viewModel)
}
}
}

View File

@@ -0,0 +1,13 @@
/*
*
* * Copyright © 2024 by Navi Technologies Limited
* * All rights reserved. Strictly confidential
*
*/
package com.navi.coin.utils.analytics
object EventConstants {
const val ONE_PROFILE_INIT_EVENT = "naviapp_oneprofile_onboarding_init"
const val ORIGIN_SCREEN = "origin_screen"
}

View File

@@ -47,6 +47,18 @@ object Constants {
const val REDEMPTION_STATUS_SCREEN_CTA_URL = "coin/REDEMPTION_STATUS_SCREEN"
const val TOTAL_CASH_REDEEMED = "totalCashRedeemed"
const val PHONE_NUMBER = "PhoneNumber"
const val HPC = "HPC"
const val VERTICAL_TYPE = "verticalType"
const val RNR = "RNR"
const val APPLICANT_TYPE = "applicantType"
const val CUSTOMER = "CUSTOMER"
const val JOURNEY_TYPE = "journeyType"
const val NON_ONBOARDING = "NON-ONBOARDING"
const val SOURCE = "source"
const val IS_SKIPPABLE = "isSkippable"
const val TRUE = "true"
const val SHOULD_SHOW_ONE_PROFILE = "should_show_op"
const val IS_EXPERIMENT_ENABLED = "isExperimentEnabled"
enum class BottomSheetAction {
SHOW,

View File

@@ -7,25 +7,96 @@
package com.navi.coin.vm
import android.os.Bundle
import androidx.core.os.bundleOf
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.viewModelScope
import com.navi.base.model.CtaData
import com.navi.base.model.CtaType
import com.navi.base.model.LineItem
import com.navi.base.utils.orFalse
import com.navi.coin.ui.activity.CoinBaseActivity
import com.navi.coin.ui.compose.screen.destinations.RedemptionStatusScreenDestination
import com.navi.coin.usecase.ContactUseCase
import com.navi.coin.utils.analytics.EventConstants.ONE_PROFILE_INIT_EVENT
import com.navi.coin.utils.analytics.EventConstants.ORIGIN_SCREEN
import com.navi.coin.utils.constant.Constants.APPLICANT_TYPE
import com.navi.coin.utils.constant.Constants.CUSTOMER
import com.navi.coin.utils.constant.Constants.HPC
import com.navi.coin.utils.constant.Constants.IS_SKIPPABLE
import com.navi.coin.utils.constant.Constants.JOURNEY_TYPE
import com.navi.coin.utils.constant.Constants.NON_ONBOARDING
import com.navi.coin.utils.constant.Constants.RNR
import com.navi.coin.utils.constant.Constants.SCREENS.TRANSACTION_HISTORY_COINS_SCREEN_NAME
import com.navi.coin.utils.constant.Constants.SHOULD_SHOW_ONE_PROFILE
import com.navi.coin.utils.constant.Constants.SOURCE
import com.navi.coin.utils.constant.Constants.TRUE
import com.navi.coin.utils.constant.Constants.VERTICAL_TYPE
import com.navi.coin.utils.navigateTo
import com.navi.common.forge.model.ScreenDefinition
import com.navi.common.navigation.NavArgs
import com.navi.common.navigation.NavigationAction
import com.navi.common.uitron.model.action.CtaAction
import com.navi.common.uitron.model.action.FetchUserRewardsDataAction
import com.navi.common.utils.Constants.APP_PLATFORM_APPLICATION_TYPE
import com.navi.naviwidgets.utils.AP_LAUNCH
import com.navi.rr.referral.models.ReferralContactList
import com.navi.rr.utils.NaviRRAnalytics
import com.navi.rr.utils.constants.Constants
import com.navi.rr.utils.constants.ReferralHomeConstants.COINS_HISTORY_BOTTOMSHEET_CTA
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject
import kotlinx.coroutines.flow.MutableStateFlow
@HiltViewModel
class RedemptionStatusVM @Inject constructor(private val contactUseCase: ContactUseCase) :
CoinBaseVM() {
private var userContactsAndRewards: ReferralContactList? = null
var isContactPermissionGranted: Boolean = false
var shareMessage: String = ""
var nextScreenCtaData: CtaData =
CtaData(url = COINS_HISTORY_BOTTOMSHEET_CTA, type = CtaType.REDIRECTION_CTA.name)
var navigationBundle: Bundle = bundleOf()
var isOneProfileJourneyInitiated = MutableStateFlow(false)
var shouldPopBackStack = MutableStateFlow(false)
fun initLifecycleObserver(context: CoinBaseActivity): LifecycleEventObserver {
val observer = LifecycleEventObserver { _, event ->
when (event) {
Lifecycle.Event.ON_PAUSE -> {
if (isOneProfileJourneyInitiated.value) {
shouldPopBackStack.value = true
}
}
Lifecycle.Event.ON_RESUME -> {
if (isOneProfileJourneyInitiated.value && shouldPopBackStack.value) {
shouldPopBackStack.value = false
isOneProfileJourneyInitiated.value = false
navigateToNextScreen(context)
}
}
else -> Unit
}
}
return observer
}
fun navigateToNextScreen(context: CoinBaseActivity) {
navigateTo(
activity = context,
navHostOwner = context,
navArgs = NavArgs(ctaData = nextScreenCtaData, bundle = navigationBundle),
navAction =
NavigationAction.NextWithPopUpTo(
route = RedemptionStatusScreenDestination.route,
inclusive = true
)
)
}
suspend fun fetchUserData(apiAction: FetchUserRewardsDataAction? = null) {
contactUseCase.fetchUserData(
apiAction = apiAction,
@@ -54,4 +125,47 @@ class RedemptionStatusVM @Inject constructor(private val contactUseCase: Contact
userContactsAndRewards?.shareMessage = shareMessage
return userContactsAndRewards
}
fun shouldShowOneProfile(screenDefinition: ScreenDefinition): Boolean {
return screenDefinition.metaData?.get(SHOULD_SHOW_ONE_PROFILE).toBoolean().orFalse()
}
fun initiateOneProfile(context: CoinBaseActivity) {
isOneProfileJourneyInitiated.value = true
val listParams =
listOf(
LineItem(APP_PLATFORM_APPLICATION_TYPE, HPC),
LineItem(VERTICAL_TYPE, RNR),
LineItem(APPLICANT_TYPE, CUSTOMER)
)
val listAdditionalParams =
listOf(
LineItem(JOURNEY_TYPE, NON_ONBOARDING),
LineItem(SOURCE, RNR),
LineItem(IS_SKIPPABLE, TRUE)
)
NaviRRAnalytics.naviRRAnalytics
.Rewards()
.sendEvent(
eventName = ONE_PROFILE_INIT_EVENT,
extraAttributes =
hashMapOf(
ORIGIN_SCREEN to TRANSACTION_HISTORY_COINS_SCREEN_NAME,
IS_SKIPPABLE to TRUE
)
)
navigateTo(
activity = context,
navHostOwner = context,
navArgs =
NavArgs(
ctaData =
CtaData(
url = AP_LAUNCH,
parameters = listParams,
additionalParameters = listAdditionalParams
)
)
)
}
}

View File

@@ -19,4 +19,7 @@ sealed class NavigationAction {
data object BackWithRefresh : NavigationAction()
data object Default : NavigationAction()
data class NextWithPopUpTo(val route: String, val inclusive: Boolean = false) :
NavigationAction()
}

View File

@@ -66,6 +66,21 @@ class DefaultComposableNavigatorImpl @Inject constructor() : ComposableNavigator
?.set(COMPOSABLE_ID, composableId)
}
private fun nextWithPopUpTo(
navHostOwner: NavHostControllerOwner,
direction: Direction,
composableId: String,
route: String,
inclusive: Boolean
) {
navHostOwner.navController.navigate(direction.route) {
popUpTo(route = route) { this.inclusive = inclusive }
}
navHostOwner.navController.currentBackStackEntry
?.savedStateHandle
?.set(COMPOSABLE_ID, composableId)
}
@SuppressLint("RestrictedApi")
override fun navigate(
navHostOwner: NavHostControllerOwner,
@@ -104,6 +119,15 @@ class DefaultComposableNavigatorImpl @Inject constructor() : ComposableNavigator
direction = direction,
composableId = composableId
)
is NavigationAction.NextWithPopUpTo -> {
nextWithPopUpTo(
navHostOwner = navHostOwner,
direction = direction,
composableId = composableId,
route = action.route,
inclusive = action.inclusive
)
}
}
}
}