mirror of
https://github.com/shaulascr/ecommerce_serang.git
synced 2025-08-10 09:22:21 +00:00
update cart wholesale
This commit is contained in:
@ -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
|
||||
)
|
@ -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) {
|
||||
|
@ -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
|
||||
}
|
||||
}
|
@ -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()
|
||||
|
12
app/src/main/res/drawable/btn_minus_24dp.xml
Normal file
12
app/src/main/res/drawable/btn_minus_24dp.xml
Normal 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>
|
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
|
Reference in New Issue
Block a user