fix sell order and confirm payment in detailpayment

This commit is contained in:
shaulascr
2025-05-30 05:19:11 +07:00
parent e51e753a04
commit 0d2edb7ea2
20 changed files with 900 additions and 1180 deletions

View File

@ -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
)

View File

@ -77,7 +77,7 @@ data class OrdersItem(
val cancelDate: String? = null, val cancelDate: String? = null,
@field:SerializedName("payment_evidence") @field:SerializedName("payment_evidence")
val paymentEvidence: Any? = null, val paymentEvidence: String,
@field:SerializedName("longitude") @field:SerializedName("longitude")
val longitude: String? = null, val longitude: String? = null,
@ -152,7 +152,7 @@ data class OrdersItem(
val postalCode: String? = null, val postalCode: String? = null,
@field:SerializedName("order_id") @field:SerializedName("order_id")
val orderId: Int? = null, val orderId: Int,
@field:SerializedName("username") @field:SerializedName("username")
val username: String? = null, val username: String? = null,

View File

@ -5,5 +5,5 @@ import com.google.gson.annotations.SerializedName
data class PaymentConfirmationResponse( data class PaymentConfirmationResponse(
@field:SerializedName("message") @field:SerializedName("message")
val message: String? = null val message: String
) )

View File

@ -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.OrderRequest
import com.alya.ecommerce_serang.data.api.dto.OrderRequestBuy 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.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.ProvinceResponse
import com.alya.ecommerce_serang.data.api.dto.RegisterRequest import com.alya.ecommerce_serang.data.api.dto.RegisterRequest
import com.alya.ecommerce_serang.data.api.dto.ReviewProductItem 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.order.CompletedOrderResponse
import com.alya.ecommerce_serang.data.api.response.product.CreateSearchResponse 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.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.CreateProductResponse
import com.alya.ecommerce_serang.data.api.response.store.product.DeleteProductResponse import com.alya.ecommerce_serang.data.api.response.store.product.DeleteProductResponse
import com.alya.ecommerce_serang.data.api.response.store.product.UpdateProductResponse import com.alya.ecommerce_serang.data.api.response.store.product.UpdateProductResponse
@ -366,6 +368,11 @@ interface ApiService {
@Part("bank_num") bankNum: RequestBody @Part("bank_num") bankNum: RequestBody
): Response<BalanceTopUpResponse> ): Response<BalanceTopUpResponse>
@PUT("store/payment/update")
suspend fun paymentConfirmation(
@Body confirmPaymentReq : PaymentConfirmRequest
): Response<PaymentConfirmationResponse>
@Multipart @Multipart
@PUT("mystore/edit") @PUT("mystore/edit")
suspend fun updateStoreProfileMultipart( suspend fun updateStoreProfileMultipart(

View File

@ -1,7 +1,9 @@
package com.alya.ecommerce_serang.data.repository package com.alya.ecommerce_serang.data.repository
import android.util.Log 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.OrderListResponse
import com.alya.ecommerce_serang.data.api.response.store.orders.PaymentConfirmationResponse
import com.alya.ecommerce_serang.data.api.retrofit.ApiService import com.alya.ecommerce_serang.data.api.retrofit.ApiService
class SellsRepository(private val apiService: 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) Log.e("SellsRepository", "Exception updating order status", e)
} }
} }
suspend fun confirmPaymentStore(request: PaymentConfirmRequest): Result<PaymentConfirmationResponse> {
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)
}
}
} }

View File

@ -63,7 +63,7 @@ class HistoryActivity : AppCompatActivity() {
supportActionBar?.setDisplayShowTitleEnabled(false) supportActionBar?.setDisplayShowTitleEnabled(false)
binding.btnBack.setOnClickListener { binding.btnBack.setOnClickListener {
onBackPressed() // onBackPressed()
finish() finish()
} }
} }

View File

@ -6,10 +6,10 @@ import android.view.ViewGroup
import android.widget.ImageView import android.widget.ImageView
import android.widget.TextView import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.alya.ecommerce_serang.BuildConfig.BASE_URL
import com.alya.ecommerce_serang.R import com.alya.ecommerce_serang.R
import com.alya.ecommerce_serang.data.api.response.customer.order.OrderItemsItem import com.alya.ecommerce_serang.data.api.response.customer.order.OrderItemsItem
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import com.google.android.material.button.MaterialButton
class OrderProductAdapter : RecyclerView.Adapter<OrderProductAdapter.ProductViewHolder>() { class OrderProductAdapter : RecyclerView.Adapter<OrderProductAdapter.ProductViewHolder>() {
@ -48,9 +48,15 @@ class OrderProductAdapter : RecyclerView.Adapter<OrderProductAdapter.ProductView
// Set price with currency format // Set price with currency format
tvProductPrice.text = formatCurrency(product.price) tvProductPrice.text = formatCurrency(product.price)
val fullImageUrl = when (val img = product.productImage) {
is String -> {
if (img.startsWith("/")) BASE_URL + img.substring(1) else img
}
else -> R.drawable.placeholder_image // Default image for null
}
// Load product image using Glide // Load product image using Glide
Glide.with(itemView.context) Glide.with(itemView.context)
.load(product.productImage) .load(fullImageUrl)
.placeholder(R.drawable.placeholder_image) .placeholder(R.drawable.placeholder_image)
// .error(R.drawable.error_image) // .error(R.drawable.error_image)
.into(ivProductImage) .into(ivProductImage)

View File

@ -1,8 +1,13 @@
package com.alya.ecommerce_serang.ui.profile.mystore.sells package com.alya.ecommerce_serang.ui.profile.mystore.sells
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle import android.os.Bundle
import android.util.Log
import androidx.activity.enableEdgeToEdge
import androidx.activity.viewModels 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 androidx.fragment.app.commit
import com.alya.ecommerce_serang.R import com.alya.ecommerce_serang.R
import com.alya.ecommerce_serang.data.api.retrofit.ApiConfig import com.alya.ecommerce_serang.data.api.retrofit.ApiConfig
@ -31,12 +36,28 @@ class SellsActivity : AppCompatActivity() {
sessionManager = SessionManager(this) 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() setupHeader()
if (savedInstanceState == null) { if (savedInstanceState == null) {
supportFragmentManager.commit { showSellsFragment()
replace(R.id.fragment_container_sells, SellsFragment())
}
} }
} }
@ -44,7 +65,14 @@ class SellsActivity : AppCompatActivity() {
binding.header.headerTitle.text = "Penjualan Saya" binding.header.headerTitle.text = "Penjualan Saya"
binding.header.headerLeftIcon.setOnClickListener { binding.header.headerLeftIcon.setOnClickListener {
onBackPressedDispatcher.onBackPressed() onBackPressed()
finish()
}
}
private fun showSellsFragment() {
supportFragmentManager.commit {
replace(R.id.fragment_container_sells, SellsFragment())
} }
} }
} }

