Skip to content
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

[Order creation] Update coupons display order details #12855

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions RELEASE-NOTES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
-----
- [*] Fixed text formatting in the "Collect Payment has moved" rationale bottom sheet [https://github.com/woocommerce/woocommerce-android/pull/12815]
- [*] Added support for loading Product images using the AVIF format [https://github.com/woocommerce/woocommerce-android/pull/12835]
- [*] Updated Coupons UI in the order creation [https://github.com/woocommerce/woocommerce-android/pull/12855]

20.9
-----
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ import com.woocommerce.android.ui.orders.creation.OrderCreateEditViewModel.Mode.
import com.woocommerce.android.ui.orders.creation.OrderCreateEditViewModel.Mode.Edit
import com.woocommerce.android.ui.orders.creation.configuration.EditProductConfigurationResult
import com.woocommerce.android.ui.orders.creation.configuration.ProductConfigurationFragment
import com.woocommerce.android.ui.orders.creation.coupon.CouponLineFormSection
import com.woocommerce.android.ui.orders.creation.coupon.edit.OrderCreateCouponDetailsViewModel
import com.woocommerce.android.ui.orders.creation.coupon.edit.OrderCreateCouponEditFragment.Companion.KEY_COUPON_EDIT_RESULT
import com.woocommerce.android.ui.orders.creation.customerlist.OrderCustomerListFragment
Expand Down Expand Up @@ -167,7 +168,7 @@ class OrderCreateEditFormFragment :
handleCouponEditResult()
handleProductDetailsEditResult()
handleResult<String>(KEY_COUPON_SELECTOR_RESULT) {
viewModel.onCouponAdded(it)
viewModel.addCoupon(it)
}
handleTaxRateSelectionResult()
viewModel.onDeviceConfigurationChanged(requireContext().windowSizeClass)
Expand Down Expand Up @@ -377,7 +378,7 @@ class OrderCreateEditFormFragment :

private fun FragmentOrderCreateEditFormBinding.initAdditionalInfoCollectionSection() {
additionalInfoCollectionSection.addShippingButton.setOnClickListener {
viewModel.onAddOrEditShipping()
viewModel.onAddOrEditShippingClicked()
}
}

Expand Down Expand Up @@ -410,6 +411,8 @@ class OrderCreateEditFormFragment :

bindShippingLinesSection(binding)

bindCouponsLinesSection(binding)

bindFeedbackSection(binding)

observeViewStateChanges(binding)
Expand All @@ -426,8 +429,27 @@ class OrderCreateEditFormFragment :
shippingLineDetails = shippingLines,
formatCurrency = { amount -> currencyFormatter.formatCurrency(amount) },
modifier = Modifier.padding(bottom = 1.dp),
onAdd = { viewModel.onAddOrEditShipping() },
onEdit = { id -> viewModel.onAddOrEditShipping(id) }
onAddClicked = { viewModel.onAddOrEditShippingClicked() },
onEditClicked = { id -> viewModel.onAddOrEditShippingClicked(id) }
)
}
}
}
}
}

private fun bindCouponsLinesSection(binding: FragmentOrderCreateEditFormBinding) {
binding.couponLines.apply {
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
setContent {
viewModel.couponLinesLiveData.observeAsState().value?.let { couponSection ->
WooThemeWithBackground {
CouponLineFormSection(
couponLineDetails = couponSection.couponLines,
isEnabled = couponSection.isEnabled,
modifier = Modifier.padding(bottom = 1.dp),
onAddClicked = { viewModel.onAddCouponButtonClicked() },
onRemoveClicked = { code -> viewModel.removeCoupon(code) }
)
}
}
Expand Down Expand Up @@ -738,6 +760,22 @@ class OrderCreateEditFormFragment :
} else {
additionalInfoCollectionSection.addShippingButtonGroup.show()
}

Copy link
Contributor Author

@malinajirka malinajirka Nov 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code would ideally live in the VM so it could be unit tested, however, refactoring it felt like out of scope and bringing inconsistency to the surrounding code feels worse than not having this tested. I'm open to suggestions though.

if (newOrderData.couponLines.isNotEmpty()) {
additionalInfoCollectionSection.addCouponButtonGroup.hide()
} else {
additionalInfoCollectionSection.addCouponButtonGroup.show()
}

// Hide the whole section when all children are invisible
if (!additionalInfoCollectionSection.addGiftCardButtonGroup.isVisible &&
!additionalInfoCollectionSection.addCouponButtonGroup.isVisible &&
!additionalInfoCollectionSection.addShippingButtonGroup.isVisible
) {
additionalInfoCollectionSection.root.isVisible = false
} else {
additionalInfoCollectionSection.root.isVisible = true
}
}

private fun OrderCreationAdditionalInfoCollectionSectionBinding.bindGiftCardSubSection(newOrderData: Order) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.asFlow
import androidx.lifecycle.asLiveData
import androidx.lifecycle.distinctUntilChanged
import androidx.lifecycle.viewModelScope
import com.woocommerce.android.AppPrefs
import com.woocommerce.android.R.string
Expand Down Expand Up @@ -98,6 +99,8 @@ import com.woocommerce.android.ui.orders.creation.CreateUpdateOrder.OrderUpdateS
import com.woocommerce.android.ui.orders.creation.GoogleBarcodeFormatMapper.BarcodeFormat
import com.woocommerce.android.ui.orders.creation.configuration.ConfigurationType
import com.woocommerce.android.ui.orders.creation.configuration.ProductConfiguration
import com.woocommerce.android.ui.orders.creation.coupon.CouponLineDetails
import com.woocommerce.android.ui.orders.creation.coupon.CouponSection
import com.woocommerce.android.ui.orders.creation.coupon.edit.OrderCreateCouponDetailsViewModel
import com.woocommerce.android.ui.orders.creation.navigation.OrderCreateEditNavigationTarget
import com.woocommerce.android.ui.orders.creation.navigation.OrderCreateEditNavigationTarget.AddCustomer
Expand Down Expand Up @@ -295,7 +298,6 @@ class OrderCreateEditViewModel @Inject constructor(
),
mode = mode,
viewState = viewState!!,
onCouponsClicked = { onCouponButtonClicked() },
onGiftClicked = { onEditGiftCardButtonClicked(selectedGiftCard) },
onTaxesLearnMore = { onTaxHelpButtonClicked() },
onMainButtonClicked = { onTotalsSectionPrimaryButtonClicked() },
Expand Down Expand Up @@ -403,10 +405,24 @@ class OrderCreateEditViewModel @Inject constructor(
}
}.asLiveData()

