transaction info page fixed

This commit is contained in:
moon 2026-09-28 10:22:36 +06:30
parent 3e6a0707d8
commit 1d2585f548
9 changed files with 246 additions and 136 deletions

View File

@ -40,8 +40,8 @@ android {
dimension = "env" dimension = "env"
applicationIdSuffix = ".uat" applicationIdSuffix = ".uat"
versionNameSuffix = "-UAT" versionNameSuffix = "-UAT"
versionCode = 21 versionCode = 29
versionName = "3.9" versionName = "4.7"
buildConfigField("String", "ENV", "\"UAT\"") buildConfigField("String", "ENV", "\"UAT\"")
resValue("string", "app_name", "MOB-UAT") resValue("string", "app_name", "MOB-UAT")
} }

View File

@ -10,13 +10,15 @@ import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.Backspace import androidx.compose.material.icons.automirrored.rounded.Backspace
import androidx.compose.material3.Button import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Card import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults import androidx.compose.material3.CardDefaults
import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.ui.draw.shadow
import androidx.compose.ui.unit.sp
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@ -64,7 +66,7 @@ internal fun HistoryTransactionCard(
style = MaterialTheme.typography.titleSmall style = MaterialTheme.typography.titleSmall
) )
Text( Text(
"${convertDateString(payDetail.transDate)} ${payDetail.transTime}", "${convertDateString(payDetail.transDate.orEmpty())} ${payDetail.transTime.orEmpty()}".trim(),
style = MaterialTheme.typography.titleSmall style = MaterialTheme.typography.titleSmall
) )
} }
@ -92,7 +94,7 @@ internal fun HistoryTransactionCard(
style = MaterialTheme.typography.titleSmall style = MaterialTheme.typography.titleSmall
) )
Text( Text(
text = payDetail.voucherNo.ifBlank { "-" }, text = payDetail.voucherNo.orEmpty().ifBlank { "-" },
style = MaterialTheme.typography.titleSmall style = MaterialTheme.typography.titleSmall
) )
} }
@ -106,7 +108,7 @@ internal fun HistoryTransactionCard(
style = MaterialTheme.typography.titleSmall style = MaterialTheme.typography.titleSmall
) )
Text( Text(
text = payDetail.referNo.ifBlank { "-" }, text = payDetail.referNo.orEmpty().ifBlank { "-" },
style = MaterialTheme.typography.titleSmall style = MaterialTheme.typography.titleSmall
) )
} }
@ -120,7 +122,7 @@ internal fun HistoryTransactionCard(
style = MaterialTheme.typography.titleSmall style = MaterialTheme.typography.titleSmall
) )
Text( Text(
text = payDetail.approvalCode.ifBlank { "-" }, text = (payDetail.approvalCode ?: payDetail.authNo).orEmpty().ifBlank { "-" },
style = MaterialTheme.typography.titleSmall style = MaterialTheme.typography.titleSmall
) )
} }
@ -133,29 +135,29 @@ internal fun HistoryTransactionDetailCard(
payDetail: PayDetail, payDetail: PayDetail,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) { ) {
val dateStr = if (payDetail.transDate.isNotBlank()) { val dateStr = if (!payDetail.transDate.isNullOrBlank()) {
convertDateString(payDetail.transDate) convertDateString(payDetail.transDate)
} else { } else {
payDetail.tradeDate.ifBlank { "-" } payDetail.tradeDate.orEmpty().ifBlank { "-" }
} }
val timeStr = payDetail.transTime.ifBlank { payDetail.tradeTime }.ifBlank { "-" } val timeStr = payDetail.transTime.orEmpty().ifBlank { payDetail.tradeTime.orEmpty() }.ifBlank { "-" }
val merchantNameStr = payDetail.merchantName.takeIf { it.isNotBlank() } val merchantNameStr = payDetail.merchantName?.takeIf { it.isNotBlank() }
?: SystemParamsOperation.getInstance().merchantName?.takeIf { it.isNotBlank() } ?: SystemParamsOperation.getInstance().merchantName?.takeIf { it.isNotBlank() }
?: "-" ?: "-"
val midStr = payDetail.merchantNo.takeIf { it.isNotBlank() } val midStr = payDetail.merchantNo?.takeIf { it.isNotBlank() }
?: SystemParamsOperation.getInstance().merchantId?.takeIf { it.isNotBlank() } ?: SystemParamsOperation.getInstance().merchantId?.takeIf { it.isNotBlank() }
?: "-" ?: "-"
val tidStr = payDetail.terminalNo.takeIf { it.isNotBlank() } val tidStr = payDetail.terminalNo?.takeIf { it.isNotBlank() }
?: SystemParamsOperation.getInstance().terminalId?.takeIf { it.isNotBlank() } ?: SystemParamsOperation.getInstance().terminalId?.takeIf { it.isNotBlank() }
?: "-" ?: "-"
val traceNoStr = payDetail.voucherNo.ifBlank { "-" } val traceNoStr = payDetail.voucherNo.orEmpty().ifBlank { "-" }
val refNoStr = payDetail.referNo.ifBlank { "-" } val refNoStr = payDetail.referNo.orEmpty().ifBlank { "-" }
val aprCodeStr = payDetail.approvalCode?.takeIf { it.isNotBlank() } val aprCodeStr = payDetail.approvalCode?.takeIf { it.isNotBlank() }
?: payDetail.authNo.takeIf { it.isNotBlank() } ?: payDetail.authNo?.takeIf { it.isNotBlank() }
?: "-" ?: "-"
val transTypeStr = displayTransactionTitle(payDetail) val transTypeStr = displayTransactionTitle(payDetail)
val amountStr = displayAmountWithSign(payDetail) val amountStr = displayAmountWithSign(payDetail)
val cardTypeStr = payDetail.accountType.ifBlank { "-" } val cardTypeStr = payDetail.accountType.orEmpty().ifBlank { "-" }
val cleanPan = payDetail.cardNo.orEmpty().replace(" ", "") val cleanPan = payDetail.cardNo.orEmpty().replace(" ", "")
val cardNoStr = if (cleanPan.length > 10) { val cardNoStr = if (cleanPan.length > 10) {
cleanPan.take(6) + "*".repeat(cleanPan.length - 10) + cleanPan.takeLast(4) cleanPan.take(6) + "*".repeat(cleanPan.length - 10) + cleanPan.takeLast(4)
@ -187,12 +189,12 @@ internal fun HistoryTransactionDetailCard(
style = MaterialTheme.typography.titleMedium, style = MaterialTheme.typography.titleMedium,
fontWeight = FontWeight.Bold fontWeight = FontWeight.Bold
) )
Text( // Text(
text = amountStr, // text = amountStr,
color = Color.Black, // color = Color.Black,
style = MaterialTheme.typography.titleMedium, // style = MaterialTheme.typography.titleMedium,
fontWeight = FontWeight.Bold // fontWeight = FontWeight.Bold
) // )
} }
HorizontalDivider( HorizontalDivider(
@ -202,7 +204,7 @@ internal fun HistoryTransactionDetailCard(
SummaryLine("Date", dateStr) SummaryLine("Date", dateStr)
SummaryLine("Time", timeStr) SummaryLine("Time", timeStr)
SummaryLine("Merchant Name", merchantNameStr) // SummaryLine("Merchant Name", merchantNameStr)
SummaryLine("Mid", midStr) SummaryLine("Mid", midStr)
SummaryLine("Tid", tidStr) SummaryLine("Tid", tidStr)
SummaryLine("Trace No", traceNoStr) SummaryLine("Trace No", traceNoStr)
@ -315,7 +317,7 @@ internal fun HistoryNumericKeypad(
) )
) { ) {
if (key == "⌫") { if (key == "⌫") {
Icon(Icons.Rounded.Backspace, contentDescription = "Backspace") Icon(Icons.AutoMirrored.Rounded.Backspace, contentDescription = "Backspace")
} else { } else {
Text(key, style = MaterialTheme.typography.headlineMedium) Text(key, style = MaterialTheme.typography.headlineMedium)
} }
@ -326,6 +328,74 @@ internal fun HistoryNumericKeypad(
} }
} }
internal val searchKeys = listOf(
listOf("1", "2", "3"),
listOf("4", "5", "6"),
listOf("7", "8", "9"),
listOf("C", "0", "\u232B")
)
@Composable
internal fun SearchInputBox(
query: String,
isFocused: Boolean,
onFocus: () -> Unit,
label: String = if (isFocused) "Trace or RRN" else "Tap to search by Trace or RRN",
onDelete: (() -> Unit)? = null,
) {
Card(
modifier = Modifier
.fillMaxWidth()
.clickable(onClick = onFocus),
colors = CardDefaults.cardColors(containerColor = Color.White),
shape = RoundedCornerShape(12.dp),
elevation = CardDefaults.cardElevation(defaultElevation = if (isFocused) 6.dp else 2.dp)
) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp, vertical = 14.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween
) {
Column(modifier = Modifier.weight(1f)) {
Text(
text = label,
style = MaterialTheme.typography.bodySmall,
color = if (isFocused) Color.LegacyRed else Color.Gray
)
Spacer(modifier = Modifier.height(4.dp))
Text(
text = query.ifEmpty { "_" },
color = Color.LegacyRed,
style = MaterialTheme.typography.headlineSmall.copy(
fontWeight = FontWeight.Bold,
letterSpacing = 2.sp
)
)
}
if (query.isNotEmpty()) {
Card(
shape = RoundedCornerShape(18.dp),
colors = CardDefaults.cardColors(containerColor = Color.White),
elevation = CardDefaults.cardElevation(defaultElevation = 4.dp),
modifier = Modifier
.shadow(2.dp, RoundedCornerShape(18.dp))
.clickable(enabled = onDelete != null) { onDelete?.invoke() }
) {
Icon(
imageVector = Icons.AutoMirrored.Rounded.Backspace,
contentDescription = "Delete",
tint = Color.LegacyRed,
modifier = Modifier.padding(horizontal = 14.dp, vertical = 12.dp)
)
}
}
}
}
}
@Preview(showBackground = true) @Preview(showBackground = true)
@Composable @Composable
private fun HistoryTransactionCardPreview() { private fun HistoryTransactionCardPreview() {

View File

@ -55,11 +55,17 @@ internal fun displayTransactionStatus(payDetail: PayDetail): String {
if (payDetail.transactionType == TransactionsType.REVERSAL.value) { if (payDetail.transactionType == TransactionsType.REVERSAL.value) {
return if (payDetail.isNeedReversal) "REVERSAL FAILED" else "REVERSAL SUCCESS" return if (payDetail.isNeedReversal) "REVERSAL FAILED" else "REVERSAL SUCCESS"
} }
return POSUtil.getInstance().getResponse(payDetail.tradeAnswerCode.orEmpty().ifBlank { "-" }) val code = payDetail.tradeAnswerCode.orEmpty().ifBlank { "-" }
return try {
POSUtil.getInstance().getResponse(code)
} catch (_: Throwable) {
if (code == "00") "Approved" else code
}
} }
internal fun displayTransactionTitle(payDetail: PayDetail): String { internal fun displayTransactionTitle(payDetail: PayDetail): String {
val title = payDetail.transType val title = payDetail.transType
.orEmpty()
.ifBlank { "TRANSACTION" } .ifBlank { "TRANSACTION" }
.replace("CASH_OUT", "CASH_ADV", ignoreCase = true) .replace("CASH_OUT", "CASH_ADV", ignoreCase = true)
return if (payDetail.transactionType == TransactionsType.REVERSAL.value) { return if (payDetail.transactionType == TransactionsType.REVERSAL.value) {

View File

@ -21,6 +21,7 @@ class HistoryViewModel @Inject constructor(
fun getLastSettlement(): LiveData<List<PayDetail>> = fun getLastSettlement(): LiveData<List<PayDetail>> =
repository.getLastSettlement() repository.getLastSettlement()
fun getReviewBatchTransaction(batchNo: String): LiveData<List<PayDetail>> = fun getReviewBatchTransaction(batchNo: String): LiveData<List<PayDetail>> =
repository.getReviewBatchTransaction(batchNo) repository.getReviewBatchTransaction(batchNo)
@ -28,5 +29,9 @@ class HistoryViewModel @Inject constructor(
repository.getSmileSummaryTrans(batchNo) repository.getSmileSummaryTrans(batchNo)
fun searchTransaction(voucherNo: String): LiveData<PayDetail> = fun searchTransaction(voucherNo: String): LiveData<PayDetail> =
repository.searchTransaction(voucherNo) if (voucherNo.length > 6) {
repository.searchPayDetail(voucherNo)
} else {
repository.searchTransaction(voucherNo.padStart(6, '0'))
}
} }

View File

@ -48,13 +48,6 @@ import com.mob.utsmyanmar.ui.theme.MOBPOSTheme
import com.utsmyanmar.paylibs.model.PayDetail import com.utsmyanmar.paylibs.model.PayDetail
import com.utsmyanmar.paylibs.utils.enums.HostType import com.utsmyanmar.paylibs.utils.enums.HostType
private val searchKeys = listOf(
listOf("1", "2", "3"),
listOf("4", "5", "6"),
listOf("7", "8", "9"),
listOf("C", "0", "\u232B")
)
@Composable @Composable
fun ReprintAnyTransactionScreen( fun ReprintAnyTransactionScreen(
viewModel: HistoryViewModel, viewModel: HistoryViewModel,
@ -128,7 +121,8 @@ fun ReprintAnyTransactionContent(
SearchInputBox( SearchInputBox(
query = searchQuery, query = searchQuery,
isFocused = isFocused, isFocused = isFocused,
onFocus = { isFocused = true } onFocus = { isFocused = true },
onDelete = { searchQuery = searchQuery.dropLast(1) }
) )
Spacer(modifier = Modifier.height(8.dp)) Spacer(modifier = Modifier.height(8.dp))
@ -191,64 +185,6 @@ fun ReprintAnyTransactionContent(
} }
} }
@Composable
private fun SearchInputBox(
query: String,
isFocused: Boolean,
onFocus: () -> Unit,
) {
Card(
modifier = Modifier
.fillMaxWidth()
.clickable(onClick = onFocus),
colors = CardDefaults.cardColors(containerColor = Color.White),
shape = RoundedCornerShape(12.dp),
elevation = CardDefaults.cardElevation(defaultElevation = if (isFocused) 6.dp else 2.dp)
) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp, vertical = 14.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween
) {
Column(modifier = Modifier.weight(1f)) {
Text(
text = if (isFocused) "Trace or RRN" else "Tap to search by Trace or RRN",
style = MaterialTheme.typography.bodySmall,
color = if (isFocused) Color.LegacyRed else Color.Gray
)
Spacer(modifier = Modifier.height(4.dp))
Text(
text = query.ifEmpty { "_" },
color = Color.LegacyRed,
style = MaterialTheme.typography.headlineSmall.copy(
fontWeight = FontWeight.Bold,
letterSpacing = 2.sp
)
)
}
if (query.isNotEmpty()) {
Card(
shape = RoundedCornerShape(18.dp),
colors = CardDefaults.cardColors(containerColor = Color.White),
elevation = CardDefaults.cardElevation(defaultElevation = 4.dp),
modifier = Modifier
.shadow(2.dp, RoundedCornerShape(18.dp))
.clickable { }
) {
Icon(
imageVector = Icons.AutoMirrored.Rounded.Backspace,
contentDescription = "Delete",
tint = Color.LegacyRed,
modifier = Modifier.padding(horizontal = 14.dp, vertical = 12.dp)
)
}
}
}
}
}
@Preview(showBackground = true) @Preview(showBackground = true)
@Composable @Composable

View File

@ -124,3 +124,42 @@ private fun ReviewDetailScreenPreview() {
) )
} }
} }
@P2Preview
@P3Preview
@Composable
private fun ReviewDetailScreenWithReprintPreview() {
MOBPOSTheme {
ReviewDetailContent(
transaction = PayDetail().apply {
transDate = "21/09/26"
transTime = "14:04:15"
merchantName = "UTS Merchant"
merchantNo = "100089476209176"
terminalNo = "10420257"
voucherNo = "000001"
referNo = "123456789012"
approvalCode = "123456"
transType = "SALE"
amount = 1500000L
accountType = "MPU"
cardNo = "9503036867315548"
tradeAnswerCode = "00"
},
onBack = {},
onReprint = {}
)
}
}
@P2Preview
@P3Preview
@Composable
private fun ReviewDetailScreenNotFoundPreview() {
MOBPOSTheme {
ReviewDetailContent(
transaction = null,
onBack = {}
)
}
}