View File

@ -5,16 +5,15 @@ import android.util.Log
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.Button
import android.widget.ImageView
import android.widget.TextView import android.widget.TextView
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.alya.ecommerce_serang.R import com.alya.ecommerce_serang.R
import com.alya.ecommerce_serang.data.api.response.store.orders.OrdersItem 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.payment.DetailPaymentActivity
import com.alya.ecommerce_serang.ui.profile.mystore.sells.shipment.DetailShipmentActivity import com.alya.ecommerce_serang.ui.profile.mystore.sells.shipment.DetailShipmentActivity
import com.alya.ecommerce_serang.utils.viewmodel.SellsViewModel 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 com.google.gson.Gson
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.Calendar import java.util.Calendar
@ -34,235 +33,310 @@ class SellsAdapter(
} }
fun submitList(newSells: List<OrdersItem>) { fun submitList(newSells: List<OrdersItem>) {
Log.d("SellsAdapter", "submitList called with ${newSells.size} items")
sells.clear() sells.clear()
sells.addAll(newSells) sells.addAll(newSells)
notifyDataSetChanged() notifyDataSetChanged()
Log.d("SellsAdapter", "Adapter updated. Current size: ${sells.size}")
} }
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SellsViewHolder { 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) val view = LayoutInflater.from(parent.context).inflate(R.layout.item_sells, parent, false)
Log.d("SellsAdapter", "View inflated successfully")
return SellsViewHolder(view) return SellsViewHolder(view)
} }
override fun onBindViewHolder(holder: SellsViewHolder, position: Int) { 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 override fun getItemCount(): Int = sells.size
inner class SellsViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { inner class SellsViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
private val layoutOrders: View = itemView.findViewById(R.id.layout_orders) private val tvStoreName: TextView = itemView.findViewById(R.id.tvUserName)
private val layoutPayments: View = itemView.findViewById(R.id.layout_payments) private val rvOrderItems: RecyclerView = itemView.findViewById(R.id.rvSellsItems)
private val layoutShipments: View = itemView.findViewById(R.id.layout_shipments) 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) fun bind(order: OrdersItem) {
private var tvSellsNumber: TextView = itemView.findViewById(R.id.tv_payment_number) Log.d("SellsAdapter", "=== ViewHolder.bind() called ===")
private var tvSellsDueDesc: TextView = itemView.findViewById(R.id.tv_payment_due_desc) Log.d("SellsAdapter", "Binding order: ${order.orderId} with status: ${order.status}")
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(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}" // Set total amount
tvSellsLocation.text = sells.subdistrict tvTotalAmount.text = "Rp${order.totalAmount}"
tvSellsCustomer.text = sells.username Log.d("SellsAdapter", "Total amount set: ${order.totalAmount}")
val product = sells.orderItems?.get(0) // Set item count
product?.let { val itemCount = order.orderItems?.size ?: 0
tvSellsProductName.text = it.productName tvItemCountLabel.text = itemView.context.getString(R.string.item_count_prod, itemCount)
tvSellsProductQty.text = "x${it.quantity}" Log.d("SellsAdapter", "Item count set: $itemCount")
tvSellsProductPrice.text = "Rp${it.price}"
Glide.with(itemView.context) // Set up the order items RecyclerView
.load(it.productImage) val productAdapter = SellsProductAdapter()
.placeholder(R.drawable.placeholder_image) rvOrderItems.apply {
.into(ivSellsProduct) layoutManager = LinearLayoutManager(itemView.context)
adapter = productAdapter
} }
Log.d("SellsAdapter", "Product RecyclerView configured")
sells.orderItems?.size?.let { // Display only the first product and show "View more" for the rest
if (it > 1) { order.orderItems?.let { items ->
tvSeeMore.visibility = View.VISIBLE if (items.isNotEmpty()) {
tvSeeMore.text = "Lihat ${it.minus(1)} produk lainnya" 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 { } 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" // Set click listener for the entire order item
tvSellsPrice.text = "Rp${sells.totalAmount}" itemView.setOnClickListener {
// onOrderClickListener(order)
// itemView.setOnClickListener { }
// onOrderClickListener(sells)
// }
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) { private fun adjustButtonsAndText(status: String, order: OrdersItem) {
Log.d("SellsAdapter", "Adjusting display for status: $status") Log.d("SellsAdapter", "Adjusting buttons for status: $status")
// Get references to buttons and status views
val btnLeft = itemView.findViewById<MaterialButton>(R.id.btn_left)
val btnRight = itemView.findViewById<MaterialButton>(R.id.btn_right)
val statusOrder = itemView.findViewById<TextView>(R.id.tvOrderStatus)
val deadlineLabel = itemView.findViewById<TextView>(R.id.tvDeadlineLabel)
val deadlineDate = itemView.findViewById<TextView>(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) { when (status) {
"pending", "unpaid" -> { "pending" -> {
layoutOrders.visibility = View.VISIBLE statusOrder.apply {
layoutPayments.visibility = View.GONE visibility = View.VISIBLE
layoutShipments.visibility = View.GONE text = "Menunggu Tagihan"
}
tvSellsTitle = itemView.findViewById(R.id.tv_order_title) deadlineLabel.apply {
tvSellsNumber = itemView.findViewById(R.id.tv_order_number) visibility = View.VISIBLE
tvSellsDue = itemView.findViewById(R.id.tv_order_due) text = "Batas waktu konfirmasi:"
tvSellsCustomer = itemView.findViewById(R.id.tv_order_customer) }
tvSellsProductName = itemView.findViewById(R.id.tv_order_product_name) deadlineDate.apply {
tvSellsProductQty = itemView.findViewById(R.id.tv_order_product_qty) visibility = View.VISIBLE
tvSellsProductPrice = itemView.findViewById(R.id.tv_order_product_price) text = formatDate(order.createdAt ?: "")
tvSeeMore = itemView.findViewById(R.id.tv_see_more_order) }
tvSellsQty = itemView.findViewById(R.id.tv_order_qty) btnLeft.apply {
tvSellsPrice = itemView.findViewById(R.id.tv_order_price) visibility = View.VISIBLE
text = "Tolak Pesanan"
tvSellsDue.text = formatDueDate(sells.updatedAt.toString(), 1) setOnClickListener {
// Handle reject order
val product = sells.orderItems?.get(0) viewModel.updateOrderStatus(order.orderId, "canceled")
product?.let { viewModel.refreshOrders()
tvSellsProductName.text = it.productName }
tvSellsProductQty.text = "x${it.quantity}" }
tvSellsProductPrice.text = "Rp${it.price}" btnRight.apply {
Glide.with(itemView.context) visibility = View.VISIBLE
.load(it.productImage) text = "Terima Pesanan"
.placeholder(R.drawable.placeholder_image) setOnClickListener {
.into(ivSellsProduct) // 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" -> { "paid" -> {
layoutOrders.visibility = View.GONE statusOrder.apply {
layoutPayments.visibility = View.VISIBLE visibility = View.VISIBLE
layoutShipments.visibility = View.GONE text = "Sudah Dibayar"
}
tvSellsDue.text = formatDueDate(sells.updatedAt.toString(), 2) deadlineLabel.apply {
btnConfirmPayment.setOnClickListener { visibility = View.VISIBLE
text = "Konfirmasi pembayaran sebelum:"
val context = itemView.context }
val intent = Intent(context, DetailPaymentActivity::class.java) deadlineDate.apply {
intent.putExtra("sells_data", Gson().toJson(sells)) visibility = View.VISIBLE
context.startActivity(intent) text = formatDatePay(order.updatedAt ?: "")
viewModel.refreshOrders() }
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" -> { "processed" -> {
layoutOrders.visibility = View.GONE statusOrder.apply {
layoutPayments.visibility = View.GONE visibility = View.VISIBLE
layoutShipments.visibility = View.VISIBLE text = "Diproses"
}
tvSellsTitle = itemView.findViewById(R.id.tv_shipment_title) deadlineLabel.apply {
tvSellsNumber = itemView.findViewById(R.id.tv_shipment_number) visibility = View.VISIBLE
tvSellsDue = itemView.findViewById(R.id.tv_shipment_due) text = "Kirim sebelum:"
tvSellsLocation = itemView.findViewById(R.id.tv_shipment_location) }
tvSellsCustomer = itemView.findViewById(R.id.tv_shipment_customer) deadlineDate.apply {
tvSellsProductName = itemView.findViewById(R.id.tv_shipment_product_name) visibility = View.VISIBLE
tvSellsProductQty = itemView.findViewById(R.id.tv_shipment_product_qty) text = formatDatePay(order.updatedAt ?: "")
tvSeeMore = itemView.findViewById(R.id.tv_see_more_shipment) }
btnRight.apply {
tvSellsDue.text = formatDueDate(sells.updatedAt.toString(), 2) visibility = View.VISIBLE
btnConfirmShipment.setOnClickListener { text = "Kirim Pesanan"
val context = itemView.context setOnClickListener {
val intent = Intent(context, DetailShipmentActivity::class.java) val context = itemView.context
intent.putExtra("sells_data", Gson().toJson(sells)) val intent = Intent(context, DetailShipmentActivity::class.java)
context.startActivity(intent) 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" -> { "shipped" -> {
layoutOrders.visibility = View.GONE statusOrder.apply {
layoutPayments.visibility = View.VISIBLE visibility = View.VISIBLE
layoutShipments.visibility = View.GONE text = "Dikirim"
}
tvSellsTitle.text = "Pesanan Telah Dikirim" deadlineLabel.apply {
tvSellsDueDesc.text = "Dikirimkan pada" visibility = View.VISIBLE
text = "Dikirimkan pada:"
tvSellsDue.text = formatDueDate(sells.updatedAt.toString(), 0) }
tvSellsDue.background = itemView.context.getDrawable(R.drawable.bg_product_inactive) deadlineDate.apply {
btnConfirmPayment.visibility = View.GONE visibility = View.VISIBLE
} text = formatDate(order.updatedAt ?: "")
"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
} }
"completed" -> { "completed" -> {
layoutOrders.visibility = View.GONE statusOrder.apply {
layoutPayments.visibility = View.VISIBLE visibility = View.VISIBLE
layoutShipments.visibility = View.GONE text = "Selesai"
}
tvSellsTitle.text = "Pesanan Selesai" deadlineLabel.apply {
tvSellsDueDesc.text = "Selesai pada" visibility = View.VISIBLE
text = "Selesai pada:"
tvSellsDue.text = formatDueDate(sells.updatedAt.toString(), 0) }
tvSellsDue.background = itemView.context.getDrawable(R.drawable.bg_product_inactive) deadlineDate.apply {
btnConfirmPayment.visibility = View.GONE visibility = View.VISIBLE
text = formatDate(order.updatedAt ?: "")
}
} }
"canceled" -> { "canceled" -> {
layoutOrders.visibility = View.GONE statusOrder.apply {
layoutPayments.visibility = View.VISIBLE visibility = View.VISIBLE
layoutShipments.visibility = View.GONE text = "Dibatalkan"
}
tvSellsTitle.text = "Pesanan Dibatalkan" deadlineLabel.apply {
tvSellsDueDesc.text = "Dibatalkan pada" visibility = View.VISIBLE
text = "Dibatalkan pada:"
tvSellsDue.text = formatDueDate(sells.updatedAt.toString(), 0) }
tvSellsDue.background = itemView.context.getDrawable(R.drawable.bg_product_inactive) deadlineDate.apply {
btnConfirmPayment.visibility = View.GONE visibility = View.VISIBLE
text = formatDate(order.cancelDate ?: "")
}
} }
} }
} }
private fun formatDueDate(date: String, dueDay: Int): String { private fun formatDate(dateString: String): String {
return try { return try {
val inputFormat = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.getDefault()) val inputFormat = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.getDefault())
inputFormat.timeZone = TimeZone.getTimeZone("UTC") 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 { date?.let {
val calendar = Calendar.getInstance() val calendar = Calendar.getInstance()
calendar.time = it calendar.time = it
calendar.add(Calendar.DATE, dueDay) calendar.set(Calendar.HOUR_OF_DAY, 23)
calendar.set(Calendar.MINUTE, 59)
outputFormat.format(calendar.time) outputFormat.format(calendar.time)
} ?: date } ?: dateString
} catch (e: Exception) { } catch (e: Exception) {
Log.e("DueDateFormatting", "Error formatting date: ${e.message}") Log.e("DateFormatting", "Error formatting date: ${e.message}")
date dateString
}.toString() }
}
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
}
} }
} }
} }

View File

@ -1,12 +1,10 @@
package com.alya.ecommerce_serang.ui.profile.mystore.sells package com.alya.ecommerce_serang.ui.profile.mystore.sells
import android.os.Bundle import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.viewpager2.widget.ViewPager2
import com.alya.ecommerce_serang.R import com.alya.ecommerce_serang.R
import com.alya.ecommerce_serang.databinding.FragmentSellsBinding import com.alya.ecommerce_serang.databinding.FragmentSellsBinding
import com.alya.ecommerce_serang.utils.SessionManager import com.alya.ecommerce_serang.utils.SessionManager
@ -21,9 +19,10 @@ class SellsFragment : Fragment() {
private lateinit var viewPagerAdapter: SellsViewPagerAdapter private lateinit var viewPagerAdapter: SellsViewPagerAdapter
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle? savedInstanceState: Bundle?
): View? { ): View {
_binding = FragmentSellsBinding.inflate(inflater, container, false) _binding = FragmentSellsBinding.inflate(inflater, container, false)
return binding.root return binding.root
} }
@ -36,58 +35,28 @@ class SellsFragment : Fragment() {
} }
private fun setupViewPager() { private fun setupViewPager() {
// Initialize the ViewPager adapter
viewPagerAdapter = SellsViewPagerAdapter(requireActivity()) viewPagerAdapter = SellsViewPagerAdapter(requireActivity())
binding.viewPagerSells.adapter = viewPagerAdapter binding.viewPagerSells.adapter = viewPagerAdapter
TabLayoutMediator(binding.tabLayoutSells, binding.viewPagerSells) {tab, position -> // Connect TabLayout with ViewPager2
tab.text = when(position){ TabLayoutMediator(binding.tabLayoutSells, binding.viewPagerSells) { tab, position ->
0 -> getString(R.string.all_orders) tab.text = when (position) {
1 -> getString(R.string.pending_orders) 0 -> getString(R.string.all_orders) // "Semua Pesanan"
2 -> getString(R.string.unpaid_orders) 1 -> getString(R.string.pending_orders) // "Menunggu Tagihan"
3 -> getString(R.string.processed_orders) 2 -> getString(R.string.unpaid_orders) // "Konfirmasi Bayar"
4 -> getString(R.string.paid_orders) 3 -> getString(R.string.paid_orders) // "Diproses"
5 -> getString(R.string.shipped_orders) 4 -> getString(R.string.processed_orders) // "Sudah Dibayar"
6 -> getString(R.string.completed_orders) 5 -> getString(R.string.shipped_orders) // "Dikirim"
7 -> getString(R.string.canceled_orders) 6 -> getString(R.string.completed_orders) // "Selesai"
7 -> getString(R.string.canceled_orders) // "Dibatalkan"
else -> "Tab $position" else -> "Tab $position"
} }
}.attach() }.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() { override fun onDestroyView() {
super.onDestroyView() super.onDestroyView()
_binding = null _binding = null
} }
}
companion object {
private const val TAG = "SellsListFragment"
}
}

View File

@ -11,6 +11,7 @@ import androidx.fragment.app.viewModels
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import com.alya.ecommerce_serang.data.api.response.store.orders.OrdersItem 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.api.retrofit.ApiConfig
import com.alya.ecommerce_serang.data.repository.Result
import com.alya.ecommerce_serang.data.repository.SellsRepository import com.alya.ecommerce_serang.data.repository.SellsRepository
import com.alya.ecommerce_serang.databinding.FragmentSellsListBinding import com.alya.ecommerce_serang.databinding.FragmentSellsListBinding
import com.alya.ecommerce_serang.ui.order.address.ViewState import com.alya.ecommerce_serang.ui.order.address.ViewState
@ -22,7 +23,7 @@ class SellsListFragment : Fragment() {
private var _binding: FragmentSellsListBinding? = null private var _binding: FragmentSellsListBinding? = null
private val binding get() = _binding!! private val binding get() = _binding!!
private lateinit var sessionManager: SessionManager private lateinit var sessionManager: SessionManager
private val viewModel: SellsViewModel by viewModels { private val viewModel: SellsViewModel by viewModels {
BaseViewModelFactory { BaseViewModelFactory {
@ -31,39 +32,45 @@ class SellsListFragment : Fragment() {
SellsViewModel(sellsRepository) SellsViewModel(sellsRepository)
} }
} }
private lateinit var sellsAdapter: SellsAdapter private lateinit var sellsAdapter: SellsAdapter
private var status: String = "all" private var status: String = "all"
companion object { companion object {
private const val TAG = "SellsListFragment" private const val TAG = "SellsListFragment"
private const val ARG_STATUS = "status" private const val ARG_STATUS = "status"
fun newInstance(status: String): SellsListFragment { fun newInstance(status: String): SellsListFragment {
Log.d(TAG, "=== Creating new instance ===") Log.d(TAG, "Creating new instance with status: '$status'")
Log.d(TAG, "Status: '$status'")
return SellsListFragment().apply { return SellsListFragment().apply {
arguments = Bundle().apply { arguments = Bundle().apply {
putString(ARG_STATUS, status) putString(ARG_STATUS, status)
} }
Log.d(TAG, "Fragment instance created with status: '$status'")
} }
} }
} }
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
Log.d(TAG, "onCreate called")
sessionManager = SessionManager(requireContext()) sessionManager = SessionManager(requireContext())
arguments?.let { arguments?.let {
status = it.getString(ARG_STATUS) ?: "all" status = it.getString(ARG_STATUS) ?: "all"
} }
Log.d(TAG, "Fragment status set to: '$status'")
} }
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle? savedInstanceState: Bundle?
): View? { ): View {
Log.d(TAG, "onCreateView called")
_binding = FragmentSellsListBinding.inflate(inflater, container, false) _binding = FragmentSellsListBinding.inflate(inflater, container, false)
return binding.root return binding.root
} }
@ -73,90 +80,104 @@ class SellsListFragment : Fragment() {
setupRecyclerView() setupRecyclerView()
observeSellsList() observeSellsList()
observePaymentConfirmation()
loadSells() loadSells()
} }
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
private fun setupRecyclerView() { private fun setupRecyclerView() {
Log.d(TAG, "Setting up RecyclerView")
sellsAdapter = SellsAdapter( sellsAdapter = SellsAdapter(
onOrderClickListener = { sells -> onOrderClickListener = { order ->
Log.d(TAG, "Order clicked: ${sells.orderId} in status '$status'") Log.d(TAG, "Order clicked: ${order.orderId}")
navigateToSellsDetail(sells) navigateToSellsDetail(order)
}, },
viewModel = viewModel viewModel = viewModel
) )
Log.d(TAG, "Setting adapter fragment status to: '$status'")
sellsAdapter.setFragmentStatus(status) sellsAdapter.setFragmentStatus(status)
Log.d(TAG, "Adapter fragment status set to: '$status'")
binding.rvSells.apply { binding.rvSells.apply {
layoutManager = LinearLayoutManager(requireContext()) layoutManager = LinearLayoutManager(requireContext())
adapter = sellsAdapter adapter = sellsAdapter
Log.d(TAG, "RecyclerView configured with LinearLayoutManager and adapter")
} }
Log.d(TAG, "RecyclerView configured")
// Log RecyclerView visibility and properties
Log.d(TAG, "RecyclerView visibility: ${binding.rvSells.visibility}")
Log.d(TAG, "RecyclerView parent: ${binding.rvSells.parent}")
} }
private fun observeSellsList() { private fun observeSellsList() {
Log.d(TAG, "Setting up sells list observer")
viewModel.sells.observe(viewLifecycleOwner) { result -> viewModel.sells.observe(viewLifecycleOwner) { result ->
Log.d(TAG, "Sells list observer triggered with result: ${result.javaClass.simpleName}")
when (result) { when (result) {
is ViewState.Success -> { is ViewState.Success -> {
binding.progressBar.visibility = View.GONE binding.progressBar.visibility = View.GONE
Log.d(TAG, "Data received: ${result.data?.size ?: 0} items")
if (result.data.isNullOrEmpty()) { if (result.data.isNullOrEmpty()) {
binding.tvEmptyState.visibility = View.VISIBLE binding.tvEmptyState.visibility = View.VISIBLE
binding.rvSells.visibility = View.GONE binding.rvSells.visibility = View.GONE
Log.d(TAG, "Showing empty state")
} else { } else {
Log.d(TAG, "✅ Data is available: ${result.data.size} items")
binding.tvEmptyState.visibility = View.GONE binding.tvEmptyState.visibility = View.GONE
binding.rvSells.visibility = View.VISIBLE binding.rvSells.visibility = View.VISIBLE
result.data.forEachIndexed { index, order -> // Log first few items for debugging
Log.d(TAG, "Order $index:") result.data.take(3).forEachIndexed { index, order ->
Log.d(TAG, " - ID: ${order.orderId}") Log.d(TAG, "Order ${index + 1}: ID=${order.orderId}, Status=${order.status}, Customer=${order.username}")
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}")
} }
sellsAdapter.submitList(result.data)
Log.d(TAG, "Final UI state:") sellsAdapter.submitList(result.data)
Log.d(TAG, " - ProgressBar visibility: ${binding.progressBar.visibility}") Log.d(TAG, "Data submitted to adapter")
Log.d(TAG, " - EmptyState visibility: ${binding.tvEmptyState.visibility}") Log.d(TAG, "Adapter item count: ${sellsAdapter.itemCount}") }
Log.d(TAG, " - RecyclerView visibility: ${binding.rvSells.visibility}")
Log.d(TAG, " - Adapter item count: ${sellsAdapter.itemCount}")
}
} }
is ViewState.Error -> { is ViewState.Error -> {
Log.e(TAG, "❌ ViewState.Error received: ${result.message}")
binding.progressBar.visibility = View.GONE binding.progressBar.visibility = View.GONE
binding.tvEmptyState.visibility = View.VISIBLE binding.tvEmptyState.visibility = View.VISIBLE
Toast.makeText(requireContext(), result.message, Toast.LENGTH_SHORT).show() Toast.makeText(requireContext(), result.message, Toast.LENGTH_SHORT).show()
} }
is ViewState.Loading -> { is ViewState.Loading -> {
binding.progressBar.visibility = View.VISIBLE 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() { private fun loadSells() {
Log.d(TAG, "Calling viewModel.getSellList('$status')") Log.d(TAG, "Loading sells with status: '$status'")
viewModel.getSellList(status) viewModel.getSellList(status)
Log.d(TAG, "getSellList called")
} }
private fun navigateToSellsDetail(sells: OrdersItem) { private fun navigateToSellsDetail(order: OrdersItem) {
// In a real app, you would navigate to sells detail screen Log.d(TAG, "Navigating to sells detail for order: ${order.orderId}")
// For example: findNavController().navigate(SellsListFragmentDirections.actionToSellsDetail(sells.orderId)) // Navigate to order detail from seller's perspective
Toast.makeText(requireContext(), "Order ID: ${sells.orderId}", Toast.LENGTH_SHORT).show() // 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
} }
} }

View File

@ -10,9 +10,15 @@ import com.alya.ecommerce_serang.R
import com.alya.ecommerce_serang.data.api.response.store.orders.OrderItemsItem import com.alya.ecommerce_serang.data.api.response.store.orders.OrderItemsItem
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
class SellsProductAdapter( class SellsProductAdapter : RecyclerView.Adapter<SellsProductAdapter.ProductViewHolder>() {
private val items: List<OrderItemsItem?>
) : RecyclerView.Adapter<SellsProductAdapter.ProductViewHolder>() { private val items = mutableListOf<OrderItemsItem?>()
fun submitList(newItems: List<OrderItemsItem?>) {
items.clear()
items.addAll(newItems)
notifyDataSetChanged()
}
inner class ProductViewHolder(view: View) : RecyclerView.ViewHolder(view) { inner class ProductViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val ivProduct: ImageView = view.findViewById(R.id.iv_order_product) val ivProduct: ImageView = view.findViewById(R.id.iv_order_product)

View File

@ -1,14 +1,14 @@
package com.alya.ecommerce_serang.ui.profile.mystore.sells package com.alya.ecommerce_serang.ui.profile.mystore.sells
import android.util.Log
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity import androidx.fragment.app.FragmentActivity
import androidx.viewpager2.adapter.FragmentStateAdapter import androidx.viewpager2.adapter.FragmentStateAdapter
import io.ktor.client.utils.EmptyContent.status
class SellsViewPagerAdapter(fragmentActivity: FragmentActivity) class SellsViewPagerAdapter(
: FragmentStateAdapter(fragmentActivity) { fragmentActivity: FragmentActivity
) : FragmentStateAdapter(fragmentActivity) {
// Define all possible sells statuses - keeping your original list
private val sellsStatuses = listOf( private val sellsStatuses = listOf(
"all", // Position 0: "Semua Pesanan" "all", // Position 0: "Semua Pesanan"
"pending", // Position 1: "Menunggu Tagihan" "pending", // Position 1: "Menunggu Tagihan"
@ -20,34 +20,10 @@ class SellsViewPagerAdapter(fragmentActivity: FragmentActivity)
"canceled" // Position 7: "Dibatalkan" "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 getItemCount(): Int = sellsStatuses.size
override fun createFragment(position: Int): Fragment { 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]) return SellsListFragment.newInstance(sellsStatuses[position])
} }
companion object {
private const val TAG = "SellsViewPagerAdapter"
}
} }

View File

@ -1,11 +1,34 @@
package com.alya.ecommerce_serang.ui.profile.mystore.sells.payment 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.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.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.LinearLayoutManager 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.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.databinding.ActivityDetailPaymentBinding
import com.alya.ecommerce_serang.ui.profile.mystore.sells.SellsProductAdapter 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 com.google.gson.Gson
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.Locale import java.util.Locale
@ -15,17 +38,37 @@ class DetailPaymentActivity : AppCompatActivity() {
private lateinit var binding: ActivityDetailPaymentBinding private lateinit var binding: ActivityDetailPaymentBinding
private lateinit var sells: OrdersItem 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?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
binding = ActivityDetailPaymentBinding.inflate(layoutInflater) binding = ActivityDetailPaymentBinding.inflate(layoutInflater)
setContentView(binding.root) setContentView(binding.root)
sessionManager = SessionManager(this)
val orderJson = intent.getStringExtra("sells_data") val orderJson = intent.getStringExtra("sells_data")
sells = Gson().fromJson(orderJson, OrdersItem::class.java) sells = Gson().fromJson(orderJson, OrdersItem::class.java)
bindOrderDetails() binding.header.headerLeftIcon.setOnClickListener {
// onBackPressed()
finish()
}
setupRecyclerView() setupRecyclerView()
bindOrderDetails()
setupPaymentEvidenceViewer()
} }
private fun bindOrderDetails() = with(binding) { private fun bindOrderDetails() = with(binding) {
@ -42,15 +85,107 @@ class DetailPaymentActivity : AppCompatActivity() {
tvOrderRecipient.text = sells.username tvOrderRecipient.text = sells.username
// tvOrderRecipientNum.text = sells.phone // tvOrderRecipientNum.text = sells.phone
tvOrderRecipientAddress.text = sells.street tvOrderRecipientAddress.text = sells.street
// sells.paymentEvidence
binding.btnConfirmPayment.setOnClickListener{
viewModel.confirmPayment(sells.orderId, "confirmed")
finish()
}
} }
private fun setupRecyclerView() { private fun setupRecyclerView() {
productAdapter = SellsProductAdapter()
binding.rvProductItems.apply { binding.rvProductItems.apply {
layoutManager = LinearLayoutManager(this@DetailPaymentActivity) 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<ImageView>(R.id.iv_payment_evidence)
val btnClose = dialog.findViewById<ImageButton>(R.id.btn_close)
val tvTitle = dialog.findViewById<TextView>(R.id.tv_title)
val progressBar = dialog.findViewById<ProgressBar>(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<Drawable>() {
override fun onResourceReady(resource: Drawable, transition: com.bumptech.glide.request.transition.Transition<in Drawable>?) {
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 { private fun formatDate(dateStr: String?): String {
return try { return try {
val inputFormat = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.getDefault()) val inputFormat = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.getDefault())

View File

@ -15,17 +15,18 @@ class DetailShipmentActivity : AppCompatActivity() {
private lateinit var binding: ActivityDetailShipmentBinding private lateinit var binding: ActivityDetailShipmentBinding
private lateinit var sells: OrdersItem private lateinit var sells: OrdersItem
private lateinit var productAdapter: SellsProductAdapter
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
binding = ActivityDetailShipmentBinding.inflate(layoutInflater) binding = ActivityDetailShipmentBinding.inflate(layoutInflater)
setContentView(binding.root) setContentView(binding.root)
val orderJson = intent.getStringExtra("order_data") val orderJson = intent.getStringExtra("sells_data")
sells = Gson().fromJson(orderJson, OrdersItem::class.java) sells = Gson().fromJson(orderJson, OrdersItem::class.java)
bindOrderDetails()
setupRecyclerView() setupRecyclerView()
bindOrderDetails()
} }
private fun bindOrderDetails() = with(binding) { private fun bindOrderDetails() = with(binding) {
@ -45,10 +46,15 @@ class DetailShipmentActivity : AppCompatActivity() {
} }
private fun setupRecyclerView() { private fun setupRecyclerView() {
productAdapter = SellsProductAdapter()
binding.rvProductItems.apply { binding.rvProductItems.apply {
layoutManager = LinearLayoutManager(this@DetailShipmentActivity) 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 { private fun formatDate(dateStr: String?): String {

View File

@ -5,7 +5,9 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope 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.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.Result
import com.alya.ecommerce_serang.data.repository.SellsRepository import com.alya.ecommerce_serang.data.repository.SellsRepository
import com.alya.ecommerce_serang.ui.order.address.ViewState import com.alya.ecommerce_serang.ui.order.address.ViewState
@ -20,66 +22,159 @@ class SellsViewModel(private val repository: SellsRepository) : ViewModel() {
private val _sells = MutableLiveData<ViewState<List<OrdersItem>>>() private val _sells = MutableLiveData<ViewState<List<OrdersItem>>>()
val sells: LiveData<ViewState<List<OrdersItem>>> = _sells val sells: LiveData<ViewState<List<OrdersItem>>> = _sells
private val _confirmPaymentStore = MutableLiveData<Result<PaymentConfirmationResponse>>()
val confirmPaymentStore: LiveData<Result<PaymentConfirmationResponse>> = _confirmPaymentStore
fun getSellList(status: String) { fun getSellList(status: String) {
Log.d(TAG, "========== Starting getSellList ==========")
Log.d(TAG, "Requested status: '$status'") Log.d(TAG, "Requested status: '$status'")
Log.d(TAG, "Repository instance: ${repository.javaClass.simpleName}")
_sells.value = ViewState.Loading _sells.value = ViewState.Loading
Log.d(TAG, "ViewState set to Loading")
viewModelScope.launch { viewModelScope.launch {
_sells.value = ViewState.Loading Log.d(TAG, "Coroutine launched successfully")
try { try {
Log.d(TAG, "Calling repository.getSellList(status='$status')")
val startTime = System.currentTimeMillis()
when (val result = repository.getSellList(status)) { when (val result = repository.getSellList(status)) {
is Result.Success -> { 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 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.d(TAG, "Orders count: ${orders?.size ?: 0}")
// Log individual order details // Check if orders list is null or empty
orders?.forEachIndexed { index, order -> if (orders == null) {
Log.d(TAG, "Order $index:") Log.w(TAG, "⚠️ Orders list is NULL")
Log.d(TAG, " - ID: ${order.orderId}") } else if (orders.isEmpty()) {
Log.d(TAG, " - Status: ${order.status}") Log.w(TAG, "⚠️ Orders list is EMPTY")
Log.d(TAG, " - Customer: ${order.username}") } else {
Log.d(TAG, " - Total: ${order.totalAmount}") Log.d(TAG, "✅ Orders list contains ${orders.size} items")
Log.d(TAG, " - Items count: ${order.orderItems?.size ?: 0}")
Log.d(TAG, " - Updated at: ${order.updatedAt}") // 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 -> { is Result.Error -> {
_sells.value = ViewState.Error(result.exception.message ?: "Unknown error occurred") val endTime = System.currentTimeMillis()
Log.e("SellsViewModel", "Error loading sells", result.exception) 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 -> { is Result.Loading -> {
null Log.d(TAG, "Result.Loading received from repository (this is unusual)")
// Keep the current loading state
} }
} }
} catch (e: Exception) { } catch (e: Exception) {
_sells.value = ViewState.Error("An unexpected error occurred: ${e.message}") Log.e(TAG, "❌ Exception caught in getSellList")
Log.e("SellsViewModel", "Exception in getOrderList", e) 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) { 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 { viewModelScope.launch {
try { try {
Log.d(TAG, "Calling repository.updateOrderStatus")
val startTime = System.currentTimeMillis()
repository.updateOrderStatus(orderId, status) 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) { } 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") { 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 // Clear current orders before fetching new ones
_sells.value = ViewState.Loading _sells.value = ViewState.Loading
Log.d(TAG, "ViewState set to Loading for refresh")
// Re-fetch the orders with the current status // Re-fetch the orders with the current status
getSellList(status) getSellList(status)
Log.d(TAG, "========== refreshOrders method completed ==========")
} }
} }

View File

@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/black">
<!-- Header with title and close button -->
<LinearLayout
android:id="@+id/header_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="16dp"
android:gravity="center_vertical"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent">
<TextView
android:id="@+id/tv_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Bukti Pembayaran"
android:textColor="@android:color/white"
android:textSize="18sp"
android:textStyle="bold" />
<ImageButton
android:id="@+id/btn_close"
android:layout_width="48dp"
android:layout_height="48dp"
android:background="?attr/selectableItemBackgroundBorderless"
android:src="@drawable/ic_close"
android:contentDescription="Close"
app:tint="@android:color/white" />
</LinearLayout>
<!-- Progress bar for loading -->
<ProgressBar
android:id="@+id/progress_bar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
<!-- Main image view -->
<ImageView
android:id="@+id/iv_payment_evidence"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_margin="16dp"
android:scaleType="centerInside"
android:contentDescription="Payment Evidence"
app:layout_constraintTop_toBottomOf="@+id/header_layout"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout <androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
@ -9,7 +9,7 @@
tools:context=".ui.profile.mystore.sells.SellsFragment"> tools:context=".ui.profile.mystore.sells.SellsFragment">
<com.google.android.material.tabs.TabLayout <com.google.android.material.tabs.TabLayout
android:id="@+id/tab_layout_sells" android:id="@+id/tabLayoutSells"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
app:tabMode="scrollable" app:tabMode="scrollable"
@ -19,12 +19,14 @@
app:tabSelectedTextColor="@color/blue_500" app:tabSelectedTextColor="@color/blue_500"
app:tabTextColor="@color/black_300" app:tabTextColor="@color/black_300"
app:tabBackground="@color/white" app:tabBackground="@color/white"
app:tabPadding="13dp"/> app:tabPadding="13dp"
app:layout_constraintTop_toTopOf="parent"/>
<androidx.viewpager2.widget.ViewPager2 <androidx.viewpager2.widget.ViewPager2
android:id="@+id/view_pager_sells" android:id="@+id/viewPagerSells"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="0dp" android:layout_height="0dp"
android:layout_weight="1" /> app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tabLayoutSells" />
</androidx.coordinatorlayout.widget.CoordinatorLayout> </androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
@ -7,14 +7,16 @@
tools:context=".ui.profile.mystore.sells.SellsListFragment"> tools:context=".ui.profile.mystore.sells.SellsListFragment">
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_sells" android:id="@+id/rvSells"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:clipToPadding="false"
android:padding="8dp"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:listitem="@layout/item_sells" /> tools:listitem="@layout/item_sells" />
<TextView <TextView
android:id="@+id/tv_empty_state" android:id="@+id/tvEmptyState"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="TIdak ada penjualan" android:text="TIdak ada penjualan"
@ -26,7 +28,7 @@
app:layout_constraintTop_toTopOf="parent" /> app:layout_constraintTop_toTopOf="parent" />
<ProgressBar <ProgressBar
android:id="@+id/progress_bar" android:id="@+id/progressBar"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:visibility="gone" android:visibility="gone"
@ -35,4 +37,4 @@
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" /> app:layout_constraintTop_toTopOf="parent" />
</FrameLayout> </androidx.constraintlayout.widget.ConstraintLayout>

File diff suppressed because it is too large Load Diff