Skip to content

Commit

Permalink
Merge pull request #13016 from woocommerce/13003-woo-pos-cash-receipt…
Browse files Browse the repository at this point in the history
…s-add-optional-receipt-button-and-empty-state-for-this

[Woo POS][Cash & Receipts] Add optional receipt button and receipt sending state mock UI
  • Loading branch information
kidinov authored Nov 29, 2024
2 parents 639a065 + 0ca85b5 commit 2ea0c82
Show file tree
Hide file tree
Showing 10 changed files with 320 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import com.woocommerce.android.ui.woopos.common.composeui.component.WooPosButton
import com.woocommerce.android.ui.woopos.common.composeui.component.WooPosErrorScreen
import com.woocommerce.android.ui.woopos.common.composeui.component.WooPosShimmerBox
import com.woocommerce.android.ui.woopos.common.composeui.toAdaptivePadding
import com.woocommerce.android.ui.woopos.home.totals.payment.receipt.WooPosTotalsPaymentReceiptScreen
import com.woocommerce.android.ui.woopos.home.totals.payment.success.WooPosPaymentSuccessScreen
import kotlinx.coroutines.delay

Expand All @@ -71,7 +72,11 @@ private fun WooPosTotalsScreen(

StateChangeAnimated(visible = state is WooPosTotalsViewState.PaymentSuccess) {
if (state is WooPosTotalsViewState.PaymentSuccess) {
WooPosPaymentSuccessScreen(state) { onUIEvent(WooPosTotalsUIEvent.OnNewTransactionClicked) }
WooPosPaymentSuccessScreen(
state,
onReceiptClicked = { onUIEvent(WooPosTotalsUIEvent.OnStartReceiptFlowClicked) },
onNewTransactionClicked = { onUIEvent(WooPosTotalsUIEvent.OnNewTransactionClicked) }
)
}
}

Expand All @@ -81,6 +86,16 @@ private fun WooPosTotalsScreen(
}
}

StateChangeAnimated(visible = state is WooPosTotalsViewState.ReceiptSending) {
if (state is WooPosTotalsViewState.ReceiptSending) {
WooPosTotalsPaymentReceiptScreen(
state,
onEmailAddressChanged = {},
onSendReceiptClicked = { onUIEvent(WooPosTotalsUIEvent.OnSendReceiptClicked) }
)
}
}

