Skip to content

[Payment Method Improvements] Gray out button until payment amount is greater or equal to amount due #11606

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
May 30, 2024
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,10 @@ class ChangeDueCalculatorFragment : BaseFragment() {
return ComposeView(requireContext()).apply {
setContent {
val uiState by viewModel.uiState.collectAsState()
val recordTransactionDetailsChecked by viewModel.recordTransactionDetailsChecked.collectAsState()
ChangeDueCalculatorScreen(
uiState = uiState,
recordTransactionDetailsChecked = recordTransactionDetailsChecked,
onNavigateUp = viewModel::onBackPressed,
onCompleteOrderClick = viewModel::addOrderNoteIfChecked,
onCompleteOrderClick = viewModel::onOrderComplete,
onAmountReceivedChanged = { viewModel.updateAmountReceived(it) },
onRecordTransactionDetailsCheckedChanged = {
viewModel.updateRecordTransactionDetailsChecked(it)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.unit.dp
import com.woocommerce.android.R
import com.woocommerce.android.ui.compose.component.BigDecimalTextFieldValueMapper
Expand All @@ -52,7 +52,6 @@ import java.math.BigDecimal
@Composable
fun ChangeDueCalculatorScreen(
uiState: ChangeDueCalculatorViewModel.UiState,
recordTransactionDetailsChecked: Boolean,
onNavigateUp: () -> Unit,
onCompleteOrderClick: () -> Unit,
onAmountReceivedChanged: (BigDecimal) -> Unit,
Expand Down Expand Up @@ -129,7 +128,7 @@ fun ChangeDueCalculatorScreen(
text = if (uiState.change < BigDecimal.ZERO) {
"-"
} else {
uiState.change.toPlainString()
"${uiState.currencySymbol}${uiState.change.toPlainString()}"
},
style = MaterialTheme.typography.h3,
fontWeight = FontWeight.Bold,
Expand All @@ -142,18 +141,20 @@ fun ChangeDueCalculatorScreen(

RecordTransactionDetailsNote(
modifier = Modifier.fillMaxWidth(),
checked = recordTransactionDetailsChecked,
checked = uiState.recordTransactionDetailsChecked,
onCheckedChange = onRecordTransactionDetailsCheckedChanged
)

MarkOrderAsCompleteButton(
loading = uiState.loading,
onClick = onCompleteOrderClick
enabled = uiState.canCompleteOrder,
onClick = onCompleteOrderClick,
modifier = Modifier.padding(top = 16.dp, bottom = 8.dp)
)
}
}
Spacer(modifier = Modifier.height(16.dp))
}
Spacer(modifier = Modifier.height(16.dp))
}
}

Expand Down Expand Up @@ -184,12 +185,13 @@ fun RecordTransactionDetailsNote(
@Composable
fun MarkOrderAsCompleteButton(
loading: Boolean,
enabled: Boolean,
onClick: () -> Unit,
modifier: Modifier = Modifier
) {
WCColoredButton(
onClick = onClick,
enabled = !loading,
enabled = !loading && enabled,
modifier = modifier
.fillMaxWidth()
) {
Expand All @@ -216,16 +218,58 @@ private fun getTitleText(uiState: ChangeDueCalculatorViewModel.UiState): String
}

@Composable
@Preview(showBackground = true)
fun ChangeDueCalculatorScreenSuccessPreview() {
@PreviewLightDark
fun ChangeDueCalculatorScreenSuccessPreviewUnchecked() {
ChangeDueCalculatorScreen(
uiState = ChangeDueCalculatorViewModel.UiState(
amountDue = BigDecimal("666.00"),
change = BigDecimal("0.00"),
amountReceived = BigDecimal("0.00"),
loading = true
loading = false,
canCompleteOrder = true,
currencySymbol = "$",
recordTransactionDetailsChecked = false,
),
onNavigateUp = {},
onCompleteOrderClick = {},
onAmountReceivedChanged = {},
onRecordTransactionDetailsCheckedChanged = {}
)
}

@Composable
@PreviewLightDark
fun ChangeDueCalculatorScreenSuccessPreviewChecked() {
ChangeDueCalculatorScreen(
uiState = ChangeDueCalculatorViewModel.UiState(
amountDue = BigDecimal("666.00"),
change = BigDecimal("0.00"),
amountReceived = BigDecimal("0.00"),
loading = true,
canCompleteOrder = true,
currencySymbol = "€",
recordTransactionDetailsChecked = true,
),
onNavigateUp = {},
onCompleteOrderClick = {},
onAmountReceivedChanged = {},
onRecordTransactionDetailsCheckedChanged = {}
)
}

@Composable
@PreviewLightDark
fun ChangeDueCalculatorScreenSuccessPreviewDisabled() {
ChangeDueCalculatorScreen(
uiState = ChangeDueCalculatorViewModel.UiState(
amountDue = BigDecimal("666.00"),
change = BigDecimal("0.00"),
amountReceived = BigDecimal("0.00"),
loading = false,
canCompleteOrder = false,
currencySymbol = "€",
recordTransactionDetailsChecked = true,
),
recordTransactionDetailsChecked = false,
onNavigateUp = {},
onCompleteOrderClick = {},
onAmountReceivedChanged = {},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,24 @@ class ChangeDueCalculatorViewModel @Inject constructor(
) : ScopedViewModel(savedStateHandle) {
val navArgs: ChangeDueCalculatorFragmentArgs by savedStateHandle.navArgs()
private val orderId: Long = navArgs.orderId
private val _recordTransactionDetailsChecked = MutableStateFlow(false)
val recordTransactionDetailsChecked: StateFlow<Boolean> = _recordTransactionDetailsChecked

data class UiState(
val amountDue: BigDecimal = BigDecimal.ZERO,
val change: BigDecimal = BigDecimal.ZERO,
val amountReceived: BigDecimal = BigDecimal.ZERO,
val loading: Boolean = false,
val recordTransactionDetailsChecked: Boolean = false,
val canCompleteOrder: Boolean,
val currencySymbol: String,
)

private val _uiState = MutableStateFlow(UiState(loading = true))
private val _uiState = MutableStateFlow(
UiState(
loading = true,
currencySymbol = getCurrencySymbol(),
canCompleteOrder = false,
)
)
val uiState: StateFlow<UiState> = _uiState

init {
Expand All @@ -50,7 +57,9 @@ class ChangeDueCalculatorViewModel @Inject constructor(
_uiState.value = UiState(
amountDue = order.total,
change = BigDecimal.ZERO,
amountReceived = BigDecimal.ZERO
amountReceived = BigDecimal.ZERO,
canCompleteOrder = false,
currencySymbol = getCurrencySymbol(),
)
}
}
Expand All @@ -62,20 +71,19 @@ class ChangeDueCalculatorViewModel @Inject constructor(
fun updateAmountReceived(amount: BigDecimal) {
val currentState = _uiState.value
val newChange = amount - currentState.amountDue
_uiState.value = currentState.copy(amountReceived = amount, change = newChange)
}

private fun getCurrencySymbol(): String {
val siteParameters = parameterRepository.getParameters()
return siteParameters.currencySymbol.orEmpty()
_uiState.value = currentState.copy(
amountReceived = amount,
change = newChange,
canCompleteOrder = newChange >= BigDecimal.ZERO,
)
}

fun updateRecordTransactionDetailsChecked(checked: Boolean) {
_recordTransactionDetailsChecked.value = checked
_uiState.value = _uiState.value.copy(recordTransactionDetailsChecked = checked)
}

fun addOrderNoteIfChecked() {
if (recordTransactionDetailsChecked.value) {
fun onOrderComplete() {
if (_uiState.value.recordTransactionDetailsChecked) {
launch {
val noteStringTemplate = resourceProvider.getString(R.string.cash_payments_order_note_text)
val noteString = generateOrderNoteString(noteStringTemplate)
Expand Down Expand Up @@ -103,6 +111,11 @@ class ChangeDueCalculatorViewModel @Inject constructor(
}
}

private fun getCurrencySymbol(): String {
val siteParameters = parameterRepository.getParameters()
return siteParameters.currencySymbol.orEmpty()
}

private fun generateOrderNoteString(noteStringTemplate: String): String {
val state = _uiState.value
val currencySymbol = getCurrencySymbol()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import androidx.lifecycle.SavedStateHandle
import com.woocommerce.android.model.Order
import com.woocommerce.android.ui.orders.details.OrderDetailRepository
import com.woocommerce.android.ui.products.ParameterRepository
import com.woocommerce.android.ui.products.models.SiteParameters
import com.woocommerce.android.viewmodel.BaseUnitTest
import com.woocommerce.android.viewmodel.ResourceProvider
import kotlinx.coroutines.ExperimentalCoroutinesApi
Expand All @@ -27,7 +28,12 @@ class ChangeDueCalculatorViewModelTest : BaseUnitTest() {

private val orderDetailRepository: OrderDetailRepository = mock()

private val parameterRepository: ParameterRepository = mock()
private val parameters: SiteParameters = mock {
on { currencySymbol }.thenReturn("$")
}
private val parameterRepository: ParameterRepository = mock {
on { getParameters() }.thenReturn(parameters)
}

private val savedStateHandle: SavedStateHandle = SavedStateHandle(mapOf("orderId" to 1L))

Expand Down
Loading