View File

@ -1,18 +1,20 @@
package com.mob.utsmyanmar.ui.history_functions package com.mob.utsmyanmar.ui.history_functions
import androidx.compose.foundation.layout.Box import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.slideInVertically
import androidx.compose.animation.slideOutVertically
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material3.Button import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Card import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@ -22,16 +24,16 @@ import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.material3.MaterialTheme
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import com.mob.utsmyanmar.ui.components.NumericKeypad
import com.mob.utsmyanmar.ui.components.appbar.AppBar import com.mob.utsmyanmar.ui.components.appbar.AppBar
import com.mob.utsmyanmar.ui.preview.P2Preview
import com.mob.utsmyanmar.ui.preview.P3Preview
import com.mob.utsmyanmar.ui.theme.Color import com.mob.utsmyanmar.ui.theme.Color
import com.mob.utsmyanmar.ui.theme.MOBPOSTheme
import com.utsmyanmar.paylibs.model.PayDetail import com.utsmyanmar.paylibs.model.PayDetail
@Composable @Composable
@ -40,7 +42,6 @@ fun ReviewTraceScreen(
onBack: () -> Unit, onBack: () -> Unit,
onNavigateReviewDetail: (String) -> Unit, onNavigateReviewDetail: (String) -> Unit,
) { ) {
var traceNumber by remember { mutableStateOf("") }
var searchedTrace by remember { mutableStateOf("") } var searchedTrace by remember { mutableStateOf("") }
var lastNavigatedTrace by remember { mutableStateOf<String?>(null) } var lastNavigatedTrace by remember { mutableStateOf<String?>(null) }
@ -61,6 +62,24 @@ fun ReviewTraceScreen(
onNavigateReviewDetail(matchedTrace) onNavigateReviewDetail(matchedTrace)
} }
ReviewTraceContent(
searchedTrace = searchedTrace,
transactionFound = transaction != null,
onBack = onBack,
onSearch = { query -> searchedTrace = query }
)
}
@Composable
fun ReviewTraceContent(
searchedTrace: String,
transactionFound: Boolean,
onBack: () -> Unit,
onSearch: (String) -> Unit,
) {
var traceNumber by remember { mutableStateOf("") }
var isFocused by remember { mutableStateOf(true) }
Scaffold( Scaffold(
containerColor = Color.IvoryBeige, containerColor = Color.IvoryBeige,
topBar = { topBar = {
@ -78,12 +97,12 @@ fun ReviewTraceScreen(
.padding(16.dp) .padding(16.dp)
) { ) {
Text( Text(
text = if (searchedTrace.isNotBlank() && transaction == null) { text = if (searchedTrace.isNotBlank() && !transactionFound) {
"No transaction found for trace $searchedTrace." "No transaction found for trace $searchedTrace."
} else { } else {
"Input trace number to review transaction." "Input trace number to review transaction."
}, },
color = if (searchedTrace.isNotBlank() && transaction == null) { color = if (searchedTrace.isNotBlank() && !transactionFound) {
Color.LegacyRed Color.LegacyRed
} else { } else {
Color.Black Color.Black
@ -93,49 +112,66 @@ fun ReviewTraceScreen(
Spacer(modifier = Modifier.height(16.dp)) Spacer(modifier = Modifier.height(16.dp))
Card( SearchInputBox(
modifier = Modifier.fillMaxWidth(), query = traceNumber,
colors = CardDefaults.cardColors(containerColor = Color.White) isFocused = isFocused,
) { onFocus = { isFocused = true },
Text( onDelete = { traceNumber = traceNumber.dropLast(1) }
text = traceNumber.padStart(6, '0').ifEmpty { "000000" },
modifier = Modifier
.fillMaxWidth()
.padding(24.dp),
textAlign = TextAlign.Center,
style = MaterialTheme.typography.displayMedium.copy(fontSize = 28.sp)
) )
}
Spacer(modifier = Modifier.height(16.dp)) Spacer(modifier = Modifier.height(16.dp))
HistoryNumericKeypad( AnimatedVisibility(
onDigit = { digit -> visible = isFocused,
if (traceNumber.length < 6) traceNumber += digit enter = slideInVertically(initialOffsetY = { it }),
}, exit = slideOutVertically(targetOffsetY = { it })
onBackspace = { ) {
if (traceNumber.isNotEmpty()) { NumericKeypad(
traceNumber = traceNumber.dropLast(1) keys = searchKeys,
modifier = Modifier
.fillMaxWidth()
.height(280.dp)
.padding(top = 8.dp),
onKeyClick = { key ->
when (key) {
"C" -> traceNumber = ""
"\u232B" -> traceNumber = traceNumber.dropLast(1)
else -> if (traceNumber.length < 12) traceNumber += key
}
} }
},
onClear = { traceNumber = "" }
) )
}
Spacer(modifier = Modifier.weight(1f)) Spacer(modifier = Modifier.weight(1f))
Button( Button(
onClick = { searchedTrace = traceNumber.padStart(6, '0') }, onClick = { onSearch(traceNumber.trim()) },
enabled = traceNumber.isNotBlank(), enabled = traceNumber.isNotBlank(),
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.height(56.dp), .height(56.dp),
shape = RoundedCornerShape(8.dp),
colors = ButtonDefaults.buttonColors( colors = ButtonDefaults.buttonColors(
containerColor = Color.LegacyRed, containerColor = Color.LegacyRed,
contentColor = Color.White contentColor = Color.White
) )
) { ) {
Text("Search") Text("Search", style = MaterialTheme.typography.titleMedium)
} }
} }
} }
} }
@P2Preview
@P3Preview
@Composable
private fun ReviewTraceScreenPreview() {
MOBPOSTheme {
ReviewTraceContent(
searchedTrace = "",
transactionFound = false,
onBack = {},
onSearch = {}
)
}
}

View File

@ -20,6 +20,7 @@ fun String?.maskCardNumber(): String {
return maskedPan.toString() return maskedPan.toString()
} }
fun convertDateString(dateStr: String): String { fun convertDateString(dateStr: String?): String {
if (dateStr.isNullOrEmpty()) return ""
return dateStr.replace(Regex("/(\\d{2})$"), "/20$1") return dateStr.replace(Regex("/(\\d{2})$"), "/20$1")
} }

View File

@ -88,23 +88,33 @@ public class BaseErrorCode {
} }
public static String getCode(String code) { public static String getCode(String code) {
if (instance == null) instance = new BaseErrorCode(); if (instance == null || (instance.errorCode.isEmpty() && PayLibsUtils.getInstance().context != null)) {
instance = new BaseErrorCode();
}
String errorMsg = instance.errorCode.get(code); String errorMsg = instance.errorCode.get(code);
// return (errorMsg != null ? "RESPONSE CODE"+"(" + code + ")\n ("+errorMsg+")" : getString(R.string.errorOthers)); // return (errorMsg != null ? "RESPONSE CODE"+"(" + code + ")\n ("+errorMsg+")" : getString(R.string.errorOthers));
if(code.length() == 2) { if(code.length() == 2) {
return (errorMsg != null ? errorMsg : getString(R.string.errorOthers)); if (errorMsg != null) return errorMsg;
String defaultError = getString(R.string.errorOthers);
return defaultError != null ? defaultError : ("00".equals(code) ? "Approved" : "Others");
} else if(code.isEmpty()) { } else if(code.isEmpty()) {
return "NO RESPONSE"; return "NO RESPONSE";
} else { } else {
return (errorMsg != null ? code + " - "+errorMsg : getString(R.string.errorOthers)); if (errorMsg != null) return code + " - "+errorMsg;
String defaultError = getString(R.string.errorOthers);
return defaultError != null ? code + " - " + defaultError : code + " - Others";
} }
} }
public static String getErrorMessage(String code) { public static String getErrorMessage(String code) {
if (instance == null) instance = new BaseErrorCode(); if (instance == null || (instance.errorCode.isEmpty() && PayLibsUtils.getInstance().context != null)) {
instance = new BaseErrorCode();
}
String errorMsg = instance.errorCode.get(code); String errorMsg = instance.errorCode.get(code);
return (errorMsg != null ?" "+ errorMsg+" " :getString(R.string.errorOthers)); if (errorMsg != null) return " " + errorMsg + " ";
String defaultError = getString(R.string.errorOthers);
return " " + (defaultError != null ? defaultError : "Others") + " ";
} }
private static BaseErrorCode instance; private static BaseErrorCode instance;
@ -117,14 +127,21 @@ public class BaseErrorCode {
if (KeyValueSet == null) return; if (KeyValueSet == null) return;
int size = KeyValueSet.length; int size = KeyValueSet.length;
if (size % 2 == 0) if (size % 2 == 0)
for (int i = 0; i < size; i += 2) for (int i = 0; i < size; i += 2) {
errorCode.put((String) KeyValueSet[i],getString((Integer)KeyValueSet[i + 1])); String val = getString((Integer)KeyValueSet[i + 1]);
if (val != null) {
errorCode.put((String) KeyValueSet[i], val);
}
}
else throw new RuntimeException("Error code key value pairs must be even numbers"); else throw new RuntimeException("Error code key value pairs must be even numbers");
} }
private Map<String, String> errorCode = new HashMap<>(); private Map<String, String> errorCode = new HashMap<>();
private static String getString(int id) { private static String getString(int id) {
if (PayLibsUtils.getInstance() == null || PayLibsUtils.getInstance().context == null) {
return null;
}
return PayLibsUtils.getInstance().context.getString(id); return PayLibsUtils.getInstance().context.getString(id);
} }