From 3c97b3b3de6297fd270cf8f197c0c63b5489799c Mon Sep 17 00:00:00 2001 From: Gracia Hotmauli <95269134+hotmauligracia@users.noreply.github.com> Date: Fri, 20 Jun 2025 01:50:39 +0700 Subject: [PATCH 1/2] product change stock and price --- .../product/ChangePriceBottomSheetFragment.kt | 77 ++++++++---------- .../product/ChangeStockBottomSheetFragment.kt | 69 ++++++++++++++++ .../mystore/product/ProductActivity.kt | 33 +++++++- .../profile/mystore/product/ProductAdapter.kt | 40 ++++++++- .../sells/shipment/DetailShipmentActivity.kt | 8 ++ .../utils/viewmodel/ProductViewModel.kt | 6 +- app/src/main/res/drawable/ic_add.png | Bin 0 -> 261 bytes app/src/main/res/drawable/ic_minus.png | Bin 0 -> 187 bytes .../fragment_change_price_bottom_sheet.xml | 50 ++++++++++-- .../fragment_change_stock_bottom_sheet.xml | 62 ++++++++++++++ 10 files changed, 286 insertions(+), 59 deletions(-) create mode 100644 app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/product/ChangeStockBottomSheetFragment.kt create mode 100644 app/src/main/res/drawable/ic_add.png create mode 100644 app/src/main/res/drawable/ic_minus.png create mode 100644 app/src/main/res/layout/fragment_change_stock_bottom_sheet.xml diff --git a/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/product/ChangePriceBottomSheetFragment.kt b/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/product/ChangePriceBottomSheetFragment.kt index 0d8be50..8a88ac1 100644 --- a/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/product/ChangePriceBottomSheetFragment.kt +++ b/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/product/ChangePriceBottomSheetFragment.kt @@ -5,56 +5,47 @@ import androidx.fragment.app.Fragment import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.widget.Button +import android.widget.EditText +import android.widget.Toast import com.alya.ecommerce_serang.R +import com.alya.ecommerce_serang.data.api.dto.ProductsItem +import com.alya.ecommerce_serang.databinding.FragmentChangePriceBottomSheetBinding +import com.google.android.material.bottomsheet.BottomSheetDialogFragment -// TODO: Rename parameter arguments, choose names that match -// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER -private const val ARG_PARAM1 = "param1" -private const val ARG_PARAM2 = "param2" - -/** - * A simple [Fragment] subclass. - * Use the [ChangePriceBottomSheetFragment.newInstance] factory method to - * create an instance of this fragment. - */ -class ChangePriceBottomSheetFragment : Fragment() { - // TODO: Rename and change types of parameters - private var param1: String? = null - private var param2: String? = null - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - arguments?.let { - param1 = it.getString(ARG_PARAM1) - param2 = it.getString(ARG_PARAM2) - } - } +class ChangePriceBottomSheetFragment( + private val product: ProductsItem, + private val onSave: (productId: Int, newPrice: Int) -> Unit +) : BottomSheetDialogFragment() { + private var _binding: FragmentChangePriceBottomSheetBinding? = null + private val binding get() = _binding!! override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? - ): View? { - // Inflate the layout for this fragment - return inflater.inflate(R.layout.fragment_change_price_bottom_sheet, container, false) + ): View { + _binding = FragmentChangePriceBottomSheetBinding.inflate(inflater, container, false) + + binding.header.headerTitle.text = "Atur Harga" + binding.header.headerLeftIcon.setImageResource(R.drawable.ic_close) + binding.header.headerLeftIcon.setOnClickListener { dismiss() } + + binding.edtPrice.setText(product.price) + + binding.btnSave.setOnClickListener { + val newPrice = binding.edtPrice.text.toString().replace(".", "").toIntOrNull() + if (newPrice != null && newPrice > 0) { + onSave(product.id, newPrice) + dismiss() + } else { + Toast.makeText(requireContext(), "Masukkan harga yang valid", Toast.LENGTH_SHORT).show() + } + } + return binding.root } - companion object { - /** - * Use this factory method to create a new instance of - * this fragment using the provided parameters. - * - * @param param1 Parameter 1. - * @param param2 Parameter 2. - * @return A new instance of fragment ChangePriceBottomSheetFragment. - */ - // TODO: Rename and change types and number of parameters - @JvmStatic - fun newInstance(param1: String, param2: String) = - ChangePriceBottomSheetFragment().apply { - arguments = Bundle().apply { - putString(ARG_PARAM1, param1) - putString(ARG_PARAM2, param2) - } - } + override fun onDestroyView() { + super.onDestroyView() + _binding = null } } \ No newline at end of file diff --git a/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/product/ChangeStockBottomSheetFragment.kt b/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/product/ChangeStockBottomSheetFragment.kt new file mode 100644 index 0000000..9a4762d --- /dev/null +++ b/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/product/ChangeStockBottomSheetFragment.kt @@ -0,0 +1,69 @@ +package com.alya.ecommerce_serang.ui.profile.mystore.product + +import android.os.Bundle +import androidx.fragment.app.Fragment +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.core.content.ContextCompat +import com.alya.ecommerce_serang.R +import com.alya.ecommerce_serang.data.api.dto.ProductsItem +import com.alya.ecommerce_serang.databinding.FragmentChangeStockBottomSheetBinding +import com.google.android.material.bottomsheet.BottomSheetDialogFragment + +class ChangeStockBottomSheetFragment( + private val product: ProductsItem, + private val onSave: (productId: Int, newStock: Int) -> Unit +): BottomSheetDialogFragment() { + private var _binding: FragmentChangeStockBottomSheetBinding? = null + private val binding get() = _binding!! + + private var stock = 0 + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + _binding = FragmentChangeStockBottomSheetBinding.inflate(inflater, container, false) + + binding.header.headerTitle.text = "Atur Stok" + binding.header.headerLeftIcon.setImageResource(R.drawable.ic_close) + binding.header.headerLeftIcon.setOnClickListener { dismiss() } + + stock = product.stock + updateStock() + + binding.btnMinus.setOnClickListener { + if (stock > 0) stock-- + updateStock() + } + + binding.btnPlus.setOnClickListener { + stock++ + updateStock() + } + + binding.btnSave.setOnClickListener { + onSave(product.id, stock) + dismiss() + } + + return binding.root + } + + private fun updateStock() { + binding.edtStock.setText(stock.toString()) + if (stock == 0) { + binding.btnMinus.isEnabled = false + binding.btnMinus.setColorFilter(ContextCompat.getColor(requireContext(), R.color.black_100)) + } else { + binding.btnMinus.isEnabled = true + binding.btnMinus.setColorFilter(ContextCompat.getColor(requireContext(), R.color.blue_500)) + } + } + + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } +} \ No newline at end of file diff --git a/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/product/ProductActivity.kt b/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/product/ProductActivity.kt index 45a3cbd..e28b2f6 100644 --- a/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/product/ProductActivity.kt +++ b/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/product/ProductActivity.kt @@ -20,9 +20,10 @@ class ProductActivity : AppCompatActivity() { private lateinit var binding: ActivityProductBinding private lateinit var sessionManager: SessionManager + private lateinit var productAdapter: ProductAdapter + private val viewModel: ProductViewModel by viewModels { BaseViewModelFactory { - sessionManager = SessionManager(this) val apiService = ApiConfig.getApiService(sessionManager) val productRepository = ProductRepository(apiService) ProductViewModel(productRepository) @@ -30,6 +31,8 @@ class ProductActivity : AppCompatActivity() { } override fun onCreate(savedInstanceState: Bundle?) { + sessionManager = SessionManager(this) + super.onCreate(savedInstanceState) binding = ActivityProductBinding.inflate(layoutInflater) setContentView(binding.root) @@ -56,9 +59,18 @@ class ProductActivity : AppCompatActivity() { is Result.Success -> { binding.progressBar.visibility = View.GONE val products = result.data - binding.rvStoreProduct.adapter = ProductAdapter(products) { - Toast.makeText(this, "Produk: ${it.name}", Toast.LENGTH_SHORT).show() - } + + productAdapter = ProductAdapter( + products, + onItemClick = { products -> + Toast.makeText(this, "Produk ${products.name} diklik", Toast.LENGTH_SHORT).show() + }, + onUpdateProduct = { productId, updatedFields -> + viewModel.updateProduct(productId, updatedFields) + } + ) + + binding.rvStoreProduct.adapter = productAdapter } is Result.Error -> { binding.progressBar.visibility = View.GONE @@ -66,6 +78,19 @@ class ProductActivity : AppCompatActivity() { } } } + + viewModel.productUpdateResult.observe(this) { result -> + when (result) { + is Result.Success -> { + Toast.makeText(this, "Produk berhasil diperbarui", Toast.LENGTH_SHORT).show() + viewModel.loadMyStoreProducts() + } + is Result.Error -> { + Toast.makeText(this, "Gagal memperbarui produk", Toast.LENGTH_SHORT).show() + } + else -> {} + } + } } private fun setupHeader() { diff --git a/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/product/ProductAdapter.kt b/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/product/ProductAdapter.kt index c249fb0..5fa810b 100644 --- a/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/product/ProductAdapter.kt +++ b/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/product/ProductAdapter.kt @@ -3,6 +3,7 @@ package com.alya.ecommerce_serang.ui.profile.mystore.product import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.widget.Button import android.widget.ImageView import android.widget.PopupMenu import android.widget.TextView @@ -15,10 +16,14 @@ import com.alya.ecommerce_serang.R import com.alya.ecommerce_serang.data.api.dto.Product import com.alya.ecommerce_serang.data.api.dto.ProductsItem import com.bumptech.glide.Glide +import okhttp3.MediaType.Companion.toMediaTypeOrNull +import okhttp3.RequestBody +import okhttp3.RequestBody.Companion.toRequestBody class ProductAdapter( private val products: List, - private val onItemClick: (ProductsItem) -> Unit + private val onItemClick: (ProductsItem) -> Unit, + private val onUpdateProduct: (productId: Int, updatedFields: Map) -> Unit ) : RecyclerView.Adapter() { inner class ProductViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { @@ -28,6 +33,8 @@ class ProductAdapter( private val tvProductStock: TextView = itemView.findViewById(R.id.tv_product_stock) private val tvProductStatus: TextView = itemView.findViewById(R.id.tv_product_status) private val ivMenu: ImageView = itemView.findViewById(R.id.iv_menu) + private val btnChangePrice: Button = itemView.findViewById(R.id.btn_change_price) + private val btnChangeStock: Button = itemView.findViewById(R.id.btn_change_stock) fun bind(product: ProductsItem) { tvProductName.text = product.name @@ -55,7 +62,6 @@ class ProductAdapter( .into(ivProduct) ivMenu.setOnClickListener { - // Show Bottom Sheet when menu is clicked val bottomSheetFragment = ProductOptionsBottomSheetFragment(product) bottomSheetFragment.show( (itemView.context as FragmentActivity).supportFragmentManager, @@ -63,6 +69,36 @@ class ProductAdapter( ) } + btnChangePrice.setOnClickListener { + val bottomSheetFragment = ChangePriceBottomSheetFragment(product) { id, newPrice -> + val body = mapOf( + "product_id" to id.toString().toRequestBody("text/plain".toMediaTypeOrNull()), + "price" to newPrice.toString().toRequestBody("text/plain".toMediaTypeOrNull()) + ) + onUpdateProduct(id, body) + Toast.makeText(itemView.context, "Harga berhasil diubah", Toast.LENGTH_SHORT).show() + } + bottomSheetFragment.show( + (itemView.context as FragmentActivity).supportFragmentManager, + bottomSheetFragment.tag + ) + } + + btnChangeStock.setOnClickListener { + val bottomSheetFragment = ChangeStockBottomSheetFragment(product) { id, newStock -> + val body = mapOf( + "product_id" to id.toString().toRequestBody("text/plain".toMediaTypeOrNull()), + "stock" to newStock.toString().toRequestBody("text/plain".toMediaTypeOrNull()) + ) + onUpdateProduct(id, body) + Toast.makeText(itemView.context, "Stok berhasil diubah", Toast.LENGTH_SHORT).show() + } + bottomSheetFragment.show( + (itemView.context as FragmentActivity).supportFragmentManager, + bottomSheetFragment.tag + ) + } + itemView.setOnClickListener { onItemClick(product) } diff --git a/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/sells/shipment/DetailShipmentActivity.kt b/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/sells/shipment/DetailShipmentActivity.kt index 9ca1b03..99b8077 100644 --- a/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/sells/shipment/DetailShipmentActivity.kt +++ b/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/sells/shipment/DetailShipmentActivity.kt @@ -6,6 +6,7 @@ import android.util.Log import android.widget.Toast import androidx.activity.viewModels import androidx.appcompat.app.AppCompatActivity +import androidx.recyclerview.widget.LinearLayoutManager import com.alya.ecommerce_serang.data.api.response.store.sells.Orders import com.alya.ecommerce_serang.data.api.response.store.sells.OrdersItem import com.alya.ecommerce_serang.data.api.retrofit.ApiConfig @@ -13,6 +14,7 @@ import com.alya.ecommerce_serang.data.repository.AddressRepository import com.alya.ecommerce_serang.data.repository.SellsRepository import com.alya.ecommerce_serang.databinding.ActivityDetailShipmentBinding import com.alya.ecommerce_serang.ui.profile.mystore.sells.SellsProductAdapter +import com.alya.ecommerce_serang.ui.profile.mystore.sells.payment.DetailPaymentActivity import com.alya.ecommerce_serang.utils.BaseViewModelFactory import com.alya.ecommerce_serang.utils.SessionManager import com.alya.ecommerce_serang.utils.viewmodel.AddressViewModel @@ -51,6 +53,12 @@ class DetailShipmentActivity : AppCompatActivity() { finish() } + productAdapter = SellsProductAdapter() + binding.rvProductItems.apply { + adapter = productAdapter + layoutManager = LinearLayoutManager(this@DetailShipmentActivity) + } + val sellsJson = intent.getStringExtra("sells_data") if (sellsJson != null) { try { diff --git a/app/src/main/java/com/alya/ecommerce_serang/utils/viewmodel/ProductViewModel.kt b/app/src/main/java/com/alya/ecommerce_serang/utils/viewmodel/ProductViewModel.kt index 280f3e1..61c796f 100644 --- a/app/src/main/java/com/alya/ecommerce_serang/utils/viewmodel/ProductViewModel.kt +++ b/app/src/main/java/com/alya/ecommerce_serang/utils/viewmodel/ProductViewModel.kt @@ -111,9 +111,9 @@ class ProductViewModel(private val repository: ProductRepository) : ViewModel() fun updateProduct( productId: Int?, data: Map, - image: MultipartBody.Part?, - halal: MultipartBody.Part?, - sppirt: MultipartBody.Part? + image: MultipartBody.Part? = null, + halal: MultipartBody.Part? = null, + sppirt: MultipartBody.Part? = null ) { viewModelScope.launch { _productUpdateResult.postValue(Result.Loading) diff --git a/app/src/main/res/drawable/ic_add.png b/app/src/main/res/drawable/ic_add.png new file mode 100644 index 0000000000000000000000000000000000000000..4acefe2b80fde2337963ff935e9c330bbf7621a7 GIT binary patch literal 261 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY1|&n@ZgvM!oCO|{#S9FJ79h;%I?XTvD9BhG z_MVx$h9@Y4dG2|T#h$KyF6*2U FngD`$O#}b{ literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable/ic_minus.png b/app/src/main/res/drawable/ic_minus.png new file mode 100644 index 0000000000000000000000000000000000000000..9d7ed0b94041f4fa1aba0130da66451e722730cf GIT binary patch literal 187 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY1|&n@ZgvM!oCO|{#S9FJ79h;%I?XTvD9BhG z - + tools:context=".ui.profile.mystore.product.ChangePriceBottomSheetFragment" + android:orientation="vertical"> - - + + + + android:layout_height="wrap_content" + android:orientation="horizontal" + android:background="@drawable/bg_text_field" + android:layout_marginTop="10dp" + android:layout_marginHorizontal="16dp"> - \ No newline at end of file + + + + + + +