diff --git a/app/src/main/java/com/mob/utsmyanmar/ui/history_functions/HistoryFilters.kt b/app/src/main/java/com/mob/utsmyanmar/ui/history_functions/HistoryFilters.kt index b7d7d8f..ac5db2c 100644 --- a/app/src/main/java/com/mob/utsmyanmar/ui/history_functions/HistoryFilters.kt +++ b/app/src/main/java/com/mob/utsmyanmar/ui/history_functions/HistoryFilters.kt @@ -46,6 +46,7 @@ internal fun displayTransactionTitle(payDetail: PayDetail): String { internal fun isValidForReprint(payDetail: PayDetail): Boolean { if (payDetail.transactionType == TransactionsType.SETTLEMENT.value) return false + if (payDetail.transactionType == TransactionsType.REVERSAL.value) return false if (payDetail.transactionType == TransactionsType.WAVEPAY.value && payDetail.qrTransStatus != 1) { return false } @@ -59,14 +60,8 @@ internal fun filterReprintAnyTransactions( transactions: List, hostType: HostType ): List { - val yesterday = POSUtil.getInstance().yesterdayDate - val dateFormat = SimpleDateFormat("dd/MM/yy", Locale.getDefault()) - return transactions.filter { pay -> - val transDate = parseTransDate(pay.transDate, dateFormat) ?: return@filter false - if (yesterday.compareTo(transDate) > 0) return@filter false - if (pay.transactionType == TransactionsType.SETTLEMENT.value) return@filter false - if (pay.transactionType == TransactionsType.REVERSAL.value) return@filter false + if (!isValidForReprint(pay)) return@filter false when (hostType) { HostType.MPU -> diff --git a/app/src/main/java/com/mob/utsmyanmar/ui/history_functions/ReprintAnyTransactionScreen.kt b/app/src/main/java/com/mob/utsmyanmar/ui/history_functions/ReprintAnyTransactionScreen.kt index 3002a9b..fc06fa0 100644 --- a/app/src/main/java/com/mob/utsmyanmar/ui/history_functions/ReprintAnyTransactionScreen.kt +++ b/app/src/main/java/com/mob/utsmyanmar/ui/history_functions/ReprintAnyTransactionScreen.kt @@ -1,8 +1,13 @@ package com.mob.utsmyanmar.ui.history_functions +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.slideInVertically +import androidx.compose.animation.slideOutVertically +import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth @@ -10,11 +15,20 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack -import androidx.compose.material3.OutlinedTextField +import androidx.compose.material.icons.automirrored.rounded.Backspace +import androidx.compose.material3.Card +import androidx.compose.material3.CardDefaults +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBar +import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.livedata.observeAsState @@ -23,12 +37,27 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.shadow +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp -import com.mob.utsmyanmar.ui.components.appbar.AppBar +import androidx.compose.ui.unit.sp +import com.mob.utsmyanmar.ui.components.NumericKeypad +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.MOBPOSTheme import com.utsmyanmar.paylibs.model.PayDetail 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") +) + +@OptIn(ExperimentalMaterial3Api::class) @Composable fun ReprintAnyTransactionScreen( viewModel: HistoryViewModel, @@ -38,6 +67,7 @@ fun ReprintAnyTransactionScreen( ) { val allTransactions by viewModel.getTransactionHistory().observeAsState(emptyList()) var searchQuery by remember { mutableStateOf("") } + var isFocused by remember { mutableStateOf(false) } val filtered = remember(allTransactions, hostType, searchQuery) { val base = filterReprintAnyTransactions(allTransactions, hostType) @@ -47,10 +77,32 @@ fun ReprintAnyTransactionScreen( Scaffold( containerColor = Color.IvoryBeige, topBar = { - AppBar( - title = "Transactions", - icon = Icons.AutoMirrored.Filled.ArrowBack, - onIconClick = onBack + TopAppBar( + title = { + Column { + Text( + text = "Reprint Transaction", + style = MaterialTheme.typography.titleMedium + ) + Text( + text = hostTypeLabel(hostType), + style = MaterialTheme.typography.labelSmall, + color = Color.Gray + ) + } + }, + navigationIcon = { + IconButton(onClick = onBack) { + Icon( + imageVector = Icons.AutoMirrored.Filled.ArrowBack, + contentDescription = "Back", + tint = Color.LegacyRed + ) + } + }, + colors = TopAppBarDefaults.topAppBarColors( + containerColor = Color.IvoryBeige + ) ) } ) { paddingValues -> @@ -58,37 +110,154 @@ fun ReprintAnyTransactionScreen( modifier = Modifier .fillMaxSize() .padding(paddingValues) - .padding(16.dp) + .padding(horizontal = 16.dp) ) { - OutlinedTextField( - value = searchQuery, - onValueChange = { searchQuery = it }, - modifier = Modifier.fillMaxWidth(), - label = { Text("Trace (6) or RRN (12)") }, - singleLine = true + SearchInputBox( + query = searchQuery, + isFocused = isFocused, + onFocus = { isFocused = true } ) - Spacer(modifier = Modifier.height(12.dp)) + Spacer(modifier = Modifier.height(8.dp)) + + Text( + text = "${filtered.size} transaction(s) found", + style = MaterialTheme.typography.labelSmall, + color = Color.Gray, + modifier = Modifier.padding(horizontal = 4.dp) + ) + + Spacer(modifier = Modifier.height(8.dp)) if (filtered.isEmpty()) { Box( - modifier = Modifier.fillMaxSize(), + modifier = Modifier.weight(1f), contentAlignment = Alignment.Center ) { - Text("No transactions found.", color = Color.Gray) + Text( + text = if (allTransactions.isEmpty()) "No transactions available" else "No matching transactions", + color = Color.Gray, + style = MaterialTheme.typography.bodyMedium + ) } } else { LazyColumn( - modifier = Modifier.fillMaxSize(), + modifier = Modifier.weight(1f), verticalArrangement = Arrangement.spacedBy(8.dp) ) { items(filtered, key = { "${it.voucherNo}_${it.referNo}_${it.PID}" }) { payDetail -> HistoryTransactionCard(payDetail) { + isFocused = false onReprintTransaction(prepareReprintPayDetail(payDetail)) } } } } + + AnimatedVisibility( + visible = isFocused, + enter = slideInVertically(initialOffsetY = { it }), + exit = slideOutVertically(targetOffsetY = { it }) + ) { + NumericKeypad( + keys = searchKeys, + modifier = Modifier + .fillMaxWidth() + .height(280.dp) + .padding(top = 8.dp), + onKeyClick = { key -> + when (key) { + "C" -> searchQuery = "" + "\u232B" -> searchQuery = searchQuery.dropLast(1) + else -> if (searchQuery.length < 12) searchQuery += key + } + } + ) + } + } + } +} + +@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) + ) + } + } + } + } +} + +@P2Preview +@P3Preview +@Composable +private fun ReprintAnyTransactionScreenPreview() { + MOBPOSTheme { + Box(modifier = Modifier.height(600.dp)) { + Card( + modifier = Modifier.fillMaxWidth(), + colors = CardDefaults.cardColors(containerColor = Color.White) + ) { + Column(modifier = Modifier.padding(16.dp)) { + Text( + text = "SALE", + color = Color.LegacyRed, + style = MaterialTheme.typography.titleSmall + ) + Spacer(modifier = Modifier.height(4.dp)) + Text("Trace 000001", style = MaterialTheme.typography.bodySmall) + Text("RRN 123456789012", style = MaterialTheme.typography.bodySmall, color = Color.Gray) + } + } } } }