mirror of
https://github.com/shaulascr/ecommerce_serang.git
synced 2025-12-15 15:41:02 +00:00
update dialog pop up and fix display picture
This commit is contained in:
@ -5,10 +5,9 @@ import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.widget.Toast
|
||||
import androidx.activity.enableEdgeToEdge
|
||||
import androidx.activity.viewModels
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.view.WindowCompat
|
||||
import com.alya.ecommerce_serang.R
|
||||
import com.alya.ecommerce_serang.data.api.dto.FcmReq
|
||||
import com.alya.ecommerce_serang.data.api.retrofit.ApiConfig
|
||||
import com.alya.ecommerce_serang.data.repository.Result
|
||||
@ -16,6 +15,7 @@ import com.alya.ecommerce_serang.data.repository.UserRepository
|
||||
import com.alya.ecommerce_serang.databinding.ActivityLoginBinding
|
||||
import com.alya.ecommerce_serang.ui.MainActivity
|
||||
import com.alya.ecommerce_serang.utils.BaseViewModelFactory
|
||||
import com.alya.ecommerce_serang.utils.PopUpDialog
|
||||
import com.alya.ecommerce_serang.utils.SessionManager
|
||||
import com.alya.ecommerce_serang.utils.viewmodel.LoginViewModel
|
||||
import com.google.firebase.FirebaseApp
|
||||
@ -39,9 +39,9 @@ class LoginActivity : AppCompatActivity() {
|
||||
|
||||
binding = ActivityLoginBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
WindowCompat.setDecorFitsSystemWindows(window, false)
|
||||
enableEdgeToEdge()
|
||||
//
|
||||
// WindowCompat.setDecorFitsSystemWindows(window, false)
|
||||
// enableEdgeToEdge()
|
||||
|
||||
setupListeners()
|
||||
observeLoginState()
|
||||
@ -83,6 +83,11 @@ class LoginActivity : AppCompatActivity() {
|
||||
retrieveFCMToken()
|
||||
// sessionManager.saveUserId(response.userId)
|
||||
|
||||
PopUpDialog.showConfirmDialog(
|
||||
context = this,
|
||||
iconRes = R.drawable.checkmark__1_,
|
||||
title = "Berhasil Masuk"
|
||||
)
|
||||
Toast.makeText(this, "Berhasil masuk", Toast.LENGTH_SHORT).show()
|
||||
|
||||
startActivity(Intent(this, MainActivity::class.java))
|
||||
@ -90,6 +95,11 @@ class LoginActivity : AppCompatActivity() {
|
||||
}
|
||||
is com.alya.ecommerce_serang.data.repository.Result.Error -> {
|
||||
Log.e("LoginActivity", "Login Failed: ${result.exception.message}")
|
||||
PopUpDialog.showConfirmDialog(
|
||||
context = this,
|
||||
iconRes = R.drawable.ic_cancel,
|
||||
title = "Gagal Masuk"
|
||||
)
|
||||
Toast.makeText(this, "Gagal masuk", Toast.LENGTH_LONG).show()
|
||||
}
|
||||
is Result.Loading -> {
|
||||
|
||||
@ -5,13 +5,14 @@ import android.util.Log
|
||||
import android.view.View
|
||||
import android.widget.Toast
|
||||
import androidx.activity.viewModels
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import com.alya.ecommerce_serang.R
|
||||
import com.alya.ecommerce_serang.data.api.retrofit.ApiConfig
|
||||
import com.alya.ecommerce_serang.data.repository.Result
|
||||
import com.alya.ecommerce_serang.data.repository.UserRepository
|
||||
import com.alya.ecommerce_serang.databinding.ActivityResetPassBinding
|
||||
import com.alya.ecommerce_serang.utils.BaseViewModelFactory
|
||||
import com.alya.ecommerce_serang.utils.PopUpDialog
|
||||
import com.alya.ecommerce_serang.utils.viewmodel.LoginViewModel
|
||||
|
||||
class ResetPassActivity : AppCompatActivity() {
|
||||
@ -36,7 +37,7 @@ class ResetPassActivity : AppCompatActivity() {
|
||||
|
||||
setupToolbar()
|
||||
setupUI()
|
||||
|
||||
observeResetPassword()
|
||||
}
|
||||
|
||||
private fun setupToolbar(){
|
||||
@ -98,26 +99,23 @@ class ResetPassActivity : AppCompatActivity() {
|
||||
private fun handleSuccess(message: String) {
|
||||
Toast.makeText(this, message, Toast.LENGTH_LONG).show()
|
||||
|
||||
// Show success dialog and navigate back to login
|
||||
AlertDialog.Builder(this)
|
||||
.setTitle("Berhasil Ubah Password")
|
||||
.setMessage(message)
|
||||
.setPositiveButton("OK") { _, _ ->
|
||||
// Navigate back to login activity
|
||||
finish()
|
||||
}
|
||||
.setCancelable(false)
|
||||
.show()
|
||||
PopUpDialog.showConfirmDialog(
|
||||
context = this,
|
||||
iconRes = R.drawable.checkmark__1_,
|
||||
title = "Berhasil Ubah Password",
|
||||
positiveText = "OK"
|
||||
)
|
||||
}
|
||||
|
||||
private fun handleError(errorMessage: String) {
|
||||
Log.e(TAG, "Error: $errorMessage")
|
||||
|
||||
// Optionally show error dialog
|
||||
AlertDialog.Builder(this)
|
||||
.setTitle("Gagal Ubah Password")
|
||||
.setMessage(errorMessage)
|
||||
.setPositiveButton("OK", null)
|
||||
.show()
|
||||
PopUpDialog.showConfirmDialog(
|
||||
context = this,
|
||||
iconRes = R.drawable.ic_cancel,
|
||||
title = "Gagal Ubah Password",
|
||||
message = errorMessage,
|
||||
positiveText = "OK"
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -27,6 +27,7 @@ import com.alya.ecommerce_serang.ui.order.address.SubdsitrictAdapter
|
||||
import com.alya.ecommerce_serang.ui.order.address.ViewState
|
||||
import com.alya.ecommerce_serang.ui.order.address.VillagesAdapter
|
||||
import com.alya.ecommerce_serang.utils.BaseViewModelFactory
|
||||
import com.alya.ecommerce_serang.utils.PopUpDialog
|
||||
import com.alya.ecommerce_serang.utils.SessionManager
|
||||
import com.alya.ecommerce_serang.utils.viewmodel.RegisterViewModel
|
||||
import com.google.android.material.progressindicator.LinearProgressIndicator
|
||||
@ -108,7 +109,16 @@ class RegisterStep3Fragment : Fragment() {
|
||||
}
|
||||
|
||||
binding.btnRegister.setOnClickListener {
|
||||
submitAddress()
|
||||
PopUpDialog.showConfirmDialog(
|
||||
context = requireContext(),
|
||||
title = "Apakah anda yakin data anda sudah benar?",
|
||||
message = "Pastikan data yang dimasukkan sudah benar",
|
||||
positiveText = "Ya",
|
||||
negativeText = "Tidak",
|
||||
onYesClicked = {
|
||||
submitAddress()
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
// Observe address submission state
|
||||
@ -498,6 +508,7 @@ class RegisterStep3Fragment : Fragment() {
|
||||
|
||||
private fun showRegistrationSuccess() {
|
||||
// Now we can show the success message for the overall registration process
|
||||
|
||||
Toast.makeText(requireContext(), "Berhasil mendaftarkan akun", Toast.LENGTH_LONG).show()
|
||||
sessionManager.clearAll()
|
||||
|
||||
|
||||
@ -43,8 +43,6 @@ class CartActivity : AppCompatActivity() {
|
||||
super.onCreate(savedInstanceState)
|
||||
sessionManager = SessionManager(this)
|
||||
apiService = ApiConfig.getApiService(sessionManager)
|
||||
|
||||
|
||||
binding = ActivityCartBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
@ -201,7 +199,8 @@ class CartActivity : AppCompatActivity() {
|
||||
|
||||
viewModel.errorMessage.observe(this) { errorMessage ->
|
||||
errorMessage?.let {
|
||||
Toast.makeText(this, it, Toast.LENGTH_SHORT).show()
|
||||
binding.emptyCart.visibility = View.VISIBLE
|
||||
Log.e("CartActivity", "Error message: $it")
|
||||
}
|
||||
}
|
||||
|
||||
@ -254,6 +253,10 @@ class CartActivity : AppCompatActivity() {
|
||||
storeAdapter.updateWholesaleStatus(wholesaleStatusMap, wholesalePriceMap)
|
||||
}
|
||||
}
|
||||
|
||||
viewModel.productImages.observe(this) { productImages ->
|
||||
storeAdapter.updateProductImages(productImages)
|
||||
}
|
||||
}
|
||||
|
||||
private fun showEmptyState(isEmpty: Boolean) {
|
||||
@ -272,5 +275,5 @@ class CartActivity : AppCompatActivity() {
|
||||
val format = NumberFormat.getCurrencyInstance(Locale("id", "ID"))
|
||||
return format.format(amount).replace("Rp", "Rp ")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -8,6 +8,7 @@ import androidx.lifecycle.viewModelScope
|
||||
import com.alya.ecommerce_serang.data.api.dto.UpdateCart
|
||||
import com.alya.ecommerce_serang.data.api.response.customer.cart.DataItemCart
|
||||
import com.alya.ecommerce_serang.data.api.response.customer.product.CartItemCheckoutInfo
|
||||
import com.alya.ecommerce_serang.data.api.response.customer.product.Product
|
||||
import com.alya.ecommerce_serang.data.repository.OrderRepository
|
||||
import com.alya.ecommerce_serang.data.repository.Result
|
||||
import kotlinx.coroutines.launch
|
||||
@ -52,6 +53,12 @@ class CartViewModel(private val repository: OrderRepository) : ViewModel() {
|
||||
private val _hasConsistentWholesaleStatus = MutableLiveData<Boolean>(true)
|
||||
val hasConsistentWholesaleStatus: LiveData<Boolean> = _hasConsistentWholesaleStatus
|
||||
|
||||
private val _productDetail = MutableLiveData<Product?>()
|
||||
val productDetail: LiveData<Product?> get() = _productDetail
|
||||
|
||||
private val _productImages = MutableLiveData<Map<Int, String>>()
|
||||
val productImages: LiveData<Map<Int, String>> = _productImages
|
||||
|
||||
fun getCart() {
|
||||
_isLoading.value = true
|
||||
_errorMessage.value = null
|
||||
@ -62,6 +69,12 @@ class CartViewModel(private val repository: OrderRepository) : ViewModel() {
|
||||
_cartItems.value = result.data
|
||||
_isLoading.value = false
|
||||
|
||||
result.data.forEach { store ->
|
||||
store.cartItems.forEach { item ->
|
||||
loadProductImage(item.productId)
|
||||
}
|
||||
}
|
||||
|
||||
// After loading cart items, check wholesale status
|
||||
checkWholesaleStatus()
|
||||
}
|
||||
@ -404,4 +417,29 @@ class CartViewModel(private val repository: OrderRepository) : ViewModel() {
|
||||
|
||||
_hasConsistentWholesaleStatus.value = allSameStatus
|
||||
}
|
||||
|
||||
fun loadProductImage(productId: Int) {
|
||||
viewModelScope.launch {
|
||||
try {
|
||||
val result = repository.fetchProductDetail(productId)
|
||||
val imageUrl = result?.product?.image ?: ""
|
||||
|
||||
val currentMap = _productImages.value?.toMutableMap() ?: mutableMapOf()
|
||||
currentMap[productId] = imageUrl
|
||||
_productImages.value = currentMap
|
||||
|
||||
} catch (e: Exception) {
|
||||
Log.e("CartViewModel", "Error loading product image: ${e.message}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// fun loadProductDetail(productId: Int) {
|
||||
// viewModelScope.launch {
|
||||
// val result = repository.fetchProductDetail(productId)
|
||||
// val currentMap = _productImages.value?.toMutableMap() ?: mutableMapOf()
|
||||
// currentMap[productId] = result?.product?.image ?: ""
|
||||
// _productImages.value = currentMap
|
||||
// }
|
||||
// }
|
||||
}
|
||||
@ -11,6 +11,7 @@ import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.alya.ecommerce_serang.BuildConfig.BASE_URL
|
||||
import com.alya.ecommerce_serang.R
|
||||
import com.alya.ecommerce_serang.data.api.response.customer.cart.CartItemsItem
|
||||
import com.alya.ecommerce_serang.data.api.response.customer.cart.DataItemCart
|
||||
@ -30,6 +31,12 @@ class StoreAdapter(
|
||||
private var activeStoreId: Int? = null
|
||||
private var wholesaleStatusMap: Map<Int, Boolean> = mapOf()
|
||||
private var wholesalePriceMap: Map<Int, Double> = mapOf()
|
||||
private var productImages: Map<Int, String> = emptyMap()
|
||||
|
||||
fun updateProductImages(newImages: Map<Int, String>) {
|
||||
productImages = newImages
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val VIEW_TYPE_STORE = 0
|
||||
@ -135,7 +142,8 @@ class StoreAdapter(
|
||||
wholesalePrice,
|
||||
{ isChecked -> onItemCheckChanged(cartItem.cartItemId, store.storeId, isChecked) },
|
||||
{ quantity -> onItemQuantityChanged(cartItem.cartItemId, quantity) },
|
||||
{ onItemDeleted(cartItem.cartItemId) }
|
||||
{ onItemDeleted(cartItem.cartItemId) },
|
||||
productImages
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -197,7 +205,8 @@ class StoreAdapter(
|
||||
wholesalePrice: Double?,
|
||||
onCheckedChange: (Boolean) -> Unit,
|
||||
onQuantityChanged: (Int) -> Unit,
|
||||
onDelete: () -> Unit
|
||||
onDelete: () -> Unit,
|
||||
productImages: Map<Int, String>
|
||||
) {
|
||||
// Set product name
|
||||
tvProductName.text = cartItem.productName
|
||||
@ -216,20 +225,6 @@ class StoreAdapter(
|
||||
// Set quantity
|
||||
tvQuantity.text = cartItem.quantity.toString()
|
||||
|
||||
// Visual indication for wholesale items
|
||||
// if (isWholesale) {
|
||||
// // You can add a background or border to indicate wholesale items
|
||||
// // For example:
|
||||
//// itemView.setBackgroundResource(R.drawable.bg_wholesale_item)
|
||||
// // If you don't have this drawable, you can use a simple color tint instead:
|
||||
// itemView.setBackgroundColor(ContextCompat.getColor(itemView.context, R.color.wholesale_item_bg))
|
||||
// } else {
|
||||
// // Reset to default background
|
||||
//// itemView.setBackgroundResource(R.drawable.bg_normal_item)
|
||||
// // Or if you don't have this drawable:
|
||||
// itemView.setBackgroundColor(ContextCompat.getColor(itemView.context, R.color.normal_item_bg))
|
||||
// }
|
||||
|
||||
// Set checkbox state without triggering listener
|
||||
cbItem.setOnCheckedChangeListener(null)
|
||||
cbItem.isChecked = isSelected
|
||||
@ -247,11 +242,16 @@ class StoreAdapter(
|
||||
onCheckedChange(isChecked)
|
||||
}
|
||||
|
||||
// Load product image
|
||||
val fullImageUrl = when (val img = productImages[cartItem.productId]) {
|
||||
is String -> {
|
||||
if (img.startsWith("/")) BASE_URL + img.substring(1) else img
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
|
||||
Glide.with(itemView.context)
|
||||
.load("https://example.com/images/${cartItem.productId}.jpg") // Assume image URL based on product ID
|
||||
.load(fullImageUrl)
|
||||
.placeholder(R.drawable.placeholder_image)
|
||||
.error(R.drawable.placeholder_image)
|
||||
.into(ivProduct)
|
||||
|
||||
// Quantity control
|
||||
|
||||
@ -1,9 +1,11 @@
|
||||
package com.alya.ecommerce_serang.ui.order
|
||||
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.alya.ecommerce_serang.BuildConfig.BASE_URL
|
||||
import com.alya.ecommerce_serang.R
|
||||
import com.alya.ecommerce_serang.data.api.dto.CheckoutData
|
||||
import com.alya.ecommerce_serang.data.api.response.customer.cart.CartItemsItem
|
||||
@ -13,37 +15,57 @@ import com.bumptech.glide.Glide
|
||||
import java.text.NumberFormat
|
||||
import java.util.Locale
|
||||
|
||||
class CartCheckoutAdapter(private val checkoutData: CheckoutData) :
|
||||
RecyclerView.Adapter<CartCheckoutAdapter.SellerViewHolder>() {
|
||||
class CartCheckoutAdapter(
|
||||
private val checkoutData: CheckoutData
|
||||
) : RecyclerView.Adapter<CartCheckoutAdapter.SellerViewHolder>() {
|
||||
|
||||
class SellerViewHolder(val binding: ItemOrderSellerBinding) : RecyclerView.ViewHolder(binding.root)
|
||||
private var productImages: Map<Int, String> = emptyMap()
|
||||
private val viewHolders = mutableListOf<SellerViewHolder>() // Keep references
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SellerViewHolder {
|
||||
val binding = ItemOrderSellerBinding.inflate(
|
||||
LayoutInflater.from(parent.context), parent, false
|
||||
)
|
||||
return SellerViewHolder(binding)
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int = 1 // Only one seller
|
||||
|
||||
override fun onBindViewHolder(holder: SellerViewHolder, position: Int) {
|
||||
with(holder.binding) {
|
||||
// Set seller name
|
||||
tvStoreName.text = checkoutData.sellerName
|
||||
|
||||
// Set up products RecyclerView with multiple items
|
||||
rvSellerOrderProduct.apply {
|
||||
layoutManager = LinearLayoutManager(context)
|
||||
adapter = MultiCartItemsAdapter(checkoutData.cartItems)
|
||||
class SellerViewHolder(val binding: ItemOrderSellerBinding) : RecyclerView.ViewHolder(binding.root) {
|
||||
val childAdapter = MultiCartItemsAdapter(emptyList(), emptyMap())
|
||||
init {
|
||||
binding.rvSellerOrderProduct.apply {
|
||||
layoutManager = LinearLayoutManager(binding.root.context)
|
||||
adapter = childAdapter
|
||||
isNestedScrollingEnabled = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SellerViewHolder {
|
||||
val binding = ItemOrderSellerBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||
val holder = SellerViewHolder(binding)
|
||||
viewHolders.add(holder) // Keep reference
|
||||
return holder
|
||||
}
|
||||
|
||||
fun updateProductImages(newImages: Map<Int, String>) {
|
||||
productImages = newImages
|
||||
// Update all existing child adapters
|
||||
viewHolders.forEach { holder ->
|
||||
holder.childAdapter.updateProductImages(newImages)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int = 1
|
||||
|
||||
override fun onBindViewHolder(holder: SellerViewHolder, position: Int) {
|
||||
holder.binding.tvStoreName.text = checkoutData.sellerName
|
||||
holder.childAdapter.updateData(checkoutData.cartItems)
|
||||
holder.childAdapter.updateProductImages(productImages) // Apply current images
|
||||
}
|
||||
|
||||
override fun onViewRecycled(holder: SellerViewHolder) {
|
||||
super.onViewRecycled(holder)
|
||||
viewHolders.remove(holder) // Clean up reference
|
||||
}
|
||||
}
|
||||
|
||||
class MultiCartItemsAdapter(private val cartItems: List<CartItemsItem>) :
|
||||
RecyclerView.Adapter<MultiCartItemsAdapter.CartItemViewHolder>() {
|
||||
class MultiCartItemsAdapter(
|
||||
private var cartItems: List<CartItemsItem> = emptyList(),
|
||||
private var productImages: Map<Int, String> = emptyMap()
|
||||
) : RecyclerView.Adapter<MultiCartItemsAdapter.CartItemViewHolder>() {
|
||||
|
||||
class CartItemViewHolder(val binding: ItemOrderProductBinding) : RecyclerView.ViewHolder(binding.root)
|
||||
|
||||
@ -56,24 +78,57 @@ class MultiCartItemsAdapter(private val cartItems: List<CartItemsItem>) :
|
||||
|
||||
override fun getItemCount(): Int = cartItems.size
|
||||
|
||||
fun updateProductImages(images: Map<Int, String>) {
|
||||
Log.d("MultiCartItemsAdapter", "updateProductImages called with: $images")
|
||||
Log.d("MultiCartItemsAdapter", "Current cartItems productIds: ${cartItems.map { it.productId }}")
|
||||
productImages = images
|
||||
notifyDataSetChanged()
|
||||
Log.d("MultiCartItemsAdapter", "notifyDataSetChanged() called")
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: CartItemViewHolder, position: Int) {
|
||||
val item = cartItems[position]
|
||||
Log.d("MultiCartItemsAdapter", "onBindViewHolder - position: $position, productId: ${item.productId}")
|
||||
Log.d("MultiCartItemsAdapter", "Available images: $productImages")
|
||||
|
||||
with(holder.binding) {
|
||||
// Set cart item details
|
||||
tvProductName.text = item.productName
|
||||
tvProductQuantity.text = "${item.quantity} buah"
|
||||
tvProductPrice.text = formatCurrency(item.price.toDouble())
|
||||
|
||||
// Load placeholder image
|
||||
val img = productImages[item.productId]
|
||||
Log.d("MultiCartItemsAdapter", "Image for productId ${item.productId}: $img")
|
||||
|
||||
val fullImageUrl = when (img) {
|
||||
is String -> {
|
||||
val url = if (img.startsWith("/")) BASE_URL + img.substring(1) else img
|
||||
Log.d("MultiCartItemsAdapter", "Full image URL: $url")
|
||||
url
|
||||
}
|
||||
else -> {
|
||||
Log.d("MultiCartItemsAdapter", "No image found, using placeholder")
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
Log.d("MultiCartItemsAdapter", "Loading image with Glide: $fullImageUrl")
|
||||
Glide.with(ivProduct.context)
|
||||
.load(R.drawable.placeholder_image)
|
||||
.load(fullImageUrl)
|
||||
.placeholder(R.drawable.placeholder_image)
|
||||
.error(R.drawable.placeholder_image) // Add error handling
|
||||
.into(ivProduct)
|
||||
}
|
||||
}
|
||||
|
||||
// Minimal helpers to update adapter data from parent adapter
|
||||
fun updateData(items: List<CartItemsItem>) {
|
||||
cartItems = items
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
|
||||
private fun formatCurrency(amount: Double): String {
|
||||
val formatter = NumberFormat.getCurrencyInstance(Locale("in", "ID"))
|
||||
return formatter.format(amount).replace(",00", "")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -36,6 +36,8 @@ class CheckoutActivity : AppCompatActivity() {
|
||||
private lateinit var binding: ActivityCheckoutBinding
|
||||
private lateinit var sessionManager: SessionManager
|
||||
private var paymentAdapter: PaymentMethodAdapter? = null
|
||||
private var cartCheckoutAdapter: CartCheckoutAdapter? = null
|
||||
private var checkoutSellerAdapter: CheckoutSellerAdapter? = null
|
||||
private var paymentMethodsLoaded = false
|
||||
|
||||
private val viewModel: CheckoutViewModel by viewModels {
|
||||
@ -210,6 +212,13 @@ class CheckoutActivity : AppCompatActivity() {
|
||||
finish()
|
||||
}
|
||||
}
|
||||
|
||||
viewModel.productImages.observe(this) { images ->
|
||||
Log.d("CheckoutActivity", "Product images updated: ${images.keys}")
|
||||
// Update adapter when images arrive
|
||||
cartCheckoutAdapter?.updateProductImages(images)
|
||||
checkoutSellerAdapter?.updateProductImages(images)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupPaymentMethodsRecyclerView(paymentMethods: List<DetailPaymentItem>) {
|
||||
@ -271,24 +280,44 @@ class CheckoutActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
private fun setupProductRecyclerView(checkoutData: CheckoutData) {
|
||||
val adapter = if (checkoutData.isBuyNow || checkoutData.cartItems.size <= 1) {
|
||||
CheckoutSellerAdapter(checkoutData)
|
||||
if (checkoutData.isBuyNow || checkoutData.cartItems.size <= 1) {
|
||||
Log.d("CheckoutActivity", "Using CheckoutSellerAdapter")
|
||||
val adapter = CheckoutSellerAdapter(checkoutData)
|
||||
|
||||
// Keep reference for image updates - create a field in your activity
|
||||
checkoutSellerAdapter = adapter
|
||||
|
||||
binding.rvProductItems.apply {
|
||||
layoutManager = LinearLayoutManager(this@CheckoutActivity)
|
||||
this.adapter = adapter
|
||||
isNestedScrollingEnabled = false
|
||||
}
|
||||
|
||||
// Load images for cart items
|
||||
if (!checkoutData.isBuyNow) {
|
||||
checkoutData.cartItems.forEach { item ->
|
||||
viewModel.loadProductImage(item.productId)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
CartCheckoutAdapter(checkoutData)
|
||||
}
|
||||
Log.d("CheckoutActivity", "Using CartCheckoutAdapter")
|
||||
Log.d("CheckoutActivity", "Cart items count: ${checkoutData.cartItems.size}")
|
||||
|
||||
binding.rvProductItems.apply {
|
||||
layoutManager = LinearLayoutManager(this@CheckoutActivity)
|
||||
this.adapter = adapter
|
||||
isNestedScrollingEnabled = false
|
||||
}
|
||||
// Create adapter and keep reference
|
||||
cartCheckoutAdapter = CartCheckoutAdapter(checkoutData)
|
||||
|
||||
// if (checkoutData.cartItems.isEmpty()) {
|
||||
// // Show empty products state
|
||||
// binding.containerEmptyProducts.visibility = View.VISIBLE
|
||||
// binding.rvProductItems.visibility = View.GONE
|
||||
// return
|
||||
// }
|
||||
binding.rvProductItems.apply {
|
||||
layoutManager = LinearLayoutManager(this@CheckoutActivity)
|
||||
adapter = cartCheckoutAdapter
|
||||
isNestedScrollingEnabled = false
|
||||
}
|
||||
|
||||
// Load images for each product
|
||||
checkoutData.cartItems.forEach { item ->
|
||||
Log.d("CheckoutActivity", "Loading image for productId: ${item.productId}")
|
||||
viewModel.loadProductImage(item.productId)
|
||||
}
|
||||
}
|
||||
|
||||
binding.containerEmptyProducts.visibility = View.GONE
|
||||
binding.rvProductItems.visibility = View.VISIBLE
|
||||
@ -375,7 +404,7 @@ class CheckoutActivity : AppCompatActivity() {
|
||||
if (validateOrder()) {
|
||||
PopUpDialog.showConfirmDialog(
|
||||
context = this,
|
||||
title = "Apakah anda yakin inging membuat pesanan?",
|
||||
title = "Apakah anda yakin membuat pesanan?",
|
||||
message = "Pastikan data yang dimasukkan sudah benar",
|
||||
positiveText = "Ya",
|
||||
negativeText = "Tidak",
|
||||
|
||||
@ -11,31 +11,53 @@ import com.alya.ecommerce_serang.databinding.ItemOrderSellerBinding
|
||||
class CheckoutSellerAdapter(private val checkoutData: CheckoutData) :
|
||||
RecyclerView.Adapter<CheckoutSellerAdapter.SellerViewHolder>() {
|
||||
|
||||
private var productImages: Map<Int, String> = emptyMap()
|
||||
private var currentViewHolder: SellerViewHolder? = null
|
||||
|
||||
class SellerViewHolder(val binding: ItemOrderSellerBinding) : RecyclerView.ViewHolder(binding.root)
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SellerViewHolder {
|
||||
val binding = ItemOrderSellerBinding.inflate(
|
||||
LayoutInflater.from(parent.context), parent, false
|
||||
)
|
||||
return SellerViewHolder(binding)
|
||||
val holder = SellerViewHolder(binding)
|
||||
currentViewHolder = holder
|
||||
return holder
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int = 1 // Only one seller
|
||||
fun updateProductImages(newImages: Map<Int, String>) {
|
||||
productImages = newImages
|
||||
currentViewHolder?.let { holder ->
|
||||
// Update the nested adapter
|
||||
val adapter = holder.binding.rvSellerOrderProduct.adapter
|
||||
when (adapter) {
|
||||
is SingleCartItemAdapter -> adapter.updateProductImages(newImages)
|
||||
is SingleProductAdapter -> {
|
||||
// For SingleProductAdapter, you might need to update differently
|
||||
// since it uses checkoutData.productImageUrl
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int = 1
|
||||
|
||||
override fun onBindViewHolder(holder: SellerViewHolder, position: Int) {
|
||||
currentViewHolder = holder
|
||||
with(holder.binding) {
|
||||
// Set seller name
|
||||
tvStoreName.text = checkoutData.sellerName
|
||||
|
||||
// Set up products RecyclerView
|
||||
rvSellerOrderProduct.apply {
|
||||
layoutManager = LinearLayoutManager(context)
|
||||
adapter = if (checkoutData.isBuyNow) {
|
||||
// Single product for Buy Now
|
||||
SingleProductAdapter(checkoutData)
|
||||
} else {
|
||||
// Single cart item
|
||||
SingleCartItemAdapter(checkoutData.cartItems.first())
|
||||
SingleCartItemAdapter(checkoutData.cartItems.first()).also { adapter ->
|
||||
// Apply existing images if available
|
||||
if (productImages.isNotEmpty()) {
|
||||
adapter.updateProductImages(productImages)
|
||||
}
|
||||
}
|
||||
}
|
||||
isNestedScrollingEnabled = false
|
||||
}
|
||||
|
||||
@ -40,6 +40,11 @@ class CheckoutViewModel(private val repository: OrderRepository) : ViewModel() {
|
||||
private val _orderCreated = MutableLiveData<Boolean>()
|
||||
val orderCreated: LiveData<Boolean> = _orderCreated
|
||||
|
||||
private val _productImages = MutableLiveData<Map<Int, String>>(emptyMap())
|
||||
val productImages: LiveData<Map<Int, String>> = _productImages
|
||||
|
||||
private val currentImages = mutableMapOf<Int, String>()
|
||||
|
||||
// Initialize "Buy Now" checkout
|
||||
fun initializeBuyNow(
|
||||
storeId: Int,
|
||||
@ -156,9 +161,13 @@ class CheckoutViewModel(private val repository: OrderRepository) : ViewModel() {
|
||||
)
|
||||
|
||||
Log.d(TAG, "CheckoutData initialized with ${matchingItems.size} items")
|
||||
matchingItems.forEachIndexed { index, item ->
|
||||
val isWholesale = isWholesaleMap[item.cartItemId] ?: false
|
||||
Log.d(TAG, "Item $index: ${item.productName}, Price: ${item.price}, IsWholesale: $isWholesale")
|
||||
matchingItems.forEach { item ->
|
||||
Log.d("CheckoutViewModel", "About to load image for productId: ${item.productId}")
|
||||
loadProductImage(item.productId)
|
||||
}
|
||||
|
||||
matchingItems.forEach { item ->
|
||||
loadProductImage(item.productId)
|
||||
}
|
||||
|
||||
// Calculate totals with updated prices
|
||||
@ -179,6 +188,8 @@ class CheckoutViewModel(private val repository: OrderRepository) : ViewModel() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
fun getPaymentMethods() {
|
||||
viewModelScope.launch {
|
||||
try {
|
||||
@ -417,6 +428,31 @@ class CheckoutViewModel(private val repository: OrderRepository) : ViewModel() {
|
||||
}
|
||||
}
|
||||
|
||||
fun loadProductImage(productId: Int) {
|
||||
Log.d("CheckoutViewModel", "loadProductImage called for productId: $productId")
|
||||
viewModelScope.launch {
|
||||
try {
|
||||
Log.d("CheckoutViewModel", "Fetching product detail for productId: $productId")
|
||||
val productDetail = repository.fetchProductDetail(productId)
|
||||
Log.d("CheckoutViewModel", "Product detail result: $productDetail")
|
||||
|
||||
val imageUrl = productDetail?.product?.image
|
||||
Log.d("CheckoutViewModel", "Extracted image URL: $imageUrl")
|
||||
|
||||
currentImages[productId] = imageUrl.toString()
|
||||
Log.d("CheckoutViewModel", "Updated currentImages: $currentImages")
|
||||
|
||||
_productImages.postValue(currentImages.toMap())
|
||||
Log.d("CheckoutViewModel", "Posted to _productImages LiveData")
|
||||
} catch (e: Exception) {
|
||||
Log.e("CheckoutViewModel", "Error loading image for productId $productId", e)
|
||||
// fallback if error
|
||||
currentImages[productId] = ""
|
||||
_productImages.postValue(currentImages.toMap())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get shipping price
|
||||
private fun getShippingPrice(): Double {
|
||||
val data = _checkoutData.value ?: return 0.0
|
||||
@ -431,4 +467,5 @@ class CheckoutViewModel(private val repository: OrderRepository) : ViewModel() {
|
||||
companion object {
|
||||
private const val TAG = "CheckoutViewModel"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -3,6 +3,7 @@ package com.alya.ecommerce_serang.ui.order
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.alya.ecommerce_serang.BuildConfig.BASE_URL
|
||||
import com.alya.ecommerce_serang.R
|
||||
import com.alya.ecommerce_serang.data.api.response.customer.cart.CartItemsItem
|
||||
import com.alya.ecommerce_serang.databinding.ItemOrderProductBinding
|
||||
@ -13,6 +14,8 @@ import java.util.Locale
|
||||
class SingleCartItemAdapter(private val cartItem: CartItemsItem) :
|
||||
RecyclerView.Adapter<SingleCartItemAdapter.CartItemViewHolder>() {
|
||||
|
||||
private var productImages: Map<Int, String> = emptyMap()
|
||||
|
||||
class CartItemViewHolder(val binding: ItemOrderProductBinding) : RecyclerView.ViewHolder(binding.root)
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CartItemViewHolder {
|
||||
@ -24,16 +27,28 @@ class SingleCartItemAdapter(private val cartItem: CartItemsItem) :
|
||||
|
||||
override fun getItemCount(): Int = 1
|
||||
|
||||
fun updateProductImages(newImages: Map<Int, String>) {
|
||||
productImages = newImages
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: CartItemViewHolder, position: Int) {
|
||||
with(holder.binding) {
|
||||
// Set cart item details
|
||||
tvProductName.text = cartItem.productName
|
||||
tvProductQuantity.text = "${cartItem.quantity} buah"
|
||||
tvProductPrice.text = formatCurrency(cartItem.price.toDouble())
|
||||
|
||||
// Load placeholder image
|
||||
// Get the image for this product
|
||||
val img = productImages[cartItem.productId]
|
||||
val fullImageUrl = when (img) {
|
||||
is String -> {
|
||||
if (img.startsWith("/")) BASE_URL + img.substring(1) else img
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
|
||||
Glide.with(ivProduct.context)
|
||||
.load(R.drawable.placeholder_image)
|
||||
.load(fullImageUrl)
|
||||
.placeholder(R.drawable.placeholder_image)
|
||||
.error(R.drawable.placeholder_image)
|
||||
.into(ivProduct)
|
||||
|
||||
@ -3,6 +3,7 @@ package com.alya.ecommerce_serang.ui.order
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.alya.ecommerce_serang.BuildConfig.BASE_URL
|
||||
import com.alya.ecommerce_serang.R
|
||||
import com.alya.ecommerce_serang.data.api.dto.CheckoutData
|
||||
import com.alya.ecommerce_serang.data.api.dto.OrderRequestBuy
|
||||
@ -36,9 +37,16 @@ class SingleProductAdapter(private val checkoutData: CheckoutData) :
|
||||
|
||||
tvProductPrice.text = formatCurrency(checkoutData.productPrice)
|
||||
|
||||
val fullImageUrl = when (val img = checkoutData.productImageUrl) {
|
||||
is String -> {
|
||||
if (img.startsWith("/")) BASE_URL + img.substring(1) else img
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
|
||||
// Load product image
|
||||
Glide.with(ivProduct.context)
|
||||
.load(checkoutData.productImageUrl)
|
||||
.load(fullImageUrl)
|
||||
.apply(
|
||||
RequestOptions()
|
||||
.placeholder(R.drawable.placeholder_image)
|
||||
|
||||
@ -33,6 +33,7 @@ import com.alya.ecommerce_serang.data.repository.OrderRepository
|
||||
import com.alya.ecommerce_serang.data.repository.Result
|
||||
import com.alya.ecommerce_serang.databinding.ActivityAddEvidencePaymentBinding
|
||||
import com.alya.ecommerce_serang.utils.BaseViewModelFactory
|
||||
import com.alya.ecommerce_serang.utils.PopUpDialog
|
||||
import com.alya.ecommerce_serang.utils.SessionManager
|
||||
import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
||||
import okhttp3.MultipartBody
|
||||
@ -166,6 +167,7 @@ class AddEvidencePaymentActivity : AppCompatActivity() {
|
||||
|
||||
// Submit button
|
||||
binding.btnSubmit.setOnClickListener {
|
||||
|
||||
validateAndUpload()
|
||||
Log.d(TAG, "AddEvidencePaymentActivity onCreate completed")
|
||||
}
|
||||
@ -313,12 +315,14 @@ class AddEvidencePaymentActivity : AppCompatActivity() {
|
||||
return
|
||||
}
|
||||
|
||||
//in case applied metode pembayaran yang lain
|
||||
// if (binding.spinnerPaymentMethod.selectedItemPosition == 0) {
|
||||
// Toast.makeText(this, "Silahkan pilih metode pembayaran", Toast.LENGTH_SHORT).show()
|
||||
// return
|
||||
// }
|
||||
binding.etAccountNumber.visibility = View.GONE
|
||||
|
||||
//in case applied nomor rekening
|
||||
// if (binding.etAccountNumber.text.toString().trim().isEmpty()) {
|
||||
// Toast.makeText(this, "Silahkan isi nomor rekening/HP", Toast.LENGTH_SHORT).show()
|
||||
// return
|
||||
@ -330,8 +334,16 @@ class AddEvidencePaymentActivity : AppCompatActivity() {
|
||||
// }
|
||||
|
||||
// All validations passed, proceed with upload
|
||||
uploadPaymentProof()
|
||||
|
||||
PopUpDialog.showConfirmDialog(
|
||||
context = this,
|
||||
title = "Apakah bukti yang dikirimkan sudah benar?",
|
||||
message = "Pastikan bukti yang dikirimkan valid",
|
||||
positiveText = "Ya",
|
||||
negativeText = "Tidak",
|
||||
onYesClicked = {
|
||||
uploadPaymentProof()
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private fun uploadPaymentProof() {
|
||||
|
||||
@ -232,7 +232,6 @@ class PaymentActivity : AppCompatActivity() {
|
||||
else -> emptyList()
|
||||
}
|
||||
|
||||
// Tampilkan instruksi dalam dialog
|
||||
val dialog = AlertDialog.Builder(this)
|
||||
.setTitle("Petunjuk Transfer $type")
|
||||
.setItems(instructions.toTypedArray(), null)
|
||||
|
||||
@ -57,6 +57,14 @@ class HistoryActivity : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
// override fun onDialogConfirmed() {
|
||||
// // Option 1: refresh activity
|
||||
// recreate()
|
||||
//
|
||||
// // Or Option 2: reload only data
|
||||
// // viewModel.loadOrders()
|
||||
// }
|
||||
|
||||
private fun setupToolbar() {
|
||||
setSupportActionBar(binding.toolbar)
|
||||
supportActionBar?.setDisplayShowTitleEnabled(false)
|
||||
|
||||
@ -231,19 +231,21 @@ class HistoryViewModel(private val repository: OrderRepository) : ViewModel() {
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun refresh(status: String) {
|
||||
fun refresh(status: String) {
|
||||
Log.d(TAG, "⏳ refresh(\"$status\") started")
|
||||
|
||||
try {
|
||||
if (status == "all") {
|
||||
Log.d(TAG, "🌐 Calling getAllOrdersCombined()")
|
||||
getAllOrdersCombined() // network → cache
|
||||
} else {
|
||||
Log.d(TAG, "🌐 repository.getOrderList(\"$status\")")
|
||||
repository.getOrderList(status) // network → cache
|
||||
viewModelScope.launch {
|
||||
if (status == "all") {
|
||||
Log.d(TAG, "🌐 Calling getAllOrdersCombined()")
|
||||
getAllOrdersCombined() // network → cache
|
||||
} else {
|
||||
Log.d(TAG, "🌐 repository.getOrderList(\"$status\")")
|
||||
repository.getOrderList(status) // network → cache
|
||||
}
|
||||
Log.d(TAG, "✅ refresh(\"$status\") completed (repository updated)")
|
||||
// Flow that watches DB/cache will emit automatically
|
||||
}
|
||||
Log.d(TAG, "✅ refresh(\"$status\") completed (repository updated)")
|
||||
// Flow that watches DB/cache will emit automatically
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "❌ refresh(\"$status\") failed: ${e.message}", e)
|
||||
}
|
||||
|
||||
@ -28,6 +28,7 @@ import com.alya.ecommerce_serang.ui.order.detail.PaymentActivity
|
||||
import com.alya.ecommerce_serang.ui.order.history.cancelorder.CancelOrderBottomSheet
|
||||
import com.alya.ecommerce_serang.ui.order.review.CreateReviewActivity
|
||||
import com.alya.ecommerce_serang.ui.product.ReviewProductActivity
|
||||
import com.alya.ecommerce_serang.utils.PopUpDialog
|
||||
import com.google.android.material.button.MaterialButton
|
||||
import com.google.android.material.textfield.TextInputLayout
|
||||
import com.google.gson.Gson
|
||||
@ -41,7 +42,8 @@ import java.util.TimeZone
|
||||
class OrderHistoryAdapter(
|
||||
private val onOrderClickListener: (OrdersItem) -> Unit,
|
||||
private val viewModel: HistoryViewModel,
|
||||
private val callbacks: OrderActionCallbacks
|
||||
private val callbacks: OrderActionCallbacks,
|
||||
private val listener: OnDialogActionListener
|
||||
) : RecyclerView.Adapter<OrderHistoryAdapter.OrderViewHolder>() {
|
||||
|
||||
interface OrderActionCallbacks {
|
||||
@ -237,9 +239,18 @@ class OrderHistoryAdapter(
|
||||
callbacks.onShowLoading(true)
|
||||
|
||||
// Call ViewModel
|
||||
viewModel.confirmOrderCompleted(order.orderId, "completed")
|
||||
PopUpDialog.showConfirmDialog(
|
||||
context = itemView.context,
|
||||
title = "Apakah anda yakin pesanan sudah sampai?",
|
||||
message = "Pastikan pesanan sudah samapi di alamat tujuan",
|
||||
positiveText = "Ya",
|
||||
negativeText = "Tidak",
|
||||
onYesClicked = {
|
||||
viewModel.confirmOrderCompleted(order.orderId, "completed")
|
||||
listener.onDialogConfirmed()
|
||||
}
|
||||
)
|
||||
// viewModel.refreshOrders()
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -520,9 +531,19 @@ class OrderHistoryAdapter(
|
||||
val bottomSheet = CancelOrderBottomSheet(
|
||||
orderId = orderId,
|
||||
onOrderCancelled = {
|
||||
callbacks.onOrderCancelled(orderId.toString(), true, "Order cancelled successfully")
|
||||
// Show a success message
|
||||
Toast.makeText(context, "Pesanan berhasil dibatalkan", Toast.LENGTH_SHORT).show()
|
||||
|
||||
PopUpDialog.showConfirmDialog(
|
||||
context = itemView.context,
|
||||
title = "Apakah anda yakin ingin membatalkan pesanan?",
|
||||
positiveText = "Ya",
|
||||
negativeText = "Tidak",
|
||||
onYesClicked = {
|
||||
callbacks.onOrderCancelled(orderId.toString(), true, "Order cancelled successfully")
|
||||
// Show a success message
|
||||
Toast.makeText(context, "Pesanan berhasil dibatalkan", Toast.LENGTH_SHORT).show()
|
||||
listener.onDialogConfirmed()
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
@ -602,4 +623,8 @@ class OrderHistoryAdapter(
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface OnDialogActionListener {
|
||||
fun onDialogConfirmed()
|
||||
}
|
||||
@ -24,7 +24,7 @@ import com.alya.ecommerce_serang.ui.order.history.detailorder.DetailOrderStatusA
|
||||
import com.alya.ecommerce_serang.utils.BaseViewModelFactory
|
||||
import com.alya.ecommerce_serang.utils.SessionManager
|
||||
|
||||
class OrderListFragment : Fragment(), OrderHistoryAdapter.OrderActionCallbacks {
|
||||
class OrderListFragment : Fragment(), OrderHistoryAdapter.OrderActionCallbacks, OnDialogActionListener {
|
||||
|
||||
private var _binding: FragmentOrderListBinding? = null
|
||||
private val binding get() = _binding!!
|
||||
@ -93,7 +93,8 @@ class OrderListFragment : Fragment(), OrderHistoryAdapter.OrderActionCallbacks {
|
||||
navigateToOrderDetail(order)
|
||||
},
|
||||
viewModel = viewModel,
|
||||
callbacks = this // Pass this fragment as callback
|
||||
callbacks = this,
|
||||
listener = this// Pass this fragment as callback
|
||||
)
|
||||
|
||||
orderAdapter.setFragmentStatus(status)
|
||||
@ -175,7 +176,6 @@ class OrderListFragment : Fragment(), OrderHistoryAdapter.OrderActionCallbacks {
|
||||
|
||||
override fun onOrderCancelled(orderId: String, success: Boolean, message: String) {
|
||||
if (success) {
|
||||
Toast.makeText(requireContext(), "Berhasil batalkan pesanan", Toast.LENGTH_SHORT).show()
|
||||
Log.d("OrderListFragment", "Order cancel success: $message")
|
||||
// loadOrders() // Refresh the list
|
||||
if (success) viewModel.updateStatus(status, forceRefresh = true)
|
||||
@ -210,4 +210,14 @@ class OrderListFragment : Fragment(), OrderHistoryAdapter.OrderActionCallbacks {
|
||||
super.onResume()
|
||||
observeOrderList()
|
||||
}
|
||||
|
||||
override fun onDialogConfirmed() {
|
||||
|
||||
viewModel.refresh(status)
|
||||
// Option 1: refresh seluruh fragment
|
||||
requireActivity().supportFragmentManager.beginTransaction()
|
||||
.detach(this)
|
||||
.attach(this)
|
||||
.commit()
|
||||
}
|
||||
}
|
||||
@ -130,13 +130,6 @@ class CancelOrderBottomSheet(
|
||||
is Result.Success -> {
|
||||
// Hide loading indicator
|
||||
showLoading(false)
|
||||
|
||||
// Show success message
|
||||
Toast.makeText(
|
||||
context,
|
||||
"Pesanan berhasil dibatalkan",
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
Log.d(TAG, "Cancel order status: SUCCESS, message: ${result.data.message}")
|
||||
|
||||
// Notify callback and close dialog
|
||||
|
||||
@ -91,10 +91,11 @@ class CategoryProductsActivity : AppCompatActivity() {
|
||||
// title = category.name
|
||||
}
|
||||
|
||||
val fullImageUrl = if (category.image.startsWith("/")) {
|
||||
BASE_URL + category.image.removePrefix("/") // Append base URL if the path starts with "/"
|
||||
} else {
|
||||
category.image // Use as is if it's already a full URL
|
||||
val fullImageUrl = when (val img = category.image) {
|
||||
is String -> {
|
||||
if (img.startsWith("/")) BASE_URL + img.substring(1) else img
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
|
||||
// Load category image
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
package com.alya.ecommerce_serang.ui.profile
|
||||
|
||||
import android.app.AlertDialog
|
||||
import android.app.ProgressDialog
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
@ -27,6 +26,7 @@ import com.alya.ecommerce_serang.ui.profile.mystore.RegisterStoreActivity
|
||||
import com.alya.ecommerce_serang.ui.profile.mystore.StoreOnReviewActivity
|
||||
import com.alya.ecommerce_serang.ui.profile.mystore.StoreSuspendedActivity
|
||||
import com.alya.ecommerce_serang.utils.BaseViewModelFactory
|
||||
import com.alya.ecommerce_serang.utils.PopUpDialog
|
||||
import com.alya.ecommerce_serang.utils.SessionManager
|
||||
import com.alya.ecommerce_serang.utils.viewmodel.MyStoreViewModel
|
||||
import com.alya.ecommerce_serang.utils.viewmodel.ProfileViewModel
|
||||
@ -200,14 +200,16 @@ class ProfileFragment : Fragment() {
|
||||
|
||||
private fun logout(){
|
||||
|
||||
AlertDialog.Builder(requireContext())
|
||||
.setTitle("Konfirmasi")
|
||||
.setMessage("Apakah anda yakin ingin keluar?")
|
||||
.setPositiveButton("Ya") { _, _ ->
|
||||
PopUpDialog.showConfirmDialog(
|
||||
context = requireContext(),
|
||||
title = "Konfirmasi",
|
||||
message = "Apakah anda yakin ingin keluar?",
|
||||
positiveText = "Ya",
|
||||
negativeText = "Tidak",
|
||||
onYesClicked = {
|
||||
actionLogout()
|
||||
}
|
||||
.setNegativeButton("Tidak", null)
|
||||
.show()
|
||||
)
|
||||
}
|
||||
|
||||
private fun actionLogout(){
|
||||
|
||||
@ -2,7 +2,6 @@ package com.alya.ecommerce_serang.ui.profile.editprofile
|
||||
|
||||
import android.Manifest
|
||||
import android.app.Activity
|
||||
import android.app.AlertDialog
|
||||
import android.app.DatePickerDialog
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
@ -29,6 +28,7 @@ import com.alya.ecommerce_serang.data.repository.Result
|
||||
import com.alya.ecommerce_serang.data.repository.UserRepository
|
||||
import com.alya.ecommerce_serang.databinding.ActivityEditProfileCustBinding
|
||||
import com.alya.ecommerce_serang.utils.BaseViewModelFactory
|
||||
import com.alya.ecommerce_serang.utils.PopUpDialog
|
||||
import com.alya.ecommerce_serang.utils.SessionManager
|
||||
import com.alya.ecommerce_serang.utils.viewmodel.ProfileViewModel
|
||||
import com.bumptech.glide.Glide
|
||||
@ -213,12 +213,17 @@ class EditProfileCustActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
private fun confirmUpdate() {
|
||||
AlertDialog.Builder(this)
|
||||
.setTitle("Konfirmasi Perubahan")
|
||||
.setMessage("Apakah Anda yakin ingin menyimpan perubahan profil toko Anda?")
|
||||
.setPositiveButton("Ya") { _, _ -> saveProfile() }
|
||||
.setNegativeButton("Batal", null)
|
||||
.show()
|
||||
|
||||
PopUpDialog.showConfirmDialog(
|
||||
context = this,
|
||||
title = "Apakah Anda yakin ingin menyimpan perubahan profil?",
|
||||
message = "Pastikan data yang dimasukkan sudah benar",
|
||||
positiveText = "Ya",
|
||||
negativeText = "Tidak",
|
||||
onYesClicked = {
|
||||
saveProfile()
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private fun hasChanged(): Boolean {
|
||||
|
||||
@ -24,6 +24,7 @@ import com.alya.ecommerce_serang.R
|
||||
import com.alya.ecommerce_serang.data.api.response.store.profile.Payment
|
||||
import com.alya.ecommerce_serang.data.api.retrofit.ApiConfig
|
||||
import com.alya.ecommerce_serang.utils.ImageUtils.compressImage
|
||||
import com.alya.ecommerce_serang.utils.PopUpDialog
|
||||
import com.alya.ecommerce_serang.utils.SessionManager
|
||||
import kotlinx.coroutines.launch
|
||||
import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
||||
@ -374,14 +375,11 @@ class BalanceTopUpActivity : AppCompatActivity() {
|
||||
|
||||
// Show a dialog with the success message
|
||||
runOnUiThread {
|
||||
AlertDialog.Builder(this@BalanceTopUpActivity)
|
||||
.setTitle("Berhasil")
|
||||
.setMessage(successMessage)
|
||||
.setPositiveButton("OK") { dialog, _ ->
|
||||
dialog.dismiss()
|
||||
finish()
|
||||
}
|
||||
.show()
|
||||
PopUpDialog.showConfirmDialog(
|
||||
context = this@BalanceTopUpActivity,
|
||||
iconRes = R.drawable.checkmark__1_,
|
||||
title = "Berhasil melakukan Top-Up"
|
||||
)
|
||||
}
|
||||
} else {
|
||||
// Get more detailed error information
|
||||
@ -408,13 +406,12 @@ class BalanceTopUpActivity : AppCompatActivity() {
|
||||
|
||||
// Show a dialog with the error message
|
||||
runOnUiThread {
|
||||
AlertDialog.Builder(this@BalanceTopUpActivity)
|
||||
.setTitle("Error Response")
|
||||
.setMessage(errorMessage)
|
||||
.setPositiveButton("OK") { dialog, _ ->
|
||||
dialog.dismiss()
|
||||
}
|
||||
.show()
|
||||
|
||||
PopUpDialog.showConfirmDialog(
|
||||
context = this@BalanceTopUpActivity,
|
||||
iconRes = R.drawable.ic_cancel,
|
||||
title = "Gagal melakukan Top-Up"
|
||||
)
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
|
||||
@ -29,9 +29,10 @@ import com.alya.ecommerce_serang.databinding.DialogStoreImageBinding
|
||||
import com.alya.ecommerce_serang.ui.profile.mystore.profile.address.DetailStoreAddressActivity
|
||||
import com.alya.ecommerce_serang.ui.profile.mystore.profile.payment_info.PaymentInfoActivity
|
||||
import com.alya.ecommerce_serang.ui.profile.mystore.profile.shipping_service.ShippingServiceActivity
|
||||
import com.alya.ecommerce_serang.utils.viewmodel.MyStoreViewModel
|
||||
import com.alya.ecommerce_serang.utils.BaseViewModelFactory
|
||||
import com.alya.ecommerce_serang.utils.PopUpDialog
|
||||
import com.alya.ecommerce_serang.utils.SessionManager
|
||||
import com.alya.ecommerce_serang.utils.viewmodel.MyStoreViewModel
|
||||
import com.bumptech.glide.Glide
|
||||
import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
||||
import okhttp3.MultipartBody
|
||||
@ -39,7 +40,6 @@ import okhttp3.RequestBody
|
||||
import okhttp3.RequestBody.Companion.asRequestBody
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
import kotlin.getValue
|
||||
|
||||
class DetailStoreProfileActivity : AppCompatActivity() {
|
||||
private lateinit var binding: ActivityDetailStoreProfileBinding
|
||||
@ -244,12 +244,17 @@ class DetailStoreProfileActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
private fun confirmUpdate() {
|
||||
AlertDialog.Builder(this)
|
||||
.setTitle("Konfirmasi Perubahan")
|
||||
.setMessage("Apakah Anda yakin ingin menyimpan perubahan profil toko Anda?")
|
||||
.setPositiveButton("Ya") { _, _ -> updateStoreProfile() }
|
||||
.setNegativeButton("Batal", null)
|
||||
.show()
|
||||
|
||||
PopUpDialog.showConfirmDialog(
|
||||
context = this,
|
||||
title = "Apakah Anda yakin ingin menyimpan perubahan profil?",
|
||||
message = "Pastikan data yang dimasukkan sudah benar",
|
||||
positiveText = "Ya",
|
||||
negativeText = "Tidak",
|
||||
onYesClicked = {
|
||||
updateStoreProfile()
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private fun showImageOptions() {
|
||||
|
||||
@ -142,7 +142,7 @@ class SellsListFragment : Fragment() {
|
||||
|
||||
binding.progressBar.visibility = View.GONE
|
||||
binding.tvEmptyState.visibility = View.VISIBLE
|
||||
Toast.makeText(requireContext(), result.message, Toast.LENGTH_SHORT).show()
|
||||
// Toast.makeText(requireContext(), result.message, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
is ViewState.Loading -> {
|
||||
binding.progressBar.visibility = View.VISIBLE
|
||||
|
||||
@ -1,22 +0,0 @@
|
||||
package com.alya.ecommerce_serang.utils
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Rect
|
||||
import android.view.View
|
||||
import androidx.annotation.DimenRes
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
|
||||
class HorizontalMarginItemDecoration(context: Context, @DimenRes horizontalMarginInDp: Int) :
|
||||
RecyclerView.ItemDecoration() {
|
||||
|
||||
private val horizontalMarginInPx: Int =
|
||||
context.resources.getDimension(horizontalMarginInDp).toInt()
|
||||
|
||||
override fun getItemOffsets(
|
||||
outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State
|
||||
) {
|
||||
outRect.right = horizontalMarginInPx
|
||||
outRect.left = horizontalMarginInPx
|
||||
}
|
||||
|
||||
}
|
||||
@ -78,7 +78,6 @@ object PopUpDialog {
|
||||
dialog.dismiss()
|
||||
}
|
||||
|
||||
|
||||
dialog.show()
|
||||
}
|
||||
}
|
||||
@ -4,8 +4,8 @@
|
||||
|
||||
<!-- Logo with controlled size -->
|
||||
<item
|
||||
android:width="200dp"
|
||||
android:height="200dp"
|
||||
android:width="120dp"
|
||||
android:height="120dp"
|
||||
android:drawable="@drawable/logo_psb_crop"
|
||||
android:gravity="center" />
|
||||
</layer-list>
|
||||
@ -12,11 +12,13 @@
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/white"
|
||||
android:orientation="vertical">
|
||||
<ImageView
|
||||
android:id="@+id/dialogIcon"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:contentDescription="icon dialog"
|
||||
android:visibility="gone" />
|
||||
@ -27,8 +29,14 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Judul"
|
||||
android:layout_marginTop="16dp"
|
||||
android:paddingHorizontal="16dp"
|
||||
android:paddingTop="4dp"
|
||||
android:ellipsize="end"
|
||||
android:scrollHorizontally="false"
|
||||
android:singleLine="false"
|
||||
android:gravity="center"
|
||||
android:textSize="18sp"
|
||||
android:textSize="16sp"
|
||||
android:maxLines="3"
|
||||
android:fontFamily="@font/dmsans_semibold"
|
||||
android:textColor="?attr/colorOnSurface" />
|
||||
|
||||
@ -38,9 +46,15 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="12dp"
|
||||
android:gravity="center"
|
||||
android:maxLines="3"
|
||||
android:paddingHorizontal="16dp"
|
||||
android:paddingTop="4dp"
|
||||
android:ellipsize="end"
|
||||
android:scrollHorizontally="false"
|
||||
android:singleLine="false"
|
||||
android:text="Pesan Dialog"
|
||||
android:fontFamily="@font/dmsans_regular"
|
||||
android:textSize="14sp"
|
||||
android:textSize="12sp"
|
||||
android:textColor="?attr/colorOnSurfaceVariant" />
|
||||
|
||||
<LinearLayout
|
||||
@ -49,6 +63,7 @@
|
||||
android:layout_marginTop="20dp"
|
||||
android:gravity="center"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:paddingHorizontal="16dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
@ -57,6 +72,8 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="@font/dmsans_regular"
|
||||
android:theme="@style/body_small"
|
||||
|
||||
android:text="Tidak" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
@ -66,6 +83,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="12dp"
|
||||
android:fontFamily="@font/dmsans_regular"
|
||||
android:theme="@style/body_small"
|
||||
android:text="Ya" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
@ -25,7 +25,7 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:text="Gracia Hotmauli"
|
||||
android:text="Nama Pengguna"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintStart_toEndOf="@id/profileImage"
|
||||
@ -35,7 +35,7 @@
|
||||
android:id="@+id/tvUsername"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="\@gracia34"
|
||||
android:text="Username"
|
||||
android:textColor="#757575"
|
||||
app:layout_constraintStart_toStartOf="@id/tvName"
|
||||
app:layout_constraintTop_toBottomOf="@id/tvName" />
|
||||
|
||||
@ -3,8 +3,6 @@
|
||||
xmlns:card_view="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="8dp"
|
||||
card_view:cardCornerRadius="12dp"
|
||||
card_view:cardElevation="6dp"
|
||||
android:foreground="?android:attr/selectableItemBackground">
|
||||
|
||||
@ -18,17 +16,10 @@
|
||||
android:id="@+id/tvOption"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="@font/dmsans_semibold"
|
||||
android:fontFamily="@font/dmsans_regular"
|
||||
android:text="Item 1"
|
||||
android:textColor="@color/black_500"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<View
|
||||
android:id="@+id/divider"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:background="@android:color/darker_gray"
|
||||
android:layout_marginTop="4dp" />
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
@ -133,21 +133,33 @@
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btn_left"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:background="@drawable/bg_button_outline"
|
||||
android:backgroundTint="@color/white"
|
||||
android:visibility="gone"
|
||||
android:maxLines="2"
|
||||
android:ellipsize="end"
|
||||
android:scrollHorizontally="false"
|
||||
android:singleLine="false"
|
||||
android:padding="4dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/tvDeadlineDate"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
android:layout_marginTop="8dp"/>
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btn_right"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:background="@drawable/bg_button_filled"
|
||||
android:visibility="gone"
|
||||
android:maxLines="2"
|
||||
android:ellipsize="end"
|
||||
android:scrollHorizontally="false"
|
||||
android:singleLine="false"
|
||||
android:padding="4dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
android:text="Kirim Bukti Bayar"
|
||||
app:layout_constraintTop_toBottomOf="@id/tvDeadlineDate"
|
||||
|
||||
@ -338,7 +338,6 @@
|
||||
<style name="ThemeOverlay.MyApp.AlertDialog" parent="ThemeOverlay.Material3.MaterialAlertDialog">
|
||||
<!-- Rounded corners -->
|
||||
<item name="shapeAppearanceMediumComponent">@style/ShapeAppearance.MyApp.MediumComponent</item>
|
||||
<!-- Dialog background color -->
|
||||
<item name="cardBackgroundColor">@color/white</item>
|
||||
<item name="materialAlertDialogBodyTextStyle">@font/dmsans_regular</item>
|
||||
<item name="android:windowBackground">@android:color/transparent</item>
|
||||
|
||||
Reference in New Issue
Block a user