fetch store product

This commit is contained in:
Gracia
2025-04-10 03:21:21 +07:00
parent a21ec50454
commit d11022d502
26 changed files with 441 additions and 38 deletions

View File

@ -0,0 +1,13 @@
package com.alya.ecommerce_serang.data.api.response
import com.alya.ecommerce_serang.data.api.dto.ProductsItem
import com.google.gson.annotations.SerializedName
data class ViewStoreProductsResponse(
@field:SerializedName("message")
val message: String? = null,
@field:SerializedName("products")
val products: List<ProductsItem?>? = null
)

View File

@ -13,6 +13,7 @@ import com.alya.ecommerce_serang.data.api.response.ProfileResponse
import com.alya.ecommerce_serang.data.api.response.RegisterResponse
import com.alya.ecommerce_serang.data.api.response.ReviewProductResponse
import com.alya.ecommerce_serang.data.api.response.StoreResponse
import com.alya.ecommerce_serang.data.api.response.ViewStoreProductsResponse
import retrofit2.Call
import retrofit2.Response
import retrofit2.http.Body
@ -64,4 +65,8 @@ interface ApiService {
@GET("mystore")
suspend fun getStore (): Response<StoreResponse>
@GET("mystore/product") // Replace with actual endpoint
suspend fun getStoreProduct(): Response<ViewStoreProductsResponse>
}

View File

@ -1,8 +0,0 @@
package com.alya.ecommerce_serang.data.model
data class BalanceTransaction(
val date: String,
val balanceTransTitle: String,
val balanceTransDesc: String,
val balanceTransAmount: String,
)

View File

@ -79,6 +79,16 @@ class ProductRepository(private val apiService: ApiService) {
null
}
}
suspend fun fetchMyStoreProducts(): List<ProductsItem> {
val response = apiService.getStoreProduct()
if (response.isSuccessful) {
val responseBody = response.body()
return responseBody?.products?.filterNotNull() ?: emptyList()
} else {
throw Exception("Failed to fetch store products: ${response.message()}")
}
}
}
// suspend fun fetchStoreDetail(storeId: Int): Store? {

View File

@ -4,10 +4,12 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.alya.ecommerce_serang.data.api.dto.ProductsItem
import com.alya.ecommerce_serang.data.api.dto.Store
import com.alya.ecommerce_serang.data.api.response.Product
import com.alya.ecommerce_serang.data.api.response.ReviewsItem
import com.alya.ecommerce_serang.data.repository.ProductRepository
import com.alya.ecommerce_serang.data.repository.Result
import kotlinx.coroutines.launch
class ProductViewModel(private val repository: ProductRepository) : ViewModel() {
@ -21,6 +23,10 @@ class ProductViewModel(private val repository: ProductRepository) : ViewModel()
private val _reviewProduct = MutableLiveData<List<ReviewsItem>>()
val reviewProduct: LiveData<List<ReviewsItem>> get() = _reviewProduct
// For List of Products in My Store
private val _productList = MutableLiveData<Result<List<ProductsItem>>>()
val productList: LiveData<Result<List<ProductsItem>>> get() = _productList
fun loadProductDetail(productId: Int) {
viewModelScope.launch {
val result = repository.fetchProductDetail(productId)
@ -34,11 +40,24 @@ class ProductViewModel(private val repository: ProductRepository) : ViewModel()
_reviewProduct.value = reviews ?: emptyList()
}
}
}
// fun loadStoreDetail(storeId: Int){
fun loadMyStoreProducts() {
viewModelScope.launch {
_productList.value = Result.Loading
try {
val result = repository.fetchMyStoreProducts()
_productList.value = Result.Success(result)
} catch (e: Exception) {
_productList.value = Result.Error(e)
}
}
}
// Optional: for store detail if you need it later
// fun loadStoreDetail(storeId: Int) {
// viewModelScope.launch {
// val storeResult = repository.fetchStoreDetail(storeId)
// _storeDetail.value = storeResult
// }
// }
// }
}

View File

