payment and shipment confirmation

This commit is contained in:
Gracia Hotmauli
2025-06-11 00:03:02 +07:00
parent aa8229f0a0
commit 1a3c2c466a
10 changed files with 223 additions and 177 deletions

View File

@ -1,4 +1,4 @@
package com.alya.ecommerce_serang.data.api.response.store.profile package com.alya.ecommerce_serang.data.api.response.store
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
@ -8,4 +8,4 @@ data class GenericResponse(
@SerializedName("success") @SerializedName("success")
val success: Boolean = true val success: Boolean = true
) )

View File

@ -71,7 +71,7 @@ import com.alya.ecommerce_serang.data.api.response.store.product.CreateProductRe
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
import com.alya.ecommerce_serang.data.api.response.store.product.ViewStoreProductsResponse import com.alya.ecommerce_serang.data.api.response.store.product.ViewStoreProductsResponse
import com.alya.ecommerce_serang.data.api.response.store.profile.GenericResponse import com.alya.ecommerce_serang.data.api.response.store.GenericResponse
import com.alya.ecommerce_serang.data.api.response.store.profile.StoreDataResponse import com.alya.ecommerce_serang.data.api.response.store.profile.StoreDataResponse
import com.alya.ecommerce_serang.data.api.response.store.topup.BalanceTopUpResponse import com.alya.ecommerce_serang.data.api.response.store.topup.BalanceTopUpResponse
import com.alya.ecommerce_serang.data.api.response.store.topup.TopUpResponse import com.alya.ecommerce_serang.data.api.response.store.topup.TopUpResponse
@ -339,10 +339,22 @@ interface ApiService {
@PUT("store/order/update") @PUT("store/order/update")
suspend fun updateOrder( suspend fun updateOrder(
@Query("order_id") orderId: Int?, @Part("order_id") orderId: Int?,
@Query("status") status: String @Part("status") status: String
): Response<com.alya.ecommerce_serang.data.api.response.store.sells.UpdateOrderItemResponse> ): Response<com.alya.ecommerce_serang.data.api.response.store.sells.UpdateOrderItemResponse>
@PUT("store/payment/update")
suspend fun confirmPayment(
@Part("order_id") orderId: Int?,
@Part("status") status: String
): Response<GenericResponse>
@PUT("store/shipping/receiptnum")
suspend fun confirmShipment(
@Part("receipt_num") receiptNum: String,
@Part("order_id") orderId: Int?
): Response<GenericResponse>
@Multipart @Multipart
@POST("addcomplaint") @POST("addcomplaint")
suspend fun addComplaint( suspend fun addComplaint(

View File

@ -2,10 +2,12 @@ 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.dto.PaymentConfirmRequest
import com.alya.ecommerce_serang.data.api.response.store.GenericResponse
import com.alya.ecommerce_serang.data.api.response.store.sells.OrderDetailResponse import com.alya.ecommerce_serang.data.api.response.store.sells.OrderDetailResponse
import com.alya.ecommerce_serang.data.api.response.store.sells.OrderListResponse import com.alya.ecommerce_serang.data.api.response.store.sells.OrderListResponse
import com.alya.ecommerce_serang.data.api.response.store.sells.PaymentConfirmationResponse import com.alya.ecommerce_serang.data.api.response.store.sells.PaymentConfirmationResponse
import com.alya.ecommerce_serang.data.api.retrofit.ApiService import com.alya.ecommerce_serang.data.api.retrofit.ApiService
import retrofit2.Response
class SellsRepository(private val apiService: ApiService) { class SellsRepository(private val apiService: ApiService) {
suspend fun getSellList(status: String): Result<OrderListResponse> { suspend fun getSellList(status: String): Result<OrderListResponse> {
@ -43,40 +45,25 @@ class SellsRepository(private val apiService: ApiService) {
} }
} }
suspend fun updateOrderStatus(orderId: Int?, status: String) { suspend fun confirmPayment(orderId: Int, status: String): Response<GenericResponse> {
try {
val response = apiService.updateOrder(orderId, status)
if (response.isSuccessful) {
Log.d("SellsRepository", "Order status updated successfully: orderId=$orderId, status=$status")
} else {
Log.e("SellsRepository", "Error updating order status: orderId=$orderId, status=$status")
}
} catch (e: Exception) {
Log.e("SellsRepository", "Exception updating order status", e)
}
}
suspend fun confirmPaymentStore(request: PaymentConfirmRequest): Result<PaymentConfirmationResponse> {
return try { return try {
Log.d("SellsRepository", "Conforming order request completed: $request") Log.d("SellsRepository", "Calling confirmPayment with orderId=$orderId, status=$status")
val response = apiService.paymentConfirmation(request) apiService.confirmPayment(orderId, status)
} catch (e: Exception) {
if(response.isSuccessful) { Log.e("SellsRepository", "Error during confirmPayment", e)
val paymentConfirmResponse = response.body() throw e
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)
} }
} }
suspend fun confirmShipment(orderId: Int, receiptNum: String): Response<GenericResponse> {
return try {
apiService.confirmShipment(
receiptNum = receiptNum,
orderId = orderId
)
} catch (e: Exception) {
throw e
}
}
} }

View File

@ -16,7 +16,6 @@ import android.widget.TextView
import android.widget.Toast import android.widget.Toast
import androidx.activity.viewModels import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.LinearLayoutManager
import com.alya.ecommerce_serang.BuildConfig.BASE_URL 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.store.sells.Orders import com.alya.ecommerce_serang.data.api.response.store.sells.Orders
@ -26,7 +25,6 @@ import com.alya.ecommerce_serang.data.repository.AddressRepository
import com.alya.ecommerce_serang.data.repository.SellsRepository 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.ui.profile.mystore.sells.shipment.DetailShipmentActivity
import com.alya.ecommerce_serang.utils.BaseViewModelFactory import com.alya.ecommerce_serang.utils.BaseViewModelFactory
import com.alya.ecommerce_serang.utils.SessionManager import com.alya.ecommerce_serang.utils.SessionManager
import com.alya.ecommerce_serang.utils.viewmodel.AddressViewModel import com.alya.ecommerce_serang.utils.viewmodel.AddressViewModel
@ -40,6 +38,7 @@ import java.text.SimpleDateFormat
import java.util.Calendar import java.util.Calendar
import java.util.Locale import java.util.Locale
import java.util.TimeZone import java.util.TimeZone
import androidx.core.graphics.drawable.toDrawable
class DetailPaymentActivity : AppCompatActivity() { class DetailPaymentActivity : AppCompatActivity() {
@ -84,6 +83,32 @@ class DetailPaymentActivity : AppCompatActivity() {
observeOrderDetails() observeOrderDetails()
binding.tvOrderSellsDesc.setOnClickListener {
val paymentEvidence = sells?.paymentEvidence
if (!paymentEvidence.isNullOrEmpty()) {
showPaymentEvidenceDialog(paymentEvidence)
} else {
Toast.makeText(this, "Bukti pembayaran tidak tersedia", Toast.LENGTH_SHORT).show()
}
}
binding.btnHoldPayment.setOnClickListener {
sells?.orderId?.let {
viewModel.confirmPayment(it, "onhold")
Toast.makeText(this, "Otomatis pembayaran dinonaktifkan", Toast.LENGTH_SHORT).show()
} ?: run {
Log.e("DetailPaymentActivity", "No order passed in intent")
}
}
binding.btnConfirmPayment.setOnClickListener {
sells?.orderId?.let {
viewModel.confirmPayment(it, "confirmed")
Toast.makeText(this, "Pembayaran dikonfirmasi", Toast.LENGTH_SHORT).show()
} ?: run {
Log.e("DetailPaymentActivity", "No order passed in intent")
}
}
} }
private fun observeOrderDetails() { private fun observeOrderDetails() {
@ -173,17 +198,6 @@ class DetailPaymentActivity : AppCompatActivity() {
return String.format(Locale("id", "ID"), "Rp%,.0f", priceDouble) return String.format(Locale("id", "ID"), "Rp%,.0f", priceDouble)
} }
private fun setupPaymentEvidenceViewer() {
binding.tvOrderSellsDesc.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) { private fun showPaymentEvidenceDialog(paymentEvidence: String) {
val dialog = Dialog(this) val dialog = Dialog(this)
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE) dialog.requestWindowFeature(Window.FEATURE_NO_TITLE)
@ -193,7 +207,7 @@ class DetailPaymentActivity : AppCompatActivity() {
// Set dialog to fullscreen // Set dialog to fullscreen
val window = dialog.window val window = dialog.window
window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT) window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)
window?.setBackgroundDrawable(ColorDrawable(Color.BLACK)) window?.setBackgroundDrawable(Color.WHITE.toDrawable())
// Get views from dialog // Get views from dialog
val imageView = dialog.findViewById<ImageView>(R.id.iv_payment_evidence) val imageView = dialog.findViewById<ImageView>(R.id.iv_payment_evidence)
@ -201,21 +215,13 @@ class DetailPaymentActivity : AppCompatActivity() {
val tvTitle = dialog.findViewById<TextView>(R.id.tv_title) val tvTitle = dialog.findViewById<TextView>(R.id.tv_title)
val progressBar = dialog.findViewById<ProgressBar>(R.id.progress_bar) val progressBar = dialog.findViewById<ProgressBar>(R.id.progress_bar)
// Set title
tvTitle.text = "Bukti Pembayaran" tvTitle.text = "Bukti Pembayaran"
val fullImageUrl =
if (paymentEvidence.startsWith("/")) BASE_URL + paymentEvidence.substring(1)
else paymentEvidence
// 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 progressBar.visibility = View.VISIBLE
// Load image with Glide
Glide.with(this) Glide.with(this)
.load(fullImageUrl) .load(fullImageUrl)
.placeholder(R.drawable.placeholder_image) .placeholder(R.drawable.placeholder_image)
@ -239,16 +245,8 @@ class DetailPaymentActivity : AppCompatActivity() {
} }
}) })
btnClose.setOnClickListener { dialog.dismiss() }
// Close button click listener imageView.setOnClickListener { dialog.dismiss() }
btnClose.setOnClickListener {
dialog.dismiss()
}
// Click outside to close
imageView.setOnClickListener {
dialog.dismiss()
}
dialog.show() dialog.show()
} }

