Skip to content

[Dynamic Dashboard] Orders card #11486

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 22 commits into from
May 16, 2024
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ data class DashboardWidget(
ONBOARDING(R.string.my_store_widget_onboarding_title, "store_setup"),
STATS(R.string.my_store_widget_stats_title, "performance"),
POPULAR_PRODUCTS(R.string.my_store_widget_top_products_title, "top_performers"),
BLAZE(R.string.my_store_widget_blaze_title, "blaze")
BLAZE(R.string.my_store_widget_blaze_title, "blaze"),
ORDERS(R.string.my_store_widget_orders_title, "orders"),
}

sealed interface Status : Parcelable {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ data class Order(
val selectedGiftCard: String?,
val giftCardDiscountedAmount: BigDecimal?,
val shippingTax: BigDecimal,
val billingName: String = ""
Copy link
Member

@hichamboushaba hichamboushaba May 10, 2024

Choose a reason for hiding this comment

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

I see some issues with this change to introduce billingName as a read-only property:

  • Adds to the size of the Order Parcelable, which is a minor thing, but something we should still avoid unless necessary.
  • Could lead to inconsistencies:
    1. we can update the billingAddress using copy function, which I believe we do in the Order edit screen, so when this happen, the billingName will still point to an outdated value.
    2. For someone unfamiliar with the code, they could think that updating the billingName is enough to update the customer's name, which is not the case.

As a solution, I suggest two solutions:

  1. Either use the existing function Order#getBillingName
  2. Introduce a computed property billingName that returns an empty string instead of the default value we use now, and then supply the default value in the UI code, this would be something like:
    @IgnoredOnParcel
    val billingName
        get() = getBillingName("").trim()

WDYT?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good point, thanks.

) : Parcelable {
@IgnoredOnParcel
val isOrderPaid = datePaid != null
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package com.woocommerce.android.model

import com.woocommerce.android.R
import com.woocommerce.android.extensions.CASH_PAYMENTS
import com.woocommerce.android.extensions.fastStripHtml
import com.woocommerce.android.extensions.getBillingName
import com.woocommerce.android.model.Order.Item
import com.woocommerce.android.util.DateUtils
import com.woocommerce.android.util.StringUtils
import com.woocommerce.android.viewmodel.ResourceProvider
import org.wordpress.android.fluxc.model.OrderEntity
import org.wordpress.android.fluxc.model.WCMetaData
import org.wordpress.android.fluxc.model.order.FeeLineTaxStatus
Expand All @@ -22,7 +25,8 @@ import org.wordpress.android.fluxc.model.order.ShippingLine as WCShippingLine

class OrderMapper @Inject constructor(
private val getLocations: GetLocations,
private val dateUtils: DateUtils
private val dateUtils: DateUtils,
private val resourceProvider: ResourceProvider
) {
fun toAppModel(databaseEntity: OrderEntity): Order {
val metaDataList = databaseEntity.getMetaDataList()
Expand Down Expand Up @@ -66,6 +70,9 @@ class OrderMapper @Inject constructor(
giftCardDiscountedAmount = databaseEntity.giftCardAmount
.toBigDecimalOrNull() ?: BigDecimal.ZERO,
shippingTax = databaseEntity.shippingTax.toBigDecimalOrNull() ?: BigDecimal.ZERO,
billingName = databaseEntity.getBillingName(
resourceProvider.getString(R.string.orderdetail_customer_name_default)
)
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.woocommerce.android.R

@Composable
Expand All @@ -24,26 +25,26 @@ fun WCTag(
modifier: Modifier = Modifier,
textColor: Color = colorResource(id = R.color.tag_text_main),
backgroundColor: Color = colorResource(R.color.tag_bg_main),
textStyle: TextStyle = MaterialTheme.typography.caption
textStyle: TextStyle = MaterialTheme.typography.caption,
fontWeight: FontWeight = FontWeight.Bold
) {
Box(
modifier = modifier
.clip(RoundedCornerShape(percent = 35))
.clip(RoundedCornerShape(4.dp))
.background(backgroundColor)
.padding(
start = dimensionResource(id = R.dimen.minor_50),
end = dimensionResource(id = R.dimen.minor_50),
horizontal = dimensionResource(id = R.dimen.minor_50),
)
) {
Text(
modifier = Modifier.padding(
horizontal = dimensionResource(id = R.dimen.minor_75),
vertical = dimensionResource(id = R.dimen.minor_25)
vertical = dimensionResource(id = R.dimen.minor_50)
),
text = text,
style = textStyle,
color = textColor,
fontWeight = FontWeight.Bold
fontWeight = fontWeight
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import com.woocommerce.android.ui.compose.component.WCOutlinedButton
import com.woocommerce.android.ui.dashboard.DashboardViewModel.DashboardEvent.OpenRangePicker
import com.woocommerce.android.ui.dashboard.blaze.DashboardBlazeCard
import com.woocommerce.android.ui.dashboard.onboarding.DashboardOnboardingCard
import com.woocommerce.android.ui.dashboard.orders.DashboardOrdersCard
import com.woocommerce.android.ui.dashboard.stats.DashboardStatsCard
import com.woocommerce.android.ui.dashboard.topperformers.DashboardTopPerformersWidgetCard

Expand Down Expand Up @@ -132,6 +133,11 @@ private fun ConfigurableWidgetCard(
parentViewModel = dashboardViewModel,
modifier = modifier
)

DashboardWidget.Type.ORDERS -> DashboardOrdersCard(
parentViewModel = dashboardViewModel,
modifier = modifier
)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import com.woocommerce.android.ui.compose.theme.WooThemeWithBackground
import com.woocommerce.android.ui.dashboard.DashboardViewModel.DashboardEvent.ContactSupport
import com.woocommerce.android.ui.dashboard.DashboardViewModel.DashboardEvent.FeedbackNegativeAction
import com.woocommerce.android.ui.dashboard.DashboardViewModel.DashboardEvent.FeedbackPositiveAction
import com.woocommerce.android.ui.dashboard.DashboardViewModel.DashboardEvent.NavigateToOrders
import com.woocommerce.android.ui.dashboard.DashboardViewModel.DashboardEvent.OpenEditWidgets
import com.woocommerce.android.ui.dashboard.DashboardViewModel.DashboardEvent.OpenRangePicker
import com.woocommerce.android.ui.dashboard.DashboardViewModel.DashboardEvent.ShareStore
Expand Down Expand Up @@ -165,6 +166,8 @@ class DashboardFragment :

is FeedbackNegativeAction -> mainNavigationRouter?.showFeedbackSurvey()

is NavigateToOrders -> mainNavigationRouter?.showOrders()
Copy link
Member

Choose a reason for hiding this comment

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

np, seeing you introduce the function showOrders here got me thinking on why we need it, and it turns out, we don't, the Navigation Component and the integration with the Bottom Navigation can handle this for us with a simple call to findNavController.navigate(R.id.orders), this means that if you want, you can handle this navigation event directly from the card in a HandleEvent function, and decouple it from the parent ViewModel, but it's a minor thing, feel free to ignore it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I thought there might be an easier way but I didn't think of this, thanks!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I followed your advice but now the bottom navigation button don't work right. I pushed the code so you could take a look while I'm trying to figure out if I can make it work, or if I need to revert the change.

Copy link
Member

Choose a reason for hiding this comment

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

I followed your advice but now the bottom navigation button don't work right. I pushed the code so you could take a look while I'm trying to figure out if I can make it work, or if I need to revert the change.

Sorry I missed this case when I suggested this solution, I found a fix after checking the code of NavigationUI.onNavDestinationSelected:

navController.navigateSafely(
                        resId = R.id.orders,
                        navOptions = navOptions {
                            popUpTo(navController.graph.findStartDestination().id) {
                                saveState = true
                            }
                        }
                    )

But I'm not sure if this is simpler than what you had before or not, I'll leave it to you to decide which solution is better.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Nice, thank you!


else -> event.isHandled = false
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,10 @@ class DashboardViewModel @Inject constructor(
triggerEvent(DashboardEvent.ContactSupport)
}

fun onNavigateToOrders() {
triggerEvent(DashboardEvent.NavigateToOrders)
}

private fun mapWidgetsToUiModels(
widgets: List<DashboardWidget>,
userFeedbackIsDue: Boolean
Expand Down Expand Up @@ -303,6 +307,8 @@ class DashboardViewModel @Inject constructor(
data object FeedbackPositiveAction : DashboardEvent()

data object FeedbackNegativeAction : DashboardEvent()

object NavigateToOrders : DashboardEvent()
}

data class RefreshEvent(val isForced: Boolean = false)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import com.woocommerce.android.model.DashboardWidget
import com.woocommerce.android.tools.SelectedSite
import com.woocommerce.android.ui.mystore.data.DashboardDataModel
import com.woocommerce.android.ui.mystore.data.DashboardWidgetDataModel
import com.woocommerce.android.util.FeatureFlag
import com.woocommerce.android.util.WooLog
import com.woocommerce.android.util.WooLog.T
import dagger.hilt.EntryPoints
Expand Down Expand Up @@ -77,4 +78,8 @@ class DashboardDataStore @Inject constructor(

// Use the feature flag [DYNAMIC_DASHBOARD_M2] to filter out unsupported widgets during development
private val supportedWidgets: List<DashboardWidget.Type> = DashboardWidget.Type.entries
.filter {
FeatureFlag.DYNAMIC_DASHBOARD_M2.isEnabled() ||
it != DashboardWidget.Type.ORDERS
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -88,10 +88,9 @@ class DashboardRepository @Inject constructor(
isSelected = widget.isAdded,
status = when (type) {
DashboardWidget.Type.STATS,
DashboardWidget.Type.ORDERS,
DashboardWidget.Type.POPULAR_PRODUCTS -> statsWidgetsStatus
Copy link
Member

Choose a reason for hiding this comment

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

Nice that you used the hasOrders logic to hide the card 👏, just one np point, I think it would be more clearer to rename the class and property now, saying statsWidgetStatus is not very clear.

And also we should probably let the iOS team know about this decision (unless this was done and I missed it).


DashboardWidget.Type.BLAZE -> blazeWidgetStatus

DashboardWidget.Type.ONBOARDING -> onboardingWidgetStatus
}
)
Expand Down
Loading
Loading