diff --git a/app/src/main/java/com/alya/ecommerce_serang/data/api/dto/PaymentConfirmRequest.kt b/app/src/main/java/com/alya/ecommerce_serang/data/api/dto/PaymentConfirmRequest.kt new file mode 100644 index 0000000..f529a31 --- /dev/null +++ b/app/src/main/java/com/alya/ecommerce_serang/data/api/dto/PaymentConfirmRequest.kt @@ -0,0 +1,12 @@ +package com.alya.ecommerce_serang.data.api.dto + +import com.google.gson.annotations.SerializedName + +data class PaymentConfirmRequest ( + @SerializedName("order_id") + val orderId : Int, + + @SerializedName("status") + val status: String + +) \ No newline at end of file diff --git a/app/src/main/java/com/alya/ecommerce_serang/data/api/response/store/orders/OrderListResponse.kt b/app/src/main/java/com/alya/ecommerce_serang/data/api/response/store/orders/OrderListResponse.kt index 9d1698b..d981252 100644 --- a/app/src/main/java/com/alya/ecommerce_serang/data/api/response/store/orders/OrderListResponse.kt +++ b/app/src/main/java/com/alya/ecommerce_serang/data/api/response/store/orders/OrderListResponse.kt @@ -77,7 +77,7 @@ data class OrdersItem( val cancelDate: String? = null, @field:SerializedName("payment_evidence") - val paymentEvidence: Any? = null, + val paymentEvidence: String, @field:SerializedName("longitude") val longitude: String? = null, @@ -152,7 +152,7 @@ data class OrdersItem( val postalCode: String? = null, @field:SerializedName("order_id") - val orderId: Int? = null, + val orderId: Int, @field:SerializedName("username") val username: String? = null, diff --git a/app/src/main/java/com/alya/ecommerce_serang/data/api/response/store/orders/PaymentConfirmationResponse.kt b/app/src/main/java/com/alya/ecommerce_serang/data/api/response/store/orders/PaymentConfirmationResponse.kt index 498cb6f..8f9156a 100644 --- a/app/src/main/java/com/alya/ecommerce_serang/data/api/response/store/orders/PaymentConfirmationResponse.kt +++ b/app/src/main/java/com/alya/ecommerce_serang/data/api/response/store/orders/PaymentConfirmationResponse.kt @@ -5,5 +5,5 @@ import com.google.gson.annotations.SerializedName data class PaymentConfirmationResponse( @field:SerializedName("message") - val message: String? = null + val message: String ) diff --git a/app/src/main/java/com/alya/ecommerce_serang/data/api/retrofit/ApiService.kt b/app/src/main/java/com/alya/ecommerce_serang/data/api/retrofit/ApiService.kt index 7763e6d..17784e6 100644 --- a/app/src/main/java/com/alya/ecommerce_serang/data/api/retrofit/ApiService.kt +++ b/app/src/main/java/com/alya/ecommerce_serang/data/api/retrofit/ApiService.kt @@ -14,6 +14,7 @@ import com.alya.ecommerce_serang.data.api.dto.LoginRequest import com.alya.ecommerce_serang.data.api.dto.OrderRequest import com.alya.ecommerce_serang.data.api.dto.OrderRequestBuy import com.alya.ecommerce_serang.data.api.dto.OtpRequest +import com.alya.ecommerce_serang.data.api.dto.PaymentConfirmRequest import com.alya.ecommerce_serang.data.api.dto.ProvinceResponse import com.alya.ecommerce_serang.data.api.dto.RegisterRequest import com.alya.ecommerce_serang.data.api.dto.ReviewProductItem @@ -65,6 +66,7 @@ import com.alya.ecommerce_serang.data.api.response.order.ComplaintResponse import com.alya.ecommerce_serang.data.api.response.order.CompletedOrderResponse import com.alya.ecommerce_serang.data.api.response.product.CreateSearchResponse import com.alya.ecommerce_serang.data.api.response.product.SearchHistoryResponse +import com.alya.ecommerce_serang.data.api.response.store.orders.PaymentConfirmationResponse import com.alya.ecommerce_serang.data.api.response.store.product.CreateProductResponse import com.alya.ecommerce_serang.data.api.response.store.product.DeleteProductResponse import com.alya.ecommerce_serang.data.api.response.store.product.UpdateProductResponse @@ -366,6 +368,11 @@ interface ApiService { @Part("bank_num") bankNum: RequestBody ): Response + @PUT("store/payment/update") + suspend fun paymentConfirmation( + @Body confirmPaymentReq : PaymentConfirmRequest + ): Response + @Multipart @PUT("mystore/edit") suspend fun updateStoreProfileMultipart( diff --git a/app/src/main/java/com/alya/ecommerce_serang/data/repository/SellsRepository.kt b/app/src/main/java/com/alya/ecommerce_serang/data/repository/SellsRepository.kt index f384565..3e991d5 100644 --- a/app/src/main/java/com/alya/ecommerce_serang/data/repository/SellsRepository.kt +++ b/app/src/main/java/com/alya/ecommerce_serang/data/repository/SellsRepository.kt @@ -1,7 +1,9 @@ package com.alya.ecommerce_serang.data.repository import android.util.Log +import com.alya.ecommerce_serang.data.api.dto.PaymentConfirmRequest import com.alya.ecommerce_serang.data.api.response.store.orders.OrderListResponse +import com.alya.ecommerce_serang.data.api.response.store.orders.PaymentConfirmationResponse import com.alya.ecommerce_serang.data.api.retrofit.ApiService class SellsRepository(private val apiService: ApiService) { @@ -42,4 +44,28 @@ class SellsRepository(private val apiService: ApiService) { Log.e("SellsRepository", "Exception updating order status", e) } } + + suspend fun confirmPaymentStore(request: PaymentConfirmRequest): Result { + return try { + Log.d("SellsRepository", "Conforming order request completed: $request") + val response = apiService.paymentConfirmation(request) + + if(response.isSuccessful) { + val paymentConfirmResponse = response.body() + if (paymentConfirmResponse != null) { + Log.d("SellsRepository", "Order confirmed successfully: ${paymentConfirmResponse.message}") + Result.Success(paymentConfirmResponse) + } else { + Log.e("SellsRepository", "Response body was null") + Result.Error(Exception("Empty response from server")) + } + } else { + val errorBody = response.errorBody()?.string() ?: "Unknown Error" + Log.e("SellsRepository", "Error confirming order: $errorBody") + Result.Error(Exception(errorBody)) + } + } catch (e: Exception){ + Result.Error(e) + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/alya/ecommerce_serang/ui/order/history/HistoryActivity.kt b/app/src/main/java/com/alya/ecommerce_serang/ui/order/history/HistoryActivity.kt index 139f894..7027991 100644 --- a/app/src/main/java/com/alya/ecommerce_serang/ui/order/history/HistoryActivity.kt +++ b/app/src/main/java/com/alya/ecommerce_serang/ui/order/history/HistoryActivity.kt @@ -63,7 +63,7 @@ class HistoryActivity : AppCompatActivity() { supportActionBar?.setDisplayShowTitleEnabled(false) binding.btnBack.setOnClickListener { - onBackPressed() +// onBackPressed() finish() } } 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 2051c2c..da1a17c 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 @@ -6,10 +6,10 @@ import android.view.ViewGroup import android.widget.ImageView import android.widget.TextView 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.order.OrderItemsItem import com.bumptech.glide.Glide -import com.google.android.material.button.MaterialButton class OrderProductAdapter : RecyclerView.Adapter() { @@ -48,9 +48,15 @@ class OrderProductAdapter : RecyclerView.Adapter { + if (img.startsWith("/")) BASE_URL + img.substring(1) else img + } + else -> R.drawable.placeholder_image // Default image for null + } // Load product image using Glide Glide.with(itemView.context) - .load(product.productImage) + .load(fullImageUrl) .placeholder(R.drawable.placeholder_image) // .error(R.drawable.error_image) .into(ivProductImage) diff --git a/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/sells/SellsActivity.kt b/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/sells/SellsActivity.kt index da6bb16..13e470e 100644 --- a/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/sells/SellsActivity.kt +++ b/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/sells/SellsActivity.kt @@ -1,8 +1,13 @@ package com.alya.ecommerce_serang.ui.profile.mystore.sells -import androidx.appcompat.app.AppCompatActivity import android.os.Bundle +import android.util.Log +import androidx.activity.enableEdgeToEdge import androidx.activity.viewModels +import androidx.appcompat.app.AppCompatActivity +import androidx.core.view.ViewCompat +import androidx.core.view.WindowCompat +import androidx.core.view.WindowInsetsCompat import androidx.fragment.app.commit import com.alya.ecommerce_serang.R import com.alya.ecommerce_serang.data.api.retrofit.ApiConfig @@ -31,12 +36,28 @@ class SellsActivity : AppCompatActivity() { sessionManager = SessionManager(this) + WindowCompat.setDecorFitsSystemWindows(window, false) + + enableEdgeToEdge() + + // Apply insets to your root layout + ViewCompat.setOnApplyWindowInsetsListener(binding.root) { view, windowInsets -> + val systemBars = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars()) + view.setPadding( + systemBars.left, + systemBars.top, + systemBars.right, + systemBars.bottom + ) + windowInsets + } + + Log.d("SellsActivity", "SellsActivity started") + setupHeader() if (savedInstanceState == null) { - supportFragmentManager.commit { - replace(R.id.fragment_container_sells, SellsFragment()) - } + showSellsFragment() } } @@ -44,7 +65,14 @@ class SellsActivity : AppCompatActivity() { binding.header.headerTitle.text = "Penjualan Saya" binding.header.headerLeftIcon.setOnClickListener { - onBackPressedDispatcher.onBackPressed() + onBackPressed() + finish() + } + } + + private fun showSellsFragment() { + supportFragmentManager.commit { + replace(R.id.fragment_container_sells, SellsFragment()) } } } \ No newline at end of file diff --git a/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/sells/SellsAdapter.kt b/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/sells/SellsAdapter.kt index 5e9794f..7dc5bf5 100644 --- a/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/sells/SellsAdapter.kt +++ b/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/sells/SellsAdapter.kt @@ -5,16 +5,15 @@ import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import android.widget.Button -import android.widget.ImageView import android.widget.TextView +import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import com.alya.ecommerce_serang.R import com.alya.ecommerce_serang.data.api.response.store.orders.OrdersItem import com.alya.ecommerce_serang.ui.profile.mystore.sells.payment.DetailPaymentActivity import com.alya.ecommerce_serang.ui.profile.mystore.sells.shipment.DetailShipmentActivity import com.alya.ecommerce_serang.utils.viewmodel.SellsViewModel -import com.bumptech.glide.Glide +import com.google.android.material.button.MaterialButton import com.google.gson.Gson import java.text.SimpleDateFormat import java.util.Calendar @@ -34,235 +33,310 @@ class SellsAdapter( } fun submitList(newSells: List) { + Log.d("SellsAdapter", "submitList called with ${newSells.size} items") sells.clear() sells.addAll(newSells) notifyDataSetChanged() + Log.d("SellsAdapter", "Adapter updated. Current size: ${sells.size}") } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SellsViewHolder { + Log.d("SellsAdapter", "onCreateViewHolder called") val view = LayoutInflater.from(parent.context).inflate(R.layout.item_sells, parent, false) + Log.d("SellsAdapter", "View inflated successfully") return SellsViewHolder(view) } override fun onBindViewHolder(holder: SellsViewHolder, position: Int) { - holder.bind(sells[position]) + Log.d("SellsAdapter", "onBindViewHolder called for position: $position") + Log.d("SellsAdapter", "Total items in adapter: ${sells.size}") + if (position < sells.size) { + holder.bind(sells[position]) + } else { + Log.e("SellsAdapter", "Position $position is out of bounds for size ${sells.size}") + } } override fun getItemCount(): Int = sells.size inner class SellsViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { - private val layoutOrders: View = itemView.findViewById(R.id.layout_orders) - private val layoutPayments: View = itemView.findViewById(R.id.layout_payments) - private val layoutShipments: View = itemView.findViewById(R.id.layout_shipments) + private val tvStoreName: TextView = itemView.findViewById(R.id.tvUserName) + private val rvOrderItems: RecyclerView = itemView.findViewById(R.id.rvSellsItems) + private val tvShowMore: TextView = itemView.findViewById(R.id.tvShowMores) + private val tvTotalAmount: TextView = itemView.findViewById(R.id.tvTotalAmounts) + private val tvItemCountLabel: TextView = itemView.findViewById(R.id.tv_count_total_items) - private var tvSellsTitle: TextView = itemView.findViewById(R.id.tv_payment_title) - private var tvSellsNumber: TextView = itemView.findViewById(R.id.tv_payment_number) - private var tvSellsDueDesc: TextView = itemView.findViewById(R.id.tv_payment_due_desc) - private var tvSellsDue: TextView = itemView.findViewById(R.id.tv_payment_due) - private var tvSellsLocation: TextView = itemView.findViewById(R.id.tv_payment_location) - private var tvSellsCustomer: TextView = itemView.findViewById(R.id.tv_payment_customer) - private var ivSellsProduct: ImageView = itemView.findViewById(R.id.iv_payment_product) - private var tvSellsProductName: TextView = itemView.findViewById(R.id.tv_payment_product_name) - private var tvSellsProductQty: TextView = itemView.findViewById(R.id.tv_payment_product_qty) - private var tvSellsProductPrice: TextView = itemView.findViewById(R.id.tv_payment_product_price) - private var tvSeeMore: TextView = itemView.findViewById(R.id.tv_see_more_payment) - private var tvSellsQty: TextView = itemView.findViewById(R.id.tv_payment_qty) - private var tvSellsPrice: TextView = itemView.findViewById(R.id.tv_payment_price) - private val btnConfirmPayment: Button = itemView.findViewById(R.id.btn_confirm_payment) - private val btnConfirmShipment: Button = itemView.findViewById(R.id.btn_confirm_shipment) + fun bind(order: OrdersItem) { + Log.d("SellsAdapter", "=== ViewHolder.bind() called ===") + Log.d("SellsAdapter", "Binding order: ${order.orderId} with status: ${order.status}") - fun bind(sells: OrdersItem) { + // Show customer/buyer name (seller's perspective) + tvStoreName.text = order.username ?: "Unknown Customer" + Log.d("SellsAdapter", "Customer name set: ${order.username}") - tvSellsNumber.text = "No. Pesanan: ${sells.orderId}" - tvSellsLocation.text = sells.subdistrict - tvSellsCustomer.text = sells.username + // Set total amount + tvTotalAmount.text = "Rp${order.totalAmount}" + Log.d("SellsAdapter", "Total amount set: ${order.totalAmount}") - val product = sells.orderItems?.get(0) - product?.let { - tvSellsProductName.text = it.productName - tvSellsProductQty.text = "x${it.quantity}" - tvSellsProductPrice.text = "Rp${it.price}" + // Set item count + val itemCount = order.orderItems?.size ?: 0 + tvItemCountLabel.text = itemView.context.getString(R.string.item_count_prod, itemCount) + Log.d("SellsAdapter", "Item count set: $itemCount") - Glide.with(itemView.context) - .load(it.productImage) - .placeholder(R.drawable.placeholder_image) - .into(ivSellsProduct) + // Set up the order items RecyclerView + val productAdapter = SellsProductAdapter() + rvOrderItems.apply { + layoutManager = LinearLayoutManager(itemView.context) + adapter = productAdapter } + Log.d("SellsAdapter", "Product RecyclerView configured") - sells.orderItems?.size?.let { - if (it > 1) { - tvSeeMore.visibility = View.VISIBLE - tvSeeMore.text = "Lihat ${it.minus(1)} produk lainnya" + // Display only the first product and show "View more" for the rest + order.orderItems?.let { items -> + if (items.isNotEmpty()) { + productAdapter.submitList(items.take(1)) + Log.d("SellsAdapter", "Product list submitted: ${items.size} items") + + // Show or hide the "View more" text based on number of items + if (items.size > 1) { + val itemString = items.size - 1 + tvShowMore.visibility = View.VISIBLE + tvShowMore.text = itemView.context.getString(R.string.show_more_product, itemString) + Log.d("SellsAdapter", "Show more visible: $itemString more items") + } else { + tvShowMore.visibility = View.GONE + Log.d("SellsAdapter", "Show more hidden: only 1 item") + } } else { - tvSeeMore.visibility = View.GONE + tvShowMore.visibility = View.GONE + Log.w("SellsAdapter", "Order has no items!") } + } ?: run { + tvShowMore.visibility = View.GONE + Log.w("SellsAdapter", "Order items is null!") } - tvSellsQty.text = "${sells.orderItems?.size} produk" - tvSellsPrice.text = "Rp${sells.totalAmount}" -// -// itemView.setOnClickListener { -// onOrderClickListener(sells) -// } + // Set click listener for the entire order item + itemView.setOnClickListener { + onOrderClickListener(order) + } - adjustDisplay(fragmentStatus, sells) + val actualStatus = if (fragmentStatus == "all") order.status ?: "" else fragmentStatus + Log.d("SellsAdapter", "Adjusting UI for status: '$actualStatus' (fragmentStatus: '$fragmentStatus')") + adjustButtonsAndText(actualStatus, order) + + Log.d("SellsAdapter", "=== ViewHolder.bind() completed ===") } - private fun adjustDisplay(status: String, sells: OrdersItem) { - Log.d("SellsAdapter", "Adjusting display for status: $status") + private fun adjustButtonsAndText(status: String, order: OrdersItem) { + Log.d("SellsAdapter", "Adjusting buttons for status: $status") + + // Get references to buttons and status views + 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) + val deadlineDate = itemView.findViewById(R.id.tvDeadlineDate) + + // Reset visibility + btnLeft.visibility = View.GONE + btnRight.visibility = View.GONE + statusOrder.visibility = View.GONE + deadlineLabel.visibility = View.GONE + deadlineDate.visibility = View.GONE when (status) { - "pending", "unpaid" -> { - layoutOrders.visibility = View.VISIBLE - layoutPayments.visibility = View.GONE - layoutShipments.visibility = View.GONE - - tvSellsTitle = itemView.findViewById(R.id.tv_order_title) - tvSellsNumber = itemView.findViewById(R.id.tv_order_number) - tvSellsDue = itemView.findViewById(R.id.tv_order_due) - tvSellsCustomer = itemView.findViewById(R.id.tv_order_customer) - tvSellsProductName = itemView.findViewById(R.id.tv_order_product_name) - tvSellsProductQty = itemView.findViewById(R.id.tv_order_product_qty) - tvSellsProductPrice = itemView.findViewById(R.id.tv_order_product_price) - tvSeeMore = itemView.findViewById(R.id.tv_see_more_order) - tvSellsQty = itemView.findViewById(R.id.tv_order_qty) - tvSellsPrice = itemView.findViewById(R.id.tv_order_price) - - tvSellsDue.text = formatDueDate(sells.updatedAt.toString(), 1) - - val product = sells.orderItems?.get(0) - product?.let { - tvSellsProductName.text = it.productName - tvSellsProductQty.text = "x${it.quantity}" - tvSellsProductPrice.text = "Rp${it.price}" - Glide.with(itemView.context) - .load(it.productImage) - .placeholder(R.drawable.placeholder_image) - .into(ivSellsProduct) + "pending" -> { + statusOrder.apply { + visibility = View.VISIBLE + text = "Menunggu Tagihan" + } + deadlineLabel.apply { + visibility = View.VISIBLE + text = "Batas waktu konfirmasi:" + } + deadlineDate.apply { + visibility = View.VISIBLE + text = formatDate(order.createdAt ?: "") + } + btnLeft.apply { + visibility = View.VISIBLE + text = "Tolak Pesanan" + setOnClickListener { + // Handle reject order + viewModel.updateOrderStatus(order.orderId, "canceled") + viewModel.refreshOrders() + } + } + btnRight.apply { + visibility = View.VISIBLE + text = "Terima Pesanan" + setOnClickListener { + // Handle accept order + viewModel.updateOrderStatus(order.orderId, "unpaid") + viewModel.refreshOrders() + } + } + } + "unpaid" -> { + statusOrder.apply { + visibility = View.VISIBLE + text = "Konfirmasi Bayar" + } + deadlineLabel.apply { + visibility = View.VISIBLE + text = "Batas pembayaran:" + } + deadlineDate.apply { + visibility = View.VISIBLE + text = formatDatePay(order.updatedAt ?: "") + } + btnLeft.apply { + visibility = View.VISIBLE + text = "Batalkan" + setOnClickListener { + viewModel.updateOrderStatus(order.orderId, "canceled") + viewModel.refreshOrders() + } } - - tvSellsQty.text = "${sells.orderItems?.size} produk" - tvSellsPrice.text = "Rp${sells.totalAmount}" } "paid" -> { - layoutOrders.visibility = View.GONE - layoutPayments.visibility = View.VISIBLE - layoutShipments.visibility = View.GONE - - tvSellsDue.text = formatDueDate(sells.updatedAt.toString(), 2) - btnConfirmPayment.setOnClickListener { - - val context = itemView.context - val intent = Intent(context, DetailPaymentActivity::class.java) - intent.putExtra("sells_data", Gson().toJson(sells)) - context.startActivity(intent) - viewModel.refreshOrders() + statusOrder.apply { + visibility = View.VISIBLE + text = "Sudah Dibayar" + } + deadlineLabel.apply { + visibility = View.VISIBLE + text = "Konfirmasi pembayaran sebelum:" + } + deadlineDate.apply { + visibility = View.VISIBLE + text = formatDatePay(order.updatedAt ?: "") + } + btnRight.apply { + visibility = View.VISIBLE + text = "Konfirmasi Pembayaran" + setOnClickListener { + val context = itemView.context + val intent = Intent(context, DetailPaymentActivity::class.java) + intent.putExtra("sells_data", Gson().toJson(order)) + context.startActivity(intent) + } } - - tvSellsTitle.text = "Pesanan Telah Dibayar" - tvSellsDueDesc.text = "Konfirmasi pembayaran sebelum:" - tvSellsDue.text = formatDueDate(sells.updatedAt.toString(), 2) - } "processed" -> { - layoutOrders.visibility = View.GONE - layoutPayments.visibility = View.GONE - layoutShipments.visibility = View.VISIBLE - - tvSellsTitle = itemView.findViewById(R.id.tv_shipment_title) - tvSellsNumber = itemView.findViewById(R.id.tv_shipment_number) - tvSellsDue = itemView.findViewById(R.id.tv_shipment_due) - tvSellsLocation = itemView.findViewById(R.id.tv_shipment_location) - tvSellsCustomer = itemView.findViewById(R.id.tv_shipment_customer) - tvSellsProductName = itemView.findViewById(R.id.tv_shipment_product_name) - tvSellsProductQty = itemView.findViewById(R.id.tv_shipment_product_qty) - tvSeeMore = itemView.findViewById(R.id.tv_see_more_shipment) - - tvSellsDue.text = formatDueDate(sells.updatedAt.toString(), 2) - btnConfirmShipment.setOnClickListener { - val context = itemView.context - val intent = Intent(context, DetailShipmentActivity::class.java) - intent.putExtra("sells_data", Gson().toJson(sells)) - context.startActivity(intent) + statusOrder.apply { + visibility = View.VISIBLE + text = "Diproses" + } + deadlineLabel.apply { + visibility = View.VISIBLE + text = "Kirim sebelum:" + } + deadlineDate.apply { + visibility = View.VISIBLE + text = formatDatePay(order.updatedAt ?: "") + } + btnRight.apply { + visibility = View.VISIBLE + text = "Kirim Pesanan" + setOnClickListener { + val context = itemView.context + val intent = Intent(context, DetailShipmentActivity::class.java) + intent.putExtra("sells_data", Gson().toJson(order)) + context.startActivity(intent) + } } - - tvSellsTitle.text = "Pesanan Perlu Dikirim" - tvSellsNumber.text = "No. Pesanan: ${sells.orderId}" - tvSellsLocation.text = sells.subdistrict - tvSellsCustomer.text = sells.username - tvSellsDue.text = formatDueDate(sells.updatedAt.toString(), 2) } "shipped" -> { - layoutOrders.visibility = View.GONE - layoutPayments.visibility = View.VISIBLE - layoutShipments.visibility = View.GONE - - tvSellsTitle.text = "Pesanan Telah Dikirim" - tvSellsDueDesc.text = "Dikirimkan pada" - - tvSellsDue.text = formatDueDate(sells.updatedAt.toString(), 0) - tvSellsDue.background = itemView.context.getDrawable(R.drawable.bg_product_inactive) - btnConfirmPayment.visibility = View.GONE - } - "delivered" -> { - layoutOrders.visibility = View.GONE - layoutPayments.visibility = View.VISIBLE - layoutShipments.visibility = View.GONE - - tvSellsTitle.text = "Pesanan Telah Dikirim" - tvSellsDueDesc.text = "Dikirimkan pada" - - tvSellsDue.text = formatDueDate(sells.updatedAt.toString(), 0) - tvSellsDue.background = itemView.context.getDrawable(R.drawable.bg_product_inactive) - btnConfirmPayment.visibility = View.GONE + statusOrder.apply { + visibility = View.VISIBLE + text = "Dikirim" + } + deadlineLabel.apply { + visibility = View.VISIBLE + text = "Dikirimkan pada:" + } + deadlineDate.apply { + visibility = View.VISIBLE + text = formatDate(order.updatedAt ?: "") + } } "completed" -> { - layoutOrders.visibility = View.GONE - layoutPayments.visibility = View.VISIBLE - layoutShipments.visibility = View.GONE - - tvSellsTitle.text = "Pesanan Selesai" - tvSellsDueDesc.text = "Selesai pada" - - tvSellsDue.text = formatDueDate(sells.updatedAt.toString(), 0) - tvSellsDue.background = itemView.context.getDrawable(R.drawable.bg_product_inactive) - btnConfirmPayment.visibility = View.GONE + statusOrder.apply { + visibility = View.VISIBLE + text = "Selesai" + } + deadlineLabel.apply { + visibility = View.VISIBLE + text = "Selesai pada:" + } + deadlineDate.apply { + visibility = View.VISIBLE + text = formatDate(order.updatedAt ?: "") + } } "canceled" -> { - layoutOrders.visibility = View.GONE - layoutPayments.visibility = View.VISIBLE - layoutShipments.visibility = View.GONE - - tvSellsTitle.text = "Pesanan Dibatalkan" - tvSellsDueDesc.text = "Dibatalkan pada" - - tvSellsDue.text = formatDueDate(sells.updatedAt.toString(), 0) - tvSellsDue.background = itemView.context.getDrawable(R.drawable.bg_product_inactive) - btnConfirmPayment.visibility = View.GONE + statusOrder.apply { + visibility = View.VISIBLE + text = "Dibatalkan" + } + deadlineLabel.apply { + visibility = View.VISIBLE + text = "Dibatalkan pada:" + } + deadlineDate.apply { + visibility = View.VISIBLE + text = formatDate(order.cancelDate ?: "") + } } } } - private fun formatDueDate(date: String, dueDay: Int): String { + private fun formatDate(dateString: String): String { return try { val inputFormat = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.getDefault()) inputFormat.timeZone = TimeZone.getTimeZone("UTC") - val outputFormat = SimpleDateFormat("dd MM; HH.mm", Locale("id", "ID")) + val outputFormat = SimpleDateFormat("HH:mm dd MMMM yyyy", Locale("id", "ID")) - val date = inputFormat.parse(date) + val date = inputFormat.parse(dateString) date?.let { val calendar = Calendar.getInstance() calendar.time = it - calendar.add(Calendar.DATE, dueDay) + calendar.set(Calendar.HOUR_OF_DAY, 23) + calendar.set(Calendar.MINUTE, 59) outputFormat.format(calendar.time) - } ?: date + } ?: dateString } catch (e: Exception) { - Log.e("DueDateFormatting", "Error formatting date: ${e.message}") - date - }.toString() + Log.e("DateFormatting", "Error formatting date: ${e.message}") + dateString + } + } + + private fun formatDatePay(dateString: String): String { + return try { + // Parse the ISO 8601 date + val isoDateFormat = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.getDefault()) + isoDateFormat.timeZone = TimeZone.getTimeZone("UTC") + + val createdDate = isoDateFormat.parse(dateString) + + // Add 24 hours to get due date + val calendar = Calendar.getInstance() + calendar.time = createdDate + calendar.add(Calendar.HOUR, 24) + + // Format due date for display + val dueDateFormat = SimpleDateFormat("dd MMM yyyy", Locale.getDefault()) + dueDateFormat.format(calendar.time) + + } catch (e: Exception) { + Log.e("DateFormatting", "Error formatting date: ${e.message}") + dateString + } } } } \ No newline at end of file diff --git a/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/sells/SellsFragment.kt b/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/sells/SellsFragment.kt index 786c6e3..5074a2c 100644 --- a/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/sells/SellsFragment.kt +++ b/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/sells/SellsFragment.kt @@ -1,12 +1,10 @@ package com.alya.ecommerce_serang.ui.profile.mystore.sells import android.os.Bundle -import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.fragment.app.Fragment -import androidx.viewpager2.widget.ViewPager2 import com.alya.ecommerce_serang.R import com.alya.ecommerce_serang.databinding.FragmentSellsBinding import com.alya.ecommerce_serang.utils.SessionManager @@ -21,9 +19,10 @@ class SellsFragment : Fragment() { private lateinit var viewPagerAdapter: SellsViewPagerAdapter override fun onCreateView( - inflater: LayoutInflater, container: ViewGroup?, + inflater: LayoutInflater, + container: ViewGroup?, savedInstanceState: Bundle? - ): View? { + ): View { _binding = FragmentSellsBinding.inflate(inflater, container, false) return binding.root } @@ -36,58 +35,28 @@ class SellsFragment : Fragment() { } private fun setupViewPager() { + // Initialize the ViewPager adapter viewPagerAdapter = SellsViewPagerAdapter(requireActivity()) binding.viewPagerSells.adapter = viewPagerAdapter - TabLayoutMediator(binding.tabLayoutSells, binding.viewPagerSells) {tab, position -> - tab.text = when(position){ - 0 -> getString(R.string.all_orders) - 1 -> getString(R.string.pending_orders) - 2 -> getString(R.string.unpaid_orders) - 3 -> getString(R.string.processed_orders) - 4 -> getString(R.string.paid_orders) - 5 -> getString(R.string.shipped_orders) - 6 -> getString(R.string.completed_orders) - 7 -> getString(R.string.canceled_orders) + // Connect TabLayout with ViewPager2 + TabLayoutMediator(binding.tabLayoutSells, binding.viewPagerSells) { tab, position -> + tab.text = when (position) { + 0 -> getString(R.string.all_orders) // "Semua Pesanan" + 1 -> getString(R.string.pending_orders) // "Menunggu Tagihan" + 2 -> getString(R.string.unpaid_orders) // "Konfirmasi Bayar" + 3 -> getString(R.string.paid_orders) // "Diproses" + 4 -> getString(R.string.processed_orders) // "Sudah Dibayar" + 5 -> getString(R.string.shipped_orders) // "Dikirim" + 6 -> getString(R.string.completed_orders) // "Selesai" + 7 -> getString(R.string.canceled_orders) // "Dibatalkan" else -> "Tab $position" } }.attach() - - binding.viewPagerSells.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() { - override fun onPageSelected(position: Int) { - super.onPageSelected(position) - - val statusList = listOf("all", "pending", "unpaid", "processed", "paid", "shipped", "completed", "canceled") - val selectedStatus = statusList.getOrNull(position) ?: "unknown" - val tabText = when(position) { - 0 -> getString(R.string.all_orders) - 1 -> getString(R.string.pending_orders) - 2 -> getString(R.string.unpaid_orders) - 3 -> getString(R.string.processed_orders) - 4 -> getString(R.string.paid_orders) - 5 -> getString(R.string.shipped_orders) - 6 -> getString(R.string.completed_orders) - 7 -> getString(R.string.canceled_orders) - else -> "Tab $position" - } - - Log.d(TAG, "🔄 *** TAB SWITCHED ***") - Log.d(TAG, "Selected position: $position") - Log.d(TAG, "Tab text: '$tabText'") - Log.d(TAG, "Status for this tab: '$selectedStatus'") - Log.d(TAG, "*** This should trigger SellsListFragment for '$selectedStatus' ***") - } - }) - } override fun onDestroyView() { super.onDestroyView() _binding = null } - - companion object { - private const val TAG = "SellsListFragment" - - } -} +} \ No newline at end of file diff --git a/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/sells/SellsListFragment.kt b/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/sells/SellsListFragment.kt index 9770abc..ed01095 100644 --- a/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/sells/SellsListFragment.kt +++ b/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/sells/SellsListFragment.kt @@ -11,6 +11,7 @@ import androidx.fragment.app.viewModels import androidx.recyclerview.widget.LinearLayoutManager import com.alya.ecommerce_serang.data.api.response.store.orders.OrdersItem import com.alya.ecommerce_serang.data.api.retrofit.ApiConfig +import com.alya.ecommerce_serang.data.repository.Result import com.alya.ecommerce_serang.data.repository.SellsRepository import com.alya.ecommerce_serang.databinding.FragmentSellsListBinding import com.alya.ecommerce_serang.ui.order.address.ViewState @@ -22,7 +23,7 @@ class SellsListFragment : Fragment() { private var _binding: FragmentSellsListBinding? = null private val binding get() = _binding!! - private lateinit var sessionManager: SessionManager + private lateinit var sessionManager: SessionManager private val viewModel: SellsViewModel by viewModels { BaseViewModelFactory { @@ -31,39 +32,45 @@ class SellsListFragment : Fragment() { SellsViewModel(sellsRepository) } } - private lateinit var sellsAdapter: SellsAdapter + private var status: String = "all" companion object { private const val TAG = "SellsListFragment" + private const val ARG_STATUS = "status" fun newInstance(status: String): SellsListFragment { - Log.d(TAG, "=== Creating new instance ===") - Log.d(TAG, "Status: '$status'") + Log.d(TAG, "Creating new instance with status: '$status'") return SellsListFragment().apply { arguments = Bundle().apply { putString(ARG_STATUS, status) } - Log.d(TAG, "Fragment instance created with status: '$status'") } } } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + Log.d(TAG, "onCreate called") + sessionManager = SessionManager(requireContext()) arguments?.let { status = it.getString(ARG_STATUS) ?: "all" } + Log.d(TAG, "Fragment status set to: '$status'") + } override fun onCreateView( - inflater: LayoutInflater, container: ViewGroup?, + inflater: LayoutInflater, + container: ViewGroup?, savedInstanceState: Bundle? - ): View? { + ): View { + Log.d(TAG, "onCreateView called") + _binding = FragmentSellsListBinding.inflate(inflater, container, false) return binding.root } @@ -73,90 +80,104 @@ class SellsListFragment : Fragment() { setupRecyclerView() observeSellsList() + observePaymentConfirmation() loadSells() } - override fun onDestroyView() { - super.onDestroyView() - _binding = null - } - - - private fun setupRecyclerView() { + Log.d(TAG, "Setting up RecyclerView") sellsAdapter = SellsAdapter( - onOrderClickListener = { sells -> - Log.d(TAG, "Order clicked: ${sells.orderId} in status '$status'") - navigateToSellsDetail(sells) + onOrderClickListener = { order -> + Log.d(TAG, "Order clicked: ${order.orderId}") + navigateToSellsDetail(order) }, viewModel = viewModel ) - Log.d(TAG, "Setting adapter fragment status to: '$status'") sellsAdapter.setFragmentStatus(status) + Log.d(TAG, "Adapter fragment status set to: '$status'") binding.rvSells.apply { layoutManager = LinearLayoutManager(requireContext()) adapter = sellsAdapter - Log.d(TAG, "RecyclerView configured with LinearLayoutManager and adapter") } - - // Log RecyclerView visibility and properties - Log.d(TAG, "RecyclerView visibility: ${binding.rvSells.visibility}") - Log.d(TAG, "RecyclerView parent: ${binding.rvSells.parent}") + Log.d(TAG, "RecyclerView configured") } private fun observeSellsList() { + Log.d(TAG, "Setting up sells list observer") + viewModel.sells.observe(viewLifecycleOwner) { result -> + Log.d(TAG, "Sells list observer triggered with result: ${result.javaClass.simpleName}") when (result) { is ViewState.Success -> { binding.progressBar.visibility = View.GONE + Log.d(TAG, "Data received: ${result.data?.size ?: 0} items") if (result.data.isNullOrEmpty()) { binding.tvEmptyState.visibility = View.VISIBLE binding.rvSells.visibility = View.GONE + Log.d(TAG, "Showing empty state") + } else { + Log.d(TAG, "✅ Data is available: ${result.data.size} items") binding.tvEmptyState.visibility = View.GONE binding.rvSells.visibility = View.VISIBLE - result.data.forEachIndexed { index, order -> - Log.d(TAG, "Order $index:") - Log.d(TAG, " - ID: ${order.orderId}") - Log.d(TAG, " - Status: ${order.status}") - Log.d(TAG, " - Customer: ${order.username}") - Log.d(TAG, " - Total: ${order.totalAmount}") - Log.d(TAG, " - Items: ${order.orderItems?.size ?: 0}") +// Log first few items for debugging + result.data.take(3).forEachIndexed { index, order -> + Log.d(TAG, "Order ${index + 1}: ID=${order.orderId}, Status=${order.status}, Customer=${order.username}") } - sellsAdapter.submitList(result.data) - Log.d(TAG, "Final UI state:") - Log.d(TAG, " - ProgressBar visibility: ${binding.progressBar.visibility}") - Log.d(TAG, " - EmptyState visibility: ${binding.tvEmptyState.visibility}") - Log.d(TAG, " - RecyclerView visibility: ${binding.rvSells.visibility}") - Log.d(TAG, " - Adapter item count: ${sellsAdapter.itemCount}") - } + sellsAdapter.submitList(result.data) + Log.d(TAG, "Data submitted to adapter") + Log.d(TAG, "Adapter item count: ${sellsAdapter.itemCount}") } } is ViewState.Error -> { + Log.e(TAG, "❌ ViewState.Error received: ${result.message}") + binding.progressBar.visibility = View.GONE binding.tvEmptyState.visibility = View.VISIBLE Toast.makeText(requireContext(), result.message, Toast.LENGTH_SHORT).show() } is ViewState.Loading -> { binding.progressBar.visibility = View.VISIBLE - binding.rvSells.visibility = View.GONE - binding.tvEmptyState.visibility = View.GONE + } + } + } + } + + private fun observePaymentConfirmation() { + viewModel.confirmPaymentStore.observe(viewLifecycleOwner) { result -> + when (result) { + is Result.Loading -> { + // Handle loading state if needed + } + is Result.Success -> { + Toast.makeText(requireContext(), "Payment confirmed successfully!", Toast.LENGTH_SHORT).show() + loadSells() + } + is Result.Error -> { + Toast.makeText(requireContext(), "Failed to payment confirm order: ${result.exception.message}", Toast.LENGTH_SHORT).show() } } } } private fun loadSells() { - Log.d(TAG, "Calling viewModel.getSellList('$status')") + Log.d(TAG, "Loading sells with status: '$status'") viewModel.getSellList(status) + Log.d(TAG, "getSellList called") } - private fun navigateToSellsDetail(sells: OrdersItem) { - // In a real app, you would navigate to sells detail screen - // For example: findNavController().navigate(SellsListFragmentDirections.actionToSellsDetail(sells.orderId)) - Toast.makeText(requireContext(), "Order ID: ${sells.orderId}", Toast.LENGTH_SHORT).show() + private fun navigateToSellsDetail(order: OrdersItem) { + Log.d(TAG, "Navigating to sells detail for order: ${order.orderId}") + // Navigate to order detail from seller's perspective + // Seller views customer's order details to manage fulfillment + Toast.makeText(requireContext(), "Customer Order ID: ${order.orderId}", Toast.LENGTH_SHORT).show() + } + + override fun onDestroyView() { + super.onDestroyView() + _binding = null } } \ No newline at end of file diff --git a/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/sells/SellsProductAdapter.kt b/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/sells/SellsProductAdapter.kt index 68a3cdf..2ece8da 100644 --- a/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/sells/SellsProductAdapter.kt +++ b/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/sells/SellsProductAdapter.kt @@ -10,9 +10,15 @@ import com.alya.ecommerce_serang.R import com.alya.ecommerce_serang.data.api.response.store.orders.OrderItemsItem import com.bumptech.glide.Glide -class SellsProductAdapter( - private val items: List -) : RecyclerView.Adapter() { +class SellsProductAdapter : RecyclerView.Adapter() { + + private val items = mutableListOf() + + fun submitList(newItems: List) { + items.clear() + items.addAll(newItems) + notifyDataSetChanged() + } inner class ProductViewHolder(view: View) : RecyclerView.ViewHolder(view) { val ivProduct: ImageView = view.findViewById(R.id.iv_order_product) diff --git a/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/sells/SellsViewPagerAdapter.kt b/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/sells/SellsViewPagerAdapter.kt index 37cd52b..85ead97 100644 --- a/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/sells/SellsViewPagerAdapter.kt +++ b/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/sells/SellsViewPagerAdapter.kt @@ -1,14 +1,14 @@ package com.alya.ecommerce_serang.ui.profile.mystore.sells -import android.util.Log import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentActivity import androidx.viewpager2.adapter.FragmentStateAdapter -import io.ktor.client.utils.EmptyContent.status -class SellsViewPagerAdapter(fragmentActivity: FragmentActivity) - : FragmentStateAdapter(fragmentActivity) { +class SellsViewPagerAdapter( + fragmentActivity: FragmentActivity +) : FragmentStateAdapter(fragmentActivity) { + // Define all possible sells statuses - keeping your original list private val sellsStatuses = listOf( "all", // Position 0: "Semua Pesanan" "pending", // Position 1: "Menunggu Tagihan" @@ -20,34 +20,10 @@ class SellsViewPagerAdapter(fragmentActivity: FragmentActivity) "canceled" // Position 7: "Dibatalkan" ) - init { - Log.d(TAG, "=== ViewPager Status Mapping ===") - sellsStatuses.forEachIndexed { index, status -> - val tabText = when(index) { - 0 -> "Semua Pesanan" - 1 -> "Menunggu Tagihan" - 2 -> "Konfirmasi Bayar" - 3 -> "Diproses" - 4 -> "Sudah Dibayar" - 5 -> "Dikirim" - 6 -> "Selesai" - 7 -> "Dibatalkan" - else -> "Tab $index" - } - Log.d(TAG, "Position $index: '$tabText' → Status: '$status'") - } - Log.d(TAG, "=== End Mapping ===") - } - - override fun getItemCount(): Int = sellsStatuses.size override fun createFragment(position: Int): Fragment { - Log.d(TAG, "Creating fragment for position $position with status: '$status'") + // Create a new instance of SellsListFragment with the appropriate status return SellsListFragment.newInstance(sellsStatuses[position]) } - - companion object { - private const val TAG = "SellsViewPagerAdapter" - } } \ No newline at end of file diff --git a/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/sells/payment/DetailPaymentActivity.kt b/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/sells/payment/DetailPaymentActivity.kt index 09e3fe8..7e9d252 100644 --- a/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/sells/payment/DetailPaymentActivity.kt +++ b/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/sells/payment/DetailPaymentActivity.kt @@ -1,11 +1,34 @@ package com.alya.ecommerce_serang.ui.profile.mystore.sells.payment +import android.app.Dialog +import android.graphics.Color +import android.graphics.drawable.ColorDrawable +import android.graphics.drawable.Drawable import android.os.Bundle +import android.view.View +import android.view.ViewGroup +import android.view.Window +import android.widget.ImageButton +import android.widget.ImageView +import android.widget.ProgressBar +import android.widget.TextView +import android.widget.Toast +import androidx.activity.viewModels import androidx.appcompat.app.AppCompatActivity import androidx.recyclerview.widget.LinearLayoutManager +import com.alya.ecommerce_serang.BuildConfig.BASE_URL +import com.alya.ecommerce_serang.R import com.alya.ecommerce_serang.data.api.response.store.orders.OrdersItem +import com.alya.ecommerce_serang.data.api.retrofit.ApiConfig +import com.alya.ecommerce_serang.data.repository.SellsRepository import com.alya.ecommerce_serang.databinding.ActivityDetailPaymentBinding import com.alya.ecommerce_serang.ui.profile.mystore.sells.SellsProductAdapter +import com.alya.ecommerce_serang.utils.BaseViewModelFactory +import com.alya.ecommerce_serang.utils.SessionManager +import com.alya.ecommerce_serang.utils.viewmodel.SellsViewModel +import com.bumptech.glide.Glide +import com.bumptech.glide.load.engine.DiskCacheStrategy +import com.bumptech.glide.request.target.CustomTarget import com.google.gson.Gson import java.text.SimpleDateFormat import java.util.Locale @@ -15,17 +38,37 @@ class DetailPaymentActivity : AppCompatActivity() { private lateinit var binding: ActivityDetailPaymentBinding private lateinit var sells: OrdersItem + private lateinit var productAdapter: SellsProductAdapter + private lateinit var sessionManager: SessionManager + + + private val viewModel: SellsViewModel by viewModels { + BaseViewModelFactory { + val apiService = ApiConfig.getApiService(sessionManager) + val sellsRepository = SellsRepository(apiService) + SellsViewModel(sellsRepository) + } + } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityDetailPaymentBinding.inflate(layoutInflater) setContentView(binding.root) + sessionManager = SessionManager(this) + val orderJson = intent.getStringExtra("sells_data") sells = Gson().fromJson(orderJson, OrdersItem::class.java) - bindOrderDetails() + binding.header.headerLeftIcon.setOnClickListener { +// onBackPressed() + finish() + } + setupRecyclerView() + bindOrderDetails() + setupPaymentEvidenceViewer() + } private fun bindOrderDetails() = with(binding) { @@ -42,15 +85,107 @@ class DetailPaymentActivity : AppCompatActivity() { tvOrderRecipient.text = sells.username // tvOrderRecipientNum.text = sells.phone tvOrderRecipientAddress.text = sells.street +// sells.paymentEvidence + + binding.btnConfirmPayment.setOnClickListener{ + viewModel.confirmPayment(sells.orderId, "confirmed") + finish() + } } private fun setupRecyclerView() { + productAdapter = SellsProductAdapter() + binding.rvProductItems.apply { layoutManager = LinearLayoutManager(this@DetailPaymentActivity) - adapter = SellsProductAdapter(sells.orderItems ?: emptyList()) + adapter = productAdapter + } + + // Submit the order items to the adapter + productAdapter.submitList(sells.orderItems ?: emptyList()) + } + + private fun setupPaymentEvidenceViewer() { + binding.tvPaymentDueDesc.setOnClickListener { + val paymentEvidence = sells.paymentEvidence + if (!paymentEvidence.isNullOrEmpty()) { + showPaymentEvidenceDialog(paymentEvidence) + } else { + Toast.makeText(this, "Bukti pembayaran tidak tersedia", Toast.LENGTH_SHORT).show() + } } } + private fun showPaymentEvidenceDialog(paymentEvidence: String) { + val dialog = Dialog(this) + dialog.requestWindowFeature(Window.FEATURE_NO_TITLE) + dialog.setContentView(R.layout.dialog_image_viewer) + dialog.setCancelable(true) + + // Set dialog to fullscreen + val window = dialog.window + window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT) + window?.setBackgroundDrawable(ColorDrawable(Color.BLACK)) + + // Get views from dialog + val imageView = dialog.findViewById(R.id.iv_payment_evidence) + val btnClose = dialog.findViewById(R.id.btn_close) + val tvTitle = dialog.findViewById(R.id.tv_title) + val progressBar = dialog.findViewById(R.id.progress_bar) + + // Set title + tvTitle.text = "Bukti Pembayaran" + + // Build image URL + val fullImageUrl = when (val img = paymentEvidence) { + is String -> { + if (img.startsWith("/")) BASE_URL + img.substring(1) else img + } + else -> R.drawable.placeholder_image // Default image for null + } + + // Show progress bar while loading + progressBar.visibility = View.VISIBLE + + // Load image with Glide + Glide.with(this) + .load(fullImageUrl) + .placeholder(R.drawable.placeholder_image) + .error(R.drawable.placeholder_image) + .diskCacheStrategy(DiskCacheStrategy.ALL) + .into(object : CustomTarget() { + override fun onResourceReady(resource: Drawable, transition: com.bumptech.glide.request.transition.Transition?) { + progressBar.visibility = View.GONE + imageView.setImageDrawable(resource) + } + + override fun onLoadCleared(placeholder: Drawable?) { + progressBar.visibility = View.GONE + imageView.setImageDrawable(placeholder) + } + + override fun onLoadFailed(errorDrawable: Drawable?) { + progressBar.visibility = View.GONE + imageView.setImageDrawable(errorDrawable) + Toast.makeText(this@DetailPaymentActivity, "Gagal memuat gambar", Toast.LENGTH_SHORT).show() + } + }) + + + // Close button click listener + btnClose.setOnClickListener { + dialog.dismiss() + } + + // Click outside to close + imageView.setOnClickListener { + dialog.dismiss() + } + + dialog.show() + } + + private fun formatDate(dateStr: String?): String { return try { val inputFormat = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.getDefault()) diff --git a/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/sells/shipment/DetailShipmentActivity.kt b/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/sells/shipment/DetailShipmentActivity.kt index f52671c..e0b9969 100644 --- a/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/sells/shipment/DetailShipmentActivity.kt +++ b/app/src/main/java/com/alya/ecommerce_serang/ui/profile/mystore/sells/shipment/DetailShipmentActivity.kt @@ -15,17 +15,18 @@ class DetailShipmentActivity : AppCompatActivity() { private lateinit var binding: ActivityDetailShipmentBinding private lateinit var sells: OrdersItem + private lateinit var productAdapter: SellsProductAdapter override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityDetailShipmentBinding.inflate(layoutInflater) setContentView(binding.root) - val orderJson = intent.getStringExtra("order_data") + val orderJson = intent.getStringExtra("sells_data") sells = Gson().fromJson(orderJson, OrdersItem::class.java) - bindOrderDetails() setupRecyclerView() + bindOrderDetails() } private fun bindOrderDetails() = with(binding) { @@ -45,10 +46,15 @@ class DetailShipmentActivity : AppCompatActivity() { } private fun setupRecyclerView() { + productAdapter = SellsProductAdapter() + binding.rvProductItems.apply { layoutManager = LinearLayoutManager(this@DetailShipmentActivity) - adapter = SellsProductAdapter(sells.orderItems ?: emptyList()) + adapter = productAdapter } + + // Submit the order items to the adapter + productAdapter.submitList(sells.orderItems ?: emptyList()) } private fun formatDate(dateStr: String?): String { diff --git a/app/src/main/java/com/alya/ecommerce_serang/utils/viewmodel/SellsViewModel.kt b/app/src/main/java/com/alya/ecommerce_serang/utils/viewmodel/SellsViewModel.kt index 6fb5028..76cb4fe 100644 --- a/app/src/main/java/com/alya/ecommerce_serang/utils/viewmodel/SellsViewModel.kt +++ b/app/src/main/java/com/alya/ecommerce_serang/utils/viewmodel/SellsViewModel.kt @@ -5,7 +5,9 @@ import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import com.alya.ecommerce_serang.data.api.dto.PaymentConfirmRequest import com.alya.ecommerce_serang.data.api.response.store.orders.OrdersItem +import com.alya.ecommerce_serang.data.api.response.store.orders.PaymentConfirmationResponse import com.alya.ecommerce_serang.data.repository.Result import com.alya.ecommerce_serang.data.repository.SellsRepository import com.alya.ecommerce_serang.ui.order.address.ViewState @@ -20,66 +22,159 @@ class SellsViewModel(private val repository: SellsRepository) : ViewModel() { private val _sells = MutableLiveData>>() val sells: LiveData>> = _sells + private val _confirmPaymentStore = MutableLiveData>() + val confirmPaymentStore: LiveData> = _confirmPaymentStore + fun getSellList(status: String) { + Log.d(TAG, "========== Starting getSellList ==========") Log.d(TAG, "Requested status: '$status'") + Log.d(TAG, "Repository instance: ${repository.javaClass.simpleName}") + _sells.value = ViewState.Loading + Log.d(TAG, "ViewState set to Loading") viewModelScope.launch { - _sells.value = ViewState.Loading + Log.d(TAG, "Coroutine launched successfully") try { + Log.d(TAG, "Calling repository.getSellList(status='$status')") + val startTime = System.currentTimeMillis() + when (val result = repository.getSellList(status)) { is Result.Success -> { + val endTime = System.currentTimeMillis() + Log.d(TAG, "Repository call completed in ${endTime - startTime}ms") + Log.d(TAG, "Result.Success received from repository") + + // Log the entire result data structure + Log.d(TAG, "Raw result data: ${result.data}") + Log.d(TAG, "Result data class: ${result.data?.javaClass?.simpleName}") + val orders = result.data.orders - Log.d(TAG, "Orders list: $orders") + Log.d(TAG, "Extracted orders list: $orders") + Log.d(TAG, "Orders list class: ${orders?.javaClass?.simpleName}") Log.d(TAG, "Orders count: ${orders?.size ?: 0}") - // Log individual order details - orders?.forEachIndexed { index, order -> - Log.d(TAG, "Order $index:") - Log.d(TAG, " - ID: ${order.orderId}") - Log.d(TAG, " - Status: ${order.status}") - Log.d(TAG, " - Customer: ${order.username}") - Log.d(TAG, " - Total: ${order.totalAmount}") - Log.d(TAG, " - Items count: ${order.orderItems?.size ?: 0}") - Log.d(TAG, " - Updated at: ${order.updatedAt}") + // Check if orders list is null or empty + if (orders == null) { + Log.w(TAG, "⚠️ Orders list is NULL") + } else if (orders.isEmpty()) { + Log.w(TAG, "⚠️ Orders list is EMPTY") + } else { + Log.d(TAG, "✅ Orders list contains ${orders.size} items") + + // Log individual order details with more comprehensive info + orders.forEachIndexed { index, order -> + Log.d(TAG, "--- Order ${index + 1}/${orders.size} ---") + Log.d(TAG, " Order object: $order") + Log.d(TAG, " Order class: ${order?.javaClass?.simpleName}") + Log.d(TAG, " - ID: ${order?.orderId}") + Log.d(TAG, " - Status: '${order?.status}'") + Log.d(TAG, " - Customer: '${order?.username}'") + Log.d(TAG, " - Total: ${order?.totalAmount}") + Log.d(TAG, " - Items count: ${order?.orderItems?.size ?: 0}") + Log.d(TAG, " - Created at: ${order?.createdAt}") + Log.d(TAG, " - Updated at: ${order?.updatedAt}") + + // Log order items if available + order?.orderItems?.let { items -> + Log.d(TAG, " Order items:") + items.forEachIndexed { itemIndex, item -> + Log.d(TAG, " Item ${itemIndex + 1}: ${item?.productName} (Qty: ${item?.quantity})") + } + } + } } - _sells.value = ViewState.Success(result.data.orders) - Log.d("SellsViewModel", "Sells loaded successfully: ${result.data.orders?.size} items") + + // Set the ViewState to Success + _sells.value = ViewState.Success(orders ?: emptyList()) + Log.d(TAG, "✅ ViewState.Success set with ${orders?.size ?: 0} orders") } + is Result.Error -> { - _sells.value = ViewState.Error(result.exception.message ?: "Unknown error occurred") - Log.e("SellsViewModel", "Error loading sells", result.exception) + val endTime = System.currentTimeMillis() + Log.e(TAG, "Repository call failed in ${endTime - startTime}ms") + Log.e(TAG, "❌ Result.Error received from repository") + Log.e(TAG, "Error message: ${result.exception.message}") + Log.e(TAG, "Exception type: ${result.exception.javaClass.simpleName}") + Log.e(TAG, "Exception stack trace:", result.exception) + + val errorMessage = result.exception.message ?: "Unknown error occurred" + _sells.value = ViewState.Error(errorMessage) + Log.d(TAG, "ViewState.Error set with message: '$errorMessage'") } + is Result.Loading -> { - null + Log.d(TAG, "Result.Loading received from repository (this is unusual)") + // Keep the current loading state } } + } catch (e: Exception) { - _sells.value = ViewState.Error("An unexpected error occurred: ${e.message}") - Log.e("SellsViewModel", "Exception in getOrderList", e) + Log.e(TAG, "❌ Exception caught in getSellList") + Log.e(TAG, "Exception type: ${e.javaClass.simpleName}") + Log.e(TAG, "Exception message: ${e.message}") + Log.e(TAG, "Exception stack trace:", e) + + val errorMessage = "An unexpected error occurred: ${e.message}" + _sells.value = ViewState.Error(errorMessage) + Log.d(TAG, "ViewState.Error set due to exception: '$errorMessage'") } } + + Log.d(TAG, "========== getSellList method completed ==========") } fun updateOrderStatus(orderId: Int?, status: String) { - Log.d(TAG, "Updating order status: orderId=$orderId, status=$status") + Log.d(TAG, "========== Starting updateOrderStatus ==========") + Log.d(TAG, "Updating order status: orderId=$orderId, status='$status'") + viewModelScope.launch { try { + Log.d(TAG, "Calling repository.updateOrderStatus") + val startTime = System.currentTimeMillis() + repository.updateOrderStatus(orderId, status) - Log.d(TAG, "Order status updated successfully: orderId=$orderId, status=$status") + + val endTime = System.currentTimeMillis() + Log.d(TAG, "✅ Order status updated successfully in ${endTime - startTime}ms") + Log.d(TAG, "Updated orderId=$orderId to status='$status'") + } catch (e: Exception) { - Log.e(TAG, "Error updating order status", e) + Log.e(TAG, "❌ Error updating order status") + Log.e(TAG, "Exception type: ${e.javaClass.simpleName}") + Log.e(TAG, "Exception message: ${e.message}") + Log.e(TAG, "Exception stack trace:", e) } } + + Log.d(TAG, "========== updateOrderStatus method completed ==========") + } + + fun confirmPayment(orderId: Int, status: String) { + Log.d(TAG, "Confirming order completed: orderId=$orderId, status=$status") + viewModelScope.launch { + _confirmPaymentStore.value = Result.Loading + val request = PaymentConfirmRequest(orderId, status) + + Log.d(TAG, "Sending order completion request: $request") + val result = repository.confirmPaymentStore(request) + Log.d(TAG, "Order completion result: $result") + _confirmPaymentStore.value = result + } } fun refreshOrders(status: String = "all") { - Log.d(TAG, "Refreshing orders with status: $status") + Log.d(TAG, "========== Starting refreshOrders ==========") + Log.d(TAG, "Refreshing orders with status: '$status'") + // Clear current orders before fetching new ones _sells.value = ViewState.Loading + Log.d(TAG, "ViewState set to Loading for refresh") // Re-fetch the orders with the current status getSellList(status) + + Log.d(TAG, "========== refreshOrders method completed ==========") } } \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_image_viewer.xml b/app/src/main/res/layout/dialog_image_viewer.xml new file mode 100644 index 0000000..b7e6f66 --- /dev/null +++ b/app/src/main/res/layout/dialog_image_viewer.xml @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_sells.xml b/app/src/main/res/layout/fragment_sells.xml index 9992f7c..70e8e3f 100644 --- a/app/src/main/res/layout/fragment_sells.xml +++ b/app/src/main/res/layout/fragment_sells.xml @@ -1,5 +1,5 @@ - + app:tabPadding="13dp" + app:layout_constraintTop_toTopOf="parent"/> + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintTop_toBottomOf="@+id/tabLayoutSells" /> - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_sells_list.xml b/app/src/main/res/layout/fragment_sells_list.xml index 3f2c4db..c74d548 100644 --- a/app/src/main/res/layout/fragment_sells_list.xml +++ b/app/src/main/res/layout/fragment_sells_list.xml @@ -1,5 +1,5 @@ - - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/item_sells.xml b/app/src/main/res/layout/item_sells.xml index d7ae883..00cf599 100644 --- a/app/src/main/res/layout/item_sells.xml +++ b/app/src/main/res/layout/item_sells.xml @@ -1,873 +1,163 @@ - + android:layout_marginBottom="8dp" + app:cardCornerRadius="8dp" + app:cardElevation="2dp"> + android:padding="16dp"> - - - - - - - - - - - - - - - - - - - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + android:visibility="gone" + tools:text="Menunggu Tagihan" /> + android:layout_height="1dp" + android:layout_marginTop="8dp" + android:background="#E0E0E0" + app:layout_constraintTop_toBottomOf="@+id/tvUserName" /> - - - - - - - - + android:layout_marginTop="8dp" + app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" + app:layout_constraintTop_toBottomOf="@+id/divider" + tools:itemCount="1" + tools:listitem="@layout/item_order_product" /> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -