mirror of
https://github.com/shaulascr/ecommerce_serang.git
synced 2025-08-10 09:22:21 +00:00
fix address and payment
This commit is contained in:
1
.idea/misc.xml
generated
1
.idea/misc.xml
generated
@ -1,4 +1,3 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CodeInsightWorkspaceSettings">
|
||||
<option name="optimizeImportsOnTheFly" value="true" />
|
||||
|
@ -3,11 +3,15 @@ package com.alya.ecommerce_serang.ui.order
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.ViewGroup
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.activity.viewModels
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.alya.ecommerce_serang.data.api.dto.CheckoutData
|
||||
import com.alya.ecommerce_serang.data.api.dto.OrderRequest
|
||||
import com.alya.ecommerce_serang.data.api.dto.OrderRequestBuy
|
||||
@ -42,6 +46,7 @@ class CheckoutActivity : AppCompatActivity() {
|
||||
|
||||
sessionManager = SessionManager(this)
|
||||
|
||||
|
||||
// Setup UI components
|
||||
setupToolbar()
|
||||
setupObservers()
|
||||
@ -74,6 +79,11 @@ class CheckoutActivity : AppCompatActivity() {
|
||||
finish()
|
||||
}
|
||||
}
|
||||
|
||||
viewModel.getPaymentMethods { paymentMethods ->
|
||||
// Logging is just for debugging
|
||||
Log.d("CheckoutActivity", "Loaded ${paymentMethods.size} payment methods")
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupToolbar() {
|
||||
@ -87,13 +97,6 @@ class CheckoutActivity : AppCompatActivity() {
|
||||
viewModel.checkoutData.observe(this) { data ->
|
||||
setupProductRecyclerView(data)
|
||||
updateOrderSummary()
|
||||
|
||||
// Load payment methods
|
||||
viewModel.getPaymentMethods { paymentMethods ->
|
||||
if (paymentMethods.isNotEmpty()) {
|
||||
setupPaymentMethodsRecyclerView(paymentMethods)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Observe address details
|
||||
@ -102,14 +105,24 @@ class CheckoutActivity : AppCompatActivity() {
|
||||
binding.tvAddress.text = "${address?.street}, ${address?.subdistrict}"
|
||||
}
|
||||
|
||||
// Observe payment details
|
||||
viewModel.paymentDetails.observe(this) { payment ->
|
||||
if (payment != null) {
|
||||
// Update selected payment in adapter by name instead of ID
|
||||
paymentAdapter?.setSelectedPaymentName(payment.name)
|
||||
viewModel.availablePaymentMethods.observe(this) { paymentMethods ->
|
||||
if (paymentMethods.isNotEmpty()) {
|
||||
setupPaymentMethodsRecyclerView(paymentMethods)
|
||||
}
|
||||
}
|
||||
|
||||
// Observe selected payment
|
||||
viewModel.selectedPayment.observe(this) { selectedPayment ->
|
||||
if (selectedPayment != null) {
|
||||
// Update the adapter to show the selected payment
|
||||
paymentAdapter?.setSelectedPaymentName(selectedPayment.name)
|
||||
|
||||
// Optional: Update other UI elements to show the selected payment
|
||||
// For example: binding.tvSelectedPaymentMethod.text = selectedPayment.name
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Observe loading state
|
||||
viewModel.isLoading.observe(this) { isLoading ->
|
||||
binding.btnPay.isEnabled = !isLoading
|
||||
@ -133,6 +146,47 @@ class CheckoutActivity : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupPaymentMethodsRecyclerView(paymentMethods: List<PaymentInfoItem>) {
|
||||
paymentAdapter = PaymentMethodAdapter(paymentMethods) { payment ->
|
||||
// Convert payment name to ID
|
||||
val paymentId = payment.name.toIntOrNull() ?: 0
|
||||
|
||||
// Call the ViewModel's setPaymentMethod function
|
||||
viewModel.setPaymentMethod(paymentId)
|
||||
}
|
||||
|
||||
binding.rvPaymentMethods.apply {
|
||||
layoutManager = LinearLayoutManager(this@CheckoutActivity)
|
||||
adapter = paymentAdapter
|
||||
}
|
||||
}
|
||||
|
||||
private fun updatePaymentMethodsAdapter(paymentMethods: List<PaymentInfoItem>, selectedId: Int?) {
|
||||
Log.d("CheckoutActivity", "Updating payment adapter with ${paymentMethods.size} methods")
|
||||
|
||||
// Simple test adapter
|
||||
val testAdapter = object : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||
val textView = TextView(parent.context)
|
||||
textView.setPadding(16, 16, 16, 16)
|
||||
textView.textSize = 16f
|
||||
return object : RecyclerView.ViewHolder(textView) {}
|
||||
}
|
||||
|
||||
override fun getItemCount() = paymentMethods.size
|
||||
|
||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||
val payment = paymentMethods[position]
|
||||
(holder.itemView as TextView).text = "Payment: ${payment.name}"
|
||||
}
|
||||
}
|
||||
|
||||
binding.rvPaymentMethods.apply {
|
||||
layoutManager = LinearLayoutManager(this@CheckoutActivity)
|
||||
adapter = testAdapter
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupProductRecyclerView(checkoutData: CheckoutData) {
|
||||
val adapter = if (checkoutData.isBuyNow || checkoutData.cartItems.size <= 1) {
|
||||
CheckoutSellerAdapter(checkoutData)
|
||||
@ -147,21 +201,6 @@ class CheckoutActivity : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupPaymentMethodsRecyclerView(paymentMethods: List<PaymentInfoItem>) {
|
||||
paymentAdapter = PaymentMethodAdapter(paymentMethods) { payment ->
|
||||
// When a payment method is selected
|
||||
// Since PaymentInfoItem doesn't have an id field, we'll use the name as identifier
|
||||
// You might need to convert the name to an ID if your backend expects an integer
|
||||
val paymentId = payment.name.toIntOrNull() ?: 0
|
||||
viewModel.setPaymentMethod(paymentId)
|
||||
}
|
||||
|
||||
binding.rvPaymentMethods.apply {
|
||||
layoutManager = LinearLayoutManager(this@CheckoutActivity)
|
||||
adapter = paymentAdapter
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateOrderSummary() {
|
||||
viewModel.checkoutData.value?.let { data ->
|
||||
// Update price information
|
||||
@ -251,6 +290,9 @@ class CheckoutActivity : AppCompatActivity() {
|
||||
val addressId = result.data?.getIntExtra(AddressActivity.EXTRA_ADDRESS_ID, 0) ?: 0
|
||||
if (addressId > 0) {
|
||||
viewModel.setSelectedAddress(addressId)
|
||||
|
||||
// You might want to show a toast or some UI feedback
|
||||
Toast.makeText(this, "Address selected successfully", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -299,7 +341,7 @@ class CheckoutActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
// Check if payment method is selected
|
||||
if (viewModel.paymentDetails.value == null) {
|
||||
if (viewModel.selectedPayment.value == null) {
|
||||
Toast.makeText(this, "Silakan pilih metode pembayaran", Toast.LENGTH_SHORT).show()
|
||||
return false
|
||||
}
|
||||
|
@ -24,8 +24,12 @@ class CheckoutViewModel(private val repository: OrderRepository) : ViewModel() {
|
||||
private val _addressDetails = MutableLiveData<AddressesItem?>()
|
||||
val addressDetails: LiveData<AddressesItem?> = _addressDetails
|
||||
|
||||
private val _paymentDetails = MutableLiveData<PaymentInfoItem?>()
|
||||
val paymentDetails: LiveData<PaymentInfoItem?> = _paymentDetails
|
||||
private val _availablePaymentMethods = MutableLiveData<List<PaymentInfoItem>>()
|
||||
val availablePaymentMethods: LiveData<List<PaymentInfoItem>> = _availablePaymentMethods
|
||||
|
||||
// Selected payment method
|
||||
private val _selectedPayment = MutableLiveData<PaymentInfoItem?>()
|
||||
val selectedPayment: LiveData<PaymentInfoItem?> = _selectedPayment
|
||||
|
||||
private val _isLoading = MutableLiveData<Boolean>()
|
||||
val isLoading: LiveData<Boolean> = _isLoading
|
||||
@ -144,7 +148,6 @@ class CheckoutViewModel(private val repository: OrderRepository) : ViewModel() {
|
||||
}
|
||||
}
|
||||
|
||||
// Get payment methods from API
|
||||
fun getPaymentMethods(callback: (List<PaymentInfoItem>) -> Unit) {
|
||||
viewModelScope.launch {
|
||||
try {
|
||||
@ -154,17 +157,74 @@ class CheckoutViewModel(private val repository: OrderRepository) : ViewModel() {
|
||||
val storeResult = repository.fetchStoreDetail(storeId)
|
||||
|
||||
if (storeResult is Result.Success && storeResult.data != null) {
|
||||
callback(storeResult.data.paymentInfo)
|
||||
val paymentMethodsList = storeResult.data.paymentInfo
|
||||
_availablePaymentMethods.value = paymentMethodsList
|
||||
callback(paymentMethodsList)
|
||||
} else {
|
||||
_availablePaymentMethods.value = emptyList()
|
||||
callback(emptyList())
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Error fetching payment methods", e)
|
||||
_availablePaymentMethods.value = emptyList()
|
||||
callback(emptyList())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set payment method
|
||||
// In CheckoutViewModel
|
||||
fun setPaymentMethod(paymentId: Int) {
|
||||
viewModelScope.launch {
|
||||
try {
|
||||
// Get the available payment methods, or fetch them if not available
|
||||
val paymentMethods = _availablePaymentMethods.value ?: run {
|
||||
val storeId = _checkoutData.value?.sellerId ?: return@launch
|
||||
val storeResult = repository.fetchStoreDetail(storeId)
|
||||
if (storeResult is Result.Success && storeResult.data != null) {
|
||||
val methods = storeResult.data.paymentInfo
|
||||
_availablePaymentMethods.value = methods
|
||||
methods
|
||||
} else {
|
||||
emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
// Find the selected payment method
|
||||
val selectedPayment = paymentMethods.find {
|
||||
// Change this line to match the actual way you want to identify the payment method
|
||||
it.name == paymentId.toString() // to do: edit to using it.id
|
||||
}
|
||||
|
||||
if (selectedPayment != null) {
|
||||
// Set the selected payment
|
||||
_selectedPayment.value = selectedPayment
|
||||
|
||||
// Update the order request with the payment method ID
|
||||
val currentData = _checkoutData.value ?: return@launch
|
||||
|
||||
// Different handling for Buy Now vs Cart checkout
|
||||
if (currentData.isBuyNow) {
|
||||
// For Buy Now checkout
|
||||
val buyRequest = currentData.orderRequest as OrderRequestBuy
|
||||
val updatedRequest = buyRequest.copy(paymentMethodId = paymentId)
|
||||
_checkoutData.value = currentData.copy(orderRequest = updatedRequest)
|
||||
} else {
|
||||
// For Cart checkout
|
||||
val cartRequest = currentData.orderRequest as OrderRequest
|
||||
val updatedRequest = cartRequest.copy(paymentMethodId = paymentId)
|
||||
_checkoutData.value = currentData.copy(orderRequest = updatedRequest)
|
||||
}
|
||||
} else {
|
||||
// If no matching payment method is found
|
||||
_errorMessage.value = "Selected payment method not found"
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
_errorMessage.value = "Error setting payment method: ${e.message}"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set selected address
|
||||
fun setSelectedAddress(addressId: Int) {
|
||||
viewModelScope.launch {
|
||||
@ -227,39 +287,6 @@ class CheckoutViewModel(private val repository: OrderRepository) : ViewModel() {
|
||||
}
|
||||
}
|
||||
|
||||
// Set payment method
|
||||
fun setPaymentMethod(paymentId: Int) {
|
||||
viewModelScope.launch {
|
||||
try {
|
||||
val storeId = _checkoutData.value?.sellerId ?: return@launch
|
||||
|
||||
// Use fetchStoreDetail instead of getStore
|
||||
val storeResult = repository.fetchStoreDetail(storeId)
|
||||
if (storeResult is Result.Success && storeResult.data != null) {
|
||||
// Find the selected payment in the payment info list
|
||||
val payment = storeResult.data.paymentInfo.find { it.name == paymentId.toString() }
|
||||
_paymentDetails.value = payment
|
||||
|
||||
// Update order request if payment isn't null
|
||||
if (payment != null) {
|
||||
val currentData = _checkoutData.value ?: return@launch
|
||||
if (currentData.isBuyNow) {
|
||||
val buyRequest = currentData.orderRequest as OrderRequestBuy
|
||||
val updatedRequest = buyRequest.copy(paymentMethodId = paymentId)
|
||||
_checkoutData.value = currentData.copy(orderRequest = updatedRequest)
|
||||
} else {
|
||||
val cartRequest = currentData.orderRequest as OrderRequest
|
||||
val updatedRequest = cartRequest.copy(paymentMethodId = paymentId)
|
||||
_checkoutData.value = currentData.copy(orderRequest = updatedRequest)
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
_errorMessage.value = "Error setting payment method: ${e.message}"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create order
|
||||
fun createOrder() {
|
||||
viewModelScope.launch {
|
||||
|
@ -154,7 +154,7 @@ private fun setupToolbar() {
|
||||
|
||||
private fun handleAddressSubmissionState(state: ViewState<String>) {
|
||||
when (state) {
|
||||
is ViewState.Loading -> showSubmitLoading(true)
|
||||
is ViewState.Loading -> null //showSubmitLoading(true)
|
||||
is ViewState.Success -> {
|
||||
showSubmitLoading(false)
|
||||
showSuccessAndFinish(state.data)
|
||||
|
@ -4,9 +4,9 @@ import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import androidx.activity.viewModels
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.alya.ecommerce_serang.data.api.retrofit.ApiConfig
|
||||
import com.alya.ecommerce_serang.data.api.retrofit.ApiService
|
||||
import com.alya.ecommerce_serang.data.repository.OrderRepository
|
||||
import com.alya.ecommerce_serang.databinding.ActivityAddressBinding
|
||||
import com.alya.ecommerce_serang.utils.BaseViewModelFactory
|
||||
@ -14,7 +14,6 @@ import com.alya.ecommerce_serang.utils.SessionManager
|
||||
|
||||
class AddressActivity : AppCompatActivity() {
|
||||
private lateinit var binding: ActivityAddressBinding
|
||||
private lateinit var apiService: ApiService
|
||||
private lateinit var sessionManager: SessionManager
|
||||
private lateinit var adapter: AddressAdapter
|
||||
|
||||
@ -26,55 +25,82 @@ class AddressActivity : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
binding = ActivityAddressBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
sessionManager = SessionManager(this)
|
||||
apiService = ApiConfig.getApiService(sessionManager)
|
||||
|
||||
|
||||
setupToolbar()
|
||||
setupRecyclerView()
|
||||
setupObservers()
|
||||
|
||||
adapter = AddressAdapter { selectedId ->
|
||||
viewModel.selectAddress(selectedId)
|
||||
viewModel.fetchAddresses()
|
||||
}
|
||||
|
||||
private fun addAddressClicked(){
|
||||
binding.addAddressClick.setOnClickListener{
|
||||
val intent = Intent(this, AddAddressActivity::class.java)
|
||||
startActivity(intent)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupToolbar() {
|
||||
// Remove duplicate toolbar setup
|
||||
addAddressClicked()
|
||||
binding.toolbar.setNavigationOnClickListener {
|
||||
onBackPressedWithResult()
|
||||
}
|
||||
}
|
||||
|
||||
binding.rvSellerOrder.layoutManager = LinearLayoutManager(this)
|
||||
binding.rvSellerOrder.adapter = adapter
|
||||
private fun setupRecyclerView() {
|
||||
adapter = AddressAdapter { address ->
|
||||
// Select the address in the ViewModel
|
||||
viewModel.selectAddress(address.id)
|
||||
|
||||
viewModel.fetchAddresses()
|
||||
// Return immediately with the selected address
|
||||
returnResultAndFinish(address.id)
|
||||
}
|
||||
|
||||
binding.rvSellerOrder.apply {
|
||||
layoutManager = LinearLayoutManager(this@AddressActivity)
|
||||
adapter = this@AddressActivity.adapter
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupObservers() {
|
||||
viewModel.addresses.observe(this) { addressList ->
|
||||
adapter.submitList(addressList)
|
||||
|
||||
// Show empty state if needed
|
||||
// binding.emptyView?.isVisible = addressList.isEmpty()
|
||||
binding.rvSellerOrder.isVisible = addressList.isNotEmpty()
|
||||
}
|
||||
|
||||
viewModel.selectedAddressId.observe(this) { selectedId ->
|
||||
adapter.setSelectedAddressId(selectedId)
|
||||
}
|
||||
}
|
||||
private fun setupToolbar() {
|
||||
binding.toolbar.setNavigationOnClickListener {
|
||||
finish()
|
||||
}
|
||||
}
|
||||
// private fun updateEmptyState(isEmpty: Boolean) {
|
||||
// binding.layoutEmptyAddresses.isVisible = isEmpty
|
||||
// binding.rvAddresses.isVisible = !isEmpty
|
||||
// }
|
||||
|
||||
private fun onBackPressedWithResult() {
|
||||
viewModel.selectedAddressId.value?.let {
|
||||
val intent = Intent()
|
||||
intent.putExtra(EXTRA_ADDRESS_ID, it)
|
||||
setResult(RESULT_OK, intent)
|
||||
}
|
||||
// If an address is selected, return it as result
|
||||
val selectedId = viewModel.selectedAddressId.value
|
||||
if (selectedId != null) {
|
||||
returnResultAndFinish(selectedId)
|
||||
finish()
|
||||
} else {
|
||||
// No selection, just finish
|
||||
setResult(RESULT_CANCELED)
|
||||
finish()
|
||||
}
|
||||
}
|
||||
|
||||
private fun returnResultAndFinish(addressId: Int) {
|
||||
val intent = Intent()
|
||||
intent.putExtra(EXTRA_ADDRESS_ID, addressId)
|
||||
setResult(RESULT_OK, intent)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
@ -13,14 +13,25 @@ import com.alya.ecommerce_serang.data.api.response.profile.AddressesItem
|
||||
import com.google.android.material.card.MaterialCardView
|
||||
|
||||
class AddressAdapter(
|
||||
private val onAddressClick: (Int) -> Unit
|
||||
private val onAddressClick: (AddressesItem) -> Unit
|
||||
) : ListAdapter<AddressesItem, AddressAdapter.AddressViewHolder>(DIFF_CALLBACK) {
|
||||
|
||||
private var selectedAddressId: Int? = null
|
||||
|
||||
fun setSelectedAddressId(id: Int?) {
|
||||
val oldSelectedId = selectedAddressId
|
||||
selectedAddressId = id
|
||||
notifyDataSetChanged()
|
||||
|
||||
// Only refresh the changed items
|
||||
if (oldSelectedId != null) {
|
||||
val oldPosition = currentList.indexOfFirst { it.id == oldSelectedId }
|
||||
if (oldPosition >= 0) notifyItemChanged(oldPosition)
|
||||
}
|
||||
|
||||
if (id != null) {
|
||||
val newPosition = currentList.indexOfFirst { it.id == id }
|
||||
if (newPosition >= 0) notifyItemChanged(newPosition)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AddressViewHolder {
|
||||
@ -33,7 +44,8 @@ class AddressAdapter(
|
||||
val address = getItem(position)
|
||||
holder.bind(address, selectedAddressId == address.id)
|
||||
holder.itemView.setOnClickListener {
|
||||
onAddressClick(address.id)
|
||||
// Pass the whole address object to provide more context
|
||||
onAddressClick(address)
|
||||
}
|
||||
}
|
||||
|
||||
@ -46,6 +58,12 @@ class AddressAdapter(
|
||||
tvName.text = address.recipient
|
||||
tvDetail.text = "${address.street}, ${address.subdistrict}, ${address.phone}"
|
||||
|
||||
// Make selection more visible
|
||||
card.strokeWidth = if (isSelected) 3 else 0
|
||||
card.strokeColor = if (isSelected)
|
||||
ContextCompat.getColor(itemView.context, R.color.blue_400)
|
||||
else 0
|
||||
|
||||
card.setCardBackgroundColor(
|
||||
ContextCompat.getColor(
|
||||
itemView.context,
|
||||
|
@ -24,6 +24,7 @@
|
||||
app:title="Alamat Pengiriman " />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/add_address_click"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAlignment="textEnd"
|
||||
|
Reference in New Issue
Block a user