NTP-48074 | Divyesh | Bill refresh before payment (#15539)
This commit is contained in:
@@ -180,6 +180,7 @@ const val BILL_FETCH_CONSENT_DEFAULT_MESSAGE =
|
||||
"By continuing, you allow Navi to fetch current bill & send reminders for future bills."
|
||||
const val TAG_BILL_FETCH_ERROR = "TAG_BILL_FETCH_ERROR"
|
||||
const val ACTION_CIRCLE_OPERATOR_SELECTION = "ACTION_CIRCLE_OPERATOR_SELECTION"
|
||||
const val TAG_BILL_ALREADY_PAID_ON_REFETCH = "TAG_BILL_ALREADY_PAID"
|
||||
|
||||
// offer experience event attributes and tags
|
||||
const val RCBP_CATEGORY = "RCBP_CATEGORY"
|
||||
|
||||
@@ -49,6 +49,7 @@ data class NaviBbpsDefaultConfig(
|
||||
val detectedBillsPollingTimeoutMillis: Long = 30000,
|
||||
@SerializedName("detectedBillsPollingWaitTimeMillis")
|
||||
val detectedBillsPollingWaitTimeMillis: Long = 2000,
|
||||
val billAlreadyPaidErrorCodes: List<String> = listOf("INVAL003"),
|
||||
) {
|
||||
data class PaymentCheckoutConfigItem(
|
||||
@SerializedName("categoryId") val categoryId: String = EMPTY,
|
||||
@@ -488,6 +489,11 @@ data class ConfigMessage(
|
||||
@SerializedName("invalidContactSelectedMessage")
|
||||
val invalidContactSelectedDescription: String =
|
||||
"It looks like you've selected an invalid phone number. Please choose another contact or enter a new phone number",
|
||||
@SerializedName("billDetailsRefreshedTitle")
|
||||
val billDetailsUpdatedTitle: String = "Bill details have been updated",
|
||||
@SerializedName("billDetailsRefreshedDescription")
|
||||
val billDetailsUpdatedDescription: String =
|
||||
"We have fetched the latest bill details from your biller. The amount or due date may have changed. Please review before proceeding.",
|
||||
)
|
||||
|
||||
data class CoinUtilisationConfig(
|
||||
|
||||
@@ -49,6 +49,7 @@ constructor(
|
||||
suspend fun fetchBillDetails(
|
||||
billDetailsRequest: BillDetailsRequest,
|
||||
metricInfo: MetricInfo<RepoResult<BillDetailsResponse>>,
|
||||
onSavedBillRefresh: (suspend (BillDetailsResponse) -> Unit)? = null,
|
||||
): RepoResult<BillDetailsResponse> {
|
||||
val response =
|
||||
apiResponseCallback(
|
||||
@@ -57,7 +58,10 @@ constructor(
|
||||
metricInfo = metricInfo,
|
||||
)
|
||||
if (response.isSuccessWithData()) {
|
||||
myBillsSyncJob.refreshBillsAsync(screenName = metricInfo.screen)
|
||||
myBillsSyncJob.refreshBillsAsync(
|
||||
screenName = metricInfo.screen,
|
||||
onSavedBillRefresh = { onSavedBillRefresh?.invoke(response.data!!) },
|
||||
)
|
||||
}
|
||||
return response
|
||||
}
|
||||
|
||||
@@ -9,6 +9,8 @@ package com.navi.bbps.common.usecase
|
||||
|
||||
import com.navi.base.utils.NaviNetworkConnectivity
|
||||
import com.navi.base.utils.orFalse
|
||||
import com.navi.base.utils.orZero
|
||||
import com.navi.bbps.common.TAG_BILL_ALREADY_PAID_ON_REFETCH
|
||||
import com.navi.bbps.common.TAG_BILL_FETCH_ERROR
|
||||
import com.navi.bbps.common.mapper.BillResponseToBillDetailsEntityMapper
|
||||
import com.navi.bbps.common.repository.BbpsCommonRepository
|
||||
@@ -18,6 +20,9 @@ import com.navi.bbps.feature.customerinput.model.network.BillDetailsRequest
|
||||
import com.navi.bbps.feature.customerinput.model.network.BillDetailsResponse
|
||||
import com.navi.bbps.feature.customerinput.model.network.DeviceDetails
|
||||
import com.navi.bbps.feature.customerinput.model.view.BillDetailsEntity
|
||||
import com.navi.bbps.feature.mybills.MyBillsRepository
|
||||
import com.navi.bbps.feature.mybills.MyBillsSyncJob
|
||||
import com.navi.bbps.feature.mybills.model.view.UnpaidBillDetails
|
||||
import com.navi.bbps.feature.paybill.PayBillViewModel
|
||||
import com.navi.common.network.models.RepoResult
|
||||
import com.navi.common.network.models.isSuccessWithData
|
||||
@@ -25,12 +30,16 @@ import javax.inject.Inject
|
||||
|
||||
typealias IsConsentRequired = Boolean
|
||||
|
||||
typealias IsBillDetailsChanged = Boolean
|
||||
|
||||
class FetchBillHandler
|
||||
@Inject
|
||||
constructor(
|
||||
private val bbpsCommonRepository: BbpsCommonRepository,
|
||||
private val naviNetworkConnectivity: NaviNetworkConnectivity,
|
||||
private val naviBbpsDateUtils: NaviBbpsDateUtils,
|
||||
private val myBillsRepository: MyBillsRepository,
|
||||
private val myBillsSyncJob: MyBillsSyncJob,
|
||||
) {
|
||||
suspend fun fetchBill(
|
||||
payBillViewModel: PayBillViewModel,
|
||||
@@ -69,6 +78,90 @@ constructor(
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun refetchBill(
|
||||
payBillViewModel: PayBillViewModel,
|
||||
screenName: String,
|
||||
onReFetchSuccess: suspend (IsBillDetailsChanged, BillDetailsEntity) -> Unit,
|
||||
billAlreadyPaidErrorCodes: List<String>,
|
||||
) {
|
||||
|
||||
val billDetailsRequest =
|
||||
BillDetailsRequest(
|
||||
billerId = payBillViewModel.payBillScreenSource.billerId,
|
||||
referenceId = payBillViewModel.payBillScreenSource.billDetailsEntity!!.referenceId,
|
||||
customerParams = payBillViewModel.payBillScreenSource.customerParams,
|
||||
isConsentProvided =
|
||||
payBillViewModel.payBillScreenSource.isConsentRequired.orFalse(),
|
||||
deviceDetails = DeviceDetails(ip = naviNetworkConnectivity.getIpAddress()),
|
||||
)
|
||||
|
||||
val billDetailsResponse =
|
||||
bbpsCommonRepository.fetchBillDetails(
|
||||
billDetailsRequest = billDetailsRequest,
|
||||
metricInfo = getBbpsMetricInfo(screenName = screenName, isNae = { false }),
|
||||
onSavedBillRefresh = { billDetailsResponse ->
|
||||
val billDetailsEntity =
|
||||
BillResponseToBillDetailsEntityMapper(naviBbpsDateUtils)
|
||||
.map(billDetailsResponse)
|
||||
val billFetchTimestamp = billDetailsResponse.apiCallTimestamp?.millis.orZero()
|
||||
|
||||
if (
|
||||
billFetchTimestamp >
|
||||
payBillViewModel.myBillEntity.value
|
||||
?.unpaidBillDetails
|
||||
?.lastGeneratedTimestamp
|
||||
?.toLongOrNull()
|
||||
.orZero() && billDetailsResponse.isBillDetailsChanged
|
||||
) {
|
||||
|
||||
payBillViewModel.myBillEntity.value?.let {
|
||||
val updatedMyBillEntity =
|
||||
payBillViewModel.myBillEntity.value!!.copy(
|
||||
unpaidBillDetails =
|
||||
UnpaidBillDetails(
|
||||
referenceId = billDetailsEntity.referenceId,
|
||||
amount = billDetailsEntity.amount,
|
||||
billDate = billDetailsEntity.billDate,
|
||||
dueDate = billDetailsEntity.dueDate,
|
||||
billNumber = billDetailsEntity.billNumber,
|
||||
accountHolderName = billDetailsEntity.accountHolderName,
|
||||
billerAdditionalParams =
|
||||
billDetailsEntity.billerAdditionalParams,
|
||||
planItemDetails =
|
||||
payBillViewModel.myBillEntity.value
|
||||
?.unpaidBillDetails
|
||||
?.planItemDetails ?: emptyMap(),
|
||||
lastGeneratedTimestamp =
|
||||
billDetailsResponse.apiCallTimestamp
|
||||
?.millis
|
||||
.toString(),
|
||||
)
|
||||
)
|
||||
|
||||
myBillsRepository.updateSavedBill(myBillEntity = updatedMyBillEntity)
|
||||
}
|
||||
}
|
||||
onReFetchSuccess(
|
||||
billDetailsResponse.isBillDetailsChanged.orFalse(),
|
||||
billDetailsEntity,
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
if (!billDetailsResponse.isSuccessWithData() && !payBillViewModel.isPayButtonClicked) {
|
||||
val error = payBillViewModel.getError(billDetailsResponse)
|
||||
|
||||
if (error.code in billAlreadyPaidErrorCodes) {
|
||||
payBillViewModel.notifyError(
|
||||
response = billDetailsResponse,
|
||||
cancelable = false,
|
||||
tag = TAG_BILL_ALREADY_PAID_ON_REFETCH,
|
||||
)
|
||||
myBillsSyncJob.refreshBillsAsync(screenName = screenName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun showBillError(
|
||||
payBillViewModel: PayBillViewModel,
|
||||
billResponse: RepoResult<BillDetailsResponse>,
|
||||
|
||||
@@ -24,7 +24,7 @@ import com.navi.bbps.feature.customerinput.model.view.BillerAdditionalParamsEnti
|
||||
import com.navi.bbps.feature.customerinput.model.view.BillerDetailsEntity
|
||||
import com.navi.bbps.feature.customerinput.model.view.CustomerParamsExtraData
|
||||
import com.navi.bbps.feature.destinations.CustomerDataInputScreenDestination
|
||||
import com.navi.bbps.feature.destinations.PayBillScreenV2Destination
|
||||
import com.navi.bbps.feature.destinations.PayBillScreenDestination
|
||||
import com.navi.bbps.feature.destinations.PrepaidRechargeScreenDestination
|
||||
import com.navi.bbps.feature.paybill.model.network.PaymentAmountExactness
|
||||
import com.navi.bbps.feature.paybill.model.view.PayBillSource
|
||||
@@ -112,7 +112,7 @@ constructor(
|
||||
getOthersPayBillSource(bundle)
|
||||
}
|
||||
|
||||
return PayBillScreenV2Destination(
|
||||
return PayBillScreenDestination(
|
||||
billCategoryEntity = billCategoryEntity,
|
||||
phoneNumberDetail = phoneContactEntity,
|
||||
payBillScreenSource = payBillSource,
|
||||
|
||||
@@ -36,6 +36,7 @@ constructor(
|
||||
myBillEntity.unpaidBillDetails?.billerAdditionalParams?.map {
|
||||
it.toBillerAdditionalParams()
|
||||
},
|
||||
isBillDetailsChanged = false,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ import com.navi.bbps.feature.contactlist.model.view.PhoneContactEntity
|
||||
import com.navi.bbps.feature.customerinput.model.view.BillerDetailsEntity
|
||||
import com.navi.bbps.feature.customerinput.model.view.CustomerParamsExtraData
|
||||
import com.navi.bbps.feature.destinations.CustomerDataInputScreenDestination
|
||||
import com.navi.bbps.feature.destinations.PayBillScreenV2Destination
|
||||
import com.navi.bbps.feature.destinations.PayBillScreenDestination
|
||||
import com.navi.bbps.feature.mybills.MyBillsSyncJob
|
||||
import com.navi.bbps.feature.mybills.model.view.MyBillEntity
|
||||
import com.navi.bbps.feature.paybill.model.view.PayBillSource
|
||||
@@ -419,7 +419,7 @@ constructor(
|
||||
)
|
||||
|
||||
val destination =
|
||||
PayBillScreenV2Destination(
|
||||
PayBillScreenDestination(
|
||||
billCategoryEntity = billCategoryEntity,
|
||||
payBillScreenSource = payBillSource,
|
||||
phoneNumberDetail = phoneNumberDetailEntity,
|
||||
|
||||
@@ -52,7 +52,7 @@ import com.navi.bbps.feature.customerinput.model.view.BillerDetailsEntity
|
||||
import com.navi.bbps.feature.customerinput.model.view.CustomerParamsExtraData
|
||||
import com.navi.bbps.feature.destinations.BbpsTransactionDetailsScreenDestination
|
||||
import com.navi.bbps.feature.destinations.CustomerDataInputScreenDestination
|
||||
import com.navi.bbps.feature.destinations.PayBillScreenV2Destination
|
||||
import com.navi.bbps.feature.destinations.PayBillScreenDestination
|
||||
import com.navi.bbps.feature.destinations.PrepaidRechargeScreenDestination
|
||||
import com.navi.bbps.feature.mybills.model.view.MyBillEntity
|
||||
import com.navi.bbps.feature.paybill.model.view.PayBillSource
|
||||
@@ -381,7 +381,7 @@ constructor(
|
||||
val source = NaviBbpsScreen.NAVI_BBPS_MY_BILL_HISTORY_DETAILS.name
|
||||
|
||||
val destination =
|
||||
PayBillScreenV2Destination(
|
||||
PayBillScreenDestination(
|
||||
billCategoryEntity = billCategoryEntity,
|
||||
payBillScreenSource = payBillSource,
|
||||
phoneNumberDetail = phoneNumberDetail,
|
||||
|
||||
@@ -29,6 +29,8 @@ import com.navi.bbps.common.BILLER_UNIQUE_ID
|
||||
import com.navi.bbps.common.BbpsSharedPreferences
|
||||
import com.navi.bbps.common.CATEGORY_ID_MOBILE_PREPAID
|
||||
import com.navi.bbps.common.CoinsSyncManager
|
||||
import com.navi.bbps.common.DATE_TIME_FORMAT_DATE_MONTH_NAME_YEAR
|
||||
import com.navi.bbps.common.DATE_TIME_FORMAT_DATE_MONTH_NAME_YEAR_INPUT
|
||||
import com.navi.bbps.common.DEFAULT_RETRY_COUNT
|
||||
import com.navi.bbps.common.LocalJsonDataSource
|
||||
import com.navi.bbps.common.NaviBbpsAnalytics
|
||||
@@ -48,6 +50,7 @@ import com.navi.bbps.common.utils.MyBillEntityToBillCategoryEntityMapper
|
||||
import com.navi.bbps.common.utils.MyBillEntityToBillerDetailsEntityMapper
|
||||
import com.navi.bbps.common.utils.NaviBbpsCommonUtils
|
||||
import com.navi.bbps.common.utils.NaviBbpsCommonUtils.getBbpsMetricInfo
|
||||
import com.navi.bbps.common.utils.NaviBbpsDateUtils
|
||||
import com.navi.bbps.common.utils.getDefaultConfig
|
||||
import com.navi.bbps.common.utils.getDisplayableAmount
|
||||
import com.navi.bbps.common.utils.refresh
|
||||
@@ -72,7 +75,7 @@ import com.navi.bbps.feature.customerinput.model.view.BillerDetailsEntity
|
||||
import com.navi.bbps.feature.customerinput.model.view.CustomerParamsExtraData
|
||||
import com.navi.bbps.feature.destinations.CustomerDataInputScreenDestination
|
||||
import com.navi.bbps.feature.destinations.MyBillHistoryDetailsScreenDestination
|
||||
import com.navi.bbps.feature.destinations.PayBillScreenV2Destination
|
||||
import com.navi.bbps.feature.destinations.PayBillScreenDestination
|
||||
import com.navi.bbps.feature.destinations.PrepaidRechargeScreenDestination
|
||||
import com.navi.bbps.feature.mybills.MyBillsRepository
|
||||
import com.navi.bbps.feature.mybills.MyBillsSyncJob
|
||||
@@ -137,6 +140,7 @@ constructor(
|
||||
val naviNetworkConnectivity: NaviNetworkConnectivity,
|
||||
private val bbpsCommonRepository: BbpsCommonRepository,
|
||||
private val resourceProvider: ResourceProvider,
|
||||
private val naviBbpsDateUtils: NaviBbpsDateUtils,
|
||||
val uploadUserDataUseCase: UploadUserDataUseCase,
|
||||
@NaviBbpsGsonBuilder private val naviBbpsGson: Gson,
|
||||
open val bbpsSharedPreferences: BbpsSharedPreferences,
|
||||
@@ -308,14 +312,29 @@ constructor(
|
||||
billerId = billerDetails.billerId,
|
||||
referenceId = myBillEntity.unpaidBillDetails?.referenceId.orEmpty(),
|
||||
amount = myBillEntity.unpaidBillDetails?.amount,
|
||||
billDate = myBillEntity.unpaidBillDetails?.billDate,
|
||||
dueDate = myBillEntity.unpaidBillDetails?.dueDate,
|
||||
billDate =
|
||||
naviBbpsDateUtils
|
||||
.getFormattedDate(
|
||||
dateTime = myBillEntity.unpaidBillDetails?.billDate,
|
||||
inputDateFormat = DATE_TIME_FORMAT_DATE_MONTH_NAME_YEAR,
|
||||
outputDateFormat = DATE_TIME_FORMAT_DATE_MONTH_NAME_YEAR_INPUT,
|
||||
)
|
||||
.orEmpty(),
|
||||
dueDate =
|
||||
naviBbpsDateUtils
|
||||
.getFormattedDate(
|
||||
dateTime = myBillEntity.unpaidBillDetails?.dueDate,
|
||||
inputDateFormat = DATE_TIME_FORMAT_DATE_MONTH_NAME_YEAR,
|
||||
outputDateFormat = DATE_TIME_FORMAT_DATE_MONTH_NAME_YEAR_INPUT,
|
||||
)
|
||||
.orEmpty(),
|
||||
billNumber = myBillEntity.unpaidBillDetails?.billNumber,
|
||||
accountHolderName = myBillEntity.unpaidBillDetails?.accountHolderName,
|
||||
billerAdditionalParams =
|
||||
myBillEntity.unpaidBillDetails?.billerAdditionalParams?.map {
|
||||
it.toBillerAdditionalParams()
|
||||
},
|
||||
isBillDetailsChanged = false,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -427,7 +446,7 @@ constructor(
|
||||
val source = NaviBbpsScreen.NAVI_BBPS_BILL_CATEGORIES.name
|
||||
|
||||
_navigateToNextScreen.emit(
|
||||
PayBillScreenV2Destination(
|
||||
PayBillScreenDestination(
|
||||
billCategoryEntity = billCategoryEntity,
|
||||
payBillScreenSource = payBillSource,
|
||||
phoneNumberDetail = phoneNumberDetail,
|
||||
@@ -437,6 +456,7 @@ constructor(
|
||||
)
|
||||
)
|
||||
} else {
|
||||
|
||||
val billCategoryEntity =
|
||||
myBillEntityToBillCategoryEntityMapper.mapMyBillEntityToBillCategoryEntity(
|
||||
myBillEntity
|
||||
@@ -470,7 +490,7 @@ constructor(
|
||||
val source = NaviBbpsScreen.NAVI_BBPS_BILL_CATEGORIES.name
|
||||
|
||||
_navigateToNextScreen.emit(
|
||||
PayBillScreenV2Destination(
|
||||
PayBillScreenDestination(
|
||||
billCategoryEntity = billCategoryEntity,
|
||||
payBillScreenSource = payBillSource,
|
||||
phoneNumberDetail = phoneNumberDetail,
|
||||
|
||||
@@ -38,6 +38,7 @@ import com.navi.bbps.common.utils.BillDetailsResponseToEntityMapper
|
||||
import com.navi.bbps.common.utils.MyBillEntityToBillCategoryEntityMapper
|
||||
import com.navi.bbps.common.utils.MyBillEntityToBillerDetailsEntityMapper
|
||||
import com.navi.bbps.common.utils.NaviBbpsCommonUtils.getBbpsMetricInfo
|
||||
import com.navi.bbps.common.utils.NaviBbpsDateUtils
|
||||
import com.navi.bbps.common.utils.OriginSessionAttributes
|
||||
import com.navi.bbps.common.utils.OriginWidgetStatus
|
||||
import com.navi.bbps.common.viewmodel.OriginBillDetectionHandler
|
||||
@@ -86,6 +87,7 @@ constructor(
|
||||
naviBbpsSessionHelper: NaviBbpsSessionHelper,
|
||||
coinsSyncManager: CoinsSyncManager,
|
||||
naviBbpsConfigUseCase: NaviBbpsConfigUseCase,
|
||||
naviBbpsDateUtils: NaviBbpsDateUtils,
|
||||
resProvider: ResourceProvider,
|
||||
bbpsCommonRepository: BbpsCommonRepository,
|
||||
naviNetworkConnectivity: NaviNetworkConnectivity,
|
||||
@@ -118,6 +120,7 @@ constructor(
|
||||
resourceProvider = resourceProvider,
|
||||
uploadUserDataUseCase = uploadUserDataUseCase,
|
||||
bbpsSharedPreferences = bbpsSharedPreferences,
|
||||
naviBbpsDateUtils = naviBbpsDateUtils,
|
||||
),
|
||||
BottomSheetController by BottomSheetControllerImpl() {
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ import com.navi.bbps.feature.contactlist.model.view.PhoneContactEntity
|
||||
import com.navi.bbps.feature.customerinput.model.network.BillDetailsRequest
|
||||
import com.navi.bbps.feature.customerinput.model.network.DeviceDetails
|
||||
import com.navi.bbps.feature.customerinput.model.view.BillerDetailsEntity
|
||||
import com.navi.bbps.feature.destinations.PayBillScreenV2Destination
|
||||
import com.navi.bbps.feature.destinations.PayBillScreenDestination
|
||||
import com.navi.bbps.feature.destinations.PrepaidRechargeScreenDestination
|
||||
import com.navi.bbps.feature.mybills.MyBillsSyncJob
|
||||
import com.navi.bbps.feature.mybills.model.view.MyBillEntity
|
||||
@@ -423,7 +423,7 @@ constructor(
|
||||
_showPostpaidBottomSheet.emit(false)
|
||||
|
||||
_navigateToNextScreen.emit(
|
||||
PayBillScreenV2Destination(
|
||||
PayBillScreenDestination(
|
||||
billCategoryEntity = billCategory,
|
||||
payBillScreenSource = payBillScreenSource,
|
||||
phoneNumberDetail = phoneNumberDetailEntity,
|
||||
@@ -596,7 +596,7 @@ constructor(
|
||||
val screenSource = NaviBbpsScreen.NAVI_BBPS_CONTACT_LIST_SCREEN.name
|
||||
|
||||
_navigateToNextScreen.emit(
|
||||
PayBillScreenV2Destination(
|
||||
PayBillScreenDestination(
|
||||
billCategoryEntity = billCategory,
|
||||
payBillScreenSource = payBillSource,
|
||||
phoneNumberDetail = phoneNumber,
|
||||
|
||||
@@ -52,7 +52,7 @@ import com.navi.bbps.feature.customerinput.model.view.CustomerInputScreenState
|
||||
import com.navi.bbps.feature.customerinput.model.view.CustomerParam
|
||||
import com.navi.bbps.feature.customerinput.model.view.CustomerParamValueState
|
||||
import com.navi.bbps.feature.customerinput.model.view.CustomerParamsExtraData
|
||||
import com.navi.bbps.feature.destinations.PayBillScreenV2Destination
|
||||
import com.navi.bbps.feature.destinations.PayBillScreenDestination
|
||||
import com.navi.bbps.feature.detectedbills.DetectedBillsRepository
|
||||
import com.navi.bbps.feature.detectedbills.model.view.DetectedBillCustomerInputResult
|
||||
import com.navi.bbps.feature.mybills.MyBillsRepository
|
||||
@@ -572,7 +572,7 @@ constructor(
|
||||
PhoneContactEntity(name = "", phoneNumber = "", normalisedPhoneNumber = "")
|
||||
|
||||
_navigateToNextScreen.emit(
|
||||
PayBillScreenV2Destination(
|
||||
PayBillScreenDestination(
|
||||
billCategoryEntity = billCategoryEntity,
|
||||
payBillScreenSource = payBillScreenSource,
|
||||
phoneNumberDetail = phoneNumberDetail,
|
||||
|
||||
@@ -12,6 +12,7 @@ import com.google.gson.annotations.SerializedName
|
||||
data class BillDetailsRequest(
|
||||
@SerializedName("billerId") val billerId: String,
|
||||
@SerializedName("customerParams") val customerParams: Map<String, String>,
|
||||
@SerializedName("referenceId") val referenceId: String? = null,
|
||||
@SerializedName("deviceDetails") val deviceDetails: DeviceDetails,
|
||||
@SerializedName("amount") val amount: String? = null,
|
||||
@SerializedName("isConsentProvided") val isConsentProvided: Boolean,
|
||||
|
||||
@@ -8,16 +8,19 @@
|
||||
package com.navi.bbps.feature.customerinput.model.network
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import org.joda.time.DateTime
|
||||
|
||||
data class BillDetailsResponse(
|
||||
@SerializedName("billId") val billId: String?,
|
||||
@SerializedName("billerId") val billerId: String,
|
||||
@SerializedName("isBillDetailsChanged") val isBillDetailsChanged: Boolean,
|
||||
@SerializedName("referenceId") val referenceId: String,
|
||||
@SerializedName("amount") val amount: String?,
|
||||
@SerializedName("billDate") val billDate: String?,
|
||||
@SerializedName("dueDate") val dueDate: String?,
|
||||
@SerializedName("billNumber") val billNumber: String?,
|
||||
@SerializedName("accountHolderName") val accountHolderName: String?,
|
||||
@SerializedName("apiCallTimestamp") val apiCallTimestamp: DateTime? = null,
|
||||
@SerializedName("billerAdditionalParams")
|
||||
val billerAdditionalParams: List<BillerAdditionalParams>?,
|
||||
)
|
||||
|
||||
@@ -10,6 +10,7 @@ package com.navi.bbps.feature.mybills
|
||||
import com.navi.bbps.feature.mybills.db.MyBillsDao
|
||||
import com.navi.bbps.feature.mybills.model.network.BillMarkAsPaidResponse
|
||||
import com.navi.bbps.feature.mybills.model.network.MyBillsResponse
|
||||
import com.navi.bbps.feature.mybills.model.view.MyBillEntity
|
||||
import com.navi.bbps.network.service.NaviBbpsRetrofitService
|
||||
import com.navi.common.checkmate.model.MetricInfo
|
||||
import com.navi.common.network.models.RepoResult
|
||||
@@ -33,6 +34,10 @@ constructor(
|
||||
|
||||
fun fetchMySavedBills() = myBillsDao.getAllBills()
|
||||
|
||||
suspend fun updateSavedBill(myBillEntity: MyBillEntity) {
|
||||
myBillsDao.updateSavedBill(myBillEntity = myBillEntity)
|
||||
}
|
||||
|
||||
suspend fun fetchSavedBillsByCategory(category: String) =
|
||||
myBillsDao.getBillsByCategory(categoryId = category)
|
||||
|
||||
|
||||
@@ -81,6 +81,8 @@ constructor(
|
||||
it.unpaidBillDetails?.billerAdditionalParams?.map {
|
||||
it.toBillerAdditionalParamsEntity()
|
||||
} ?: emptyList(),
|
||||
lastGeneratedTimestamp =
|
||||
it.unpaidBillDetails?.lastGeneratedTimestamp?.millis.toString(),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ constructor(
|
||||
) {
|
||||
private var syncJob: Job? = null
|
||||
|
||||
suspend fun refreshBills(screenName: String) {
|
||||
suspend fun refreshBills(screenName: String, onSavedBillRefresh: (suspend () -> Unit)? = null) {
|
||||
val response =
|
||||
myBillsRepository.fetchBillsFromNetwork(
|
||||
metricInfo = getBbpsMetricInfo(screenName = screenName, isNae = { false })
|
||||
@@ -41,9 +41,13 @@ constructor(
|
||||
myBillsDao.refresh(myBills)
|
||||
}
|
||||
}
|
||||
onSavedBillRefresh?.invoke()
|
||||
}
|
||||
|
||||
fun refreshBillsAsync(screenName: String): Job? {
|
||||
fun refreshBillsAsync(
|
||||
screenName: String,
|
||||
onSavedBillRefresh: (suspend () -> Unit)? = null,
|
||||
): Job? {
|
||||
if (syncJob?.isActive == true) {
|
||||
try {
|
||||
syncJob?.cancel()
|
||||
@@ -53,7 +57,9 @@ constructor(
|
||||
}
|
||||
}
|
||||
syncJob =
|
||||
CoroutineScope(dispatcherProvider.io).launch { refreshBills(screenName = screenName) }
|
||||
CoroutineScope(dispatcherProvider.io).launch {
|
||||
refreshBills(screenName = screenName, onSavedBillRefresh = onSavedBillRefresh)
|
||||
}
|
||||
return syncJob
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ import com.navi.bbps.feature.customerinput.model.view.BillerDetailsEntity
|
||||
import com.navi.bbps.feature.customerinput.model.view.CustomerParamsExtraData
|
||||
import com.navi.bbps.feature.destinations.CustomerDataInputScreenDestination
|
||||
import com.navi.bbps.feature.destinations.MyBillHistoryDetailsScreenDestination
|
||||
import com.navi.bbps.feature.destinations.PayBillScreenV2Destination
|
||||
import com.navi.bbps.feature.destinations.PayBillScreenDestination
|
||||
import com.navi.bbps.feature.destinations.PrepaidRechargeScreenDestination
|
||||
import com.navi.bbps.feature.detectedbills.DetectedBillsRepository
|
||||
import com.navi.bbps.feature.detectedbills.model.view.NewAddedBills
|
||||
@@ -547,7 +547,7 @@ constructor(
|
||||
val source = NaviBbpsScreen.NAVI_BBPS_MY_SAVED_BILLS.name
|
||||
|
||||
_navigateToNextScreen.emit(
|
||||
PayBillScreenV2Destination(
|
||||
PayBillScreenDestination(
|
||||
billCategoryEntity = billCategoryEntity,
|
||||
payBillScreenSource = payBillScreenSource,
|
||||
phoneNumberDetail = phoneNumberDetail,
|
||||
@@ -625,7 +625,7 @@ constructor(
|
||||
val source = NaviBbpsScreen.NAVI_BBPS_MY_SAVED_BILLS.name
|
||||
|
||||
_navigateToNextScreen.emit(
|
||||
PayBillScreenV2Destination(
|
||||
PayBillScreenDestination(
|
||||
billCategoryEntity = billCategoryEntity,
|
||||
payBillScreenSource = payBillScreenSource,
|
||||
phoneNumberDetail = phoneNumberDetail,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright © 2024 by Navi Technologies Limited
|
||||
* * Copyright © 2024-2025 by Navi Technologies Limited
|
||||
* * All rights reserved. Strictly confidential
|
||||
*
|
||||
*/
|
||||
@@ -13,6 +13,7 @@ import androidx.room.OnConflictStrategy
|
||||
import androidx.room.Query
|
||||
import androidx.room.RawQuery
|
||||
import androidx.room.Transaction
|
||||
import androidx.room.Update
|
||||
import androidx.sqlite.db.SupportSQLiteQuery
|
||||
import com.navi.bbps.db.NaviBbpsAppDatabase.Companion.NAVI_BBPS_TABLE_MY_SAVED_BILLS
|
||||
import com.navi.bbps.feature.mybills.model.view.MyBillEntity
|
||||
@@ -26,6 +27,8 @@ interface MyBillsDao {
|
||||
@Query("SELECT * FROM $NAVI_BBPS_TABLE_MY_SAVED_BILLS WHERE categoryId == :categoryId")
|
||||
suspend fun getBillsByCategory(categoryId: String): List<MyBillEntity>
|
||||
|
||||
@Update suspend fun updateSavedBill(myBillEntity: MyBillEntity)
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
suspend fun insertAll(myBills: List<MyBillEntity>)
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ package com.navi.bbps.feature.mybills.model.network
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import com.navi.bbps.feature.customerinput.model.network.BillerAdditionalParams
|
||||
import org.joda.time.DateTime
|
||||
|
||||
data class MyBillsResponse(@SerializedName("bills") val bills: List<SavedBillItem>?)
|
||||
|
||||
@@ -45,6 +46,7 @@ data class UnpaidBillDetailsResponse(
|
||||
@SerializedName("billNumber") val billNumber: String?,
|
||||
@SerializedName("accountHolderName") val accountHolderName: String?,
|
||||
@SerializedName("planItemDetails") val planItemDetails: Map<String, String>?,
|
||||
@SerializedName("lastGeneratedTimestamp") val lastGeneratedTimestamp: DateTime?,
|
||||
@SerializedName("billerAdditionalParams")
|
||||
val billerAdditionalParams: List<BillerAdditionalParams>?,
|
||||
)
|
||||
|
||||
@@ -63,4 +63,5 @@ data class UnpaidBillDetails(
|
||||
val accountHolderName: String,
|
||||
val billerAdditionalParams: List<BillerAdditionalParamsEntity>,
|
||||
val planItemDetails: Map<String, String>,
|
||||
val lastGeneratedTimestamp: String,
|
||||
) : Parcelable
|
||||
|
||||
@@ -12,9 +12,11 @@ import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.navi.adverse.flux.provider.GsonProvider.gson
|
||||
import com.navi.base.cache.repository.NaviCacheRepository
|
||||
import com.navi.base.model.CtaData
|
||||
import com.navi.base.utils.EMPTY
|
||||
import com.navi.base.utils.NaviNetworkConnectivity
|
||||
import com.navi.base.utils.ResourceProvider
|
||||
import com.navi.base.utils.TrustedTimeAccessor
|
||||
import com.navi.base.utils.ZERO_STRING
|
||||
import com.navi.base.utils.isNotNull
|
||||
import com.navi.base.utils.orFalse
|
||||
@@ -40,8 +42,10 @@ import com.navi.bbps.common.model.config.NaviBbpsDefaultConfig
|
||||
import com.navi.bbps.common.model.view.NaviBbpsSessionHelper
|
||||
import com.navi.bbps.common.repository.BbpsCommonRepository
|
||||
import com.navi.bbps.common.usecase.FetchBillHandler
|
||||
import com.navi.bbps.common.usecase.GetABTestingExperimentUseCase
|
||||
import com.navi.bbps.common.usecase.NaviBbpsConfigUseCase
|
||||
import com.navi.bbps.common.usecase.RewardNudgeUseCase
|
||||
import com.navi.bbps.common.utils.NaviBbpsCommonUtils
|
||||
import com.navi.bbps.common.utils.NaviBbpsCommonUtils.evaluateMvelExpression
|
||||
import com.navi.bbps.common.utils.NaviBbpsCommonUtils.getBbpsMetricInfo
|
||||
import com.navi.bbps.common.utils.NaviBbpsCommonUtils.getValidatedAmountNumber
|
||||
@@ -74,16 +78,21 @@ import com.navi.bbps.feature.paybill.model.network.PayBillResponse
|
||||
import com.navi.bbps.feature.paybill.model.network.PaymentAmountExactness
|
||||
import com.navi.bbps.feature.paybill.model.view.AmountChipEntity
|
||||
import com.navi.bbps.feature.paybill.model.view.CoinUtilisationProperties
|
||||
import com.navi.bbps.feature.paybill.model.view.CoinUtilisationPropertiesV2
|
||||
import com.navi.bbps.feature.paybill.model.view.CreditCardAmountType
|
||||
import com.navi.bbps.feature.paybill.model.view.CreditCardPaymentOption
|
||||
import com.navi.bbps.feature.paybill.model.view.PayBillBottomSheetType
|
||||
import com.navi.bbps.feature.paybill.model.view.PayBillHeaderState
|
||||
import com.navi.bbps.feature.paybill.model.view.PayBillScreenState
|
||||
import com.navi.bbps.feature.paybill.model.view.PayBillSource
|
||||
import com.navi.bbps.feature.paybill.util.getBillOrderModel
|
||||
import com.navi.bbps.feature.prepaidrecharge.model.view.OperatorItemEntity
|
||||
import com.navi.bbps.feature.prepaidrecharge.model.view.PlanItemEntity
|
||||
import com.navi.common.R as CommonR
|
||||
import com.navi.common.constants.DBCacheConstants.ARC_NUDGE_RESPONSE_CACHE_KEY
|
||||
import com.navi.common.di.CoroutineDispatcherProvider
|
||||
import com.navi.common.firebaseremoteconfig.FirebaseRemoteConfigHelper
|
||||
import com.navi.common.firebaseremoteconfig.FirebaseRemoteConfigHelper.NAVI_BBPS_BILL_REFRESH_DURATION
|
||||
import com.navi.common.model.common.NudgeDetailEntity
|
||||
import com.navi.common.network.models.RepoResult
|
||||
import com.navi.common.network.models.isSuccessWithData
|
||||
@@ -95,6 +104,7 @@ import com.navi.common.utils.Constants
|
||||
import com.navi.common.utils.Constants.LITMUS_EXPERIMENT_NAVIPAY_NAVI_POWER_PLAY
|
||||
import com.navi.common.utils.TemporaryStorageHelper
|
||||
import com.navi.common.utils.toJsonObject
|
||||
import com.navi.payment.nativepayment.utils.NaviPaymentRewardsEventBus
|
||||
import com.navi.payment.nativepayment.utils.getDiscountAdjustedAmount
|
||||
import com.navi.payment.paymentscreen.utils.PaymentNavigator
|
||||
import com.navi.payment.tstore.repository.TStoreOrderHandler
|
||||
@@ -104,17 +114,20 @@ import com.ramcosta.composedestinations.spec.Direction
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.delay
|
||||
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.collectLatest
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.json.JSONObject
|
||||
|
||||
@HiltViewModel
|
||||
@@ -126,6 +139,7 @@ constructor(
|
||||
private val payBillRepository: PayBillRepository,
|
||||
private val naviBbpsDateUtils: NaviBbpsDateUtils,
|
||||
private val naviBbpsConfigUseCase: NaviBbpsConfigUseCase,
|
||||
private val getABTestingExperimentUseCase: GetABTestingExperimentUseCase,
|
||||
private val myBillsRepository: MyBillsRepository,
|
||||
private val tStoreOrderHandler: TStoreOrderHandler,
|
||||
private val naviNetworkConnectivity: NaviNetworkConnectivity,
|
||||
@@ -135,6 +149,7 @@ constructor(
|
||||
private val billCategoriesRepository: BillCategoriesRepository,
|
||||
private val resProvider: ResourceProvider,
|
||||
private val rewardsNudgeEntityFetchUseCase: RewardNudgeUseCase,
|
||||
private val naviPaymentRewardEventBus: NaviPaymentRewardsEventBus,
|
||||
private val naviCacheRepository: NaviCacheRepository,
|
||||
private val naviBbpsCommonRepository: BbpsCommonRepository,
|
||||
private val resourceProvider: ResourceProvider,
|
||||
@@ -166,7 +181,7 @@ constructor(
|
||||
private val _initialPaymentAmount = MutableStateFlow("")
|
||||
val initialPaymentAmount = _initialPaymentAmount.asStateFlow()
|
||||
|
||||
internal val _paymentAmount = MutableStateFlow("")
|
||||
private val _paymentAmount = MutableStateFlow("")
|
||||
val paymentAmount = _paymentAmount.asStateFlow()
|
||||
|
||||
private val _showErrorText = MutableStateFlow(false)
|
||||
@@ -191,6 +206,10 @@ constructor(
|
||||
MutableStateFlow<PayBillScreenState>(PayBillScreenState.BillDetailsUnavailable)
|
||||
val payBillScreenState = _payBillScreenState.asStateFlow()
|
||||
|
||||
open val _payBillBottomSheetType =
|
||||
MutableStateFlow<PayBillBottomSheetType>(PayBillBottomSheetType.None)
|
||||
val payBillBottomSheetType = _payBillBottomSheetType.asStateFlow()
|
||||
|
||||
private val _rewardsNudgeDetailEntity = MutableStateFlow<NudgeDetailEntity?>(null)
|
||||
val rewardsNudgeDetailEntity = _rewardsNudgeDetailEntity.asStateFlow()
|
||||
|
||||
@@ -252,6 +271,11 @@ constructor(
|
||||
|
||||
private val amountChips = MutableStateFlow(emptyList<String>())
|
||||
|
||||
private val _showBillDetailsUpdatedBottomSheet = MutableSharedFlow<Boolean>()
|
||||
val showBillDetailsUpdatedBottomSheet = _showBillDetailsUpdatedBottomSheet.asSharedFlow()
|
||||
|
||||
var isPayButtonClicked = false
|
||||
|
||||
var arcNudgeResponse: ArcNudgeResponse? = null
|
||||
|
||||
@Inject lateinit var paymentNavigator: PaymentNavigator
|
||||
@@ -272,6 +296,25 @@ constructor(
|
||||
|
||||
var isIPLPowerPlayThemeExperimentEnabled = false
|
||||
|
||||
var updatedBillDetailsEntity: BillDetailsEntity? = null
|
||||
|
||||
private val _navigateToNextScreenFromHelpCta = MutableSharedFlow<CtaData?>()
|
||||
val navigateToNextScreenFromHelpCta = _navigateToNextScreenFromHelpCta.asSharedFlow()
|
||||
|
||||
val helpCta = NaviBbpsCommonUtils.getHelpCtaData(NaviBbpsScreen.NAVI_BBPS_PAY_BILL_SCREEN.name)
|
||||
|
||||
private val _coinsUtilisationPropertiesV2 = MutableStateFlow<CoinUtilisationPropertiesV2?>(null)
|
||||
val coinUtilisationPropertiesV2 = _coinsUtilisationPropertiesV2.asStateFlow()
|
||||
|
||||
private val _amountAfterCoinDiscount = MutableStateFlow(ZERO_STRING)
|
||||
val amountAfterCoinDiscount = _amountAfterCoinDiscount.asStateFlow()
|
||||
|
||||
private val _isCoinDiscountApplied = MutableStateFlow(false)
|
||||
val isCoinDiscountApplied = _isCoinDiscountApplied.asStateFlow()
|
||||
|
||||
private val _isLottieAnimationShown = MutableStateFlow(false)
|
||||
val isLottieAnimationShown = _isLottieAnimationShown.asStateFlow()
|
||||
|
||||
init {
|
||||
viewModelScope.launch(dispatcherProvider.io) {
|
||||
// Concurrent calls section
|
||||
@@ -281,6 +324,7 @@ constructor(
|
||||
launch { fetchBillAndUpdateScreen() }
|
||||
launch { updateScreenState() }
|
||||
launch { updateBottomRewardsNudgeEntity() }
|
||||
launch { pmsDiscountListener() }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -437,48 +481,81 @@ constructor(
|
||||
)
|
||||
updateIsBillLoading(isLoading = false)
|
||||
} else {
|
||||
fetchMatchingBillAndUpdateEntity()
|
||||
updateBillDetails()
|
||||
myBillEntity.value?.unpaidBillDetails.let { unpaidBillDetails ->
|
||||
if (
|
||||
TrustedTimeAccessor.getCurrentTimeMillis() -
|
||||
unpaidBillDetails?.lastGeneratedTimestamp?.toLongOrNull().orZero() >
|
||||
FirebaseRemoteConfigHelper.getLong(
|
||||
key = NAVI_BBPS_BILL_REFRESH_DURATION,
|
||||
defaultValue = 10000L,
|
||||
)
|
||||
) {
|
||||
refetchBillDetails()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun fetchMatchingBillAndUpdateEntity() {
|
||||
viewModelScope.launch(dispatcherProvider.io) {
|
||||
val savedBill = findMatchingSavedBill()
|
||||
private suspend fun refetchBillDetails() {
|
||||
fetchBillHandler.refetchBill(
|
||||
payBillViewModel = this,
|
||||
onReFetchSuccess = { isBillDetailsChanged, billDetailsEntity ->
|
||||
if (!isPayButtonClicked && isBillDetailsChanged) {
|
||||
updatedBillDetailsEntity = billDetailsEntity
|
||||
_payBillBottomSheetType.update {
|
||||
PayBillBottomSheetType.BillDetailsUpdateInfo(
|
||||
title =
|
||||
naviBbpsDefaultConfig.value.configMessage.billDetailsUpdatedTitle,
|
||||
description =
|
||||
naviBbpsDefaultConfig.value.configMessage
|
||||
.billDetailsUpdatedDescription,
|
||||
)
|
||||
}
|
||||
_showBillDetailsUpdatedBottomSheet.emit(true)
|
||||
}
|
||||
},
|
||||
screenName = naviBbpsVmData.screen.screenName,
|
||||
billAlreadyPaidErrorCodes = naviBbpsDefaultConfig.value.billAlreadyPaidErrorCodes,
|
||||
)
|
||||
}
|
||||
|
||||
updateMyBillEntity(myBillEntity = savedBill)
|
||||
}
|
||||
fun updateLatestBillDetails() {
|
||||
_billDetailsEntity.update { updatedBillDetailsEntity }
|
||||
updateBillDetails()
|
||||
}
|
||||
|
||||
private suspend fun fetchMatchingBillAndUpdateEntity() {
|
||||
val savedBill = findMatchingSavedBill()
|
||||
updateMyBillEntity(myBillEntity = savedBill)
|
||||
}
|
||||
|
||||
private fun updateBillDetails() {
|
||||
if (payBillScreenSource is PayBillSource.Others) {
|
||||
fetchMatchingBillAndUpdateEntity()
|
||||
billDetailsEntity.value?.let { updateBillAndAmountValues(billDetailsEntity = it) }
|
||||
billDetailsEntity.value?.let { updateBillAndAmountValues(billDetailsEntity = it) }
|
||||
|
||||
billDetailsEntity.value?.let {
|
||||
fetchAndUpdateBillerAdditionalParams(billerAdditionalParams = it.billerAdditionalParams)
|
||||
}
|
||||
if (billCategoryEntity?.categoryId == CATEGORY_ID_CREDIT_CARD) {
|
||||
billDetailsEntity.value?.let {
|
||||
fetchAndUpdateBillerAdditionalParams(
|
||||
billerAdditionalParams = it.billerAdditionalParams
|
||||
)
|
||||
}
|
||||
if (billCategoryEntity?.categoryId == CATEGORY_ID_CREDIT_CARD) {
|
||||
billDetailsEntity.value?.let {
|
||||
updateCreditCardPaymentOptions(billDetailsEntity = it)
|
||||
viewModelScope.launch(dispatcherProvider.main) {
|
||||
onCreditCardPaymentOptionSelected(
|
||||
creditCardPaymentOption = creditCardPaymentOptions.first()
|
||||
)
|
||||
}
|
||||
updateCreditCardPaymentOptions(billDetailsEntity = it)
|
||||
viewModelScope.launch(dispatcherProvider.main) {
|
||||
onCreditCardPaymentOptionSelected(
|
||||
creditCardPaymentOption = creditCardPaymentOptions.first()
|
||||
)
|
||||
}
|
||||
}
|
||||
if (
|
||||
!isCategoryOfTypeAmountChipsRequired(
|
||||
categoryId = billCategoryEntity?.categoryId.orEmpty()
|
||||
)
|
||||
) {
|
||||
updateShouldAutoFocusOnAmount(paymentAmount = paymentAmount.value)
|
||||
return
|
||||
}
|
||||
updateAmountChips(chipsConfigData = naviBbpsDefaultConfig.value.chipsConfigData)
|
||||
}
|
||||
if (
|
||||
!isCategoryOfTypeAmountChipsRequired(
|
||||
categoryId = billCategoryEntity?.categoryId.orEmpty()
|
||||
)
|
||||
) {
|
||||
updateShouldAutoFocusOnAmount(paymentAmount = paymentAmount.value)
|
||||
return
|
||||
}
|
||||
updateAmountChips(chipsConfigData = naviBbpsDefaultConfig.value.chipsConfigData)
|
||||
}
|
||||
|
||||
private fun updateAmountChips(chipsConfigData: ChipsConfigData) {
|
||||
@@ -763,6 +840,10 @@ constructor(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isCategoryOfTypeAmountChipsRequired(billCategoryEntity?.categoryId.orEmpty())) {
|
||||
updateAmountChipEntity(amount = newAmountValue)
|
||||
}
|
||||
}
|
||||
|
||||
internal val isPayButtonEnabled =
|
||||
@@ -807,11 +888,197 @@ constructor(
|
||||
}
|
||||
}
|
||||
|
||||
fun getApplicableDiscount() {
|
||||
if (coinBurnData.value?.expression.isNullOrEmpty()) return
|
||||
handleDiscountProperties(
|
||||
discountExpression = coinBurnData.value?.expression.toString(),
|
||||
cashEquivalentOfDiscount = coinBurnData.value?.cashEquivalentOfDiscount,
|
||||
coinValue = coinBurnData.value?.config?.coins.toString(),
|
||||
)
|
||||
}
|
||||
|
||||
private fun handleDiscountProperties(
|
||||
discountExpression: String,
|
||||
cashEquivalentOfDiscount: Int?,
|
||||
coinValue: String,
|
||||
) {
|
||||
if (discountExpression.isNotNullAndNotEmpty()) {
|
||||
val discountAmount = runBlocking {
|
||||
calculateDiscountedAmountFromFormula(
|
||||
discountedFormula = discountExpression,
|
||||
cashEquivalentOfDiscount = cashEquivalentOfDiscount.toString(),
|
||||
)
|
||||
}
|
||||
val coinsUsed = (discountAmount.toInt() * (coinValue.toInt())).toString()
|
||||
val discountInfoText =
|
||||
resProvider.getString(
|
||||
R.string.bbps_save_rupee_symbol_amount,
|
||||
discountAmount.getDisplayableAmount(),
|
||||
)
|
||||
val discountInfoTextAfterDiscount =
|
||||
resProvider.getString(
|
||||
R.string.bbps_saved_rupee_symbol_amount,
|
||||
discountAmount.getDisplayableAmount(),
|
||||
)
|
||||
updateCoinsUtilisationProperties(
|
||||
CoinUtilisationPropertiesV2(
|
||||
discountAmount = discountAmount,
|
||||
coinUtilisationText = discountInfoText,
|
||||
coinUsedForDiscount = coinsUsed.getDisplayableAmount(),
|
||||
discountAmountTextAfterDiscount = discountInfoTextAfterDiscount,
|
||||
)
|
||||
)
|
||||
} else return
|
||||
}
|
||||
|
||||
private suspend fun calculateDiscountedAmountFromFormula(
|
||||
discountedFormula: String,
|
||||
cashEquivalentOfDiscount: String? = null,
|
||||
): String {
|
||||
return evaluateMvelExpression(
|
||||
key = discountedFormula,
|
||||
data =
|
||||
mapOf(
|
||||
"cashEquivalentOfDiscount" to
|
||||
(cashEquivalentOfDiscount
|
||||
?: coinsSyncManager.getCashEquivalentOfDiscount().toDoubleOrNull()
|
||||
?: 0.0),
|
||||
"billAmount" to (paymentAmount.value.toDoubleOrNull() ?: 0.0),
|
||||
),
|
||||
ZERO_STRING,
|
||||
)
|
||||
}
|
||||
|
||||
private fun updateCoinsUtilisationProperties(
|
||||
coinUtilisationPropertiesV2: CoinUtilisationPropertiesV2
|
||||
) {
|
||||
_coinsUtilisationPropertiesV2.update { coinUtilisationPropertiesV2 }
|
||||
}
|
||||
|
||||
fun onMoreClicked() {
|
||||
val description =
|
||||
when (payBillScreenSource) {
|
||||
is PayBillSource.Prepaid -> {
|
||||
payBillScreenSource.planItemEntity.packageDescription
|
||||
}
|
||||
else -> EMPTY
|
||||
}
|
||||
_payBillBottomSheetType.update {
|
||||
PayBillBottomSheetType.PlanDetails(
|
||||
title = resProvider.getString(R.string.bbps_plan_details),
|
||||
description = description,
|
||||
icon = CommonR.drawable.ic_purple_exclamation,
|
||||
ctaText = resProvider.getString(R.string.bbps_okay_got_it),
|
||||
amount = paymentAmount.value.getDisplayableAmount(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun enteredAmountInputChanged(
|
||||
newInput: String,
|
||||
isAmountChangedByChipSelection: Boolean = false,
|
||||
) {
|
||||
viewModelScope.launch(dispatcherProvider.io) {
|
||||
var newAmount = ""
|
||||
if (newInput.isNotEmpty() && newInput != ZERO_STRING) {
|
||||
newAmount =
|
||||
getValidatedAmountNumber(
|
||||
text = newInput,
|
||||
amountMaxLengthAfterDecimal = AMOUNT_MAX_LENGTH_AFTER_DECIMAL,
|
||||
amountMaxLengthBeforeDecimal = AMOUNT_MAX_LENGTH_BEFORE_DECIMAL,
|
||||
)
|
||||
|
||||
if (isAmountChangedByChipSelection) {
|
||||
newAmount = newInput
|
||||
}
|
||||
}
|
||||
|
||||
updatePaymentAmount(newAmountValue = newAmount)
|
||||
}
|
||||
}
|
||||
|
||||
fun onAppliedDiscountClicked() {
|
||||
val discountAmount = coinUtilisationPropertiesV2.value?.discountAmount.orEmpty()
|
||||
if (discountAmount.isNotEmpty()) {
|
||||
val paymentAmountAfterCoinDiscount =
|
||||
(paymentAmount.value.toDoubleOrNull().orZero() -
|
||||
discountAmount.toDoubleOrNull().orZero())
|
||||
.toString()
|
||||
_amountAfterCoinDiscount.update { paymentAmountAfterCoinDiscount }
|
||||
_isCoinDiscountApplied.update { true }
|
||||
}
|
||||
}
|
||||
|
||||
fun triggerAnimation() {
|
||||
viewModelScope.launch(dispatcherProvider.io) {
|
||||
delay(3000)
|
||||
_isLottieAnimationShown.update { true }
|
||||
}
|
||||
}
|
||||
|
||||
fun onRemoveDiscountClicked() {
|
||||
_isCoinDiscountApplied.update { false }
|
||||
}
|
||||
|
||||
fun onOfferRolodexClicked(transactionAmount: Double?) {
|
||||
offerDataList.value?.let { offerDataList ->
|
||||
_payBillBottomSheetType.update {
|
||||
PayBillBottomSheetType.OfferList(
|
||||
offerData = offerDataList,
|
||||
transactionAmount = transactionAmount,
|
||||
offerListHeading =
|
||||
if (offerDataList.size == 1) {
|
||||
resourceProvider.getString(
|
||||
R.string.bbps_offer_category_bottomsheet_count_title_singular,
|
||||
offerDataList.size,
|
||||
billCategoryEntity?.title ?: EMPTY,
|
||||
)
|
||||
} else {
|
||||
resourceProvider.getString(
|
||||
R.string.bbps_offer_category_bottomsheet_count_title_plural,
|
||||
offerDataList.size,
|
||||
billCategoryEntity?.title ?: EMPTY,
|
||||
)
|
||||
},
|
||||
coinBurnData = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun onHelpCtaClicked() {
|
||||
viewModelScope.launch(Dispatchers.IO) { updateNavigateToNextScreenOnHelpCta(helpCta) }
|
||||
}
|
||||
|
||||
private suspend fun updateNavigateToNextScreenOnHelpCta(ctaData: CtaData?) {
|
||||
_navigateToNextScreenFromHelpCta.emit(ctaData)
|
||||
}
|
||||
|
||||
suspend fun pmsDiscountListener() {
|
||||
naviPaymentRewardEventBus.events.collectLatest { event ->
|
||||
if (event.showDiscountedAmount) {
|
||||
onAppliedDiscountClicked()
|
||||
} else {
|
||||
onRemoveDiscountClicked()
|
||||
}
|
||||
if (event.isDiscountApplyLottieShown) {
|
||||
_isLottieAnimationShown.update { true }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun handleDiscountRemovalOnAmountFieldClick() {
|
||||
if (billCategoryEntity?.categoryId != CATEGORY_ID_MOBILE_PREPAID) {
|
||||
onRemoveDiscountClicked()
|
||||
}
|
||||
}
|
||||
|
||||
internal fun updateIsTokenLoading(isLoading: Boolean) {
|
||||
_isTokenLoading.update { isLoading }
|
||||
}
|
||||
|
||||
internal fun generatePaymentToken() {
|
||||
isPayButtonClicked = true
|
||||
viewModelScope.launch(dispatcherProvider.io) {
|
||||
if (billDetailsEntity.value == null) {
|
||||
return@launch
|
||||
|
||||
@@ -1,346 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright © 2024-2025 by Navi Technologies Limited
|
||||
* * All rights reserved. Strictly confidential
|
||||
*
|
||||
*/
|
||||
|
||||
package com.navi.bbps.feature.paybill
|
||||
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.navi.base.cache.repository.NaviCacheRepository
|
||||
import com.navi.base.model.CtaData
|
||||
import com.navi.base.utils.EMPTY
|
||||
import com.navi.base.utils.NaviNetworkConnectivity
|
||||
import com.navi.base.utils.ResourceProvider
|
||||
import com.navi.base.utils.ZERO_STRING
|
||||
import com.navi.base.utils.isNotNullAndNotEmpty
|
||||
import com.navi.base.utils.orZero
|
||||
import com.navi.bbps.R
|
||||
import com.navi.bbps.common.AMOUNT_MAX_LENGTH_AFTER_DECIMAL
|
||||
import com.navi.bbps.common.AMOUNT_MAX_LENGTH_BEFORE_DECIMAL
|
||||
import com.navi.bbps.common.CATEGORY_ID_MOBILE_PREPAID
|
||||
import com.navi.bbps.common.CoinsSyncManager
|
||||
import com.navi.bbps.common.NaviBbpsScreen
|
||||
import com.navi.bbps.common.model.view.NaviBbpsSessionHelper
|
||||
import com.navi.bbps.common.repository.BbpsCommonRepository
|
||||
import com.navi.bbps.common.usecase.FetchBillHandler
|
||||
import com.navi.bbps.common.usecase.GetABTestingExperimentUseCase
|
||||
import com.navi.bbps.common.usecase.NaviBbpsConfigUseCase
|
||||
import com.navi.bbps.common.usecase.RewardNudgeUseCase
|
||||
import com.navi.bbps.common.utils.NaviBbpsCommonUtils
|
||||
import com.navi.bbps.common.utils.NaviBbpsCommonUtils.evaluateMvelExpression
|
||||
import com.navi.bbps.common.utils.NaviBbpsCommonUtils.getValidatedAmountNumber
|
||||
import com.navi.bbps.common.utils.NaviBbpsCommonUtils.isCategoryOfTypeAmountChipsRequired
|
||||
import com.navi.bbps.common.utils.NaviBbpsDateUtils
|
||||
import com.navi.bbps.common.utils.getDisplayableAmount
|
||||
import com.navi.bbps.feature.category.BillCategoriesRepository
|
||||
import com.navi.bbps.feature.mybills.MyBillsRepository
|
||||
import com.navi.bbps.feature.paybill.model.network.PaymentAmountExactness
|
||||
import com.navi.bbps.feature.paybill.model.view.CoinUtilisationPropertiesV2
|
||||
import com.navi.bbps.feature.paybill.model.view.PayBillBottomSheetType
|
||||
import com.navi.bbps.feature.paybill.model.view.PayBillSource
|
||||
import com.navi.common.R as CommonR
|
||||
import com.navi.common.di.CoroutineDispatcherProvider
|
||||
import com.navi.common.usecase.LitmusExperimentsUseCase
|
||||
import com.navi.payment.nativepayment.utils.NaviPaymentRewardsEventBus
|
||||
import com.navi.payment.tstore.repository.TStoreOrderHandler
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asSharedFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
|
||||
@HiltViewModel
|
||||
class PayBillViewModelV2
|
||||
@Inject
|
||||
constructor(
|
||||
savedStateHandle: SavedStateHandle,
|
||||
private val dispatcherProvider: CoroutineDispatcherProvider,
|
||||
payBillRepository: PayBillRepository,
|
||||
naviBbpsDateUtils: NaviBbpsDateUtils,
|
||||
naviBbpsConfigUseCase: NaviBbpsConfigUseCase,
|
||||
getABTestingExperimentUseCase: GetABTestingExperimentUseCase,
|
||||
myBillsRepository: MyBillsRepository,
|
||||
tStoreOrderHandler: TStoreOrderHandler,
|
||||
naviNetworkConnectivity: NaviNetworkConnectivity,
|
||||
fetchBillHandler: FetchBillHandler,
|
||||
naviBbpsSessionHelper: NaviBbpsSessionHelper,
|
||||
private val coinsSyncManager: CoinsSyncManager,
|
||||
billCategoriesRepository: BillCategoriesRepository,
|
||||
private val resProvider: ResourceProvider,
|
||||
rewardsNudgeEntityFetchUseCase: RewardNudgeUseCase,
|
||||
private val naviPaymentRewardEventBus: NaviPaymentRewardsEventBus,
|
||||
naviCacheRepository: NaviCacheRepository,
|
||||
naviBbpsCommonRepository: BbpsCommonRepository,
|
||||
private val resourceProvider: ResourceProvider,
|
||||
private val litmusExperimentsUseCase: LitmusExperimentsUseCase,
|
||||
) :
|
||||
PayBillViewModel(
|
||||
savedStateHandle = savedStateHandle,
|
||||
dispatcherProvider = dispatcherProvider,
|
||||
naviBbpsDateUtils = naviBbpsDateUtils,
|
||||
naviBbpsConfigUseCase = naviBbpsConfigUseCase,
|
||||
myBillsRepository = myBillsRepository,
|
||||
tStoreOrderHandler = tStoreOrderHandler,
|
||||
naviNetworkConnectivity = naviNetworkConnectivity,
|
||||
fetchBillHandler = fetchBillHandler,
|
||||
naviBbpsSessionHelper = naviBbpsSessionHelper,
|
||||
coinsSyncManager = coinsSyncManager,
|
||||
billCategoriesRepository = billCategoriesRepository,
|
||||
resProvider = resProvider,
|
||||
rewardsNudgeEntityFetchUseCase = rewardsNudgeEntityFetchUseCase,
|
||||
payBillRepository = payBillRepository,
|
||||
naviCacheRepository = naviCacheRepository,
|
||||
naviBbpsCommonRepository = naviBbpsCommonRepository,
|
||||
resourceProvider = resourceProvider,
|
||||
litmusExperimentsUseCase = litmusExperimentsUseCase,
|
||||
) {
|
||||
|
||||
private val _payBillBottomSheetType =
|
||||
MutableStateFlow<PayBillBottomSheetType>(PayBillBottomSheetType.None)
|
||||
val payBillBottomSheetType = _payBillBottomSheetType.asStateFlow()
|
||||
|
||||
private val _navigateToNextScreenFromHelpCta = MutableSharedFlow<CtaData?>()
|
||||
val navigateToNextScreenFromHelpCta = _navigateToNextScreenFromHelpCta.asSharedFlow()
|
||||
|
||||
val helpCta = NaviBbpsCommonUtils.getHelpCtaData(NaviBbpsScreen.NAVI_BBPS_PAY_BILL_SCREEN.name)
|
||||
|
||||
private val _coinsUtilisationPropertiesV2 = MutableStateFlow<CoinUtilisationPropertiesV2?>(null)
|
||||
val coinUtilisationPropertiesV2 = _coinsUtilisationPropertiesV2.asStateFlow()
|
||||
|
||||
private val _amountAfterCoinDiscount = MutableStateFlow(ZERO_STRING)
|
||||
val amountAfterCoinDiscount = _amountAfterCoinDiscount.asStateFlow()
|
||||
|
||||
private val _isCoinDiscountApplied = MutableStateFlow(false)
|
||||
val isCoinDiscountApplied = _isCoinDiscountApplied.asStateFlow()
|
||||
|
||||
private val _isLottieAnimationShown = MutableStateFlow(false)
|
||||
val isLottieAnimationShown = _isLottieAnimationShown.asStateFlow()
|
||||
|
||||
init {
|
||||
viewModelScope.launch(dispatcherProvider.io) { launch { pmsDiscountListener() } }
|
||||
}
|
||||
|
||||
override fun updatePaymentAmount(newAmountValue: String) {
|
||||
val validatedNewAmount =
|
||||
if (newAmountValue.toDoubleOrNull().orZero() <= 0) "" else newAmountValue
|
||||
_paymentAmount.update { validatedNewAmount }
|
||||
|
||||
val paymentAmountValue = paymentAmount.value.toDoubleOrNull() ?: 0.0
|
||||
val initialPaymentAmountValue = initialPaymentAmount.value.toDoubleOrNull() ?: 0.0
|
||||
|
||||
if (validatedNewAmount.isEmpty()) {
|
||||
updateShowErrorText(value = false)
|
||||
} else {
|
||||
when (paymentAmountExactness.value) {
|
||||
PaymentAmountExactness.EXACT_AND_ABOVE -> {
|
||||
updateShowErrorText(value = paymentAmountValue < initialPaymentAmountValue)
|
||||
}
|
||||
PaymentAmountExactness.EXACT_AND_BELOW -> {
|
||||
updateShowErrorText(value = paymentAmountValue > initialPaymentAmountValue)
|
||||
}
|
||||
PaymentAmountExactness.EXACT -> {
|
||||
updateShowErrorText(value = paymentAmountValue != initialPaymentAmountValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isCategoryOfTypeAmountChipsRequired(billCategoryEntity?.categoryId.orEmpty())) {
|
||||
updateAmountChipEntity(amount = newAmountValue)
|
||||
}
|
||||
}
|
||||
|
||||
fun getApplicableDiscount() {
|
||||
if (coinBurnData.value?.expression.isNullOrEmpty()) return
|
||||
handleDiscountProperties(
|
||||
discountExpression = coinBurnData.value?.expression.toString(),
|
||||
cashEquivalentOfDiscount = coinBurnData.value?.cashEquivalentOfDiscount,
|
||||
coinValue = coinBurnData.value?.config?.coins.toString(),
|
||||
)
|
||||
}
|
||||
|
||||
private fun handleDiscountProperties(
|
||||
discountExpression: String,
|
||||
cashEquivalentOfDiscount: Int?,
|
||||
coinValue: String,
|
||||
) {
|
||||
if (discountExpression.isNotNullAndNotEmpty()) {
|
||||
val discountAmount = runBlocking {
|
||||
calculateDiscountedAmountFromFormula(
|
||||
discountedFormula = discountExpression,
|
||||
cashEquivalentOfDiscount = cashEquivalentOfDiscount.toString(),
|
||||
)
|
||||
}
|
||||
val coinsUsed = (discountAmount.toInt() * (coinValue.toInt())).toString()
|
||||
val discountInfoText =
|
||||
resProvider.getString(
|
||||
R.string.bbps_save_rupee_symbol_amount,
|
||||
discountAmount.getDisplayableAmount(),
|
||||
)
|
||||
val discountInfoTextAfterDiscount =
|
||||
resProvider.getString(
|
||||
R.string.bbps_saved_rupee_symbol_amount,
|
||||
discountAmount.getDisplayableAmount(),
|
||||
)
|
||||
updateCoinsUtilisationProperties(
|
||||
CoinUtilisationPropertiesV2(
|
||||
discountAmount = discountAmount,
|
||||
coinUtilisationText = discountInfoText,
|
||||
coinUsedForDiscount = coinsUsed.getDisplayableAmount(),
|
||||
discountAmountTextAfterDiscount = discountInfoTextAfterDiscount,
|
||||
)
|
||||
)
|
||||
} else return
|
||||
}
|
||||
|
||||
private suspend fun calculateDiscountedAmountFromFormula(
|
||||
discountedFormula: String,
|
||||
cashEquivalentOfDiscount: String? = null,
|
||||
): String {
|
||||
return evaluateMvelExpression(
|
||||
key = discountedFormula,
|
||||
data =
|
||||
mapOf(
|
||||
"cashEquivalentOfDiscount" to
|
||||
(cashEquivalentOfDiscount
|
||||
?: coinsSyncManager.getCashEquivalentOfDiscount().toDoubleOrNull()
|
||||
?: 0.0),
|
||||
"billAmount" to (paymentAmount.value.toDoubleOrNull() ?: 0.0),
|
||||
),
|
||||
ZERO_STRING,
|
||||
)
|
||||
}
|
||||
|
||||
private fun updateCoinsUtilisationProperties(
|
||||
coinUtilisationPropertiesV2: CoinUtilisationPropertiesV2
|
||||
) {
|
||||
_coinsUtilisationPropertiesV2.update { coinUtilisationPropertiesV2 }
|
||||
}
|
||||
|
||||
fun onMoreClicked() {
|
||||
val description =
|
||||
when (payBillScreenSource) {
|
||||
is PayBillSource.Prepaid -> {
|
||||
payBillScreenSource.planItemEntity.packageDescription
|
||||
}
|
||||
else -> EMPTY
|
||||
}
|
||||
_payBillBottomSheetType.update {
|
||||
PayBillBottomSheetType.PlanDetails(
|
||||
title = resProvider.getString(R.string.bbps_plan_details),
|
||||
description = description,
|
||||
icon = CommonR.drawable.ic_purple_exclamation,
|
||||
ctaText = resProvider.getString(R.string.bbps_okay_got_it),
|
||||
amount = paymentAmount.value.getDisplayableAmount(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun enteredAmountInputChanged(
|
||||
newInput: String,
|
||||
isAmountChangedByChipSelection: Boolean = false,
|
||||
) {
|
||||
viewModelScope.launch(dispatcherProvider.io) {
|
||||
var newAmount = ""
|
||||
if (newInput.isNotEmpty() && newInput != ZERO_STRING) {
|
||||
newAmount =
|
||||
getValidatedAmountNumber(
|
||||
text = newInput,
|
||||
amountMaxLengthAfterDecimal = AMOUNT_MAX_LENGTH_AFTER_DECIMAL,
|
||||
amountMaxLengthBeforeDecimal = AMOUNT_MAX_LENGTH_BEFORE_DECIMAL,
|
||||
)
|
||||
|
||||
if (isAmountChangedByChipSelection) {
|
||||
newAmount = newInput
|
||||
}
|
||||
}
|
||||
|
||||
updatePaymentAmount(newAmountValue = newAmount)
|
||||
}
|
||||
}
|
||||
|
||||
fun onAppliedDiscountClicked() {
|
||||
val discountAmount = coinUtilisationPropertiesV2.value?.discountAmount.orEmpty()
|
||||
if (discountAmount.isNotEmpty()) {
|
||||
val paymentAmountAfterCoinDiscount =
|
||||
(paymentAmount.value.toDoubleOrNull().orZero() -
|
||||
discountAmount.toDoubleOrNull().orZero())
|
||||
.toString()
|
||||
_amountAfterCoinDiscount.update { paymentAmountAfterCoinDiscount }
|
||||
_isCoinDiscountApplied.update { true }
|
||||
}
|
||||
}
|
||||
|
||||
fun triggerAnimation() {
|
||||
viewModelScope.launch(dispatcherProvider.io) {
|
||||
delay(3000)
|
||||
_isLottieAnimationShown.update { true }
|
||||
}
|
||||
}
|
||||
|
||||
fun onRemoveDiscountClicked() {
|
||||
_isCoinDiscountApplied.update { false }
|
||||
}
|
||||
|
||||
fun onOfferRolodexClicked(transactionAmount: Double?) {
|
||||
offerDataList.value?.let { offerDataList ->
|
||||
_payBillBottomSheetType.update {
|
||||
PayBillBottomSheetType.OfferList(
|
||||
offerData = offerDataList,
|
||||
transactionAmount = transactionAmount,
|
||||
offerListHeading =
|
||||
if (offerDataList.size == 1) {
|
||||
resourceProvider.getString(
|
||||
R.string.bbps_offer_category_bottomsheet_count_title_singular,
|
||||
offerDataList.size,
|
||||
billCategoryEntity?.title ?: EMPTY,
|
||||
)
|
||||
} else {
|
||||
resourceProvider.getString(
|
||||
R.string.bbps_offer_category_bottomsheet_count_title_plural,
|
||||
offerDataList.size,
|
||||
billCategoryEntity?.title ?: EMPTY,
|
||||
)
|
||||
},
|
||||
coinBurnData = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun onHelpCtaClicked() {
|
||||
viewModelScope.launch(Dispatchers.IO) { updateNavigateToNextScreenOnHelpCta(helpCta) }
|
||||
}
|
||||
|
||||
private suspend fun updateNavigateToNextScreenOnHelpCta(ctaData: CtaData?) {
|
||||
_navigateToNextScreenFromHelpCta.emit(ctaData)
|
||||
}
|
||||
|
||||
suspend fun pmsDiscountListener() {
|
||||
naviPaymentRewardEventBus.events.collectLatest { event ->
|
||||
if (event.showDiscountedAmount) {
|
||||
onAppliedDiscountClicked()
|
||||
} else {
|
||||
onRemoveDiscountClicked()
|
||||
}
|
||||
if (event.isDiscountApplyLottieShown) {
|
||||
_isLottieAnimationShown.update { true }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun handleDiscountRemovalOnAmountFieldClick() {
|
||||
if (billCategoryEntity?.categoryId != CATEGORY_ID_MOBILE_PREPAID) {
|
||||
onRemoveDiscountClicked()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -26,5 +26,8 @@ sealed class PayBillBottomSheetType {
|
||||
val transactionAmount: Double?,
|
||||
) : PayBillBottomSheetType()
|
||||
|
||||
data class BillDetailsUpdateInfo(val title: String, val description: String) :
|
||||
PayBillBottomSheetType()
|
||||
|
||||
data object None : PayBillBottomSheetType()
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ private val AMOUNT_FIELD_FONT_WEIGHT = FontWeightEnum.NAVI_HEADLINE_REGULAR
|
||||
|
||||
@OptIn(ExperimentalMaterialApi::class)
|
||||
@Composable
|
||||
fun AmountTextFieldV2(
|
||||
fun AmountTextField(
|
||||
modifier: Modifier,
|
||||
isReadOnly: Boolean,
|
||||
focusManager: FocusManager,
|
||||
|
||||
@@ -20,15 +20,19 @@ import androidx.compose.runtime.Composable
|
||||
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.base.utils.EMPTY
|
||||
import com.navi.base.utils.SPACE
|
||||
import com.navi.bbps.R
|
||||
import com.navi.bbps.common.BULLET
|
||||
import com.navi.bbps.common.SYMBOL_RUPEE
|
||||
import com.navi.bbps.common.theme.NaviBbpsColor
|
||||
import com.navi.bbps.common.ui.BbpsOfferBottomSheet
|
||||
import com.navi.bbps.common.ui.BottomSheetContentWithIconHeaderPrimarySecondaryButton
|
||||
import com.navi.bbps.feature.paybill.model.view.PayBillBottomSheetType
|
||||
import com.navi.common.R as CommonR
|
||||
import com.navi.common.customview.LoaderRoundedButton
|
||||
import com.navi.design.font.FontWeightEnum
|
||||
import com.navi.design.font.getFontWeight
|
||||
@@ -61,6 +65,17 @@ fun PayBillBottomSheetContent(
|
||||
closeSheet()
|
||||
}
|
||||
}
|
||||
is PayBillBottomSheetType.BillDetailsUpdateInfo -> {
|
||||
BottomSheetContentWithIconHeaderPrimarySecondaryButton(
|
||||
iconId = CommonR.drawable.ic_purple_exclamation,
|
||||
onPrimaryButtonClicked = closeSheet,
|
||||
description = payBillBottomSheetType.description,
|
||||
header = payBillBottomSheetType.title,
|
||||
primaryButton = stringResource(id = R.string.bbps_okay_got_it),
|
||||
secondaryButton = null,
|
||||
onSecondaryButtonClicked = {},
|
||||
)
|
||||
}
|
||||
is PayBillBottomSheetType.None -> {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@@ -82,6 +82,7 @@ import com.navi.bbps.common.NaviBbpsScreen
|
||||
import com.navi.bbps.common.RCBP_CATEGORY
|
||||
import com.navi.bbps.common.SCROLL_OFFSET_FOR_TITLE_IN_HEADER
|
||||
import com.navi.bbps.common.SYMBOL_RUPEE
|
||||
import com.navi.bbps.common.TAG_BILL_ALREADY_PAID_ON_REFETCH
|
||||
import com.navi.bbps.common.TAG_BILL_FETCH_ERROR
|
||||
import com.navi.bbps.common.model.config.NaviBbpsDefaultConfig
|
||||
import com.navi.bbps.common.model.view.LoadingState
|
||||
@@ -111,12 +112,13 @@ import com.navi.bbps.feature.destinations.BillCategoriesScreenV2Destination
|
||||
import com.navi.bbps.feature.destinations.MyBillHistoryDetailsScreenDestination
|
||||
import com.navi.bbps.feature.mybills.model.view.MyBillEntity
|
||||
import com.navi.bbps.feature.mybills.model.view.UnpaidBillDetails
|
||||
import com.navi.bbps.feature.paybill.PayBillViewModelV2
|
||||
import com.navi.bbps.feature.paybill.PayBillViewModel
|
||||
import com.navi.bbps.feature.paybill.model.network.PayBillResponse
|
||||
import com.navi.bbps.feature.paybill.model.network.PaymentAmountExactness
|
||||
import com.navi.bbps.feature.paybill.model.view.AmountChipEntity
|
||||
import com.navi.bbps.feature.paybill.model.view.CoinUtilisationPropertiesV2
|
||||
import com.navi.bbps.feature.paybill.model.view.CreditCardPaymentOption
|
||||
import com.navi.bbps.feature.paybill.model.view.PayBillBottomSheetType
|
||||
import com.navi.bbps.feature.paybill.model.view.PayBillHeaderState
|
||||
import com.navi.bbps.feature.paybill.model.view.PayBillScreenState
|
||||
import com.navi.bbps.feature.paybill.model.view.PayBillSource
|
||||
@@ -159,9 +161,9 @@ import kotlinx.coroutines.launch
|
||||
|
||||
@Destination
|
||||
@Composable
|
||||
fun PayBillScreenV2(
|
||||
fun PayBillScreen(
|
||||
naviBbpsActivity: NaviBbpsActivity,
|
||||
payBillViewModelV2: PayBillViewModelV2 = hiltViewModel(),
|
||||
payBillViewModel: PayBillViewModel = hiltViewModel(),
|
||||
naviCheckoutViewModel: NaviCheckoutViewModelV2 = hiltViewModel(),
|
||||
billCategoryEntity: BillCategoryEntity,
|
||||
navigator: DestinationsNavigator,
|
||||
@@ -172,16 +174,16 @@ fun PayBillScreenV2(
|
||||
initialSource: String,
|
||||
naviBbpsAnalytics: NaviBbpsAnalytics.PayBill = NaviBbpsAnalytics.INSTANCE.PayBill(),
|
||||
) {
|
||||
val billDetailsEntity by payBillViewModelV2.billDetailsEntity.collectAsStateWithLifecycle()
|
||||
val billDetailsEntity by payBillViewModel.billDetailsEntity.collectAsStateWithLifecycle()
|
||||
val keyboardController = LocalSoftwareKeyboardController.current
|
||||
val paymentsResultLauncher =
|
||||
rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) { result
|
||||
->
|
||||
payBillViewModelV2.updateIsTokenLoading(isLoading = false)
|
||||
payBillViewModel.updateIsTokenLoading(isLoading = false)
|
||||
val status = result.data?.extras?.getString(STATUS.uppercase(Locale.getDefault()))
|
||||
val paymentCancelSource =
|
||||
result.data?.extras?.getString(PAYMENT_CANCEL_SOURCE).orEmpty()
|
||||
payBillViewModelV2.prevPaymentCancelSource = paymentCancelSource
|
||||
payBillViewModel.prevPaymentCancelSource = paymentCancelSource
|
||||
val data = result.data?.extras?.getString(KEY_DATA)
|
||||
val shouldReopenKeyboard =
|
||||
result.data?.extras?.getBoolean(SHOULD_PROMPT_AMOUNT_EDIT).orFalse()
|
||||
@@ -190,7 +192,7 @@ fun PayBillScreenV2(
|
||||
}
|
||||
when (status) {
|
||||
PaymentSdkTypes.DISMISS_LOADER.name -> {
|
||||
payBillViewModelV2.updateIsTokenLoading(isLoading = false)
|
||||
payBillViewModel.updateIsTokenLoading(isLoading = false)
|
||||
}
|
||||
else -> {
|
||||
val dataJSONObject = data?.stringToJsonObject()
|
||||
@@ -200,20 +202,20 @@ fun PayBillScreenV2(
|
||||
paymentStatus = dataJSONObject?.optString(STATUS).toString(),
|
||||
response = data,
|
||||
categoryId = billCategoryEntity.categoryId,
|
||||
sessionAttribute = payBillViewModelV2.getNaviBbpsSessionAttributes(),
|
||||
sessionAttribute = payBillViewModel.getNaviBbpsSessionAttributes(),
|
||||
source = source,
|
||||
initialSource = initialSource,
|
||||
)
|
||||
if (dataJSONObject != null) {
|
||||
payBillViewModelV2.onPaymentResultReceived(
|
||||
bbpsTransactionId = payBillViewModelV2.txnId,
|
||||
payBillViewModel.onPaymentResultReceived(
|
||||
bbpsTransactionId = payBillViewModel.txnId,
|
||||
paymentResponseMetadata = dataJSONObject,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
val orderReferenceId by payBillViewModelV2.orderReferenceId.collectAsStateWithLifecycle()
|
||||
val orderReferenceId by payBillViewModel.orderReferenceId.collectAsStateWithLifecycle()
|
||||
LaunchedEffect(Unit) {
|
||||
naviBbpsActivity.errorEventHandler.bbpsErrorCtaClickEvent.collectLatest { event ->
|
||||
// In case of bill fetch error, go back to previous screen
|
||||
@@ -226,7 +228,7 @@ fun PayBillScreenV2(
|
||||
LaunchedEffect(Unit) {
|
||||
val category = billCategoryEntity.categoryId
|
||||
val paymentCheckoutConfig =
|
||||
payBillViewModelV2.naviBbpsDefaultConfig.value.paymentCheckoutConfig.firstOrNull {
|
||||
payBillViewModel.naviBbpsDefaultConfig.value.paymentCheckoutConfig.firstOrNull {
|
||||
it.categoryId == category
|
||||
}
|
||||
naviCheckoutViewModel.setUpOneClickCheckout(
|
||||
@@ -238,7 +240,7 @@ fun PayBillScreenV2(
|
||||
}
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
payBillViewModelV2.navigateToOrderDetailsScreen.collectLatest { navigateToOrderDetailsScreen
|
||||
payBillViewModel.navigateToOrderDetailsScreen.collectLatest { navigateToOrderDetailsScreen
|
||||
->
|
||||
if (navigateToOrderDetailsScreen) {
|
||||
val orderDetailsCtaData =
|
||||
@@ -270,48 +272,45 @@ fun PayBillScreenV2(
|
||||
val view = LocalView.current
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
val isBillLoading by payBillViewModelV2.isBillLoading.collectAsStateWithLifecycle()
|
||||
val paymentAmount by payBillViewModelV2.paymentAmount.collectAsStateWithLifecycle()
|
||||
val isBillLoading by payBillViewModel.isBillLoading.collectAsStateWithLifecycle()
|
||||
val paymentAmount by payBillViewModel.paymentAmount.collectAsStateWithLifecycle()
|
||||
val shouldAutoFocusOnAmount by
|
||||
payBillViewModelV2.shouldAutoFocusOnAmount.collectAsStateWithLifecycle()
|
||||
val errorMessageId by payBillViewModelV2.errorMessageId.collectAsStateWithLifecycle()
|
||||
val showErrorText by payBillViewModelV2.showErrorText.collectAsStateWithLifecycle()
|
||||
val isTokenLoading by payBillViewModelV2.isTokenLoading.collectAsStateWithLifecycle()
|
||||
val initialPaymentAmount by
|
||||
payBillViewModelV2.initialPaymentAmount.collectAsStateWithLifecycle()
|
||||
val isAmountReadOnly by payBillViewModelV2.isAmountReadOnly.collectAsStateWithLifecycle()
|
||||
val isPayButtonEnabled by payBillViewModelV2.isPayButtonEnabled.collectAsStateWithLifecycle()
|
||||
val payBillHeaderState by payBillViewModelV2.payBillHeaderState.collectAsStateWithLifecycle()
|
||||
val payBillScreenState by payBillViewModelV2.payBillScreenState.collectAsStateWithLifecycle()
|
||||
payBillViewModel.shouldAutoFocusOnAmount.collectAsStateWithLifecycle()
|
||||
val errorMessageId by payBillViewModel.errorMessageId.collectAsStateWithLifecycle()
|
||||
val showErrorText by payBillViewModel.showErrorText.collectAsStateWithLifecycle()
|
||||
val isTokenLoading by payBillViewModel.isTokenLoading.collectAsStateWithLifecycle()
|
||||
val initialPaymentAmount by payBillViewModel.initialPaymentAmount.collectAsStateWithLifecycle()
|
||||
val isAmountReadOnly by payBillViewModel.isAmountReadOnly.collectAsStateWithLifecycle()
|
||||
val isPayButtonEnabled by payBillViewModel.isPayButtonEnabled.collectAsStateWithLifecycle()
|
||||
val payBillHeaderState by payBillViewModel.payBillHeaderState.collectAsStateWithLifecycle()
|
||||
val payBillScreenState by payBillViewModel.payBillScreenState.collectAsStateWithLifecycle()
|
||||
val billerAdditionalParams by
|
||||
payBillViewModelV2.billerAdditionalParams.collectAsStateWithLifecycle()
|
||||
payBillViewModel.billerAdditionalParams.collectAsStateWithLifecycle()
|
||||
|
||||
val formattedLastPaidDate by
|
||||
payBillViewModelV2.formattedLastPaidDate.collectAsStateWithLifecycle()
|
||||
payBillViewModel.formattedLastPaidDate.collectAsStateWithLifecycle()
|
||||
val formattedLastPaidAmount by
|
||||
payBillViewModelV2.formattedLastPaidAmount.collectAsStateWithLifecycle()
|
||||
val myBillEntity by payBillViewModelV2.myBillEntity.collectAsStateWithLifecycle()
|
||||
payBillViewModel.formattedLastPaidAmount.collectAsStateWithLifecycle()
|
||||
val myBillEntity by payBillViewModel.myBillEntity.collectAsStateWithLifecycle()
|
||||
val coinUtilisationProperties by
|
||||
payBillViewModelV2.coinUtilisationPropertiesV2.collectAsStateWithLifecycle()
|
||||
val creditCardPaymentOptions = payBillViewModelV2.creditCardPaymentOptions
|
||||
payBillViewModel.coinUtilisationPropertiesV2.collectAsStateWithLifecycle()
|
||||
val creditCardPaymentOptions = payBillViewModel.creditCardPaymentOptions
|
||||
val payBillBottomSheetType by
|
||||
payBillViewModelV2.payBillBottomSheetType.collectAsStateWithLifecycle()
|
||||
val amountChipEntityList by
|
||||
payBillViewModelV2.amountChipEntityList.collectAsStateWithLifecycle()
|
||||
val offerDataList by payBillViewModelV2.offerDataList.collectAsStateWithLifecycle()
|
||||
val coinBurnData by payBillViewModelV2.coinBurnData.collectAsStateWithLifecycle()
|
||||
payBillViewModel.payBillBottomSheetType.collectAsStateWithLifecycle()
|
||||
val amountChipEntityList by payBillViewModel.amountChipEntityList.collectAsStateWithLifecycle()
|
||||
val offerDataList by payBillViewModel.offerDataList.collectAsStateWithLifecycle()
|
||||
val coinBurnData by payBillViewModel.coinBurnData.collectAsStateWithLifecycle()
|
||||
val amountAfterCoinDiscount by
|
||||
payBillViewModelV2.amountAfterCoinDiscount.collectAsStateWithLifecycle()
|
||||
payBillViewModel.amountAfterCoinDiscount.collectAsStateWithLifecycle()
|
||||
val isCoinDiscountApplied by
|
||||
payBillViewModelV2.isCoinDiscountApplied.collectAsStateWithLifecycle()
|
||||
payBillViewModel.isCoinDiscountApplied.collectAsStateWithLifecycle()
|
||||
val isLottieAnimationShown by
|
||||
payBillViewModelV2.isLottieAnimationShown.collectAsStateWithLifecycle()
|
||||
payBillViewModel.isLottieAnimationShown.collectAsStateWithLifecycle()
|
||||
val naviBbpsDefaultConfig by
|
||||
payBillViewModelV2.naviBbpsDefaultConfig.collectAsStateWithLifecycle()
|
||||
val isConsentViewVisible by
|
||||
payBillViewModelV2.isConsentViewVisible.collectAsStateWithLifecycle()
|
||||
val isConsentProvided by payBillViewModelV2.isConsentProvided.collectAsStateWithLifecycle()
|
||||
val isArcProtected by payBillViewModelV2.isArcProtected.collectAsStateWithLifecycle()
|
||||
payBillViewModel.naviBbpsDefaultConfig.collectAsStateWithLifecycle()
|
||||
val isConsentViewVisible by payBillViewModel.isConsentViewVisible.collectAsStateWithLifecycle()
|
||||
val isConsentProvided by payBillViewModel.isConsentProvided.collectAsStateWithLifecycle()
|
||||
val isArcProtected by payBillViewModel.isArcProtected.collectAsStateWithLifecycle()
|
||||
|
||||
val sortedOfferList by
|
||||
remember(offerDataList, paymentAmount) {
|
||||
@@ -332,7 +331,7 @@ fun PayBillScreenV2(
|
||||
if (offerDataList.isNotNullAndNotEmpty()) {
|
||||
naviBbpsAnalytics.rewardCampaignList(
|
||||
offerDataList = offerDataList.orEmpty(),
|
||||
sessionAttribute = payBillViewModelV2.getNaviBbpsSessionAttributes(),
|
||||
sessionAttribute = payBillViewModel.getNaviBbpsSessionAttributes(),
|
||||
source = source,
|
||||
initialSource = initialSource,
|
||||
)
|
||||
@@ -344,28 +343,28 @@ fun PayBillScreenV2(
|
||||
billerId = payBillScreenSource.billerId,
|
||||
billCategoryEntity = billCategoryEntity,
|
||||
billDetailsEntity = billDetailsEntity,
|
||||
sessionAttribute = payBillViewModelV2.getNaviBbpsSessionAttributes(),
|
||||
sessionAttribute = payBillViewModel.getNaviBbpsSessionAttributes(),
|
||||
source = source,
|
||||
initialSource = initialSource,
|
||||
)
|
||||
payBillViewModelV2.fetchOffersAndCoinBurnForProduct(
|
||||
payBillViewModel.fetchOffersAndCoinBurnForProduct(
|
||||
attributes =
|
||||
mapOf(
|
||||
RCBP_CATEGORY to billCategoryEntity.categoryId,
|
||||
BILLER_UNIQUE_ID to payBillScreenSource.billerId,
|
||||
)
|
||||
)
|
||||
payBillViewModelV2.startPaymentFlow.collectLatest { payBillResponse ->
|
||||
payBillViewModel.startPaymentFlow.collectLatest { payBillResponse ->
|
||||
if (payBillResponse != null) {
|
||||
startPaymentFlow(
|
||||
payBillResponse = payBillResponse,
|
||||
initiatePayment = naviCheckoutViewModel::onTokenGenerated,
|
||||
naviBbpsAnalytics = naviBbpsAnalytics,
|
||||
billCategoryEntity = billCategoryEntity,
|
||||
sessionAttribute = payBillViewModelV2.getNaviBbpsSessionAttributes(),
|
||||
sessionAttribute = payBillViewModel.getNaviBbpsSessionAttributes(),
|
||||
source = source,
|
||||
initialSource = initialSource,
|
||||
prevPaymentCancelSource = payBillViewModelV2.prevPaymentCancelSource,
|
||||
prevPaymentCancelSource = payBillViewModel.prevPaymentCancelSource,
|
||||
coinUtilisationPropertiesV2 = coinUtilisationProperties,
|
||||
isAppliedDiscountClicked = isCoinDiscountApplied,
|
||||
isDiscountApplyLottieShown = isLottieAnimationShown,
|
||||
@@ -379,13 +378,13 @@ fun PayBillScreenV2(
|
||||
}
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
payBillViewModelV2.navigateToNextScreenFromHelpCta.collectLatest {
|
||||
payBillViewModel.navigateToNextScreenFromHelpCta.collectLatest {
|
||||
it?.let { NaviBbpsRouter.onCtaClick(naviBbpsActivity = naviBbpsActivity, ctaData = it) }
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(paymentAmount, offerDataList, coinBurnData) {
|
||||
payBillViewModelV2.getApplicableDiscount()
|
||||
payBillViewModel.getApplicableDiscount()
|
||||
}
|
||||
|
||||
val bottomSheetState =
|
||||
@@ -401,10 +400,17 @@ fun PayBillScreenV2(
|
||||
event.errorConfig.tag == TAG_BILL_FETCH_ERROR -> {
|
||||
navigator.navigateUp()
|
||||
}
|
||||
event.errorConfig.tag == TAG_BILL_ALREADY_PAID_ON_REFETCH -> {
|
||||
if (source == NAVI_HOME || source == EMPTY) {
|
||||
naviBbpsActivity.finish()
|
||||
} else {
|
||||
navigator.navigateUp()
|
||||
}
|
||||
}
|
||||
event.clickedButtonConfig.action is NaviBbpsButtonAction.Redirect -> {
|
||||
val apiUrl = event.clickedButtonConfig.action.url
|
||||
if (isUrlPathValidForSavedBills(urlPath = apiUrl)) {
|
||||
payBillViewModelV2.onSavedBillCtaClicked(apiUrl = apiUrl)
|
||||
payBillViewModel.onSavedBillCtaClicked(apiUrl = apiUrl)
|
||||
bottomSheetState.hide()
|
||||
navigator.navigateUp()
|
||||
}
|
||||
@@ -414,7 +420,7 @@ fun PayBillScreenV2(
|
||||
}
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
payBillViewModelV2.goToNextScreen.collectLatest { nextScreen ->
|
||||
payBillViewModel.goToNextScreen.collectLatest { nextScreen ->
|
||||
val direction = nextScreen.first
|
||||
val clearBackStack = nextScreen.second
|
||||
if (direction != null) {
|
||||
@@ -459,16 +465,16 @@ fun PayBillScreenV2(
|
||||
isChecked = !isConsentProvided,
|
||||
billDetailsEntity = payBillScreenSource.billDetailsEntity,
|
||||
billCategoryEntity = billCategoryEntity,
|
||||
sessionAttribute = payBillViewModelV2.getNaviBbpsSessionAttributes(),
|
||||
sessionAttribute = payBillViewModel.getNaviBbpsSessionAttributes(),
|
||||
source = source,
|
||||
initialSource = initialSource,
|
||||
)
|
||||
payBillViewModelV2.toggleConsentProvided()
|
||||
payBillViewModel.toggleConsentProvided()
|
||||
}
|
||||
|
||||
val onAmountChipClicked = { amount: String ->
|
||||
focusManager.clearFocus()
|
||||
payBillViewModelV2.enteredAmountInputChanged(
|
||||
payBillViewModel.enteredAmountInputChanged(
|
||||
newInput = amount,
|
||||
isAmountChangedByChipSelection = true,
|
||||
)
|
||||
@@ -484,12 +490,12 @@ fun PayBillScreenV2(
|
||||
}
|
||||
|
||||
val onMoreClicked = {
|
||||
payBillViewModelV2.onMoreClicked()
|
||||
payBillViewModel.onMoreClicked()
|
||||
openSheet()
|
||||
}
|
||||
|
||||
val onCreditCardPaymentOptionSelected = { creditCardPaymentOption: CreditCardPaymentOption ->
|
||||
payBillViewModelV2.onCreditCardPaymentOptionSelected(creditCardPaymentOption)
|
||||
payBillViewModel.onCreditCardPaymentOptionSelected(creditCardPaymentOption)
|
||||
}
|
||||
|
||||
var loadingState by remember {
|
||||
@@ -530,6 +536,24 @@ fun PayBillScreenV2(
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
payBillViewModel.showBillDetailsUpdatedBottomSheet.collectLatest {
|
||||
showBillDetailsUpdatedBottomSheet ->
|
||||
if (showBillDetailsUpdatedBottomSheet) {
|
||||
openSheet()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(bottomSheetState.isVisible) {
|
||||
if (
|
||||
!bottomSheetState.isVisible &&
|
||||
payBillBottomSheetType is PayBillBottomSheetType.BillDetailsUpdateInfo
|
||||
) {
|
||||
payBillViewModel.updateLatestBillDetails()
|
||||
}
|
||||
}
|
||||
|
||||
NaviBbpsModalBottomSheetLayout(
|
||||
sheetContent = {
|
||||
PayBillBottomSheetContent(
|
||||
@@ -549,8 +573,8 @@ fun PayBillScreenV2(
|
||||
scrollState = scrollState,
|
||||
isCreditCardCategory = isCreditCardCategory,
|
||||
billCategoryEntity = billCategoryEntity,
|
||||
helpCtaText = payBillViewModelV2.helpCta.title.orEmpty(),
|
||||
onHelpCtaClicked = payBillViewModelV2::onHelpCtaClicked,
|
||||
helpCtaText = payBillViewModel.helpCta.title.orEmpty(),
|
||||
onHelpCtaClicked = payBillViewModel::onHelpCtaClicked,
|
||||
payBillScreenSource = payBillScreenSource,
|
||||
)
|
||||
},
|
||||
@@ -614,7 +638,7 @@ fun PayBillScreenV2(
|
||||
isAmountReadOnly = isAmountReadOnly,
|
||||
generateToken = {
|
||||
keyboardController?.customHide(context = context, view = view)
|
||||
payBillViewModelV2.generatePaymentToken()
|
||||
payBillViewModel.generatePaymentToken()
|
||||
},
|
||||
)
|
||||
}
|
||||
@@ -634,7 +658,7 @@ fun PayBillScreenV2(
|
||||
else {
|
||||
if (isCreditCardCategory) {
|
||||
if (payBillScreenState is PayBillScreenState.BillDetailsAvailable) {
|
||||
RenderCreditCardPayBillScreenV2(
|
||||
RenderCreditCardPayBillScreen(
|
||||
payBillScreenState =
|
||||
payBillScreenState
|
||||
as PayBillScreenState.BillDetailsAvailable,
|
||||
@@ -655,17 +679,17 @@ fun PayBillScreenV2(
|
||||
initialPaymentAmount = initialPaymentAmount,
|
||||
paymentAmount = paymentAmount,
|
||||
onAmountValueChanged =
|
||||
payBillViewModelV2::onAmountValueChanged,
|
||||
payBillViewModel::onAmountValueChanged,
|
||||
scrollState = scrollState,
|
||||
coinBurnData = coinBurnData,
|
||||
onAppliedDiscountClicked =
|
||||
payBillViewModelV2::onAppliedDiscountClicked,
|
||||
payBillViewModel::onAppliedDiscountClicked,
|
||||
onRemoveDiscountClicked =
|
||||
payBillViewModelV2::onRemoveDiscountClicked,
|
||||
payBillViewModel::onRemoveDiscountClicked,
|
||||
isAppliedDiscountClicked = isCoinDiscountApplied,
|
||||
sortedOfferList = sortedOfferList,
|
||||
onOfferClicked = {
|
||||
payBillViewModelV2.onOfferRolodexClicked(
|
||||
payBillViewModel.onOfferRolodexClicked(
|
||||
if (paymentAmount.isNotEmpty())
|
||||
paymentAmount.toDouble()
|
||||
else null
|
||||
@@ -676,8 +700,7 @@ fun PayBillScreenV2(
|
||||
initialSource = initialSource,
|
||||
coinBurnData = coinBurnData,
|
||||
sessionAttribute =
|
||||
payBillViewModelV2
|
||||
.getNaviBbpsSessionAttributes(),
|
||||
payBillViewModel.getNaviBbpsSessionAttributes(),
|
||||
billCategoryEntity = billCategoryEntity,
|
||||
)
|
||||
openSheet()
|
||||
@@ -690,7 +713,7 @@ fun PayBillScreenV2(
|
||||
)
|
||||
}
|
||||
} else {
|
||||
RenderNonCreditCardPayBillScreenV2(
|
||||
RenderNonCreditCardPayBillScreen(
|
||||
billDetailsEntity = billDetailsEntity,
|
||||
phoneNumberDetail = phoneNumberDetail,
|
||||
payBillHeaderState = payBillHeaderState,
|
||||
@@ -700,7 +723,7 @@ fun PayBillScreenV2(
|
||||
initialSource = initialSource,
|
||||
formattedLastPaidDate = formattedLastPaidDate,
|
||||
billCategoryEntity = billCategoryEntity,
|
||||
payBillViewModelV2 = payBillViewModelV2,
|
||||
payBillViewModel = payBillViewModel,
|
||||
keyboardController = keyboardController,
|
||||
context = context,
|
||||
view = view,
|
||||
@@ -771,7 +794,7 @@ fun PayBillScreenV2(
|
||||
.padding(top = 16.dp)
|
||||
.fillMaxWidth(),
|
||||
)
|
||||
payBillViewModelV2.triggerAnimation()
|
||||
payBillViewModel.triggerAnimation()
|
||||
}
|
||||
BottomBarShadow(shadowHeight = 32.dp)
|
||||
}
|
||||
@@ -968,6 +991,7 @@ fun onBillHistoryClicked(
|
||||
accountHolderName = payBillHeaderState.phoneContactEntity.name,
|
||||
billerAdditionalParams = emptyList(),
|
||||
planItemDetails = emptyMap(),
|
||||
lastGeneratedTimestamp = EMPTY,
|
||||
),
|
||||
)
|
||||
is PayBillHeaderState.OtherHeaders ->
|
||||
@@ -989,6 +1013,7 @@ fun onBillHistoryClicked(
|
||||
accountHolderName = billDetailsEntity?.accountHolderName.orEmpty(),
|
||||
billerAdditionalParams = emptyList(),
|
||||
planItemDetails = emptyMap(),
|
||||
lastGeneratedTimestamp = EMPTY,
|
||||
),
|
||||
)
|
||||
else -> defaultMyBillEntity
|
||||
@@ -106,7 +106,7 @@ import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.filter
|
||||
|
||||
@Composable
|
||||
fun RenderCreditCardPayBillScreenV2(
|
||||
fun RenderCreditCardPayBillScreen(
|
||||
payBillScreenState: PayBillScreenState.BillDetailsAvailable,
|
||||
formattedLastPaidDate: String,
|
||||
formattedLastPaidAmount: String,
|
||||
@@ -53,7 +53,7 @@ import com.navi.bbps.feature.customerinput.model.view.BillDetailsEntity
|
||||
import com.navi.bbps.feature.customerinput.model.view.BillerAdditionalParamsEntity
|
||||
import com.navi.bbps.feature.customerinput.model.view.BillerDetailsEntity
|
||||
import com.navi.bbps.feature.mybills.model.view.MyBillEntity
|
||||
import com.navi.bbps.feature.paybill.PayBillViewModelV2
|
||||
import com.navi.bbps.feature.paybill.PayBillViewModel
|
||||
import com.navi.bbps.feature.paybill.model.view.AmountChipEntity
|
||||
import com.navi.bbps.feature.paybill.model.view.CoinUtilisationPropertiesV2
|
||||
import com.navi.bbps.feature.paybill.model.view.PayBillHeaderState
|
||||
@@ -73,7 +73,7 @@ import com.navi.rr.common.models.OfferData
|
||||
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
|
||||
|
||||
@Composable
|
||||
fun RenderNonCreditCardPayBillScreenV2(
|
||||
fun RenderNonCreditCardPayBillScreen(
|
||||
billDetailsEntity: BillDetailsEntity?,
|
||||
phoneNumberDetail: PhoneContactEntity,
|
||||
payBillHeaderState: PayBillHeaderState?,
|
||||
@@ -83,7 +83,7 @@ fun RenderNonCreditCardPayBillScreenV2(
|
||||
initialSource: String,
|
||||
formattedLastPaidDate: String,
|
||||
billCategoryEntity: BillCategoryEntity,
|
||||
payBillViewModelV2: PayBillViewModelV2,
|
||||
payBillViewModel: PayBillViewModel,
|
||||
keyboardController: SoftwareKeyboardController?,
|
||||
context: Context,
|
||||
view: View,
|
||||
@@ -120,12 +120,12 @@ fun RenderNonCreditCardPayBillScreenV2(
|
||||
initialSource = initialSource,
|
||||
formattedLastPaidDate = formattedLastPaidDate,
|
||||
billCategoryEntity = billCategoryEntity,
|
||||
removeDiscountOnViewHistoryClicked = payBillViewModelV2::onRemoveDiscountClicked,
|
||||
removeDiscountOnViewHistoryClicked = payBillViewModel::onRemoveDiscountClicked,
|
||||
keyboardController = keyboardController,
|
||||
context = context,
|
||||
view = view,
|
||||
)
|
||||
AmountTextFieldV2(
|
||||
AmountTextField(
|
||||
modifier = Modifier.Companion.fillMaxWidth().padding(top = 32.dp),
|
||||
isReadOnly = isAmountReadOnly,
|
||||
focusManager = focusManager,
|
||||
@@ -133,14 +133,13 @@ fun RenderNonCreditCardPayBillScreenV2(
|
||||
stringResource(id = errorMessageId, initialPaymentAmount.getDisplayableAmount()),
|
||||
paymentAmount =
|
||||
if (isAmountReadOnly) paymentAmount.getDisplayableAmount() else paymentAmount,
|
||||
onPaymentAmountChanged = payBillViewModelV2::onAmountValueChanged,
|
||||
onPaymentAmountChanged = payBillViewModel::onAmountValueChanged,
|
||||
amountMaxLength = MAX_AMOUNT_LENGTH,
|
||||
showErrorText = showErrorText,
|
||||
isAppliedClicked = isCoinDiscountApplied,
|
||||
discountedAmount = amountAfterCoinDiscount,
|
||||
shouldAutoFocus = shouldAutoFocusOnAmount,
|
||||
removeDiscountOnAmountFieldClick =
|
||||
payBillViewModelV2::handleDiscountRemovalOnAmountFieldClick,
|
||||
removeDiscountOnAmountFieldClick = payBillViewModel::handleDiscountRemovalOnAmountFieldClick,
|
||||
)
|
||||
if (amountChipEntityList.isNotEmpty()) {
|
||||
Column {
|
||||
@@ -149,7 +148,7 @@ fun RenderNonCreditCardPayBillScreenV2(
|
||||
onAmountChipClicked = onAmountChipClicked,
|
||||
amountChipEntityList = amountChipEntityList,
|
||||
isCoinDiscountApplied = isCoinDiscountApplied,
|
||||
onRemoveDiscountClicked = payBillViewModelV2::onRemoveDiscountClicked,
|
||||
onRemoveDiscountClicked = payBillViewModel::onRemoveDiscountClicked,
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.Companion.height(24.dp))
|
||||
@@ -175,17 +174,17 @@ fun RenderNonCreditCardPayBillScreenV2(
|
||||
offerSuffix = offerItem.offer.titleSuffix.orEmpty(),
|
||||
coinUtilisationPropertiesV2 = coinUtilisationProperties,
|
||||
onAppliedDiscountClicked =
|
||||
payBillViewModelV2::onAppliedDiscountClicked,
|
||||
payBillViewModel::onAppliedDiscountClicked,
|
||||
isCoinDiscountAppliedClicked = isCoinDiscountApplied,
|
||||
onRemoveDiscountClicked =
|
||||
payBillViewModelV2::onRemoveDiscountClicked,
|
||||
payBillViewModel::onRemoveDiscountClicked,
|
||||
offerData = offerDataList,
|
||||
isApplied =
|
||||
paymentAmount.isNotEmpty() &&
|
||||
sortedOfferList.any { it.disabledData.isNull() },
|
||||
isBurnDisabled = showErrorText,
|
||||
onViewMoreClick = {
|
||||
payBillViewModelV2.onOfferRolodexClicked(
|
||||
payBillViewModel.onOfferRolodexClicked(
|
||||
if (paymentAmount.isNotEmpty()) paymentAmount.toDouble()
|
||||
else null
|
||||
)
|
||||
@@ -195,7 +194,7 @@ fun RenderNonCreditCardPayBillScreenV2(
|
||||
initialSource = initialSource,
|
||||
coinBurnData = coinBurnData,
|
||||
sessionAttribute =
|
||||
payBillViewModelV2.getNaviBbpsSessionAttributes(),
|
||||
payBillViewModel.getNaviBbpsSessionAttributes(),
|
||||
billCategoryEntity = billCategoryEntity,
|
||||
)
|
||||
openSheet()
|
||||
@@ -215,7 +214,7 @@ fun RenderNonCreditCardPayBillScreenV2(
|
||||
paymentAmount.isNotEmpty() &&
|
||||
sortedOfferList.any { it.disabledData.isNull() },
|
||||
onViewMoreClick = {
|
||||
payBillViewModelV2.onOfferRolodexClicked(
|
||||
payBillViewModel.onOfferRolodexClicked(
|
||||
if (paymentAmount.isNotEmpty()) paymentAmount.toDouble()
|
||||
else null
|
||||
)
|
||||
@@ -225,7 +224,7 @@ fun RenderNonCreditCardPayBillScreenV2(
|
||||
initialSource = initialSource,
|
||||
coinBurnData = coinBurnData,
|
||||
sessionAttribute =
|
||||
payBillViewModelV2.getNaviBbpsSessionAttributes(),
|
||||
payBillViewModel.getNaviBbpsSessionAttributes(),
|
||||
billCategoryEntity = billCategoryEntity,
|
||||
)
|
||||
openSheet()
|
||||
@@ -263,11 +262,11 @@ fun RenderNonCreditCardPayBillScreenV2(
|
||||
billDetailsEntity = billDetailsEntity,
|
||||
billCategoryEntity = billCategoryEntity,
|
||||
)
|
||||
payBillViewModelV2.onViewOtherPlansClicked()
|
||||
payBillViewModel.onViewOtherPlansClicked()
|
||||
},
|
||||
onMoreClicked = onMoreClicked,
|
||||
removeDiscountAnimationOnOtherPlansClicked =
|
||||
payBillViewModelV2::onRemoveDiscountClicked,
|
||||
payBillViewModel::onRemoveDiscountClicked,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -40,7 +40,7 @@ import com.navi.bbps.feature.contactlist.model.view.PhoneContactEntity
|
||||
import com.navi.bbps.feature.customerinput.model.network.BillDetailsRequest
|
||||
import com.navi.bbps.feature.customerinput.model.network.DeviceDetails
|
||||
import com.navi.bbps.feature.customerinput.model.view.BillDetailsEntity
|
||||
import com.navi.bbps.feature.destinations.PayBillScreenV2Destination
|
||||
import com.navi.bbps.feature.destinations.PayBillScreenDestination
|
||||
import com.navi.bbps.feature.mybills.MyBillsRepository
|
||||
import com.navi.bbps.feature.paybill.model.view.PayBillSource
|
||||
import com.navi.bbps.feature.prepaidrecharge.model.network.CircleItemResponse
|
||||
@@ -959,7 +959,7 @@ constructor(
|
||||
)
|
||||
|
||||
_navigateToNextScreen.emit(
|
||||
PayBillScreenV2Destination(
|
||||
PayBillScreenDestination(
|
||||
payBillScreenSource = payBillScreenSource,
|
||||
phoneNumberDetail = phoneNumberDetail,
|
||||
billCategoryEntity = billCategoryEntity,
|
||||
|
||||
@@ -194,11 +194,11 @@ object FirebaseRemoteConfigHelper {
|
||||
"NAVI_CHECK_BALANCE_CROSS_SELL_AD_FALLBACK_TIMEOUT"
|
||||
const val NAVI_BBPS_PPS_CROSS_SELL_AD_RE_ID = "NAVI_BBPS_PPS_CROSS_SELL_AD_RE_ID"
|
||||
const val NAVI_BBPS_DISMISS_BILL_DURATION = "NAVI_BBPS_DISMISS_BILL_DURATION"
|
||||
|
||||
const val NAVI_BBPS_PPS_SHARE_RECEIPT_CALLOUT_TEXT = "NAVI_BBPS_PPS_SHARE_RECEIPT_CALLOUT_TEXT"
|
||||
const val NAVI_BBPS_TDS_SHARE_RECEIPT_CALLOUT_TEXT = "NAVI_BBPS_TDS_SHARE_RECEIPT_CALLOUT_TEXT"
|
||||
const val NAVI_BBPS_EXTERNAL_APP_SHARE_CONFIGURABLE_TEXT =
|
||||
"NAVI_BBPS_EXTERNAL_APP_SHARE_CONFIGURABLE_TEXT"
|
||||
const val NAVI_BBPS_BILL_REFRESH_DURATION = "NAVI_BBPS_BILL_REFRESH_DURATION"
|
||||
|
||||
const val NAVI_BBPS_OFFER_SHIMMER_TIMEOUT = "NAVI_BBPS_OFFER_SHIMMER_TIMEOUT"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user