diff --git a/app/src/main/java/com/mob/utsmyanmar/ui/error/TransactionErrorScreen.kt b/app/src/main/java/com/mob/utsmyanmar/ui/error/TransactionErrorScreen.kt new file mode 100644 index 0000000..bf27286 --- /dev/null +++ b/app/src/main/java/com/mob/utsmyanmar/ui/error/TransactionErrorScreen.kt @@ -0,0 +1,139 @@ +package com.mob.utsmyanmar.ui.error + +import androidx.activity.compose.BackHandler +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +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.statusBarsPadding +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.rounded.Check +import androidx.compose.material.icons.rounded.Close +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import com.mob.utsmyanmar.ui.preview.P2Preview +import com.mob.utsmyanmar.ui.theme.Color +import kotlinx.coroutines.delay + +private const val AUTO_DISMISS_DELAY_MS = 3000L + +@Composable +fun TransactionErrorScreen( + isSuccess: Boolean, + message: String, + onDone: () -> Unit +) { + BackHandler(enabled = true) { + onDone() + } + + LaunchedEffect(Unit) { + delay(AUTO_DISMISS_DELAY_MS) + onDone() + } + + TransactionErrorContent(isSuccess= isSuccess, message = message) +} + +@Composable +private fun TransactionErrorContent(isSuccess: Boolean,message: String) { + Scaffold( + containerColor = Color.IvoryBeige + ) { paddingValues -> + Column( + modifier = Modifier + .fillMaxSize() + .background(Color.IvoryBeige) + .padding(paddingValues) + .statusBarsPadding() + .navigationBarsPadding() + .padding(horizontal = 20.dp), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Spacer(modifier = Modifier.height(72.dp)) + + FailIcon(isSuccess) + + Spacer(modifier = Modifier.height(24.dp)) + + Text( + text = "Transaction Failed", + color = Color.LegacyRed, + style = MaterialTheme.typography.headlineLarge + ) + + Spacer(modifier = Modifier.height(10.dp)) + + Text( + text = message.ifBlank { "Something went wrong. Please try again." }, + color = Color.Gray, + style = MaterialTheme.typography.bodyMedium, + textAlign = TextAlign.Center + ) + } + } +} + +@Composable +private fun FailIcon(isSuccess: Boolean) { + Box( + modifier = Modifier.size(132.dp), + contentAlignment = Alignment.Center + ) { + Box( + modifier = Modifier + .size(132.dp) + .background( + color = if (isSuccess) Color.Success.copy(alpha = 0.12f) else Color.Error.copy(alpha = 0.12f), + shape = CircleShape + ) + ) + + Box( + modifier = Modifier + .size(96.dp) + .background( + color = if (isSuccess) Color.Success else Color.Error, + shape = CircleShape + ), + contentAlignment = Alignment.Center + ) { + if(isSuccess) { + Icon( + imageVector = Icons.Rounded.Check, + contentDescription = "Success", + tint = Color.White, + modifier = Modifier.size(64.dp) + ) + } else { + Icon( + imageVector = Icons.Rounded.Close, + contentDescription = "Failed", + tint = Color.White, + modifier = Modifier.size(64.dp) + ) + } + + } + } +} + +@P2Preview +@Composable +private fun PreviewTransactionErrorScreen() { + TransactionErrorContent(isSuccess = true, message = "Reversal Success") +} diff --git a/app/src/main/java/com/mob/utsmyanmar/ui/navigation/AppNavGraph.kt b/app/src/main/java/com/mob/utsmyanmar/ui/navigation/AppNavGraph.kt index 9146070..7b57f06 100644 --- a/app/src/main/java/com/mob/utsmyanmar/ui/navigation/AppNavGraph.kt +++ b/app/src/main/java/com/mob/utsmyanmar/ui/navigation/AppNavGraph.kt @@ -23,6 +23,7 @@ import com.mob.utsmyanmar.ui.dashboard.DashboardScreen2 import com.mob.utsmyanmar.ui.dashboard.DashboardViewModel import com.mob.utsmyanmar.ui.dashboard.SeeMoreScreen import com.mob.utsmyanmar.ui.device_info.DeviceInfoViewModel +import com.mob.utsmyanmar.ui.error.TransactionErrorScreen import com.mob.utsmyanmar.ui.functions.FunctionsScreen import com.mob.utsmyanmar.ui.history_functions.HistoryRoute import com.mob.utsmyanmar.ui.input_amount.AmountRoute @@ -685,7 +686,35 @@ fun AppNavGraph( launchSingleTop = true } }, - onNavigateMain = { + onNavigateError = { isSuccess,message -> + navController.navigate(Routes.TransactionError.createRoute(isSuccess,message)) { + popUpTo(Routes.Processing.route) { + inclusive = true + } + launchSingleTop = true + } + } + ) + } + + composable( + route = Routes.TransactionError.route, + arguments = listOf( + navArgument("isSuccess") { + type = NavType.BoolType + }, + navArgument("message") { + type = NavType.StringType + } + ) + ) { backStackEntry -> + val isSuccess = backStackEntry.arguments?.getBoolean("isSuccess") ?: false + val message = backStackEntry.arguments?.getString("message").orEmpty() + + TransactionErrorScreen( + isSuccess = isSuccess, + message = message, + onDone = { navController.navigate(Routes.Dashboard.route) { popUpTo(Routes.Dashboard.route) { inclusive = false diff --git a/app/src/main/java/com/mob/utsmyanmar/ui/navigation/Routes.kt b/app/src/main/java/com/mob/utsmyanmar/ui/navigation/Routes.kt index 6ba9067..6c9af3d 100644 --- a/app/src/main/java/com/mob/utsmyanmar/ui/navigation/Routes.kt +++ b/app/src/main/java/com/mob/utsmyanmar/ui/navigation/Routes.kt @@ -45,4 +45,7 @@ sealed class Routes(val route: String) { data object Disable : Routes("disable/{message}") { fun createRoute(message: String): String = "disable/${Uri.encode(message)}" } + data object TransactionError : Routes("transaction_error/{isSuccess}/{message}") { + fun createRoute(isSuccess: Boolean, message: String): String = "transaction_error/$isSuccess/${Uri.encode(message)}" + } } diff --git a/app/src/main/java/com/mob/utsmyanmar/ui/sending_to_host/SendingToHostRoute.kt b/app/src/main/java/com/mob/utsmyanmar/ui/sending_to_host/SendingToHostRoute.kt index 9fbefed..bfcea7e 100644 --- a/app/src/main/java/com/mob/utsmyanmar/ui/sending_to_host/SendingToHostRoute.kt +++ b/app/src/main/java/com/mob/utsmyanmar/ui/sending_to_host/SendingToHostRoute.kt @@ -1,5 +1,6 @@ package com.mob.utsmyanmar.ui.sending_to_host +import android.R import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue @@ -20,7 +21,7 @@ fun ProcessingRoute( settlementViewModel: SettlementViewModel, onNavigateTransactionResult: () -> Unit, onNavigateSignature: () -> Unit, - onNavigateMain: ()-> Unit + onNavigateError: (Boolean, String) -> Unit ) { val transStatus by transProcessViewModel.transResultStatus.collectAsStateWithLifecycle() @@ -46,7 +47,7 @@ fun ProcessingRoute( } } else { LaunchedEffect(Unit) { -// transProcessViewModel.resetTransactionStatus() + transProcessViewModel.startOnlineProcess() } @@ -65,9 +66,20 @@ fun ProcessingRoute( sharedViewModel.payDetail.value = transProcessViewModel.payDetailResult.value onNavigateTransactionResult() } - TransResultStatus.REVERSAL_SUCCESS -> onNavigateMain() - TransResultStatus.REVERSAL_FAIL -> onNavigateMain() - TransResultStatus.ERROR -> onNavigateMain() + TransResultStatus.REVERSAL_SUCCESS -> { + onNavigateError(true,"Reversal success") + } + + TransResultStatus.REVERSAL_FAIL -> { + onNavigateError(false,"Reversal failed") + } + + TransResultStatus.ERROR -> { + onNavigateError(false, + transProcessViewModel.errorMessage.value?.takeIf { it.isNotBlank() } + ?: "Something went wrong. Please try again." + ) + } else -> {} } } diff --git a/app/src/main/java/com/mob/utsmyanmar/viewmodel/TransProcessViewModel.kt b/app/src/main/java/com/mob/utsmyanmar/viewmodel/TransProcessViewModel.kt index 6fa433b..813b9fe 100644 --- a/app/src/main/java/com/mob/utsmyanmar/viewmodel/TransProcessViewModel.kt +++ b/app/src/main/java/com/mob/utsmyanmar/viewmodel/TransProcessViewModel.kt @@ -3,6 +3,7 @@ package com.mob.utsmyanmar.viewmodel import android.content.Context import android.text.TextUtils import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope import com.mob.utsmyanmar.model.TransResultStatus import com.mob.utsmyanmar.ui.sending_to_host.ProcessingState import com.utsmyanmar.baselib.repo.Repository @@ -19,9 +20,12 @@ import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation import com.utsmyanmar.paylibs.utils.iso_utils.TransactionsType import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.qualifiers.ApplicationContext +import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.launch import javax.inject.Inject +import kotlin.time.Duration.Companion.milliseconds @HiltViewModel class TransProcessViewModel @Inject constructor( @@ -210,7 +214,10 @@ class TransProcessViewModel @Inject constructor( TransResultStatus.REVERSAL_PREPARE _state.value = _state.value.copy("Preparing Reversal") - callReversal(tradeData) + viewModelScope.launch { + delay(10_000L) + callReversal(tradeData) + } } override fun onError(message: String) { diff --git a/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/iso_utils/FieldUtils.java b/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/iso_utils/FieldUtils.java index d84bc0b..efb10f5 100644 --- a/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/iso_utils/FieldUtils.java +++ b/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/iso_utils/FieldUtils.java @@ -361,7 +361,12 @@ public class FieldUtils { // } else { // iterator.remove(); // } - field.setDataStr("000"); + if(payDetail.getTransactionType() == REVERSAL.value) { + field.setDataStr("001"); + } else { + field.setDataStr("000"); + } + break; case 24: //Network International Identifier NII @@ -376,10 +381,10 @@ public class FieldUtils { 08 – mail order/telephone order * */ // Service point condition code Fill in 00 for ordinary consumer transactions and mobile phone chip transactions, fill in 08 for order consumer transactions, fill in 64 for installment transactions, fill in 65 for points consumption transactions, fill in 67 for mobile phone card-free reservations - if (payDetail.getTransactionType() == PRE_AUTH_SALE.value) { + // do not remove double check for preauth, it's control for reversal + if (payDetail.getTransactionType() == PRE_AUTH_SALE.value || payDetail.getTransType().equals(PRE_AUTH_SALE.name)) { field.setDataStr("06"); - } - else if(payDetail.getTransactionType() == REFUND.value || payDetail.getTransactionType() == REVERSAL.value) { + } else if(payDetail.getTransactionType() == REFUND.value || payDetail.getTransType().equals(REFUND.name) ) { // field.setDataStr("00"); // MPU field.setDataStr("61"); // CZ } else if(payDetail.getCardType() == -1) {