update cart wholesale

This commit is contained in:
shaulascr
2025-05-21 21:57:42 +07:00
parent aa0c01140b
commit 419eddee90
8 changed files with 184 additions and 28 deletions

View File

@ -78,13 +78,16 @@ data class Product(
val preorderDuration: String? = null
)
data class CartItemWholesaleInfo(
val cartItemId: Int,
val isWholesale: Boolean,
val wholesalePrice: Double? = null
)
data class CartItemCheckoutInfo(
val cartItem: CartItemsItem,
val isWholesale: Boolean
)
data class CartItemWholesaleInfo(
val cartItemId: Int,
val isWholesale: Boolean,
val wholesalePrice: Double? = null
)

View File

@ -91,7 +91,6 @@ class CartActivity : AppCompatActivity() {
adapter = storeAdapter
}
}
private fun setupListeners() {
binding.cbSelectAll.setOnCheckedChangeListener { _, _ ->
viewModel.toggleSelectAll()
@ -99,16 +98,20 @@ class CartActivity : AppCompatActivity() {
binding.btnCheckout.setOnClickListener {
if (viewModel.totalSelectedCount.value ?: 0 > 0) {
val selectedItems = viewModel.prepareCheckout()
if (selectedItems.isNotEmpty()) {
// Check if all items are from the same store
val storeId = viewModel.activeStoreId.value
if (storeId != null) {
// Start checkout with the prepared items
startCheckoutWithWholesaleInfo(selectedItems)
} else {
Toast.makeText(this, "Please select items from a single store only", Toast.LENGTH_SHORT).show()
if (viewModel.hasConsistentWholesaleStatus.value == true) {
val selectedItems = viewModel.prepareCheckout()
if (selectedItems.isNotEmpty()) {
// Check if all items are from the same store
val storeId = viewModel.activeStoreId.value
if (storeId != null) {
// Start checkout with the prepared items
startCheckoutWithWholesaleInfo(selectedItems)
} else {
Toast.makeText(this, "Please select items from a single store only", Toast.LENGTH_SHORT).show()
}
}
} else {
Toast.makeText(this, "Tidak dapat checkout produk grosir dan retail sekaligus", Toast.LENGTH_LONG).show()
}
} else {
Toast.makeText(this, "Pilih produk terlebih dahulu", Toast.LENGTH_SHORT).show()
@ -176,6 +179,30 @@ class CartActivity : AppCompatActivity() {
viewModel.toggleSelectAll()
}
}
viewModel.hasConsistentWholesaleStatus.observe(this) { isConsistent ->
if (!isConsistent && (viewModel.totalSelectedCount.value ?: 0) > 1) {
binding.btnCheckout.isEnabled = false
// Show an error message or indicator
binding.tvWholesaleWarning.visibility = View.VISIBLE
binding.tvWholesaleWarning.text = "Tidak dapat checkout produk grosir dan retail sekaligus"
} else {
binding.btnCheckout.isEnabled = true
binding.tvWholesaleWarning.visibility = View.GONE
}
}
viewModel.cartItemWholesaleStatus.observe(this) { wholesaleStatusMap ->
viewModel.cartItemWholesalePrice.value?.let { wholesalePriceMap ->
storeAdapter.updateWholesaleStatus(wholesaleStatusMap, wholesalePriceMap)
}
}
viewModel.cartItemWholesalePrice.observe(this) { wholesalePriceMap ->
viewModel.cartItemWholesaleStatus.value?.let { wholesaleStatusMap ->
storeAdapter.updateWholesaleStatus(wholesaleStatusMap, wholesalePriceMap)
}
}
}
private fun showEmptyState(isEmpty: Boolean) {

View File

@ -49,6 +49,9 @@ class CartViewModel(private val repository: OrderRepository) : ViewModel() {
private val _cartItemWholesalePrice = MutableLiveData<Map<Int, Double>>(mapOf())
val cartItemWholesalePrice: LiveData<Map<Int, Double>> = _cartItemWholesalePrice
private val _hasConsistentWholesaleStatus = MutableLiveData<Boolean>(true)
val hasConsistentWholesaleStatus: LiveData<Boolean> = _hasConsistentWholesaleStatus
fun getCart() {
_isLoading.value = true
_errorMessage.value = null
@ -379,4 +382,26 @@ class CartViewModel(private val repository: OrderRepository) : ViewModel() {
calculateTotalPrice()
}
}
private fun checkWholesaleConsistency() {
val selectedItemIds = _selectedItems.value ?: HashSet()
val wholesaleStatus = _cartItemWholesaleStatus.value ?: mapOf()
if (selectedItemIds.isEmpty()) {
_hasConsistentWholesaleStatus.value = true
return
}
// Get the wholesale status of the first selected item
val firstSelectedId = selectedItemIds.first()
val firstStatus = wholesaleStatus[firstSelectedId] ?: false
// Check if all other selected items have the same wholesale status
val allSameStatus = selectedItemIds.all { itemId ->
val itemStatus = wholesaleStatus[itemId] ?: false
itemStatus == firstStatus
}
_hasConsistentWholesaleStatus.value = allSameStatus
}
}

View File

@ -28,6 +28,8 @@ class StoreAdapter(
private var selectedItems = HashSet<Int>()
private var selectedStores = HashSet<Int>()
private var activeStoreId: Int? = null
private var wholesaleStatusMap: Map<Int, Boolean> = mapOf()
private var wholesalePriceMap: Map<Int, Double> = mapOf()
companion object {
private const val VIEW_TYPE_STORE = 0
@ -70,6 +72,27 @@ class StoreAdapter(
return count
}
private fun isItemSelectable(cartItemId: Int): Boolean {
// If no items are selected, any item can be selected
if (selectedItems.isEmpty()) return true
// Get wholesale status of this item
val thisItemWholesale = wholesaleStatusMap[cartItemId] ?: false
// Get wholesale status of first selected item
val firstSelectedId = selectedItems.first()
val firstSelectedWholesale = wholesaleStatusMap[firstSelectedId] ?: false
// Item can be selected if its wholesale status matches the first selected item
return thisItemWholesale == firstSelectedWholesale
}
fun updateWholesaleStatus(wholesaleStatusMap: Map<Int, Boolean>, wholesalePriceMap: Map<Int, Double>) {
this.wholesaleStatusMap = wholesaleStatusMap
this.wholesalePriceMap = wholesalePriceMap
notifyDataSetChanged()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return when (viewType) {
VIEW_TYPE_STORE -> {
@ -100,11 +123,16 @@ class StoreAdapter(
val cartItem = store.cartItems[itemIndex]
val isSelected = selectedItems.contains(cartItem.cartItemId)
val isEnabled = activeStoreId == null || activeStoreId == store.storeId
val isItemWholesale = wholesaleStatusMap[cartItem.cartItemId] ?: false
val wholesalePrice = wholesalePriceMap[cartItem.cartItemId]
val isSelectable = isItemSelectable(cartItem.cartItemId)
holder.bind(
cartItem,
isSelected,
isEnabled,
isEnabled && isSelectable,
isItemWholesale,
wholesalePrice,
{ isChecked -> onItemCheckChanged(cartItem.cartItemId, store.storeId, isChecked) },
{ quantity -> onItemQuantityChanged(cartItem.cartItemId, quantity) },
{ onItemDeleted(cartItem.cartItemId) }
@ -158,20 +186,67 @@ class StoreAdapter(
private val btnMinus: ImageButton = itemView.findViewById(R.id.btnMinus)
private val tvQuantity: TextView = itemView.findViewById(R.id.tvQuantity)
private val btnPlus: ImageButton = itemView.findViewById(R.id.btnPlus)
private val tvWholesaleIndicator : TextView = itemView.findViewById((R.id.tvWholesaleIndicator))
private val quantityController: ConstraintLayout = itemView.findViewById(R.id.quantityController)
fun bind(
cartItem: CartItemsItem,
isChecked: Boolean,
isSelected: Boolean,
isEnabled: Boolean,
isWholesale: Boolean,
wholesalePrice: Double?,
onCheckedChange: (Boolean) -> Unit,
onQuantityChanged: (Int) -> Unit,
onDelete: () -> Unit
) {
// Set product name
tvProductName.text = cartItem.productName
tvPrice.text = formatCurrency(cartItem.price)
// Set price based on wholesale status
if (isWholesale && wholesalePrice != null) {
tvPrice.text = formatCurrency(wholesalePrice.toInt())
// Show wholesale indicator if available
tvWholesaleIndicator?.visibility = View.VISIBLE
tvWholesaleIndicator?.text = "Harga Grosir"
} else {
tvPrice.text = formatCurrency(cartItem.price)
tvWholesaleIndicator?.visibility = View.GONE
}
// Set quantity
tvQuantity.text = cartItem.quantity.toString()
// Visual indication for wholesale items
// if (isWholesale) {
// // You can add a background or border to indicate wholesale items
// // For example:
//// itemView.setBackgroundResource(R.drawable.bg_wholesale_item)
// // If you don't have this drawable, you can use a simple color tint instead:
// itemView.setBackgroundColor(ContextCompat.getColor(itemView.context, R.color.wholesale_item_bg))
// } else {
// // Reset to default background
//// itemView.setBackgroundResource(R.drawable.bg_normal_item)
// // Or if you don't have this drawable:
// itemView.setBackgroundColor(ContextCompat.getColor(itemView.context, R.color.normal_item_bg))
// }
// Set checkbox state without triggering listener
cbItem.setOnCheckedChangeListener(null)
cbItem.isChecked = isSelected
cbItem.isEnabled = isEnabled
// If not enabled, visually indicate this item can't be selected
if (!isEnabled) {
itemView.alpha = 0.5f
} else {
itemView.alpha = 1.0f
}
// Set checkbox listener
cbItem.setOnCheckedChangeListener { _, isChecked ->
onCheckedChange(isChecked)
}
// Load product image
Glide.with(itemView.context)
.load("https://example.com/images/${cartItem.productId}.jpg") // Assume image URL based on product ID
@ -179,15 +254,6 @@ class StoreAdapter(
.error(R.drawable.placeholder_image)
.into(ivProduct)
// Set checkbox state without triggering listener
cbItem.setOnCheckedChangeListener(null)
cbItem.isChecked = isChecked
cbItem.isEnabled = isEnabled
cbItem.setOnCheckedChangeListener { _, isChecked ->
onCheckedChange(isChecked)
}
// Quantity control
btnMinus.setOnClickListener {
val currentQty = tvQuantity.text.toString().toInt()

View File

@ -0,0 +1,12 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M20,12H12H4"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="#000000"
android:strokeLineCap="round"/>
</vector>

View File

@ -21,6 +21,16 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/header"/>
<TextView
android:id="@+id/tvWholesaleWarning"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="#F44336"
android:textSize="12sp"
android:gravity="center"
android:visibility="gone"
app:layout_constraintBottom_toTopOf="@id/bottomCheckoutLayout" />
<!-- Bottom Checkout Layout -->
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/bottomCheckoutLayout"
@ -64,6 +74,8 @@
app:layout_constraintStart_toEndOf="@+id/tvTotalLabel"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/btnCheckout"
android:layout_width="wrap_content"

View File

@ -79,7 +79,7 @@
android:layout_width="30dp"
android:layout_height="30dp"
android:background="@drawable/bg_button_filled"
android:src="@drawable/baseline_add_24"
android:src="@drawable/btn_minus_24dp"
app:tint="@color/white"/>
<TextView

View File

@ -54,6 +54,17 @@
app:layout_constraintStart_toStartOf="@+id/tvProductName"
app:layout_constraintTop_toBottomOf="@+id/tvProductName" />
<TextView
android:id="@+id/tvWholesaleIndicator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Harga Grosir"
android:textColor="@color/blue_500"
android:textSize="12sp"
android:visibility="gone"
app:layout_constraintTop_toBottomOf="@id/tvPrice"
app:layout_constraintStart_toStartOf="@id/tvPrice" />
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/quantityController"
android:layout_width="wrap_content"