product create, update, delete

This commit is contained in:
Gracia Hotmauli
2025-05-25 17:31:07 +07:00
parent 59e2e6a43b
commit e9b4d7a8f1
4 changed files with 89 additions and 52 deletions

View File

@ -274,10 +274,13 @@ interface ApiService {
@Part halal: MultipartBody.Part? @Part halal: MultipartBody.Part?
): Response<CreateProductResponse> ): Response<CreateProductResponse>
@PUT("store/editproduct/{id}") @Multipart
@PUT("store/editproduct")
suspend fun updateProduct( suspend fun updateProduct(
@Path("id") productId: Int?, @PartMap data: Map<String, @JvmSuppressWildcards RequestBody>,
@Body updatedProduct: Map<String, Any?> @Part productImage: MultipartBody.Part?,
@Part halal: MultipartBody.Part?,
@Part sppirt: MultipartBody.Part?
): Response<UpdateProductResponse> ): Response<UpdateProductResponse>
@DELETE("store/deleteproduct/{id}") @DELETE("store/deleteproduct/{id}")

View File

@ -12,10 +12,8 @@ import com.alya.ecommerce_serang.data.api.response.customer.cart.AddCartResponse
import com.alya.ecommerce_serang.data.api.response.customer.product.ProductResponse import com.alya.ecommerce_serang.data.api.response.customer.product.ProductResponse
import com.alya.ecommerce_serang.data.api.response.customer.product.ReviewsItem import com.alya.ecommerce_serang.data.api.response.customer.product.ReviewsItem
import com.alya.ecommerce_serang.data.api.response.customer.product.StoreProduct import com.alya.ecommerce_serang.data.api.response.customer.product.StoreProduct
import com.alya.ecommerce_serang.data.api.response.store.product.UpdateProductResponse
import com.alya.ecommerce_serang.data.api.response.product.Search import com.alya.ecommerce_serang.data.api.response.product.Search
import com.alya.ecommerce_serang.data.api.retrofit.ApiService import com.alya.ecommerce_serang.data.api.retrofit.ApiService
import com.alya.ecommerce_serang.utils.SessionManager
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import okhttp3.MediaType.Companion.toMediaTypeOrNull import okhttp3.MediaType.Companion.toMediaTypeOrNull
@ -267,16 +265,13 @@ class ProductRepository(private val apiService: ApiService) {
} }
} }
suspend fun updateProduct(productId: Int?, updatedProduct: Map<String, Any?>) : UpdateProductResponse { suspend fun updateProduct(
// Build the request with the updated fields productId: Int?,
val response = apiService.updateProduct(productId, updatedProduct) data: Map<String, RequestBody>,
if (response.isSuccessful) { image: MultipartBody.Part?,
return response.body()!! halal: MultipartBody.Part?,
} else { sppirt: MultipartBody.Part?
throw Exception("Gagal memperbarui produk: ${response.code()}") ) = apiService.updateProduct(data, image, halal, sppirt)
}
}
suspend fun deleteProduct(productId: Int): Result<Unit> { suspend fun deleteProduct(productId: Int): Result<Unit> {
return withContext(Dispatchers.IO) { return withContext(Dispatchers.IO) {

View File

@ -110,17 +110,6 @@ class DetailStoreProductActivity : AppCompatActivity() {
adapterCondition.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) adapterCondition.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
binding.spinnerKondisiProduk.adapter = adapterCondition binding.spinnerKondisiProduk.adapter = adapterCondition
// Setup Pre-Order visibility
binding.switchIsPreOrder.setOnCheckedChangeListener { _, isChecked ->
togglePreOrderVisibility(isChecked)
validateForm()
}
binding.switchIsWholesale.setOnCheckedChangeListener { _, isChecked ->
toggleWholesaleVisibility(isChecked)
validateForm()
}
with(binding) { with(binding) {
edtNamaProduk.doAfterTextChanged { validateForm() } edtNamaProduk.doAfterTextChanged { validateForm() }
edtDeskripsiProduk.doAfterTextChanged { validateForm() } edtDeskripsiProduk.doAfterTextChanged { validateForm() }
@ -131,8 +120,14 @@ class DetailStoreProductActivity : AppCompatActivity() {
edtDurasi.doAfterTextChanged { validateForm() } edtDurasi.doAfterTextChanged { validateForm() }
edtMinPesanGrosir.doAfterTextChanged { validateForm() } edtMinPesanGrosir.doAfterTextChanged { validateForm() }
edtHargaGrosir.doAfterTextChanged { validateForm() } edtHargaGrosir.doAfterTextChanged { validateForm() }
switchIsPreOrder.setOnCheckedChangeListener { _, _ -> validateForm() } switchIsPreOrder.setOnCheckedChangeListener { _, isChecked ->
switchIsWholesale.setOnCheckedChangeListener { _, _ -> validateForm() } togglePreOrderVisibility(isChecked)
validateForm()
}
switchIsWholesale.setOnCheckedChangeListener { _, isChecked ->
toggleWholesaleVisibility(isChecked)
validateForm()
}
} }
validateForm() validateForm()
@ -424,27 +419,61 @@ class DetailStoreProductActivity : AppCompatActivity() {
} }
private fun updateProduct(productId: Int?) { private fun updateProduct(productId: Int?) {
val updatedProduct = mapOf( if (productId == null) return
"name" to binding.edtNamaProduk.text.toString(),
"description" to binding.edtDeskripsiProduk.text.toString(), val imageFile = imageUri?.let { uriToNamedFile(it, this, "productimg") }
"price" to binding.edtHargaProduk.text.toString(), val sppirtFile = sppirtUri?.let { uriToNamedFile(it, this, "sppirt") }
"stock" to binding.edtStokProduk.text.toString().toInt(), val halalFile = halalUri?.let { uriToNamedFile(it, this, "halal") }
"min_order" to binding.edtMinOrder.text.toString().toInt(),
"weight" to binding.edtBeratProduk.text.toString().toInt(), val imagePart = createPartFromFile("productimg", imageFile)
"is_pre_order" to binding.switchIsPreOrder.isChecked, val sppirtPart = createPartFromFile("sppirt", sppirtFile)
"duration" to (binding.edtDurasi.text.toString().toIntOrNull() ?: 0), val halalPart = createPartFromFile("halal", halalFile)
"is_wholesale" to binding.switchIsWholesale.isChecked,
"wholesale_min_item" to (binding.edtMinPesanGrosir.text.toString().toIntOrNull() ?: 0), val data = mutableMapOf<String, RequestBody>(
"wholesale_price" to (binding.edtHargaGrosir.text.toString().toIntOrNull() ?: 0), "product_id" to toRequestBody(productId.toString()),
"category_id" to categoryList[binding.spinnerKategoriProduk.selectedItemPosition].id, "name" to toRequestBody(binding.edtNamaProduk.text.toString()),
"status" to if (binding.switchIsActive.isChecked) "active" else "inactive", "description" to toRequestBody(binding.edtDeskripsiProduk.text.toString()),
"condition" to binding.spinnerKondisiProduk.selectedItem.toString(), "price" to toRequestBody(binding.edtHargaProduk.text.toString()),
"productimg" to imageUri?.path, "stock" to toRequestBody(binding.edtStokProduk.text.toString()),
"sppirt" to sppirtUri?.path, "min_order" to toRequestBody(binding.edtMinOrder.text.toString()),
"halal" to halalUri?.path "weight" to toRequestBody(binding.edtBeratProduk.text.toString()),
"is_pre_order" to toRequestBody(binding.switchIsPreOrder.isChecked.toString()),
"preorder_duration" to toRequestBody(
if (binding.switchIsPreOrder.isChecked)
binding.edtDurasi.text.toString()
else
"0"
),
"is_wholesale" to toRequestBody(binding.switchIsWholesale.isChecked.toString()),
"wholesale_min_item" to toRequestBody(
if (binding.switchIsWholesale.isChecked)
binding.edtMinPesanGrosir.text.toString()
else
"0"
),
"wholesale_price" to toRequestBody(
if (binding.switchIsWholesale.isChecked)
binding.edtHargaGrosir.text.toString()
else
"0"
),
"category_id" to toRequestBody(
categoryList[binding.spinnerKategoriProduk.selectedItemPosition].id.toString()
),
"status" to toRequestBody(
if (binding.switchIsActive.isChecked) "active" else "inactive"
),
"condition" to toRequestBody(binding.spinnerKondisiProduk.selectedItem.toString())
)
viewModel.updateProduct(
productId,
data,
imagePart,
halalPart,
sppirtPart
) )
viewModel.updateProduct(productId, updatedProduct)
viewModel.productUpdateResult.observe(this) { result -> viewModel.productUpdateResult.observe(this) { result ->
when (result) { when (result) {
is Result.Loading -> binding.btnSaveProduct.isEnabled = false is Result.Loading -> binding.btnSaveProduct.isEnabled = false
@ -461,4 +490,7 @@ class DetailStoreProductActivity : AppCompatActivity() {
} }
} }
} }
private fun toRequestBody(value: String): RequestBody =
RequestBody.create("text/plain".toMediaTypeOrNull(), value)
} }

View File

@ -17,6 +17,7 @@ import com.alya.ecommerce_serang.data.repository.ProductRepository
import com.alya.ecommerce_serang.data.repository.Result import com.alya.ecommerce_serang.data.repository.Result
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import okhttp3.MultipartBody import okhttp3.MultipartBody
import okhttp3.RequestBody
class ProductViewModel(private val repository: ProductRepository) : ViewModel() { class ProductViewModel(private val repository: ProductRepository) : ViewModel() {
@ -107,14 +108,20 @@ class ProductViewModel(private val repository: ProductRepository) : ViewModel()
} }
} }
fun updateProduct(productId: Int?, updatedProduct: Map<String, Any?>) { fun updateProduct(
_productUpdateResult.value = Result.Loading productId: Int?,
data: Map<String, RequestBody>,
image: MultipartBody.Part?,
halal: MultipartBody.Part?,
sppirt: MultipartBody.Part?
) {
viewModelScope.launch { viewModelScope.launch {
_productUpdateResult.postValue(Result.Loading)
try { try {
val response = repository.updateProduct(productId, updatedProduct) val response = repository.updateProduct(productId, data, image, halal, sppirt)
_productUpdateResult.value = Result.Success(response) _productUpdateResult.postValue(Result.Success(response.body()!!))
} catch (e: Exception) { } catch (e: Exception) {
_productUpdateResult.value = Result.Error(e) _productUpdateResult.postValue(Result.Error(e))
} }
} }
} }