NTP-43759 | Venkat Praneeth | Locked coins (#15686)

This commit is contained in:
Venkat Praneeth Reddy
2025-04-09 17:00:02 +05:30
committed by GitHub
parent 82ff18a316
commit dec80abe4e
14 changed files with 170 additions and 58 deletions

View File

@@ -26,6 +26,7 @@ data class ScratchCard(
val status: String? = null,
val value: String? = null,
val naviCoinDetails: NaviCoinDetails? = null,
val rewardState: String? = null,
val metadata: ScratchCardHistoryCardMetaData,
val accrualExpireAtEpoch: Long? = 0L,
)
@@ -57,6 +58,7 @@ data class ScratchCardAttributes(
val screenDefinition: ScreenDefinition? = null,
val requestId: String? = null,
val rewardAmount: Int? = null,
val rewardState: String? = null,
)
fun ScratchCard.toFlatMap(): Map<String, Any?> {
@@ -72,6 +74,7 @@ fun ScratchCard.toFlatMap(): Map<String, Any?> {
"rewardType" to rewardType,
"status" to status,
"value" to value,
"rewardState" to rewardState,
"expiryTimeLeft" to formattedExpiryTime,
) +
naviCoinDetailsMap.entries.associate { "naviCoinDetails.${it.key}" to it.value } +

View File

@@ -31,3 +31,9 @@ enum class ScratchCardStatus {
IN_PROGRESS,
COMPLETE,
}
enum class RewardState {
SUCCESS,
HOLD,
FAILURE,
}

View File

@@ -24,3 +24,5 @@ val Color_F3F1F3 = Color(0xFFF3F1F3)
val Color_757375 = Color(0xFF757375)
val topBarGradientStartColor = Color(0xFF451156)
val topBarGradientEndColor = Color(0xFF340D41)
val onSurfaceCritical = Color(0xFFEF0000)
val bgError = Color(0XFFFFEAEA)

View File

@@ -71,16 +71,19 @@ import coil.request.ImageRequest
import com.navi.base.utils.EMPTY
import com.navi.coin.R
import com.navi.coin.models.model.ScratchCard
import com.navi.coin.models.states.RewardState
import com.navi.coin.models.states.ScratchCardPaginatedHistoryScreenState
import com.navi.coin.models.states.ScratchCardStatus
import com.navi.coin.theme.Color_757375
import com.navi.coin.theme.Color_824992
import com.navi.coin.theme.Color_F3F1F3
import com.navi.coin.theme.Color_F9F9F9
import com.navi.coin.theme.bgError
import com.navi.coin.theme.borderAlt
import com.navi.coin.theme.brandSupportingMidGreen
import com.navi.coin.theme.ctaTertiary
import com.navi.coin.theme.midGoldColor
import com.navi.coin.theme.onSurfaceCritical
import com.navi.coin.theme.onSurfaceHighlight
import com.navi.coin.theme.textGray
import com.navi.coin.theme.textOrange
@@ -93,6 +96,8 @@ import com.navi.coin.utils.constant.Constants.IN_PROGRESS
import com.navi.coin.utils.constant.Constants.LOCKED_SCRATCH_CARD_URL_KEY
import com.navi.coin.utils.constant.Constants.SCRATCHED_SCRATCH_CARD_URL_KEY
import com.navi.coin.utils.constant.Constants.SCRATCH_CARD_EXPIRED_BOTTOM_SHEET
import com.navi.coin.utils.constant.Constants.SCRATCH_CARD_FAILED_BOTTOM_SHEET
import com.navi.coin.utils.constant.Constants.SCRATCH_CARD_HELD_BOTTOM_SHEET
import com.navi.coin.utils.constant.Constants.SCRATCH_CARD_IN_PROGRESS_BOTTOM_SHEET
import com.navi.coin.utils.constant.Constants.SCRATCH_CARD_RECEIVED_BOTTOM_SHEET
import com.navi.coin.utils.constant.Constants.ScratchCardHistoryScreen.VIEW_MORE_SCROLL_DOWN_IN_DP
@@ -112,8 +117,9 @@ import com.navi.rr.common.widgetFactory.NotifyWidgetRenderer
import com.navi.rr.common.widgetFactory.WidgetRenderer
import com.navi.rr.utils.NaviRRAnalytics
import com.navi.rr.utils.constants.Constants.SHOULD_NOTIFY_WIDGET
import com.navi.rr.utils.constants.EventConstants.BOTTOM_SHEET_TYPE
import com.navi.rr.utils.constants.EventConstants.REWARD_STATE
import com.navi.rr.utils.constants.EventConstants.SCRATCH_CARD_HISTORY_BOTTOM_SHEET_VISIBLE_EVENT
import com.navi.rr.utils.constants.EventConstants.SCRATCH_CARD_STATUS
import com.navi.rr.utils.custompager.PagerItemState
import com.navi.rr.utils.custompager.PagerStateHolder
import com.navi.rr.utils.getNaviCoinsString
@@ -538,7 +544,7 @@ fun ScratchCardLockedOrExpired(
when (scratchCardState) {
ScratchCardStatus.LOCKED.name -> Color_824992
ScratchCardStatus.EXPIRED.name -> textTertiary
else -> Color_824992
else -> textTertiary
},
shape = RoundedCornerShape(topStart = 4.dp, topEnd = 4.dp),
)
@@ -655,7 +661,15 @@ fun ScratchCardScratched(
Modifier.background(
color =
when (scratchCard.status) {
ScratchCardStatus.COMPLETE.name -> brandSupportingMidGreen
ScratchCardStatus.COMPLETE.name -> {
val rewardState = scratchCard.rewardState
when (rewardState) {
RewardState.SUCCESS.name -> brandSupportingMidGreen
RewardState.FAILURE.name -> bgError
RewardState.HOLD.name -> midGoldColor
else -> midGoldColor
}
}
ScratchCardStatus.IN_PROGRESS.name -> midGoldColor
else -> midGoldColor
},
@@ -666,10 +680,19 @@ fun ScratchCardScratched(
Text(
text =
when (scratchCard.status) {
ScratchCardStatus.COMPLETE.name ->
stringResource(id = R.string.received)
ScratchCardStatus.COMPLETE.name -> {
val rewardState = scratchCard.rewardState
when (rewardState) {
RewardState.SUCCESS.name ->
stringResource(id = R.string.received)
RewardState.FAILURE.name -> stringResource(id = R.string.failed)
RewardState.HOLD.name ->
stringResource(id = R.string.in_progress)
else -> stringResource(id = R.string.in_progress)
}
}
ScratchCardStatus.IN_PROGRESS.name -> IN_PROGRESS
else -> EXPIRED
else -> IN_PROGRESS
},
fontFamily = naviFontFamily,
fontWeight = getFontWeight(FontWeightEnum.NAVI_HEADLINE_REGULAR),
@@ -677,7 +700,15 @@ fun ScratchCardScratched(
lineHeight = 18.sp,
color =
when (scratchCard.status) {
ScratchCardStatus.COMPLETE.name -> onSurfaceHighlight
ScratchCardStatus.COMPLETE.name -> {
val rewardState = scratchCard.rewardState
when (rewardState) {
RewardState.SUCCESS.name -> onSurfaceHighlight
RewardState.FAILURE.name -> onSurfaceCritical
RewardState.HOLD.name -> textOrange
else -> textOrange
}
}
ScratchCardStatus.IN_PROGRESS.name -> textOrange
else -> textOrange
},
@@ -705,7 +736,7 @@ private fun sendBottomSheetDataOrShowGratification(
analyticsHelper.sendEvent(
eventName = SCRATCH_CARD_HISTORY_BOTTOM_SHEET_VISIBLE_EVENT,
extraAttributes =
hashMapOf(BOTTOM_SHEET_TYPE to ScratchCardStatus.EXPIRED.name),
hashMapOf(SCRATCH_CARD_STATUS to ScratchCardStatus.EXPIRED.name),
)
renderBottomSheet.invoke(SCRATCH_CARD_EXPIRED_BOTTOM_SHEET, scratchCard)
}
@@ -720,17 +751,50 @@ private fun sendBottomSheetDataOrShowGratification(
analyticsHelper.sendEvent(
eventName = SCRATCH_CARD_HISTORY_BOTTOM_SHEET_VISIBLE_EVENT,
extraAttributes =
hashMapOf(BOTTOM_SHEET_TYPE to ScratchCardStatus.IN_PROGRESS.name),
hashMapOf(SCRATCH_CARD_STATUS to ScratchCardStatus.IN_PROGRESS.name),
)
renderBottomSheet.invoke(SCRATCH_CARD_IN_PROGRESS_BOTTOM_SHEET, scratchCard)
}
ScratchCardStatus.COMPLETE.name -> {
analyticsHelper.sendEvent(
eventName = SCRATCH_CARD_HISTORY_BOTTOM_SHEET_VISIBLE_EVENT,
extraAttributes =
hashMapOf(BOTTOM_SHEET_TYPE to ScratchCardStatus.COMPLETE.name),
)
renderBottomSheet.invoke(SCRATCH_CARD_RECEIVED_BOTTOM_SHEET, scratchCard)
val rewardState = scratchCard.rewardState
when (rewardState) {
RewardState.SUCCESS.name -> {
renderBottomSheet.invoke(SCRATCH_CARD_RECEIVED_BOTTOM_SHEET, scratchCard)
analyticsHelper.sendEvent(
eventName = SCRATCH_CARD_HISTORY_BOTTOM_SHEET_VISIBLE_EVENT,
extraAttributes =
hashMapOf(
SCRATCH_CARD_STATUS to ScratchCardStatus.COMPLETE.name,
REWARD_STATE to RewardState.SUCCESS.name,
),
)
}
RewardState.FAILURE.name -> {
renderBottomSheet.invoke(SCRATCH_CARD_FAILED_BOTTOM_SHEET, scratchCard)
analyticsHelper.sendEvent(
eventName = SCRATCH_CARD_HISTORY_BOTTOM_SHEET_VISIBLE_EVENT,
extraAttributes =
hashMapOf(
SCRATCH_CARD_STATUS to ScratchCardStatus.COMPLETE.name,
REWARD_STATE to RewardState.FAILURE.name,
),
)
}
RewardState.HOLD.name -> {
renderBottomSheet.invoke(SCRATCH_CARD_HELD_BOTTOM_SHEET, scratchCard)
analyticsHelper.sendEvent(
eventName = SCRATCH_CARD_HISTORY_BOTTOM_SHEET_VISIBLE_EVENT,
extraAttributes =
hashMapOf(
SCRATCH_CARD_STATUS to ScratchCardStatus.COMPLETE.name,
REWARD_STATE to RewardState.HOLD.name,
),
)
}
else -> {
renderBottomSheet.invoke(SCRATCH_CARD_IN_PROGRESS_BOTTOM_SHEET, scratchCard)
}
}
}
else -> {
renderBottomSheet.invoke(SCRATCH_CARD_IN_PROGRESS_BOTTOM_SHEET, scratchCard)

View File

@@ -73,6 +73,7 @@ import com.navi.base.utils.orFalse
import com.navi.base.utils.orZero
import com.navi.coin.R
import com.navi.coin.models.model.ScratchCard
import com.navi.coin.models.states.RewardState
import com.navi.coin.models.states.ScratchCardHistoryScreenState
import com.navi.coin.models.states.ScratchCardStatus
import com.navi.coin.theme.topBarGradientEndColor
@@ -441,10 +442,12 @@ fun ScratchCardHistoryScreen(
) { response ->
scratchAnalyticsTrigger(response, analyticsHandler)
viewModel.userHasScratchedCard = true
viewModel.previousBalance =
viewModel.previousBalance?.plus(
currentScratchCard.rewardAmount.orZero()
)
if (currentScratchCard.rewardState != RewardState.HOLD.name) {
viewModel.previousBalance =
viewModel.previousBalance?.plus(
currentScratchCard.rewardAmount.orZero()
)
}
}
}
}
@@ -491,10 +494,12 @@ fun ScratchCardHistoryScreen(
) { response ->
scratchAnalyticsTrigger(response, analyticsHandler)
viewModel.userHasScratchedCard = true
viewModel.previousBalance =
viewModel.previousBalance?.plus(
nextScratchCard.rewardAmount.orZero()
)
if (nextScratchCard.rewardState != RewardState.HOLD.name) {
viewModel.previousBalance =
viewModel.previousBalance?.plus(
nextScratchCard.rewardAmount.orZero()
)
}
}
}
}

View File

@@ -12,6 +12,7 @@ import com.navi.base.utils.isNotNull
import com.navi.coin.models.model.ScratchCard
import com.navi.coin.models.model.ScratchCardAttributes
import com.navi.coin.models.model.toFlatMap
import com.navi.coin.models.states.RewardState
import com.navi.coin.utils.constant.Constants
import com.navi.common.forge.model.ScreenDefinition
import com.navi.common.forge.model.WidgetModelDefinition
@@ -153,13 +154,18 @@ constructor(@Assisted val coroutineScope: CoroutineScope) {
private fun getTemplateName(
amount: String?,
rewardType: String? = null,
template: ScreenDefinition?,
screenDefinition: ScreenDefinition?,
rewardState: String?,
): String? {
val jsonMetaData = template?.jsonMetaData?.get("templateName").toJsonObject()
val jsonMetaData = screenDefinition?.jsonMetaData?.get("templateName").toJsonObject()
return if (amount != "0") {
jsonMetaData?.optJSONObject(rewardType)?.getString("REWARD")
if (rewardState == RewardState.HOLD.name) {
jsonMetaData?.optJSONObject(rewardType)?.getString(HELD_REWARD)
} else {
jsonMetaData?.optJSONObject(rewardType)?.getString(REWARD)
}
} else {
jsonMetaData?.optJSONObject(rewardType)?.getString("NO_REWARD")
jsonMetaData?.optJSONObject(rewardType)?.getString(NO_REWARD)
}
}
@@ -208,7 +214,8 @@ constructor(@Assisted val coroutineScope: CoroutineScope) {
getTemplateName(
amount = coinAmount,
rewardType = scratchCardData.rewardType ?: EMPTY,
template = screenDefinition,
screenDefinition = screenDefinition,
rewardState = scratchCardData.rewardState,
)
)
?.let { template ->
@@ -223,6 +230,7 @@ constructor(@Assisted val coroutineScope: CoroutineScope) {
screenDefinition = tempScreenDefinition,
requestId = scratchCardData.refId ?: "",
rewardAmount = coinAmountValue,
rewardState = scratchCardData.rewardState,
)
)
} ?: run { callback(null) }
@@ -249,5 +257,8 @@ constructor(@Assisted val coroutineScope: CoroutineScope) {
const val MORE = "more"
const val DONE = "done"
const val SCRATCH_MORE = "SCRATCH_MORE"
const val HELD_REWARD = "HELD_REWARD"
const val REWARD = "REWARD"
const val NO_REWARD = "NO_REWARD"
}
}

View File

@@ -22,6 +22,8 @@ object Constants {
const val SCRATCH_CARD_EXPIRED_BOTTOM_SHEET = "SCRATCH_CARD_EXPIRED_BOTTOM_SHEET"
const val SCRATCH_CARD_IN_PROGRESS_BOTTOM_SHEET = "SCRATCH_CARD_IN_PROGRESS_BOTTOM_SHEET"
const val SCRATCH_CARD_RECEIVED_BOTTOM_SHEET = "SCRATCH_CARD_RECEIVED_BOTTOM_SHEET"
const val SCRATCH_CARD_FAILED_BOTTOM_SHEET = "SCRATCH_CARD_FAILED_BOTTOM_SHEET"
const val SCRATCH_CARD_HELD_BOTTOM_SHEET = "SCRATCH_CARD_HELD_BOTTOM_SHEET"
const val SCRATCH_CARD_BAL = "scratchCardBal"
const val CAMPAIGN_ID = "campaign_id"
const val FULL_STOP = "."

View File

@@ -140,6 +140,7 @@ abstract class BaseScratchCardNudgeHelper(
const val TEMPLATE_NAME = "templateName"
const val REWARD = "REWARD"
const val NO_REWARD = "NO_REWARD"
const val HELD_REWARD = "HELD_REWARD"
const val INSTANT_REWARD = "INSTANT_REWARD"
const val NONE = "NONE"
const val ZERO_AMOUNT = "0"

View File

@@ -10,6 +10,7 @@ package com.navi.rr.scratchcard.helper.nudgeHelperV2
import com.navi.base.utils.isNotNull
import com.navi.common.forge.model.ScreenDefinition
import com.navi.common.utils.toJsonObject
import com.navi.rr.scratchcard.helper.BaseScratchCardNudgeHelper.Companion.HELD_REWARD
import com.navi.rr.scratchcard.helper.BaseScratchCardNudgeHelper.Companion.INSTANT_REWARD
import com.navi.rr.scratchcard.helper.BaseScratchCardNudgeHelper.Companion.N
import com.navi.rr.scratchcard.helper.BaseScratchCardNudgeHelper.Companion.NONE
@@ -57,6 +58,7 @@ class ScratchCardResponseHandler @Inject constructor(private val fieldInjector:
rewardType = scratchCardData?.rewardType,
template = template,
rewardForm = scratchCardData?.rewardForm,
isRewardLocked = scratchCardData?.isRewardLocked,
)
template?.screenStructure?.templates?.get(screenTemplate)?.let {
val inflatedTemplate =
@@ -83,6 +85,7 @@ class ScratchCardResponseHandler @Inject constructor(private val fieldInjector:
amount: String?,
rewardType: String? = null,
rewardForm: String? = null,
isRewardLocked: Boolean? = null,
template: ScreenDefinition?,
): String? {
val jsonMetaData = template?.jsonMetaData?.get(TEMPLATE_NAME).toJsonObject()
@@ -94,7 +97,11 @@ class ScratchCardResponseHandler @Inject constructor(private val fieldInjector:
}
}
return if (amount != ZERO_AMOUNT) {
jsonMetaData?.optJSONObject(rewardType)?.getString(REWARD)
if (isRewardLocked == true) {
jsonMetaData?.optJSONObject(rewardType)?.getString(HELD_REWARD)
} else {
jsonMetaData?.optJSONObject(rewardType)?.getString(REWARD)
}
} else {
jsonMetaData?.optJSONObject(rewardType)?.getString(NO_REWARD)
}

View File

@@ -51,6 +51,7 @@ data class ScratchCardResponse(
val naviCoinDetails: NaviCoinDetails? = null,
val metadata: ScratchCardHistoryCardMetaData? = null,
val isPlayerCard: Boolean? = null,
val isRewardLocked: Boolean? = null,
) {
fun toScratchCard(): ScratchCard {
return ScratchCard(
@@ -69,6 +70,7 @@ data class ScratchCardResponse(
),
naviCoinDetails = naviCoinDetails,
expiryEpoch = accrualExpireAtEpoch,
isRewardLocked = isRewardLocked,
)
}
@@ -89,6 +91,7 @@ data class ScratchCardResponse(
),
naviCoinDetails = naviCoinDetails,
expiryEpoch = accrualExpireAtEpoch,
isRewardLocked = isRewardLocked,
)
}
}
@@ -106,6 +109,7 @@ data class ScratchCard(
val metadata: ScratchCardHistoryCardMetaData,
val expiryEpoch: Long? = null,
val templateName: String? = null,
val isRewardLocked: Boolean? = null,
)
data class ScratchCardHistoryCardMetaData(

View File

@@ -31,6 +31,7 @@ data class ScratchCardModel(
val inventoryValue: PlayerValue? = null,
val metaData: Map<String, Any?>? = null,
val type: String? = null,
val isRewardLocked: Boolean? = null,
)
data class ScratchCardModelDataEntity(
@@ -68,6 +69,7 @@ data class CardAttributes(
val rewardAmount: Int? = null,
val isCoinScratchCard: Boolean = true,
val customerName: String? = null,
val isRewardLocked: Boolean? = false,
)
data class PlayerValue(val cardType: String? = null, val cardSubType: String? = null)

View File

@@ -261,23 +261,20 @@ fun ScratchCardDeck(
sendBackResponse.invoke(viewModel.scratchCardBackResponse.value)
viewModel.resetData()
onBackPress?.invoke()
// viewModel.clearScratchCardList()
},
) { response ->
//
// scratchAnalyticsTrigger(response,
// analyticsHandler)
scope.launch {
viewModel.scratchCardDeckUseCases.updateSecondCardData()
}
response?.let { viewModel.setScratchCardBackResponse(it) }
onScratched?.invoke(currentScratchCard.requestId ?: "")
viewModel.userHasScratchedCard = true
viewModel.previousBalance =
viewModel.previousBalance?.plus(
currentScratchCard.rewardAmount.orZero()
)
if (currentScratchCard.isRewardLocked != true) {
viewModel.previousBalance =
viewModel.previousBalance?.plus(
currentScratchCard.rewardAmount.orZero()
)
}
}
}
}
@@ -316,19 +313,16 @@ fun ScratchCardDeck(
sendBackResponse.invoke(viewModel.scratchCardBackResponse.value)
viewModel.resetData()
onBackPress?.invoke()
// viewModel.clearScratchCardList()
},
) { response ->
//
// scratchAnalyticsTrigger(response,
// analyticsHandler)
onScratched?.invoke(nextScratchCard.requestId ?: "")
viewModel.userHasScratchedCard = true
viewModel.previousBalance =
viewModel.previousBalance?.plus(
nextScratchCard.rewardAmount.orZero()
)
if (nextScratchCard.isRewardLocked != true) {
viewModel.previousBalance =
viewModel.previousBalance?.plus(
nextScratchCard.rewardAmount.orZero()
)
}
}
}
}