private val _couponLinesLiveData = MediatorLiveData(CouponSection(emptyList(), true))
samiuelson marked this conversation as resolved.
Show resolved Hide resolved
val couponLinesLiveData = _couponLinesLiveData.distinctUntilChanged()
samiuelson marked this conversation as resolved.
Show resolved Hide resolved

init {
monitorPluginAvailabilityChanges()
shouldDisplayShippingFeedback()

_couponLinesLiveData.addSource(orderDraft) { newOrderDraft ->
_couponLinesLiveData.value =
_couponLinesLiveData.value
?.copy(couponLines = newOrderDraft.couponLines.map { CouponLineDetails(it.code) })
}

_couponLinesLiveData.addSource(viewStateData.liveData) { newViewState ->
_couponLinesLiveData.value = _couponLinesLiveData.value
?.copy(isEnabled = newViewState.isIdle && viewState.isEditable)
}

when (mode) {
is Mode.Creation -> {
_orderDraft.update {
Expand Down Expand Up @@ -556,7 +572,7 @@ class OrderCreateEditViewModel @Inject constructor(
private fun handleCouponEditResult(couponEditResult: OrderCreateCouponDetailsViewModel.CouponEditResult) {
when (couponEditResult) {
is OrderCreateCouponDetailsViewModel.CouponEditResult.RemoveCoupon -> {
onCouponRemoved(couponEditResult.couponCode)
removeCoupon(couponEditResult.couponCode)
}
}
}
Expand Down Expand Up @@ -1253,7 +1269,7 @@ class OrderCreateEditViewModel @Inject constructor(
_selectedGiftCard.update { selectedGiftCard }
}

fun onAddOrEditShipping(itemId: Long? = null) {
fun onAddOrEditShippingClicked(itemId: Long? = null) {
tracker.track(AnalyticsEvent.ORDER_ADD_SHIPPING_TAPPED)
val shippingLine = itemId?.let { id -> currentDraft.shippingLines.firstOrNull { it.itemId == id } }
triggerEvent(EditShipping(shippingLine))
Expand Down Expand Up @@ -1793,7 +1809,7 @@ class OrderCreateEditViewModel @Inject constructor(
}
}

fun onCouponAdded(couponCode: String) {
fun addCoupon(couponCode: String) {
if (_orderDraft.value.couponLines.any { it.code == couponCode }) return
_orderDraft.update { draft ->
val couponLines = draft.couponLines
Expand All @@ -1803,7 +1819,7 @@ class OrderCreateEditViewModel @Inject constructor(
}
}

private fun onCouponRemoved(couponCode: String) {
fun removeCoupon(couponCode: String) {
trackCouponRemoved()
_orderDraft.update { draft ->
val updatedCouponLines = draft.couponLines.filter { it.code != couponCode }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.woocommerce.android.ui.orders.creation.coupon

data class CouponLineDetails(
val code: String
)

data class CouponSection(
val couponLines: List<CouponLineDetails>,
val isEnabled: Boolean,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
package com.woocommerce.android.ui.orders.creation.coupon

import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Card
import androidx.compose.material.Icon
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Add
import androidx.compose.material.icons.outlined.DeleteOutline
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.graphics.RectangleShape
import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.woocommerce.android.R
import com.woocommerce.android.ui.compose.theme.WooThemeWithBackground

@Composable
fun CouponLineFormSection(
couponLineDetails: List<CouponLineDetails>,
isEnabled: Boolean,
onAddClicked: () -> Unit,
onRemoveClicked: (code: String) -> Unit,
modifier: Modifier = Modifier
) {
AnimatedVisibility(couponLineDetails.isNotEmpty()) {
Card(shape = RectangleShape, modifier = modifier) {
Column(modifier = Modifier.padding(16.dp)) {
Row(modifier = Modifier.padding(bottom = 16.dp)) {
Text(
text = stringResource(id = R.string.coupons),
style = MaterialTheme.typography.h6,
modifier = modifier
.weight(2f, true)
.align(Alignment.CenterVertically),
)
Icon(
imageVector = Icons.Default.Add,
contentDescription = stringResource(id = R.string.order_creation_add_coupon),
modifier = Modifier
.align(Alignment.CenterVertically)
.alpha(if (isEnabled) 1f else 0.4f)
.clickable(enabled = isEnabled) { onAddClicked() },
tint = MaterialTheme.colors.primary
)
}

samiuelson marked this conversation as resolved.
Show resolved Hide resolved
couponLineDetails.forEachIndexed { i, couponDetails ->
val itemModifier = if (i == 0) Modifier else Modifier.padding(top = 8.dp)
CouponLineEditCard(
couponLine = couponDetails,
modifier = itemModifier
.alpha(if (isEnabled) 1f else 0.4f)
.clickable(enabled = isEnabled) { onRemoveClicked(couponDetails.code) }
)
}
}
}
}
}

@Composable
fun CouponLineEditCard(
couponLine: CouponLineDetails,
modifier: Modifier = Modifier
) {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = modifier
.fillMaxWidth()
.border(
brush = SolidColor(MaterialTheme.colors.onSurface.copy(alpha = 0.12f)),
width = 1.dp,
shape = RoundedCornerShape(dimensionResource(id = R.dimen.corner_radius_large))
)
.padding(dimensionResource(id = R.dimen.major_100))
) {
Text(
modifier = Modifier.weight(1f),
text = couponLine.code,
style = TextStyle(
fontWeight = FontWeight.Normal,
fontSize = 18.sp
),
color = colorResource(id = R.color.color_on_surface),
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
Icon(
imageVector = Icons.Outlined.DeleteOutline,
contentDescription = stringResource(id = R.string.order_creation_remove_coupon),
modifier = Modifier
.align(Alignment.CenterVertically)
.padding(start = 16.dp)
)
}
}

@PreviewLightDark
@Composable
fun CouponLineDetailsPreview() {
WooThemeWithBackground {
CouponLineDetails(
code = "abcdefg",
)
}
}

@PreviewLightDark
@Composable
fun CouponLineFormSectionPreview() {
val couponLine = List(3) { i ->
CouponLineDetails(
code = "abcdefg_abcdefg_abcdefg_abcdefg_$i",
)
}
WooThemeWithBackground {
CouponLineFormSection(
couponLineDetails = couponLine,
isEnabled = true,
onAddClicked = { },
onRemoveClicked = { }
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ import java.math.BigDecimal
@Composable
fun ShippingLineFormSection(
shippingLineDetails: List<ShippingLineDetails>,
onAdd: () -> Unit,
onEdit: (id: Long) -> Unit,
onAddClicked: () -> Unit,
onEditClicked: (id: Long) -> Unit,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❤️

formatCurrency: (amount: BigDecimal) -> String,
modifier: Modifier = Modifier
) {
Expand All @@ -66,7 +66,7 @@ fun ShippingLineFormSection(
.clickable(
interactionSource = remember { MutableInteractionSource() },
indication = null
) { onAdd() },
) { onAddClicked() },
tint = MaterialTheme.colors.primary
)
}
Expand All @@ -75,7 +75,7 @@ fun ShippingLineFormSection(
val itemModifier = if (i == 0) Modifier else Modifier.padding(top = 8.dp)
ShippingLineEditCard(
shippingLine = shippingDetails,
onEdit = onEdit,
onEdit = onEditClicked,
formatCurrency = formatCurrency,
modifier = itemModifier
)
Expand Down Expand Up @@ -182,8 +182,8 @@ fun ShippingLineFormSectionPreview() {
ShippingLineFormSection(
shippingLineDetails = shippingDetails,
formatCurrency = { it.toString() },
onAdd = { },
onEdit = { }
onAddClicked = { },
onEditClicked = { }
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -506,12 +506,9 @@ private fun OrderCreateEditTotalsFullViewPreview() {
enabled = true,
onClick = {},
),
TotalsSectionsState.Line.Button(
text = stringResource(R.string.order_creation_coupon_button),
value = "-$4.25",
extraValue = "20 OFF",
enabled = false,
onClick = {},
TotalsSectionsState.Line.Simple(
label = stringResource(R.string.order_creation_coupons_title),
value = "-$4.25"
),
TotalsSectionsState.Line.Button(
text = stringResource(R.string.order_gift_card),
Expand Down
Loading
Loading