NTP-20431 | Added Nudge Action API (#14685)

This commit is contained in:
Aparna Vadlamani
2025-01-27 18:53:01 +05:30
committed by GitHub
parent 330eb5063c
commit 934bc9c391
20 changed files with 162 additions and 38 deletions

View File

@@ -514,12 +514,6 @@ class HomePageActivity :
screenOverlayVM.bottomSheetEffect.collect {
screenOverlayEffectHandler.handleBottomSheetEffect(
effect = it,
triggerStateUpdateApiCall = { nudgeTransitionState ->
screenOverlayVM.triggerStateUpdateApiCall(
nudgeTransitionState,
naeScreenName = screenName,
)
},
handleUitronAction = { actionData -> screenOverlayVM.handleActions(actionData) },
)
}

View File

@@ -40,7 +40,7 @@ open class HpBottomSheetConfig(
val contentColor: String? = null,
val scrimColor: String? = null,
val onDismiss: () -> Unit = {},
val onVisible: () -> Unit = {},
val onView: () -> Unit = {},
val uiStrategy: AlchemistBottomSheetStructure.UiStrategy? = null,
val bottomSheetPercentageHeight: Float? = null,
)

View File

@@ -176,7 +176,7 @@ fun WidgetRenderer(
.NotifyMe(HOME_SCREEN_IN_CAPS)
.notifyMeNudgeOpenSettingsBottomSheetDismissEvent()
},
onVisible = {
onView = {
CommonNaviAnalytics.naviAnalytics
.NotifyMe(HOME_SCREEN_IN_CAPS)
.notifyMeNudgeOpenSettingsBottomSheetLandEvent()

View File

@@ -110,6 +110,7 @@ import com.naviapp.payment.models.LoanPreclosureDetail
import com.naviapp.payment.models.TransactionDetail
import com.naviapp.screenOverlay.model.OverlayItemsStateUpdates
import com.naviapp.screenOverlay.model.OverlayScreenStructure
import com.naviapp.screenOverlay.model.ScreenOverlayActionUpdateRequest
import java.net.ConnectException
import java.net.SocketTimeoutException
import java.net.UnknownHostException
@@ -656,6 +657,12 @@ interface RetrofitService {
@Body request: OverlayItemsStateUpdates
): Response<GenericResponse<Any>>
@RetryPolicy(retryCount = 3)
@PATCH("/nudge/action")
suspend fun updateScreenOverlayElementAction(
@Body request: ScreenOverlayActionUpdateRequest
): Response<GenericResponse<Any>>
@RetryPolicy
@EnableRequestBodyLogging
@GET("/alchemist/inflate/{screenId}")

View File

@@ -25,4 +25,5 @@ data class BottomSheetConfig(
val contentColor: String? = null,
val scrimColor: String? = null,
val onDismiss: UiTronActionData? = null,
val onView: UiTronActionData? = null,
)

View File

@@ -1,6 +1,6 @@
/*
*
* * Copyright © 2024 by Navi Technologies Limited
* * Copyright © 2024-2025 by Navi Technologies Limited
* * All rights reserved. Strictly confidential
*
*/
@@ -22,9 +22,7 @@ sealed interface BottomSheetEvent : UiEvent {
@Immutable
sealed interface BottomSheetEffect : UiEffect {
data class OnBottomSheetRender(val bottomSheetId: String) : BottomSheetEffect
data class OnBottomSheetDismiss(val onDismiss: UiTronActionData) : BottomSheetEffect
data class TriggerUiTronAction(val uiTronActionData: UiTronActionData) : BottomSheetEffect
}
@Immutable

View File

@@ -86,7 +86,7 @@ fun HomeScreenBottomSheet(viewModel: SharedVM, handleAction: (UiTronAction?) ->
LaunchedEffect(key1 = bottomSheetStateHolder.state) {
when (bottomSheetStateHolder.state) {
HpBottomSheetState.Visible -> {
bottomSheetStateHolder.config?.onVisible?.invoke()
bottomSheetStateHolder.config?.onView?.invoke()
modalBottomSheetState.show()
}
HpBottomSheetState.Hidden -> {

View File

@@ -25,11 +25,13 @@ fun BottomSheetData.toHpBottomSheetConfig(viewModel: ScreenOverlayVM): HpBottomS
onDismiss = {
viewModel.sendEvent(BottomSheetEvent.DismissBottomSheet(bottomSheetId.orEmpty()))
bottomSheetConfig?.onDismiss?.let {
viewModel.setEffect { BottomSheetEffect.OnBottomSheetDismiss(it) }
viewModel.setEffect { BottomSheetEffect.TriggerUiTronAction(it) }
}
},
onVisible = {
viewModel.setEffect { BottomSheetEffect.OnBottomSheetRender(bottomSheetId.orEmpty()) }
onView = {
bottomSheetConfig?.onView?.let {
viewModel.setEffect { BottomSheetEffect.TriggerUiTronAction(it) }
}
},
)
}

View File

@@ -9,30 +9,17 @@ package com.naviapp.screenOverlay.handler
import com.navi.uitron.model.data.UiTronActionData
import com.naviapp.screenOverlay.bottomsheet.model.BottomSheetEffect
import com.naviapp.screenOverlay.model.OverlayItemStateUpdate
import com.naviapp.screenOverlay.model.OverlayItemTransitionState
import javax.inject.Inject
class BottomSheetEffectHandler @Inject constructor() {
fun handleBottomSheetEffect(
effect: BottomSheetEffect,
triggerStateUpdateApiCall: (nudgeTransitionState: List<OverlayItemStateUpdate>) -> Unit,
handleUitronAction: (UiTronActionData) -> Unit,
) {
when (effect) {
is BottomSheetEffect.OnBottomSheetRender -> {
triggerStateUpdateApiCall(
mutableListOf(
OverlayItemStateUpdate(
effect.bottomSheetId,
OverlayItemTransitionState.PAUSED,
)
)
)
}
is BottomSheetEffect.OnBottomSheetDismiss -> {
handleUitronAction(effect.onDismiss)
is BottomSheetEffect.TriggerUiTronAction -> {
handleUitronAction(effect.uiTronActionData)
}
}
}

View File

@@ -49,13 +49,8 @@ constructor(
fun handleBottomSheetEffect(
effect: BottomSheetEffect,
triggerStateUpdateApiCall: (nudgeTransitionState: List<OverlayItemStateUpdate>) -> Unit,
handleUitronAction: (UiTronActionData) -> Unit,
) {
bottomSheetEffectHandler.handleBottomSheetEffect(
effect,
triggerStateUpdateApiCall,
handleUitronAction,
)
bottomSheetEffectHandler.handleBottomSheetEffect(effect, handleUitronAction)
}
}

View File

@@ -13,6 +13,7 @@ import com.navi.common.utils.isValidResponse
import com.naviapp.screenOverlay.bottomsheet.model.BottomSheetData
import com.naviapp.screenOverlay.model.OverlayItemsStateUpdates
import com.naviapp.screenOverlay.model.OverlayScreenStructure
import com.naviapp.screenOverlay.model.ScreenOverlayActionUpdateRequest
import com.naviapp.screenOverlay.nudge.model.NudgeListData
import com.naviapp.screenOverlay.nudge.model.StaticNudgeData
import com.naviapp.screenOverlay.popup.model.PopupListData
@@ -111,6 +112,20 @@ constructor(
}
}
suspend fun updateOverlayItemAction(
screenOverlayActionUpdateRequest: ScreenOverlayActionUpdateRequest,
naeScreenName: String,
) {
val response =
screenOverlayRepository.updateOverlayItemAction(
screenOverlayActionUpdateRequest,
naeScreenName = naeScreenName,
)
if (response.isValidResponse().not()) {
analyticsEventTracker.actionUpdateApiCallError(response.error.toString())
}
}
fun collectRequestPopupExists() = collectRequestPopupExists
fun triggerClickStreamEvent(eventName: String, eventValue: Map<String, String>) {

View File

@@ -0,0 +1,18 @@
/*
*
* * Copyright © 2025 by Navi Technologies Limited
* * All rights reserved. Strictly confidential
*
*/
package com.naviapp.screenOverlay.model
data class ScreenOverlayActionUpdateRequest(val nudgeItems: List<OverlayItemActionData>)
data class OverlayItemActionData(val nudgeId: String, val action: OverlayItemAction)
enum class OverlayItemAction {
VIEW,
CLICK,
DISMISS,
}

View File

@@ -14,4 +14,5 @@ data class OverlayItemStateUpdate(val nudgeId: String, val state: OverlayItemTra
enum class OverlayItemTransitionState {
PAUSED,
SUCCESS_ACKNOWLEDGED,
COMPLETED,
}

View File

@@ -15,7 +15,9 @@ import com.navi.ap.common.handler.HandlePublishEventAction
import com.navi.base.deeplink.DeepLinkManager
import com.navi.base.model.CtaData
import com.navi.base.utils.orFalse
import com.navi.common.uitron.model.action.ScreenOverlayActionUpdateAction
import com.navi.common.uitron.model.action.ScreenOverlayApiAction
import com.navi.common.uitron.model.action.ScreenOverlayStateUpdateAction
import com.naviapp.appsettings.utils.hasNotificationPermission
import com.naviapp.home.compose.activity.HomePageActivity
import com.naviapp.home.model.BottomBarTabType
@@ -25,6 +27,10 @@ import com.naviapp.home.viewmodel.SharedVM
import com.naviapp.screenOverlay.bottomsheet.model.BottomSheetState
import com.naviapp.screenOverlay.bottomsheet.utils.toHpBottomSheetConfig
import com.naviapp.screenOverlay.bottomsheet.utils.toHpBottomSheetContent
import com.naviapp.screenOverlay.model.OverlayItemAction
import com.naviapp.screenOverlay.model.OverlayItemActionData
import com.naviapp.screenOverlay.model.OverlayItemStateUpdate
import com.naviapp.screenOverlay.model.OverlayItemTransitionState
import com.naviapp.screenOverlay.viewModel.ScreenOverlayVM
@Composable
@@ -122,12 +128,63 @@ fun HandleApiAction(
isNotificationPermissionEnabled = isNotificationPermissionEnabled,
)
}
is ScreenOverlayStateUpdateAction -> {
val nudgeTransitionState =
action.states.map {
OverlayItemStateUpdate(
nudgeId = it.nudgeId,
state = getOverlayItemTransitionState(overlayItemState = it.state),
)
}
viewModel.triggerStateUpdateApiCall(
nudgeTransitionState = nudgeTransitionState,
naeScreenName = naeScreenName,
)
}
is ScreenOverlayActionUpdateAction -> {
val nudgeActions =
action.actions.map {
OverlayItemActionData(
nudgeId = it.nudgeId,
action = getOverlayItemAction(action = it.action),
)
}
viewModel.triggerActionUpdateApiCall(nudgeActions, naeScreenName)
}
else -> {}
}
}
}
}
private fun getOverlayItemTransitionState(overlayItemState: String): OverlayItemTransitionState {
return when (overlayItemState) {
OverlayItemTransitionState.SUCCESS_ACKNOWLEDGED.name -> {
OverlayItemTransitionState.SUCCESS_ACKNOWLEDGED
}
OverlayItemTransitionState.COMPLETED.name -> {
OverlayItemTransitionState.COMPLETED
}
else -> {
OverlayItemTransitionState.PAUSED
}
}
}
private fun getOverlayItemAction(action: String): OverlayItemAction {
return when (action) {
OverlayItemAction.VIEW.name -> {
OverlayItemAction.VIEW
}
OverlayItemAction.CLICK.name -> {
OverlayItemAction.CLICK
}
else -> {
OverlayItemAction.DISMISS
}
}
}
private fun handleCta(activity: HomePageActivity, ctaData: CtaData) {
DeepLinkManager.getDeepLinkListener()
?.navigateTo(

View File

@@ -16,6 +16,7 @@ import com.naviapp.network.retrofit.ResponseCallback
import com.naviapp.network.retrofit.RetrofitService
import com.naviapp.screenOverlay.model.OverlayItemsStateUpdates
import com.naviapp.screenOverlay.model.OverlayScreenStructure
import com.naviapp.screenOverlay.model.ScreenOverlayActionUpdateRequest
import com.naviapp.screenOverlay.utils.NudgeConstants.HOME_NUDGE
import com.naviapp.screenOverlay.utils.NudgeConstants.NUDGE_ID
import javax.inject.Inject
@@ -52,4 +53,13 @@ constructor(@SuperAppRetroFit private val retrofitService: RetrofitService) : Re
retrofitService.updateScreenOverlayElementState(overlayItemsStateUpdates),
metricInfo = MetricInfo.AppMetric(screen = naeScreenName, isNae = { false }),
)
suspend fun updateOverlayItemAction(
screenOverlayActionUpdateRequest: ScreenOverlayActionUpdateRequest,
naeScreenName: String,
) =
apiResponseCallback(
retrofitService.updateScreenOverlayElementAction(screenOverlayActionUpdateRequest),
metricInfo = MetricInfo.AppMetric(screen = naeScreenName, isNae = { false }),
)
}

View File

@@ -13,6 +13,10 @@ import javax.inject.Inject
class ScreenOverlayAnalytics @Inject constructor() {
fun actionUpdateApiCallError(error: String) {
NaviTrackEvent.trackEvent(SCREEN_OVERLAY_ACTION_UPDATE_API_ERROR, mapOf(ERROR to error))
}
fun pauseApiCallError(error: String) {
NaviTrackEvent.trackEvent(SCREEN_OVERLAY_PAUSE_API_ERROR, mapOf(ERROR to error))
}
@@ -52,5 +56,6 @@ class ScreenOverlayAnalytics @Inject constructor() {
const val BOTTOM_SHEET_ID = "bottom_sheet_id"
const val SCREEN_OVERLAY_ID_LIST = "screen_overlay_id_list"
const val SCREEN_OVERLAY_PAUSE_API_ERROR = "screen_overlay_pause_api_error"
const val SCREEN_OVERLAY_ACTION_UPDATE_API_ERROR = "screen_overlay_action_update_api_error"
}
}

View File

@@ -20,8 +20,10 @@ import com.naviapp.screenOverlay.bottomsheet.model.BottomSheetState
import com.naviapp.screenOverlay.bottomsheet.reducer.BottomSheetReducer
import com.naviapp.screenOverlay.handler.ScreenOverlayHandler
import com.naviapp.screenOverlay.handler.ScreenOverlayUitronActionHandler
import com.naviapp.screenOverlay.model.OverlayItemActionData
import com.naviapp.screenOverlay.model.OverlayItemStateUpdate
import com.naviapp.screenOverlay.model.OverlayItemsStateUpdates
import com.naviapp.screenOverlay.model.ScreenOverlayActionUpdateRequest
import com.naviapp.screenOverlay.nudge.model.NudgeEvent
import com.naviapp.screenOverlay.nudge.model.NudgeListData
import com.naviapp.screenOverlay.nudge.model.NudgeState
@@ -88,6 +90,20 @@ constructor(
}
}
fun triggerActionUpdateApiCall(
nudgeActions: List<OverlayItemActionData>,
naeScreenName: String,
) {
viewModelScope.launch(Dispatchers.IO) {
if (nudgeActions.isNotEmpty()) {
screenOverlayHandler.updateOverlayItemAction(
ScreenOverlayActionUpdateRequest(nudgeItems = nudgeActions),
naeScreenName = naeScreenName,
)
}
}
}
fun fetchOverlayScreenData(
triggerLoadingState: Boolean = false,
naeScreenName: String,

View File

@@ -26,7 +26,9 @@ import com.navi.common.uitron.model.action.MMFetchFinarkeinData
import com.navi.common.uitron.model.action.PartialFillCallAction
import com.navi.common.uitron.model.action.RedeemCoinAction
import com.navi.common.uitron.model.action.RewardsAndReferralApiAction
import com.navi.common.uitron.model.action.ScreenOverlayActionUpdateAction
import com.navi.common.uitron.model.action.ScreenOverlayApiAction
import com.navi.common.uitron.model.action.ScreenOverlayStateUpdateAction
import com.navi.common.uitron.model.action.SdkExitAction
import com.navi.common.uitron.model.action.SubmitFeedbackAction
import com.navi.common.uitron.model.action.V3HomeAction
@@ -86,6 +88,10 @@ class UiTronTriggerApiActionDeserializer : BaseUiTronTriggerApiActionDeserialize
context?.deserialize(jsonObject, CycsGetWebTokenUrlApiAction::class.java)
ApiType.MMFetchFinarkeinData.name ->
context?.deserialize(jsonObject, MMFetchFinarkeinData::class.java)
ApiType.ScreenOverlayStateUpdateAction.name ->
context?.deserialize(jsonObject, ScreenOverlayStateUpdateAction::class.java)
ApiType.ScreenOverlayActionUpdateAction.name ->
context?.deserialize(jsonObject, ScreenOverlayActionUpdateAction::class.java)
else -> super.deserialize(json, typeOfT, context)
}
}

View File

@@ -1,6 +1,6 @@
/*
*
* * Copyright © 2024 by Navi Technologies Limited
* * Copyright © 2024-2025 by Navi Technologies Limited
* * All rights reserved. Strictly confidential
*
*/
@@ -10,3 +10,13 @@ package com.navi.common.uitron.model.action
import com.navi.uitron.model.action.TriggerApiAction
data object ScreenOverlayApiAction : TriggerApiAction()
data class ScreenOverlayStateUpdateAction(val states: List<ScreenOverlayState>) :
TriggerApiAction()
data class ScreenOverlayActionUpdateAction(val actions: List<ScreenOverlayAction>) :
TriggerApiAction()
data class ScreenOverlayState(val nudgeId: String, val state: String)
data class ScreenOverlayAction(val nudgeId: String, val action: String)

View File

@@ -77,6 +77,8 @@ enum class ApiType {
FetchUsersReferralDataAction,
GetScreenOverlayData,
MMFetchFinarkeinData,
ScreenOverlayStateUpdateAction,
ScreenOverlayActionUpdateAction,
}
enum class SourceType {