View File

@@ -380,6 +380,7 @@ constructor(@Assisted val coroutineScope: CoroutineScope) {
rewardAmount = coinAmountValue,
isCoinScratchCard = scratchCardData.inventoryValue.isNull(),
customerName = scratchCardData.metadata.customerName,
isRewardLocked = scratchCardData.isRewardLocked ?: false,
)
)
} ?: run { callback(null) }
@@ -394,17 +395,19 @@ constructor(@Assisted val coroutineScope: CoroutineScope) {
private fun getDefaultTemplates(scratchCardData: ScratchCardModel?): String {
return when (dataSource) {
is FixedScratchCardDataSource -> {
if (scratchCardData?.inventoryValue.isNull()) {
if (scratchCardData?.metadata?.subtitle == "0") {
"FESTIVE_SCRATCH_CARD_DUAL_EXPERIENCE_NO_REWARDS"
} else {
"FESTIVE_SCRATCH_CARD_DUAL_EXPERIENCE"
}
} else {
"PLAYER_CARD"
val isInventoryNull = scratchCardData?.inventoryValue.isNull()
val isRewardAmountZero = scratchCardData?.metadata?.subtitle == "0"
val isRewardLocked = scratchCardData?.isRewardLocked == true
when {
isInventoryNull && isRewardAmountZero ->
FESTIVE_SCRATCH_CARD_DUAL_EXPERIENCE_NO_REWARDS
isInventoryNull && isRewardLocked -> FESTIVE_SCRATCH_CARD_DUAL_HELD_EXPERIENCE
isInventoryNull -> FESTIVE_SCRATCH_CARD_DUAL_EXPERIENCE
else -> PLAYER_CARD
}
}
else -> "PLAYERCARDS"
else -> PLAYERCARDS
}
}
@@ -432,5 +435,12 @@ constructor(@Assisted val coroutineScope: CoroutineScope) {
const val MORE = "more"
const val DONE = "done"
const val SCRATCH_MORE = "SCRATCH_MORE"
const val FESTIVE_SCRATCH_CARD_DUAL_EXPERIENCE_NO_REWARDS =
"FESTIVE_SCRATCH_CARD_DUAL_EXPERIENCE_NO_REWARDS"
const val FESTIVE_SCRATCH_CARD_DUAL_EXPERIENCE = "FESTIVE_SCRATCH_CARD_DUAL_EXPERIENCE"
const val FESTIVE_SCRATCH_CARD_DUAL_HELD_EXPERIENCE =
"FESTIVE_SCRATCH_CARD_DUAL_HELD_EXPERIENCE"
const val PLAYER_CARD = "PLAYER_CARD"
const val PLAYERCARDS = "PLAYERCARDS"
}
}

View File

@@ -1,6 +1,6 @@
/*
*
* * Copyright © 2024 by Navi Technologies Limited
* * Copyright © 2024-2025 by Navi Technologies Limited
* * All rights reserved. Strictly confidential
*
*/
@@ -17,7 +17,8 @@ object EventConstants {
const val SCRATCHED = "scratched"
const val YES = "Y"
const val NO = "N"
const val BOTTOM_SHEET_TYPE = "bottomsheet_type"
const val SCRATCH_CARD_STATUS = "ScratchCardStatus"
const val REWARD_STATE = "rewardState"
const val TRANSACTION_ID = "transaction_id"
const val SCREEN_NAME = "screen_name"
const val REWARD_EARNED = "reward_earned"