NTP-64314 | Divyesh | Add bill options enhancement (#16214)
This commit is contained in:
@@ -296,6 +296,48 @@ class NaviBbpsAnalytics private constructor() {
|
||||
)
|
||||
}
|
||||
|
||||
fun billDeletionSuccess(
|
||||
data: BbpsGenericResponse,
|
||||
myBillEntity: MyBillEntity,
|
||||
sessionAttribute: Map<String, String>,
|
||||
source: String,
|
||||
initialSource: String,
|
||||
) {
|
||||
NaviTrackEvent.trackEventOnClickStream(
|
||||
eventName = "NaviBBPS_CategoryPage_DeletedBill_Success",
|
||||
eventValues =
|
||||
mapOf(
|
||||
"data" to data.toString(),
|
||||
"billId" to myBillEntity.billId,
|
||||
"billerName" to myBillEntity.billerName,
|
||||
NAVI_BBPS_SESSION_ID to sessionAttribute[NAVI_BBPS_SESSION_ID].orEmpty(),
|
||||
NAVI_BBPS_SOURCE to source,
|
||||
NAVI_BBPS_INITIAL_SOURCE to initialSource,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
fun billDeletionFailed(
|
||||
deleteBillResponse: RepoResult<BbpsGenericResponse>,
|
||||
myBillEntity: MyBillEntity,
|
||||
sessionAttribute: Map<String, String>,
|
||||
source: String,
|
||||
initialSource: String,
|
||||
) {
|
||||
NaviTrackEvent.trackEventOnClickStream(
|
||||
eventName = "NaviBBPS_CategoryPage_DeletedBill_Failed",
|
||||
eventValues =
|
||||
mapOf(
|
||||
"deleteBillResponse" to deleteBillResponse.toString(),
|
||||
"billId" to myBillEntity.billId,
|
||||
"billerName" to myBillEntity.billerName,
|
||||
NAVI_BBPS_SESSION_ID to sessionAttribute[NAVI_BBPS_SESSION_ID].orEmpty(),
|
||||
NAVI_BBPS_SOURCE to source,
|
||||
NAVI_BBPS_INITIAL_SOURCE to initialSource,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
fun onUnpaidBillOptionsClicked(
|
||||
sessionAttribute: Map<String, String>,
|
||||
billEntity: MyBillEntity,
|
||||
@@ -728,6 +770,25 @@ class NaviBbpsAnalytics private constructor() {
|
||||
)
|
||||
}
|
||||
|
||||
fun onBillOptionsClicked(
|
||||
sessionAttribute: Map<String, String>,
|
||||
billEntity: MyBillEntity,
|
||||
action: String,
|
||||
) {
|
||||
NaviTrackEvent.trackEventOnClickStream(
|
||||
eventName = "NaviBBPS_BillerList_BillsOptions_Clicked",
|
||||
eventValues =
|
||||
mapOf(
|
||||
"billId" to billEntity.billId,
|
||||
"billerId" to billEntity.billerId,
|
||||
"categoryId" to billEntity.categoryId,
|
||||
"billerName" to billEntity.billerName,
|
||||
"action" to action,
|
||||
NAVI_BBPS_SESSION_ID to sessionAttribute[NAVI_BBPS_SESSION_ID].orEmpty(),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
fun onNavigateToNextScreen(
|
||||
billCategoryEntity: BillCategoryEntity,
|
||||
route: String,
|
||||
@@ -848,7 +909,7 @@ class NaviBbpsAnalytics private constructor() {
|
||||
)
|
||||
}
|
||||
|
||||
fun billDeletedSuccessfully(
|
||||
fun billDeletionSuccess(
|
||||
data: BbpsGenericResponse,
|
||||
myBillEntity: MyBillEntity,
|
||||
sessionAttribute: Map<String, String>,
|
||||
@@ -1658,6 +1719,25 @@ class NaviBbpsAnalytics private constructor() {
|
||||
)
|
||||
}
|
||||
|
||||
fun onBillOptionsClicked(
|
||||
sessionAttribute: Map<String, String>,
|
||||
billEntity: MyBillEntity,
|
||||
action: String,
|
||||
) {
|
||||
NaviTrackEvent.trackEventOnClickStream(
|
||||
eventName = "NaviBBPS_ContactList_BillsOptions_Clicked",
|
||||
eventValues =
|
||||
mapOf(
|
||||
"billId" to billEntity.billId,
|
||||
"billerId" to billEntity.billerId,
|
||||
"categoryId" to billEntity.categoryId,
|
||||
"billerName" to billEntity.billerName,
|
||||
"action" to action,
|
||||
NAVI_BBPS_SESSION_ID to sessionAttribute[NAVI_BBPS_SESSION_ID].orEmpty(),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
fun onDeleteAccountKebabMenuClicked(
|
||||
myBillEntity: MyBillEntity,
|
||||
sessionAttribute: Map<String, String>,
|
||||
@@ -1711,7 +1791,7 @@ class NaviBbpsAnalytics private constructor() {
|
||||
)
|
||||
}
|
||||
|
||||
fun billDeletedSuccessfully(
|
||||
fun billDeletionSuccess(
|
||||
data: BbpsGenericResponse,
|
||||
myBillEntity: MyBillEntity,
|
||||
sessionAttribute: Map<String, String>,
|
||||
@@ -2506,6 +2586,48 @@ class NaviBbpsAnalytics private constructor() {
|
||||
)
|
||||
}
|
||||
|
||||
fun billDeletionSuccess(
|
||||
data: BbpsGenericResponse,
|
||||
myBillEntity: MyBillEntity,
|
||||
sessionAttribute: Map<String, String>,
|
||||
source: String,
|
||||
initialSource: String,
|
||||
) {
|
||||
NaviTrackEvent.trackEventOnClickStream(
|
||||
eventName = "NaviBBPS_MyBills_DeletedBill_Success",
|
||||
eventValues =
|
||||
mapOf(
|
||||
"data" to data.toString(),
|
||||
"billId" to myBillEntity.billId,
|
||||
"billerName" to myBillEntity.billerName,
|
||||
NAVI_BBPS_SESSION_ID to sessionAttribute[NAVI_BBPS_SESSION_ID].orEmpty(),
|
||||
NAVI_BBPS_SOURCE to source,
|
||||
NAVI_BBPS_INITIAL_SOURCE to initialSource,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
fun billDeletionFailed(
|
||||
deleteBillResponse: RepoResult<BbpsGenericResponse>,
|
||||
myBillEntity: MyBillEntity,
|
||||
sessionAttribute: Map<String, String>,
|
||||
source: String,
|
||||
initialSource: String,
|
||||
) {
|
||||
NaviTrackEvent.trackEventOnClickStream(
|
||||
eventName = "NaviBBPS_MyBills_DeletedBill_Failed",
|
||||
eventValues =
|
||||
mapOf(
|
||||
"deleteBillResponse" to deleteBillResponse.toString(),
|
||||
"billId" to myBillEntity.billId,
|
||||
"billerName" to myBillEntity.billerName,
|
||||
NAVI_BBPS_SESSION_ID to sessionAttribute[NAVI_BBPS_SESSION_ID].orEmpty(),
|
||||
NAVI_BBPS_SOURCE to source,
|
||||
NAVI_BBPS_INITIAL_SOURCE to initialSource,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
fun onMyBillMoreOptionsBottomSheetClicked(billEntity: MyBillEntity, action: String) {
|
||||
NaviTrackEvent.trackEventOnClickStream(
|
||||
eventName = "NaviBBPS_MyBills_BottomSheet_Options_Clicked",
|
||||
|
||||
@@ -12,6 +12,7 @@ import android.graphics.Rect
|
||||
import android.view.ViewTreeObserver
|
||||
import androidx.annotation.ColorRes
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.compose.animation.AnimatedContent
|
||||
import androidx.compose.animation.AnimatedContentTransitionScope
|
||||
import androidx.compose.animation.core.animateFloatAsState
|
||||
@@ -125,7 +126,12 @@ import com.navi.bbps.common.BULLET
|
||||
import com.navi.bbps.common.CATEGORY_ID_CREDIT_CARD
|
||||
import com.navi.bbps.common.DASH
|
||||
import com.navi.bbps.common.DATE_TIME_FORMAT_DATE_MONTH_NAME
|
||||
import com.navi.bbps.common.ICON_MARK_AS_PAID_UNPAID_BILL_BOTTOMSHEET
|
||||
import com.navi.bbps.common.ICON_REFRESH_BILL_UNPAID_BILL_BOTTOMSHEET
|
||||
import com.navi.bbps.common.ICON_REMOVE_ACCOUNT_UNPAID_BILL_BOTTOMSHEET
|
||||
import com.navi.bbps.common.ICON_VIEW_BILL_HISTORY_UNPAID_BILL_BOTTOMSHEET
|
||||
import com.navi.bbps.common.NaviBbpsDimens
|
||||
import com.navi.bbps.common.SYMBOL_RUPEE
|
||||
import com.navi.bbps.common.model.view.DetectedBillEntity
|
||||
import com.navi.bbps.common.model.view.NaviPermissionResult
|
||||
import com.navi.bbps.common.model.view.PrepaidPlanItemLoadingState
|
||||
@@ -1940,7 +1946,10 @@ fun BillAmountAndDueDateSectionWithShimmer(
|
||||
Spacer(modifier = Modifier.height(2.dp))
|
||||
Box(
|
||||
modifier =
|
||||
Modifier.padding(start = 48.dp).width(200.dp).height(20.dp).bbpsShimmerEffect()
|
||||
Modifier.padding(start = if (startWithPadding) 48.dp else 0.dp)
|
||||
.width(200.dp)
|
||||
.height(20.dp)
|
||||
.bbpsShimmerEffect()
|
||||
)
|
||||
} else {
|
||||
if (myBillEntity.isBillPaid.not()) {
|
||||
@@ -2340,6 +2349,195 @@ fun OriginLandingWidget(
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun BillOptionsBottomSheetContent(
|
||||
billerLogoUrl: String,
|
||||
title: String,
|
||||
amount: String,
|
||||
billerName: String,
|
||||
expiringOn: String,
|
||||
isBillPaid: Boolean = false,
|
||||
isRechargeCategory: Boolean,
|
||||
onMarkAsPaidClicked: () -> Unit,
|
||||
onRefreshBillClicked: () -> Unit,
|
||||
onViewBillHistoryClicked: () -> Unit,
|
||||
onRemoveAccountClicked: () -> Unit,
|
||||
onCloseClicked: () -> Unit,
|
||||
) {
|
||||
val descriptionText = buildAnnotatedString {
|
||||
if (isBillPaid) {
|
||||
append(billerName)
|
||||
} else {
|
||||
val fullText = stringResource(id = R.string.bbps_payment_due, billerName, expiringOn)
|
||||
withStyle(
|
||||
style =
|
||||
SpanStyle(
|
||||
fontFamily = naviFontFamily,
|
||||
fontWeight = getFontWeight(FontWeightEnum.NAVI_BODY_REGULAR),
|
||||
fontSize = 14.sp,
|
||||
color = NaviBbpsColor.textTertiary,
|
||||
)
|
||||
) {
|
||||
append(fullText)
|
||||
}
|
||||
addStyle(
|
||||
style =
|
||||
SpanStyle(
|
||||
fontFamily = naviFontFamily,
|
||||
fontWeight = getFontWeight(FontWeightEnum.NAVI_BODY_REGULAR),
|
||||
fontSize = 14.sp,
|
||||
color = NaviBbpsColor.inputFieldError,
|
||||
),
|
||||
start = fullText.indexOf(expiringOn),
|
||||
end = fullText.indexOf(expiringOn) + expiringOn.length,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Column(
|
||||
modifier =
|
||||
Modifier.navigationBarsPadding()
|
||||
.fillMaxWidth()
|
||||
.wrapContentHeight()
|
||||
.padding(start = 16.dp, end = 16.dp, top = 16.dp, bottom = 32.dp)
|
||||
) {
|
||||
Row(modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
|
||||
BbpsAsyncImage(
|
||||
imageUrl = billerLogoUrl,
|
||||
modifier = Modifier.size(24.dp),
|
||||
placeholderIconResId = CommonR.drawable.navi_common_ic_biller_placeholder,
|
||||
)
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
Image(
|
||||
painter = painterResource(id = CommonR.drawable.ic_close_black),
|
||||
contentDescription = null,
|
||||
modifier = Modifier.size(24.dp).clickableDebounce { onCloseClicked() },
|
||||
)
|
||||
}
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
NaviText(
|
||||
text =
|
||||
buildString {
|
||||
if (title.isNotBlank()) {
|
||||
append(title)
|
||||
append(com.navi.common.utils.SPACE)
|
||||
}
|
||||
if (!isBillPaid) {
|
||||
if (title.isNotBlank() && amount.isNotBlank()) {
|
||||
append(BULLET)
|
||||
append(com.navi.common.utils.SPACE)
|
||||
}
|
||||
if (amount.isNotBlank()) {
|
||||
append(SYMBOL_RUPEE)
|
||||
append(amount)
|
||||
}
|
||||
}
|
||||
},
|
||||
fontSize = 16.sp,
|
||||
fontFamily = naviFontFamily,
|
||||
fontWeight = getFontWeight(FontWeightEnum.NAVI_BODY_DEMI_BOLD),
|
||||
color = NaviBbpsColor.textPrimary,
|
||||
)
|
||||
Spacer(modifier = Modifier.height(2.dp))
|
||||
|
||||
if (descriptionText.isNotBlank()) {
|
||||
NaviText(
|
||||
text = descriptionText,
|
||||
fontSize = 14.sp,
|
||||
fontFamily = naviFontFamily,
|
||||
fontWeight = getFontWeight(FontWeightEnum.NAVI_BODY_REGULAR),
|
||||
color = NaviBbpsColor.textTertiary,
|
||||
lineHeight = 22.sp,
|
||||
)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
|
||||
val actions = mutableListOf<ActionItem>()
|
||||
|
||||
if (!isBillPaid) {
|
||||
actions.add(
|
||||
ActionItem(
|
||||
imageS3Url = ICON_MARK_AS_PAID_UNPAID_BILL_BOTTOMSHEET,
|
||||
textResId = R.string.bbps_mark_as_paid,
|
||||
onClick = onMarkAsPaidClicked,
|
||||
)
|
||||
)
|
||||
}
|
||||
if (!isRechargeCategory) {
|
||||
actions.add(
|
||||
ActionItem(
|
||||
imageS3Url = ICON_REFRESH_BILL_UNPAID_BILL_BOTTOMSHEET,
|
||||
textResId = R.string.bbps_refresh_bill,
|
||||
onClick = onRefreshBillClicked,
|
||||
)
|
||||
)
|
||||
}
|
||||
actions.addAll(
|
||||
listOf(
|
||||
ActionItem(
|
||||
imageS3Url = ICON_VIEW_BILL_HISTORY_UNPAID_BILL_BOTTOMSHEET,
|
||||
textResId =
|
||||
if (isRechargeCategory) {
|
||||
R.string.bbps_view_recharge_history
|
||||
} else R.string.bbps_view_bill_history,
|
||||
onClick = onViewBillHistoryClicked,
|
||||
),
|
||||
ActionItem(
|
||||
imageS3Url = ICON_REMOVE_ACCOUNT_UNPAID_BILL_BOTTOMSHEET,
|
||||
textResId = R.string.bbps_remove_account,
|
||||
onClick = onRemoveAccountClicked,
|
||||
),
|
||||
)
|
||||
)
|
||||
|
||||
actions.forEachIndexed { index, action ->
|
||||
IconActionRow(
|
||||
imageS3Url = action.imageS3Url,
|
||||
text = stringResource(id = action.textResId),
|
||||
onClick = action.onClick,
|
||||
)
|
||||
|
||||
if (index < actions.lastIndex) {
|
||||
HorizontalDivider(
|
||||
modifier = Modifier.padding(vertical = 20.dp),
|
||||
thickness = 1.dp,
|
||||
color = NaviBbpsColor.borderAlt,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class ActionItem(
|
||||
val imageS3Url: String,
|
||||
@StringRes val textResId: Int,
|
||||
val onClick: () -> Unit,
|
||||
)
|
||||
|
||||
@Composable
|
||||
fun IconActionRow(
|
||||
imageS3Url: String,
|
||||
text: String,
|
||||
onClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Row(
|
||||
modifier = modifier.fillMaxWidth().noRippleClickableWithDebounce(onClick = onClick),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
AsyncImage(modifier = Modifier.size(24.dp), model = imageS3Url, contentDescription = "")
|
||||
Spacer(modifier = Modifier.width(12.dp))
|
||||
NaviText(
|
||||
text = text,
|
||||
fontSize = 14.sp,
|
||||
fontFamily = naviFontFamily,
|
||||
fontWeight = getFontWeight(FontWeightEnum.NAVI_BODY_REGULAR),
|
||||
color = NaviBbpsColor.textPrimary,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun OriginLandingWidgetPreview() {
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright © 2025 by Navi Technologies Limited
|
||||
* * All rights reserved. Strictly confidential
|
||||
*
|
||||
*/
|
||||
|
||||
package com.navi.bbps.common.usecase
|
||||
|
||||
import com.navi.base.utils.NaviNetworkConnectivity
|
||||
import com.navi.base.utils.retry
|
||||
import com.navi.bbps.common.DEFAULT_RETRY_COUNT
|
||||
import com.navi.bbps.common.RETRY_INTERVAL_IN_SECONDS
|
||||
import com.navi.bbps.common.model.network.BbpsGenericResponse
|
||||
import com.navi.bbps.common.repository.BbpsCommonRepository
|
||||
import com.navi.bbps.common.utils.NaviBbpsCommonUtils.getBbpsMetricInfo
|
||||
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.mybills.MyBillsRepository
|
||||
import com.navi.bbps.feature.mybills.MyBillsSyncJob
|
||||
import com.navi.bbps.feature.mybills.model.view.MyBillEntity
|
||||
import com.navi.common.network.models.RepoResult
|
||||
import com.navi.common.network.models.isSuccessWithData
|
||||
import javax.inject.Inject
|
||||
|
||||
class MyBillActionsHandler
|
||||
@Inject
|
||||
constructor(
|
||||
private val bbpsCommonRepository: BbpsCommonRepository,
|
||||
private val naviNetworkConnectivity: NaviNetworkConnectivity,
|
||||
private val myBillsRepository: MyBillsRepository,
|
||||
private val myBillsSyncJob: MyBillsSyncJob,
|
||||
) {
|
||||
|
||||
suspend fun refreshBill(
|
||||
myBillEntity: MyBillEntity,
|
||||
screenName: String,
|
||||
onSuccess: () -> Unit,
|
||||
onError: suspend (RepoResult<BillDetailsResponse>) -> Unit,
|
||||
) {
|
||||
val billDetailsRequest =
|
||||
BillDetailsRequest(
|
||||
billerId = myBillEntity.billerId,
|
||||
customerParams = myBillEntity.customerParams,
|
||||
deviceDetails = DeviceDetails(ip = naviNetworkConnectivity.getIpAddress()),
|
||||
amount = myBillEntity.actualLastPaidAmount,
|
||||
isConsentProvided = true,
|
||||
)
|
||||
|
||||
val billDetailsResponse =
|
||||
bbpsCommonRepository.fetchBillDetails(
|
||||
billDetailsRequest = billDetailsRequest,
|
||||
metricInfo = getBbpsMetricInfo(screenName = screenName),
|
||||
)
|
||||
|
||||
if (billDetailsResponse.isSuccessWithData() && billDetailsResponse.data != null) {
|
||||
onSuccess()
|
||||
} else {
|
||||
onError(billDetailsResponse)
|
||||
}
|
||||
myBillsSyncJob.refreshBills(screenName = screenName)
|
||||
}
|
||||
|
||||
suspend fun deleteBill(
|
||||
billId: String,
|
||||
categoryId: String,
|
||||
screenName: String,
|
||||
onSuccess: suspend (RepoResult<BbpsGenericResponse>) -> Unit,
|
||||
onError: suspend (RepoResult<BbpsGenericResponse>) -> Unit,
|
||||
) {
|
||||
val savedBills = bbpsCommonRepository.fetchSavedBillsByCategory(category = categoryId)
|
||||
if (savedBills.isNotEmpty()) {
|
||||
val deleteBillResponse =
|
||||
bbpsCommonRepository.deleteBill(
|
||||
savedBillId = billId,
|
||||
metricInfo = getBbpsMetricInfo(screenName = screenName),
|
||||
)
|
||||
if (deleteBillResponse.isSuccessWithData()) {
|
||||
myBillsSyncJob.refreshBills(screenName = screenName)
|
||||
onSuccess(deleteBillResponse)
|
||||
} else {
|
||||
onError(deleteBillResponse)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun markAsPaid(billId: String, screenName: String, onSuccess: () -> Unit) {
|
||||
val response =
|
||||
retry(
|
||||
retryCount = DEFAULT_RETRY_COUNT,
|
||||
retryIntervalInSeconds = RETRY_INTERVAL_IN_SECONDS,
|
||||
execute = {
|
||||
myBillsRepository.markBillAsPaid(
|
||||
billId = billId,
|
||||
metricInfo = getBbpsMetricInfo(screenName = screenName, isNae = { false }),
|
||||
)
|
||||
},
|
||||
shouldRetry = { !it.isSuccessWithData() },
|
||||
)
|
||||
if (response.isSuccessWithData()) {
|
||||
myBillsSyncJob.refreshBills(screenName = screenName)
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,8 +12,8 @@ import androidx.lifecycle.viewModelScope
|
||||
import com.google.firebase.crashlytics.FirebaseCrashlytics
|
||||
import com.navi.base.utils.BaseUtils
|
||||
import com.navi.base.utils.EMPTY
|
||||
import com.navi.base.utils.NaviNetworkConnectivity
|
||||
import com.navi.base.utils.ResourceProvider
|
||||
import com.navi.base.utils.isNotNull
|
||||
import com.navi.bbps.R
|
||||
import com.navi.bbps.common.CATEGORY_ID_FASTAG
|
||||
import com.navi.bbps.common.CATEGORY_ID_MOBILE_POSTPAID
|
||||
@@ -23,9 +23,11 @@ import com.navi.bbps.common.NaviBbpsScreen
|
||||
import com.navi.bbps.common.model.NaviBbpsVmData
|
||||
import com.navi.bbps.common.model.config.NaviBbpsDefaultConfig
|
||||
import com.navi.bbps.common.model.view.NaviPermissionResult
|
||||
import com.navi.bbps.common.model.view.RefreshBillState
|
||||
import com.navi.bbps.common.repository.BbpsCommonRepository
|
||||
import com.navi.bbps.common.session.NaviBbpsSessionHelper
|
||||
import com.navi.bbps.common.usecase.FindLastOrderWithSuccessfulPaymentUseCase
|
||||
import com.navi.bbps.common.usecase.MyBillActionsHandler
|
||||
import com.navi.bbps.common.usecase.NaviBbpsConfigUseCase
|
||||
import com.navi.bbps.common.usecase.RewardNudgeUseCase
|
||||
import com.navi.bbps.common.utils.BillDetailsResponseToEntityMapper
|
||||
@@ -48,8 +50,9 @@ 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.MyBillHistoryDetailsScreenDestination
|
||||
import com.navi.bbps.feature.destinations.PayBillScreenDestination
|
||||
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.isRedirectToCustomerInputRequired
|
||||
@@ -96,14 +99,16 @@ constructor(
|
||||
private val bbpsCommonRepository: BbpsCommonRepository,
|
||||
private val naviBbpsConfigUseCase: NaviBbpsConfigUseCase,
|
||||
private val deviceLocationProvider: DeviceLocationProvider,
|
||||
private val myBillsSyncJob: MyBillsSyncJob,
|
||||
private val rewardsNudgeEntityFetchUseCase: RewardNudgeUseCase,
|
||||
private val naviBbpsSessionHelper: NaviBbpsSessionHelper,
|
||||
private val myBillEntityToBillDetailsResponseMapper: MyBillEntityToBillDetailsResponseMapper,
|
||||
private val billDetailsResponseToEntityMapper: BillDetailsResponseToEntityMapper,
|
||||
private val resourceProvider: ResourceProvider,
|
||||
private val billerItemResponseToEntityMapper: BillerItemResponseToEntityMapper,
|
||||
private val findLastOrderWithSuccessfulPaymentUseCase: FindLastOrderWithSuccessfulPaymentUseCase,
|
||||
private val findLastOrderWithSuccessfulPaymentUseCase:
|
||||
FindLastOrderWithSuccessfulPaymentUseCase,
|
||||
private val naviNetworkConnectivity: NaviNetworkConnectivity,
|
||||
private val myBillActionsHandler: MyBillActionsHandler,
|
||||
) : NaviBbpsBaseVM(naviBbpsVmData = NaviBbpsVmData(screen = NaviBbpsScreen.NAVI_BBPS_BILLER_LIST)) {
|
||||
|
||||
private val naviBbpsAnalytics: NaviBbpsAnalytics.BillerList =
|
||||
@@ -130,15 +135,11 @@ constructor(
|
||||
val rewardsNudgeDetailEntity = _rewardsNudgeDetailEntity.asStateFlow()
|
||||
|
||||
private val _billerListBottomSheetType =
|
||||
MutableStateFlow<BillerListBottomSheetType>(
|
||||
BillerListBottomSheetType.MenuOptions(
|
||||
BillerListBottomSheetType.createEmptyMyBillEntity()
|
||||
)
|
||||
)
|
||||
MutableStateFlow<BillerListBottomSheetType>(BillerListBottomSheetType.None)
|
||||
val billerListBottomSheetType = _billerListBottomSheetType.asStateFlow()
|
||||
|
||||
private val _showSnackBar = MutableStateFlow(false)
|
||||
val showSnackBar = _showSnackBar.asStateFlow()
|
||||
private val _refreshBillItemAndStatus = MutableStateFlow(RefreshBillState())
|
||||
val refreshBillItemAndStatus = _refreshBillItemAndStatus.asStateFlow()
|
||||
|
||||
val phoneNumber = BaseUtils.getPhoneNumber().toString()
|
||||
val normalisedPhoneNumber = getNormalisedPhoneNumber(phoneNumber = phoneNumber)
|
||||
@@ -184,6 +185,9 @@ constructor(
|
||||
private val _naviBbpsDefaultConfig = MutableStateFlow(NaviBbpsDefaultConfig())
|
||||
val naviBbpsDefaultConfig = _naviBbpsDefaultConfig.asStateFlow()
|
||||
|
||||
private val _snackBarState = MutableStateFlow(SnackBarState(show = false))
|
||||
val snackBarState = _snackBarState.asStateFlow()
|
||||
|
||||
private var recentBillsEntity = RecentBillsEntity(title = "", bills = listOf())
|
||||
|
||||
val isTrailingIconEnabled =
|
||||
@@ -236,8 +240,12 @@ constructor(
|
||||
_navigateToNextScreen.emit(direction)
|
||||
}
|
||||
|
||||
fun updateSnackBarState(showSnackBar: Boolean) {
|
||||
_showSnackBar.update { showSnackBar }
|
||||
fun updateSnackBarState(show: Boolean, messageId: Int = R.string.bbps_copied_to_clipboard) {
|
||||
_snackBarState.update { SnackBarState(show = show, messageId = messageId) }
|
||||
}
|
||||
|
||||
private fun updateRefreshState(isRefreshing: Boolean, bill: MyBillEntity? = null) {
|
||||
_refreshBillItemAndStatus.value = RefreshBillState(isRefreshing, bill)
|
||||
}
|
||||
|
||||
private val _permissionResult =
|
||||
@@ -290,25 +298,128 @@ constructor(
|
||||
}
|
||||
}
|
||||
|
||||
fun onDeleteMenuClicked(myBillEntity: MyBillEntity) {
|
||||
_billerListBottomSheetType.update { BillerListBottomSheetType.MenuOptions(myBillEntity) }
|
||||
fun onBillOptionsKebabMenuClicked(myBillEntity: MyBillEntity, openSheet: () -> Unit) {
|
||||
_billerListBottomSheetType.update {
|
||||
BillerListBottomSheetType.MenuOptions(
|
||||
myBillEntity = myBillEntity,
|
||||
onMarkAsPaidClicked = {
|
||||
naviBbpsAnalytics.onBillOptionsClicked(
|
||||
sessionAttribute = getNaviBbpsSessionAttributes(),
|
||||
billEntity = myBillEntity,
|
||||
action = resourceProvider.getString(R.string.bbps_mark_as_paid),
|
||||
)
|
||||
viewModelScope.launch {
|
||||
delay(200)
|
||||
/* this is added to make sure the bottom sheet is closed before
|
||||
opening the new one and to make the transition smoother */
|
||||
_billerListBottomSheetType.update {
|
||||
BillerListBottomSheetType.MarkAsPaid(
|
||||
myBillEntity = myBillEntity,
|
||||
title =
|
||||
resourceProvider.getString(
|
||||
R.string.bbps_bill_mark_as_paid_heading
|
||||
),
|
||||
description =
|
||||
resourceProvider.getString(
|
||||
R.string.bbps_bill_mark_as_paid_description
|
||||
),
|
||||
firstBtnText = resourceProvider.getString(R.string.bbps_no),
|
||||
secondButtonText = resourceProvider.getString(R.string.bbps_yes),
|
||||
onFirstBtnClick = {},
|
||||
onSecondBtnClick = {
|
||||
onMarkBillAsPaidConfirmedCtaClicked(myBillEntity = myBillEntity)
|
||||
},
|
||||
)
|
||||
}
|
||||
openSheet.invoke()
|
||||
}
|
||||
},
|
||||
onRefreshBillClicked = {
|
||||
naviBbpsAnalytics.onBillOptionsClicked(
|
||||
sessionAttribute = getNaviBbpsSessionAttributes(),
|
||||
billEntity = myBillEntity,
|
||||
action = resourceProvider.getString(R.string.bbps_refresh_bill),
|
||||
)
|
||||
viewModelScope.launch(dispatcherProvider.io) {
|
||||
if (!naviNetworkConnectivity.isInternetConnected()) {
|
||||
notifyError(getNoInternetErrorConfig())
|
||||
return@launch
|
||||
} else {
|
||||
refreshBillAndUpdateInfo(myBillEntity = myBillEntity)
|
||||
}
|
||||
}
|
||||
},
|
||||
onViewBillHistoryClicked = {
|
||||
naviBbpsAnalytics.onBillOptionsClicked(
|
||||
sessionAttribute = getNaviBbpsSessionAttributes(),
|
||||
billEntity = myBillEntity,
|
||||
action = resourceProvider.getString(R.string.bbps_view_bill_history),
|
||||
)
|
||||
viewModelScope.launch {
|
||||
delay(200)
|
||||
_navigateToNextScreen.emit(
|
||||
MyBillHistoryDetailsScreenDestination(
|
||||
myBillEntity = myBillEntity,
|
||||
source = naviBbpsVmData.screen.name,
|
||||
initialSource = initialSource,
|
||||
)
|
||||
)
|
||||
}
|
||||
},
|
||||
onRemoveAccountClicked = {
|
||||
naviBbpsAnalytics.onBillOptionsClicked(
|
||||
sessionAttribute = getNaviBbpsSessionAttributes(),
|
||||
billEntity = myBillEntity,
|
||||
action = resourceProvider.getString(R.string.bbps_remove_account),
|
||||
)
|
||||
viewModelScope.launch {
|
||||
delay(200)
|
||||
_billerListBottomSheetType.update {
|
||||
BillerListBottomSheetType.RemoveAccount(
|
||||
myBillEntity = myBillEntity,
|
||||
title =
|
||||
naviBbpsDefaultConfig.value.configMessage
|
||||
.removeAccountBottomSheetTitle,
|
||||
description =
|
||||
naviBbpsDefaultConfig.value.configMessage
|
||||
.removeAccountBottomSheetMessage,
|
||||
firstBtnTextResId = R.string.bbps_cancel,
|
||||
secondButtonTextResId = R.string.bbps_remove,
|
||||
onFirstBtnClick = {},
|
||||
onSecondBtnClick = { deleteBill(myBillEntity) },
|
||||
)
|
||||
}
|
||||
openSheet.invoke()
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun onDeleteAccountBillClicked(myBillEntity: MyBillEntity) {
|
||||
viewModelScope.launch {
|
||||
delay(100) // for smooth transition of next bottom sheet
|
||||
_billerListBottomSheetType.update {
|
||||
BillerListBottomSheetType.Confirmation(
|
||||
title = naviBbpsDefaultConfig.value.configMessage.removeAccountBottomSheetTitle,
|
||||
description =
|
||||
naviBbpsDefaultConfig.value.configMessage.removeAccountBottomSheetMessage,
|
||||
firstBtnTextResId = R.string.bbps_cancel,
|
||||
secondButtonTextResId = R.string.bbps_remove,
|
||||
onFirstBtnClick = {},
|
||||
onSecondBtnClick = { deleteBill(myBillEntity) },
|
||||
private suspend fun refreshBillAndUpdateInfo(myBillEntity: MyBillEntity) {
|
||||
updateRefreshState(isRefreshing = true, bill = myBillEntity)
|
||||
myBillActionsHandler.refreshBill(
|
||||
myBillEntity = myBillEntity,
|
||||
screenName = naviBbpsVmData.screen.screenName,
|
||||
onSuccess = {
|
||||
updateSnackBarState(
|
||||
show = true,
|
||||
messageId = R.string.bbps_bill_refreshed_sucessfully,
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
onError = { response ->
|
||||
val errorCode = getError(response).code
|
||||
if (errorCode in naviBbpsDefaultConfig.value.billAlreadyPaidErrorCodes) {
|
||||
notifyError(response = response)
|
||||
} else {
|
||||
updateSnackBarState(
|
||||
show = true,
|
||||
messageId = R.string.bbps_bill_refreshed_failed,
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
updateRefreshState(isRefreshing = false, bill = myBillEntity)
|
||||
}
|
||||
|
||||
private suspend fun updateRecentBillsEntity() {
|
||||
@@ -321,55 +432,91 @@ constructor(
|
||||
}
|
||||
|
||||
private fun deleteBill(myBillEntity: MyBillEntity) {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
val savedBills =
|
||||
bbpsCommonRepository.fetchSavedBillsByCategory(
|
||||
category = billCategoryEntity.categoryId
|
||||
)
|
||||
|
||||
if (savedBills.isNotEmpty()) {
|
||||
if (myBillEntity.isNotNull()) {
|
||||
val deleteBillResponse =
|
||||
bbpsCommonRepository.deleteBill(
|
||||
myBillEntity.billId,
|
||||
metricInfo = getBbpsMetricInfo(screenName = naviBbpsVmData.screen.name),
|
||||
)
|
||||
if (deleteBillResponse.isSuccessWithData()) {
|
||||
myBillsSyncJob.refreshBills(naviBbpsVmData.screen.screenName)
|
||||
updateRecentBillsEntity()
|
||||
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,
|
||||
)
|
||||
viewModelScope.launch(dispatcherProvider.io) {
|
||||
myBillActionsHandler.deleteBill(
|
||||
billId = myBillEntity.billId,
|
||||
categoryId = billCategoryEntity.categoryId,
|
||||
screenName = naviBbpsVmData.screen.screenName,
|
||||
onSuccess = { deleteBillResponse ->
|
||||
updateRecentBillsEntity()
|
||||
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,
|
||||
)
|
||||
}
|
||||
updateSnackBarState(showSnackBar = true)
|
||||
naviBbpsAnalytics.billDeletedSuccessfully(
|
||||
data = deleteBillResponse.data!!,
|
||||
myBillEntity = myBillEntity,
|
||||
sessionAttribute = getNaviBbpsSessionAttributes(),
|
||||
source = source,
|
||||
initialSource = initialSource,
|
||||
)
|
||||
} else {
|
||||
notifyError(deleteBillResponse)
|
||||
naviBbpsAnalytics.billDeletionFailed(
|
||||
deleteBillResponse = deleteBillResponse,
|
||||
myBillEntity = myBillEntity,
|
||||
sessionAttribute = getNaviBbpsSessionAttributes(),
|
||||
source = source,
|
||||
initialSource = initialSource,
|
||||
}
|
||||
|
||||
updateSnackBarState(
|
||||
show = true,
|
||||
messageId = R.string.bbps_account_removed_successfully,
|
||||
)
|
||||
naviBbpsAnalytics.billDeletionSuccess(
|
||||
data = deleteBillResponse.data!!,
|
||||
myBillEntity = myBillEntity,
|
||||
sessionAttribute = getNaviBbpsSessionAttributes(),
|
||||
source = source,
|
||||
initialSource = initialSource,
|
||||
)
|
||||
},
|
||||
onError = { deleteBillResponse ->
|
||||
notifyError(deleteBillResponse)
|
||||
naviBbpsAnalytics.billDeletionFailed(
|
||||
deleteBillResponse = deleteBillResponse,
|
||||
myBillEntity = myBillEntity,
|
||||
sessionAttribute = getNaviBbpsSessionAttributes(),
|
||||
source = source,
|
||||
initialSource = initialSource,
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
myBillActionsHandler.markAsPaid(
|
||||
billId = myBillEntity.billId,
|
||||
screenName = naviBbpsVmData.screen.screenName,
|
||||
onSuccess = {
|
||||
updateSnackBarState(show = true, messageId = R.string.bbps_bill_marked_as_paid)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun observeRecentBills() {
|
||||
viewModelScope.launch(dispatcherProvider.io) {
|
||||
bbpsCommonRepository
|
||||
.fetchSavedBillsByCategoryAsFlow(categoryId = billCategoryEntity.categoryId)
|
||||
.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,
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -587,32 +734,6 @@ 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 {
|
||||
|
||||
@@ -13,7 +13,33 @@ import com.navi.rr.common.models.CoinBurnData
|
||||
import com.navi.rr.common.models.OfferData
|
||||
|
||||
sealed class BillerListBottomSheetType {
|
||||
data class MenuOptions(val myBillEntity: MyBillEntity) : BillerListBottomSheetType()
|
||||
data class MenuOptions(
|
||||
val myBillEntity: MyBillEntity,
|
||||
val onMarkAsPaidClicked: () -> Unit,
|
||||
val onRefreshBillClicked: () -> Unit,
|
||||
val onViewBillHistoryClicked: () -> Unit,
|
||||
val onRemoveAccountClicked: () -> Unit,
|
||||
) : BillerListBottomSheetType()
|
||||
|
||||
data class MarkAsPaid(
|
||||
val myBillEntity: MyBillEntity,
|
||||
val title: String,
|
||||
val description: String? = null,
|
||||
val firstBtnText: String,
|
||||
val secondButtonText: String,
|
||||
val onFirstBtnClick: () -> Unit,
|
||||
val onSecondBtnClick: () -> Unit,
|
||||
) : BillerListBottomSheetType()
|
||||
|
||||
data class RemoveAccount(
|
||||
val myBillEntity: MyBillEntity,
|
||||
val title: String,
|
||||
val description: String? = null,
|
||||
val firstBtnTextResId: Int,
|
||||
val secondButtonTextResId: Int,
|
||||
val onFirstBtnClick: () -> Unit,
|
||||
val onSecondBtnClick: () -> Unit,
|
||||
) : BillerListBottomSheetType()
|
||||
|
||||
data object FastagBankDetails : BillerListBottomSheetType()
|
||||
|
||||
@@ -32,6 +58,8 @@ sealed class BillerListBottomSheetType {
|
||||
val coinBurnData: CoinBurnData?,
|
||||
) : BillerListBottomSheetType()
|
||||
|
||||
data object None : BillerListBottomSheetType()
|
||||
|
||||
companion object {
|
||||
fun createEmptyMyBillEntity(): MyBillEntity {
|
||||
return MyBillEntity(
|
||||
|
||||
@@ -8,19 +8,13 @@
|
||||
package com.navi.bbps.feature.billerlist.ui
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.layout.wrapContentHeight
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Alignment.Companion.Start
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
@@ -34,11 +28,16 @@ import com.navi.bbps.common.ICON_FASTAG_BOTTOMSHEET
|
||||
import com.navi.bbps.common.NaviBbpsAnalytics
|
||||
import com.navi.bbps.common.theme.NaviBbpsColor
|
||||
import com.navi.bbps.common.ui.BbpsOfferBottomSheet
|
||||
import com.navi.bbps.common.ui.BillOptionsBottomSheetContent
|
||||
import com.navi.bbps.common.ui.ConfirmationBottomSheetContent
|
||||
import com.navi.bbps.common.ui.ThemeRoundedButton
|
||||
import com.navi.bbps.common.utils.NaviBbpsCommonUtils.isRechargeCategory
|
||||
import com.navi.bbps.feature.billerlist.model.view.BillerListBottomSheetType
|
||||
import com.navi.bbps.feature.mybills.model.view.MyBillEntity
|
||||
import com.navi.bbps.feature.mybills.ui.MarkAsPaidBottomSheetContent
|
||||
import com.navi.bbps.feature.mybills.ui.RemoveAccountBottomSheetContent
|
||||
import com.navi.bbps.getBillTitleFromAccountHolderNameOrPrimaryCustomerParams
|
||||
import com.navi.common.R as CommonR
|
||||
import com.navi.common.utils.firstLetterToLowerCase
|
||||
import com.navi.design.font.FontWeightEnum
|
||||
import com.navi.design.font.getFontWeight
|
||||
import com.navi.design.font.naviFontFamily
|
||||
@@ -48,7 +47,6 @@ import com.navi.naviwidgets.extensions.NaviText
|
||||
fun BillerListBottomSheetContent(
|
||||
billerListBottomSheetType: BillerListBottomSheetType,
|
||||
closeSheet: () -> Unit,
|
||||
onDeleteAccountBillClicked: (MyBillEntity) -> Unit,
|
||||
naviBbpsAnalytics: NaviBbpsAnalytics.BillerList,
|
||||
sessionAttribute: Map<String, String>,
|
||||
source: String,
|
||||
@@ -56,10 +54,45 @@ fun BillerListBottomSheetContent(
|
||||
) {
|
||||
when (billerListBottomSheetType) {
|
||||
is BillerListBottomSheetType.MenuOptions -> {
|
||||
BillerListMenuBottomSheetContent(
|
||||
onDeleteAccountBillClicked = {
|
||||
onDeleteAccountBillClicked.invoke(billerListBottomSheetType.myBillEntity)
|
||||
}
|
||||
BillOptionsBottomSheetContent(
|
||||
billerLogoUrl = billerListBottomSheetType.myBillEntity.billerLogoUrl,
|
||||
title =
|
||||
getBillTitleFromAccountHolderNameOrPrimaryCustomerParams(
|
||||
accountHolderName =
|
||||
billerListBottomSheetType.myBillEntity.unpaidBillDetails
|
||||
?.accountHolderName,
|
||||
primaryCustomerParams =
|
||||
billerListBottomSheetType.myBillEntity.primaryCustomerParamValue,
|
||||
),
|
||||
expiringOn =
|
||||
billerListBottomSheetType.myBillEntity.unpaidBillWarning
|
||||
.firstLetterToLowerCase(),
|
||||
amount = billerListBottomSheetType.myBillEntity.unpaidBillDetails?.amount.orEmpty(),
|
||||
billerName = billerListBottomSheetType.myBillEntity.billerName,
|
||||
onRemoveAccountClicked = {
|
||||
closeSheet()
|
||||
billerListBottomSheetType.onRemoveAccountClicked()
|
||||
},
|
||||
onCloseClicked = { closeSheet() },
|
||||
isBillPaid = billerListBottomSheetType.myBillEntity.isBillPaid,
|
||||
isRechargeCategory =
|
||||
isRechargeCategory(
|
||||
categoryId = billerListBottomSheetType.myBillEntity.categoryId
|
||||
),
|
||||
onMarkAsPaidClicked = {
|
||||
closeSheet()
|
||||
if (!billerListBottomSheetType.myBillEntity.isBillPaid) {
|
||||
billerListBottomSheetType.onMarkAsPaidClicked()
|
||||
}
|
||||
},
|
||||
onRefreshBillClicked = {
|
||||
closeSheet()
|
||||
billerListBottomSheetType.onRefreshBillClicked()
|
||||
},
|
||||
onViewBillHistoryClicked = {
|
||||
closeSheet()
|
||||
billerListBottomSheetType.onViewBillHistoryClicked()
|
||||
},
|
||||
)
|
||||
}
|
||||
is BillerListBottomSheetType.FastagBankDetails -> {
|
||||
@@ -102,38 +135,43 @@ fun BillerListBottomSheetContent(
|
||||
closeSheet = closeSheet,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun BillerListMenuBottomSheetContent(onDeleteAccountBillClicked: () -> Unit) {
|
||||
Column(
|
||||
modifier =
|
||||
Modifier.fillMaxWidth()
|
||||
.wrapContentHeight()
|
||||
.padding(start = 16.dp, top = 16.dp, end = 16.dp, bottom = 32.dp)
|
||||
) {
|
||||
Row(
|
||||
modifier =
|
||||
Modifier.fillMaxWidth().padding(vertical = 16.dp).clickable {
|
||||
onDeleteAccountBillClicked()
|
||||
is BillerListBottomSheetType.MarkAsPaid -> {
|
||||
MarkAsPaidBottomSheetContent(
|
||||
title = billerListBottomSheetType.title,
|
||||
description = billerListBottomSheetType.description,
|
||||
secondaryButtonText = billerListBottomSheetType.firstBtnText,
|
||||
primaryButtonText = billerListBottomSheetType.secondButtonText,
|
||||
onSecondaryButtonClicked = {
|
||||
closeSheet()
|
||||
billerListBottomSheetType.onFirstBtnClick()
|
||||
},
|
||||
onPrimaryButtonClicked = {
|
||||
closeSheet()
|
||||
billerListBottomSheetType.onSecondBtnClick()
|
||||
},
|
||||
horizontalArrangement = Arrangement.Start,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource(id = R.drawable.ic_remove_account),
|
||||
contentDescription = null,
|
||||
)
|
||||
Spacer(modifier = Modifier.width(14.dp))
|
||||
NaviText(
|
||||
text = stringResource(id = R.string.bbps_remove_account),
|
||||
fontSize = 14.sp,
|
||||
fontFamily = naviFontFamily,
|
||||
fontWeight = getFontWeight(FontWeightEnum.NAVI_BODY_REGULAR),
|
||||
color = NaviBbpsColor.textPrimary,
|
||||
}
|
||||
is BillerListBottomSheetType.RemoveAccount -> {
|
||||
RemoveAccountBottomSheetContent(
|
||||
title = billerListBottomSheetType.title,
|
||||
description = billerListBottomSheetType.description,
|
||||
secondaryButtonText =
|
||||
stringResource(id = billerListBottomSheetType.firstBtnTextResId),
|
||||
primaryButtonText =
|
||||
stringResource(id = billerListBottomSheetType.secondButtonTextResId),
|
||||
onSecondaryButtonClicked = {
|
||||
closeSheet()
|
||||
billerListBottomSheetType.onFirstBtnClick()
|
||||
},
|
||||
onPrimaryButtonClicked = {
|
||||
closeSheet()
|
||||
billerListBottomSheetType.onSecondBtnClick()
|
||||
},
|
||||
)
|
||||
}
|
||||
is BillerListBottomSheetType.None -> {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -77,6 +77,7 @@ import com.navi.bbps.initials
|
||||
import com.navi.design.font.FontWeightEnum
|
||||
import com.navi.design.font.getFontWeight
|
||||
import com.navi.design.font.naviFontFamily
|
||||
import com.navi.design.snackbar.ErrorSnackBar
|
||||
import com.navi.design.snackbar.SuccessSnackBar
|
||||
import com.navi.naviwidgets.extensions.NaviText
|
||||
import com.ramcosta.composedestinations.annotation.Destination
|
||||
@@ -116,7 +117,6 @@ fun BillerListScreen(
|
||||
billerListViewModel.showSpaceBelowSearchBar.collectAsStateWithLifecycle()
|
||||
val billerListBottomSheetType by
|
||||
billerListViewModel.billerListBottomSheetType.collectAsStateWithLifecycle()
|
||||
val showSnackBar by billerListViewModel.showSnackBar.collectAsStateWithLifecycle()
|
||||
val bbpsSnackBarPredefinedConfig = remember { BbpsSnackBarPredefinedConfig() }
|
||||
|
||||
val permissionResult by billerListViewModel.permissionResult.collectAsStateWithLifecycle()
|
||||
@@ -126,6 +126,9 @@ fun BillerListScreen(
|
||||
val coinBurnData by billerListViewModel.coinBurnData.collectAsStateWithLifecycle()
|
||||
val multipleOffersDataList by
|
||||
billerListViewModel.multipleOffersDataList.collectAsStateWithLifecycle()
|
||||
val refreshBillItemAndStatus by
|
||||
billerListViewModel.refreshBillItemAndStatus.collectAsStateWithLifecycle()
|
||||
val snackBarState by billerListViewModel.snackBarState.collectAsStateWithLifecycle()
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
naviBbpsAnalytics.onLanded(
|
||||
@@ -214,11 +217,6 @@ fun BillerListScreen(
|
||||
billerListViewModel.onRecentBillItemClicked(myBillEntity = myBillEntity)
|
||||
}
|
||||
|
||||
val onDeleteAccountBillClicked = { myBillEntity: MyBillEntity ->
|
||||
billerListViewModel.onDeleteAccountBillClicked(myBillEntity)
|
||||
openSheet()
|
||||
}
|
||||
|
||||
val onBackClick = {
|
||||
naviBbpsAnalytics.onBackClicked(
|
||||
billCategoryEntity = billCategoryEntity,
|
||||
@@ -348,7 +346,6 @@ fun BillerListScreen(
|
||||
sheetContent = {
|
||||
BillerListBottomSheetContent(
|
||||
billerListBottomSheetType = billerListBottomSheetType,
|
||||
onDeleteAccountBillClicked = onDeleteAccountBillClicked,
|
||||
closeSheet = closeSheet,
|
||||
naviBbpsAnalytics = naviBbpsAnalytics,
|
||||
sessionAttribute = billerListViewModel.getNaviBbpsSessionAttributes(),
|
||||
@@ -466,7 +463,7 @@ fun BillerListScreen(
|
||||
)
|
||||
onRecentBillItemClicked(it)
|
||||
},
|
||||
onDeleteRecentBillClicked = {
|
||||
onBillOptionsKebabMenuClicked = {
|
||||
naviBbpsAnalytics.onDeleteAccountKebabMenuClicked(
|
||||
myBillEntity = it,
|
||||
sessionAttribute =
|
||||
@@ -474,7 +471,10 @@ fun BillerListScreen(
|
||||
source = source,
|
||||
initialSource = initialSource,
|
||||
)
|
||||
billerListViewModel.onDeleteMenuClicked(myBillEntity = it)
|
||||
billerListViewModel.onBillOptionsKebabMenuClicked(
|
||||
myBillEntity = it,
|
||||
openSheet = openSheet,
|
||||
)
|
||||
openSheet()
|
||||
},
|
||||
isSearchBillerRunning = isSearchBillerRunning,
|
||||
@@ -482,6 +482,7 @@ fun BillerListScreen(
|
||||
fetchLocationPermissionState.allPermissionsGranted,
|
||||
naviBbpsAnalytics = naviBbpsAnalytics,
|
||||
multipleOffersDataList = multipleOffersDataList,
|
||||
refreshBillItemAndStatus = refreshBillItemAndStatus,
|
||||
onFailedOrderCalloutClicked = {
|
||||
val failedOrder = it.first
|
||||
val billDetails = it.second
|
||||
@@ -523,23 +524,43 @@ fun BillerListScreen(
|
||||
}
|
||||
},
|
||||
snackbarHost = {
|
||||
if (showSnackBar) {
|
||||
if (snackBarState.show) {
|
||||
Column {
|
||||
SuccessSnackBar(
|
||||
modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp),
|
||||
show = true,
|
||||
snackBarConfig =
|
||||
bbpsSnackBarPredefinedConfig.successConfig(
|
||||
title =
|
||||
stringResource(
|
||||
id = R.string.bbps_account_removed_successfully
|
||||
)
|
||||
),
|
||||
onDismissed = { billerListViewModel.updateSnackBarState(false) },
|
||||
onTrailingIconClicked = {
|
||||
billerListViewModel.updateSnackBarState(false)
|
||||
},
|
||||
)
|
||||
if (snackBarState.messageId == R.string.bbps_bill_refreshed_failed) {
|
||||
ErrorSnackBar(
|
||||
modifier =
|
||||
Modifier.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp, vertical = 32.dp),
|
||||
show = true,
|
||||
snackBarConfig =
|
||||
bbpsSnackBarPredefinedConfig.errorConfig(
|
||||
title = stringResource(id = snackBarState.messageId)
|
||||
),
|
||||
onDismissed = {
|
||||
billerListViewModel.updateSnackBarState(show = false)
|
||||
},
|
||||
onTrailingIconClicked = {
|
||||
billerListViewModel.updateSnackBarState(show = false)
|
||||
},
|
||||
)
|
||||
} else {
|
||||
SuccessSnackBar(
|
||||
modifier =
|
||||
Modifier.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp, vertical = 32.dp),
|
||||
show = true,
|
||||
snackBarConfig =
|
||||
bbpsSnackBarPredefinedConfig.successConfig(
|
||||
title = stringResource(id = snackBarState.messageId)
|
||||
),
|
||||
onDismissed = {
|
||||
billerListViewModel.updateSnackBarState(show = false)
|
||||
},
|
||||
onTrailingIconClicked = {
|
||||
billerListViewModel.updateSnackBarState(show = false)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import androidx.compose.animation.core.tween
|
||||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.animation.slideOutHorizontally
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.border
|
||||
@@ -60,7 +61,6 @@ import androidx.compose.ui.unit.sp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.navi.bbps.R
|
||||
import com.navi.bbps.common.BILL_ITEM_SLIDE_OUT_DURATION
|
||||
import com.navi.bbps.common.BULLET
|
||||
import com.navi.bbps.common.NaviBbpsAnalytics
|
||||
import com.navi.bbps.common.NaviBbpsDimens
|
||||
import com.navi.bbps.common.model.view.RefreshBillState
|
||||
@@ -99,6 +99,7 @@ import com.navi.rr.common.models.OfferData
|
||||
import kotlin.math.ceil
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
fun RenderBillerListScreen(
|
||||
billerListState: BillerListState.Loaded,
|
||||
@@ -108,11 +109,12 @@ fun RenderBillerListScreen(
|
||||
openSheet: () -> Unit,
|
||||
onBillerItemClicked: (BillerItemEntity) -> Unit,
|
||||
onRecentBillItemClicked: (MyBillEntity) -> Unit,
|
||||
onDeleteRecentBillClicked: (MyBillEntity) -> Unit,
|
||||
onBillOptionsKebabMenuClicked: (MyBillEntity) -> Unit,
|
||||
isSearchBillerRunning: Boolean,
|
||||
isLocationPermissionProvided: Boolean,
|
||||
naviBbpsAnalytics: NaviBbpsAnalytics.BillerList,
|
||||
multipleOffersDataList: Map<String, List<OfferData>>?,
|
||||
refreshBillItemAndStatus: RefreshBillState,
|
||||
onFailedOrderCalloutClicked: (Pair<OrderEntity, MyBillEntity>) -> Unit,
|
||||
) {
|
||||
val isScreenFastagRecharge by
|
||||
@@ -217,6 +219,17 @@ fun RenderBillerListScreen(
|
||||
mutableStateOf(billerListState.recentBills.bills.toList())
|
||||
}
|
||||
val vmRecentBills = rememberUpdatedState(billerListState.recentBills.bills)
|
||||
|
||||
fun updateAnimatedRecentBills() {
|
||||
animatedRecentBills = vmRecentBills.value.toList()
|
||||
}
|
||||
|
||||
LaunchedEffect(vmRecentBills.value) {
|
||||
if (animatedRecentBills.size == vmRecentBills.value.size) {
|
||||
updateAnimatedRecentBills()
|
||||
}
|
||||
}
|
||||
|
||||
LazyColumn(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
flingBehavior = maxScrollFlingBehavior(),
|
||||
@@ -301,14 +314,15 @@ fun RenderBillerListScreen(
|
||||
RecentBillerItem(
|
||||
myBillEntity = billItem,
|
||||
onRecentBillItemClicked = { onRecentBillItemClicked(billItem) },
|
||||
onDeleteRecentBillClicked = {
|
||||
onDeleteRecentBillClicked(billItem)
|
||||
onBillOptionsKebabMenuClicked = {
|
||||
onBillOptionsKebabMenuClicked(billItem)
|
||||
},
|
||||
offerData =
|
||||
getOfferDataForMultipleBillItems(
|
||||
multipleOffersDataList = multipleOffersDataList,
|
||||
billId = billItem.billId,
|
||||
),
|
||||
refreshBillItemAndStatus = refreshBillItemAndStatus,
|
||||
failedOrder = failedOrder,
|
||||
onFailedOrderCalloutClicked = onFailedOrderCalloutClicked,
|
||||
)
|
||||
@@ -454,10 +468,11 @@ fun RecentBillerItem(
|
||||
modifier: Modifier = Modifier,
|
||||
myBillEntity: MyBillEntity,
|
||||
onRecentBillItemClicked: () -> Unit,
|
||||
onDeleteRecentBillClicked: (MyBillEntity) -> Unit,
|
||||
onBillOptionsKebabMenuClicked: (MyBillEntity) -> Unit,
|
||||
offerData: OfferData?,
|
||||
failedOrder: OrderEntity? = null,
|
||||
onFailedOrderCalloutClicked: (Pair<OrderEntity, MyBillEntity>) -> Unit,
|
||||
refreshBillItemAndStatus: RefreshBillState,
|
||||
) {
|
||||
Box(modifier = modifier) {
|
||||
Column(
|
||||
@@ -491,52 +506,11 @@ fun RecentBillerItem(
|
||||
Spacer(modifier = Modifier.height(2.dp))
|
||||
BillerNameWithPrimaryCustomerParamValueSection(myBillEntity = myBillEntity)
|
||||
Spacer(modifier = Modifier.height(2.dp))
|
||||
|
||||
if (myBillEntity.isBillPaid) {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
if (myBillEntity.formattedLastPaidAmount.isNotBlank()) {
|
||||
NaviText(
|
||||
text =
|
||||
stringResource(
|
||||
id = R.string.bbps_rupee_symbol_x,
|
||||
myBillEntity.formattedLastPaidAmount,
|
||||
),
|
||||
color = NaviBbpsColor.textPrimary,
|
||||
fontFamily = naviFontFamily,
|
||||
fontSize = 14.sp,
|
||||
fontWeight = getFontWeight(FontWeightEnum.NAVI_BODY_DEMI_BOLD),
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
}
|
||||
if (myBillEntity.formattedLastPaidDate.isNotBlank()) {
|
||||
Spacer(modifier = Modifier.width(4.dp))
|
||||
NaviText(
|
||||
text = BULLET,
|
||||
color = NaviBbpsColor.textPrimary,
|
||||
fontFamily = naviFontFamily,
|
||||
fontSize = 16.sp,
|
||||
fontWeight = getFontWeight(FontWeightEnum.NAVI_BODY_REGULAR),
|
||||
)
|
||||
Spacer(modifier = Modifier.width(4.dp))
|
||||
NaviText(
|
||||
text =
|
||||
"${stringResource(id = R.string.bbps_last_paid)} ${myBillEntity.formattedLastPaidDate}",
|
||||
color = NaviBbpsColor.textTertiary,
|
||||
fontFamily = naviFontFamily,
|
||||
fontSize = 12.sp,
|
||||
fontWeight = getFontWeight(FontWeightEnum.NAVI_BODY_REGULAR),
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
BillAmountAndDueDateSectionWithShimmer(
|
||||
myBillEntity = myBillEntity,
|
||||
refreshBillItemAndStatus = RefreshBillState(),
|
||||
startWithPadding = false,
|
||||
)
|
||||
}
|
||||
BillAmountAndDueDateSectionWithShimmer(
|
||||
myBillEntity = myBillEntity,
|
||||
refreshBillItemAndStatus = refreshBillItemAndStatus,
|
||||
startWithPadding = false,
|
||||
)
|
||||
}
|
||||
Spacer(modifier = Modifier.width(16.dp))
|
||||
|
||||
@@ -576,7 +550,7 @@ fun RecentBillerItem(
|
||||
Modifier.padding(top = 6.dp)
|
||||
.size(24.dp)
|
||||
.align(Alignment.Top)
|
||||
.clickableDebounce { onDeleteRecentBillClicked(myBillEntity) },
|
||||
.clickableDebounce { onBillOptionsKebabMenuClicked(myBillEntity) },
|
||||
)
|
||||
}
|
||||
if (!myBillEntity.isBillPaid) {
|
||||
|
||||
@@ -19,18 +19,15 @@ import com.navi.base.utils.ResourceProvider
|
||||
import com.navi.base.utils.ZERO_STRING
|
||||
import com.navi.base.utils.isNotNull
|
||||
import com.navi.base.utils.orFalse
|
||||
import com.navi.base.utils.retry
|
||||
import com.navi.bbps.R
|
||||
import com.navi.bbps.common.APP_VERSION_CODE
|
||||
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.DEFAULT_RETRY_COUNT
|
||||
import com.navi.bbps.common.NaviBbpsAnalytics
|
||||
import com.navi.bbps.common.NaviBbpsScreen
|
||||
import com.navi.bbps.common.RCBP_CATEGORY
|
||||
import com.navi.bbps.common.RETRY_INTERVAL_IN_SECONDS
|
||||
import com.navi.bbps.common.TXN_AMOUNT
|
||||
import com.navi.bbps.common.model.NaviBbpsVmData
|
||||
import com.navi.bbps.common.model.config.NaviBbpsDefaultConfig
|
||||
@@ -38,6 +35,7 @@ import com.navi.bbps.common.model.view.RefreshBillState
|
||||
import com.navi.bbps.common.repository.BbpsCommonRepository
|
||||
import com.navi.bbps.common.session.NaviBbpsSessionHelper
|
||||
import com.navi.bbps.common.usecase.FindLastOrderWithSuccessfulPaymentUseCase
|
||||
import com.navi.bbps.common.usecase.MyBillActionsHandler
|
||||
import com.navi.bbps.common.usecase.NaviBbpsConfigUseCase
|
||||
import com.navi.bbps.common.usecase.UploadUserDataUseCase
|
||||
import com.navi.bbps.common.utils.BillDetailsResponseToEntityMapper
|
||||
@@ -60,9 +58,7 @@ import com.navi.bbps.feature.category.model.view.PendingBillsShowMoreLessButtonS
|
||||
import com.navi.bbps.feature.category.model.view.RewardDataEntity
|
||||
import com.navi.bbps.feature.contactlist.PhoneContactManager
|
||||
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.BillDetailsResponse
|
||||
import com.navi.bbps.feature.customerinput.model.network.DeviceDetails
|
||||
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
|
||||
@@ -133,6 +129,7 @@ constructor(
|
||||
val uploadUserDataUseCase: UploadUserDataUseCase,
|
||||
open val bbpsSharedPreferences: BbpsSharedPreferences,
|
||||
val findLastOrderWithSuccessfulPaymentUseCase: FindLastOrderWithSuccessfulPaymentUseCase,
|
||||
private val myBillActionsHandler: MyBillActionsHandler,
|
||||
) :
|
||||
NaviBbpsBaseVM(
|
||||
naviBbpsVmData = NaviBbpsVmData(screen = NaviBbpsScreen.NAVI_BBPS_BILL_CATEGORIES)
|
||||
@@ -639,20 +636,37 @@ constructor(
|
||||
|
||||
fun deleteBill(myBillEntity: MyBillEntity) {
|
||||
viewModelScope.launch(dispatcherProvider.io) {
|
||||
val deleteBillResponse =
|
||||
bbpsCommonRepository.deleteBill(
|
||||
myBillEntity.billId,
|
||||
metricInfo = getBbpsMetricInfo(screenName = naviBbpsVmData.screen.screenName),
|
||||
)
|
||||
if (deleteBillResponse.isSuccessWithData()) {
|
||||
myBillsSyncJob.refreshBills(naviBbpsVmData.screen.screenName)
|
||||
updateSnackBarState(
|
||||
show = true,
|
||||
messageId = R.string.bbps_account_removed_successfully,
|
||||
)
|
||||
} else {
|
||||
updateSnackBarState(show = true, messageId = R.string.bbps_account_delete_failed)
|
||||
}
|
||||
myBillActionsHandler.deleteBill(
|
||||
billId = myBillEntity.billId,
|
||||
categoryId = myBillEntity.categoryId,
|
||||
screenName = naviBbpsVmData.screen.screenName,
|
||||
onSuccess = { deleteBillResponse ->
|
||||
naviBbpsAnalytics.billDeletionSuccess(
|
||||
data = deleteBillResponse.data!!,
|
||||
myBillEntity = myBillEntity,
|
||||
sessionAttribute = getNaviBbpsSessionAttributes(),
|
||||
source = source,
|
||||
initialSource = initialSource,
|
||||
)
|
||||
updateSnackBarState(
|
||||
show = true,
|
||||
messageId = R.string.bbps_account_removed_successfully,
|
||||
)
|
||||
},
|
||||
onError = { deleteBillResponse ->
|
||||
naviBbpsAnalytics.billDeletionFailed(
|
||||
deleteBillResponse = deleteBillResponse,
|
||||
myBillEntity = myBillEntity,
|
||||
sessionAttribute = getNaviBbpsSessionAttributes(),
|
||||
source = source,
|
||||
initialSource = initialSource,
|
||||
)
|
||||
updateSnackBarState(
|
||||
show = true,
|
||||
messageId = R.string.bbps_account_delete_failed,
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -818,27 +832,13 @@ constructor(
|
||||
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()) {
|
||||
myBillsSyncJob.refreshBills(naviBbpsVmData.screen.screenName)
|
||||
updateSnackBarState(show = true, messageId = R.string.bbps_bill_marked_as_paid)
|
||||
}
|
||||
myBillActionsHandler.markAsPaid(
|
||||
billId = myBillEntity.billId,
|
||||
screenName = naviBbpsVmData.screen.screenName,
|
||||
onSuccess = {
|
||||
updateSnackBarState(show = true, messageId = R.string.bbps_bill_marked_as_paid)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -852,33 +852,27 @@ constructor(
|
||||
}
|
||||
|
||||
updateRefreshState(isRefreshing = true, bill = myBillEntity)
|
||||
val billDetailsRequest =
|
||||
BillDetailsRequest(
|
||||
billerId = myBillEntity.billerId,
|
||||
customerParams = myBillEntity.customerParams,
|
||||
deviceDetails = DeviceDetails(ip = naviNetworkConnectivity.getIpAddress()),
|
||||
amount = myBillEntity.actualLastPaidAmount,
|
||||
isConsentProvided = true,
|
||||
)
|
||||
|
||||
val billDetailsResponse =
|
||||
bbpsCommonRepository.fetchBillDetails(
|
||||
billDetailsRequest = billDetailsRequest,
|
||||
metricInfo = getBbpsMetricInfo(screenName = naviBbpsVmData.screen.screenName),
|
||||
)
|
||||
|
||||
if (billDetailsResponse.isSuccessWithData()) {
|
||||
myBillEntity.unpaidBillDetails?.let {
|
||||
myBillsSyncJob.refreshBills(naviBbpsVmData.screen.screenName)
|
||||
myBillActionsHandler.refreshBill(
|
||||
myBillEntity = myBillEntity,
|
||||
screenName = naviBbpsVmData.screen.screenName,
|
||||
onSuccess = {
|
||||
updateSnackBarState(
|
||||
show = true,
|
||||
messageId = R.string.bbps_bill_refreshed_sucessfully,
|
||||
)
|
||||
}
|
||||
} else {
|
||||
updateSnackBarState(show = true, messageId = R.string.bbps_bill_refreshed_failed)
|
||||
}
|
||||
|
||||
},
|
||||
onError = { response ->
|
||||
val errorCode = getError(response).code
|
||||
if (errorCode in naviBbpsDefaultConfig.billAlreadyPaidErrorCodes) {
|
||||
notifyError(response = response)
|
||||
} else {
|
||||
updateSnackBarState(
|
||||
show = true,
|
||||
messageId = R.string.bbps_bill_refreshed_failed,
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
updateRefreshState(isRefreshing = false, bill = myBillEntity)
|
||||
}
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ import com.navi.bbps.common.model.view.NaviPermissionResult
|
||||
import com.navi.bbps.common.repository.BbpsCommonRepository
|
||||
import com.navi.bbps.common.session.NaviBbpsSessionHelper
|
||||
import com.navi.bbps.common.usecase.FindLastOrderWithSuccessfulPaymentUseCase
|
||||
import com.navi.bbps.common.usecase.MyBillActionsHandler
|
||||
import com.navi.bbps.common.usecase.NaviBbpsConfigUseCase
|
||||
import com.navi.bbps.common.usecase.OriginExperimentUtils
|
||||
import com.navi.bbps.common.usecase.UploadUserDataUseCase
|
||||
@@ -91,6 +92,7 @@ constructor(
|
||||
bbpsCommonRepository: BbpsCommonRepository,
|
||||
naviNetworkConnectivity: NaviNetworkConnectivity,
|
||||
uploadUserDataUseCase: UploadUserDataUseCase,
|
||||
myBillActionsHandler: MyBillActionsHandler,
|
||||
@NaviBbpsGsonBuilder val naviBbpsGson: Gson,
|
||||
private val resourceProvider: ResourceProvider,
|
||||
val originBillDetectionHandler: OriginBillDetectionHandler,
|
||||
@@ -120,6 +122,7 @@ constructor(
|
||||
uploadUserDataUseCase = uploadUserDataUseCase,
|
||||
bbpsSharedPreferences = bbpsSharedPreferences,
|
||||
findLastOrderWithSuccessfulPaymentUseCase = findLastOrderWithSuccessfulPaymentUseCase,
|
||||
myBillActionsHandler = myBillActionsHandler,
|
||||
),
|
||||
BottomSheetController by BottomSheetControllerImpl() {
|
||||
|
||||
|
||||
@@ -12,12 +12,13 @@ import androidx.compose.ui.res.stringResource
|
||||
import com.navi.bbps.common.NaviBbpsAnalytics
|
||||
import com.navi.bbps.common.arc.ui.ArcNudgeBottomSheetContent
|
||||
import com.navi.bbps.common.ui.BbpsOfferBottomSheet
|
||||
import com.navi.bbps.common.ui.BillOptionsBottomSheetContent
|
||||
import com.navi.bbps.common.ui.TitleDescriptionWithLinearProgressBar
|
||||
import com.navi.bbps.common.utils.NaviBbpsCommonUtils.isRechargeCategory
|
||||
import com.navi.bbps.common.utils.getDisplayableAmount
|
||||
import com.navi.bbps.feature.category.model.view.BillCategoryBottomSheetType
|
||||
import com.navi.bbps.feature.mybills.ui.MarkAsPaidBottomSheetContent
|
||||
import com.navi.bbps.feature.mybills.ui.RemoveAccountBottomSheetContent
|
||||
import com.navi.bbps.feature.mybills.ui.UnpaidBillOptionsBottomSheetContent
|
||||
import com.navi.bbps.getBillTitleFromAccountHolderNameOrPrimaryCustomerParams
|
||||
import com.navi.common.utils.firstLetterToLowerCase
|
||||
|
||||
@@ -90,13 +91,15 @@ fun BillCategoryBottomSheetContent(
|
||||
)
|
||||
}
|
||||
is BillCategoryBottomSheetType.UnpaidBillOptions -> {
|
||||
UnpaidBillOptionsBottomSheetContent(
|
||||
BillOptionsBottomSheetContent(
|
||||
billerLogoUrl = billCategoryBottomSheetType.myBillEntity.billerLogoUrl,
|
||||
title =
|
||||
getBillTitleFromAccountHolderNameOrPrimaryCustomerParams(
|
||||
billCategoryBottomSheetType.myBillEntity.unpaidBillDetails
|
||||
?.accountHolderName,
|
||||
billCategoryBottomSheetType.myBillEntity.primaryCustomerParamValue,
|
||||
accountHolderName =
|
||||
billCategoryBottomSheetType.myBillEntity.unpaidBillDetails
|
||||
?.accountHolderName,
|
||||
primaryCustomerParams =
|
||||
billCategoryBottomSheetType.myBillEntity.primaryCustomerParamValue,
|
||||
),
|
||||
expiringOn =
|
||||
billCategoryBottomSheetType.myBillEntity.unpaidBillWarning
|
||||
@@ -106,7 +109,11 @@ fun BillCategoryBottomSheetContent(
|
||||
?.amount
|
||||
?.getDisplayableAmount()
|
||||
.orEmpty(),
|
||||
operatorName = billCategoryBottomSheetType.myBillEntity.billerName,
|
||||
billerName = billCategoryBottomSheetType.myBillEntity.billerName,
|
||||
isRechargeCategory =
|
||||
isRechargeCategory(
|
||||
categoryId = billCategoryBottomSheetType.myBillEntity.categoryId
|
||||
),
|
||||
onMarkAsPaidClicked = {
|
||||
closeSheet()
|
||||
naviBbpsAnalytics.onMyBillMoreOptionsBottomSheetClicked(
|
||||
|
||||
@@ -29,9 +29,11 @@ import com.navi.bbps.common.mapper.BillResponseToBillDetailsEntityMapper
|
||||
import com.navi.bbps.common.model.NaviBbpsVmData
|
||||
import com.navi.bbps.common.model.config.NaviBbpsDefaultConfig
|
||||
import com.navi.bbps.common.model.view.NaviPermissionResult
|
||||
import com.navi.bbps.common.model.view.RefreshBillState
|
||||
import com.navi.bbps.common.repository.BbpsCommonRepository
|
||||
import com.navi.bbps.common.session.NaviBbpsSessionHelper
|
||||
import com.navi.bbps.common.usecase.FindLastOrderWithSuccessfulPaymentUseCase
|
||||
import com.navi.bbps.common.usecase.MyBillActionsHandler
|
||||
import com.navi.bbps.common.usecase.NaviBbpsConfigUseCase
|
||||
import com.navi.bbps.common.usecase.RewardNudgeUseCase
|
||||
import com.navi.bbps.common.utils.BillDetailsResponseToEntityMapper
|
||||
@@ -50,9 +52,12 @@ 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.MyBillHistoryDetailsScreenDestination
|
||||
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.network.PaymentAmountExactness
|
||||
import com.navi.bbps.feature.paybill.model.view.PayBillSource
|
||||
@@ -68,6 +73,7 @@ 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
|
||||
@@ -76,7 +82,6 @@ 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
|
||||
@@ -101,7 +106,10 @@ constructor(
|
||||
private val billDetailsResponseToEntityMapper: BillDetailsResponseToEntityMapper,
|
||||
private val resourceProvider: ResourceProvider,
|
||||
private val naviBbpsDateUtils: NaviBbpsDateUtils,
|
||||
private val findLastOrderWithSuccessfulPaymentUseCase: FindLastOrderWithSuccessfulPaymentUseCase,
|
||||
private val findLastOrderWithSuccessfulPaymentUseCase:
|
||||
FindLastOrderWithSuccessfulPaymentUseCase,
|
||||
private val myBillsRepository: MyBillsRepository,
|
||||
private val myBillActionsHandler: MyBillActionsHandler,
|
||||
) :
|
||||
NaviBbpsBaseVM(
|
||||
naviBbpsVmData = NaviBbpsVmData(screen = NaviBbpsScreen.NAVI_BBPS_CONTACT_LIST_SCREEN)
|
||||
@@ -137,6 +145,12 @@ constructor(
|
||||
|
||||
private var operatorBillersList = emptyList<BillerItemEntity>()
|
||||
|
||||
private val _snackBarState = MutableStateFlow(SnackBarState(show = false))
|
||||
val snackBarState = _snackBarState.asStateFlow()
|
||||
|
||||
private val _refreshBillItemAndStatus = MutableStateFlow(RefreshBillState())
|
||||
val refreshBillItemAndStatus = _refreshBillItemAndStatus.asStateFlow()
|
||||
|
||||
val isSearchQueryEmpty: StateFlow<Boolean> =
|
||||
_searchQuery
|
||||
.map { it.isEmpty() }
|
||||
@@ -156,9 +170,6 @@ constructor(
|
||||
private val _showPostpaidBottomSheet = MutableSharedFlow<Boolean>()
|
||||
val showPostpaidBottomSheet = _showPostpaidBottomSheet.asSharedFlow()
|
||||
|
||||
private val _showSnackBar = MutableStateFlow(false)
|
||||
val showSnackBar = _showSnackBar.asStateFlow()
|
||||
|
||||
private val _allRecentBills = MutableStateFlow(RecentBillsEntity("", emptyList()))
|
||||
val allRecentBills = _allRecentBills.asStateFlow()
|
||||
|
||||
@@ -166,11 +177,7 @@ constructor(
|
||||
val isContactListEmpty = _isContactListEmpty.asStateFlow()
|
||||
|
||||
private val _contactListBottomSheetType =
|
||||
MutableStateFlow<ContactListBottomSheetType>(
|
||||
ContactListBottomSheetType.MenuOptions(
|
||||
ContactListBottomSheetType.createEmptyMyBillEntity()
|
||||
)
|
||||
)
|
||||
MutableStateFlow<ContactListBottomSheetType>(ContactListBottomSheetType.None)
|
||||
val contactListBottomSheetType = _contactListBottomSheetType.asStateFlow()
|
||||
|
||||
var isPermissionPopupSeenOnLanded = false
|
||||
@@ -187,8 +194,12 @@ constructor(
|
||||
_contactListState.update { contactListState }
|
||||
}
|
||||
|
||||
fun updateSnackBarState(showSnackBar: Boolean) {
|
||||
_showSnackBar.update { showSnackBar }
|
||||
fun updateSnackBarState(show: Boolean, messageId: Int = R.string.bbps_copied_to_clipboard) {
|
||||
_snackBarState.update { SnackBarState(show = show, messageId = messageId) }
|
||||
}
|
||||
|
||||
private fun updateRefreshState(isRefreshing: Boolean, bill: MyBillEntity? = null) {
|
||||
_refreshBillItemAndStatus.value = RefreshBillState(isRefreshing, bill)
|
||||
}
|
||||
|
||||
val phoneNumber = MutableStateFlow("")
|
||||
@@ -495,11 +506,20 @@ constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun getRecentBills(): RecentBillsEntity {
|
||||
val savedBills =
|
||||
bbpsCommonRepository.fetchSavedBillsByCategory(category = billCategoryEntity.categoryId)
|
||||
|
||||
return RecentBillsEntity(
|
||||
title = resourceProvider.getString(R.string.bbps_recent_recharges),
|
||||
bills = savedBills,
|
||||
)
|
||||
}
|
||||
|
||||
private fun observeRecentBills() {
|
||||
viewModelScope.launch(dispatcherProvider.io) {
|
||||
bbpsCommonRepository
|
||||
.fetchSavedBillsByCategoryAsFlow(categoryId = billCategoryEntity.categoryId)
|
||||
.distinctUntilChanged()
|
||||
.collectLatest { recentBills ->
|
||||
if (contactListUIState.value is ContactListState.Loaded) {
|
||||
updateContactListUIState(
|
||||
@@ -519,33 +539,148 @@ constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun getRecentBills(): RecentBillsEntity {
|
||||
val savedBills =
|
||||
bbpsCommonRepository.fetchSavedBillsByCategory(category = billCategoryEntity.categoryId)
|
||||
|
||||
return RecentBillsEntity(
|
||||
title = resourceProvider.getString(R.string.bbps_recent_recharges),
|
||||
bills = savedBills,
|
||||
)
|
||||
}
|
||||
|
||||
fun onDeleteMenuClicked(myBillEntity: MyBillEntity) {
|
||||
_contactListBottomSheetType.update { ContactListBottomSheetType.MenuOptions(myBillEntity) }
|
||||
}
|
||||
|
||||
fun onDeleteAccountBillClicked(myBillEntity: MyBillEntity) {
|
||||
fun onBillOptionsKebabMenuClicked(myBillEntity: MyBillEntity, openSheet: () -> Unit) {
|
||||
_contactListBottomSheetType.update {
|
||||
ContactListBottomSheetType.Confirmation(
|
||||
title = naviBbpsDefaultConfig.configMessage.removeAccountBottomSheetTitle,
|
||||
description = naviBbpsDefaultConfig.configMessage.removeAccountBottomSheetMessage,
|
||||
firstBtnTextResId = R.string.bbps_cancel,
|
||||
secondButtonTextResId = R.string.bbps_remove,
|
||||
onFirstBtnClick = {},
|
||||
onSecondBtnClick = { deleteBill(myBillEntity) },
|
||||
ContactListBottomSheetType.MenuOptions(
|
||||
myBillEntity = myBillEntity,
|
||||
onMarkAsPaidClicked = {
|
||||
viewModelScope.launch {
|
||||
delay(200)
|
||||
/* this is added to make sure the bottom sheet is closed before
|
||||
opening the new one and to make the transition smoother */
|
||||
_contactListBottomSheetType.update {
|
||||
naviBbpsAnalytics.onBillOptionsClicked(
|
||||
sessionAttribute = getNaviBbpsSessionAttributes(),
|
||||
billEntity = myBillEntity,
|
||||
action = resourceProvider.getString(R.string.bbps_mark_as_paid),
|
||||
)
|
||||
ContactListBottomSheetType.MarkAsPaid(
|
||||
myBillEntity = myBillEntity,
|
||||
title =
|
||||
resourceProvider.getString(
|
||||
R.string.bbps_bill_mark_as_paid_heading
|
||||
),
|
||||
description =
|
||||
resourceProvider.getString(
|
||||
R.string.bbps_bill_mark_as_paid_description
|
||||
),
|
||||
firstBtnText = resourceProvider.getString(R.string.bbps_no),
|
||||
secondButtonText = resourceProvider.getString(R.string.bbps_yes),
|
||||
onFirstBtnClick = {},
|
||||
onSecondBtnClick = {
|
||||
onMarkBillAsPaidConfirmedCtaClicked(myBillEntity = myBillEntity)
|
||||
},
|
||||
)
|
||||
}
|
||||
openSheet.invoke()
|
||||
}
|
||||
},
|
||||
onRefreshBillClicked = {
|
||||
naviBbpsAnalytics.onBillOptionsClicked(
|
||||
sessionAttribute = getNaviBbpsSessionAttributes(),
|
||||
billEntity = myBillEntity,
|
||||
action = resourceProvider.getString(R.string.bbps_refresh_bill),
|
||||
)
|
||||
viewModelScope.launch {
|
||||
if (!naviNetworkConnectivity.isInternetConnected()) {
|
||||
notifyError(getNoInternetErrorConfig())
|
||||
return@launch
|
||||
} else {
|
||||
refreshBillAndUpdateInfo(myBillEntity = myBillEntity)
|
||||
}
|
||||
}
|
||||
},
|
||||
onViewBillHistoryClicked = {
|
||||
naviBbpsAnalytics.onBillOptionsClicked(
|
||||
sessionAttribute = getNaviBbpsSessionAttributes(),
|
||||
billEntity = myBillEntity,
|
||||
action = resourceProvider.getString(R.string.bbps_view_bill_history),
|
||||
)
|
||||
viewModelScope.launch {
|
||||
delay(200)
|
||||
_navigateToNextScreen.emit(
|
||||
MyBillHistoryDetailsScreenDestination(
|
||||
myBillEntity = myBillEntity,
|
||||
source = naviBbpsVmData.screen.name,
|
||||
initialSource = initialSource,
|
||||
)
|
||||
)
|
||||
}
|
||||
},
|
||||
onRemoveAccountClicked = {
|
||||
naviBbpsAnalytics.onBillOptionsClicked(
|
||||
sessionAttribute = getNaviBbpsSessionAttributes(),
|
||||
billEntity = myBillEntity,
|
||||
action = resourceProvider.getString(R.string.bbps_remove_account),
|
||||
)
|
||||
viewModelScope.launch {
|
||||
delay(200)
|
||||
_contactListBottomSheetType.update {
|
||||
ContactListBottomSheetType.RemoveAccount(
|
||||
myBillEntity = myBillEntity,
|
||||
title =
|
||||
naviBbpsDefaultConfig.configMessage
|
||||
.removeAccountBottomSheetTitle,
|
||||
description =
|
||||
naviBbpsDefaultConfig.configMessage
|
||||
.removeAccountBottomSheetMessage,
|
||||
firstBtnTextResId = R.string.bbps_cancel,
|
||||
secondButtonTextResId = R.string.bbps_remove,
|
||||
onFirstBtnClick = {},
|
||||
onSecondBtnClick = { deleteBill(myBillEntity) },
|
||||
)
|
||||
}
|
||||
openSheet.invoke()
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
myBillActionsHandler.markAsPaid(
|
||||
billId = myBillEntity.billId,
|
||||
screenName = naviBbpsVmData.screen.screenName,
|
||||
onSuccess = {
|
||||
updateSnackBarState(show = true, messageId = R.string.bbps_bill_marked_as_paid)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun refreshBillAndUpdateInfo(myBillEntity: MyBillEntity) {
|
||||
updateRefreshState(isRefreshing = true, bill = myBillEntity)
|
||||
myBillActionsHandler.refreshBill(
|
||||
myBillEntity = myBillEntity,
|
||||
screenName = naviBbpsVmData.screen.screenName,
|
||||
onSuccess = {
|
||||
updateSnackBarState(
|
||||
show = true,
|
||||
messageId = R.string.bbps_bill_refreshed_sucessfully,
|
||||
)
|
||||
},
|
||||
onError = { response ->
|
||||
val errorCode = getError(response).code
|
||||
if (errorCode in naviBbpsDefaultConfig.billAlreadyPaidErrorCodes) {
|
||||
notifyError(response = response)
|
||||
} else {
|
||||
updateSnackBarState(
|
||||
show = true,
|
||||
messageId = R.string.bbps_bill_refreshed_failed,
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
updateRefreshState(isRefreshing = false, bill = myBillEntity)
|
||||
}
|
||||
|
||||
fun updateInvalidContactListBottomSheetType() {
|
||||
_contactListBottomSheetType.update {
|
||||
ContactListBottomSheetType.InvalidContactNumberSelection(
|
||||
@@ -557,32 +692,38 @@ constructor(
|
||||
|
||||
private fun deleteBill(myBillEntity: MyBillEntity) {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
val deleteBillResponse =
|
||||
bbpsCommonRepository.deleteBill(
|
||||
myBillEntity.billId,
|
||||
metricInfo = getBbpsMetricInfo(screenName = naviBbpsVmData.screen.screenName),
|
||||
)
|
||||
if (deleteBillResponse.isSuccessWithData()) {
|
||||
naviBbpsAnalytics.billDeletedSuccessfully(
|
||||
data = deleteBillResponse.data!!,
|
||||
myBillEntity = myBillEntity,
|
||||
sessionAttribute = getNaviBbpsSessionAttributes(),
|
||||
source = source,
|
||||
initialSource = initialSource,
|
||||
)
|
||||
myBillsSyncJob.refreshBills(naviBbpsVmData.screen.screenName)
|
||||
fetchContacts()
|
||||
updateSnackBarState(true)
|
||||
} else {
|
||||
naviBbpsAnalytics.billDeletionFailed(
|
||||
deleteBillResponse = deleteBillResponse,
|
||||
myBillEntity = myBillEntity,
|
||||
sessionAttribute = getNaviBbpsSessionAttributes(),
|
||||
source = source,
|
||||
initialSource = initialSource,
|
||||
)
|
||||
notifyError(deleteBillResponse)
|
||||
}
|
||||
myBillActionsHandler.deleteBill(
|
||||
billId = myBillEntity.billId,
|
||||
categoryId = billCategoryEntity.categoryId,
|
||||
screenName = naviBbpsVmData.screen.screenName,
|
||||
onSuccess = { deleteBillResponse ->
|
||||
naviBbpsAnalytics.billDeletionSuccess(
|
||||
data = deleteBillResponse.data!!,
|
||||
myBillEntity = myBillEntity,
|
||||
sessionAttribute = getNaviBbpsSessionAttributes(),
|
||||
source = source,
|
||||
initialSource = initialSource,
|
||||
)
|
||||
fetchContacts()
|
||||
updateSnackBarState(
|
||||
show = true,
|
||||
messageId = R.string.bbps_account_removed_successfully,
|
||||
)
|
||||
},
|
||||
onError = { deleteBillResponse ->
|
||||
naviBbpsAnalytics.billDeletionFailed(
|
||||
deleteBillResponse = deleteBillResponse,
|
||||
myBillEntity = myBillEntity,
|
||||
sessionAttribute = getNaviBbpsSessionAttributes(),
|
||||
source = source,
|
||||
initialSource = initialSource,
|
||||
)
|
||||
updateSnackBarState(
|
||||
show = true,
|
||||
messageId = R.string.bbps_account_delete_failed,
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,33 @@ import com.navi.rr.common.models.CoinBurnData
|
||||
import com.navi.rr.common.models.OfferData
|
||||
|
||||
sealed class ContactListBottomSheetType {
|
||||
data class MenuOptions(val myBillEntity: MyBillEntity) : ContactListBottomSheetType()
|
||||
data class MenuOptions(
|
||||
val myBillEntity: MyBillEntity,
|
||||
val onMarkAsPaidClicked: () -> Unit,
|
||||
val onRefreshBillClicked: () -> Unit,
|
||||
val onViewBillHistoryClicked: () -> Unit,
|
||||
val onRemoveAccountClicked: () -> Unit,
|
||||
) : ContactListBottomSheetType()
|
||||
|
||||
data class MarkAsPaid(
|
||||
val myBillEntity: MyBillEntity,
|
||||
val title: String,
|
||||
val description: String? = null,
|
||||
val firstBtnText: String,
|
||||
val secondButtonText: String,
|
||||
val onFirstBtnClick: () -> Unit,
|
||||
val onSecondBtnClick: () -> Unit,
|
||||
) : ContactListBottomSheetType()
|
||||
|
||||
data class RemoveAccount(
|
||||
val myBillEntity: MyBillEntity,
|
||||
val title: String,
|
||||
val description: String? = null,
|
||||
val firstBtnTextResId: Int,
|
||||
val secondButtonTextResId: Int,
|
||||
val onFirstBtnClick: () -> Unit,
|
||||
val onSecondBtnClick: () -> Unit,
|
||||
) : ContactListBottomSheetType()
|
||||
|
||||
data class Confirmation(
|
||||
val title: String,
|
||||
@@ -39,6 +65,8 @@ sealed class ContactListBottomSheetType {
|
||||
val phoneNumberDetailEntity: PhoneContactEntity,
|
||||
) : ContactListBottomSheetType()
|
||||
|
||||
data object None : ContactListBottomSheetType()
|
||||
|
||||
companion object {
|
||||
fun createEmptyMyBillEntity(): MyBillEntity {
|
||||
return MyBillEntity(
|
||||
|
||||
@@ -7,9 +7,6 @@
|
||||
|
||||
package com.navi.bbps.feature.contactlist.ui
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
@@ -19,7 +16,6 @@ import androidx.compose.foundation.layout.heightIn
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.layout.wrapContentHeight
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
@@ -29,7 +25,6 @@ import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalConfiguration
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
@@ -40,14 +35,19 @@ import com.navi.bbps.common.NaviBbpsAnalytics
|
||||
import com.navi.bbps.common.theme.NaviBbpsColor
|
||||
import com.navi.bbps.common.ui.BbpsCircleImage
|
||||
import com.navi.bbps.common.ui.BbpsOfferBottomSheet
|
||||
import com.navi.bbps.common.ui.BillOptionsBottomSheetContent
|
||||
import com.navi.bbps.common.ui.BottomSheetContentWithIconHeaderPrimarySecondaryButton
|
||||
import com.navi.bbps.common.ui.ConfirmationBottomSheetContent
|
||||
import com.navi.bbps.common.utils.NaviBbpsCommonUtils.isRechargeCategory
|
||||
import com.navi.bbps.feature.billerlist.model.view.BillerItemEntity
|
||||
import com.navi.bbps.feature.contactlist.model.view.ContactListBottomSheetType
|
||||
import com.navi.bbps.feature.contactlist.model.view.PhoneContactEntity
|
||||
import com.navi.bbps.feature.mybills.model.view.MyBillEntity
|
||||
import com.navi.bbps.feature.mybills.ui.MarkAsPaidBottomSheetContent
|
||||
import com.navi.bbps.feature.mybills.ui.RemoveAccountBottomSheetContent
|
||||
import com.navi.bbps.getBillTitleFromAccountHolderNameOrPrimaryCustomerParams
|
||||
import com.navi.common.R as CommonR
|
||||
import com.navi.common.customview.LoaderRoundedButton
|
||||
import com.navi.common.utils.firstLetterToLowerCase
|
||||
import com.navi.design.font.FontWeightEnum
|
||||
import com.navi.design.font.getFontWeight
|
||||
import com.navi.design.font.naviFontFamily
|
||||
@@ -57,7 +57,6 @@ import com.navi.naviwidgets.extensions.NaviText
|
||||
fun ContactListBottomSheetContent(
|
||||
contactListBottomSheetType: ContactListBottomSheetType,
|
||||
closeSheet: () -> Unit,
|
||||
onDeleteAccountBillClicked: (MyBillEntity) -> Unit,
|
||||
naviBbpsAnalytics: NaviBbpsAnalytics.ContactList,
|
||||
sessionAttribute: Map<String, String>,
|
||||
source: String,
|
||||
@@ -70,10 +69,46 @@ fun ContactListBottomSheetContent(
|
||||
|
||||
when (contactListBottomSheetType) {
|
||||
is ContactListBottomSheetType.MenuOptions -> {
|
||||
ContactListMenuBottomSheetContent(
|
||||
onDeleteAccountBillClicked = {
|
||||
onDeleteAccountBillClicked.invoke(contactListBottomSheetType.myBillEntity)
|
||||
}
|
||||
BillOptionsBottomSheetContent(
|
||||
billerLogoUrl = contactListBottomSheetType.myBillEntity.billerLogoUrl,
|
||||
title =
|
||||
getBillTitleFromAccountHolderNameOrPrimaryCustomerParams(
|
||||
accountHolderName =
|
||||
contactListBottomSheetType.myBillEntity.unpaidBillDetails
|
||||
?.accountHolderName,
|
||||
primaryCustomerParams =
|
||||
contactListBottomSheetType.myBillEntity.primaryCustomerParamValue,
|
||||
),
|
||||
expiringOn =
|
||||
contactListBottomSheetType.myBillEntity.unpaidBillWarning
|
||||
.firstLetterToLowerCase(),
|
||||
isBillPaid = contactListBottomSheetType.myBillEntity.isBillPaid,
|
||||
amount =
|
||||
contactListBottomSheetType.myBillEntity.unpaidBillDetails?.amount.toString(),
|
||||
billerName = contactListBottomSheetType.myBillEntity.billerName,
|
||||
isRechargeCategory =
|
||||
isRechargeCategory(
|
||||
categoryId = contactListBottomSheetType.myBillEntity.categoryId
|
||||
),
|
||||
onRemoveAccountClicked = {
|
||||
closeSheet()
|
||||
contactListBottomSheetType.onRemoveAccountClicked()
|
||||
},
|
||||
onCloseClicked = { closeSheet() },
|
||||
onMarkAsPaidClicked = {
|
||||
closeSheet()
|
||||
if (!contactListBottomSheetType.myBillEntity.isBillPaid) {
|
||||
contactListBottomSheetType.onMarkAsPaidClicked()
|
||||
}
|
||||
},
|
||||
onRefreshBillClicked = {
|
||||
closeSheet()
|
||||
contactListBottomSheetType.onRefreshBillClicked()
|
||||
},
|
||||
onViewBillHistoryClicked = {
|
||||
closeSheet()
|
||||
contactListBottomSheetType.onViewBillHistoryClicked()
|
||||
},
|
||||
)
|
||||
}
|
||||
is ContactListBottomSheetType.Confirmation -> {
|
||||
@@ -113,6 +148,40 @@ fun ContactListBottomSheetContent(
|
||||
closeSheet = closeSheet,
|
||||
)
|
||||
}
|
||||
is ContactListBottomSheetType.MarkAsPaid -> {
|
||||
MarkAsPaidBottomSheetContent(
|
||||
title = contactListBottomSheetType.title,
|
||||
description = contactListBottomSheetType.description,
|
||||
secondaryButtonText = contactListBottomSheetType.firstBtnText,
|
||||
primaryButtonText = contactListBottomSheetType.secondButtonText,
|
||||
onSecondaryButtonClicked = {
|
||||
closeSheet()
|
||||
contactListBottomSheetType.onFirstBtnClick()
|
||||
},
|
||||
onPrimaryButtonClicked = {
|
||||
closeSheet()
|
||||
contactListBottomSheetType.onSecondBtnClick()
|
||||
},
|
||||
)
|
||||
}
|
||||
is ContactListBottomSheetType.RemoveAccount -> {
|
||||
RemoveAccountBottomSheetContent(
|
||||
title = contactListBottomSheetType.title,
|
||||
description = contactListBottomSheetType.description,
|
||||
secondaryButtonText =
|
||||
stringResource(id = contactListBottomSheetType.firstBtnTextResId),
|
||||
primaryButtonText =
|
||||
stringResource(id = contactListBottomSheetType.secondButtonTextResId),
|
||||
onSecondaryButtonClicked = {
|
||||
closeSheet()
|
||||
contactListBottomSheetType.onFirstBtnClick()
|
||||
},
|
||||
onPrimaryButtonClicked = {
|
||||
closeSheet()
|
||||
contactListBottomSheetType.onSecondBtnClick()
|
||||
},
|
||||
)
|
||||
}
|
||||
is ContactListBottomSheetType.InvalidContactNumberSelection -> {
|
||||
BottomSheetContentWithIconHeaderPrimarySecondaryButton(
|
||||
iconId = CommonR.drawable.ic_purple_exclamation,
|
||||
@@ -135,37 +204,8 @@ fun ContactListBottomSheetContent(
|
||||
onPostpaidOperatorSelectionContinueClicked,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ContactListMenuBottomSheetContent(onDeleteAccountBillClicked: () -> Unit) {
|
||||
Column(
|
||||
modifier =
|
||||
Modifier.fillMaxWidth()
|
||||
.wrapContentHeight()
|
||||
.padding(start = 16.dp, top = 16.dp, end = 16.dp, bottom = 32.dp)
|
||||
) {
|
||||
Row(
|
||||
modifier =
|
||||
Modifier.fillMaxWidth().padding(vertical = 16.dp).clickable {
|
||||
onDeleteAccountBillClicked()
|
||||
},
|
||||
horizontalArrangement = Arrangement.Start,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource(id = R.drawable.ic_remove_account),
|
||||
contentDescription = null,
|
||||
)
|
||||
Spacer(modifier = Modifier.width(14.dp))
|
||||
NaviText(
|
||||
text = stringResource(id = R.string.bbps_remove_account),
|
||||
fontSize = 14.sp,
|
||||
fontFamily = naviFontFamily,
|
||||
fontWeight = getFontWeight(FontWeightEnum.NAVI_BODY_REGULAR),
|
||||
color = NaviBbpsColor.textPrimary,
|
||||
)
|
||||
is ContactListBottomSheetType.None -> {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,9 +61,9 @@ import com.navi.bbps.feature.contactlist.model.view.ContactListState.Loaded
|
||||
import com.navi.bbps.feature.contactlist.model.view.ContactListState.Loading
|
||||
import com.navi.bbps.feature.contactlist.model.view.PhoneContactEntity
|
||||
import com.navi.bbps.feature.destinations.NaviBbpsPermissionScreenDestination
|
||||
import com.navi.bbps.feature.mybills.model.view.MyBillEntity
|
||||
import com.navi.bbps.feature.permission.utils.PermissionKeys
|
||||
import com.navi.bbps.feature.permission.utils.PermissionUtils
|
||||
import com.navi.design.snackbar.ErrorSnackBar
|
||||
import com.navi.design.snackbar.SuccessSnackBar
|
||||
import com.ramcosta.composedestinations.annotation.Destination
|
||||
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
|
||||
@@ -101,7 +101,6 @@ fun ContactListScreen(
|
||||
val isSearchQueryEmpty by contactListViewModel.isSearchQueryEmpty.collectAsState(true)
|
||||
val contactListBottomSheetType by
|
||||
contactListViewModel.contactListBottomSheetType.collectAsStateWithLifecycle()
|
||||
val showSnackBar by contactListViewModel.showSnackBar.collectAsStateWithLifecycle()
|
||||
val recentBills by contactListViewModel.allRecentBills.collectAsStateWithLifecycle()
|
||||
val bbpsSnackBarPredefinedConfig = remember { BbpsSnackBarPredefinedConfig() }
|
||||
val permissionResult by contactListViewModel.permissionResult.collectAsStateWithLifecycle()
|
||||
@@ -123,6 +122,9 @@ fun ContactListScreen(
|
||||
val context = LocalContext.current
|
||||
val view = LocalView.current
|
||||
val keyboardController = LocalSoftwareKeyboardController.current
|
||||
val refreshBillItemAndStatus by
|
||||
contactListViewModel.refreshBillItemAndStatus.collectAsStateWithLifecycle()
|
||||
val snackBarState by contactListViewModel.snackBarState.collectAsStateWithLifecycle()
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
contactListViewModel.fetchOffersAndCoinBurnForProduct(
|
||||
@@ -269,16 +271,6 @@ fun ContactListScreen(
|
||||
LaunchedEffect(Unit) { contactListViewModel.fetchContacts() }
|
||||
}
|
||||
|
||||
val onDeleteMenuClicked = { myBillEntity: MyBillEntity ->
|
||||
contactListViewModel.onDeleteMenuClicked(myBillEntity)
|
||||
openSheet()
|
||||
}
|
||||
|
||||
val onDeleteAccountBillClicked = { myBillEntity: MyBillEntity ->
|
||||
contactListViewModel.onDeleteAccountBillClicked(myBillEntity)
|
||||
openSheet()
|
||||
}
|
||||
|
||||
val onContactSelected = { phoneNumberDetail: PhoneContactEntity ->
|
||||
naviBbpsAnalytics.onContactClick(
|
||||
billCategoryEntity = billCategoryEntity,
|
||||
@@ -345,7 +337,6 @@ fun ContactListScreen(
|
||||
ContactListBottomSheetContent(
|
||||
contactListBottomSheetType = contactListBottomSheetType,
|
||||
closeSheet = closeSheet,
|
||||
onDeleteAccountBillClicked = onDeleteAccountBillClicked,
|
||||
naviBbpsAnalytics = naviBbpsAnalytics,
|
||||
sessionAttribute = contactListViewModel.getNaviBbpsSessionAttributes(),
|
||||
source = source,
|
||||
@@ -391,7 +382,7 @@ fun ContactListScreen(
|
||||
contactList = contactList,
|
||||
onContactSelected = onContactSelected,
|
||||
contactListState = contactListUIState as Loaded,
|
||||
onDeleteRecentBillClicked = {
|
||||
onBillOptionsKebabMenuClicked = {
|
||||
naviBbpsAnalytics.onDeleteAccountKebabMenuClicked(
|
||||
myBillEntity = it,
|
||||
sessionAttribute =
|
||||
@@ -399,7 +390,10 @@ fun ContactListScreen(
|
||||
source = source,
|
||||
initialSource = initialSource,
|
||||
)
|
||||
onDeleteMenuClicked(it)
|
||||
contactListViewModel.onBillOptionsKebabMenuClicked(
|
||||
myBillEntity = it,
|
||||
openSheet = openSheet,
|
||||
)
|
||||
openSheet()
|
||||
},
|
||||
onRecentBillItemClicked =
|
||||
@@ -433,6 +427,7 @@ fun ContactListScreen(
|
||||
openSheet()
|
||||
},
|
||||
multipleOffersDataList = multipleOffersDataList,
|
||||
refreshBillItemAndStatus = refreshBillItemAndStatus,
|
||||
onFailedOrderCalloutClicked = {
|
||||
val failedOrder = it.first
|
||||
val billDetails = it.second
|
||||
@@ -472,23 +467,41 @@ fun ContactListScreen(
|
||||
}
|
||||
},
|
||||
snackbarHost = {
|
||||
if (showSnackBar) {
|
||||
if (snackBarState.show) {
|
||||
Column {
|
||||
SuccessSnackBar(
|
||||
modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp),
|
||||
show = true,
|
||||
snackBarConfig =
|
||||
bbpsSnackBarPredefinedConfig.successConfig(
|
||||
title =
|
||||
stringResource(
|
||||
id = R.string.bbps_account_removed_successfully
|
||||
)
|
||||
),
|
||||
onDismissed = { contactListViewModel.updateSnackBarState(false) },
|
||||
onTrailingIconClicked = {
|
||||
contactListViewModel.updateSnackBarState(false)
|
||||
},
|
||||
)
|
||||
if (snackBarState.messageId == R.string.bbps_bill_refreshed_failed) {
|
||||
ErrorSnackBar(
|
||||
modifier =
|
||||
Modifier.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp, vertical = 32.dp),
|
||||
show = true,
|
||||
snackBarConfig =
|
||||
bbpsSnackBarPredefinedConfig.errorConfig(
|
||||
title = stringResource(id = snackBarState.messageId)
|
||||
),
|
||||
onDismissed = {
|
||||
contactListViewModel.updateSnackBarState(show = false)
|
||||
},
|
||||
onTrailingIconClicked = {
|
||||
contactListViewModel.updateSnackBarState(show = false)
|
||||
},
|
||||
)
|
||||
} else {
|
||||
SuccessSnackBar(
|
||||
modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp),
|
||||
show = true,
|
||||
snackBarConfig =
|
||||
bbpsSnackBarPredefinedConfig.successConfig(
|
||||
title = stringResource(id = snackBarState.messageId)
|
||||
),
|
||||
onDismissed = {
|
||||
contactListViewModel.updateSnackBarState(show = false)
|
||||
},
|
||||
onTrailingIconClicked = {
|
||||
contactListViewModel.updateSnackBarState(show = false)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
}
|
||||
|
||||
@@ -50,13 +50,14 @@ import androidx.compose.ui.unit.sp
|
||||
import com.navi.bbps.R
|
||||
import com.navi.bbps.common.BBPS_CROSS_FADE_DURATION
|
||||
import com.navi.bbps.common.BILL_ITEM_SLIDE_OUT_DURATION
|
||||
import com.navi.bbps.common.BULLET
|
||||
import com.navi.bbps.common.MOBILE_NUMBER_LENGTH
|
||||
import com.navi.bbps.common.NaviBbpsDimens
|
||||
import com.navi.bbps.common.model.view.NaviPermissionResult
|
||||
import com.navi.bbps.common.model.view.RefreshBillState
|
||||
import com.navi.bbps.common.theme.NaviBbpsColor
|
||||
import com.navi.bbps.common.ui.BbpsCircleImage
|
||||
import com.navi.bbps.common.ui.BbpsListDivider
|
||||
import com.navi.bbps.common.ui.BillAmountAndDueDateSectionWithShimmer
|
||||
import com.navi.bbps.common.ui.BillItemOfferWithShimmer
|
||||
import com.navi.bbps.common.ui.ContactIconView
|
||||
import com.navi.bbps.common.ui.FailedOrderCallout
|
||||
@@ -66,7 +67,6 @@ import com.navi.bbps.common.ui.OfferRolodexWithShimmer
|
||||
import com.navi.bbps.common.ui.PermissionTile
|
||||
import com.navi.bbps.common.ui.getOfferDataForMultipleBillItems
|
||||
import com.navi.bbps.common.utils.NaviBbpsCommonUtils.getNormalisedPhoneNumber
|
||||
import com.navi.bbps.common.utils.getDisplayableAmount
|
||||
import com.navi.bbps.feature.contactlist.ContactListViewModel
|
||||
import com.navi.bbps.feature.contactlist.model.view.ContactListState
|
||||
import com.navi.bbps.feature.contactlist.model.view.PhoneContactEntity
|
||||
@@ -92,7 +92,7 @@ fun RenderContactListScreen(
|
||||
contactList: List<PhoneContactEntity>,
|
||||
onContactSelected: (PhoneContactEntity) -> Unit,
|
||||
contactListState: ContactListState.Loaded,
|
||||
onDeleteRecentBillClicked: (MyBillEntity) -> Unit,
|
||||
onBillOptionsKebabMenuClicked: (MyBillEntity) -> Unit,
|
||||
onRecentBillItemClicked: (PhoneContactEntity, MyBillEntity) -> Unit,
|
||||
getContactNameFromPhoneNumber: (String) -> String,
|
||||
searchQuery: String,
|
||||
@@ -107,6 +107,7 @@ fun RenderContactListScreen(
|
||||
offerData: List<OfferData>?,
|
||||
coinBurnData: CoinBurnData?,
|
||||
multipleOffersDataList: Map<String, List<OfferData>>?,
|
||||
refreshBillItemAndStatus: RefreshBillState,
|
||||
onFailedOrderCalloutClicked: (Pair<OrderEntity, MyBillEntity>) -> Unit,
|
||||
) {
|
||||
val shouldShowRecentBills =
|
||||
@@ -166,6 +167,16 @@ fun RenderContactListScreen(
|
||||
}
|
||||
val vmRecentBills = rememberUpdatedState(contactListState.recentBills.bills)
|
||||
|
||||
fun updateAnimatedRecentBills() {
|
||||
animatedRecentBills = vmRecentBills.value.toList()
|
||||
}
|
||||
|
||||
LaunchedEffect(vmRecentBills.value) {
|
||||
if (animatedRecentBills.size == vmRecentBills.value.size) {
|
||||
updateAnimatedRecentBills()
|
||||
}
|
||||
}
|
||||
|
||||
LazyColumn {
|
||||
if (isSearchQueryEmpty) {
|
||||
if (!isMyNumberItemVisible) {
|
||||
@@ -207,9 +218,10 @@ fun RenderContactListScreen(
|
||||
},
|
||||
getContactNameFromPhoneNumber = getContactNameFromPhoneNumber,
|
||||
onRecentBillItemClicked = onRecentBillItemClicked,
|
||||
onDeleteRecentBillClicked = onDeleteRecentBillClicked,
|
||||
onBillOptionsKebabMenuClicked = onBillOptionsKebabMenuClicked,
|
||||
multipleOffersDataList = multipleOffersDataList,
|
||||
onFailedOrderCalloutClicked = onFailedOrderCalloutClicked,
|
||||
refreshBillItemAndStatus = refreshBillItemAndStatus,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -276,9 +288,10 @@ fun RecentBillsSection(
|
||||
updateAnimatedRecentBills: () -> Unit,
|
||||
getContactNameFromPhoneNumber: (String) -> String,
|
||||
onRecentBillItemClicked: (PhoneContactEntity, MyBillEntity) -> Unit,
|
||||
onDeleteRecentBillClicked: (MyBillEntity) -> Unit,
|
||||
onBillOptionsKebabMenuClicked: (MyBillEntity) -> Unit,
|
||||
multipleOffersDataList: Map<String, List<OfferData>>?,
|
||||
onFailedOrderCalloutClicked: (Pair<OrderEntity, MyBillEntity>) -> Unit,
|
||||
refreshBillItemAndStatus: RefreshBillState,
|
||||
) {
|
||||
animatedRecentBills.forEachIndexed { index, billItem ->
|
||||
var failedOrder: OrderEntity? by remember { mutableStateOf(null) }
|
||||
@@ -315,7 +328,7 @@ fun RecentBillsSection(
|
||||
onRecentBillItemClicked = {
|
||||
onRecentBillItemClicked(phoneContactEntity, billItem)
|
||||
},
|
||||
onDeleteRecentBillClicked = { onDeleteRecentBillClicked(billItem) },
|
||||
onBillOptionsKebabMenuClicked = { onBillOptionsKebabMenuClicked(billItem) },
|
||||
getContactNameFromPhoneNumber = getContactNameFromPhoneNumber,
|
||||
offerData =
|
||||
getOfferDataForMultipleBillItems(
|
||||
@@ -325,6 +338,7 @@ fun RecentBillsSection(
|
||||
primaryCustomerParamValue = billItem.primaryCustomerParamValue,
|
||||
failedOrder = failedOrder,
|
||||
onFailedOrderCalloutClicked = onFailedOrderCalloutClicked,
|
||||
refreshBillItemAndStatus = refreshBillItemAndStatus,
|
||||
)
|
||||
if (index < recentBills.size - 1) {
|
||||
BbpsListDivider(
|
||||
@@ -457,11 +471,12 @@ fun RecentBillItem(
|
||||
myBillEntity: MyBillEntity,
|
||||
onRecentBillItemClicked: () -> Unit,
|
||||
primaryCustomerParamValue: String,
|
||||
onDeleteRecentBillClicked: (MyBillEntity) -> Unit,
|
||||
onBillOptionsKebabMenuClicked: (MyBillEntity) -> Unit,
|
||||
getContactNameFromPhoneNumber: (String) -> String,
|
||||
offerData: OfferData?,
|
||||
failedOrder: OrderEntity? = null,
|
||||
onFailedOrderCalloutClicked: (Pair<OrderEntity, MyBillEntity>) -> Unit,
|
||||
refreshBillItemAndStatus: RefreshBillState,
|
||||
) {
|
||||
Box(modifier = modifier) {
|
||||
Column(
|
||||
@@ -500,87 +515,11 @@ fun RecentBillItem(
|
||||
)
|
||||
Spacer(modifier = Modifier.height(2.dp))
|
||||
|
||||
if (myBillEntity.isBillPaid) {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
if (myBillEntity.formattedLastPaidAmount.isNotBlank()) {
|
||||
NaviText(
|
||||
text =
|
||||
stringResource(
|
||||
id = R.string.bbps_rupee_symbol_x,
|
||||
myBillEntity.formattedLastPaidAmount,
|
||||
),
|
||||
color = NaviBbpsColor.textPrimary,
|
||||
fontFamily = naviFontFamily,
|
||||
fontSize = 14.sp,
|
||||
fontWeight = getFontWeight(FontWeightEnum.NAVI_BODY_DEMI_BOLD),
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
}
|
||||
if (myBillEntity.formattedLastPaidDate.isNotBlank()) {
|
||||
Spacer(modifier = Modifier.width(4.dp))
|
||||
NaviText(
|
||||
text = BULLET,
|
||||
color = NaviBbpsColor.textPrimary,
|
||||
fontFamily = naviFontFamily,
|
||||
fontSize = 16.sp,
|
||||
fontWeight = getFontWeight(FontWeightEnum.NAVI_BODY_REGULAR),
|
||||
)
|
||||
Spacer(modifier = Modifier.width(4.dp))
|
||||
NaviText(
|
||||
text =
|
||||
"${
|
||||
stringResource(
|
||||
id = R.string.bbps_last_recharged,
|
||||
myBillEntity.formattedLastPaidDate,
|
||||
)
|
||||
} ",
|
||||
color = NaviBbpsColor.textTertiary,
|
||||
fontFamily = naviFontFamily,
|
||||
fontSize = 12.sp,
|
||||
fontWeight = getFontWeight(FontWeightEnum.NAVI_BODY_REGULAR),
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
if (myBillEntity.unpaidBillDetails?.amount?.isNotEmpty() == true) {
|
||||
NaviText(
|
||||
text =
|
||||
stringResource(
|
||||
id = R.string.bbps_rupee_symbol_x,
|
||||
myBillEntity.unpaidBillDetails.amount
|
||||
.getDisplayableAmount(),
|
||||
),
|
||||
color = NaviBbpsColor.textPrimary,
|
||||
fontFamily = naviFontFamily,
|
||||
fontSize = 14.sp,
|
||||
fontWeight = getFontWeight(FontWeightEnum.NAVI_BODY_DEMI_BOLD),
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
Spacer(modifier = Modifier.width(4.dp))
|
||||
NaviText(
|
||||
text = BULLET,
|
||||
color = NaviBbpsColor.textPrimary,
|
||||
fontFamily = naviFontFamily,
|
||||
fontSize = 16.sp,
|
||||
fontWeight = getFontWeight(FontWeightEnum.NAVI_BODY_REGULAR),
|
||||
)
|
||||
Spacer(modifier = Modifier.width(4.dp))
|
||||
}
|
||||
|
||||
NaviText(
|
||||
text = myBillEntity.unpaidBillWarning,
|
||||
color = NaviBbpsColor.onSurfaceCritical,
|
||||
fontFamily = naviFontFamily,
|
||||
fontSize = 12.sp,
|
||||
fontWeight = getFontWeight(FontWeightEnum.NAVI_BODY_REGULAR),
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
)
|
||||
}
|
||||
}
|
||||
BillAmountAndDueDateSectionWithShimmer(
|
||||
myBillEntity = myBillEntity,
|
||||
refreshBillItemAndStatus = refreshBillItemAndStatus,
|
||||
startWithPadding = false,
|
||||
)
|
||||
}
|
||||
Spacer(modifier = Modifier.width(16.dp))
|
||||
|
||||
@@ -620,7 +559,7 @@ fun RecentBillItem(
|
||||
Modifier.padding(top = 6.dp)
|
||||
.size(24.dp)
|
||||
.align(Alignment.Top)
|
||||
.clickableDebounce { onDeleteRecentBillClicked(myBillEntity) },
|
||||
.clickableDebounce { onBillOptionsKebabMenuClicked(myBillEntity) },
|
||||
)
|
||||
}
|
||||
if (!myBillEntity.isBillPaid) {
|
||||
|
||||
@@ -15,16 +15,13 @@ import com.navi.base.utils.EMPTY
|
||||
import com.navi.base.utils.NaviNetworkConnectivity
|
||||
import com.navi.base.utils.ResourceProvider
|
||||
import com.navi.base.utils.orZero
|
||||
import com.navi.base.utils.retry
|
||||
import com.navi.bbps.R
|
||||
import com.navi.bbps.common.APP_VERSION_CODE
|
||||
import com.navi.bbps.common.BILLER_UNIQUE_ID
|
||||
import com.navi.bbps.common.CATEGORY_ID_MOBILE_PREPAID
|
||||
import com.navi.bbps.common.DEFAULT_RETRY_COUNT
|
||||
import com.navi.bbps.common.NaviBbpsAnalytics
|
||||
import com.navi.bbps.common.NaviBbpsScreen
|
||||
import com.navi.bbps.common.RCBP_CATEGORY
|
||||
import com.navi.bbps.common.RETRY_INTERVAL_IN_SECONDS
|
||||
import com.navi.bbps.common.TXN_AMOUNT
|
||||
import com.navi.bbps.common.model.NaviBbpsVmData
|
||||
import com.navi.bbps.common.model.config.NaviBbpsDefaultConfig
|
||||
@@ -32,9 +29,9 @@ import com.navi.bbps.common.model.view.DetectedBillEntity
|
||||
import com.navi.bbps.common.model.view.DetectedBillSource
|
||||
import com.navi.bbps.common.model.view.NaviPermissionResult
|
||||
import com.navi.bbps.common.model.view.RefreshBillState
|
||||
import com.navi.bbps.common.repository.BbpsCommonRepository
|
||||
import com.navi.bbps.common.session.NaviBbpsSessionHelper
|
||||
import com.navi.bbps.common.usecase.FindLastOrderWithSuccessfulPaymentUseCase
|
||||
import com.navi.bbps.common.usecase.MyBillActionsHandler
|
||||
import com.navi.bbps.common.usecase.OriginExperimentUtils
|
||||
import com.navi.bbps.common.usecase.UploadUserDataUseCase
|
||||
import com.navi.bbps.common.utils.BbpsOriginSessionHandler
|
||||
@@ -43,7 +40,6 @@ import com.navi.bbps.common.utils.MyBillEntityToBillCategoryEntityMapper
|
||||
import com.navi.bbps.common.utils.MyBillEntityToBillDetailsResponseMapper
|
||||
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.NaviBbpsCommonUtils.getNormalisedPhoneNumber
|
||||
import com.navi.bbps.common.utils.OriginSessionAttributes
|
||||
import com.navi.bbps.common.utils.OriginWidgetStatus
|
||||
@@ -54,9 +50,7 @@ import com.navi.bbps.feature.billerlist.model.view.BillerItemEntity
|
||||
import com.navi.bbps.feature.category.model.view.BillCategoryEntity
|
||||
import com.navi.bbps.feature.contactlist.PhoneContactManager
|
||||
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.BillDetailsResponse
|
||||
import com.navi.bbps.feature.customerinput.model.network.DeviceDetails
|
||||
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
|
||||
@@ -75,7 +69,6 @@ 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
|
||||
import com.navi.naviwidgets.utils.ZERO
|
||||
import com.navi.pay.tstore.list.model.view.OrderEntity
|
||||
import com.navi.rr.common.models.OfferRequest
|
||||
@@ -113,7 +106,6 @@ constructor(
|
||||
private val naviNetworkConnectivity: NaviNetworkConnectivity,
|
||||
private val phoneContactManager: Lazy<PhoneContactManager>,
|
||||
private val myBillsSyncJob: MyBillsSyncJob,
|
||||
private val bbpsCommonRepository: BbpsCommonRepository,
|
||||
private val resourceProvider: ResourceProvider,
|
||||
val originBillDetectionHandler: OriginBillDetectionHandler,
|
||||
private val originSessionHandler: BbpsOriginSessionHandler,
|
||||
@@ -122,6 +114,7 @@ constructor(
|
||||
private val findLastOrderWithSuccessfulPaymentUseCase:
|
||||
FindLastOrderWithSuccessfulPaymentUseCase,
|
||||
private val originExperimentUtils: OriginExperimentUtils,
|
||||
private val myBillActionsHandler: MyBillActionsHandler,
|
||||
) :
|
||||
NaviBbpsBaseVM(
|
||||
naviBbpsVmData = NaviBbpsVmData(screen = NaviBbpsScreen.NAVI_BBPS_MY_SAVED_BILLS)
|
||||
@@ -417,32 +410,13 @@ constructor(
|
||||
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()) {
|
||||
|
||||
val updatedBillEntity = myBillEntity.copy(isBillPaid = true)
|
||||
updateSavedBills(
|
||||
updatedBillEntity = updatedBillEntity,
|
||||
oldBillEntity = myBillEntity,
|
||||
)
|
||||
updateSnackBarState(show = true, messageId = R.string.bbps_bill_marked_as_paid)
|
||||
}
|
||||
myBillActionsHandler.markAsPaid(
|
||||
billId = myBillEntity.billId,
|
||||
screenName = naviBbpsVmData.screen.screenName,
|
||||
onSuccess = {
|
||||
updateSnackBarState(show = true, messageId = R.string.bbps_bill_marked_as_paid)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -455,34 +429,27 @@ constructor(
|
||||
private suspend fun refreshBillAndUpdateInfo(myBillEntity: MyBillEntity) {
|
||||
|
||||
updateRefreshState(isRefreshing = true, myBillEntity = myBillEntity)
|
||||
|
||||
val billDetailsRequest =
|
||||
BillDetailsRequest(
|
||||
billerId = myBillEntity.billerId,
|
||||
customerParams = myBillEntity.customerParams,
|
||||
deviceDetails = DeviceDetails(ip = naviNetworkConnectivity.getIpAddress()),
|
||||
amount = myBillEntity.actualLastPaidAmount,
|
||||
isConsentProvided = true,
|
||||
)
|
||||
|
||||
val billDetailsResponse =
|
||||
bbpsCommonRepository.fetchBillDetails(
|
||||
billDetailsRequest = billDetailsRequest,
|
||||
metricInfo = getBbpsMetricInfo(screenName = naviBbpsVmData.screen.screenName),
|
||||
)
|
||||
|
||||
if (billDetailsResponse.isSuccessWithData() && billDetailsResponse.data != null) {
|
||||
myBillEntity.unpaidBillDetails?.let {
|
||||
myBillsSyncJob.refreshBills(naviBbpsVmData.screen.screenName)
|
||||
myBillActionsHandler.refreshBill(
|
||||
myBillEntity = myBillEntity,
|
||||
screenName = naviBbpsVmData.screen.screenName,
|
||||
onSuccess = {
|
||||
updateSnackBarState(
|
||||
show = true,
|
||||
messageId = R.string.bbps_bill_refreshed_sucessfully,
|
||||
)
|
||||
}
|
||||
} else {
|
||||
updateSnackBarState(show = true, messageId = R.string.bbps_bill_refreshed_failed)
|
||||
}
|
||||
|
||||
},
|
||||
onError = { response ->
|
||||
val errorCode = getError(response).code
|
||||
if (errorCode in naviBbpsDefaultConfig.billAlreadyPaidErrorCodes) {
|
||||
notifyError(response = response)
|
||||
} else {
|
||||
updateSnackBarState(
|
||||
show = true,
|
||||
messageId = R.string.bbps_bill_refreshed_failed,
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
updateRefreshState(isRefreshing = false, myBillEntity = myBillEntity)
|
||||
}
|
||||
|
||||
@@ -765,20 +732,37 @@ constructor(
|
||||
|
||||
fun deleteBill(myBillEntity: MyBillEntity) {
|
||||
viewModelScope.launch(dispatcherProvider.io) {
|
||||
val deleteBillResponse =
|
||||
bbpsCommonRepository.deleteBill(
|
||||
myBillEntity.billId,
|
||||
metricInfo = getBbpsMetricInfo(screenName = naviBbpsVmData.screen.screenName),
|
||||
)
|
||||
if (deleteBillResponse.isSuccessWithData()) {
|
||||
myBillsSyncJob.refreshBills(naviBbpsVmData.screen.screenName)
|
||||
updateSnackBarState(
|
||||
show = true,
|
||||
messageId = R.string.bbps_account_removed_successfully,
|
||||
)
|
||||
} else {
|
||||
updateSnackBarState(show = true, messageId = R.string.bbps_account_delete_failed)
|
||||
}
|
||||
myBillActionsHandler.deleteBill(
|
||||
billId = myBillEntity.billId,
|
||||
categoryId = myBillEntity.categoryId,
|
||||
screenName = naviBbpsVmData.screen.screenName,
|
||||
onSuccess = { deleteBillResponse ->
|
||||
naviBbpsAnalytics.billDeletionSuccess(
|
||||
data = deleteBillResponse.data!!,
|
||||
myBillEntity = myBillEntity,
|
||||
sessionAttribute = getNaviBbpsSessionAttributes(),
|
||||
source = source,
|
||||
initialSource = initialSource,
|
||||
)
|
||||
updateSnackBarState(
|
||||
show = true,
|
||||
messageId = R.string.bbps_account_removed_successfully,
|
||||
)
|
||||
},
|
||||
onError = { deleteBillResponse ->
|
||||
naviBbpsAnalytics.billDeletionFailed(
|
||||
deleteBillResponse = deleteBillResponse,
|
||||
myBillEntity = myBillEntity,
|
||||
sessionAttribute = getNaviBbpsSessionAttributes(),
|
||||
source = source,
|
||||
initialSource = initialSource,
|
||||
)
|
||||
updateSnackBarState(
|
||||
show = true,
|
||||
messageId = R.string.bbps_account_delete_failed,
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,57 +7,21 @@
|
||||
|
||||
package com.navi.bbps.feature.mybills.ui
|
||||
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.navigationBarsPadding
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.layout.wrapContentHeight
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
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.text.SpanStyle
|
||||
import androidx.compose.ui.text.buildAnnotatedString
|
||||
import androidx.compose.ui.text.withStyle
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import coil.compose.AsyncImage
|
||||
import com.navi.bbps.R
|
||||
import com.navi.bbps.common.BULLET
|
||||
import com.navi.bbps.common.ICON_MARK_AS_PAID_UNPAID_BILL_BOTTOMSHEET
|
||||
import com.navi.bbps.common.ICON_REFRESH_BILL_UNPAID_BILL_BOTTOMSHEET
|
||||
import com.navi.bbps.common.ICON_REMOVE_ACCOUNT_UNPAID_BILL_BOTTOMSHEET
|
||||
import com.navi.bbps.common.ICON_VIEW_BILL_HISTORY_UNPAID_BILL_BOTTOMSHEET
|
||||
import com.navi.bbps.common.NaviBbpsAnalytics
|
||||
import com.navi.bbps.common.SYMBOL_RUPEE
|
||||
import com.navi.bbps.common.theme.NaviBbpsColor
|
||||
import com.navi.bbps.common.ui.BbpsAsyncImage
|
||||
import com.navi.bbps.common.ui.BbpsOfferBottomSheet
|
||||
import com.navi.bbps.common.ui.BillOptionsBottomSheetContent
|
||||
import com.navi.bbps.common.ui.ConfirmationBottomSheetContent
|
||||
import com.navi.bbps.common.ui.TitleDescriptionWithLinearProgressBar
|
||||
import com.navi.bbps.common.utils.NaviBbpsCommonUtils.isRechargeCategory
|
||||
import com.navi.bbps.common.utils.getDisplayableAmount
|
||||
import com.navi.bbps.feature.category.ui.DetectedBillsBottomSheetContent
|
||||
import com.navi.bbps.feature.category.ui.NoBillDetectedErrorBottomSheetContent
|
||||
import com.navi.bbps.feature.mybills.model.view.MyBillsBottomSheetType
|
||||
import com.navi.bbps.getBillTitleFromAccountHolderNameOrPrimaryCustomerParams
|
||||
import com.navi.bbps.noRippleClickableWithDebounce
|
||||
import com.navi.common.R as CommonR
|
||||
import com.navi.common.utils.SPACE
|
||||
import com.navi.common.utils.firstLetterToLowerCase
|
||||
import com.navi.design.font.FontWeightEnum
|
||||
import com.navi.design.font.getFontWeight
|
||||
import com.navi.design.font.naviFontFamily
|
||||
import com.navi.guarddog.utils.clickableDebounce
|
||||
import com.navi.naviwidgets.extensions.NaviText
|
||||
|
||||
@Composable
|
||||
fun MyBillsBottomSheetContent(
|
||||
@@ -69,12 +33,15 @@ fun MyBillsBottomSheetContent(
|
||||
) {
|
||||
when (myBillsBottomSheetType) {
|
||||
is MyBillsBottomSheetType.UnpaidBillOptions -> {
|
||||
UnpaidBillOptionsBottomSheetContent(
|
||||
BillOptionsBottomSheetContent(
|
||||
billerLogoUrl = myBillsBottomSheetType.myBillEntity.billerLogoUrl,
|
||||
title =
|
||||
getBillTitleFromAccountHolderNameOrPrimaryCustomerParams(
|
||||
myBillsBottomSheetType.myBillEntity.unpaidBillDetails?.accountHolderName,
|
||||
myBillsBottomSheetType.myBillEntity.primaryCustomerParamValue,
|
||||
accountHolderName =
|
||||
myBillsBottomSheetType.myBillEntity.unpaidBillDetails
|
||||
?.accountHolderName,
|
||||
primaryCustomerParams =
|
||||
myBillsBottomSheetType.myBillEntity.primaryCustomerParamValue,
|
||||
),
|
||||
expiringOn =
|
||||
(myBillsBottomSheetType.myBillEntity.unpaidBillWarning)
|
||||
@@ -84,7 +51,9 @@ fun MyBillsBottomSheetContent(
|
||||
?.amount
|
||||
?.getDisplayableAmount()
|
||||
.orEmpty(),
|
||||
operatorName = myBillsBottomSheetType.myBillEntity.billerName,
|
||||
billerName = myBillsBottomSheetType.myBillEntity.billerName,
|
||||
isRechargeCategory =
|
||||
isRechargeCategory(categoryId = myBillsBottomSheetType.myBillEntity.categoryId),
|
||||
onMarkAsPaidClicked = {
|
||||
closeSheet()
|
||||
naviBbpsAnalytics.onMyBillMoreOptionsBottomSheetClicked(
|
||||
@@ -105,7 +74,14 @@ fun MyBillsBottomSheetContent(
|
||||
closeSheet()
|
||||
naviBbpsAnalytics.onMyBillMoreOptionsBottomSheetClicked(
|
||||
billEntity = myBillsBottomSheetType.myBillEntity,
|
||||
action = "view_bill_history",
|
||||
action =
|
||||
if (
|
||||
isRechargeCategory(
|
||||
categoryId = myBillsBottomSheetType.myBillEntity.categoryId
|
||||
)
|
||||
)
|
||||
"view_recharge_history"
|
||||
else "view_bill_history",
|
||||
)
|
||||
myBillsBottomSheetType.onViewBillHistoryClicked()
|
||||
},
|
||||
@@ -254,170 +230,3 @@ fun RemoveAccountBottomSheetContent(
|
||||
onPrimaryButtonClicked = { onPrimaryButtonClicked.invoke() },
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun UnpaidBillOptionsBottomSheetContent(
|
||||
billerLogoUrl: String,
|
||||
title: String,
|
||||
amount: String,
|
||||
operatorName: String,
|
||||
expiringOn: String,
|
||||
onMarkAsPaidClicked: () -> Unit,
|
||||
onRefreshBillClicked: () -> Unit,
|
||||
onViewBillHistoryClicked: () -> Unit,
|
||||
onRemoveAccountClicked: () -> Unit,
|
||||
onCloseClicked: () -> Unit,
|
||||
) {
|
||||
val descriptionText = buildAnnotatedString {
|
||||
val fullText = stringResource(id = R.string.bbps_payment_due, operatorName, expiringOn)
|
||||
withStyle(
|
||||
style =
|
||||
SpanStyle(
|
||||
fontFamily = naviFontFamily,
|
||||
fontWeight = getFontWeight(FontWeightEnum.NAVI_BODY_REGULAR),
|
||||
fontSize = 14.sp,
|
||||
color = NaviBbpsColor.textTertiary,
|
||||
)
|
||||
) {
|
||||
append(fullText)
|
||||
}
|
||||
addStyle(
|
||||
style =
|
||||
SpanStyle(
|
||||
fontFamily = naviFontFamily,
|
||||
fontWeight = getFontWeight(FontWeightEnum.NAVI_BODY_REGULAR),
|
||||
fontSize = 14.sp,
|
||||
color = NaviBbpsColor.inputFieldError,
|
||||
),
|
||||
start = fullText.indexOf(expiringOn),
|
||||
end = fullText.indexOf(expiringOn) + expiringOn.length,
|
||||
)
|
||||
}
|
||||
|
||||
Column(
|
||||
modifier =
|
||||
Modifier.navigationBarsPadding()
|
||||
.fillMaxWidth()
|
||||
.wrapContentHeight()
|
||||
.padding(start = 16.dp, end = 16.dp, top = 16.dp, bottom = 32.dp)
|
||||
) {
|
||||
Row(modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
|
||||
BbpsAsyncImage(
|
||||
imageUrl = billerLogoUrl,
|
||||
modifier = Modifier.size(24.dp),
|
||||
placeholderIconResId = com.navi.common.R.drawable.navi_common_ic_biller_placeholder,
|
||||
)
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
Image(
|
||||
painter = painterResource(id = com.navi.common.R.drawable.ic_close_black),
|
||||
contentDescription = null,
|
||||
modifier = Modifier.size(24.dp).clickableDebounce { onCloseClicked() },
|
||||
)
|
||||
}
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
NaviText(
|
||||
text =
|
||||
buildString {
|
||||
if (title.isNotBlank()) {
|
||||
append(title)
|
||||
append(SPACE)
|
||||
}
|
||||
if (title.isNotBlank() && amount.isNotBlank()) {
|
||||
append(BULLET)
|
||||
append(SPACE)
|
||||
}
|
||||
if (amount.isNotBlank()) {
|
||||
append(SYMBOL_RUPEE)
|
||||
append(amount)
|
||||
}
|
||||
},
|
||||
fontSize = 16.sp,
|
||||
fontFamily = naviFontFamily,
|
||||
fontWeight = getFontWeight(FontWeightEnum.NAVI_BODY_DEMI_BOLD),
|
||||
color = NaviBbpsColor.textPrimary,
|
||||
)
|
||||
Spacer(modifier = Modifier.height(2.dp))
|
||||
|
||||
if (descriptionText.isNotBlank()) {
|
||||
NaviText(
|
||||
text = descriptionText,
|
||||
fontSize = 14.sp,
|
||||
fontFamily = naviFontFamily,
|
||||
fontWeight = getFontWeight(FontWeightEnum.NAVI_BODY_REGULAR),
|
||||
color = NaviBbpsColor.textTertiary,
|
||||
lineHeight = 22.sp,
|
||||
)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
|
||||
val actions =
|
||||
listOf(
|
||||
ActionItem(
|
||||
imageS3Url = ICON_MARK_AS_PAID_UNPAID_BILL_BOTTOMSHEET,
|
||||
textResId = R.string.bbps_mark_as_paid,
|
||||
onClick = onMarkAsPaidClicked,
|
||||
),
|
||||
ActionItem(
|
||||
imageS3Url = ICON_REFRESH_BILL_UNPAID_BILL_BOTTOMSHEET,
|
||||
textResId = R.string.bbps_refresh_bill,
|
||||
onClick = onRefreshBillClicked,
|
||||
),
|
||||
ActionItem(
|
||||
imageS3Url = ICON_VIEW_BILL_HISTORY_UNPAID_BILL_BOTTOMSHEET,
|
||||
textResId = R.string.bbps_view_bill_history,
|
||||
onClick = onViewBillHistoryClicked,
|
||||
),
|
||||
ActionItem(
|
||||
imageS3Url = ICON_REMOVE_ACCOUNT_UNPAID_BILL_BOTTOMSHEET,
|
||||
textResId = R.string.bbps_remove_account,
|
||||
onClick = onRemoveAccountClicked,
|
||||
),
|
||||
)
|
||||
|
||||
actions.forEachIndexed { index, action ->
|
||||
IconActionRow(
|
||||
imageS3Url = action.imageS3Url,
|
||||
text = stringResource(id = action.textResId),
|
||||
onClick = action.onClick,
|
||||
)
|
||||
|
||||
if (index < actions.lastIndex) {
|
||||
HorizontalDivider(
|
||||
modifier = Modifier.padding(vertical = 20.dp),
|
||||
thickness = 1.dp,
|
||||
color = NaviBbpsColor.borderAlt,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class ActionItem(
|
||||
val imageS3Url: String,
|
||||
@StringRes val textResId: Int,
|
||||
val onClick: () -> Unit,
|
||||
)
|
||||
|
||||
@Composable
|
||||
fun IconActionRow(
|
||||
imageS3Url: String,
|
||||
text: String,
|
||||
onClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Row(
|
||||
modifier = modifier.fillMaxWidth().noRippleClickableWithDebounce(onClick = onClick),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
AsyncImage(modifier = Modifier.size(24.dp), model = imageS3Url, contentDescription = "")
|
||||
Spacer(modifier = Modifier.width(12.dp))
|
||||
NaviText(
|
||||
text = text,
|
||||
fontSize = 14.sp,
|
||||
fontFamily = naviFontFamily,
|
||||
fontWeight = getFontWeight(FontWeightEnum.NAVI_BODY_REGULAR),
|
||||
color = NaviBbpsColor.textPrimary,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -270,6 +270,7 @@
|
||||
<string name="bbps_payment_due">%s payment %s.</string>
|
||||
<string name="bbps_due_on">due on %s</string>
|
||||
<string name="bbps_refresh_bill">Refresh bill</string>
|
||||
<string name="bbps_view_recharge_history">View recharge history</string>
|
||||
<string name="bbps_view_bill_history">View bill history</string>
|
||||
<string name="bbps_offer_bottomsheet_count_title_singular">%s Bill payment offer</string>
|
||||
<string name="bbps_offer_bottomsheet_count_title_plural">%s Bill payment offers</string>
|
||||
|
||||
Reference in New Issue
Block a user