From d11022d502f720745395dff12b9cc1eca4c41c4a Mon Sep 17 00:00:00 2001 From: Gracia Date: Thu, 10 Apr 2025 03:21:21 +0700 Subject: [PATCH] fetch store product --- .idea/gradle.xml | 3 +- app/build.gradle.kts | 3 + .../api/response/ViewStoreProductsResponse.kt | 13 ++ .../data/api/retrofit/ApiService.kt | 5 + .../data/model/BalanceTransaction.kt | 8 -- .../data/repository/ProductRepository.kt | 10 ++ .../ui/product/ProductViewModel.kt | 25 +++- .../balance/BalanceTransactionAdapter.kt | 2 - .../mystore/product/ProductActivity.kt | 89 +++++++++++-- .../profile/mystore/product/ProductAdapter.kt | 63 +++++++++ .../main/res/drawable/bg_product_active.xml | 6 + .../main/res/drawable/bg_product_inactive.xml | 6 + app/src/main/res/drawable/ic_search.png | Bin 0 -> 820 bytes .../main/res/layout/activity_add_product.xml | 5 +- app/src/main/res/layout/activity_balance.xml | 5 +- .../res/layout/activity_balance_top_up.xml | 5 +- .../res/layout/activity_claim_payment.xml | 5 +- app/src/main/res/layout/activity_my_store.xml | 5 +- app/src/main/res/layout/activity_product.xml | 82 +++++++++++- .../layout/activity_shipping_confirmation.xml | 5 +- .../res/layout/activity_shipping_service.xml | 1 + .../res/layout/activity_store_address.xml | 1 + .../main/res/layout/item_store_product.xml | 123 ++++++++++++++++++ app/src/main/res/values/themes.xml | 5 + gradle/libs.versions.toml | 2 +- gradle/wrapper/gradle-wrapper.properties | 2 +- 26 files changed, 441 insertions(+), 38 deletions(-) create mode 100644 app/src/main/java/com/alya/ecommerce_serang/data/api/response/ViewStoreProductsResponse.kt delete mode 100644 app/src/main/java/com/alya/ecommerce_serang/data/model/BalanceTransaction.kt create mode 100644 app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/product/ProductAdapter.kt create mode 100644 app/src/main/res/drawable/bg_product_active.xml create mode 100644 app/src/main/res/drawable/bg_product_inactive.xml create mode 100644 app/src/main/res/drawable/ic_search.png create mode 100644 app/src/main/res/layout/item_store_product.xml diff --git a/.idea/gradle.xml b/.idea/gradle.xml index 7b3006b..d124cf2 100644 --- a/.idea/gradle.xml +++ b/.idea/gradle.xml @@ -6,14 +6,13 @@ - diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 2a25f1f..07c27e4 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -1,3 +1,5 @@ +import org.gradle.api.tasks.compile.JavaCompile + plugins { alias(libs.plugins.android.application) alias(libs.plugins.jetbrains.kotlin.android) @@ -84,3 +86,4 @@ dependencies { // kapt("androidx.hilt:hilt-compiler:1.0.0") } + diff --git a/app/src/main/java/com/alya/ecommerce_serang/data/api/response/ViewStoreProductsResponse.kt b/app/src/main/java/com/alya/ecommerce_serang/data/api/response/ViewStoreProductsResponse.kt new file mode 100644 index 0000000..c933ac7 --- /dev/null +++ b/app/src/main/java/com/alya/ecommerce_serang/data/api/response/ViewStoreProductsResponse.kt @@ -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? = null +) diff --git a/app/src/main/java/com/alya/ecommerce_serang/data/api/retrofit/ApiService.kt b/app/src/main/java/com/alya/ecommerce_serang/data/api/retrofit/ApiService.kt index f616739..1ad98bf 100644 --- a/app/src/main/java/com/alya/ecommerce_serang/data/api/retrofit/ApiService.kt +++ b/app/src/main/java/com/alya/ecommerce_serang/data/api/retrofit/ApiService.kt @@ -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 + + @GET("mystore/product") // Replace with actual endpoint + suspend fun getStoreProduct(): Response + } \ No newline at end of file diff --git a/app/src/main/java/com/alya/ecommerce_serang/data/model/BalanceTransaction.kt b/app/src/main/java/com/alya/ecommerce_serang/data/model/BalanceTransaction.kt deleted file mode 100644 index 227f35d..0000000 --- a/app/src/main/java/com/alya/ecommerce_serang/data/model/BalanceTransaction.kt +++ /dev/null @@ -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, -) diff --git a/app/src/main/java/com/alya/ecommerce_serang/data/repository/ProductRepository.kt b/app/src/main/java/com/alya/ecommerce_serang/data/repository/ProductRepository.kt index 519b5d4..f65d677 100644 --- a/app/src/main/java/com/alya/ecommerce_serang/data/repository/ProductRepository.kt +++ b/app/src/main/java/com/alya/ecommerce_serang/data/repository/ProductRepository.kt @@ -79,6 +79,16 @@ class ProductRepository(private val apiService: ApiService) { null } } + + suspend fun fetchMyStoreProducts(): List { + 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? { diff --git a/app/src/main/java/com/alya/ecommerce_serang/ui/product/ProductViewModel.kt b/app/src/main/java/com/alya/ecommerce_serang/ui/product/ProductViewModel.kt index e349bfa..c048a13 100644 --- a/app/src/main/java/com/alya/ecommerce_serang/ui/product/ProductViewModel.kt +++ b/app/src/main/java/com/alya/ecommerce_serang/ui/product/ProductViewModel.kt @@ -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>() val reviewProduct: LiveData> get() = _reviewProduct + // For List of Products in My Store + private val _productList = MutableLiveData>>() + val productList: LiveData>> 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 // } -// } \ No newline at end of file +// } +} \ No newline at end of file diff --git a/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/balance/BalanceTransactionAdapter.kt b/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/balance/BalanceTransactionAdapter.kt index efa6f87..e106b1d 100644 --- a/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/balance/BalanceTransactionAdapter.kt +++ b/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/balance/BalanceTransactionAdapter.kt @@ -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) : RecyclerView.Adapter() { 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 9505316..3b9db9b 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 @@ -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) + } } \ No newline at end of file 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 new file mode 100644 index 0000000..09ff20c --- /dev/null +++ b/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/product/ProductAdapter.kt @@ -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, + private val onItemClick: (ProductsItem) -> Unit +) : RecyclerView.Adapter() { + + 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]) + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_product_active.xml b/app/src/main/res/drawable/bg_product_active.xml new file mode 100644 index 0000000..a652973 --- /dev/null +++ b/app/src/main/res/drawable/bg_product_active.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_product_inactive.xml b/app/src/main/res/drawable/bg_product_inactive.xml new file mode 100644 index 0000000..923c799 --- /dev/null +++ b/app/src/main/res/drawable/bg_product_inactive.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_search.png b/app/src/main/res/drawable/ic_search.png new file mode 100644 index 0000000000000000000000000000000000000000..4c0332e12afb5d1d507326b3a275a54a5a400f62 GIT binary patch literal 820 zcmV-41Izr0P)camnpcGr_-)@%^s}x*@KVSyq#l6lc(;sI}b6CCj*o~ zrqCcb^a;)fBnVUrXS^q;{O=h}y*$^4U(EBoNA5s=`-+16bL+JyYp8vSHHT0*BDy^0 ztvxp%2=Ue%LkXU=ZMG{?V&CrtScOntw5g!_m~3OTAk>kAp@<7y9D67f$T!t>0Z3hfD~@e8w!cjhAsK**=gR?!dE429B~Egq^5$EHpJ9OzJ0btbE1RRh6IhZclqbAzm_PHJ z%QX0GpBh$HqDaNb>Y#uN6vKE)Dpx3b;aVJj40lirYjGwi9woyIs)+)`j}a_MKBLN< zkX+7C9xTvFgMYkPiz-$~Jj^mv^Fh0F@qKXe z138(dV3=V|Cyi&YB=xH&jOK#8L(aQB|DcN;aISAfb%HUUT1`<-t8OJ; y0B=mFCN7pe90bAcd;G8HW8mkk%ql7>3i1~e-ZU1VcfRHT0000 - + - + - + - + - + - + tools:context=".ui.profile.mystore.product.ProductActivity" + android:orientation="vertical"> - \ No newline at end of file + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_shipping_confirmation.xml b/app/src/main/res/layout/activity_shipping_confirmation.xml index 91a3aa9..f20c38c 100644 --- a/app/src/main/res/layout/activity_shipping_confirmation.xml +++ b/app/src/main/res/layout/activity_shipping_confirmation.xml @@ -2,13 +2,16 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +