From d1fcec6d14c51b8fe1dc6fb7efd5514695469dc2 Mon Sep 17 00:00:00 2001 From: shaulascr Date: Sat, 19 Apr 2025 15:39:47 +0700 Subject: [PATCH] add payment --- .../data/repository/OrderRepository.kt | 9 +- .../ui/order/detail/PaymentActivity.kt | 198 ++++++++++++++++-- .../ui/order/detail/PaymentViewModel.kt | 53 +++++ .../ui/order/history/OrderHistoryAdapter.kt | 143 ++++++++++++- .../ui/order/history/OrderListFragment.kt | 2 + .../ui/order/history/OrderProductAdapter.kt | 4 + .../main/res/drawable/bg_button_outline.xml | 1 - app/src/main/res/layout/activity_payment.xml | 32 +-- .../main/res/layout/item_order_history.xml | 1 + app/src/main/res/values/strings.xml | 19 ++ 10 files changed, 416 insertions(+), 46 deletions(-) create mode 100644 app/src/main/java/com/alya/ecommerce_serang/ui/order/detail/PaymentViewModel.kt diff --git a/app/src/main/java/com/alya/ecommerce_serang/data/repository/OrderRepository.kt b/app/src/main/java/com/alya/ecommerce_serang/data/repository/OrderRepository.kt index 36942f1..b1d8b7a 100644 --- a/app/src/main/java/com/alya/ecommerce_serang/data/repository/OrderRepository.kt +++ b/app/src/main/java/com/alya/ecommerce_serang/data/repository/OrderRepository.kt @@ -237,8 +237,13 @@ class OrderRepository(private val apiService: ApiService) { } suspend fun getOrderDetails(orderId: Int): OrderDetailResponse? { - val response = apiService.getDetailOrder(orderId) - return if (response.isSuccessful) response.body() else null + return try { + val response = apiService.getDetailOrder(orderId) + if (response.isSuccessful) response.body() else null + } catch (e: Exception) { + Log.e("OrderRepository", "Error getting order details", e) + null + } } suspend fun uploadPaymentProof(request : AddEvidenceRequest): Result { diff --git a/app/src/main/java/com/alya/ecommerce_serang/ui/order/detail/PaymentActivity.kt b/app/src/main/java/com/alya/ecommerce_serang/ui/order/detail/PaymentActivity.kt index 1ba879a..00d3d49 100644 --- a/app/src/main/java/com/alya/ecommerce_serang/ui/order/detail/PaymentActivity.kt +++ b/app/src/main/java/com/alya/ecommerce_serang/ui/order/detail/PaymentActivity.kt @@ -1,21 +1,195 @@ package com.alya.ecommerce_serang.ui.order.detail import android.os.Bundle -import androidx.activity.enableEdgeToEdge +import android.util.Log +import android.widget.Toast +import androidx.activity.viewModels +import androidx.appcompat.app.AlertDialog 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.data.api.retrofit.ApiConfig +import com.alya.ecommerce_serang.data.repository.OrderRepository +import com.alya.ecommerce_serang.databinding.ActivityPaymentBinding +import com.alya.ecommerce_serang.utils.BaseViewModelFactory +import com.alya.ecommerce_serang.utils.SessionManager +import java.text.SimpleDateFormat +import java.util.Calendar +import java.util.Locale class PaymentActivity : AppCompatActivity() { - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - enableEdgeToEdge() - setContentView(R.layout.activity_payment) - ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets -> - val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()) - v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom) - insets + private lateinit var binding: ActivityPaymentBinding + private lateinit var sessionManager: SessionManager + + companion object { + private const val TAG = "PaymentActivity" + } + + private val viewModel: PaymentViewModel by viewModels { + BaseViewModelFactory { + val apiService = ApiConfig.getApiService(sessionManager) + val orderRepository = OrderRepository(apiService) + PaymentViewModel(orderRepository) } } + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + binding = ActivityPaymentBinding.inflate(layoutInflater) + setContentView(binding.root) + + sessionManager = SessionManager(this) + + // Mengambil data dari intent + val orderId = intent.getIntExtra("ORDER_ID", 0) + val paymentInfoId = intent.getIntExtra("ORDER_PAYMENT_ID", 0) + + if (orderId == 0) { + Toast.makeText(this, "ID pesanan tidak valid", Toast.LENGTH_SHORT).show() + finish() + } + + // Setup toolbar + binding.toolbar.setNavigationOnClickListener { + finish() + } + + // Setup petunjuk transfer + binding.layoutMBankingInstructions.setOnClickListener { + // Tampilkan instruksi mBanking + showInstructions("mBanking") + } + + binding.layoutATMInstructions.setOnClickListener { + // Tampilkan instruksi ATM + showInstructions("ATM") + } + + // Setup button upload bukti bayar + binding.btnUploadPaymentProof.setOnClickListener { + // Intent ke activity upload bukti bayar +// val intent = Intent(this, UploadPaymentProofActivity::class.java) + intent.putExtra("ORDER_ID", orderId) + intent.putExtra("PAYMENT_INFO_ID", paymentInfoId) + Log.d(TAG, "Received Order ID: $orderId, Payment Info ID: $paymentInfoId") + + startActivity(intent) + } + + // Setup button negosiasi harga + binding.btnNegotiatePrice.setOnClickListener { + // Intent ke activity negosiasi harga +// val intent = Intent(this, NegotiatePriceActivity::class.java) +// intent.putExtra("ORDER_ID", orderId) +// startActivity(intent) + } + + // Observe data + observeData() + + // Load data + Log.d(TAG, "Fetching order details for Order ID: $orderId") + viewModel.getOrderDetails(orderId) + } + + private fun observeData() { + // Observe Order Details + viewModel.orderDetails.observe(this) { order -> + Log.d(TAG, "Order details received: $order") + + // Set total amount + binding.tvTotalAmount.text = order.totalAmount ?: "Rp0" + Log.d(TAG, "Total Amount: ${order.totalAmount}") + + + // Set bank information + binding.tvBankName.text = order.payInfoName ?: "Bank BCA" + binding.tvAccountNumber.text = order.payInfoNum ?: "0123456789" + Log.d(TAG, "Bank Name: ${order.payInfoName}, Account Number: ${order.payInfoNum}") + + + // Calculate remaining time and due date + setupPaymentDueDate(order.updatedAt) + } + + // Observe loading state + viewModel.isLoading.observe(this) { isLoading -> + // Show loading indicator if needed + // binding.progressBar.visibility = if (isLoading) View.VISIBLE else View.GONE + } + + // Observe error + viewModel.error.observe(this) { error -> + if (error.isNotEmpty()) { + Toast.makeText(this, error, Toast.LENGTH_SHORT).show() + } + } + } + + private fun setupPaymentDueDate(createdAt: String) { + Log.d(TAG, "Setting up payment due date from updated at: $createdAt") + + try { + // Parse the created date + val dateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()) + val createdDate = dateFormat.parse(createdAt) ?: return + + // Add 24 hours to get due date + val calendar = Calendar.getInstance() + calendar.time = createdDate + calendar.add(Calendar.HOUR, 24) + val dueDate = calendar.time + + // Format due date for display + val dueDateFormat = SimpleDateFormat("dd MMM yyyy", Locale.getDefault()) + binding.tvDueDate.text = "Jatuh tempo ${dueDateFormat.format(dueDate)}" + Log.d(TAG, "Due Date: ${dueDateFormat.format(dueDate)}") + + + // Calculate remaining time + val now = Calendar.getInstance().time + val diff = dueDate.time - now.time + + if (diff > 0) { + val hours = diff / (60 * 60 * 1000) + val minutes = (diff % (60 * 60 * 1000)) / (60 * 1000) + binding.tvRemainingTime.text = "$hours jam $minutes menit" + Log.d(TAG, "Remaining Time: $hours hours $minutes minutes") + + } else { + binding.tvRemainingTime.text = "Waktu habis" + } + } catch (e: Exception) { + binding.tvDueDate.text = "Jatuh tempo -" + binding.tvRemainingTime.text = "-" + } + } + + private fun showInstructions(type: String) { + // Implementasi tampilkan instruksi + val instructions = when (type) { + "mBanking" -> listOf( + "1. Login ke aplikasi mobile banking", + "2. Pilih menu Transfer", + "3. Pilih menu Antar Rekening", + "4. Masukkan nomor rekening tujuan", + "5. Masukkan nominal transfer sesuai tagihan", + "6. Konfirmasi dan selesaikan transfer" + ) + "ATM" -> listOf( + "1. Masukkan kartu ATM dan PIN", + "2. Pilih menu Transfer", + "3. Pilih menu Antar Rekening", + "4. Masukkan kode bank dan nomor rekening tujuan", + "5. Masukkan nominal transfer sesuai tagihan", + "6. Konfirmasi dan selesaikan transfer" + ) + else -> emptyList() + } + + // Tampilkan instruksi dalam dialog + val dialog = AlertDialog.Builder(this) + .setTitle("Petunjuk Transfer $type") + .setItems(instructions.toTypedArray(), null) + .setPositiveButton("Tutup", null) + .create() + dialog.show() + } } \ No newline at end of file diff --git a/app/src/main/java/com/alya/ecommerce_serang/ui/order/detail/PaymentViewModel.kt b/app/src/main/java/com/alya/ecommerce_serang/ui/order/detail/PaymentViewModel.kt new file mode 100644 index 0000000..5929f5a --- /dev/null +++ b/app/src/main/java/com/alya/ecommerce_serang/ui/order/detail/PaymentViewModel.kt @@ -0,0 +1,53 @@ +package com.alya.ecommerce_serang.ui.order.detail + +import android.util.Log +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.alya.ecommerce_serang.data.api.response.order.OrderListItemsItem +import com.alya.ecommerce_serang.data.api.response.order.Orders +import com.alya.ecommerce_serang.data.repository.OrderRepository +import kotlinx.coroutines.launch + +class PaymentViewModel(private val repository: OrderRepository) : ViewModel() { + companion object { + private const val TAG = "PaymentViewModel" + } + + // LiveData untuk Order + private val _orderDetails = MutableLiveData() + val orderDetails: LiveData get() = _orderDetails + + // LiveData untuk OrderItems + private val _orderItems = MutableLiveData>() + val orderItems: LiveData> get() = _orderItems + + // LiveData untuk status loading + private val _isLoading = MutableLiveData() + val isLoading: LiveData get() = _isLoading + + // LiveData untuk error + private val _error = MutableLiveData() + val error: LiveData get() = _error + + fun getOrderDetails(orderId: Int) { + _isLoading.value = true + viewModelScope.launch { + try { + val response = repository.getOrderDetails(orderId) + if (response != null) { + _orderDetails.value = response.orders + _orderItems.value = response.orders.orderItems + } else { + _error.value = "Gagal memuat detail pesanan" + } + } catch (e: Exception) { + _error.value = "Terjadi kesalahan: ${e.message}" + Log.e(TAG, "Error fetching order details", e) + } finally { + _isLoading.value = false + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/alya/ecommerce_serang/ui/order/history/OrderHistoryAdapter.kt b/app/src/main/java/com/alya/ecommerce_serang/ui/order/history/OrderHistoryAdapter.kt index b1b13f4..2258b10 100644 --- a/app/src/main/java/com/alya/ecommerce_serang/ui/order/history/OrderHistoryAdapter.kt +++ b/app/src/main/java/com/alya/ecommerce_serang/ui/order/history/OrderHistoryAdapter.kt @@ -1,5 +1,7 @@ package com.alya.ecommerce_serang.ui.order.history +import android.content.Intent +import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -8,6 +10,8 @@ import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import com.alya.ecommerce_serang.R import com.alya.ecommerce_serang.data.api.response.order.OrdersItem +import com.alya.ecommerce_serang.ui.order.detail.PaymentActivity +import com.google.android.material.button.MaterialButton class OrderHistoryAdapter( private val onOrderClickListener: (OrdersItem) -> Unit @@ -15,6 +19,12 @@ class OrderHistoryAdapter( private val orders = mutableListOf() + private var fragmentStatus: String = "all" + + fun setFragmentStatus(status: String) { + fragmentStatus = status + } + fun submitList(newOrders: List) { orders.clear() orders.addAll(newOrders) @@ -34,7 +44,6 @@ class OrderHistoryAdapter( inner class OrderViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { private val tvStoreName: TextView = itemView.findViewById(R.id.tvStoreName) - private val tvOrderStatus: TextView = itemView.findViewById(R.id.tvOrderStatus) private val rvOrderItems: RecyclerView = itemView.findViewById(R.id.rvOrderItems) private val tvShowMore: TextView = itemView.findViewById(R.id.tvShowMore) private val tvTotalAmount: TextView = itemView.findViewById(R.id.tvTotalAmount) @@ -46,9 +55,6 @@ class OrderHistoryAdapter( val storeName = if (order.orderItems.isNotEmpty()) order.orderItems[0].storeName else "" tvStoreName.text = storeName - // Set order status based on shipment status - tvOrderStatus.text = getStatusLabel(order.shipmentStatus) - // Set total amount tvTotalAmount.text = order.totalAmount @@ -56,8 +62,8 @@ class OrderHistoryAdapter( val itemCount = order.orderItems.size tvItemCountLabel.text = itemView.context.getString(R.string.item_count_prod, itemCount) - // Set deadline date - tvDeadlineDate.text = formatDate(order.createdAt) // This would need a proper date formatting function + // Set deadline date, adjust to each status + tvDeadlineDate.text = formatDate(order.createdAt) // Set up the order items RecyclerView val productAdapter = OrderProductAdapter() @@ -86,6 +92,10 @@ class OrderHistoryAdapter( itemView.setOnClickListener { onOrderClickListener(order) } + + //adjust each fragment + adjustButtonsAndText(fragmentStatus, order) + } private fun getStatusLabel(status: String): String { @@ -102,6 +112,127 @@ class OrderHistoryAdapter( } } + private fun adjustButtonsAndText(status: String, order: OrdersItem) { + Log.d("OrderHistoryAdapter", "Adjusting buttons for status: $status") + // Mendapatkan referensi ke tombol-tombol + val btnLeft = itemView.findViewById(R.id.btn_left) + val btnRight = itemView.findViewById(R.id.btn_right) + val statusOrder = itemView.findViewById(R.id.tvOrderStatus) + val deadlineLabel = itemView.findViewById(R.id.tvDeadlineLabel) + + // Reset visibility + btnLeft.visibility = View.GONE + btnRight.visibility = View.GONE + statusOrder.visibility = View.GONE + deadlineLabel.visibility = View.GONE + + when (status) { + "pending" -> { + statusOrder.apply { + visibility = View.VISIBLE + text = itemView.context.getString(R.string.pending_orders) + } + deadlineLabel.apply { + visibility = View.VISIBLE + text = itemView.context.getString(R.string.dl_pending) + } + } + "unpaid" -> { + statusOrder.apply { + visibility = View.VISIBLE + text = itemView.context.getString(R.string.unpaid_orders) + } + deadlineLabel.apply { + visibility = View.VISIBLE + text = itemView.context.getString(R.string.dl_unpaid) + } + btnLeft.apply { + visibility = View.VISIBLE + text = itemView.context.getString(R.string.canceled_order_btn) + setOnClickListener { + } + } + btnRight.apply { + visibility = View.VISIBLE + text = itemView.context.getString(R.string.sent_evidence) + setOnClickListener { + val intent = Intent(itemView.context, PaymentActivity::class.java) + // Menambahkan data yang diperlukan + intent.putExtra("ORDER_ID", order.orderId) + intent.putExtra("ORDER_PAYMENT_ID", order.paymentInfoId) + + // Memulai aktivitas + itemView.context.startActivity(intent) + } + } + } + "processed" -> { + // Untuk status processed, tampilkan "Hubungi Penjual" + statusOrder.apply { + visibility = View.VISIBLE + text = itemView.context.getString(R.string.processed_orders) + } + deadlineLabel.apply { + visibility = View.VISIBLE + text = itemView.context.getString(R.string.dl_processed) + } + + } + "shipped" -> { + // Untuk status shipped, tampilkan "Lacak Pengiriman" dan "Terima Barang" + statusOrder.apply { + visibility = View.VISIBLE + text = itemView.context.getString(R.string.shipped_orders) + } + deadlineLabel.apply { + visibility = View.VISIBLE + text = itemView.context.getString(R.string.dl_shipped) + } + btnLeft.apply { + visibility = View.VISIBLE + text = itemView.context.getString(R.string.claim_complaint) + setOnClickListener { + // Handle click event + } + } + btnRight.apply { + visibility = View.VISIBLE + text = itemView.context.getString(R.string.claim_order) + setOnClickListener { + // Handle click event + } + } + } + "delivered" -> { + // Untuk status delivered, tampilkan "Beri Ulasan" + btnRight.apply { + visibility = View.VISIBLE + text = itemView.context.getString(R.string.add_review) + setOnClickListener { + // Handle click event + } + } + } + "completed" -> { + statusOrder.apply { + visibility = View.VISIBLE + text = itemView.context.getString(R.string.shipped_orders) + } + deadlineLabel.apply { + visibility = View.VISIBLE + text = itemView.context.getString(R.string.dl_shipped) + } + btnRight.apply { + visibility = View.VISIBLE + text = itemView.context.getString(R.string.add_review) + setOnClickListener { + // Handle click event + } + } + } + } + } + private fun formatDate(dateString: String): String { // In a real app, you would parse the date string and format it // For this example, just return the string as is diff --git a/app/src/main/java/com/alya/ecommerce_serang/ui/order/history/OrderListFragment.kt b/app/src/main/java/com/alya/ecommerce_serang/ui/order/history/OrderListFragment.kt index 6686484..4c51557 100644 --- a/app/src/main/java/com/alya/ecommerce_serang/ui/order/history/OrderListFragment.kt +++ b/app/src/main/java/com/alya/ecommerce_serang/ui/order/history/OrderListFragment.kt @@ -77,6 +77,8 @@ class OrderListFragment : Fragment() { navigateToOrderDetail(order) } + orderAdapter.setFragmentStatus(status) + binding.rvOrders.apply { layoutManager = LinearLayoutManager(requireContext()) adapter = orderAdapter diff --git a/app/src/main/java/com/alya/ecommerce_serang/ui/order/history/OrderProductAdapter.kt b/app/src/main/java/com/alya/ecommerce_serang/ui/order/history/OrderProductAdapter.kt index 2cfcb16..2f36ab7 100644 --- a/app/src/main/java/com/alya/ecommerce_serang/ui/order/history/OrderProductAdapter.kt +++ b/app/src/main/java/com/alya/ecommerce_serang/ui/order/history/OrderProductAdapter.kt @@ -9,6 +9,7 @@ import androidx.recyclerview.widget.RecyclerView import com.alya.ecommerce_serang.R import com.alya.ecommerce_serang.data.api.response.order.OrderItemsItem import com.bumptech.glide.Glide +import com.google.android.material.button.MaterialButton class OrderProductAdapter : RecyclerView.Adapter() { @@ -53,8 +54,11 @@ class OrderProductAdapter : RecyclerView.Adapter - + app:navigationIcon="@drawable/ic_back_24"> + android:fontFamily="@font/dmsans_bold" + android:textSize="18sp" /> @@ -103,7 +102,7 @@ android:layout_height="wrap_content" android:layout_marginTop="16dp" app:cardCornerRadius="8dp" - app:cardElevation="2dp"> + app:cardElevation="4dp"> - - - @@ -239,7 +221,7 @@ android:padding="16dp" app:layout_constraintBottom_toBottomOf="parent"> -