View File

@ -1,7 +1,9 @@
package com.alya.ecommerce_serang.ui.profile.mystore.sells.shipment package com.alya.ecommerce_serang.ui.profile.mystore.sells.shipment
import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.util.Log import android.util.Log
import android.widget.Toast
import androidx.activity.viewModels import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import com.alya.ecommerce_serang.data.api.response.store.sells.Orders import com.alya.ecommerce_serang.data.api.response.store.sells.Orders
@ -64,6 +66,16 @@ class DetailShipmentActivity : AppCompatActivity() {
} }
observeOrderDetails() observeOrderDetails()
binding.btnConfirmShipment.setOnClickListener {
sells?.let {
val intent = Intent(this, ShipmentConfirmationActivity::class.java)
intent.putExtra("sells_data", Gson().toJson(it))
startActivity(intent)
} ?: run {
Toast.makeText(this, "Data pesanan tidak tersedia", Toast.LENGTH_SHORT).show()
}
}
} }
private fun observeOrderDetails() { private fun observeOrderDetails() {

View File

@ -1,21 +1,71 @@
package com.alya.ecommerce_serang.ui.profile.mystore.sells.shipment package com.alya.ecommerce_serang.ui.profile.mystore.sells.shipment
import android.os.Bundle import android.os.Bundle
import androidx.activity.enableEdgeToEdge import android.widget.Toast
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat import com.alya.ecommerce_serang.data.api.response.store.sells.Orders
import androidx.core.view.WindowInsetsCompat import com.alya.ecommerce_serang.data.api.retrofit.ApiConfig
import com.alya.ecommerce_serang.R import com.alya.ecommerce_serang.data.repository.SellsRepository
import com.alya.ecommerce_serang.databinding.ActivityShipmentConfirmationBinding
import com.alya.ecommerce_serang.utils.BaseViewModelFactory
import com.alya.ecommerce_serang.utils.SessionManager
import com.alya.ecommerce_serang.utils.viewmodel.SellsViewModel
import com.google.gson.Gson
import kotlin.getValue
class ShipmentConfirmationActivity : AppCompatActivity() { class ShipmentConfirmationActivity : AppCompatActivity() {
private lateinit var binding: ActivityShipmentConfirmationBinding
private var sells: Orders? = null
private lateinit var sessionManager: SessionManager
private val viewModel: SellsViewModel by viewModels {
BaseViewModelFactory {
sessionManager = SessionManager(this)
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)
enableEdgeToEdge() binding = ActivityShipmentConfirmationBinding.inflate(layoutInflater)
setContentView(R.layout.activity_shipment_confirmation) setContentView(binding.root)
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()) binding.header.headerTitle.text = "Konfirmasi Pengiriman"
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom) binding.header.headerLeftIcon.setOnClickListener {
insets onBackPressed()
finish()
}
val sellsJson = intent.getStringExtra("sells_data")
sells = Gson().fromJson(sellsJson, Orders::class.java)
// Pre-fill fields
binding.edtNoPesanan.setText(sells?.orderId?.toString())
binding.edtKurir.setText(sells?.courier ?: "")
binding.edtLayananKirim.setText(sells?.service ?: "")
binding.btnConfirm.setOnClickListener {
val receiptNum = binding.edtNoResi.text.toString().trim()
val orderId = sells?.orderId
if (receiptNum.isEmpty()) {
Toast.makeText(this, "Nomor resi tidak boleh kosong", Toast.LENGTH_SHORT).show()
} else if (orderId == null) {
Toast.makeText(this, "Order ID tidak ditemukan", Toast.LENGTH_SHORT).show()
} else {
viewModel.confirmShipment(orderId, receiptNum)
}
}
viewModel.message.observe(this) {
Toast.makeText(this, it, Toast.LENGTH_SHORT).show()
}
viewModel.isSuccess.observe(this) { success ->
if (success) finish()
} }
} }
} }