@ -1,7 +1,5 @@
package com.alya.ecommerce_serang.ui.profile.mystore.balance
import com.alya.ecommerce_serang.data.model.BalanceTransaction
/* class BalanceTransactionAdapter(private val balanceTransactionList: List<BalanceTransaction>) :
RecyclerView.Adapter<BalanceTransactionAdapter.TransactionViewHolder>() {

View File

@ -1,21 +1,86 @@
package com.alya.ecommerce_serang.ui.profile.mystore.product
import android.content.Intent
import android.os.Bundle
import androidx.activity.enableEdgeToEdge
import android.view.View
import android.widget.Toast
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import com.alya.ecommerce_serang.R
import androidx.recyclerview.widget.LinearLayoutManager
import com.alya.ecommerce_serang.data.api.retrofit.ApiConfig
import com.alya.ecommerce_serang.data.repository.ProductRepository
import com.alya.ecommerce_serang.data.repository.Result
import com.alya.ecommerce_serang.databinding.ActivityProductBinding
import com.alya.ecommerce_serang.ui.product.ProductViewModel
import com.alya.ecommerce_serang.utils.BaseViewModelFactory
import com.alya.ecommerce_serang.utils.SessionManager
class ProductActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContentView(R.layout.activity_product)
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
insets
private lateinit var binding: ActivityProductBinding
private lateinit var sessionManager: SessionManager
private val viewModel: ProductViewModel by viewModels {
BaseViewModelFactory {
sessionManager = SessionManager(this)
val apiService = ApiConfig.getApiService(sessionManager)
val productRepository = ProductRepository(apiService)
ProductViewModel(productRepository)
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityProductBinding.inflate(layoutInflater)
setContentView(binding.root)
setupHeader()
setupRecyclerView()
observeViewModel()
binding.progressBar.visibility = View.VISIBLE
viewModel.loadMyStoreProducts()
}
private fun observeViewModel() {
viewModel.productList.observe(this) { result ->
when (result) {
is Result.Loading -> {
binding.progressBar.visibility = View.VISIBLE
}
is Result.Success -> {
binding.progressBar.visibility = View.GONE
val products = result.data
binding.rvStoreProduct.adapter = ProductAdapter(products) {
Toast.makeText(this, "Clicked: ${it.name}", Toast.LENGTH_SHORT).show()
}
}
is Result.Error -> {
binding.progressBar.visibility = View.GONE
Toast.makeText(this, "Failed to load products: ${result.exception.message}", Toast.LENGTH_SHORT).show()
}
}
}
}
private fun setupHeader() {
binding.header.headerTitle.text = "Produk Saya"
binding.header.headerRightText.visibility = View.VISIBLE
binding.header.headerLeftIcon.setOnClickListener {
onBackPressedDispatcher.onBackPressed()
}
binding.header.headerRightText.setOnClickListener {
startActivity(Intent(this, AddProductActivity::class.java))
}
}
private fun setupRecyclerView() {
binding.rvStoreProduct.layoutManager = LinearLayoutManager(this)
}
}

View File

@ -0,0 +1,63 @@
package com.alya.ecommerce_serang.ui.profile.mystore.product
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.RecyclerView
import com.alya.ecommerce_serang.R
import com.alya.ecommerce_serang.data.api.dto.ProductsItem
import com.bumptech.glide.Glide
class ProductAdapter(
private val products: List<ProductsItem>,
private val onItemClick: (ProductsItem) -> Unit
) : RecyclerView.Adapter<ProductAdapter.ProductViewHolder>() {
inner class ProductViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
private val ivProduct: ImageView = itemView.findViewById(R.id.iv_product)
private val tvProductName: TextView = itemView.findViewById(R.id.tv_product_name)
private val tvProductPrice: TextView = itemView.findViewById(R.id.tv_product_price)
private val tvProductStock: TextView = itemView.findViewById(R.id.tv_product_stock)
private val tvProductStatus: TextView = itemView.findViewById(R.id.tv_product_status)
fun bind(product: ProductsItem) {
tvProductName.text = product.name
tvProductPrice.text = "Rp${product.price}"
tvProductStock.text = "Stok: ${product.stock}"
tvProductStatus.text = product.status
// Change color depending on status
tvProductStatus.setTextColor(
ContextCompat.getColor(
itemView.context,
if (product.status.equals("active", true))
R.color.darkblue_500 else R.color.black_500
)
)
Glide.with(itemView.context)
.load(product.image)
.placeholder(R.drawable.placeholder_image)
.into(ivProduct)
itemView.setOnClickListener {
onItemClick(product)
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ProductViewHolder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.item_store_product, parent, false)
return ProductViewHolder(view)
}
override fun getItemCount(): Int = products.size
override fun onBindViewHolder(holder: ProductViewHolder, position: Int) {
holder.bind(products[position])
}
}