StateChangeAnimated(visible = state is WooPosTotalsViewState.Error) {
if (state is WooPosTotalsViewState.Error) {
TotalsErrorScreen(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,6 @@ sealed class WooPosTotalsUIEvent {
data object CollectPaymentClicked : WooPosTotalsUIEvent()
data object OnNewTransactionClicked : WooPosTotalsUIEvent()
data object RetryOrderCreationClicked : WooPosTotalsUIEvent()
data object OnStartReceiptFlowClicked : WooPosTotalsUIEvent()
data object OnSendReceiptClicked : WooPosTotalsUIEvent()
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import com.woocommerce.android.ui.woopos.home.ParentToChildrenEvent
import com.woocommerce.android.ui.woopos.home.WooPosChildrenToParentEventSender
import com.woocommerce.android.ui.woopos.home.WooPosParentToChildrenEventReceiver
import com.woocommerce.android.ui.woopos.home.items.WooPosItemsViewModel
import com.woocommerce.android.ui.woopos.home.totals.payment.receipt.WooPosIsReceiptSendingAvailable
import com.woocommerce.android.ui.woopos.util.WooPosNetworkStatus
import com.woocommerce.android.ui.woopos.util.analytics.WooPosAnalyticsEvent
import com.woocommerce.android.ui.woopos.util.analytics.WooPosAnalyticsTracker
Expand All @@ -38,6 +39,7 @@ class WooPosTotalsViewModel @Inject constructor(
private val priceFormat: WooPosFormatPrice,
private val analyticsTracker: WooPosAnalyticsTracker,
private val networkStatus: WooPosNetworkStatus,
private val isReceiptSendingAvailable: WooPosIsReceiptSendingAvailable,
savedState: SavedStateHandle,
) : ViewModel() {

Expand Down Expand Up @@ -79,6 +81,10 @@ class WooPosTotalsViewModel @Inject constructor(
is WooPosTotalsUIEvent.RetryOrderCreationClicked -> {
createOrderDraft(dataState.value.itemClickedDataList)
}
WooPosTotalsUIEvent.OnSendReceiptClicked -> TODO()
WooPosTotalsUIEvent.OnStartReceiptFlowClicked -> {
uiState.value = WooPosTotalsViewState.ReceiptSending(email = "")
}
}
}

Expand Down Expand Up @@ -121,7 +127,14 @@ class WooPosTotalsViewModel @Inject constructor(
is WooPosCardReaderPaymentStatus.Success -> {
val state = uiState.value
check(state is WooPosTotalsViewState.Totals)
uiState.value = WooPosTotalsViewState.PaymentSuccess(orderTotalText = state.orderTotalText)
val orderTotalText = resourceProvider.getString(
R.string.woopos_success_screen_total,
state.orderTotalText
)
uiState.value = WooPosTotalsViewState.PaymentSuccess(
orderTotalText = orderTotalText,
isReceiptAvailable = isReceiptSendingAvailable()
)
childrenToParentEventSender.sendToParent(ChildToParentEvent.OrderSuccessfullyPaid)
}
is WooPosCardReaderPaymentStatus.Failure,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,19 @@ sealed class WooPosTotalsViewState : Parcelable {
data object Loading : WooPosTotalsViewState()

data class Totals(
var orderSubtotalText: String,
var orderTaxText: String,
var orderTotalText: String,
val orderSubtotalText: String,
val orderTaxText: String,
val orderTotalText: String,
) : WooPosTotalsViewState()

data class PaymentSuccess(var orderTotalText: String) : WooPosTotalsViewState()
data class PaymentSuccess(
val orderTotalText: String,
val isReceiptAvailable: Boolean,
) : WooPosTotalsViewState()

data class ReceiptSending(
val email: String,
) : WooPosTotalsViewState()

data class Error(val message: String) : WooPosTotalsViewState()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.woocommerce.android.ui.woopos.home.totals.payment.receipt

import com.woocommerce.android.extensions.semverCompareTo
import com.woocommerce.android.ui.woopos.featureflags.WooPosIsReceiptsEnabled
import com.woocommerce.android.util.GetWooCorePluginCachedVersion
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import javax.inject.Inject

class WooPosIsReceiptSendingAvailable @Inject constructor(
private val isReceiptsEnabled: WooPosIsReceiptsEnabled,
private val getWooCoreVersion: GetWooCorePluginCachedVersion,
) {
suspend operator fun invoke() =
if (!isReceiptsEnabled()) {
false
} else {
isWooCoreSupportsSendingReceiptsByEmail()
}

private suspend fun isWooCoreSupportsSendingReceiptsByEmail() = withContext(Dispatchers.IO) {
val wooCoreVersion = getWooCoreVersion()
if (wooCoreVersion == null) {
false
} else {
wooCoreVersion.semverCompareTo(WC_VERSION_SUPPORTS_SENDING_RECEIPTS_BY_EMAIL) >= 0
}
}

private companion object {
const val WC_VERSION_SUPPORTS_SENDING_RECEIPTS_BY_EMAIL = "9.5.0"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package com.woocommerce.android.ui.woopos.home.totals.payment.receipt

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.width
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.material.TextField
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.constraintlayout.compose.ConstraintLayout
import com.woocommerce.android.ui.woopos.common.composeui.WooPosPreview
import com.woocommerce.android.ui.woopos.common.composeui.component.WooPosButton
import com.woocommerce.android.ui.woopos.home.totals.WooPosTotalsViewState

@Composable
fun WooPosTotalsPaymentReceiptScreen(
state: WooPosTotalsViewState.ReceiptSending,
onEmailAddressChanged: (String) -> Unit,
onSendReceiptClicked: () -> Unit,
) {
Box(
modifier = Modifier
.fillMaxSize(),
contentAlignment = Alignment.Center
) {
ConstraintLayout(
modifier = Modifier
.width(540.dp),
) {
val (title, email, button) = createRefs()

Text(
text = "Receipt",
style = MaterialTheme.typography.h2,
modifier = Modifier.constrainAs(title) {
top.linkTo(parent.top)
start.linkTo(parent.start)
}
)

TextField(
value = state.email,
onValueChange = onEmailAddressChanged,
label = { "email" },
modifier = Modifier.constrainAs(email) {
top.linkTo(title.bottom, margin = 16.dp)
start.linkTo(parent.start)
end.linkTo(parent.end)
}
)

WooPosButton(
text = "Send",
onClick = onSendReceiptClicked,
modifier = Modifier.constrainAs(button) {
top.linkTo(email.bottom, margin = 16.dp)
start.linkTo(parent.start)
end.linkTo(parent.end)
},
)
}
}
}

@WooPosPreview
@Composable
fun PreviewWooPosTotalsPaymentReceiptScreen() {
WooPosTotalsPaymentReceiptScreen(
state = WooPosTotalsViewState.ReceiptSending("email hint"),
onEmailAddressChanged = {},
onSendReceiptClicked = {},
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import kotlinx.coroutines.delay
@Composable
fun WooPosPaymentSuccessScreen(
state: WooPosTotalsViewState.PaymentSuccess,
onReceiptClicked: () -> Unit,
onNewTransactionClicked: () -> Unit,
) {
var bottomAnimationStarted by remember { mutableStateOf(false) }
Expand All @@ -56,6 +57,7 @@ fun WooPosPaymentSuccessScreen(
state = state,
iconAnimationStarted = iconAnimationStarted,
bottomAnimationStarted = bottomAnimationStarted,
onReceiptClicked = onReceiptClicked,
onNewTransactionClicked = onNewTransactionClicked,
)
}
Expand All @@ -65,6 +67,7 @@ fun WooPosPaymentSuccessScreen(
state: WooPosTotalsViewState.PaymentSuccess,
iconAnimationStarted: Boolean,
bottomAnimationStarted: Boolean,
onReceiptClicked: () -> Unit,
onNewTransactionClicked: () -> Unit,
) {
Box(
Expand All @@ -79,7 +82,7 @@ fun WooPosPaymentSuccessScreen(
)
@Suppress("DestructuringDeclarationWithTooManyEntries")
ConstraintLayout {
val (icon, title, message, button) = createRefs()
val (icon, title, message, buttonReceipt, buttonNewOrder) = createRefs()

val checkMarkIconMargin = 56.dp.toAdaptivePadding()
CheckMarkIcon(
Expand All @@ -106,22 +109,39 @@ fun WooPosPaymentSuccessScreen(
)

val marginBetweenButtonAndTextAdaptive = marginBetweenButtonAndText.toAdaptivePadding()
val textLinkTo = if (state.isReceiptAvailable) buttonReceipt else buttonNewOrder
Text(
text = stringResource(R.string.woopos_success_screen_total, state.orderTotalText),
text = state.orderTotalText,
style = MaterialTheme.typography.h6,
textAlign = TextAlign.Center,
fontWeight = FontWeight.Normal,
color = MaterialTheme.colors.onSurface,
modifier = Modifier.constrainAs(message) {
start.linkTo(parent.start)
end.linkTo(parent.end)
bottom.linkTo(button.top, margin = marginBetweenButtonAndTextAdaptive)
bottom.linkTo(textLinkTo.top, margin = marginBetweenButtonAndTextAdaptive)
}
)

val marginBetweenButtons = 16.dp.toAdaptivePadding()
if (state.isReceiptAvailable) {
WooPosButton(
modifier = Modifier
.constrainAs(buttonReceipt) {
bottom.linkTo(buttonNewOrder.top, margin = marginBetweenButtons)
start.linkTo(parent.start)
end.linkTo(parent.end)
}
.height(80.dp)
.width(604.dp),
onClick = onReceiptClicked,
text = stringResource(R.string.woopos_receipt_button),
)
}

WooPosButton(
modifier = Modifier
.constrainAs(button) {
.constrainAs(buttonNewOrder) {
bottom.linkTo(parent.bottom)
start.linkTo(parent.start)
end.linkTo(parent.end)
Expand Down Expand Up @@ -183,9 +203,30 @@ private fun CheckMarkIcon(
fun WooPosPaymentSuccessScreenPreview() {
WooPosTheme {
WooPosPaymentSuccessScreen(
state = WooPosTotalsViewState.PaymentSuccess(orderTotalText = "$13.18"),
state = WooPosTotalsViewState.PaymentSuccess(
orderTotalText = "A payment of 13.18 was successfully made",
isReceiptAvailable = true,
),
bottomAnimationStarted = true,
iconAnimationStarted = true,
onReceiptClicked = {},
onNewTransactionClicked = {}
)
}
}

@WooPosPreview
@Composable
fun WooPosPaymentSuccessWithoutReceiptScreenPreview() {
WooPosTheme {
WooPosPaymentSuccessScreen(
state = WooPosTotalsViewState.PaymentSuccess(
orderTotalText = "A payment of 13.18 was successfully made",
isReceiptAvailable = false,
),
bottomAnimationStarted = true,
iconAnimationStarted = true,
onReceiptClicked = {},
onNewTransactionClicked = {}
)
}
Expand Down
1 change: 1 addition & 0 deletions WooCommerce/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4281,6 +4281,7 @@
<string name="woopos_payment_successful_label">Payment successful</string>
<string name="woopos_payment_successful_checkmark_icon_content_description">Payment successful checkmark icon</string>
<string name="woopos_new_order_button">New order</string>
<string name="woopos_receipt_button">Receipt</string>
<string name="woopos_payment_subtotal_label">Subtotal</string>
<string name="woopos_payment_tax_label">Taxes</string>
<string name="woopos_payment_total_label">Total</string>
Expand Down
Loading

0 comments on commit 2ea0c82

Please sign in to comment.