View File

@ -169,42 +169,53 @@ class SellsViewModel(private val repository: SellsRepository) : ViewModel() {
} }
} }
fun updateOrderStatus(orderId: Int?, status: String) { fun confirmPayment(orderId: Int, status: String) {
Log.d(TAG, "========== Starting updateOrderStatus ==========") Log.d(TAG, "Confirming order completed: orderId=$orderId, status=$status")
Log.d(TAG, "Updating order status: orderId=$orderId, status='$status'") _isLoading.value = true
viewModelScope.launch { viewModelScope.launch {
try { try {
Log.d(TAG, "Calling repository.updateOrderStatus") val response = repository.confirmPayment(orderId, status)
val startTime = System.currentTimeMillis() if (response.isSuccessful) {
val body = response.body()
repository.updateOrderStatus(orderId, status) Log.d(TAG, "confirmPayment success: ${body?.message}")
_message.value = body?.message ?: "Status berhasil diperbarui"
val endTime = System.currentTimeMillis() _isSuccess.value = true
Log.d(TAG, "✅ Order status updated successfully in ${endTime - startTime}ms") } else {
Log.d(TAG, "Updated orderId=$orderId to status='$status'") val errorMsg = response.errorBody()?.string() ?: "Unknown error"
Log.e(TAG, "confirmPayment failed: $errorMsg")
_error.value = "Gagal memperbarui status: $errorMsg"
_isSuccess.value = false
}
} catch (e: Exception) { } catch (e: Exception) {
Log.e(TAG, "❌ Error updating order status") Log.e(TAG, "Exception in confirmPayment", e)
Log.e(TAG, "Exception type: ${e.javaClass.simpleName}") _error.value = "Terjadi kesalahan: ${e.message}"
Log.e(TAG, "Exception message: ${e.message}") _isSuccess.value = false
Log.e(TAG, "Exception stack trace:", e) } finally {
_isLoading.value = false
} }
} }
Log.d(TAG, "========== updateOrderStatus method completed ==========")
} }
fun confirmPayment(orderId: Int, status: String) { fun confirmShipment(orderId: Int, receiptNum: String) {
Log.d(TAG, "Confirming order completed: orderId=$orderId, status=$status") _isLoading.value = true
viewModelScope.launch { viewModelScope.launch {
_confirmPaymentStore.value = Result.Loading try {
val request = PaymentConfirmRequest(orderId, status) val response = repository.confirmShipment(orderId, receiptNum)
if (response.isSuccessful) {
Log.d(TAG, "Sending order completion request: $request") _message.value = response.body()?.message ?: "Berhasil mengonfirmasi pengiriman"
val result = repository.confirmPaymentStore(request) _isSuccess.value = true
Log.d(TAG, "Order completion result: $result") } else {
_confirmPaymentStore.value = result val errorMsg = response.errorBody()?.string() ?: "Gagal konfirmasi pengiriman"
_error.value = errorMsg
_isSuccess.value = false
}
} catch (e: Exception) {
_error.value = "Terjadi kesalahan: ${e.message}"
_isSuccess.value = false
} finally {
_isLoading.value = false
}
} }
} }

