Skip to content

Commit

Permalink
Merge pull request #13652 from woocommerce/issue/connect-customs-form…
Browse files Browse the repository at this point in the history
…-with-creation-form

[Shipping Labels Revamp] Connect customs form with creation form
  • Loading branch information
atorresveiga authored Mar 5, 2025
2 parents 9b23bcf + 467f903 commit a64d1fc
Show file tree
Hide file tree
Showing 12 changed files with 177 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import com.woocommerce.android.ui.orders.wooshippinglabels.WooShippingLabelCreat
import com.woocommerce.android.ui.orders.wooshippinglabels.WooShippingLabelCreationViewModel.StartPackageSelection
import com.woocommerce.android.ui.orders.wooshippinglabels.address.EditAddressFlow
import com.woocommerce.android.ui.orders.wooshippinglabels.address.WooShippingEditAddressFragment.Companion.DESTINATION_ADDRESS_UPDATE_RESULT
import com.woocommerce.android.ui.orders.wooshippinglabels.customs.CustomsData
import com.woocommerce.android.ui.orders.wooshippinglabels.customs.WooShippingCustomsFormFragment.Companion.CUSTOMS_DATA_RESULT
import com.woocommerce.android.ui.orders.wooshippinglabels.models.DestinationShippingAddress
import com.woocommerce.android.ui.orders.wooshippinglabels.packages.WooShippingLabelPackageCreationFragment.Companion.PACKAGE_SELECTION_RESULT
import com.woocommerce.android.ui.orders.wooshippinglabels.packages.ui.PackageData
Expand Down Expand Up @@ -88,7 +90,8 @@ class WooShippingLabelCreationFragment : BaseFragment(), BackPressListener {
is StartCustomsFormEdit -> {
WooShippingLabelCreationFragmentDirections
.actionWooShippingLabelCreationFragmentToWooShippingLabelCustomsFormFragment(
shippableItems = event.shippableItems.toTypedArray()
shippableItems = event.shippableItems.toTypedArray(),
customsData = event.customData
).let { findNavController().navigateSafely(it) }
}
is MultiLiveEvent.Event.ShowSnackbar -> uiMessageResolver.showSnack(event.message)
Expand All @@ -104,6 +107,10 @@ class WooShippingLabelCreationFragment : BaseFragment(), BackPressListener {
handleResult<DestinationShippingAddress>(DESTINATION_ADDRESS_UPDATE_RESULT) {
viewModel.onUpdateDestinationAddress(it)
}

handleResult<CustomsData>(CUSTOMS_DATA_RESULT) {
viewModel.onCustomsDataAvailable(it)
}
}

override fun onRequestAllowBackPress(): Boolean = viewModel.allowBackNavigation()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,18 @@ private fun CustomsCard(
onEditCustomsClick: () -> Unit,
modifier: Modifier = Modifier
) {
val (backgroundColor, labelText) = if (customsState is Unavailable) {
Pair(
colorResource(id = R.color.woo_red_20),
stringResource(id = R.string.shipping_labels_customs_missing_info_badge)
)
} else {
Pair(
colorResource(id = R.color.woo_green_20),
stringResource(id = R.string.shipping_labels_customs_completed_badge)
)
}

if (customsState !is NotRequired) {
Row(
modifier = modifier
Expand Down Expand Up @@ -462,13 +474,13 @@ private fun CustomsCard(
Box(
modifier = Modifier
.background(
color = colorResource(id = R.color.woo_red_20),
color = backgroundColor,
shape = RoundedCornerShape(dimensionResource(R.dimen.corner_radius_medium))
)
.align(Alignment.CenterVertically)
) {
Text(
text = stringResource(id = R.string.shipping_labels_customs_missing_info_badge),
text = labelText,
style = MaterialTheme.typography.caption,
color = MaterialTheme.colors.onSurface,
modifier = Modifier
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.runtime.snapshotFlow
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.viewModelScope
import com.woocommerce.android.R
import com.woocommerce.android.extensions.combine
import com.woocommerce.android.extensions.formatToString
Expand All @@ -21,6 +22,7 @@ import com.woocommerce.android.ui.orders.wooshippinglabels.address.AddressStatus
import com.woocommerce.android.ui.orders.wooshippinglabels.address.destination.VerifyDestinationAddress
import com.woocommerce.android.ui.orders.wooshippinglabels.address.origin.FetchOriginAddresses
import com.woocommerce.android.ui.orders.wooshippinglabels.address.origin.ObserveOriginAddresses
import com.woocommerce.android.ui.orders.wooshippinglabels.customs.CustomsData
import com.woocommerce.android.ui.orders.wooshippinglabels.customs.ShouldRequireCustomsForm
import com.woocommerce.android.ui.orders.wooshippinglabels.models.DestinationShippingAddress
import com.woocommerce.android.ui.orders.wooshippinglabels.models.OriginShippingAddress
Expand All @@ -46,6 +48,10 @@ import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.flow.drop
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.joinAll
Expand Down Expand Up @@ -81,6 +87,7 @@ class WooShippingLabelCreationViewModel @Inject constructor(
private val shippableItems = MutableStateFlow<List<ShippableItemModel>>(emptyList())

private val packageSelected = MutableStateFlow<PackageData?>(null)
private val customsFormData = MutableStateFlow<CustomsData?>(null)
private val packageWeight = MutableStateFlow<PackageWeight?>(null)
private val packageSelection = MutableStateFlow<PackageSelectionState>(NotSelected)
private val customsState = MutableStateFlow<CustomsState>(NotRequired)
Expand Down Expand Up @@ -255,13 +262,33 @@ class WooShippingLabelCreationViewModel @Inject constructor(
private suspend fun observeCustomsDataChanges() {
combine(
shippingAddresses,
customsFormData,
customsState
) { addresses, _ ->
) { addresses, customsData, _ ->
when {
customsData != null -> CustomsState.DataAvailable(customsData)
addresses != null && shouldRequireCustoms(addresses) -> Unavailable
else -> NotRequired
}
}.collectLatest { customsState.value = it }
}.onEach {
customsState.value = it
}.launchIn(viewModelScope)

combine(
packageSelected.filterNotNull(),
customsState.filter { it is CustomsState.DataAvailable }
) { packageSelected, customState ->
val customData = customState
.run { this as? CustomsState.DataAvailable }
?.customsData?.copy(
packageId = packageSelected.id,
packageName = packageSelected.name
)

packageSelected.copy(customsData = customData)
}.onEach {
packageSelected.value = it
}.launchIn(viewModelScope)
}

private suspend fun getShippingAddresses() {
Expand Down Expand Up @@ -517,12 +544,17 @@ class WooShippingLabelCreationViewModel @Inject constructor(
packageSelected.value = packageData
}

fun onCustomsDataAvailable(customsData: CustomsData) {
customsFormData.value = customsData
}

fun onCustomWeightChange(input: String) {
customWeight = input
}

fun onEditCustomsClick() {
triggerEvent(StartCustomsFormEdit(shippableItems.value))
val event = StartCustomsFormEdit(shippableItems.value, customsFormData.value)
triggerEvent(event)
}

fun allowBackNavigation(): Boolean {
Expand Down Expand Up @@ -568,11 +600,14 @@ class WooShippingLabelCreationViewModel @Inject constructor(
data object StartPackageSelection : Event()
data class LabelPurchased(val purchaseData: PurchasedShippingLabelData) : Event()
data class StartOriginAddressEdit(val originAddress: OriginShippingAddress) : Event()
data class StartCustomsFormEdit(val shippableItems: List<ShippableItemModel>) : Event()
data class StartDestinationAddressEdit(
val destinationAddress: DestinationShippingAddress,
val orderId: Long
) : Event()
data class StartCustomsFormEdit(
val shippableItems: List<ShippableItemModel>,
val customData: CustomsData?
) : Event()

sealed class WooShippingViewState {
data object Error : WooShippingViewState()
Expand Down Expand Up @@ -651,6 +686,7 @@ class WooShippingLabelCreationViewModel @Inject constructor(
sealed class CustomsState {
data object NotRequired : CustomsState()
data object Unavailable : CustomsState()
data class DataAvailable(val customsData: CustomsData) : CustomsState()
}

companion object {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.woocommerce.android.ui.orders.wooshippinglabels.customs

import android.os.Parcelable
import com.woocommerce.android.ui.orders.wooshippinglabels.customs.WooShippingCustomsFormViewModel.ContentType
import com.woocommerce.android.ui.orders.wooshippinglabels.customs.WooShippingCustomsFormViewModel.RestrictionType
import kotlinx.parcelize.Parcelize
import java.math.BigDecimal

@Parcelize
data class CustomsData(
val packageId: String,
val packageName: String,
val contentType: ContentType,
val contentDescription: String,
val restrictionType: RestrictionType,
val restrictionDescription: String,
val noDeliveryOption: Boolean,
val itn: String,
val items: List<CustomsItem>
) : Parcelable

@Parcelize
data class CustomsItem(
val productID: Long,
val description: String,
val quantity: Float,
val value: BigDecimal,
val weight: Float,
val hsTariffNumber: String,
val originCountry: String
) : Parcelable
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@ import androidx.navigation.fragment.findNavController
import com.woocommerce.android.R
import com.woocommerce.android.extensions.handleDialogResult
import com.woocommerce.android.extensions.handleResult
import com.woocommerce.android.extensions.navigateBackWithResult
import com.woocommerce.android.extensions.navigateSafely
import com.woocommerce.android.model.Location
import com.woocommerce.android.ui.base.BaseFragment
import com.woocommerce.android.ui.compose.theme.WooThemeWithBackground
import com.woocommerce.android.ui.orders.wooshippinglabels.customs.WooShippingCustomsFormViewModel.ContentType
import com.woocommerce.android.ui.orders.wooshippinglabels.customs.WooShippingCustomsFormViewModel.FinishCustomsForm
import com.woocommerce.android.ui.orders.wooshippinglabels.customs.WooShippingCustomsFormViewModel.RestrictionType
import com.woocommerce.android.ui.orders.wooshippinglabels.customs.WooShippingCustomsFormViewModel.ShowContentTypeDialog
import com.woocommerce.android.ui.orders.wooshippinglabels.customs.WooShippingCustomsFormViewModel.ShowCountrySelector
Expand Down Expand Up @@ -73,6 +75,8 @@ class WooShippingCustomsFormFragment : BaseFragment() {
}

is ShowCountrySelector -> showCountrySearchScreen(event.countries)

is FinishCustomsForm -> navigateBackWithResult(CUSTOMS_DATA_RESULT, event.customData)
}
}
}
Expand Down Expand Up @@ -135,5 +139,7 @@ class WooShippingCustomsFormFragment : BaseFragment() {
const val SELECTOR_CONTENT_REQUEST_KEY = "label_customs_content_selector"
const val SELECTOR_RESTRICTION_REQUEST_KEY = "label_customs_restriction_selector"
const val SELECT_COUNTRY_REQUEST = "select_address_country_request"

const val CUSTOMS_DATA_RESULT = "customs_data_result"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,7 @@ fun PreviewWooShippingCustomsFormScreen() {
shouldDisplayRestrictionTypeInput = false,
shippingProducts = listOf(
WooShippingCustomsProductUIModel(
productId = 0,
name = "Little Nap Brazil 250g",
description = InputValue.Data("Product Description"),
tariffNumber = InputValue.Data("123456"),
Expand All @@ -232,6 +233,7 @@ fun PreviewWooShippingCustomsFormScreen() {
isExpanded = false
),
WooShippingCustomsProductUIModel(
productId = 0,
name = "Little Nap Brazil 250g",
description = InputValue.Data("Product Description"),
tariffNumber = InputValue.Data("123456"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,12 @@ class WooShippingCustomsFormViewModel @Inject constructor(

init {
launch { loadCountries() }
val shippableProducts = navArgs.shippableItems.map { item -> item.toProductUIModel() }
_viewState.update { it.copy(shippingProducts = shippableProducts) }
navArgs.customsData?.let { customData ->
loadViewStateFromExistentCustomData(customData)
} ?: run {
val shippableProducts = navArgs.shippableItems.map { item -> item.toProductUIModel() }
_viewState.update { it.copy(shippingProducts = shippableProducts) }
}
observeShippableItemsChanges()
}

Expand All @@ -64,6 +68,32 @@ class WooShippingCustomsFormViewModel @Inject constructor(
}.launchIn(viewModelScope)
}

private fun loadViewStateFromExistentCustomData(customData: CustomsData) {
_viewState.update {
it.copy(
contentType = customData.contentType,
otherContentInput = InputValue.Data(customData.contentDescription),
restrictionType = customData.restrictionType,
otherRestrictionInput = InputValue.Data(customData.restrictionDescription),
itnValue = InputValue.Data(customData.itn),
returnToSenderChecked = customData.noDeliveryOption,
shippingProducts = customData.items.map { item ->
WooShippingCustomsProductUIModel(
productId = item.productID,
name = item.description,
description = InputValue.Data(item.description),
tariffNumber = InputValue.Data(item.hsTariffNumber),
valuePerUnit = InputValue.Data(item.value.toString()),
weightPerUnit = InputValue.Data(item.weight.toString()),
originCountry = item.originCountry,
quantity = item.quantity,
isExpanded = false
)
}
)
}
}

fun onContentTypeClick() {
val currentSelection = _viewState.value.contentType
triggerEvent(ShowContentTypeDialog(currentSelection))
Expand Down Expand Up @@ -218,7 +248,7 @@ class WooShippingCustomsFormViewModel @Inject constructor(
}

fun onAddCustomsDataClick() {
triggerEvent(FinishCustomsForm)
_viewState.value.asCustomData.let { triggerEvent(FinishCustomsForm(it)) }
}

private fun updateShippingProductsAt(
Expand All @@ -243,6 +273,7 @@ class WooShippingCustomsFormViewModel @Inject constructor(
}

private fun ShippableItemModel.toProductUIModel() = WooShippingCustomsProductUIModel(
productId = productId,
name = title,
description = "".asInputValueError,
tariffNumber = "".asInputValueError,
Expand Down Expand Up @@ -292,6 +323,19 @@ class WooShippingCustomsFormViewModel @Inject constructor(
(contentType != ContentType.OTHER || otherContentInput is InputValue.Data) &&
(restrictionType != RestrictionType.OTHER || otherRestrictionInput is InputValue.Data) &&
shippingProducts.all { it.isValid }

val asCustomData: CustomsData
get() = CustomsData(
packageId = "",
packageName = "",
contentType = contentType,
contentDescription = otherContentInput.currentInput,
restrictionType = restrictionType,
restrictionDescription = otherRestrictionInput.currentInput,
itn = itnValue.currentInput,
noDeliveryOption = returnToSenderChecked,
items = shippingProducts.map { it.asCustomItem }
)
}

@Parcelize
Expand Down Expand Up @@ -334,7 +378,7 @@ class WooShippingCustomsFormViewModel @Inject constructor(
data class ShowContentTypeDialog(val currentSelection: ContentType) : MultiLiveEvent.Event()
data class ShowRestrictionTypeDialog(val currentSelection: RestrictionType) : MultiLiveEvent.Event()
data class ShowCountrySelector(val countries: List<Location>) : MultiLiveEvent.Event()
object FinishCustomsForm : MultiLiveEvent.Event()
data class FinishCustomsForm(val customData: CustomsData) : MultiLiveEvent.Event()

companion object {
/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,7 @@ fun WooShippingCustomsProductListCollapsedItemPreview() {
Box(Modifier.padding(16.dp)) {
WooShippingCustomsProductListItem(
itemData = WooShippingCustomsProductUIModel(
productId = 0,
name = "Little Nap Brazil 250g",
description = InputValue.Data("Coffee Beans"),
tariffNumber = InputValue.Data("HS 14-1"),
Expand Down Expand Up @@ -283,6 +284,7 @@ fun WooShippingCustomsProductListCollapsedItemErrorPreview() {
Box(Modifier.padding(16.dp)) {
WooShippingCustomsProductListItem(
itemData = WooShippingCustomsProductUIModel(
productId = 0,
name = "Little Nap Brazil 250g",
description = InputValue.Error("Coffee Beans", 0),
tariffNumber = InputValue.Data("HS 14-1"),
Expand Down Expand Up @@ -310,6 +312,7 @@ fun WooShippingCustomsProductListExpandedItemPreview() {
Box(Modifier.padding(16.dp)) {
WooShippingCustomsProductListItem(
itemData = WooShippingCustomsProductUIModel(
productId = 0,
name = "Little Nap Brazil 250g",
description = InputValue.Data("Coffee Beans"),
tariffNumber = InputValue.Data("HS 14-1"),
Expand Down Expand Up @@ -337,6 +340,7 @@ fun WooShippingCustomsProductListExpandedItemErrorPreview() {
Box(Modifier.padding(16.dp)) {
WooShippingCustomsProductListItem(
itemData = WooShippingCustomsProductUIModel(
productId = 0,
name = "Little Nap Brazil 250g",
description = InputValue.Error("Coffee Beans", 0),
tariffNumber = InputValue.Error("HS 14-1", 0),
Expand Down
Loading

0 comments on commit a64d1fc

Please sign in to comment.