diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/methodselection/ChangeDueCalculatorFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/methodselection/ChangeDueCalculatorFragment.kt new file mode 100644 index 00000000000..832ccaa33e6 --- /dev/null +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/methodselection/ChangeDueCalculatorFragment.kt @@ -0,0 +1,71 @@ +package com.woocommerce.android.ui.payments.methodselection + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.ComposeView +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import androidx.fragment.app.DialogFragment +import androidx.fragment.app.viewModels +import com.woocommerce.android.R +import dagger.hilt.android.AndroidEntryPoint + +@AndroidEntryPoint +class ChangeDueCalculatorFragment : DialogFragment() { + + private val viewModel: ChangeDueCalculatorViewModel by viewModels() + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { + return ComposeView(requireContext()).apply { + setContent { + ChangeDueCalculatorScreen() + } + } + } + + @Composable + fun ChangeDueCalculatorScreen() { + val uiState by viewModel.uiState.collectAsState() + + Column( + modifier = Modifier + .fillMaxSize() + .padding(16.dp), + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally + ) { + // Display dynamic content based on UI state + when (uiState) { + is ChangeDueCalculatorViewModel.UiState.Loading -> { + Text(text = stringResource(R.string.loading), style = MaterialTheme.typography.h5) + } + + is ChangeDueCalculatorViewModel.UiState.Success -> { + val state = uiState as ChangeDueCalculatorViewModel.UiState.Success + Text( + text = stringResource(R.string.cash_payments_take_payment_title, state.amountDue), + style = MaterialTheme.typography.h5, + modifier = Modifier.padding(bottom = 16.dp) + ) + } + + is ChangeDueCalculatorViewModel.UiState.Error -> { + Text(text = stringResource(R.string.error_generic), style = MaterialTheme.typography.h5) + } + } + } + } +} diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/methodselection/ChangeDueCalculatorViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/methodselection/ChangeDueCalculatorViewModel.kt new file mode 100644 index 00000000000..bf441e9620d --- /dev/null +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/methodselection/ChangeDueCalculatorViewModel.kt @@ -0,0 +1,41 @@ +package com.woocommerce.android.ui.payments.methodselection + +import androidx.lifecycle.SavedStateHandle +import com.woocommerce.android.ui.orders.details.OrderDetailRepository +import com.woocommerce.android.viewmodel.ScopedViewModel +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.launch +import java.math.BigDecimal +import javax.inject.Inject + +@HiltViewModel +class ChangeDueCalculatorViewModel @Inject constructor( + savedStateHandle: SavedStateHandle, + private val orderDetailRepository: OrderDetailRepository +) : ScopedViewModel(savedStateHandle) { + + private val orderId: Long = savedStateHandle.get("orderId") + ?: throw IllegalArgumentException("OrderId is required") + + sealed class UiState { + data object Loading : UiState() + data class Success(val amountDue: BigDecimal, val change: BigDecimal) : UiState() + data object Error : UiState() + } + + private val _uiState = MutableStateFlow(UiState.Loading) + val uiState: StateFlow = _uiState + + init { + loadOrderDetails() + } + + private fun loadOrderDetails() { + launch { + val order = orderDetailRepository.getOrderById(orderId)!! + _uiState.value = UiState.Success(amountDue = order.total, 0.00.toBigDecimal()) + } + } +} diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/methodselection/SelectPaymentMethodEvent.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/methodselection/SelectPaymentMethodEvent.kt index 408647b13bc..a984704284b 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/methodselection/SelectPaymentMethodEvent.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/methodselection/SelectPaymentMethodEvent.kt @@ -44,4 +44,8 @@ data class NavigateBackToOrderList( val order: Order ) : MultiLiveEvent.Event() +data class NavigateToChangeDueCalculatorScreen( + val order: Order +) : MultiLiveEvent.Event() + data class OpenGenericWebView(val url: String) : MultiLiveEvent.Event() diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/methodselection/SelectPaymentMethodFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/methodselection/SelectPaymentMethodFragment.kt index f312bafeb5b..e96bdf9fa1e 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/methodselection/SelectPaymentMethodFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/methodselection/SelectPaymentMethodFragment.kt @@ -254,6 +254,15 @@ class SelectPaymentMethodFragment : BaseFragment(R.layout.fragment_select_paymen findNavController().navigateSafely(action) } + is NavigateToChangeDueCalculatorScreen -> { + val action = + SelectPaymentMethodFragmentDirections + .actionSelectPaymentMethodFragmentToChangeDueCalculatorFragment( + orderId = event.order.id + ) + findNavController().navigate(action) + } + is NavigateToTapToPaySummary -> { findNavController().navigateSafely( SelectPaymentMethodFragmentDirections diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/methodselection/SelectPaymentMethodViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/methodselection/SelectPaymentMethodViewModel.kt index 8b621230e5f..4d6f34851e0 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/methodselection/SelectPaymentMethodViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/payments/methodselection/SelectPaymentMethodViewModel.kt @@ -39,6 +39,7 @@ import com.woocommerce.android.ui.payments.tracking.CardReaderTrackingInfoKeeper import com.woocommerce.android.ui.payments.tracking.PaymentsFlowTracker import com.woocommerce.android.util.CoroutineDispatchers import com.woocommerce.android.util.CurrencyFormatter +import com.woocommerce.android.util.FeatureFlag import com.woocommerce.android.viewmodel.MultiLiveEvent import com.woocommerce.android.viewmodel.ScopedViewModel import com.woocommerce.android.viewmodel.navArgs @@ -229,23 +230,34 @@ class SelectPaymentMethodViewModel @Inject constructor( } fun onCashPaymentClicked() { + if (FeatureFlag.OTHER_PAYMENT_METHODS.isEnabled()) { + handleCashPaymentClick() + } else { + launch { + trackPaymentMethodSelection(VALUE_SIMPLE_PAYMENTS_COLLECT_CASH) + val messageIdForPaymentType = when (cardReaderPaymentFlowParam.paymentType) { + SIMPLE, TRY_TAP_TO_PAY -> R.string.simple_payments_cash_dlg_message + ORDER, ORDER_CREATION -> R.string.existing_order_cash_dlg_message + } + triggerEvent( + MultiLiveEvent.Event.ShowDialog( + titleId = R.string.simple_payments_cash_dlg_title, + messageId = messageIdForPaymentType, + positiveButtonId = R.string.simple_payments_cash_dlg_button, + positiveBtnAction = { _, _ -> + onCashPaymentConfirmed() + }, + negativeButtonId = R.string.cancel + ) + ) + } + } + } + + private fun handleCashPaymentClick() { launch { trackPaymentMethodSelection(VALUE_SIMPLE_PAYMENTS_COLLECT_CASH) - val messageIdForPaymentType = when (cardReaderPaymentFlowParam.paymentType) { - SIMPLE, TRY_TAP_TO_PAY -> R.string.simple_payments_cash_dlg_message - ORDER, ORDER_CREATION -> R.string.existing_order_cash_dlg_message - } - triggerEvent( - MultiLiveEvent.Event.ShowDialog( - titleId = R.string.simple_payments_cash_dlg_title, - messageId = messageIdForPaymentType, - positiveButtonId = R.string.simple_payments_cash_dlg_button, - positiveBtnAction = { _, _ -> - onCashPaymentConfirmed() - }, - negativeButtonId = R.string.cancel - ) - ) + triggerEvent(NavigateToChangeDueCalculatorScreen(order.first())) } } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/util/FeatureFlag.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/util/FeatureFlag.kt index 8a6db970eff..98c02ae855c 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/util/FeatureFlag.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/util/FeatureFlag.kt @@ -27,7 +27,8 @@ enum class FeatureFlag { PackageUtils.isDebugBuild() || context != null && PackageUtils.isBetaBuild(context) } - OTHER_PAYMENT_METHODS, + OTHER_PAYMENT_METHODS -> false + MORE_MENU_INBOX, WOO_POS, WC_SHIPPING_BANNER, diff --git a/WooCommerce/src/main/res/navigation/nav_graph_payment_flow.xml b/WooCommerce/src/main/res/navigation/nav_graph_payment_flow.xml index 0771d23890b..cf8451a4b69 100644 --- a/WooCommerce/src/main/res/navigation/nav_graph_payment_flow.xml +++ b/WooCommerce/src/main/res/navigation/nav_graph_payment_flow.xml @@ -46,6 +46,13 @@ android:name="orderId" app:argType="long" /> + + + + + + Share Payment Link Checkout - %s + + Take payment (%s) + diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/methodselection/ChangeDueCalculatorViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/methodselection/ChangeDueCalculatorViewModelTest.kt new file mode 100644 index 00000000000..9f0fca75621 --- /dev/null +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/methodselection/ChangeDueCalculatorViewModelTest.kt @@ -0,0 +1,33 @@ +package com.woocommerce.android.ui.payments.methodselection + +import com.woocommerce.android.viewmodel.BaseUnitTest +import kotlinx.coroutines.ExperimentalCoroutinesApi +import org.junit.Test + +@ExperimentalCoroutinesApi +class ChangeDueCalculatorViewModelTest : BaseUnitTest() { + @Test + fun `given valid order id, when order details are requested, then success state is emitted`() = testBlocking { + // GIVEN + // TODO val viewModel: ChangeDueCalculatorViewModel = mock() + // TODO + + // WHEN + // TODO + + // THEN + // TODO + } + + @Test + fun `given order details retrieval failure, when order details are loaded, then error state is emitted`() = testBlocking { + // GIVEN + // TODO val viewModel: ChangeDueCalculatorViewModel = mock() + + // WHEN + // TODO + + // THEN + // TODO assertThat(viewModel.uiState.value).isEqualTo(ChangeDueCalculatorViewModel.UiState.Error) + } +}