View File

@ -31,7 +31,7 @@
<!-- Payment Header --> <!-- Payment Header -->
<View <View
android:id="@+id/shape_payment_order_title" android:id="@+id/shape_shipment_order_title"
android:layout_width="4dp" android:layout_width="4dp"
android:layout_height="10dp" android:layout_height="10dp"
android:layout_marginTop="3dp" android:layout_marginTop="3dp"
@ -44,7 +44,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="12dp" android:layout_marginStart="12dp"
app:layout_constraintStart_toStartOf="@id/shape_payment_order_title" app:layout_constraintStart_toStartOf="@id/shape_shipment_order_title"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
android:gravity="center"> android:gravity="center">
@ -278,7 +278,7 @@
<RelativeLayout <RelativeLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="@id/shape_payment_order_title" app:layout_constraintStart_toStartOf="@id/shape_shipment_order_title"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
android:gravity="center"> android:gravity="center">
@ -409,7 +409,7 @@
android:gravity="bottom"> android:gravity="bottom">
<Button <Button
android:id="@+id/btn_confirm_payment" android:id="@+id/btn_confirm_shipment"
style="@style/button.large.active.long" style="@style/button.large.active.long"
android:text="Kirim Pesanan" android:text="Kirim Pesanan"
android:layout_alignParentEnd="true"/> android:layout_alignParentEnd="true"/>

