mirror of
https://github.com/shaulascr/ecommerce_serang.git
synced 2025-08-10 09:22:21 +00:00
add complaint (in dialog)
This commit is contained in:
@ -0,0 +1,16 @@
|
||||
package com.alya.ecommerce_serang.data.api.dto
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import okhttp3.MultipartBody
|
||||
|
||||
data class ComplaintRequest (
|
||||
@SerializedName("order_id")
|
||||
val orderId: Int,
|
||||
|
||||
@SerializedName("description")
|
||||
val description: String,
|
||||
|
||||
@SerializedName("complaintimg")
|
||||
val complaintImg: MultipartBody.Part
|
||||
|
||||
)
|
@ -0,0 +1,36 @@
|
||||
package com.alya.ecommerce_serang.data.api.response.order
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
data class ComplaintResponse(
|
||||
|
||||
@field:SerializedName("voucher")
|
||||
val voucher: Voucher,
|
||||
|
||||
@field:SerializedName("message")
|
||||
val message: String
|
||||
)
|
||||
|
||||
data class Voucher(
|
||||
|
||||
@field:SerializedName("solution")
|
||||
val solution: Any,
|
||||
|
||||
@field:SerializedName("evidence")
|
||||
val evidence: String,
|
||||
|
||||
@field:SerializedName("description")
|
||||
val description: String,
|
||||
|
||||
@field:SerializedName("created_at")
|
||||
val createdAt: String,
|
||||
|
||||
@field:SerializedName("id")
|
||||
val id: Int,
|
||||
|
||||
@field:SerializedName("order_id")
|
||||
val orderId: Int,
|
||||
|
||||
@field:SerializedName("status")
|
||||
val status: String
|
||||
)
|
@ -19,6 +19,7 @@ import com.alya.ecommerce_serang.data.api.response.cart.AddCartResponse
|
||||
import com.alya.ecommerce_serang.data.api.response.cart.ListCartResponse
|
||||
import com.alya.ecommerce_serang.data.api.response.cart.UpdateCartResponse
|
||||
import com.alya.ecommerce_serang.data.api.response.order.AddEvidenceResponse
|
||||
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.CourierCostResponse
|
||||
import com.alya.ecommerce_serang.data.api.response.order.CreateOrderResponse
|
||||
@ -187,4 +188,12 @@ interface ApiService {
|
||||
suspend fun confirmOrder(
|
||||
@Body confirmOrder : CompletedOrderRequest
|
||||
): Response<CompletedOrderResponse>
|
||||
|
||||
@Multipart
|
||||
@POST("addcomplaint")
|
||||
suspend fun addComplaint(
|
||||
@Part("order_id") orderId: RequestBody,
|
||||
@Part("description") description: RequestBody,
|
||||
@Part complaintimg: MultipartBody.Part
|
||||
): Response<ComplaintResponse>
|
||||
}
|
@ -10,6 +10,7 @@ import com.alya.ecommerce_serang.data.api.dto.OrderRequestBuy
|
||||
import com.alya.ecommerce_serang.data.api.dto.UserProfile
|
||||
import com.alya.ecommerce_serang.data.api.response.cart.DataItem
|
||||
import com.alya.ecommerce_serang.data.api.response.order.AddEvidenceResponse
|
||||
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.CourierCostResponse
|
||||
import com.alya.ecommerce_serang.data.api.response.order.CreateOrderResponse
|
||||
@ -23,7 +24,16 @@ import com.alya.ecommerce_serang.data.api.response.product.StoreResponse
|
||||
import com.alya.ecommerce_serang.data.api.response.profile.AddressResponse
|
||||
import com.alya.ecommerce_serang.data.api.response.profile.CreateAddressResponse
|
||||
import com.alya.ecommerce_serang.data.api.retrofit.ApiService
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
||||
import okhttp3.MultipartBody
|
||||
import okhttp3.RequestBody.Companion.asRequestBody
|
||||
import okhttp3.RequestBody.Companion.toRequestBody
|
||||
import retrofit2.Response
|
||||
import java.io.File
|
||||
|
||||
class OrderRepository(private val apiService: ApiService) {
|
||||
|
||||
@ -351,4 +361,75 @@ suspend fun uploadPaymentProof(request: AddEvidenceMultipartRequest): Result<Add
|
||||
}
|
||||
}
|
||||
|
||||
fun submitComplaint(
|
||||
orderId: String,
|
||||
reason: String,
|
||||
imageFile: File?
|
||||
): Flow<Result<ComplaintResponse>> = flow {
|
||||
emit(Result.Loading)
|
||||
|
||||
try {
|
||||
// Debug logging
|
||||
Log.d("OrderRepository", "Submitting complaint for order: $orderId")
|
||||
Log.d("OrderRepository", "Reason: $reason")
|
||||
Log.d("OrderRepository", "Image file: ${imageFile?.absolutePath ?: "null"}")
|
||||
|
||||
// Create form data for the multipart request
|
||||
// Explicitly convert orderId to string to ensure correct formatting
|
||||
val orderIdRequestBody = orderId.toString().toRequestBody("text/plain".toMediaTypeOrNull())
|
||||
val reasonRequestBody = reason.toRequestBody("text/plain".toMediaTypeOrNull())
|
||||
|
||||
// Create the image part for the API
|
||||
val imagePart = if (imageFile != null && imageFile.exists()) {
|
||||
// Use the actual image file
|
||||
// Use asRequestBody() for files which is more efficient
|
||||
val imageRequestBody = imageFile.asRequestBody("image/*".toMediaTypeOrNull())
|
||||
MultipartBody.Part.createFormData(
|
||||
"complaintimg",
|
||||
imageFile.name,
|
||||
imageRequestBody
|
||||
)
|
||||
} else {
|
||||
// Create a simple empty part if no image
|
||||
val dummyRequestBody = "".toRequestBody("text/plain".toMediaTypeOrNull())
|
||||
MultipartBody.Part.createFormData(
|
||||
"complaintimg",
|
||||
"",
|
||||
dummyRequestBody
|
||||
)
|
||||
}
|
||||
|
||||
// Log request details before making the API call
|
||||
Log.d("OrderRepository", "Making API call to add complaint")
|
||||
Log.d("OrderRepository", "orderId: $orderId (as string)")
|
||||
|
||||
val response = apiService.addComplaint(
|
||||
orderIdRequestBody,
|
||||
reasonRequestBody,
|
||||
imagePart
|
||||
)
|
||||
|
||||
Log.d("OrderRepository", "Response code: ${response.code()}")
|
||||
Log.d("OrderRepository", "Response message: ${response.message()}")
|
||||
|
||||
if (response.isSuccessful && response.body() != null) {
|
||||
val complaintResponse = response.body() as ComplaintResponse
|
||||
emit(Result.Success(complaintResponse))
|
||||
} else {
|
||||
// Get the error message from the response if possible
|
||||
val errorBody = response.errorBody()?.string()
|
||||
val errorMessage = if (!errorBody.isNullOrEmpty()) {
|
||||
"Server error: $errorBody"
|
||||
} else {
|
||||
"Failed to submit complaint: ${response.code()} ${response.message()}"
|
||||
}
|
||||
Log.e("OrderRepository", errorMessage)
|
||||
emit(Result.Error(Exception(errorMessage)))
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e("OrderRepository", "Error submitting complaint: ${e.message}")
|
||||
emit(Result.Error(e))
|
||||
}
|
||||
}.flowOn(Dispatchers.IO)
|
||||
|
||||
}
|
@ -12,6 +12,7 @@ import com.alya.ecommerce_serang.data.repository.OrderRepository
|
||||
import com.alya.ecommerce_serang.data.repository.Result
|
||||
import com.alya.ecommerce_serang.ui.order.address.ViewState
|
||||
import kotlinx.coroutines.launch
|
||||
import java.io.File
|
||||
|
||||
class HistoryViewModel(private val repository: OrderRepository) : ViewModel() {
|
||||
|
||||
@ -25,6 +26,15 @@ class HistoryViewModel(private val repository: OrderRepository) : ViewModel() {
|
||||
private val _orderCompletionStatus = MutableLiveData<Result<CompletedOrderResponse>>()
|
||||
val orderCompletionStatus: LiveData<Result<CompletedOrderResponse>> = _orderCompletionStatus
|
||||
|
||||
private val _isLoading = MutableLiveData<Boolean>()
|
||||
val isLoading: LiveData<Boolean> = _isLoading
|
||||
|
||||
private val _message = MutableLiveData<String>()
|
||||
val message: LiveData<String> = _message
|
||||
|
||||
private val _isSuccess = MutableLiveData<Boolean>()
|
||||
val isSuccess: LiveData<Boolean> = _isSuccess
|
||||
|
||||
fun getOrderList(status: String) {
|
||||
_orders.value = ViewState.Loading
|
||||
viewModelScope.launch {
|
||||
@ -51,12 +61,42 @@ class HistoryViewModel(private val repository: OrderRepository) : ViewModel() {
|
||||
}
|
||||
}
|
||||
fun confirmOrderCompleted(orderId: Int, status: String) {
|
||||
Log.d(TAG, "Confirming order completed: orderId=$orderId, status=$status")
|
||||
viewModelScope.launch {
|
||||
_orderCompletionStatus.value = Result.Loading
|
||||
val request = CompletedOrderRequest(orderId, status)
|
||||
|
||||
Log.d(TAG, "Sending order completion request: $request")
|
||||
val result = repository.confirmOrderCompleted(request)
|
||||
Log.d(TAG, "Order completion result: $result")
|
||||
_orderCompletionStatus.value = result
|
||||
}
|
||||
}
|
||||
|
||||
fun cancelOrderWithImage(orderId: String, reason: String, imageFile: File?) {
|
||||
Log.d(TAG, "Cancelling order with image: orderId=$orderId, reason=$reason, hasImage=${imageFile != null}")
|
||||
viewModelScope.launch {
|
||||
repository.submitComplaint(orderId, reason, imageFile).collect { result ->
|
||||
when (result) {
|
||||
is Result.Loading -> {
|
||||
Log.d(TAG, "Submitting complaint: Loading")
|
||||
_isLoading.value = true
|
||||
}
|
||||
is Result.Success -> {
|
||||
Log.d(TAG, "Complaint submitted successfully: ${result.data.message}")
|
||||
_message.value = result.data.message
|
||||
_isSuccess.value = true
|
||||
_isLoading.value = false
|
||||
}
|
||||
is Result.Error -> {
|
||||
val errorMessage = result.exception.message ?: "Error submitting complaint"
|
||||
Log.e(TAG, "Error submitting complaint: $errorMessage", result.exception)
|
||||
_message.value = errorMessage
|
||||
_isSuccess.value = false
|
||||
_isLoading.value = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,17 +1,31 @@
|
||||
package com.alya.ecommerce_serang.ui.order.history
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.Dialog
|
||||
import android.content.Intent
|
||||
import android.graphics.Color
|
||||
import android.net.Uri
|
||||
import android.provider.MediaStore
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.Window
|
||||
import android.widget.ArrayAdapter
|
||||
import android.widget.AutoCompleteTextView
|
||||
import android.widget.ImageView
|
||||
import android.widget.ProgressBar
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.lifecycle.findViewTreeLifecycleOwner
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.alya.ecommerce_serang.R
|
||||
import com.alya.ecommerce_serang.data.api.response.order.OrdersItem
|
||||
import com.alya.ecommerce_serang.ui.order.detail.PaymentActivity
|
||||
import com.google.android.material.button.MaterialButton
|
||||
import com.google.android.material.textfield.TextInputLayout
|
||||
import java.io.File
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Calendar
|
||||
import java.util.Locale
|
||||
@ -128,6 +142,13 @@ class OrderHistoryAdapter(
|
||||
visibility = View.VISIBLE
|
||||
text = itemView.context.getString(R.string.dl_pending)
|
||||
}
|
||||
btnLeft.apply {
|
||||
visibility = View.VISIBLE
|
||||
text = itemView.context.getString(R.string.canceled_order_btn)
|
||||
setOnClickListener {
|
||||
showCancelOrderDialog(order.orderId.toString())
|
||||
}
|
||||
}
|
||||
deadlineDate.apply {
|
||||
visibility = View.VISIBLE
|
||||
text = formatDate(order.createdAt)
|
||||
@ -146,6 +167,7 @@ class OrderHistoryAdapter(
|
||||
visibility = View.VISIBLE
|
||||
text = itemView.context.getString(R.string.canceled_order_btn)
|
||||
setOnClickListener {
|
||||
showCancelOrderDialog(order.orderId.toString())
|
||||
}
|
||||
}
|
||||
|
||||
@ -177,7 +199,13 @@ class OrderHistoryAdapter(
|
||||
visibility = View.VISIBLE
|
||||
text = itemView.context.getString(R.string.dl_processed)
|
||||
}
|
||||
|
||||
btnLeft.apply {
|
||||
visibility = View.VISIBLE
|
||||
text = itemView.context.getString(R.string.canceled_order_btn)
|
||||
setOnClickListener {
|
||||
showCancelOrderDialog(order.orderId.toString())
|
||||
}
|
||||
}
|
||||
}
|
||||
"shipped" -> {
|
||||
// Untuk status shipped, tampilkan "Lacak Pengiriman" dan "Terima Barang"
|
||||
@ -193,6 +221,7 @@ class OrderHistoryAdapter(
|
||||
visibility = View.VISIBLE
|
||||
text = itemView.context.getString(R.string.claim_complaint)
|
||||
setOnClickListener {
|
||||
showCancelOrderDialog(order.orderId.toString())
|
||||
// Handle click event
|
||||
}
|
||||
}
|
||||
@ -318,5 +347,158 @@ class OrderHistoryAdapter(
|
||||
dateString
|
||||
}
|
||||
}
|
||||
|
||||
private fun showCancelOrderDialog(orderId: String) {
|
||||
val context = itemView.context
|
||||
val dialog = Dialog(context)
|
||||
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE)
|
||||
dialog.setContentView(R.layout.dialog_cancel_order)
|
||||
dialog.setCancelable(true)
|
||||
|
||||
// Set the dialog width to match parent
|
||||
val window = dialog.window
|
||||
window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
|
||||
|
||||
// Get references to the views in the dialog
|
||||
val spinnerCancelReason = dialog.findViewById<AutoCompleteTextView>(R.id.spinnerCancelReason)
|
||||
val tilCancelReason = dialog.findViewById<TextInputLayout>(R.id.tilCancelReason)
|
||||
val btnCancelDialog = dialog.findViewById<MaterialButton>(R.id.btnCancelDialog)
|
||||
val btnConfirmCancel = dialog.findViewById<MaterialButton>(R.id.btnConfirmCancel)
|
||||
val ivComplaintImage = dialog.findViewById<ImageView>(R.id.ivComplaintImage)
|
||||
val tvSelectImage = dialog.findViewById<TextView>(R.id.tvSelectImage)
|
||||
|
||||
// Set up the reasons dropdown
|
||||
val reasons = context.resources.getStringArray(R.array.cancellation_reasons)
|
||||
val adapter = ArrayAdapter(context, android.R.layout.simple_dropdown_item_1line, reasons)
|
||||
spinnerCancelReason.setAdapter(adapter)
|
||||
|
||||
// For storing the selected image URI
|
||||
var selectedImageUri: Uri? = null
|
||||
|
||||
// Set click listener for image selection
|
||||
ivComplaintImage.setOnClickListener {
|
||||
// Create an intent to open the image picker
|
||||
val galleryIntent = Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
|
||||
(context as? Activity)?.startActivityForResult(galleryIntent, REQUEST_IMAGE_PICK)
|
||||
|
||||
// Set up result handler in the activity
|
||||
val activity = context as? Activity
|
||||
activity?.let {
|
||||
// Remove any existing callbacks to avoid memory leaks
|
||||
if (imagePickCallback != null) {
|
||||
imagePickCallback = null
|
||||
}
|
||||
|
||||
// Create a new callback for this specific dialog
|
||||
imagePickCallback = { uri ->
|
||||
selectedImageUri = uri
|
||||
|
||||
// Load and display the selected image
|
||||
ivComplaintImage.setImageURI(uri)
|
||||
tvSelectImage.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set click listeners for buttons
|
||||
btnCancelDialog.setOnClickListener {
|
||||
dialog.dismiss()
|
||||
}
|
||||
|
||||
btnConfirmCancel.setOnClickListener {
|
||||
val reason = spinnerCancelReason.text.toString().trim()
|
||||
|
||||
if (reason.isEmpty()) {
|
||||
tilCancelReason.error = context.getString(R.string.please_select_cancellation_reason)
|
||||
return@setOnClickListener
|
||||
}
|
||||
|
||||
// Clear error if any
|
||||
tilCancelReason.error = null
|
||||
|
||||
// Convert selected image to file if available
|
||||
val imageFile = selectedImageUri?.let { uri ->
|
||||
try {
|
||||
// Get the file path from URI
|
||||
val filePathColumn = arrayOf(MediaStore.Images.Media.DATA)
|
||||
val cursor = context.contentResolver.query(uri, filePathColumn, null, null, null)
|
||||
cursor?.use {
|
||||
if (it.moveToFirst()) {
|
||||
val columnIndex = it.getColumnIndex(filePathColumn[0])
|
||||
val filePath = it.getString(columnIndex)
|
||||
return@let File(filePath)
|
||||
}
|
||||
}
|
||||
null
|
||||
} catch (e: Exception) {
|
||||
Log.e("OrderHistoryAdapter", "Error getting file from URI: ${e.message}")
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
// Show loading indicator
|
||||
val loadingView = View(context).apply {
|
||||
layoutParams = ViewGroup.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.MATCH_PARENT
|
||||
)
|
||||
setBackgroundColor(Color.parseColor("#80000000"))
|
||||
|
||||
val progressBar = ProgressBar(context).apply {
|
||||
layoutParams = ViewGroup.LayoutParams(
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
)
|
||||
}
|
||||
|
||||
// addView(progressBar)
|
||||
// (progressBar.layoutParams as? ViewGroup.MarginLayoutParams)?.apply {
|
||||
// gravity = Gravity.CENTER
|
||||
// }
|
||||
}
|
||||
|
||||
dialog.addContentView(loadingView, loadingView.layoutParams)
|
||||
|
||||
// Call the ViewModel to cancel the order with image
|
||||
viewModel.cancelOrderWithImage(orderId, reason, imageFile)
|
||||
|
||||
// Observe for success/failure
|
||||
viewModel.isSuccess.observe(itemView.findViewTreeLifecycleOwner()!!) { isSuccess ->
|
||||
// Remove loading indicator
|
||||
(loadingView.parent as? ViewGroup)?.removeView(loadingView)
|
||||
|
||||
if (isSuccess) {
|
||||
Toast.makeText(context, context.getString(R.string.order_canceled_successfully), Toast.LENGTH_SHORT).show()
|
||||
dialog.dismiss()
|
||||
|
||||
// Find the order in the list and remove it or update its status
|
||||
val position = orders.indexOfFirst { it.orderId.toString() == orderId }
|
||||
if (position != -1) {
|
||||
orders.removeAt(position)
|
||||
notifyItemRemoved(position)
|
||||
notifyItemRangeChanged(position, orders.size)
|
||||
}
|
||||
} else {
|
||||
Toast.makeText(context, viewModel.message.value ?: context.getString(R.string.failed_to_cancel_order), Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
dialog.show()
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val REQUEST_IMAGE_PICK = 100
|
||||
private var imagePickCallback: ((Uri) -> Unit)? = null
|
||||
|
||||
// This method should be called from the activity's onActivityResult
|
||||
fun handleImageResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
if (requestCode == REQUEST_IMAGE_PICK && resultCode == Activity.RESULT_OK && data != null) {
|
||||
val selectedImageUri = data.data
|
||||
selectedImageUri?.let { uri ->
|
||||
imagePickCallback?.invoke(uri)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -52,23 +52,6 @@ class HomeViewModel (
|
||||
loadProducts()
|
||||
loadCategories()
|
||||
}
|
||||
|
||||
// private fun fetchUserData() {
|
||||
// viewModelScope.launch {
|
||||
// try {
|
||||
// val response = apiService.getProtectedData() // Example API request
|
||||
// if (response.isSuccessful) {
|
||||
// val data = response.body()
|
||||
// Log.d("HomeFragment", "User Data: $data")
|
||||
// // Update UI with data
|
||||
// } else {
|
||||
// Log.e("HomeFragment", "Error: ${response.message()}")
|
||||
// }
|
||||
// } catch (e: Exception) {
|
||||
// Log.e("HomeFragment", "Exception: ${e.message}")
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
sealed class HomeUiState {
|
||||
|
11
app/src/main/res/drawable/bg_dashboard_border.xml
Normal file
11
app/src/main/res/drawable/bg_dashboard_border.xml
Normal file
@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<stroke
|
||||
android:width="2dp"
|
||||
android:color="#BCBCBC"
|
||||
android:dashWidth="10dp"
|
||||
android:dashGap="6dp" />
|
||||
<corners android:radius="8dp" />
|
||||
<solid android:color="#F5F5F5" />
|
||||
</shape>
|
103
app/src/main/res/layout/dialog_cancel_order.xml
Normal file
103
app/src/main/res/layout/dialog_cancel_order.xml
Normal file
@ -0,0 +1,103 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.cardview.widget.CardView 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="wrap_content"
|
||||
app:cardCornerRadius="16dp"
|
||||
app:cardElevation="8dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="24dp">
|
||||
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:text="@string/cancel_order_confirmation"
|
||||
android:textAlignment="center"
|
||||
android:fontFamily="@font/dmsans_semibold"
|
||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Headline6" />
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/tilCancelReason"
|
||||
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.ExposedDropdownMenu"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:hint="@string/reason_for_cancellation">
|
||||
|
||||
<AutoCompleteTextView
|
||||
android:id="@+id/spinnerCancelReason"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="none"
|
||||
android:focusable="false" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<!-- Image Upload Section -->
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/upload_evidence"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:fontFamily="@font/dmsans_medium"
|
||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Body1" />
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/ivComplaintImage"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="150dp"
|
||||
android:scaleType="centerCrop"
|
||||
android:background="@drawable/bg_dashboard_border"
|
||||
android:contentDescription="@string/complaint_image" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvSelectImage"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:text="@string/tap_to_select_image"
|
||||
android:drawableTop="@drawable/baseline_upload_file_24"
|
||||
android:drawablePadding="8dp"
|
||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Body2" />
|
||||
</FrameLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btnCancelDialog"
|
||||
style="@style/RoundedBorderStyle"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_weight="1"
|
||||
android:fontFamily="@font/dmsans_semibold"
|
||||
android:textColor="@color/blue_500"
|
||||
android:text="@string/cancel" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btnConfirmCancel"
|
||||
style="@style/RoundedBorderStyleFilled"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_weight="1"
|
||||
android:fontFamily="@font/dmsans_semibold"
|
||||
android:text="@string/confirm" />
|
||||
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</androidx.cardview.widget.CardView>
|
@ -93,5 +93,29 @@
|
||||
<string name="claim_order">Pesanan Diterima </string>
|
||||
<string name="add_review">Beri Ulasan </string>
|
||||
|
||||
<string name="warning_icon">Warning Icon</string>
|
||||
<string name="cancel_order_confirmation">Apakah anda yakin ingin membatalkan pesanan?</string>
|
||||
<string name="reason_for_cancellation">Alasan Batalkan Pesanan</string>
|
||||
<string name="cancel">Kembali</string>
|
||||
<string name="confirm">Batalkan Pesanan</string>
|
||||
<string name="order_canceled_successfully">Order canceled successfully</string>
|
||||
<string name="failed_to_cancel_order">Failed to cancel order</string>
|
||||
<string name="please_select_cancellation_reason">Please select a reason for cancellation</string>
|
||||
<string name="upload_evidence">Unggah Bukti Komplain</string>
|
||||
<string name="complaint_image">Complaint evidence image</string>
|
||||
<string name="tap_to_select_image">Tekan untuk unggah foto</string>
|
||||
<string name="please_select_image">Please select an image as evidence</string>
|
||||
<string name="image_too_large">Image is too large. Please select a smaller image.</string>
|
||||
|
||||
<!-- Cancellation Reasons -->
|
||||
<string-array name="cancellation_reasons">
|
||||
<item>Found a better price elsewhere</item>
|
||||
<item>Changed my mind about the product</item>
|
||||
<item>Ordered the wrong item</item>
|
||||
<item>Shipping time is too long</item>
|
||||
<item>Financial reasons</item>
|
||||
<item>Other reason</item>
|
||||
</string-array>
|
||||
|
||||
|
||||
</resources>
|
@ -7,4 +7,22 @@
|
||||
<item name="android:padding">12dp</item>
|
||||
<!-- Add more style attributes as needed -->
|
||||
</style>
|
||||
|
||||
<style name="RoundedBorderStyle">
|
||||
<!-- This style can be applied to views -->
|
||||
<!-- <item name="android:background">@drawable/bg_button_outline</item>-->
|
||||
<item name="strokeColor">@color/blue_500</item>
|
||||
<item name="strokeWidth">2dp</item>
|
||||
<item name="cornerRadius">8dp</item>
|
||||
<item name="backgroundTint">@android:color/transparent</item>
|
||||
</style>
|
||||
|
||||
<style name="RoundedBorderStyleFilled">
|
||||
<!-- This style can be applied to views -->
|
||||
<!-- <item name="android:background">@drawable/bg_button_outline</item>-->
|
||||
<item name="strokeColor">@color/blue_500</item>
|
||||
<item name="strokeWidth">2dp</item>
|
||||
<item name="cornerRadius">8dp</item>
|
||||
<item name="backgroundTint">@color/blue_500</item>
|
||||
</style>
|
||||
</resources>
|
Reference in New Issue
Block a user