NTP-59175 | Divyesh | Bill history reminders enhancements (#16040)
This commit is contained in:
@@ -25,6 +25,7 @@ import androidx.compose.ui.platform.SoftwareKeyboardController
|
||||
import androidx.core.content.getSystemService
|
||||
import com.navi.base.utils.orFalse
|
||||
import com.navi.bbps.common.CATEGORY_ID_CREDIT_CARD
|
||||
import com.navi.bbps.common.CATEGORY_ID_MOBILE_PREPAID
|
||||
import com.navi.bbps.common.theme.NaviBbpsColor
|
||||
import com.navi.bbps.feature.mybills.model.view.MyBillEntity
|
||||
import com.navi.common.utils.ClickDebounce
|
||||
@@ -104,6 +105,11 @@ fun MyBillEntity.isRedirectToCustomerInputRequired(): Boolean {
|
||||
return this.categoryId == CATEGORY_ID_CREDIT_CARD && !isConsentProvided()
|
||||
}
|
||||
|
||||
fun MyBillEntity.isPrepaidRechargePaidOrWithoutPlanDetails(): Boolean {
|
||||
return categoryId == CATEGORY_ID_MOBILE_PREPAID &&
|
||||
(isBillPaid || unpaidBillDetails?.planItemDetails.isNullOrEmpty())
|
||||
}
|
||||
|
||||
fun getBillTitleFromAccountHolderNameOrPrimaryCustomerParams(
|
||||
accountHolderName: String?,
|
||||
primaryCustomerParams: String,
|
||||
|
||||
@@ -172,6 +172,9 @@ constructor(
|
||||
suspend fun fetchSavedBillsByCategory(category: String) =
|
||||
myBillsDao.getBillsByCategory(categoryId = category)
|
||||
|
||||
fun fetchSavedBillsByCategoryAsFlow(categoryId: String) =
|
||||
myBillsDao.getBillsByCategoryAsFlow(categoryId = categoryId)
|
||||
|
||||
suspend fun getRewardDetailsV2(
|
||||
metricInfo: MetricInfo<RepoResult<RewardDetailsV2Response>>
|
||||
): RepoResult<RewardDetailsV2Response> {
|
||||
|
||||
@@ -70,4 +70,5 @@ object NaviBbpsColor {
|
||||
val lightGreen = Color(0xFFF4FFF8)
|
||||
val bgDarkPurple = Color(0xFF22223D)
|
||||
val bottomSheetScrimColor = bgDarkPurple.copy(alpha = 0.64f)
|
||||
val secondaryCtaDisabledTextColor = Color(0xFFAAAAAA)
|
||||
}
|
||||
|
||||
@@ -86,6 +86,7 @@ fun ThemeRoundedButton(
|
||||
fun SecondaryRoundedButton(
|
||||
modifier: Modifier = Modifier,
|
||||
text: String,
|
||||
enabled: Boolean = true,
|
||||
cornerRadius: Dp = 4.dp,
|
||||
paddingValues: PaddingValues = PaddingValues(vertical = 14.dp, horizontal = 10.dp),
|
||||
onClick: () -> Unit,
|
||||
@@ -99,13 +100,19 @@ fun SecondaryRoundedButton(
|
||||
shape = RoundedCornerShape(cornerRadius),
|
||||
colors = ButtonDefaults.buttonColors(backgroundColor = NaviBbpsColor.ctaSecondary),
|
||||
contentPadding = paddingValues,
|
||||
enabled = enabled,
|
||||
) {
|
||||
NaviText(
|
||||
text = text,
|
||||
fontSize = 14.sp,
|
||||
fontFamily = naviFontFamily,
|
||||
fontWeight = getFontWeight(FontWeightEnum.NAVI_BODY_DEMI_BOLD),
|
||||
color = NaviBbpsColor.ctaPrimary,
|
||||
color =
|
||||
if (enabled) {
|
||||
NaviBbpsColor.ctaPrimary
|
||||
} else {
|
||||
NaviBbpsColor.secondaryCtaDisabledTextColor
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -206,6 +206,7 @@ constructor(
|
||||
initConfig()
|
||||
initSearchFlow()
|
||||
updateRewardsNudgeEntity()
|
||||
observeRecentBills()
|
||||
initLocationEvents()
|
||||
}
|
||||
|
||||
@@ -604,6 +605,32 @@ constructor(
|
||||
)
|
||||
}
|
||||
|
||||
private fun observeRecentBills() {
|
||||
viewModelScope.launch(dispatcherProvider.io) {
|
||||
bbpsCommonRepository
|
||||
.fetchSavedBillsByCategoryAsFlow(categoryId = billCategoryEntity.categoryId)
|
||||
.distinctUntilChanged()
|
||||
.collectLatest { recentBills ->
|
||||
recentBillsEntity =
|
||||
RecentBillsEntity(
|
||||
title = resourceProvider.getString(R.string.bbps_recents),
|
||||
bills = recentBills,
|
||||
)
|
||||
if (billerListState.value is BillerListState.Loaded) {
|
||||
updateBillerListState(
|
||||
BillerListState.Loaded(
|
||||
recentBills = recentBillsEntity,
|
||||
billerGroups =
|
||||
(billerListState.value as BillerListState.Loaded).billerGroups,
|
||||
popularBillers =
|
||||
(billerListState.value as BillerListState.Loaded).popularBillers,
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun createLoadedStateFromBillerResponse(
|
||||
billerListResponse: RepoResult<BillerListResponse>
|
||||
): BillerListState.Loaded {
|
||||
|
||||
@@ -12,23 +12,29 @@ import androidx.lifecycle.viewModelScope
|
||||
import com.google.firebase.crashlytics.FirebaseCrashlytics
|
||||
import com.navi.base.model.CtaData
|
||||
import com.navi.base.utils.DateUtils.getDateTimeObjectFromEpoch
|
||||
import com.navi.base.utils.EMPTY
|
||||
import com.navi.base.utils.NaviDateFormatter
|
||||
import com.navi.base.utils.NaviNetworkConnectivity
|
||||
import com.navi.base.utils.ResourceProvider
|
||||
import com.navi.base.utils.SPACE
|
||||
import com.navi.base.utils.retry
|
||||
import com.navi.bbps.R
|
||||
import com.navi.bbps.common.CATEGORY_ID_MOBILE_PREPAID
|
||||
import com.navi.bbps.common.DATE_TIME_FORMAT_DATE_MONTH_NAME_YEAR
|
||||
import com.navi.bbps.common.DATE_TIME_FORMAT_DATE_MONTH_NAME_YEAR_COMMA_TIME
|
||||
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.DISPLAYABLE_MOBILE_NUMBER_KEY
|
||||
import com.navi.bbps.common.NaviBbpsAnalytics
|
||||
import com.navi.bbps.common.NaviBbpsScreen
|
||||
import com.navi.bbps.common.RETRY_INTERVAL_IN_SECONDS
|
||||
import com.navi.bbps.common.model.NaviBbpsVmData
|
||||
import com.navi.bbps.common.model.config.NaviBbpsDefaultConfig
|
||||
import com.navi.bbps.common.repository.BbpsCommonRepository
|
||||
import com.navi.bbps.common.usecase.NaviBbpsConfigUseCase
|
||||
import com.navi.bbps.common.utils.NaviBbpsCommonUtils
|
||||
import com.navi.bbps.common.utils.NaviBbpsCommonUtils.getBbpsMetricInfo
|
||||
import com.navi.bbps.common.utils.NaviBbpsCommonUtils.isRechargeCategory
|
||||
import com.navi.bbps.common.utils.NaviBbpsDateUtils
|
||||
import com.navi.bbps.common.utils.getDefaultConfig
|
||||
import com.navi.bbps.common.utils.getDisplayableAmount
|
||||
@@ -36,6 +42,7 @@ import com.navi.bbps.common.utils.toBillerAdditionalParamsEntity
|
||||
import com.navi.bbps.common.viewmodel.NaviBbpsBaseVM
|
||||
import com.navi.bbps.feature.billerlist.model.view.BillerItemEntity
|
||||
import com.navi.bbps.feature.billhistorydetail.model.network.TransactionItemResponse
|
||||
import com.navi.bbps.feature.billhistorydetail.model.view.AmountInfoData
|
||||
import com.navi.bbps.feature.billhistorydetail.model.view.BillTransactionItemEntity
|
||||
import com.navi.bbps.feature.billhistorydetail.model.view.BillTransactionsState
|
||||
import com.navi.bbps.feature.billhistorydetail.model.view.MyBillDetailsBottomSheetType
|
||||
@@ -54,23 +61,34 @@ import com.navi.bbps.feature.destinations.BbpsTransactionDetailsScreenDestinatio
|
||||
import com.navi.bbps.feature.destinations.CustomerDataInputScreenDestination
|
||||
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
|
||||
import com.navi.bbps.feature.mybills.MyBillsViewModel.SnackBarState
|
||||
import com.navi.bbps.feature.mybills.model.view.MyBillEntity
|
||||
import com.navi.bbps.feature.paybill.model.view.PayBillSource
|
||||
import com.navi.bbps.feature.prepaidrecharge.model.view.OperatorItemEntity
|
||||
import com.navi.bbps.feature.prepaidrecharge.model.view.PlanItemEntity
|
||||
import com.navi.bbps.isPrepaidRechargePaidOrWithoutPlanDetails
|
||||
import com.navi.bbps.isRedirectToCustomerInputRequired
|
||||
import com.navi.common.di.CoroutineDispatcherProvider
|
||||
import com.navi.common.extensions.or
|
||||
import com.navi.common.network.models.RepoResult
|
||||
import com.navi.common.network.models.isSuccessWithData
|
||||
import com.navi.common.upi.AMOUNT
|
||||
import com.navi.pay.R as NaviPayR
|
||||
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.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.flow.update
|
||||
@@ -91,12 +109,17 @@ constructor(
|
||||
private val stringResouceProvider: ResourceProvider,
|
||||
private val naviBbpsConfigUseCase: NaviBbpsConfigUseCase,
|
||||
private val resourceProvider: ResourceProvider,
|
||||
private val myBillsRepository: MyBillsRepository,
|
||||
private val myBillsSyncJob: MyBillsSyncJob,
|
||||
) :
|
||||
NaviBbpsBaseVM(
|
||||
naviBbpsVmData = NaviBbpsVmData(screen = NaviBbpsScreen.NAVI_BBPS_MY_BILL_HISTORY_DETAILS)
|
||||
) {
|
||||
|
||||
private val myBillEntity = savedStateHandle.get<MyBillEntity>("myBillEntity")!!
|
||||
private val _myBillEntity =
|
||||
MutableStateFlow(savedStateHandle.get<MyBillEntity>("myBillEntity")!!)
|
||||
|
||||
val myBillEntity = _myBillEntity.asStateFlow()
|
||||
|
||||
private val source = savedStateHandle.get<String>("source").orEmpty()
|
||||
|
||||
@@ -124,6 +147,9 @@ constructor(
|
||||
private val _isLoading = MutableStateFlow(true)
|
||||
val isLoading = _isLoading.asStateFlow()
|
||||
|
||||
private val _snackBarState = MutableStateFlow(SnackBarState(show = false))
|
||||
val snackBarState = _snackBarState.asStateFlow()
|
||||
|
||||
private var naviBbpsDefaultConfig = NaviBbpsDefaultConfig()
|
||||
|
||||
private val naviBbpsAnalytics: NaviBbpsAnalytics.MyBillHistoryDetails =
|
||||
@@ -165,22 +191,37 @@ constructor(
|
||||
naviBbpsConfigUseCase.getDefaultConfig(naviBbpsVmData.screen.screenName)
|
||||
}
|
||||
}
|
||||
updateSavedBillAsFlow()
|
||||
}
|
||||
|
||||
private fun updateSavedBillAsFlow() {
|
||||
viewModelScope.launch(dispatcherProvider.io) {
|
||||
myBillsRepository
|
||||
.fetchSavedBillsByCategoryAsFlow(myBillEntity.value.categoryId)
|
||||
.distinctUntilChanged()
|
||||
.collectLatest {
|
||||
val savedBill = it.find { it.billId == myBillEntity.value.billId }
|
||||
savedBill?.let { _myBillEntity.update { savedBill } }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getDisplayableCustomerParams(): Map<String, String> {
|
||||
return if (myBillEntity.categoryId.equals(CATEGORY_ID_MOBILE_PREPAID, ignoreCase = true)) {
|
||||
mapOf(DISPLAYABLE_MOBILE_NUMBER_KEY to myBillEntity.primaryCustomerParamValue)
|
||||
return if (
|
||||
myBillEntity.value.categoryId.equals(CATEGORY_ID_MOBILE_PREPAID, ignoreCase = true)
|
||||
) {
|
||||
mapOf(DISPLAYABLE_MOBILE_NUMBER_KEY to myBillEntity.value.primaryCustomerParamValue)
|
||||
} else {
|
||||
myBillEntity.customerParams
|
||||
myBillEntity.value.customerParams
|
||||
}
|
||||
}
|
||||
|
||||
fun fetchBillHistoryList() {
|
||||
viewModelScope.launch(dispatcherProvider.io) {
|
||||
if (myBillEntity.billId.isNullOrEmpty()) {
|
||||
if (myBillEntity.value.billId.isNullOrEmpty()) {
|
||||
_billHistoryDetailsState.update {
|
||||
BillTransactionsState.createEmptyState(
|
||||
categoryId = myBillEntity.categoryId,
|
||||
categoryId = myBillEntity.value.categoryId,
|
||||
billHistoryEmptyStateConfig =
|
||||
naviBbpsDefaultConfig.billHistoryEmptyStateConfig,
|
||||
)
|
||||
@@ -189,7 +230,7 @@ constructor(
|
||||
}
|
||||
val billTransactionsResponse =
|
||||
billHistoryDetailsRepository.fetchBillTransactions(
|
||||
savedBillId = myBillEntity.billId,
|
||||
savedBillId = myBillEntity.value.billId,
|
||||
metricInfo = getBbpsMetricInfo(screenName = naviBbpsVmData.screen.screenName),
|
||||
)
|
||||
if (billTransactionsResponse.isSuccessWithData()) {
|
||||
@@ -197,7 +238,7 @@ constructor(
|
||||
_billHistoryDetailsState.update {
|
||||
if (transactions.isEmpty()) {
|
||||
BillTransactionsState.createEmptyState(
|
||||
categoryId = myBillEntity.categoryId,
|
||||
categoryId = myBillEntity.value.categoryId,
|
||||
billHistoryEmptyStateConfig =
|
||||
naviBbpsDefaultConfig.billHistoryEmptyStateConfig,
|
||||
)
|
||||
@@ -209,7 +250,7 @@ constructor(
|
||||
}
|
||||
contactNameForMobileNumber =
|
||||
getCustomerNameForMobileNumber(
|
||||
primaryCustomerParamValue = myBillEntity.primaryCustomerParamValue
|
||||
primaryCustomerParamValue = myBillEntity.value.primaryCustomerParamValue
|
||||
)
|
||||
} else {
|
||||
_billHistoryDetailsState.update { BillTransactionsState.Error }
|
||||
@@ -258,7 +299,7 @@ constructor(
|
||||
formattedAmount = amount.getDisplayableAmount(),
|
||||
netAmountAfterDiscount = "",
|
||||
planName = planName ?: "",
|
||||
primaryCustomerParamValue = myBillEntity.primaryCustomerParamValue,
|
||||
primaryCustomerParamValue = myBillEntity.value.primaryCustomerParamValue,
|
||||
billDate =
|
||||
if (billDate.isNullOrBlank()) ""
|
||||
else
|
||||
@@ -289,13 +330,17 @@ constructor(
|
||||
_myBillDetailsBottomSheetType.update { MyBillDetailsBottomSheetType.MenuOptions }
|
||||
}
|
||||
|
||||
fun updateSnackBarState(show: Boolean, messageId: Int = R.string.bbps_copied_to_clipboard) {
|
||||
_snackBarState.update { SnackBarState(show = show, messageId = messageId) }
|
||||
}
|
||||
|
||||
fun onTransactionItemClicked(billTransactionItemEntity: BillTransactionItemEntity) {
|
||||
viewModelScope.launch(dispatcherProvider.io) {
|
||||
updateNextScreenDestinationState(
|
||||
BbpsTransactionDetailsScreenDestination(
|
||||
billTransactionItemEntity = billTransactionItemEntity,
|
||||
myBillEntity =
|
||||
myBillEntity.copy(customerParams = getDisplayableCustomerParams()),
|
||||
myBillEntity.value.copy(customerParams = getDisplayableCustomerParams()),
|
||||
source = NaviBbpsScreen.NAVI_BBPS_MY_BILL_HISTORY_DETAILS.name,
|
||||
initialSource = initialSource,
|
||||
)
|
||||
@@ -303,6 +348,61 @@ constructor(
|
||||
}
|
||||
}
|
||||
|
||||
fun getNextActionFooterCtaText(): String {
|
||||
val billState = myBillEntity.value
|
||||
val categoryId = billState.categoryId
|
||||
|
||||
return when {
|
||||
billState.isBillPaid -> {
|
||||
if (categoryId == CATEGORY_ID_MOBILE_PREPAID) {
|
||||
resourceProvider.getString(R.string.bbps_view_all_plans)
|
||||
} else {
|
||||
resourceProvider.getString(R.string.bbps_pay_bill_in_advance)
|
||||
}
|
||||
}
|
||||
|
||||
billState.nextActionCtaText.isNotBlank() -> {
|
||||
billState.nextActionCtaText
|
||||
}
|
||||
|
||||
isRechargeCategory(categoryId) -> {
|
||||
resourceProvider.getString(R.string.bbps_recharge)
|
||||
}
|
||||
|
||||
else -> {
|
||||
resourceProvider.getString(R.string.bbps_pay_bill_in_advance)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getAmountInfoFooterText(): AmountInfoData? {
|
||||
val isRechargeCategory = isRechargeCategory(categoryId = myBillEntity.value.categoryId)
|
||||
return when {
|
||||
isRechargeCategory && !myBillEntity.value.formattedLastPaidAmount.isBlank() -> {
|
||||
AmountInfoData(
|
||||
amountPrefixText =
|
||||
resourceProvider.getString(resId = R.string.bbps_last_recharged, AMOUNT),
|
||||
amount = myBillEntity.value.formattedLastPaidAmount,
|
||||
)
|
||||
}
|
||||
!isRechargeCategory &&
|
||||
!myBillEntity.value.unpaidBillDetails?.amount.isNullOrEmpty() -> {
|
||||
AmountInfoData(
|
||||
amountPrefixText =
|
||||
myBillEntity.value.categoryName +
|
||||
SPACE +
|
||||
resourceProvider.getString(resId = R.string.bbps_bill_amount),
|
||||
amount =
|
||||
myBillEntity.value.unpaidBillDetails
|
||||
?.amount
|
||||
?.getDisplayableAmount()
|
||||
.orEmpty(),
|
||||
)
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
fun onDeleteBillMenuClicked(deleteBill: () -> Unit) {
|
||||
_myBillDetailsBottomSheetType.update {
|
||||
MyBillDetailsBottomSheetType.Confirmation(
|
||||
@@ -316,6 +416,55 @@ constructor(
|
||||
}
|
||||
}
|
||||
|
||||
fun onMarkAsPaidClicked() {
|
||||
_myBillDetailsBottomSheetType.update {
|
||||
MyBillDetailsBottomSheetType.Confirmation(
|
||||
title = resourceProvider.getString(R.string.bbps_bill_mark_as_paid_heading),
|
||||
description =
|
||||
resourceProvider.getString(R.string.bbps_bill_mark_as_paid_description),
|
||||
firstBtnTextResId = R.string.bbps_no,
|
||||
secondButtonTextResId = R.string.bbps_yes,
|
||||
onFirstBtnClick = {},
|
||||
onSecondBtnClick = { onMarkBillAsPaidConfirmedCtaClicked(myBillEntity.value) },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun onMarkBillAsPaidConfirmedCtaClicked(myBillEntity: MyBillEntity) {
|
||||
viewModelScope.launch(dispatcherProvider.io) {
|
||||
delay(50) // before this bottom sheet is getting closed, added for smoother
|
||||
// transition
|
||||
if (!naviNetworkConnectivity.isInternetConnected()) {
|
||||
notifyError(getNoInternetErrorConfig())
|
||||
return@launch
|
||||
}
|
||||
val response =
|
||||
retry(
|
||||
retryCount = DEFAULT_RETRY_COUNT,
|
||||
retryIntervalInSeconds = RETRY_INTERVAL_IN_SECONDS,
|
||||
execute = {
|
||||
myBillsRepository.markBillAsPaid(
|
||||
myBillEntity.billId,
|
||||
metricInfo =
|
||||
getBbpsMetricInfo(
|
||||
screenName = naviBbpsVmData.screen.screenName,
|
||||
isNae = { false },
|
||||
),
|
||||
)
|
||||
},
|
||||
shouldRetry = { !it.isSuccessWithData() },
|
||||
)
|
||||
|
||||
if (response.isSuccessWithData()) {
|
||||
updateSnackBarState(show = true, messageId = R.string.bbps_bill_marked_as_paid)
|
||||
|
||||
_myBillEntity.update { it.copy(isBillPaid = true) }
|
||||
myBillsSyncJob.refreshBillsAsync(screenName = naviBbpsVmData.screen.screenName)
|
||||
billResponse = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateNewBillFetchingState(isInProgress: Boolean) {
|
||||
_isFetchingNewBill.update { isInProgress }
|
||||
}
|
||||
@@ -326,8 +475,8 @@ constructor(
|
||||
) {
|
||||
val billCategoryEntity =
|
||||
BillCategoryEntity(
|
||||
categoryId = myBillEntity.categoryId,
|
||||
title = myBillEntity.categoryName,
|
||||
categoryId = myBillEntity.value.categoryId,
|
||||
title = myBillEntity.value.categoryName,
|
||||
iconUrl = "",
|
||||
searchBoxPlaceholderText = "",
|
||||
billerListStateHeading = "",
|
||||
@@ -361,39 +510,101 @@ constructor(
|
||||
billPeriod = billDetails.billPeriod.orEmpty(),
|
||||
)
|
||||
|
||||
val payBillSource =
|
||||
PayBillSource.Others(
|
||||
billerDetailsEntity = billerDetails,
|
||||
billDetailsEntity = billDetailsEntity,
|
||||
customerParams = myBillEntity.customerParams,
|
||||
billerId = myBillEntity.billerId,
|
||||
amount = billDetails.amount,
|
||||
formattedLastPaidDate = myBillEntity.formattedLastPaidDate,
|
||||
formattedLastPaidAmount = myBillEntity.formattedLastPaidAmount,
|
||||
isConsentRequired = myBillEntity.isConsentRequired,
|
||||
)
|
||||
|
||||
val phoneNumberDetail =
|
||||
PhoneContactEntity(
|
||||
name = myBillEntity.billerName,
|
||||
phoneNumber = myBillEntity.primaryCustomerParamValue,
|
||||
normalisedPhoneNumber = myBillEntity.primaryCustomerParamValue,
|
||||
name = myBillEntity.value.billerName,
|
||||
phoneNumber = myBillEntity.value.primaryCustomerParamValue,
|
||||
normalisedPhoneNumber = myBillEntity.value.primaryCustomerParamValue,
|
||||
)
|
||||
|
||||
val source = NaviBbpsScreen.NAVI_BBPS_MY_BILL_HISTORY_DETAILS.name
|
||||
if (billCategoryEntity.categoryId == CATEGORY_ID_MOBILE_PREPAID) {
|
||||
val planItemEntity =
|
||||
PlanItemEntity(
|
||||
planName =
|
||||
myBillEntity.value.unpaidBillDetails
|
||||
?.planItemDetails
|
||||
?.get("planName")
|
||||
.orEmpty(),
|
||||
price =
|
||||
myBillEntity.value.unpaidBillDetails
|
||||
?.planItemDetails
|
||||
?.get("price")
|
||||
.orEmpty(),
|
||||
validity =
|
||||
myBillEntity.value.unpaidBillDetails
|
||||
?.planItemDetails
|
||||
?.get("validity")
|
||||
.orEmpty(),
|
||||
talkTime =
|
||||
myBillEntity.value.unpaidBillDetails
|
||||
?.planItemDetails
|
||||
?.get("talkTime")
|
||||
.orEmpty(),
|
||||
packageDescription =
|
||||
myBillEntity.value.unpaidBillDetails
|
||||
?.planItemDetails
|
||||
?.get("packageDescription")
|
||||
.orEmpty(),
|
||||
)
|
||||
|
||||
val destination =
|
||||
PayBillScreenDestination(
|
||||
billCategoryEntity = billCategoryEntity,
|
||||
payBillScreenSource = payBillSource,
|
||||
phoneNumberDetail = phoneNumberDetail,
|
||||
isRootScreen = isRootScreen,
|
||||
source = source,
|
||||
initialSource = initialSource,
|
||||
isBillSyncRequiredInBackground = false,
|
||||
val operatorItemEntity =
|
||||
OperatorItemEntity(
|
||||
operatorLogoUrl = billerDetails.billerLogoUrl,
|
||||
operatorCode = EMPTY,
|
||||
operatorName = myBillEntity.value.billerName,
|
||||
billerId = billerDetails.billerId,
|
||||
)
|
||||
|
||||
val payBillSource =
|
||||
PayBillSource.Prepaid(
|
||||
planItemEntity = planItemEntity,
|
||||
billDetailsEntity = billDetailsEntity,
|
||||
operatorItemEntity = operatorItemEntity,
|
||||
customerParams = myBillEntity.value.customerParams,
|
||||
billerId = billerDetails.billerId,
|
||||
amount = billDetailsEntity.amount.orEmpty(),
|
||||
formattedLastPaidDate = myBillEntity.value.formattedLastPaidDate,
|
||||
formattedLastPaidAmount = myBillEntity.value.formattedLastPaidAmount,
|
||||
)
|
||||
|
||||
_navigateToNextScreen.emit(
|
||||
PayBillScreenDestination(
|
||||
billCategoryEntity = billCategoryEntity,
|
||||
payBillScreenSource = payBillSource,
|
||||
phoneNumberDetail = phoneNumberDetail,
|
||||
isRootScreen = isRootScreen,
|
||||
source = source,
|
||||
initialSource = initialSource,
|
||||
)
|
||||
)
|
||||
} else {
|
||||
val payBillSource =
|
||||
PayBillSource.Others(
|
||||
billerDetailsEntity = billerDetails,
|
||||
billDetailsEntity = billDetailsEntity,
|
||||
customerParams = myBillEntity.value.customerParams,
|
||||
billerId = myBillEntity.value.billerId,
|
||||
amount = billDetails.amount,
|
||||
formattedLastPaidDate = myBillEntity.value.formattedLastPaidDate,
|
||||
formattedLastPaidAmount = myBillEntity.value.formattedLastPaidAmount,
|
||||
isConsentRequired = myBillEntity.value.isConsentRequired,
|
||||
)
|
||||
|
||||
_navigateToNextScreen.emit(destination)
|
||||
val source = NaviBbpsScreen.NAVI_BBPS_MY_BILL_HISTORY_DETAILS.name
|
||||
|
||||
val destination =
|
||||
PayBillScreenDestination(
|
||||
billCategoryEntity = billCategoryEntity,
|
||||
payBillScreenSource = payBillSource,
|
||||
phoneNumberDetail = phoneNumberDetail,
|
||||
isRootScreen = isRootScreen,
|
||||
source = source,
|
||||
initialSource = initialSource,
|
||||
isBillSyncRequiredInBackground = false,
|
||||
)
|
||||
|
||||
_navigateToNextScreen.emit(destination)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun updateNextScreenDestinationState(direction: Direction) {
|
||||
@@ -402,19 +613,19 @@ constructor(
|
||||
|
||||
fun onPayNowClicked() {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
if (myBillEntity.categoryId == CATEGORY_ID_MOBILE_PREPAID) {
|
||||
if (myBillEntity.value.isPrepaidRechargePaidOrWithoutPlanDetails()) {
|
||||
updateNextScreenDestinationState(
|
||||
PrepaidRechargeScreenDestination(
|
||||
phoneNumberDetail =
|
||||
PhoneContactEntity(
|
||||
name = contactNameForMobileNumber,
|
||||
phoneNumber = myBillEntity.primaryCustomerParamValue,
|
||||
normalisedPhoneNumber = myBillEntity.primaryCustomerParamValue,
|
||||
phoneNumber = myBillEntity.value.primaryCustomerParamValue,
|
||||
normalisedPhoneNumber = myBillEntity.value.primaryCustomerParamValue,
|
||||
),
|
||||
billCategoryEntity =
|
||||
BillCategoryEntity(
|
||||
categoryId = myBillEntity.categoryId,
|
||||
title = myBillEntity.categoryName,
|
||||
categoryId = myBillEntity.value.categoryId,
|
||||
title = myBillEntity.value.categoryName,
|
||||
iconUrl = "",
|
||||
searchBoxPlaceholderText = "",
|
||||
billerListStateHeading = "",
|
||||
@@ -424,19 +635,19 @@ constructor(
|
||||
initialSource = initialSource,
|
||||
)
|
||||
)
|
||||
} else if (myBillEntity.isRedirectToCustomerInputRequired()) {
|
||||
} else if (myBillEntity.value.isRedirectToCustomerInputRequired()) {
|
||||
goToCustomerDataInputScreen()
|
||||
} else {
|
||||
updateNewBillFetchingState(isInProgress = true)
|
||||
val billerDetails =
|
||||
BillerDetailsEntity(
|
||||
billerId = myBillEntity.billerId,
|
||||
billerName = myBillEntity.billerName,
|
||||
billerLogoUrl = myBillEntity.billerLogoUrl,
|
||||
status = myBillEntity.status,
|
||||
isAdhoc = myBillEntity.isAdhoc,
|
||||
fetchOption = myBillEntity.fetchOption,
|
||||
paymentAmountExactness = myBillEntity.paymentAmountExactness,
|
||||
billerId = myBillEntity.value.billerId,
|
||||
billerName = myBillEntity.value.billerName,
|
||||
billerLogoUrl = myBillEntity.value.billerLogoUrl,
|
||||
status = myBillEntity.value.status,
|
||||
isAdhoc = myBillEntity.value.isAdhoc,
|
||||
fetchOption = myBillEntity.value.fetchOption,
|
||||
paymentAmountExactness = myBillEntity.value.paymentAmountExactness,
|
||||
)
|
||||
|
||||
if (billResponse?.isSuccessWithData() == true) {
|
||||
@@ -458,24 +669,24 @@ constructor(
|
||||
CustomerDataInputScreenDestination(
|
||||
billerItemEntity =
|
||||
BillerItemEntity(
|
||||
billerId = myBillEntity.billerId,
|
||||
billerName = myBillEntity.billerName,
|
||||
billerLogoUrl = myBillEntity.billerLogoUrl,
|
||||
status = myBillEntity.status,
|
||||
isAdhoc = myBillEntity.isAdhoc,
|
||||
billerId = myBillEntity.value.billerId,
|
||||
billerName = myBillEntity.value.billerName,
|
||||
billerLogoUrl = myBillEntity.value.billerLogoUrl,
|
||||
status = myBillEntity.value.status,
|
||||
isAdhoc = myBillEntity.value.isAdhoc,
|
||||
state = "",
|
||||
region = "",
|
||||
categoryId = myBillEntity.categoryId,
|
||||
categoryId = myBillEntity.value.categoryId,
|
||||
isPopular = false,
|
||||
),
|
||||
customerParamsExtraData =
|
||||
CustomerParamsExtraData(
|
||||
existingCustomerParams = myBillEntity.customerParams
|
||||
existingCustomerParams = myBillEntity.value.customerParams
|
||||
),
|
||||
billCategoryEntity =
|
||||
BillCategoryEntity(
|
||||
categoryId = myBillEntity.categoryId,
|
||||
title = myBillEntity.categoryName,
|
||||
categoryId = myBillEntity.value.categoryId,
|
||||
title = myBillEntity.value.categoryName,
|
||||
iconUrl = "",
|
||||
searchBoxPlaceholderText = "",
|
||||
billerListStateHeading = "",
|
||||
@@ -490,23 +701,23 @@ constructor(
|
||||
}
|
||||
|
||||
private suspend fun fetchBillDetailsResponse(): RepoResult<BillDetailsResponse> {
|
||||
naviBbpsAnalytics.onLoaded(myBillEntity = myBillEntity)
|
||||
naviBbpsAnalytics.onLoaded(myBillEntity = myBillEntity.value)
|
||||
|
||||
val billerDetails =
|
||||
BillerDetailsEntity(
|
||||
billerId = myBillEntity.billerId,
|
||||
billerName = myBillEntity.billerName,
|
||||
billerLogoUrl = myBillEntity.billerLogoUrl,
|
||||
status = myBillEntity.status,
|
||||
isAdhoc = myBillEntity.isAdhoc,
|
||||
fetchOption = myBillEntity.fetchOption,
|
||||
paymentAmountExactness = myBillEntity.paymentAmountExactness,
|
||||
billerId = myBillEntity.value.billerId,
|
||||
billerName = myBillEntity.value.billerName,
|
||||
billerLogoUrl = myBillEntity.value.billerLogoUrl,
|
||||
status = myBillEntity.value.status,
|
||||
isAdhoc = myBillEntity.value.isAdhoc,
|
||||
fetchOption = myBillEntity.value.fetchOption,
|
||||
paymentAmountExactness = myBillEntity.value.paymentAmountExactness,
|
||||
)
|
||||
|
||||
val billDetailsRequest =
|
||||
BillDetailsRequest(
|
||||
billerId = billerDetails.billerId,
|
||||
customerParams = myBillEntity.customerParams,
|
||||
customerParams = myBillEntity.value.customerParams,
|
||||
deviceDetails = DeviceDetails(ip = naviNetworkConnectivity.getIpAddress()),
|
||||
isConsentProvided = false,
|
||||
)
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright © 2025 by Navi Technologies Limited
|
||||
* * All rights reserved. Strictly confidential
|
||||
*
|
||||
*/
|
||||
|
||||
package com.navi.bbps.feature.billhistorydetail.model.view
|
||||
|
||||
data class AmountInfoData(val amountPrefixText: String, val amount: String)
|
||||
@@ -10,6 +10,8 @@ package com.navi.bbps.feature.billhistorydetail.ui
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
@@ -19,6 +21,7 @@ import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.imePadding
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.ModalBottomSheetValue
|
||||
import androidx.compose.material.rememberModalBottomSheetState
|
||||
import androidx.compose.material3.Scaffold
|
||||
@@ -30,6 +33,8 @@ import androidx.compose.runtime.rememberCoroutineScope
|
||||
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.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
@@ -41,6 +46,7 @@ import androidx.lifecycle.compose.LocalLifecycleOwner
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.navi.base.utils.EMPTY
|
||||
import com.navi.base.utils.SPACE
|
||||
import com.navi.base.utils.orTrue
|
||||
import com.navi.bbps.R
|
||||
import com.navi.bbps.common.BULLET
|
||||
import com.navi.bbps.common.NaviBbpsAnalytics
|
||||
@@ -51,12 +57,15 @@ import com.navi.bbps.common.ui.BbpsCircleImage
|
||||
import com.navi.bbps.common.ui.DisplayAccountHolderNameAndPrimaryCustomerParamValue
|
||||
import com.navi.bbps.common.ui.NaviBbpsHeader
|
||||
import com.navi.bbps.common.ui.NaviBbpsModalBottomSheetLayout
|
||||
import com.navi.bbps.common.ui.SecondaryRoundedButton
|
||||
import com.navi.bbps.common.ui.SetStatusBarColor
|
||||
import com.navi.bbps.common.utils.NaviBbpsCommonUtils.isRechargeCategory
|
||||
import com.navi.bbps.common.utils.SnackBarPredefinedConfig
|
||||
import com.navi.bbps.entry.NaviBbpsActivity
|
||||
import com.navi.bbps.entry.NaviBbpsRouter
|
||||
import com.navi.bbps.feature.billhistorydetail.BillHistoryDetailsViewModel
|
||||
import com.navi.bbps.feature.billhistorydetail.model.view.AmountInfoData
|
||||
import com.navi.bbps.feature.billhistorydetail.model.view.BillTransactionItemEntity
|
||||
import com.navi.bbps.feature.billhistorydetail.model.view.BillTransactionsState
|
||||
import com.navi.bbps.feature.mybills.model.view.MyBillEntity
|
||||
import com.navi.common.R as CommonR
|
||||
import com.navi.common.customview.LoaderRoundedButton
|
||||
@@ -65,8 +74,10 @@ import com.navi.common.navigation.setResultAndNavigateBack
|
||||
import com.navi.design.font.FontWeightEnum
|
||||
import com.navi.design.font.getFontWeight
|
||||
import com.navi.design.font.naviFontFamily
|
||||
import com.navi.design.snackbar.SuccessSnackBar
|
||||
import com.navi.design.utils.clickableWithNoGesture
|
||||
import com.navi.naviwidgets.extensions.NaviText
|
||||
import com.navi.payment.nativepayment.components.BottomBarShadow
|
||||
import com.ramcosta.composedestinations.annotation.Destination
|
||||
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
|
||||
import com.ramcosta.composedestinations.result.ResultBackNavigator
|
||||
@@ -139,6 +150,8 @@ fun MyBillHistoryDetailsScreen(
|
||||
billHistoryDetailsViewModel.myBillDetailsBottomSheetType.collectAsStateWithLifecycle()
|
||||
val isUserActionBlocked by
|
||||
billHistoryDetailsViewModel.isUserActionBlocked.collectAsStateWithLifecycle()
|
||||
val snackBarState by billHistoryDetailsViewModel.snackBarState.collectAsStateWithLifecycle()
|
||||
val myBillEntityState by billHistoryDetailsViewModel.myBillEntity.collectAsStateWithLifecycle()
|
||||
|
||||
val onTransactionItemClicked = { billTransactionItemEntity: BillTransactionItemEntity ->
|
||||
naviBbpsAnalytics.onTransactionItemClicked(
|
||||
@@ -207,12 +220,14 @@ fun MyBillHistoryDetailsScreen(
|
||||
myBillDetailsBottomSheetType = myBillDetailsBottomSheetType,
|
||||
onDeleteBillMenuClicked = {
|
||||
naviBbpsAnalytics.onDeleteMenuClicked(
|
||||
myBillEntity = myBillEntity,
|
||||
myBillEntity = myBillEntityState,
|
||||
source = source,
|
||||
initialSource = initialSource,
|
||||
)
|
||||
billHistoryDetailsViewModel.onDeleteBillMenuClicked {
|
||||
naviBbpsActivity.navController.setResultAndNavigateBack(myBillEntity.billId)
|
||||
naviBbpsActivity.navController.setResultAndNavigateBack(
|
||||
myBillEntityState.billId
|
||||
)
|
||||
}
|
||||
openSheet()
|
||||
naviBbpsAnalytics.onBottomSheetLanded(
|
||||
@@ -233,11 +248,11 @@ fun MyBillHistoryDetailsScreen(
|
||||
topBar = {
|
||||
MyBillsHistoryHeader(
|
||||
navigator = navigator,
|
||||
myBillEntity = myBillEntity,
|
||||
myBillEntity = myBillEntityState,
|
||||
isMenuButtonEnabled = isUserActionBlocked.not(),
|
||||
onMoreOptionsClicked = {
|
||||
naviBbpsAnalytics.onKebabMenuClicked(
|
||||
myBillEntity,
|
||||
myBillEntityState,
|
||||
source = source,
|
||||
initialSource = initialSource,
|
||||
)
|
||||
@@ -255,58 +270,72 @@ fun MyBillHistoryDetailsScreen(
|
||||
)
|
||||
},
|
||||
content = { innerPadding ->
|
||||
Column(
|
||||
modifier =
|
||||
Modifier.fillMaxSize()
|
||||
.background(color = NaviBbpsColor.bgDefault)
|
||||
.padding(innerPadding)
|
||||
Box(
|
||||
Modifier.padding(innerPadding).fillMaxSize().background(NaviBbpsColor.textWhite)
|
||||
) {
|
||||
BillTransactionsListView(
|
||||
billHistoryDetailsState = billHistoryDetailsState,
|
||||
myBillEntity = myBillEntity,
|
||||
onItemClicked = onTransactionItemClicked,
|
||||
recordScreenRenderTime = {
|
||||
billHistoryDetailsViewModel.recordScreenRenderTime(
|
||||
billHistoryDetailsViewModel.naviBbpsVmData.screen.screenName,
|
||||
ModuleNameV2.BBPS.name,
|
||||
)
|
||||
Column(
|
||||
modifier =
|
||||
Modifier.fillMaxWidth().background(color = NaviBbpsColor.bgDefault)
|
||||
) {
|
||||
BillTransactionsListView(
|
||||
billHistoryDetailsState = billHistoryDetailsState,
|
||||
myBillEntity = myBillEntityState,
|
||||
onItemClicked = onTransactionItemClicked,
|
||||
recordScreenRenderTime = {
|
||||
billHistoryDetailsViewModel.recordScreenRenderTime(
|
||||
billHistoryDetailsViewModel.naviBbpsVmData.screen.screenName,
|
||||
ModuleNameV2.BBPS.name,
|
||||
)
|
||||
},
|
||||
recordApiEndTime = {
|
||||
billHistoryDetailsViewModel.recordApiEndTime(
|
||||
billHistoryDetailsViewModel.naviBbpsVmData.screen.screenName
|
||||
)
|
||||
},
|
||||
getTransactionStatusDisplayText =
|
||||
billHistoryDetailsViewModel::getTransactionStatusDisplayText,
|
||||
)
|
||||
}
|
||||
BottomBarShadow(shadowHeight = 32.dp)
|
||||
}
|
||||
},
|
||||
snackbarHost = {
|
||||
if (snackBarState.show) {
|
||||
SuccessSnackBar(
|
||||
modifier = Modifier.padding(horizontal = 16.dp, vertical = 32.dp),
|
||||
show = true,
|
||||
snackBarConfig =
|
||||
SnackBarPredefinedConfig.successConfig(
|
||||
title = stringResource(id = snackBarState.messageId),
|
||||
trailingIconResId = null,
|
||||
),
|
||||
onDismissed = {
|
||||
billHistoryDetailsViewModel.updateSnackBarState(show = false)
|
||||
},
|
||||
recordApiEndTime = {
|
||||
billHistoryDetailsViewModel.recordApiEndTime(
|
||||
billHistoryDetailsViewModel.naviBbpsVmData.screen.screenName
|
||||
)
|
||||
},
|
||||
getTransactionStatusDisplayText =
|
||||
billHistoryDetailsViewModel::getTransactionStatusDisplayText,
|
||||
)
|
||||
}
|
||||
},
|
||||
bottomBar = {
|
||||
val nextCtaText =
|
||||
when (billHistoryDetailsState) {
|
||||
is BillTransactionsState.Empty ->
|
||||
(billHistoryDetailsState as BillTransactionsState.Empty)
|
||||
.emptyStateEntity
|
||||
.ctaText
|
||||
else -> myBillEntity.nextActionCtaText
|
||||
}
|
||||
LoaderRoundedButton(
|
||||
text = nextCtaText,
|
||||
onClick = {
|
||||
naviBbpsAnalytics.onPayNowClicked(
|
||||
myBillEntity,
|
||||
source = source,
|
||||
initialSource = initialSource,
|
||||
)
|
||||
billHistoryDetailsViewModel.onPayNowClicked()
|
||||
},
|
||||
enabled = !isUserActionBlocked,
|
||||
showLoader = isUserActionBlocked,
|
||||
modifier =
|
||||
Modifier.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp, vertical = 32.dp)
|
||||
.height(48.dp),
|
||||
)
|
||||
Column(modifier = Modifier.fillMaxWidth().background(NaviBbpsColor.textWhite)) {
|
||||
MyBillsHistoryFooter(
|
||||
myBillEntity = myBillEntityState,
|
||||
onMarkAsPaidClicked = {
|
||||
billHistoryDetailsViewModel.onMarkAsPaidClicked()
|
||||
openSheet()
|
||||
},
|
||||
onPrimaryButtonClicked = {
|
||||
naviBbpsAnalytics.onPayNowClicked(
|
||||
myBillEntityState,
|
||||
source = source,
|
||||
initialSource = initialSource,
|
||||
)
|
||||
billHistoryDetailsViewModel.onPayNowClicked()
|
||||
},
|
||||
isUserActionBlocked = isUserActionBlocked,
|
||||
nextCtaText = billHistoryDetailsViewModel.getNextActionFooterCtaText(),
|
||||
amountInfoData = billHistoryDetailsViewModel.getAmountInfoFooterText(),
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
@@ -396,3 +425,146 @@ private fun MyBillsHistoryHeader(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun MyBillsHistoryFooter(
|
||||
myBillEntity: MyBillEntity?,
|
||||
onMarkAsPaidClicked: () -> Unit,
|
||||
onPrimaryButtonClicked: () -> Unit,
|
||||
nextCtaText: String,
|
||||
isUserActionBlocked: Boolean,
|
||||
amountInfoData: AmountInfoData?,
|
||||
) {
|
||||
|
||||
Column(
|
||||
modifier = Modifier.padding(start = 16.dp, end = 16.dp, top = 16.dp, bottom = 32.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
if (myBillEntity?.isBillPaid.orTrue()) {
|
||||
if (!isRechargeCategory(categoryId = myBillEntity?.categoryId.orEmpty())) {
|
||||
NaviText(
|
||||
text = stringResource(id = R.string.bbps_no_bills_due_description),
|
||||
fontSize = 12.sp,
|
||||
lineHeight = 16.sp,
|
||||
color = NaviBbpsColor.textTertiary,
|
||||
fontFamily = naviFontFamily,
|
||||
fontWeight = getFontWeight(FontWeightEnum.NAVI_BODY_REGULAR),
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
textAlign = TextAlign.Center,
|
||||
)
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
}
|
||||
|
||||
LoaderRoundedButton(
|
||||
text = nextCtaText,
|
||||
onClick = onPrimaryButtonClicked,
|
||||
enabled = !isUserActionBlocked,
|
||||
showLoader = isUserActionBlocked,
|
||||
modifier = Modifier.fillMaxWidth().height(48.dp),
|
||||
)
|
||||
} else {
|
||||
amountInfoData?.let { BillAmountInfo(amountInfoData = amountInfoData) }
|
||||
|
||||
if (!myBillEntity?.unpaidBillWarning.isNullOrEmpty()) {
|
||||
Row(
|
||||
modifier =
|
||||
Modifier.fillMaxWidth()
|
||||
.background(
|
||||
color = NaviBbpsColor.bgError,
|
||||
shape =
|
||||
RoundedCornerShape(
|
||||
topStart = 0.dp,
|
||||
topEnd = 0.dp,
|
||||
bottomStart = 4.dp,
|
||||
bottomEnd = 4.dp,
|
||||
),
|
||||
)
|
||||
.padding(vertical = 2.dp),
|
||||
horizontalArrangement = Arrangement.Center,
|
||||
) {
|
||||
NaviText(
|
||||
text = myBillEntity.unpaidBillWarning,
|
||||
fontSize = 12.sp,
|
||||
lineHeight = 18.sp,
|
||||
fontFamily = naviFontFamily,
|
||||
fontWeight = getFontWeight(FontWeightEnum.NAVI_BODY_REGULAR),
|
||||
color = NaviBbpsColor.onSurfaceCritical,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
SecondaryRoundedButton(
|
||||
text = stringResource(id = R.string.bbps_mark_as_paid),
|
||||
onClick = onMarkAsPaidClicked,
|
||||
modifier = Modifier.weight(1f),
|
||||
enabled = !isUserActionBlocked,
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.width(16.dp))
|
||||
|
||||
LoaderRoundedButton(
|
||||
text = nextCtaText,
|
||||
onClick = onPrimaryButtonClicked,
|
||||
enabled = !isUserActionBlocked,
|
||||
showLoader = isUserActionBlocked,
|
||||
modifier = Modifier.weight(1f).height(48.dp),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun BillAmountInfo(amountInfoData: AmountInfoData) {
|
||||
Row(
|
||||
modifier =
|
||||
Modifier.fillMaxWidth()
|
||||
.background(
|
||||
color = NaviBbpsColor.bgAlt,
|
||||
shape =
|
||||
RoundedCornerShape(
|
||||
topStart = 4.dp,
|
||||
topEnd = 4.dp,
|
||||
bottomStart = 0.dp,
|
||||
bottomEnd = 0.dp,
|
||||
),
|
||||
)
|
||||
.padding(vertical = 12.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.Center,
|
||||
) {
|
||||
NaviText(
|
||||
text = amountInfoData.amountPrefixText,
|
||||
fontSize = 14.sp,
|
||||
lineHeight = 22.sp,
|
||||
fontFamily = naviFontFamily,
|
||||
color = NaviBbpsColor.textPrimary,
|
||||
fontWeight = getFontWeight(FontWeightEnum.NAVI_BODY_REGULAR),
|
||||
)
|
||||
|
||||
NaviText(
|
||||
text = BULLET,
|
||||
fontSize = 14.sp,
|
||||
lineHeight = 22.sp,
|
||||
fontFamily = naviFontFamily,
|
||||
fontWeight = getFontWeight(FontWeightEnum.NAVI_BODY_DEMI_BOLD),
|
||||
color = NaviBbpsColor.textPrimary,
|
||||
modifier = Modifier.padding(horizontal = 4.dp),
|
||||
)
|
||||
|
||||
NaviText(
|
||||
text = stringResource(id = R.string.bbps_rupee_symbol_x, amountInfoData.amount),
|
||||
fontSize = 14.sp,
|
||||
lineHeight = 22.sp,
|
||||
fontFamily = naviFontFamily,
|
||||
fontWeight = getFontWeight(FontWeightEnum.NAVI_BODY_DEMI_BOLD),
|
||||
color = NaviBbpsColor.textPrimary,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,6 +83,7 @@ import com.navi.bbps.feature.mybills.model.view.MyBillEntity
|
||||
import com.navi.bbps.feature.paybill.model.view.PayBillSource
|
||||
import com.navi.bbps.feature.prepaidrecharge.model.view.OperatorItemEntity
|
||||
import com.navi.bbps.feature.prepaidrecharge.model.view.PlanItemEntity
|
||||
import com.navi.bbps.isPrepaidRechargePaidOrWithoutPlanDetails
|
||||
import com.navi.bbps.isRedirectToCustomerInputRequired
|
||||
import com.navi.bbps.network.di.NaviBbpsGsonBuilder
|
||||
import com.navi.common.constants.ARC_LOCAL_COUNTER_KEY
|
||||
@@ -516,10 +517,7 @@ constructor(
|
||||
myBillEntityToBillerDetailsEntityMapper.mapMyBillEntityToBillerDetailsEntity(
|
||||
myBillEntity = myBillEntity
|
||||
)
|
||||
if (
|
||||
myBillEntity.unpaidBillDetails?.planItemDetails.isNullOrEmpty() &&
|
||||
myBillEntity.categoryId == CATEGORY_ID_MOBILE_PREPAID
|
||||
) {
|
||||
if (myBillEntity.isPrepaidRechargePaidOrWithoutPlanDetails()) {
|
||||
goToPrepaidRechargeScreen(myBillEntity)
|
||||
} else if (myBillEntity.isRedirectToCustomerInputRequired()) {
|
||||
goToCustomerInputScreen(myBillEntity)
|
||||
|
||||
@@ -56,6 +56,9 @@ import com.navi.bbps.feature.mybills.MyBillsSyncJob
|
||||
import com.navi.bbps.feature.mybills.model.view.MyBillEntity
|
||||
import com.navi.bbps.feature.paybill.model.network.PaymentAmountExactness
|
||||
import com.navi.bbps.feature.paybill.model.view.PayBillSource
|
||||
import com.navi.bbps.feature.prepaidrecharge.model.view.OperatorItemEntity
|
||||
import com.navi.bbps.feature.prepaidrecharge.model.view.PlanItemEntity
|
||||
import com.navi.bbps.isPrepaidRechargePaidOrWithoutPlanDetails
|
||||
import com.navi.common.di.CoroutineDispatcherProvider
|
||||
import com.navi.common.extensions.removeSpaces
|
||||
import com.navi.common.model.common.NudgeDetailEntity
|
||||
@@ -71,7 +74,9 @@ import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asSharedFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
@@ -195,6 +200,7 @@ constructor(
|
||||
initConfig()
|
||||
fetchUserPhoneNumber()
|
||||
updateRewardsNudgeEntity()
|
||||
observeRecentBills()
|
||||
}
|
||||
|
||||
private fun initConfig() {
|
||||
@@ -491,6 +497,30 @@ constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private fun observeRecentBills() {
|
||||
viewModelScope.launch(dispatcherProvider.io) {
|
||||
bbpsCommonRepository
|
||||
.fetchSavedBillsByCategoryAsFlow(categoryId = billCategoryEntity.categoryId)
|
||||
.distinctUntilChanged()
|
||||
.collectLatest { recentBills ->
|
||||
if (contactListUIState.value is ContactListState.Loaded) {
|
||||
updateContactListUIState(
|
||||
ContactListState.Loaded(
|
||||
recentBills =
|
||||
RecentBillsEntity(
|
||||
title = resourceProvider.getString(R.string.bbps_recents),
|
||||
bills = recentBills,
|
||||
),
|
||||
allContactList =
|
||||
(contactListUIState.value as ContactListState.Loaded)
|
||||
.allContactList,
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun getRecentBills(): RecentBillsEntity {
|
||||
val savedBills =
|
||||
bbpsCommonRepository.fetchSavedBillsByCategory(category = billCategoryEntity.categoryId)
|
||||
@@ -580,17 +610,6 @@ constructor(
|
||||
billDetails = myBillEntityToBillDetailsResponseMapper.map(myBillEntity)
|
||||
)
|
||||
|
||||
val payBillSource =
|
||||
PayBillSource.Others(
|
||||
billDetailsEntity = billDetailsEntity,
|
||||
billerDetailsEntity = billerDetails,
|
||||
customerParams = myBillEntity.customerParams,
|
||||
formattedLastPaidDate = myBillEntity.formattedLastPaidDate,
|
||||
formattedLastPaidAmount = myBillEntity.formattedLastPaidAmount,
|
||||
billerId = billerDetails.billerId,
|
||||
isConsentRequired = null,
|
||||
)
|
||||
|
||||
val phoneNumber =
|
||||
PhoneContactEntity(
|
||||
name = phoneNumberDetail.name,
|
||||
@@ -600,16 +619,83 @@ constructor(
|
||||
|
||||
val screenSource = NaviBbpsScreen.NAVI_BBPS_CONTACT_LIST_SCREEN.name
|
||||
|
||||
_navigateToNextScreen.emit(
|
||||
PayBillScreenDestination(
|
||||
billCategoryEntity = billCategory,
|
||||
payBillScreenSource = payBillSource,
|
||||
phoneNumberDetail = phoneNumber,
|
||||
isRootScreen = isRootScreen,
|
||||
source = screenSource,
|
||||
initialSource = initialSource,
|
||||
if (billCategory.categoryId == CATEGORY_ID_MOBILE_PREPAID && !myBillEntity.isBillPaid) {
|
||||
val planItemEntity =
|
||||
PlanItemEntity(
|
||||
planName =
|
||||
myBillEntity.unpaidBillDetails?.planItemDetails?.get("planName").orEmpty(),
|
||||
price = myBillEntity.unpaidBillDetails?.planItemDetails?.get("price").orEmpty(),
|
||||
validity =
|
||||
myBillEntity.unpaidBillDetails?.planItemDetails?.get("validity").orEmpty(),
|
||||
talkTime =
|
||||
myBillEntity.unpaidBillDetails?.planItemDetails?.get("talkTime").orEmpty(),
|
||||
packageDescription =
|
||||
myBillEntity.unpaidBillDetails
|
||||
?.planItemDetails
|
||||
?.get("packageDescription")
|
||||
.orEmpty(),
|
||||
)
|
||||
|
||||
val operatorItemEntity =
|
||||
OperatorItemEntity(
|
||||
operatorLogoUrl = billerDetails.billerLogoUrl,
|
||||
operatorCode = EMPTY,
|
||||
operatorName = myBillEntity.billerName,
|
||||
billerId = billerDetails.billerId,
|
||||
)
|
||||
|
||||
val payBillSource =
|
||||
PayBillSource.Prepaid(
|
||||
planItemEntity = planItemEntity,
|
||||
billDetailsEntity = billDetailsEntity!!,
|
||||
operatorItemEntity = operatorItemEntity,
|
||||
customerParams = myBillEntity.customerParams,
|
||||
billerId = billerDetails.billerId,
|
||||
amount = billDetailsEntity.amount.orEmpty(),
|
||||
formattedLastPaidDate = myBillEntity.formattedLastPaidDate,
|
||||
formattedLastPaidAmount = myBillEntity.formattedLastPaidAmount,
|
||||
)
|
||||
|
||||
_navigateToNextScreen.emit(
|
||||
PayBillScreenDestination(
|
||||
billCategoryEntity = billCategory,
|
||||
payBillScreenSource = payBillSource,
|
||||
phoneNumberDetail = phoneNumber,
|
||||
isRootScreen = isRootScreen,
|
||||
source = screenSource,
|
||||
initialSource = initialSource,
|
||||
)
|
||||
)
|
||||
)
|
||||
} else {
|
||||
val payBillSource =
|
||||
PayBillSource.Others(
|
||||
billDetailsEntity = billDetailsEntity,
|
||||
billerDetailsEntity = billerDetails,
|
||||
customerParams = myBillEntity.customerParams,
|
||||
formattedLastPaidDate = myBillEntity.formattedLastPaidDate,
|
||||
formattedLastPaidAmount = myBillEntity.formattedLastPaidAmount,
|
||||
billerId = billerDetails.billerId,
|
||||
isConsentRequired = null,
|
||||
)
|
||||
|
||||
val phoneNumber =
|
||||
PhoneContactEntity(
|
||||
name = phoneNumberDetail.name,
|
||||
phoneNumber = phoneNumberDetail.phoneNumber,
|
||||
normalisedPhoneNumber = phoneNumberDetail.normalisedPhoneNumber,
|
||||
)
|
||||
|
||||
_navigateToNextScreen.emit(
|
||||
PayBillScreenDestination(
|
||||
billCategoryEntity = billCategory,
|
||||
payBillScreenSource = payBillSource,
|
||||
phoneNumberDetail = phoneNumber,
|
||||
isRootScreen = isRootScreen,
|
||||
source = screenSource,
|
||||
initialSource = initialSource,
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun onRecentBillItemClicked(phoneNumberDetail: PhoneContactEntity, myBillEntity: MyBillEntity) {
|
||||
@@ -621,7 +707,17 @@ constructor(
|
||||
source = source,
|
||||
initialSource = initialSource,
|
||||
)
|
||||
if (billCategoryEntity.categoryId == CATEGORY_ID_MOBILE_PREPAID) {
|
||||
val billerDetails =
|
||||
BillerDetailsEntity(
|
||||
billerId = myBillEntity.billerId,
|
||||
billerName = myBillEntity.billerName,
|
||||
billerLogoUrl = myBillEntity.billerLogoUrl,
|
||||
status = myBillEntity.status,
|
||||
isAdhoc = myBillEntity.isAdhoc,
|
||||
fetchOption = EMPTY,
|
||||
paymentAmountExactness = myBillEntity.paymentAmountExactness,
|
||||
)
|
||||
if (myBillEntity.isPrepaidRechargePaidOrWithoutPlanDetails()) {
|
||||
updateNextScreenDestinationState(
|
||||
PrepaidRechargeScreenDestination(
|
||||
phoneNumberDetail =
|
||||
@@ -645,16 +741,6 @@ constructor(
|
||||
)
|
||||
)
|
||||
} else {
|
||||
val billerDetails =
|
||||
BillerDetailsEntity(
|
||||
billerId = myBillEntity.billerId,
|
||||
billerName = myBillEntity.billerName,
|
||||
billerLogoUrl = myBillEntity.billerLogoUrl,
|
||||
status = myBillEntity.status,
|
||||
isAdhoc = myBillEntity.isAdhoc,
|
||||
fetchOption = EMPTY,
|
||||
paymentAmountExactness = myBillEntity.paymentAmountExactness,
|
||||
)
|
||||
navigateToNextScreen(
|
||||
billerDetails = billerDetails,
|
||||
phoneNumberDetail = phoneNumberDetail,
|
||||
|
||||
@@ -579,6 +579,7 @@ constructor(
|
||||
phoneNumberDetail = phoneNumberDetail,
|
||||
source = source,
|
||||
initialSource = initialSource,
|
||||
isBillSyncRequiredInBackground = false,
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -41,6 +41,9 @@ constructor(
|
||||
suspend fun fetchSavedBillsByCategory(category: String) =
|
||||
myBillsDao.getBillsByCategory(categoryId = category)
|
||||
|
||||
fun fetchSavedBillsByCategoryAsFlow(category: String) =
|
||||
myBillsDao.getBillsByCategoryAsFlow(categoryId = category)
|
||||
|
||||
suspend fun markBillAsPaid(
|
||||
billId: String,
|
||||
metricInfo: MetricInfo<RepoResult<BillMarkAsPaidResponse>>,
|
||||
|
||||
@@ -72,6 +72,7 @@ import com.navi.bbps.feature.mybills.model.view.MyBillsState
|
||||
import com.navi.bbps.feature.paybill.model.view.PayBillSource
|
||||
import com.navi.bbps.feature.prepaidrecharge.model.view.OperatorItemEntity
|
||||
import com.navi.bbps.feature.prepaidrecharge.model.view.PlanItemEntity
|
||||
import com.navi.bbps.isPrepaidRechargePaidOrWithoutPlanDetails
|
||||
import com.navi.bbps.isRedirectToCustomerInputRequired
|
||||
import com.navi.common.di.CoroutineDispatcherProvider
|
||||
import com.navi.common.network.models.isSuccessWithData
|
||||
@@ -690,10 +691,7 @@ constructor(
|
||||
myBillEntityToBillerDetailsEntityMapper.mapMyBillEntityToBillerDetailsEntity(
|
||||
myBillEntity = myBillEntity
|
||||
)
|
||||
if (
|
||||
myBillEntity.unpaidBillDetails?.planItemDetails.isNullOrEmpty() &&
|
||||
myBillEntity.categoryId == CATEGORY_ID_MOBILE_PREPAID
|
||||
) {
|
||||
if (myBillEntity.isPrepaidRechargePaidOrWithoutPlanDetails()) {
|
||||
_navigateToNextScreen.emit(
|
||||
PrepaidRechargeScreenDestination(
|
||||
phoneNumberDetail =
|
||||
|
||||
@@ -27,6 +27,9 @@ interface MyBillsDao {
|
||||
@Query("SELECT * FROM $NAVI_BBPS_TABLE_MY_SAVED_BILLS WHERE categoryId == :categoryId")
|
||||
suspend fun getBillsByCategory(categoryId: String): List<MyBillEntity>
|
||||
|
||||
@Query("SELECT * FROM $NAVI_BBPS_TABLE_MY_SAVED_BILLS WHERE categoryId == :categoryId")
|
||||
fun getBillsByCategoryAsFlow(categoryId: String): Flow<List<MyBillEntity>>
|
||||
|
||||
@Update suspend fun updateSavedBill(myBillEntity: MyBillEntity)
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
|
||||
@@ -357,4 +357,9 @@
|
||||
<string name="bbps_duplicate_payment_pending_secondary_cta_text">Pay again</string>
|
||||
<string name="bbps_duplicate_payment_failed_mainline_text">Last payment on %s failed, know why?</string>
|
||||
<string name="bbps_duplicate_payment_failed_annotated_text">know why?</string>
|
||||
<string name="bbps_no_bills_due_description">You currently have no due bills for this biller.</string>
|
||||
<string name="bbps_pay_bill_in_advance">Pay in advance</string>
|
||||
<string name="bbps_recharge">Recharge</string>
|
||||
<string name="bbps_bill_amount">bill amount</string>
|
||||
<string name="bbps_view_all_plans">View all plans</string>
|
||||
</resources>
|
||||
Reference in New Issue
Block a user