View File

@ -59,7 +59,7 @@
android:orientation="vertical" android:orientation="vertical"
android:layout_marginBottom="24dp"> android:layout_marginBottom="24dp">
<!-- Label Kurir Pengiriman -->
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@ -72,47 +72,37 @@
style="@style/body_medium" style="@style/body_medium"
android:layout_marginEnd="4dp"/> android:layout_marginEnd="4dp"/>
</LinearLayout> <TextView
<!-- Spinner Dropdown dengan Chevron -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:background="@drawable/bg_text_field_disabled"
android:gravity="center_vertical"
android:layout_marginTop="10dp">
<Spinner
android:id="@+id/spinner_kurir"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="1" android:layout_weight="1"
android:padding="8dp" android:text="*"
style="@style/body_small" style="@style/body_medium"
android:background="@null" android:textColor="@color/red_required"
android:clickable="false"/> android:layout_gravity="end"/>
<!-- Chevron Down Icon -->
<ImageView
android:layout_width="16dp"
android:layout_height="16dp"
android:src="@drawable/ic_down"
android:layout_marginEnd="8dp"
android:contentDescription="Chevron Down" />
</LinearLayout> </LinearLayout>
<EditText
android:id="@+id/edt_kurir"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/bg_text_field"
android:hint="Isi kurir pengiriman di sini"
android:padding="8dp"
style="@style/body_small"
android:layout_marginTop="4dp"/>
</LinearLayout> </LinearLayout>
<!-- Paket Pengiriman --> <!-- Layanan Pengiriman -->
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical" android:orientation="vertical"
android:layout_marginBottom="24dp"> android:layout_marginBottom="24dp">
<!-- Label Kondisi Produk -->
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@ -121,43 +111,32 @@
<TextView <TextView
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="Paket Pengiriman" android:text="Layanan Pengiriman"
style="@style/body_medium" style="@style/body_medium"
android:layout_marginEnd="4dp"/> android:layout_marginEnd="4dp"/>
</LinearLayout> <TextView
<!-- Spinner Dropdown dengan Chevron -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:background="@drawable/bg_text_field_disabled"
android:gravity="center_vertical"
android:layout_marginTop="10dp">
<Spinner
android:id="@+id/spinner_paket_kirim"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="1" android:layout_weight="1"
android:padding="8dp" android:text="*"
style="@style/body_small" style="@style/body_medium"
android:background="@null" android:textColor="@color/red_required"
android:clickable="false"/> android:layout_gravity="end"/>
<!-- Chevron Down Icon -->
<ImageView
android:layout_width="16dp"
android:layout_height="16dp"
android:src="@drawable/ic_down"
android:layout_marginEnd="8dp"
android:contentDescription="Chevron Down" />
</LinearLayout> </LinearLayout>
</LinearLayout> <EditText
android:id="@+id/edt_layanan_kirim"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/bg_text_field"
android:hint="Isi layanan pengiriman dari kurir di sini"
android:padding="8dp"
style="@style/body_small"
android:layout_marginTop="4dp"/>
</LinearLayout>
<!-- Nomor Resi --> <!-- Nomor Resi -->
<LinearLayout <LinearLayout

View File

@ -3,7 +3,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="@android:color/black"> android:background="@color/white">
<!-- Header with title and close button --> <!-- Header with title and close button -->
<LinearLayout <LinearLayout
@ -23,18 +23,15 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="1" android:layout_weight="1"
android:text="Bukti Pembayaran" android:text="Bukti Pembayaran"
android:textColor="@android:color/white" style="@style/title_large" />
android:textSize="18sp"
android:textStyle="bold" />
<ImageButton <ImageButton
android:id="@+id/btn_close" android:id="@+id/btn_close"
android:layout_width="48dp" android:layout_width="24dp"
android:layout_height="48dp" android:layout_height="24dp"
android:background="?attr/selectableItemBackgroundBorderless" android:background="?attr/selectableItemBackgroundBorderless"
android:src="@drawable/ic_close" android:src="@drawable/ic_close"
android:contentDescription="Close" android:contentDescription="Close" />
app:tint="@android:color/white" />
</LinearLayout> </LinearLayout>