diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index f7e9e77..54fdf3b 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -29,6 +29,12 @@
android:theme="@style/Theme.Ecommerce_serang"
android:usesCleartextTraffic="true"
tools:targetApi="31">
+
+
@@ -48,7 +54,7 @@
android:name=".ui.product.storeDetail.StoreDetailActivity"
android:exported="false" />
? = null,
+
+ @field:SerializedName("message")
+ val message: String? = null
+)
diff --git a/app/src/main/java/com/alya/ecommerce_serang/data/api/response/store/sells/OrderListResponse.kt b/app/src/main/java/com/alya/ecommerce_serang/data/api/response/store/sells/OrderListResponse.kt
index 5439b14..5efc65d 100644
--- a/app/src/main/java/com/alya/ecommerce_serang/data/api/response/store/sells/OrderListResponse.kt
+++ b/app/src/main/java/com/alya/ecommerce_serang/data/api/response/store/sells/OrderListResponse.kt
@@ -129,5 +129,7 @@ data class OrdersItem(
val status: String? = null,
@field:SerializedName("city_id")
- val cityId: Int? = null
+ val cityId: Int? = null,
+
+ var displayStatus: String? = 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 a081e8e..1a04e32 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
@@ -75,6 +75,7 @@ import com.alya.ecommerce_serang.data.api.response.store.product.UpdateProductRe
import com.alya.ecommerce_serang.data.api.response.store.product.ViewStoreProductsResponse
import com.alya.ecommerce_serang.data.api.response.store.GenericResponse
import com.alya.ecommerce_serang.data.api.response.store.profile.StoreDataResponse
+import com.alya.ecommerce_serang.data.api.response.store.review.ProductReviewResponse
import com.alya.ecommerce_serang.data.api.response.store.topup.BalanceTopUpResponse
import com.alya.ecommerce_serang.data.api.response.store.topup.TopUpResponse
import okhttp3.MultipartBody
@@ -507,4 +508,8 @@ interface ApiService {
@GET("mystore/notification")
suspend fun getNotifStore(
): Response
+
+ @GET("store/reviews")
+ suspend fun getStoreProductReview(
+ ): Response
}
\ No newline at end of file
diff --git a/app/src/main/java/com/alya/ecommerce_serang/data/repository/ReviewRepository.kt b/app/src/main/java/com/alya/ecommerce_serang/data/repository/ReviewRepository.kt
new file mode 100644
index 0000000..b443a3b
--- /dev/null
+++ b/app/src/main/java/com/alya/ecommerce_serang/data/repository/ReviewRepository.kt
@@ -0,0 +1,50 @@
+package com.alya.ecommerce_serang.data.repository
+
+import com.alya.ecommerce_serang.data.api.dto.ProductsItem
+import com.alya.ecommerce_serang.data.api.response.customer.product.ProductResponse
+import com.alya.ecommerce_serang.data.api.response.store.review.ProductReviewResponse
+import com.alya.ecommerce_serang.data.api.retrofit.ApiService
+
+class ReviewRepository(private val apiService: ApiService) {
+ suspend fun getReviewList(score: String): Result {
+ return try {
+ val response = apiService.getStoreProductReview()
+
+ if (response.isSuccessful) {
+ val allReviews = response.body()
+ val filteredReviews = if (score == "all") {
+ allReviews
+ } else {
+ val targetScore = score.toIntOrNull()
+ allReviews?.copy(reviews = allReviews.reviews?.filter {
+ val rating = it?.rating ?: 0
+ when(targetScore) {
+ 5 -> rating > 4
+ 4 -> rating > 3 && rating <= 4
+ 3 -> rating > 2 && rating <= 3
+ 2 -> rating > 1 && rating <= 2
+ 1 -> rating <= 1
+ else -> true
+ }
+ })
+ }
+ Result.Success(filteredReviews!!)
+ } else {
+ Result.Error(Exception("HTTP ${response.code()}: ${response.message()}"))
+ }
+ } catch (e: Exception) {
+ Result.Error(e)
+ }
+ }
+
+ suspend fun getProductDetail(productId: Int): ProductResponse? {
+ return try {
+ val response = apiService.getDetailProduct(productId)
+ if (response.isSuccessful) {
+ response.body()
+ } else null
+ } catch (e: Exception) {
+ null
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/alya/ecommerce_serang/ui/profile/ProfileFragment.kt b/app/src/main/java/com/alya/ecommerce_serang/ui/profile/ProfileFragment.kt
index 25b7a0f..bf15129 100644
--- a/app/src/main/java/com/alya/ecommerce_serang/ui/profile/ProfileFragment.kt
+++ b/app/src/main/java/com/alya/ecommerce_serang/ui/profile/ProfileFragment.kt
@@ -16,15 +16,18 @@ import com.alya.ecommerce_serang.BuildConfig.BASE_URL
import com.alya.ecommerce_serang.R
import com.alya.ecommerce_serang.data.api.dto.UserProfile
import com.alya.ecommerce_serang.data.api.retrofit.ApiConfig
+import com.alya.ecommerce_serang.data.repository.MyStoreRepository
import com.alya.ecommerce_serang.data.repository.UserRepository
import com.alya.ecommerce_serang.databinding.FragmentProfileBinding
import com.alya.ecommerce_serang.ui.auth.LoginActivity
-import com.alya.ecommerce_serang.ui.auth.RegisterStoreActivity
+import com.alya.ecommerce_serang.ui.profile.mystore.RegisterStoreActivity
import com.alya.ecommerce_serang.ui.order.address.AddressActivity
import com.alya.ecommerce_serang.ui.order.history.HistoryActivity
import com.alya.ecommerce_serang.ui.profile.mystore.MyStoreActivity
+import com.alya.ecommerce_serang.ui.profile.mystore.StoreOnReviewActivity
import com.alya.ecommerce_serang.utils.BaseViewModelFactory
import com.alya.ecommerce_serang.utils.SessionManager
+import com.alya.ecommerce_serang.utils.viewmodel.MyStoreViewModel
import com.alya.ecommerce_serang.utils.viewmodel.ProfileViewModel
import com.bumptech.glide.Glide
import kotlinx.coroutines.delay
@@ -44,6 +47,14 @@ class ProfileFragment : Fragment() {
}
}
+ private val myStoreViewModel: MyStoreViewModel by viewModels {
+ BaseViewModelFactory {
+ val apiService = ApiConfig.getApiService(sessionManager)
+ val myStoreRepository = MyStoreRepository(apiService)
+ MyStoreViewModel(myStoreRepository)
+ }
+ }
+
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
sessionManager = SessionManager(requireContext())
@@ -59,26 +70,32 @@ class ProfileFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
+
observeUserProfile()
+
viewModel.loadUserProfile()
viewModel.checkStoreUser()
-
+ val hasStore = viewModel.checkStore.value
+ Log.d("Profile Fragment", "Check store $hasStore")
+ binding.tvBukaToko.text = if (hasStore == true) "Toko Saya" else "Buka Toko"
binding.cardBukaToko.setOnClickListener{
- val hasStore = viewModel.checkStore.value
-
- Log.d("Profile Fragment", "Check store $hasStore")
-
- if (hasStore == true){
- binding.tvBukaToko.text = "Lihat Toko Saya"
- val intentBuka = Intent(requireContext(), MyStoreActivity::class.java)
- startActivity(intentBuka)
- } else {
- binding.tvBukaToko.text = "Buka Toko"
- val intentBuka = Intent(requireContext(), RegisterStoreActivity::class.java)
- startActivity(intentBuka)
- }
+// if (hasStore == true) startActivity(Intent(requireContext(), MyStoreActivity::class.java))
+// else startActivity(Intent(requireContext(), RegisterStoreActivity::class.java))
+ if (viewModel.checkStore.value == true) {
+ myStoreViewModel.loadMyStore()
+ myStoreViewModel.myStoreProfile.observe(viewLifecycleOwner) { store ->
+ store?.let {
+ when (store.storeStatus) {
+ "active" -> startActivity(Intent(requireContext(), MyStoreActivity::class.java))
+ else -> startActivity(Intent(requireContext(), StoreOnReviewActivity::class.java))
+ }
+ } ?: run {
+ Toast.makeText(requireContext(), "Gagal memuat data toko", Toast.LENGTH_SHORT).show()
+ }
+ }
+ } else startActivity(Intent(requireContext(), RegisterStoreActivity::class.java))
}
binding.btnDetailProfile.setOnClickListener{
@@ -96,15 +113,14 @@ class ProfileFragment : Fragment() {
startActivity(intent)
}
- binding.cardLogout.setOnClickListener({
+ binding.cardLogout.setOnClickListener{
logout()
+ }
- })
-
- binding.cardAddress.setOnClickListener({
+ binding.cardAddress.setOnClickListener{
val intent = Intent(requireContext(), AddressActivity::class.java)
startActivity(intent)
- })
+ }
}
private fun observeUserProfile() {
diff --git a/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/MyStoreActivity.kt b/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/MyStoreActivity.kt
index c2a9200..4b89434 100644
--- a/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/MyStoreActivity.kt
+++ b/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/MyStoreActivity.kt
@@ -20,6 +20,7 @@ import com.alya.ecommerce_serang.ui.profile.mystore.balance.BalanceActivity
import com.alya.ecommerce_serang.ui.profile.mystore.chat.ChatListStoreActivity
import com.alya.ecommerce_serang.ui.profile.mystore.product.ProductActivity
import com.alya.ecommerce_serang.ui.profile.mystore.profile.DetailStoreProfileActivity
+import com.alya.ecommerce_serang.ui.profile.mystore.review.ReviewActivity
import com.alya.ecommerce_serang.ui.profile.mystore.review.ReviewFragment
import com.alya.ecommerce_serang.ui.profile.mystore.sells.SellsActivity
import com.alya.ecommerce_serang.utils.BaseViewModelFactory
@@ -105,25 +106,21 @@ class MyStoreActivity : AppCompatActivity() {
}
binding.tvHistory.setOnClickListener {
- val intent = Intent(this, SellsActivity::class.java)
- startActivity(intent)
+ startActivity(Intent(this, SellsActivity::class.java))
}
binding.layoutPerluTagihan.setOnClickListener {
- val intent = Intent(this, SellsActivity::class.java)
- startActivity(intent)
+ startActivity(Intent(this, SellsActivity::class.java))
//navigateToSellsFragment("pending")
}
binding.layoutPembayaran.setOnClickListener {
- val intent = Intent(this, SellsActivity::class.java)
- startActivity(intent)
+ startActivity(Intent(this, SellsActivity::class.java))
//navigateToSellsFragment("paid")
}
binding.layoutPerluDikirim.setOnClickListener {
- val intent = Intent(this, SellsActivity::class.java)
- startActivity(intent)
+ startActivity(Intent(this, SellsActivity::class.java))
//navigateToSellsFragment("processed")
}
@@ -132,15 +129,11 @@ class MyStoreActivity : AppCompatActivity() {
}
binding.layoutReview.setOnClickListener {
- supportFragmentManager.beginTransaction()
- .replace(android.R.id.content, ReviewFragment())
- .addToBackStack(null)
- .commit()
+ startActivity(Intent(this, ReviewActivity::class.java))
}
binding.layoutInbox.setOnClickListener {
- val intent = Intent(this, ChatListStoreActivity::class.java)
- startActivity(intent)
+ startActivity(Intent(this, ChatListStoreActivity::class.java))
}
}
diff --git a/app/src/main/java/com/alya/ecommerce_serang/ui/auth/RegisterStoreActivity.kt b/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/RegisterStoreActivity.kt
similarity index 88%
rename from app/src/main/java/com/alya/ecommerce_serang/ui/auth/RegisterStoreActivity.kt
rename to app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/RegisterStoreActivity.kt
index 32e36b5..a383441 100644
--- a/app/src/main/java/com/alya/ecommerce_serang/ui/auth/RegisterStoreActivity.kt
+++ b/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/RegisterStoreActivity.kt
@@ -1,7 +1,6 @@
-package com.alya.ecommerce_serang.ui.auth
+package com.alya.ecommerce_serang.ui.profile.mystore
import android.Manifest
-import android.app.Activity
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
@@ -26,6 +25,7 @@ import androidx.core.content.ContextCompat
import androidx.core.view.ViewCompat
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat
+import com.alya.ecommerce_serang.R
import com.alya.ecommerce_serang.data.api.response.auth.StoreTypesItem
import com.alya.ecommerce_serang.data.api.retrofit.ApiConfig
import com.alya.ecommerce_serang.data.repository.Result
@@ -35,6 +35,9 @@ import com.alya.ecommerce_serang.ui.order.address.CityAdapter
import com.alya.ecommerce_serang.ui.order.address.ProvinceAdapter
import com.alya.ecommerce_serang.utils.BaseViewModelFactory
import com.alya.ecommerce_serang.utils.SessionManager
+import com.alya.ecommerce_serang.utils.viewmodel.RegisterStoreViewModel
+import androidx.core.graphics.drawable.toDrawable
+import androidx.core.widget.ImageViewCompat
class RegisterStoreActivity : AppCompatActivity() {
@@ -48,15 +51,13 @@ class RegisterStoreActivity : AppCompatActivity() {
private val PICK_KTP_REQUEST = 1002
private val PICK_NPWP_REQUEST = 1003
private val PICK_NIB_REQUEST = 1004
- private val PICK_PERSETUJUAN_REQUEST = 1005
- private val PICK_QRIS_REQUEST = 1006
// Location request code
private val LOCATION_PERMISSION_REQUEST = 2001
private val viewModel: RegisterStoreViewModel by viewModels {
BaseViewModelFactory {
- val apiService = ApiConfig.getApiService(sessionManager)
+ val apiService = ApiConfig.Companion.getApiService(sessionManager)
val orderRepository = UserRepository(apiService)
RegisterStoreViewModel(orderRepository)
}
@@ -84,6 +85,8 @@ class RegisterStoreActivity : AppCompatActivity() {
windowInsets
}
+ setupHeader()
+
provinceAdapter = ProvinceAdapter(this)
cityAdapter = CityAdapter(this)
Log.d(TAG, "onCreate: Adapters initialized")
@@ -114,6 +117,9 @@ class RegisterStoreActivity : AppCompatActivity() {
Log.d(TAG, "onCreate: Fetching provinces from API")
viewModel.getProvinces()
+ viewModel.provinceId.observe(this) { validateRequiredFields() }
+ viewModel.cityId.observe(this) { validateRequiredFields() }
+ viewModel.storeTypeId.observe(this) { validateRequiredFields() }
// Setup register button
binding.btnRegister.setOnClickListener {
@@ -130,6 +136,45 @@ class RegisterStoreActivity : AppCompatActivity() {
Log.d(TAG, "onCreate: RegisterStoreActivity setup completed")
}
+ private fun setupHeader() {
+ binding.header.main.background = ContextCompat.getColor(this, R.color.blue_500).toDrawable()
+ binding.header.headerTitle.visibility = View.GONE
+ binding.header.headerLeftIcon.setColorFilter(
+ ContextCompat.getColor(this, R.color.white),
+ android.graphics.PorterDuff.Mode.SRC_IN
+ )
+ binding.header.headerLeftIcon.setOnClickListener {
+ onBackPressedDispatcher.onBackPressed()
+ finish()
+ }
+ }
+
+ private fun validateRequiredFields() {
+ val isFormValid = !viewModel.storeName.value.isNullOrBlank() &&
+ !viewModel.street.value.isNullOrBlank() &&
+ (viewModel.postalCode.value ?: 0) > 0 &&
+ !viewModel.subdistrict.value.isNullOrBlank() &&
+ !viewModel.bankName.value.isNullOrBlank() &&
+ (viewModel.bankNumber.value ?: 0) > 0 &&
+ (viewModel.provinceId.value ?: 0) > 0 &&
+ (viewModel.cityId.value ?: 0) > 0 &&
+ (viewModel.storeTypeId.value ?: 0) > 0 &&
+ viewModel.ktpUri != null &&
+ viewModel.nibUri != null &&
+ viewModel.npwpUri != null &&
+ viewModel.selectedCouriers.isNotEmpty()
+
+ binding.btnRegister.isEnabled = isFormValid
+
+ if (isFormValid) {
+ binding.btnRegister.setBackgroundResource(R.drawable.bg_button_active)
+ binding.btnRegister.setTextColor(ContextCompat.getColor(this, R.color.white))
+ } else {
+ binding.btnRegister.setBackgroundResource(R.drawable.bg_button_disabled)
+ binding.btnRegister.setTextColor(ContextCompat.getColor(this, R.color.black_300))
+ }
+ }
+
private fun setupObservers() {
Log.d(TAG, "setupObservers: Setting up LiveData observers")
@@ -138,12 +183,12 @@ class RegisterStoreActivity : AppCompatActivity() {
when (state) {
is Result.Loading -> {
Log.d(TAG, "setupObservers: Loading provinces...")
- binding.provinceProgressBar?.visibility = View.VISIBLE
+ binding.provinceProgressBar.visibility = View.VISIBLE
binding.spinnerProvince.isEnabled = false
}
is Result.Success -> {
Log.d(TAG, "setupObservers: Provinces loaded successfully: ${state.data.size} provinces")
- binding.provinceProgressBar?.visibility = View.GONE
+ binding.provinceProgressBar.visibility = View.GONE
binding.spinnerProvince.isEnabled = true
// Update adapter with data
@@ -151,7 +196,7 @@ class RegisterStoreActivity : AppCompatActivity() {
}
is Result.Error -> {
Log.e(TAG, "setupObservers: Error loading provinces: ${state.exception.message}")
- binding.provinceProgressBar?.visibility = View.GONE
+ binding.provinceProgressBar.visibility = View.GONE
binding.spinnerProvince.isEnabled = true
}
}
@@ -162,12 +207,12 @@ class RegisterStoreActivity : AppCompatActivity() {
when (state) {
is Result.Loading -> {
Log.d(TAG, "setupObservers: Loading cities...")
- binding.cityProgressBar?.visibility = View.VISIBLE
+ binding.cityProgressBar.visibility = View.VISIBLE
binding.spinnerCity.isEnabled = false
}
is Result.Success -> {
Log.d(TAG, "setupObservers: Cities loaded successfully: ${state.data.size} cities")
- binding.cityProgressBar?.visibility = View.GONE
+ binding.cityProgressBar.visibility = View.GONE
binding.spinnerCity.isEnabled = true
// Update adapter with data
@@ -175,7 +220,7 @@ class RegisterStoreActivity : AppCompatActivity() {
}
is Result.Error -> {
Log.e(TAG, "setupObservers: Error loading cities: ${state.exception.message}")
- binding.cityProgressBar?.visibility = View.GONE
+ binding.cityProgressBar.visibility = View.GONE
binding.spinnerCity.isEnabled = true
}
}
@@ -214,11 +259,11 @@ class RegisterStoreActivity : AppCompatActivity() {
Log.d(TAG, "setupStoreTypesObserver: Loading store types...")
// Show loading indicator for store types spinner
binding.spinnerStoreType.isEnabled = false
- binding.storeTypeProgressBar?.visibility = View.VISIBLE
+ binding.storeTypeProgressBar.visibility = View.VISIBLE
} else {
Log.d(TAG, "setupStoreTypesObserver: Store types loading completed")
binding.spinnerStoreType.isEnabled = true
- binding.storeTypeProgressBar?.visibility = View.GONE
+ binding.storeTypeProgressBar.visibility = View.GONE
}
}
@@ -309,7 +354,7 @@ class RegisterStoreActivity : AppCompatActivity() {
}
// Hide progress bar after setup
- binding.storeTypeProgressBar?.visibility = View.GONE
+ binding.storeTypeProgressBar.visibility = View.GONE
Log.d(TAG, "setupStoreTypeSpinner: Store type spinner setup completed")
}
@@ -398,23 +443,11 @@ class RegisterStoreActivity : AppCompatActivity() {
}
// NPWP
- binding.containerNpwp?.setOnClickListener {
+ binding.containerNpwp.setOnClickListener {
Log.d(TAG, "NPWP container clicked, picking image")
pickImage(PICK_NPWP_REQUEST)
}
- // SPPIRT
- binding.containerSppirt.setOnClickListener {
- Log.d(TAG, "SPPIRT container clicked, picking document")
- pickDocument(PICK_PERSETUJUAN_REQUEST)
- }
-
- // Halal
- binding.containerHalal.setOnClickListener {
- Log.d(TAG, "Halal container clicked, picking document")
- pickDocument(PICK_QRIS_REQUEST)
- }
-
Log.d(TAG, "setupDocumentUploads: Document upload buttons setup completed")
}
@@ -442,16 +475,16 @@ class RegisterStoreActivity : AppCompatActivity() {
handleCourierSelection("jne", isChecked)
}
- binding.checkboxJnt.setOnCheckedChangeListener { _, isChecked ->
- Log.d(TAG, "JNT checkbox ${if (isChecked) "checked" else "unchecked"}")
- handleCourierSelection("tiki", isChecked)
- }
-
binding.checkboxPos.setOnCheckedChangeListener { _, isChecked ->
Log.d(TAG, "POS checkbox ${if (isChecked) "checked" else "unchecked"}")
handleCourierSelection("pos", isChecked)
}
+ binding.checkboxTiki.setOnCheckedChangeListener { _, isChecked ->
+ Log.d(TAG, "TIKI checkbox ${if (isChecked) "checked" else "unchecked"}")
+ handleCourierSelection("tiki", isChecked)
+ }
+
Log.d(TAG, "setupCourierSelection: Courier checkboxes setup completed")
}
@@ -465,6 +498,7 @@ class RegisterStoreActivity : AppCompatActivity() {
viewModel.selectedCouriers.remove(courier)
Log.d(TAG, "handleCourierSelection: Removed courier: $courier. Current couriers: ${viewModel.selectedCouriers}")
}
+ validateRequiredFields()
}
private fun setupMap() {
@@ -516,6 +550,7 @@ class RegisterStoreActivity : AppCompatActivity() {
override fun afterTextChanged(s: Editable?) {
viewModel.storeName.value = s.toString()
Log.d(TAG, "Store name updated: ${s.toString()}")
+ validateRequiredFields()
}
})
@@ -534,6 +569,7 @@ class RegisterStoreActivity : AppCompatActivity() {
override fun afterTextChanged(s: Editable?) {
viewModel.street.value = s.toString()
Log.d(TAG, "Street address updated: ${s.toString()}")
+ validateRequiredFields()
}
})
@@ -547,6 +583,7 @@ class RegisterStoreActivity : AppCompatActivity() {
} catch (e: NumberFormatException) {
// Handle invalid input
Log.e(TAG, "Invalid postal code input: ${s.toString()}, error: $e")
+ validateRequiredFields()
}
}
})
@@ -578,6 +615,7 @@ class RegisterStoreActivity : AppCompatActivity() {
viewModel.bankNumber.value = 0 // or 0
Log.d(TAG, "Bank number set to default: 0")
}
+ validateRequiredFields()
}
})
@@ -587,6 +625,7 @@ class RegisterStoreActivity : AppCompatActivity() {
override fun afterTextChanged(s: Editable?) {
viewModel.subdistrict.value = s.toString()
Log.d(TAG, "Subdistrict updated: ${s.toString()}")
+ validateRequiredFields()
}
})
@@ -596,6 +635,7 @@ class RegisterStoreActivity : AppCompatActivity() {
override fun afterTextChanged(s: Editable?) {
viewModel.bankName.value = s.toString()
Log.d(TAG, "Bank name updated: ${s.toString()}")
+ validateRequiredFields()
}
})
@@ -605,7 +645,7 @@ class RegisterStoreActivity : AppCompatActivity() {
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
Log.d(TAG, "onActivityResult: Request code: $requestCode, Result code: $resultCode")
- if (resultCode == Activity.RESULT_OK && data != null) {
+ if (resultCode == RESULT_OK && data != null) {
val uri = data.data
Log.d(TAG, "onActivityResult: URI received: $uri")
when (requestCode) {
@@ -618,26 +658,19 @@ class RegisterStoreActivity : AppCompatActivity() {
Log.d(TAG, "KTP image selected")
viewModel.ktpUri = uri
updateImagePreview(uri, binding.imgKtp, binding.layoutUploadKtp)
+ validateRequiredFields()
}
PICK_NPWP_REQUEST -> {
Log.d(TAG, "NPWP document selected")
viewModel.npwpUri = uri
updateDocumentPreview(binding.layoutUploadNpwp)
+ validateRequiredFields()
}
PICK_NIB_REQUEST -> {
Log.d(TAG, "NIB document selected")
viewModel.nibUri = uri
updateDocumentPreview(binding.layoutUploadNib)
- }
- PICK_PERSETUJUAN_REQUEST -> {
- Log.d(TAG, "SPPIRT document selected")
- viewModel.persetujuanUri = uri
- updateDocumentPreview(binding.layoutUploadSppirt)
- }
- PICK_QRIS_REQUEST -> {
- Log.d(TAG, "Halal document selected")
- viewModel.qrisUri = uri
- updateDocumentPreview(binding.layoutUploadHalal)
+ validateRequiredFields()
}
else -> {
Log.w(TAG, "Unknown request code: $requestCode")
diff --git a/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/StoreOnReviewActivity.kt b/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/StoreOnReviewActivity.kt
new file mode 100644
index 0000000..338e5a5
--- /dev/null
+++ b/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/StoreOnReviewActivity.kt
@@ -0,0 +1,25 @@
+package com.alya.ecommerce_serang.ui.profile.mystore
+
+import android.os.Bundle
+import androidx.activity.enableEdgeToEdge
+import androidx.appcompat.app.AppCompatActivity
+import androidx.core.view.ViewCompat
+import androidx.core.view.WindowInsetsCompat
+import com.alya.ecommerce_serang.R
+import com.alya.ecommerce_serang.databinding.ActivityStoreOnReviewBinding
+
+class StoreOnReviewActivity : AppCompatActivity() {
+ private lateinit var binding: ActivityStoreOnReviewBinding
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ binding = ActivityStoreOnReviewBinding.inflate(layoutInflater)
+ setContentView(binding.root)
+
+ binding.header.headerTitle.text = "Verifikasi Pengajuan Toko"
+ binding.header.headerLeftIcon.setOnClickListener {
+ onBackPressedDispatcher.onBackPressed()
+ finish()
+ }
+ }
+}
\ No newline at end of file
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/review/ReviewActivity.kt b/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/review/ReviewActivity.kt
new file mode 100644
index 0000000..8d131ea
--- /dev/null
+++ b/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/review/ReviewActivity.kt
@@ -0,0 +1,74 @@
+package com.alya.ecommerce_serang.ui.profile.mystore.review
+
+import android.os.Bundle
+import androidx.activity.enableEdgeToEdge
+import androidx.activity.viewModels
+import androidx.appcompat.app.AppCompatActivity
+import androidx.core.view.ViewCompat
+import androidx.core.view.WindowInsetsCompat
+import androidx.fragment.app.commit
+import com.alya.ecommerce_serang.R
+import com.alya.ecommerce_serang.data.api.retrofit.ApiConfig
+import com.alya.ecommerce_serang.data.repository.ReviewRepository
+import com.alya.ecommerce_serang.databinding.ActivityReviewBinding
+import com.alya.ecommerce_serang.utils.BaseViewModelFactory
+import com.alya.ecommerce_serang.utils.SessionManager
+import com.alya.ecommerce_serang.utils.viewmodel.ReviewViewModel
+
+class ReviewActivity : AppCompatActivity() {
+ private lateinit var binding: ActivityReviewBinding
+ private lateinit var sessionManager: SessionManager
+
+ private val viewModel: ReviewViewModel by viewModels {
+ BaseViewModelFactory {
+ val apiService = ApiConfig.getApiService(sessionManager)
+ val reviewRepository = ReviewRepository(apiService)
+ ReviewViewModel(reviewRepository)
+ }
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ binding = ActivityReviewBinding.inflate(layoutInflater)
+ setContentView(binding.root)
+
+ sessionManager = SessionManager(this)
+
+ ViewCompat.setOnApplyWindowInsetsListener(binding.root) { view, windowInsets ->
+ val systemBars = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
+ view.setPadding(
+ systemBars.left,
+ systemBars.top,
+ systemBars.right,
+ systemBars.bottom
+ )
+ windowInsets
+ }
+
+ setupHeader()
+
+ viewModel.getReview("all")
+ viewModel.averageScore.observe(this) { binding.tvReviewScore.text = it }
+ viewModel.totalReview.observe(this) { binding.tvTotalReview.text = "$it rating" }
+ viewModel.totalReviewWithDesc.observe(this) { binding.tvTotalReviewWithDesc.text = "$it ulasan" }
+
+ if (savedInstanceState == null) {
+ showReviewFragment()
+ }
+ }
+
+ private fun setupHeader() {
+ binding.header.headerTitle.text = "Ulasan Pembeli"
+
+ binding.header.headerLeftIcon.setOnClickListener {
+ onBackPressed()
+ finish()
+ }
+ }
+
+ private fun showReviewFragment() {
+ supportFragmentManager.commit {
+ replace(R.id.fragment_container_reviews, ReviewFragment())
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/review/ReviewAdapter.kt b/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/review/ReviewAdapter.kt
new file mode 100644
index 0000000..5eab57f
--- /dev/null
+++ b/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/review/ReviewAdapter.kt
@@ -0,0 +1,81 @@
+package com.alya.ecommerce_serang.ui.profile.mystore.review
+
+import android.util.Log
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.ImageView
+import android.widget.TextView
+import androidx.recyclerview.widget.RecyclerView
+import com.alya.ecommerce_serang.R
+import com.alya.ecommerce_serang.data.api.dto.ReviewsItem
+import com.alya.ecommerce_serang.utils.viewmodel.ReviewViewModel
+import com.bumptech.glide.Glide
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+
+class ReviewAdapter(
+ private val viewModel: ReviewViewModel
+): RecyclerView.Adapter() {
+
+ private val reviews = mutableListOf()
+ private var fragmentScore: String = "all"
+
+ fun setFragmentScore(score: String) {
+ fragmentScore = score
+ }
+
+ fun submitList(newReviews: List) {
+ reviews.clear()
+ reviews.addAll(newReviews)
+ notifyDataSetChanged()
+ }
+
+ override fun onCreateViewHolder(
+ parent: ViewGroup,
+ viewType: Int
+ ): ReviewAdapter.ReviewViewHolder {
+ val view = LayoutInflater.from(parent.context).inflate(R.layout.item_store_product_review, parent, false)
+ return ReviewViewHolder(view)
+ }
+
+ override fun onBindViewHolder(holder: ReviewViewHolder, position: Int) {
+ if (position < reviews.size) {
+ holder.bind(reviews[position])
+ } else {
+ Log.e("ReviewAdapter", "Position $position is out of bounds for size ${reviews.size}")
+ }
+ }
+
+ override fun getItemCount(): Int = reviews.size
+
+ inner class ReviewViewHolder(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 tvReviewScore: TextView = itemView.findViewById(R.id.tv_review_score)
+ private val tvReviewDate: TextView = itemView.findViewById(R.id.tv_review_date)
+ private val tvUsername: TextView = itemView.findViewById(R.id.tv_username)
+ private val tvReviewDesc: TextView = itemView.findViewById(R.id.tv_review_desc)
+ private val ivMenu: ImageView = itemView.findViewById(R.id.iv_menu)
+
+ fun bind(review: ReviewsItem) {
+ val actualScore =
+ if (fragmentScore == "all") review.rating.toString() else fragmentScore
+
+ CoroutineScope(Dispatchers.Main).launch {
+ val imageUrl = viewModel.getProductImage(review.productId ?: -1)
+ Glide.with(itemView.context)
+ .load(imageUrl)
+ .placeholder(R.drawable.placeholder_image)
+ .into(ivProduct)
+ }
+
+ tvProductName.text = review.productName
+ tvReviewScore.text = actualScore
+ tvReviewDate.text = review.reviewDate
+ tvUsername.text = review.username
+ tvReviewDesc.text = review.reviewText
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/review/ReviewFragment.kt b/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/review/ReviewFragment.kt
index 45e553b..0b9e947 100644
--- a/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/review/ReviewFragment.kt
+++ b/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/review/ReviewFragment.kt
@@ -1,32 +1,56 @@
package com.alya.ecommerce_serang.ui.profile.mystore.review
-import androidx.fragment.app.viewModels
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
-import com.alya.ecommerce_serang.R
-import com.alya.ecommerce_serang.utils.viewmodel.ReviewViewModel
+import com.alya.ecommerce_serang.databinding.FragmentReviewBinding
+import com.alya.ecommerce_serang.utils.SessionManager
+import com.google.android.material.tabs.TabLayoutMediator
class ReviewFragment : Fragment() {
- companion object {
- fun newInstance() = ReviewFragment()
- }
+ private var _binding: FragmentReviewBinding? = null
+ private val binding get() = _binding!!
+ private lateinit var sessionManager: SessionManager
- private val viewModel: ReviewViewModel by viewModels()
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
-
- // TODO: Use the ViewModel
- }
+ private lateinit var viewPagerAdapter: ReviewViewPagerAdapter
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
- return inflater.inflate(R.layout.fragment_review, container, false)
+ _binding = FragmentReviewBinding.inflate(inflater, container, false)
+ return binding.root
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ sessionManager = SessionManager(requireContext())
+
+ setupViewPager()
+ }
+
+ private fun setupViewPager() {
+ viewPagerAdapter = ReviewViewPagerAdapter(requireActivity())
+ binding.viewPagerReview.adapter = viewPagerAdapter
+
+ TabLayoutMediator(binding.tabLayoutReview, binding.viewPagerReview) { tab, position ->
+ tab.text = when (position) {
+ 0 -> "Semua"
+ 1 -> "5 Bintang"
+ 2 -> "4 Bintang"
+ 3 -> "3 Bintang"
+ 4 -> "2 Bintang"
+ 5 -> "1 Bintang"
+ else -> "Tab $position"
+ }
+ }.attach()
+ }
+
+ 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/review/ReviewListFragment.kt b/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/review/ReviewListFragment.kt
new file mode 100644
index 0000000..029d873
--- /dev/null
+++ b/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/review/ReviewListFragment.kt
@@ -0,0 +1,123 @@
+package com.alya.ecommerce_serang.ui.profile.mystore.review
+
+import android.os.Bundle
+import android.util.Log
+import androidx.fragment.app.Fragment
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.Toast
+import androidx.fragment.app.viewModels
+import androidx.recyclerview.widget.LinearLayoutManager
+import com.alya.ecommerce_serang.R
+import com.alya.ecommerce_serang.data.api.retrofit.ApiConfig
+import com.alya.ecommerce_serang.data.repository.ReviewRepository
+import com.alya.ecommerce_serang.databinding.FragmentReviewListBinding
+import com.alya.ecommerce_serang.ui.order.address.ViewState
+import com.alya.ecommerce_serang.utils.BaseViewModelFactory
+import com.alya.ecommerce_serang.utils.SessionManager
+import com.alya.ecommerce_serang.utils.viewmodel.ProductViewModel
+import com.alya.ecommerce_serang.utils.viewmodel.ReviewViewModel
+
+class ReviewListFragment : Fragment() {
+
+ private var _binding: FragmentReviewListBinding? = null
+ private val binding get() = _binding!!
+ private lateinit var sessionManager: SessionManager
+
+ private lateinit var reviewAdapter: ReviewAdapter
+ private val viewModel: ReviewViewModel by viewModels {
+ BaseViewModelFactory {
+ val apiService = ApiConfig.getApiService(SessionManager(requireContext()))
+ ReviewViewModel(ReviewRepository(apiService))
+ }
+ }
+
+ private var score: String = "all"
+
+ companion object {
+ private const val ARG_SCORE = "score"
+
+ fun newInstance(score: String): ReviewListFragment = ReviewListFragment().apply {
+ arguments = Bundle().apply {
+ putString(ARG_SCORE, score)
+ }
+ }
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ sessionManager = SessionManager(requireContext())
+ score = arguments?.getString(ARG_SCORE) ?: "all"
+ }
+
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View? {
+ _binding = FragmentReviewListBinding.inflate(inflater, container, false)
+ return binding.root
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ reviewAdapter = ReviewAdapter(viewModel)
+ binding.rvReview.apply {
+ layoutManager = LinearLayoutManager(requireContext())
+ adapter = reviewAdapter
+ }
+
+ observeReviewList()
+ fetchReviewByScore(score)
+ }
+
+ private fun fetchReviewByScore(score: String) {
+ val normalizedScore = when (score) {
+ "all" -> "all"
+ else -> {
+ val scoreValue = score.toDoubleOrNull() ?: 0.0
+ when {
+ scoreValue > 4.5 -> "5"
+ scoreValue > 3.5 -> "4"
+ scoreValue > 2.5 -> "3"
+ scoreValue > 1.5 -> "2"
+ else -> "1"
+ }
+ }
+ }
+ viewModel.getReview(normalizedScore)
+ }
+
+ private fun observeReviewList() {
+ viewModel.review.observe(viewLifecycleOwner) { result ->
+ when (result) {
+ is ViewState.Success -> {
+ val data = result.data.orEmpty().sortedByDescending { it.reviewDate }
+ binding.progressBar.visibility = View.GONE
+
+ if (data.isEmpty()) {
+ binding.tvEmptyState.visibility = View.VISIBLE
+ binding.rvReview.visibility = View.GONE
+ } else {
+ binding.tvEmptyState.visibility = View.GONE
+ binding.rvReview.visibility = View.VISIBLE
+ reviewAdapter.submitList(data)
+ }
+ }
+
+ is ViewState.Loading -> binding.progressBar.visibility = View.VISIBLE
+ is ViewState.Error -> {
+ binding.progressBar.visibility = View.GONE
+ binding.tvEmptyState.visibility = View.VISIBLE
+ Toast.makeText(requireContext(), result.message, Toast.LENGTH_SHORT).show()
+ }
+ }
+ }
+ }
+
+ 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/review/ReviewViewPagerAdapter.kt b/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/review/ReviewViewPagerAdapter.kt
new file mode 100644
index 0000000..8973690
--- /dev/null
+++ b/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/review/ReviewViewPagerAdapter.kt
@@ -0,0 +1,24 @@
+package com.alya.ecommerce_serang.ui.profile.mystore.review
+
+import androidx.fragment.app.Fragment
+import androidx.fragment.app.FragmentActivity
+import androidx.viewpager2.adapter.FragmentStateAdapter
+
+class ReviewViewPagerAdapter(
+ fragmentActivity: FragmentActivity
+) : FragmentStateAdapter(fragmentActivity) {
+ private val reviewScore = listOf(
+ "all",
+ "5",
+ "4",
+ "3",
+ "2",
+ "1"
+ )
+
+ override fun getItemCount(): Int = reviewScore.size
+
+ override fun createFragment(position: Int): Fragment {
+ return ReviewListFragment.newInstance(reviewScore[position])
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/sells/SellsAdapter.kt b/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/sells/SellsAdapter.kt
index 4fadaab..38342be 100644
--- a/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/sells/SellsAdapter.kt
+++ b/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/sells/SellsAdapter.kt
@@ -86,7 +86,7 @@ class SellsAdapter(
Log.d("SellsAdapter", "=== ViewHolder.bind() called ===")
Log.d("SellsAdapter", "Binding order: ${order.orderId} with status: ${order.status}")
- val actualStatus = if (fragmentStatus == "all") order.status ?: "" else fragmentStatus
+ val actualStatus = if (fragmentStatus == "all") order.displayStatus ?: "" else fragmentStatus
adjustDisplay(actualStatus, order)
tvSellsNumber.text = "No. Pesanan: ${order.orderId}"
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/java/com/alya/ecommerce_serang/ui/auth/RegisterStoreViewModel.kt b/app/src/main/java/com/alya/ecommerce_serang/utils/viewmodel/RegisterStoreViewModel.kt
similarity index 96%
rename from app/src/main/java/com/alya/ecommerce_serang/ui/auth/RegisterStoreViewModel.kt
rename to app/src/main/java/com/alya/ecommerce_serang/utils/viewmodel/RegisterStoreViewModel.kt
index b29fa41..ae9b8f4 100644
--- a/app/src/main/java/com/alya/ecommerce_serang/ui/auth/RegisterStoreViewModel.kt
+++ b/app/src/main/java/com/alya/ecommerce_serang/utils/viewmodel/RegisterStoreViewModel.kt
@@ -1,4 +1,4 @@
-package com.alya.ecommerce_serang.ui.auth
+package com.alya.ecommerce_serang.utils.viewmodel
import android.content.Context
import android.net.Uri
@@ -21,8 +21,8 @@ class RegisterStoreViewModel(
) : ViewModel() {
// LiveData for UI state
- private val _registerState = MutableLiveData>()
- val registerState: LiveData> = _registerState
+ private val _registerState = MutableLiveData>()
+ val registerState: LiveData> = _registerState
private val _storeTypes = MutableLiveData>()
val storeTypes: LiveData> = _storeTypes
@@ -141,7 +141,7 @@ class RegisterStoreViewModel(
_registerState.value = result
} catch (e: Exception) {
- _registerState.value = com.alya.ecommerce_serang.data.repository.Result.Error(e)
+ _registerState.value = Result.Error(e)
}
}
}
diff --git a/app/src/main/java/com/alya/ecommerce_serang/utils/viewmodel/ReviewViewModel.kt b/app/src/main/java/com/alya/ecommerce_serang/utils/viewmodel/ReviewViewModel.kt
index 3959502..2493692 100644
--- a/app/src/main/java/com/alya/ecommerce_serang/utils/viewmodel/ReviewViewModel.kt
+++ b/app/src/main/java/com/alya/ecommerce_serang/utils/viewmodel/ReviewViewModel.kt
@@ -1,7 +1,71 @@
package com.alya.ecommerce_serang.utils.viewmodel
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import com.alya.ecommerce_serang.BuildConfig.BASE_URL
+import com.alya.ecommerce_serang.data.api.dto.ReviewsItem
+import com.alya.ecommerce_serang.data.repository.Result
+import com.alya.ecommerce_serang.data.repository.ReviewRepository
+import com.alya.ecommerce_serang.ui.order.address.ViewState
+import kotlinx.coroutines.launch
+import kotlin.getOrThrow
-class ReviewViewModel : ViewModel() {
- // TODO: Implement the ViewModel
+class ReviewViewModel(private val repository: ReviewRepository) : ViewModel() {
+
+ private val _review = MutableLiveData>>()
+ val review: LiveData>> = _review
+
+ private val _averageScore = MutableLiveData()
+ val averageScore: LiveData = _averageScore
+
+ private val _totalReview = MutableLiveData()
+ val totalReview: LiveData = _totalReview
+
+ private val _totalReviewWithDesc = MutableLiveData()
+ val totalReviewWithDesc: LiveData = _totalReviewWithDesc
+
+ private val _isLoading = MutableLiveData()
+ val isLoading: LiveData = _isLoading
+
+ private val productImageCache = mutableMapOf()
+
+ fun getReview(score: String) {
+ _review.value = ViewState.Loading
+ viewModelScope.launch {
+ try {
+ val response = repository.getReviewList(score)
+ if (response is Result.Success) {
+ val reviews = response.data.reviews?.filterNotNull().orEmpty()
+ _review.value = ViewState.Success(reviews)
+
+ if (score == "all") {
+ val avg = if (reviews.isNotEmpty()) {
+ reviews.mapNotNull { it.rating }.average()
+ } else 0.0
+ _averageScore.value = String.format("%.1f", avg)
+ _totalReview.value = reviews.size
+ _totalReviewWithDesc.value = reviews.count { !it.reviewText.isNullOrBlank() }
+ }
+ } else if (response is Result.Error) {
+ _review.value = ViewState.Error(response.exception.message ?: "Gagal memuat ulasan")
+ }
+ } catch (e: Exception) {
+ _review.value = ViewState.Error(e.message ?: "Terjadi kesalahan")
+ }
+ }
+ }
+
+ suspend fun getProductImage(productId: Int): String? {
+ if (productImageCache.containsKey(productId)) {
+ return productImageCache[productId]
+ }
+ val result = repository.getProductDetail(productId)
+ val imageUrl = if (result?.product?.image?.startsWith("/") == true) {
+ BASE_URL + result.product.image.removePrefix("/")
+ } else result?.product?.image
+ productImageCache[productId] = imageUrl.toString()
+ return imageUrl.toString()
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/alya/ecommerce_serang/utils/viewmodel/SellsViewModel.kt b/app/src/main/java/com/alya/ecommerce_serang/utils/viewmodel/SellsViewModel.kt
index c5c0d73..05a26aa 100644
--- a/app/src/main/java/com/alya/ecommerce_serang/utils/viewmodel/SellsViewModel.kt
+++ b/app/src/main/java/com/alya/ecommerce_serang/utils/viewmodel/SellsViewModel.kt
@@ -14,7 +14,12 @@ import com.alya.ecommerce_serang.data.api.response.store.sells.PaymentConfirmati
import com.alya.ecommerce_serang.data.repository.Result
import com.alya.ecommerce_serang.data.repository.SellsRepository
import com.alya.ecommerce_serang.ui.order.address.ViewState
+import kotlinx.coroutines.async
+import kotlinx.coroutines.awaitAll
+import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.launch
+import java.text.SimpleDateFormat
+import java.util.Locale
class SellsViewModel(private val repository: SellsRepository) : ViewModel() {
@@ -59,79 +64,128 @@ class SellsViewModel(private val repository: SellsRepository) : ViewModel() {
Log.d(TAG, "Coroutine launched successfully")
try {
- Log.d(TAG, "Calling repository.getSellList(status='$status')")
- val startTime = System.currentTimeMillis()
+ if(status == "all") {
+ Log.d(TAG, "Status is 'all', calling repository.getSellList()")
+ val allStatuses = listOf("pending", "unpaid", "processed", "shipped")
+ val allSells = mutableListOf()
- when (val result = repository.getSellList(status)) {
- is Result.Success -> {
- val endTime = System.currentTimeMillis()
- Log.d(TAG, "Repository call completed in ${endTime - startTime}ms")
- Log.d(TAG, "Result.Success received from repository")
-
- // Log the entire result data structure
- Log.d(TAG, "Raw result data: ${result.data}")
- Log.d(TAG, "Result data class: ${result.data.javaClass.simpleName}")
-
- val orders = result.data.orders
- Log.d(TAG, "Extracted orders list: $orders")
- Log.d(TAG, "Orders list class: ${orders.javaClass.simpleName}")
- Log.d(TAG, "Orders count: ${orders.size}")
-
- // Check if orders list is null or empty
- if (false) {
- Log.w(TAG, "⚠️ Orders list is NULL")
- } else if (orders.isEmpty()) {
- Log.w(TAG, "⚠️ Orders list is EMPTY")
- } else {
- Log.d(TAG, "✅ Orders list contains ${orders.size} items")
-
- // Log individual order details with more comprehensive info
- orders.forEachIndexed { index, order ->
- Log.d(TAG, "--- Order ${index + 1}/${orders.size} ---")
- Log.d(TAG, " Order object: $order")
- Log.d(TAG, " Order class: ${order.javaClass.simpleName}")
- Log.d(TAG, " - ID: ${order.orderId}")
- Log.d(TAG, " - Status: '${order.status}'")
- Log.d(TAG, " - Customer: '${order.username}'")
- Log.d(TAG, " - Total: ${order.totalAmount}")
- Log.d(TAG, " - Items count: ${order.orderItems?.size ?: 0}")
- Log.d(TAG, " - Created at: ${order.createdAt}")
- Log.d(TAG, " - Updated at: ${order.updatedAt}")
-
- // Log order items if available
- order.orderItems?.let { items ->
- Log.d(TAG, " Order items:")
- items.forEachIndexed { itemIndex, item ->
- Log.d(TAG, " Item ${itemIndex + 1}: ${item?.productName} (Qty: ${item?.quantity})")
+ coroutineScope {
+ val deferreds = allStatuses.map { status ->
+ async {
+ when (val result = repository.getSellList(status)) {
+ is Result.Success -> {
+ result.data.orders.onEach { it.displayStatus = status }
}
+
+ is Result.Error -> {
+ Log.e(
+ TAG,
+ "Error loading orders for status $status",
+ result.exception
+ )
+ emptyList()
+ }
+
+ is Result.Loading -> emptyList()
}
}
}
- // Set the ViewState to Success
- _sells.value = ViewState.Success(orders)
- Log.d(TAG, "✅ ViewState.Success set with ${orders.size} orders")
+ deferreds.awaitAll().forEach { orders ->
+ allSells.addAll(orders)
+ }
}
- is Result.Error -> {
- val endTime = System.currentTimeMillis()
- Log.e(TAG, "Repository call failed in ${endTime - startTime}ms")
- Log.e(TAG, "❌ Result.Error received from repository")
- Log.e(TAG, "Error message: ${result.exception.message}")
- Log.e(TAG, "Exception type: ${result.exception.javaClass.simpleName}")
- Log.e(TAG, "Exception stack trace:", result.exception)
-
- val errorMessage = result.exception.message ?: "Unknown error occurred"
- _sells.value = ViewState.Error(errorMessage)
- Log.d(TAG, "ViewState.Error set with message: '$errorMessage'")
+ val sortedSells = allSells.sortedByDescending { order ->
+ try {
+ SimpleDateFormat(
+ "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'",
+ Locale.getDefault()
+ ).parse(order.createdAt)
+ } catch (e: Exception) {
+ null
+ }
}
- is Result.Loading -> {
- Log.d(TAG, "Result.Loading received from repository (this is unusual)")
- // Keep the current loading state
+ _sells.value = ViewState.Success(sortedSells)
+ Log.d(TAG, "All orders loaded successfully: ${sortedSells.size} items")
+ } else {
+ Log.d(TAG, "Calling repository.getSellList(status='$status')")
+ val startTime = System.currentTimeMillis()
+
+ when (val result = repository.getSellList(status)) {
+ is Result.Success -> {
+ val endTime = System.currentTimeMillis()
+ Log.d(TAG, "Repository call completed in ${endTime - startTime}ms")
+ Log.d(TAG, "Result.Success received from repository")
+
+ // Log the entire result data structure
+ Log.d(TAG, "Raw result data: ${result.data}")
+ Log.d(TAG, "Result data class: ${result.data.javaClass.simpleName}")
+
+ val orders = result.data.orders
+ Log.d(TAG, "Extracted orders list: $orders")
+ Log.d(TAG, "Orders list class: ${orders.javaClass.simpleName}")
+ Log.d(TAG, "Orders count: ${orders.size}")
+
+ // Check if orders list is null or empty
+ if (false) {
+ Log.w(TAG, "⚠️ Orders list is NULL")
+ } else if (orders.isEmpty()) {
+ Log.w(TAG, "⚠️ Orders list is EMPTY")
+ } else {
+ Log.d(TAG, "✅ Orders list contains ${orders.size} items")
+
+ // Log individual order details with more comprehensive info
+ orders.forEachIndexed { index, order ->
+ Log.d(TAG, "--- Order ${index + 1}/${orders.size} ---")
+ Log.d(TAG, " Order object: $order")
+ Log.d(TAG, " Order class: ${order.javaClass.simpleName}")
+ Log.d(TAG, " - ID: ${order.orderId}")
+ Log.d(TAG, " - Status: '${order.status}'")
+ Log.d(TAG, " - Customer: '${order.username}'")
+ Log.d(TAG, " - Total: ${order.totalAmount}")
+ Log.d(TAG, " - Items count: ${order.orderItems?.size ?: 0}")
+ Log.d(TAG, " - Created at: ${order.createdAt}")
+ Log.d(TAG, " - Updated at: ${order.updatedAt}")
+
+ // Log order items if available
+ order.orderItems?.let { items ->
+ Log.d(TAG, " Order items:")
+ items.forEachIndexed { itemIndex, item ->
+ Log.d(
+ TAG,
+ " Item ${itemIndex + 1}: ${item?.productName} (Qty: ${item?.quantity})"
+ )
+ }
+ }
+ }
+ }
+
+ // Set the ViewState to Success
+ _sells.value = ViewState.Success(orders)
+ Log.d(TAG, "✅ ViewState.Success set with ${orders.size} orders")
+ }
+
+ is Result.Error -> {
+ val endTime = System.currentTimeMillis()
+ Log.e(TAG, "Repository call failed in ${endTime - startTime}ms")
+ Log.e(TAG, "❌ Result.Error received from repository")
+ Log.e(TAG, "Error message: ${result.exception.message}")
+ Log.e(TAG, "Exception type: ${result.exception.javaClass.simpleName}")
+ Log.e(TAG, "Exception stack trace:", result.exception)
+
+ val errorMessage = result.exception.message ?: "Unknown error occurred"
+ _sells.value = ViewState.Error(errorMessage)
+ Log.d(TAG, "ViewState.Error set with message: '$errorMessage'")
+ }
+
+ is Result.Loading -> {
+ Log.d(TAG, "Result.Loading received from repository (this is unusual)")
+ // Keep the current loading state
+ }
}
}
-
} catch (e: Exception) {
Log.e(TAG, "❌ Exception caught in getSellList")
Log.e(TAG, "Exception type: ${e.javaClass.simpleName}")
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 0000000..4acefe2
Binary files /dev/null and b/app/src/main/res/drawable/ic_add.png differ
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 0000000..9d7ed0b
Binary files /dev/null and b/app/src/main/res/drawable/ic_minus.png differ
diff --git a/app/src/main/res/drawable/ic_under_review.png b/app/src/main/res/drawable/ic_under_review.png
new file mode 100644
index 0000000..973390b
Binary files /dev/null and b/app/src/main/res/drawable/ic_under_review.png differ
diff --git a/app/src/main/res/layout/activity_register_store.xml b/app/src/main/res/layout/activity_register_store.xml
index 2ac26d7..7f2a7cf 100644
--- a/app/src/main/res/layout/activity_register_store.xml
+++ b/app/src/main/res/layout/activity_register_store.xml
@@ -6,7 +6,11 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
- tools:context=".ui.auth.RegisterStoreActivity">
+ tools:context=".ui.profile.mystore.RegisterStoreActivity">
+
+
+ android:textColor="@color/white"
+ style="@style/headline_large" />
+ android:text="@string/buka_toko_desc"
+ android:textColor="@color/white" />
@@ -46,510 +48,874 @@
android:orientation="vertical"
android:padding="16dp">
-
-
-
-
-
+ android:orientation="horizontal">
-
+
-
+
-
+
-
+
+ android:orientation="vertical"
+ android:layout_marginVertical="24dp">
-
+
-
+
-
+
+
+
+
+
+
+
+
+
-
+ android:orientation="vertical"
+ android:layout_marginBottom="24dp">
-
+
+
-
+
+
+
-
+ android:orientation="vertical"
+ android:layout_marginBottom="24dp">
-
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ android:orientation="vertical"
+ android:layout_marginBottom="24dp">
-
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ android:orientation="vertical"
+ android:layout_marginBottom="24dp">
-
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ android:orientation="vertical"
+ android:layout_marginBottom="24dp">
-
+
-
+
-
+
-
+
+
+
+
+
+
+
+ android:orientation="vertical"
+ android:layout_marginBottom="24dp">
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+ android:orientation="vertical"
+ android:layout_marginBottom="24dp">
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+ android:orientation="vertical"
+ android:layout_marginBottom="24dp">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+ android:text="17. Pilih Titik Lokasi Usaha"
+ style="@style/body_medium"
+ android:layout_marginEnd="4dp"/>
-
+ android:layout_weight="1"
+ android:text="*"
+ style="@style/body_medium"
+ android:textColor="@color/red_required"
+ android:layout_gravity="end"/>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ android:text="Daftar" />
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_review.xml b/app/src/main/res/layout/activity_review.xml
new file mode 100644
index 0000000..40b70c0
--- /dev/null
+++ b/app/src/main/res/layout/activity_review.xml
@@ -0,0 +1,85 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_store_on_review.xml b/app/src/main/res/layout/activity_store_on_review.xml
new file mode 100644
index 0000000..bcb2910
--- /dev/null
+++ b/app/src/main/res/layout/activity_store_on_review.xml
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_change_price_bottom_sheet.xml b/app/src/main/res/layout/fragment_change_price_bottom_sheet.xml
index 9e7b5ba..81252e8 100644
--- a/app/src/main/res/layout/fragment_change_price_bottom_sheet.xml
+++ b/app/src/main/res/layout/fragment_change_price_bottom_sheet.xml
@@ -1,14 +1,50 @@
-
+ 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
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/fragment_change_stock_bottom_sheet.xml b/app/src/main/res/layout/fragment_change_stock_bottom_sheet.xml
new file mode 100644
index 0000000..1de3cc8
--- /dev/null
+++ b/app/src/main/res/layout/fragment_change_stock_bottom_sheet.xml
@@ -0,0 +1,62 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_review.xml b/app/src/main/res/layout/fragment_review.xml
index dace922..84f61b0 100644
--- a/app/src/main/res/layout/fragment_review.xml
+++ b/app/src/main/res/layout/fragment_review.xml
@@ -1,13 +1,32 @@
-
-
+ android:layout_height="wrap_content"
+ app:tabMode="scrollable"
+ app:tabTextAppearance="@style/label_medium_prominent"
+ app:tabSelectedTextAppearance="@style/label_medium_prominent"
+ app:tabIndicatorColor="@color/blue_500"
+ app:tabSelectedTextColor="@color/blue_500"
+ app:tabTextColor="@color/black_300"
+ app:tabBackground="@color/white"
+ app:tabPadding="13dp"
+ app:layout_constraintTop_toTopOf="parent"/>
-
\ No newline at end of file
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_review_list.xml b/app/src/main/res/layout/fragment_review_list.xml
new file mode 100644
index 0000000..19438d4
--- /dev/null
+++ b/app/src/main/res/layout/fragment_review_list.xml
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_sells.xml b/app/src/main/res/layout/fragment_sells.xml
index 70e8e3f..2d20d1e 100644
--- a/app/src/main/res/layout/fragment_sells.xml
+++ b/app/src/main/res/layout/fragment_sells.xml
@@ -9,7 +9,7 @@
tools:context=".ui.profile.mystore.sells.SellsFragment">
+ app:layout_constraintTop_toBottomOf="@+id/tab_layout_sells" />
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_sells_list.xml b/app/src/main/res/layout/fragment_sells_list.xml
index c74d548..8dd8bae 100644
--- a/app/src/main/res/layout/fragment_sells_list.xml
+++ b/app/src/main/res/layout/fragment_sells_list.xml
@@ -7,7 +7,7 @@
tools:context=".ui.profile.mystore.sells.SellsListFragment">
+ android:background="@null">
+ app:contentInsetStartWithNavigation="0dp"
+ android:background="@null">
+ android:orientation="vertical"
+ android:clickable="true"
+ android:focusable="true">
+ android:layout_marginStart="8dp"
+ android:clickable="true"
+ android:focusable="true"/>
diff --git a/app/src/main/res/layout/item_store_product_review.xml b/app/src/main/res/layout/item_store_product_review.xml
new file mode 100644
index 0000000..43b14c6
--- /dev/null
+++ b/app/src/main/res/layout/item_store_product_review.xml
@@ -0,0 +1,105 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index f85637e..e84f11b 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -145,6 +145,7 @@
Disconnected. Reconnecting...
Connection error: %1$s
User is typing...
+ Mohon untuk melengkapi formulir pendaftaran ini agar dapat mengakses fitur penjual pada aplikasi.
\ No newline at end of file