From 331410eb98ee1165ec9810aa074d1652d1da6005 Mon Sep 17 00:00:00 2001 From: shaulascr Date: Wed, 2 Jul 2025 01:40:41 +0700 Subject: [PATCH] update province cities subdistricts and villages --- .../data/api/dto/CreateAddressRequest.kt | 4 +- .../customer/order/ListProvinceResponse.kt | 8 +- .../customer/order/OrderDetailResponse.kt | 2 +- .../customer/order/OrderListResponse.kt | 2 +- .../customer/order/SubdistrictResponse.kt | 21 +++ .../customer/order/VillagesResponse.kt | 24 ++++ .../data/api/retrofit/ApiService.kt | 16 ++- .../data/repository/UserRepository.kt | 14 +- .../ecommerce_serang/ui/auth/LoginActivity.kt | 1 + .../auth/fragments/RegisterStep2Fragment.kt | 17 +-- .../auth/fragments/RegisterStep3Fragment.kt | 114 +++++++++++++-- .../ui/home/SearchResultAdapter.kt | 11 ++ .../ui/order/CheckoutViewModel.kt | 2 +- .../ui/order/address/AddAddressActivity.kt | 2 +- .../ui/order/address/AddAddressViewModel.kt | 6 +- .../ui/order/address/ProvinceAdapter.kt | 131 +++++++++++++++++- .../detail/AddEvidencePaymentActivity.kt | 13 +- .../ui/order/history/OrderHistoryAdapter.kt | 42 +++--- .../cancelorder/CancelOrderBottomSheet.kt | 12 +- .../detailorder/DetailOrderStatusActivity.kt | 102 +++++++++++--- .../detailorder/DetailOrderViewModel.kt | 1 + .../ui/product/DetailProductActivity.kt | 21 ++- .../ui/product/OtherProductAdapter.kt | 12 +- .../storeDetail/StoreDetailActivity.kt | 12 +- .../profile/mystore/RegisterStoreActivity.kt | 5 +- .../utils/viewmodel/RegisterStoreViewModel.kt | 6 +- .../utils/viewmodel/RegisterViewModel.kt | 72 +++++++++- .../layout/activity_add_evidence_payment.xml | 4 + .../res/layout/fragment_register_step3.xml | 63 +++++++-- app/src/main/res/values/strings.xml | 11 +- 30 files changed, 628 insertions(+), 123 deletions(-) create mode 100644 app/src/main/java/com/alya/ecommerce_serang/data/api/response/customer/order/SubdistrictResponse.kt create mode 100644 app/src/main/java/com/alya/ecommerce_serang/data/api/response/customer/order/VillagesResponse.kt diff --git a/app/src/main/java/com/alya/ecommerce_serang/data/api/dto/CreateAddressRequest.kt b/app/src/main/java/com/alya/ecommerce_serang/data/api/dto/CreateAddressRequest.kt index 8aefbe3..bdfdf08 100644 --- a/app/src/main/java/com/alya/ecommerce_serang/data/api/dto/CreateAddressRequest.kt +++ b/app/src/main/java/com/alya/ecommerce_serang/data/api/dto/CreateAddressRequest.kt @@ -16,12 +16,12 @@ data class CreateAddressRequest ( val subDistrict: String, @SerializedName("city_id") - val cityId: Int, + val cityId: String, @SerializedName("province_id") val provId: Int, @SerializedName("postal_code") - val postCode: String? = null, + val postCode: String, @SerializedName("detail") val detailAddress: String? = null, diff --git a/app/src/main/java/com/alya/ecommerce_serang/data/api/response/customer/order/ListProvinceResponse.kt b/app/src/main/java/com/alya/ecommerce_serang/data/api/response/customer/order/ListProvinceResponse.kt index b9904bb..38b66c9 100644 --- a/app/src/main/java/com/alya/ecommerce_serang/data/api/response/customer/order/ListProvinceResponse.kt +++ b/app/src/main/java/com/alya/ecommerce_serang/data/api/response/customer/order/ListProvinceResponse.kt @@ -12,10 +12,8 @@ data class ListProvinceResponse( ) data class ProvincesItem( - - @field:SerializedName("province") - val province: String, - @field:SerializedName("province_id") - val provinceId: String + val provinceId: String, + @field:SerializedName("province") + val province: String ) diff --git a/app/src/main/java/com/alya/ecommerce_serang/data/api/response/customer/order/OrderDetailResponse.kt b/app/src/main/java/com/alya/ecommerce_serang/data/api/response/customer/order/OrderDetailResponse.kt index 3adb6d4..0156579 100644 --- a/app/src/main/java/com/alya/ecommerce_serang/data/api/response/customer/order/OrderDetailResponse.kt +++ b/app/src/main/java/com/alya/ecommerce_serang/data/api/response/customer/order/OrderDetailResponse.kt @@ -56,7 +56,7 @@ data class Orders( val orderItems: List, @field:SerializedName("auto_completed_at") - val autoCompletedAt: String? = null, + val autoCompletedAt: String, @field:SerializedName("is_store_location") val isStoreLocation: Boolean? = null, diff --git a/app/src/main/java/com/alya/ecommerce_serang/data/api/response/customer/order/OrderListResponse.kt b/app/src/main/java/com/alya/ecommerce_serang/data/api/response/customer/order/OrderListResponse.kt index dd8c43f..2ab5242 100644 --- a/app/src/main/java/com/alya/ecommerce_serang/data/api/response/customer/order/OrderListResponse.kt +++ b/app/src/main/java/com/alya/ecommerce_serang/data/api/response/customer/order/OrderListResponse.kt @@ -15,7 +15,7 @@ data class OrderListResponse( data class OrderItemsItem( @field:SerializedName("review_id") - val reviewId: Int? = null, + val reviewId: Int, @field:SerializedName("quantity") val quantity: Int, diff --git a/app/src/main/java/com/alya/ecommerce_serang/data/api/response/customer/order/SubdistrictResponse.kt b/app/src/main/java/com/alya/ecommerce_serang/data/api/response/customer/order/SubdistrictResponse.kt new file mode 100644 index 0000000..56b103a --- /dev/null +++ b/app/src/main/java/com/alya/ecommerce_serang/data/api/response/customer/order/SubdistrictResponse.kt @@ -0,0 +1,21 @@ +package com.alya.ecommerce_serang.data.api.response.customer.order + +import com.google.gson.annotations.SerializedName + +data class SubdistrictResponse( + + @field:SerializedName("subdistricts") + val subdistricts: List, + + @field:SerializedName("message") + val message: String +) + +data class SubdistrictsItem( + + @field:SerializedName("subdistrict_id") + val subdistrictId: String, + + @field:SerializedName("subdistrict_name") + val subdistrictName: String +) diff --git a/app/src/main/java/com/alya/ecommerce_serang/data/api/response/customer/order/VillagesResponse.kt b/app/src/main/java/com/alya/ecommerce_serang/data/api/response/customer/order/VillagesResponse.kt new file mode 100644 index 0000000..04da40e --- /dev/null +++ b/app/src/main/java/com/alya/ecommerce_serang/data/api/response/customer/order/VillagesResponse.kt @@ -0,0 +1,24 @@ +package com.alya.ecommerce_serang.data.api.response.customer.order + +import com.google.gson.annotations.SerializedName + +data class VillagesResponse( + + @field:SerializedName("villages") + val villages: List, + + @field:SerializedName("message") + val message: String +) + +data class VillagesItem( + + @field:SerializedName("village_id") + val villageId: String, + + @field:SerializedName("village_name") + val villageName: String, + + @field:SerializedName("postal_code") + val postalCode: String +) diff --git a/app/src/main/java/com/alya/ecommerce_serang/data/api/retrofit/ApiService.kt b/app/src/main/java/com/alya/ecommerce_serang/data/api/retrofit/ApiService.kt index 1a04e32..6a85bca 100644 --- a/app/src/main/java/com/alya/ecommerce_serang/data/api/retrofit/ApiService.kt +++ b/app/src/main/java/com/alya/ecommerce_serang/data/api/retrofit/ApiService.kt @@ -53,6 +53,8 @@ import com.alya.ecommerce_serang.data.api.response.customer.order.ListCityRespon import com.alya.ecommerce_serang.data.api.response.customer.order.ListProvinceResponse import com.alya.ecommerce_serang.data.api.response.customer.order.OrderDetailResponse import com.alya.ecommerce_serang.data.api.response.customer.order.OrderListResponse +import com.alya.ecommerce_serang.data.api.response.customer.order.SubdistrictResponse +import com.alya.ecommerce_serang.data.api.response.customer.order.VillagesResponse import com.alya.ecommerce_serang.data.api.response.customer.product.AllProductResponse import com.alya.ecommerce_serang.data.api.response.customer.product.CategoryResponse import com.alya.ecommerce_serang.data.api.response.customer.product.DetailStoreProductResponse @@ -68,14 +70,14 @@ import com.alya.ecommerce_serang.data.api.response.order.ComplaintResponse import com.alya.ecommerce_serang.data.api.response.order.CompletedOrderResponse import com.alya.ecommerce_serang.data.api.response.product.CreateSearchResponse import com.alya.ecommerce_serang.data.api.response.product.SearchHistoryResponse -import com.alya.ecommerce_serang.data.api.response.store.sells.PaymentConfirmationResponse +import com.alya.ecommerce_serang.data.api.response.store.GenericResponse import com.alya.ecommerce_serang.data.api.response.store.product.CreateProductResponse import com.alya.ecommerce_serang.data.api.response.store.product.DeleteProductResponse import com.alya.ecommerce_serang.data.api.response.store.product.UpdateProductResponse import com.alya.ecommerce_serang.data.api.response.store.product.ViewStoreProductsResponse -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.review.ProductReviewResponse +import com.alya.ecommerce_serang.data.api.response.store.sells.PaymentConfirmationResponse import com.alya.ecommerce_serang.data.api.response.store.topup.BalanceTopUpResponse import com.alya.ecommerce_serang.data.api.response.store.topup.TopUpResponse import okhttp3.MultipartBody @@ -512,4 +514,14 @@ interface ApiService { @GET("store/reviews") suspend fun getStoreProductReview( ): Response + + @GET("subdistrict/{cityId}") + suspend fun getSubdistrict( + @Path("cityId") cityId: String + ): Response + + @GET("villages/{subdistrictId}") + suspend fun getVillages( + @Path("subdistrictId") subdistrictId: String + ): Response } \ No newline at end of file diff --git a/app/src/main/java/com/alya/ecommerce_serang/data/repository/UserRepository.kt b/app/src/main/java/com/alya/ecommerce_serang/data/repository/UserRepository.kt index f5a5c9f..df62ae7 100644 --- a/app/src/main/java/com/alya/ecommerce_serang/data/repository/UserRepository.kt +++ b/app/src/main/java/com/alya/ecommerce_serang/data/repository/UserRepository.kt @@ -21,6 +21,8 @@ import com.alya.ecommerce_serang.data.api.response.auth.RegisterStoreResponse import com.alya.ecommerce_serang.data.api.response.auth.VerifRegisterResponse import com.alya.ecommerce_serang.data.api.response.customer.order.ListCityResponse import com.alya.ecommerce_serang.data.api.response.customer.order.ListProvinceResponse +import com.alya.ecommerce_serang.data.api.response.customer.order.SubdistrictResponse +import com.alya.ecommerce_serang.data.api.response.customer.order.VillagesResponse import com.alya.ecommerce_serang.data.api.response.customer.profile.EditProfileResponse import com.alya.ecommerce_serang.data.api.retrofit.ApiService import com.alya.ecommerce_serang.utils.FileUtils @@ -68,6 +70,16 @@ class UserRepository(private val apiService: ApiService) { return if (response.isSuccessful) response.body() else null } + suspend fun getListSubdistrict(cityId : String): SubdistrictResponse? { + val response = apiService.getSubdistrict(cityId) + return if (response.isSuccessful) response.body() else null + } + + suspend fun getListVillages(subId: String): VillagesResponse? { + val response = apiService.getVillages(subId) + return if (response.isSuccessful) response.body() else null + } + suspend fun registerUser(request: RegisterRequest): RegisterResponse { val response = apiService.register(request) // API call @@ -87,7 +99,7 @@ class UserRepository(private val apiService: ApiService) { longitude: String, street: String, subdistrict: String, - cityId: Int, + cityId: String, provinceId: Int, postalCode: Int, detail: String, diff --git a/app/src/main/java/com/alya/ecommerce_serang/ui/auth/LoginActivity.kt b/app/src/main/java/com/alya/ecommerce_serang/ui/auth/LoginActivity.kt index 531b526..3d0ce11 100644 --- a/app/src/main/java/com/alya/ecommerce_serang/ui/auth/LoginActivity.kt +++ b/app/src/main/java/com/alya/ecommerce_serang/ui/auth/LoginActivity.kt @@ -105,6 +105,7 @@ class LoginActivity : AppCompatActivity() { finish() } is com.alya.ecommerce_serang.data.repository.Result.Error -> { + Log.e("LoginActivity", "Login Failed: ${result.exception.message}") Toast.makeText(this, "Login Failed: ${result.exception.message}", Toast.LENGTH_LONG).show() } is Result.Loading -> { diff --git a/app/src/main/java/com/alya/ecommerce_serang/ui/auth/fragments/RegisterStep2Fragment.kt b/app/src/main/java/com/alya/ecommerce_serang/ui/auth/fragments/RegisterStep2Fragment.kt index e7e5bb6..ecf2a66 100644 --- a/app/src/main/java/com/alya/ecommerce_serang/ui/auth/fragments/RegisterStep2Fragment.kt +++ b/app/src/main/java/com/alya/ecommerce_serang/ui/auth/fragments/RegisterStep2Fragment.kt @@ -88,7 +88,7 @@ class RegisterStep2Fragment : Fragment() { // Update the email sent message userData?.let { - binding.tvEmailSent.text = "We've sent a verification code to ${it.email}" + binding.tvEmailSent.text = "Kami telah mengirimkan kode OTP ke alamat email ${it.email}. Silahkan periksa email anda." } // Start the resend cooldown timer @@ -119,7 +119,7 @@ class RegisterStep2Fragment : Fragment() { Log.d(TAG, "verifyOtp called with OTP: $otp") if (otp.isEmpty()) { - Toast.makeText(requireContext(), "Please enter the verification code", Toast.LENGTH_SHORT).show() + Toast.makeText(requireContext(), "Masukkan kode OTP anda", Toast.LENGTH_SHORT).show() return } @@ -153,13 +153,13 @@ class RegisterStep2Fragment : Fragment() { } is com.alya.ecommerce_serang.data.repository.Result.Success -> { binding.progressBar.visibility = View.GONE - Toast.makeText(requireContext(), "Verification code resent", Toast.LENGTH_SHORT).show() + Toast.makeText(requireContext(), "Kode OTP sudah dikirim", Toast.LENGTH_SHORT).show() startResendCooldown() } is Result.Error -> { Log.e(TAG, "OTP request: Error - ${result.exception.message}") binding.progressBar.visibility = View.GONE - Toast.makeText(requireContext(), "Failed to resend code: ${result.exception.message}", Toast.LENGTH_SHORT).show() + Toast.makeText(requireContext(), "Gagal mengirim kode OTP", Toast.LENGTH_SHORT).show() } else -> { Log.d(TAG, "OTP request: Unknown state") @@ -180,7 +180,7 @@ class RegisterStep2Fragment : Fragment() { countDownTimer = object : CountDownTimer(30000, 1000) { override fun onTick(millisUntilFinished: Long) { timeRemaining = (millisUntilFinished / 1000).toInt() - binding.tvTimer.text = "Resend available in 00:${String.format("%02d", timeRemaining)}" + binding.tvTimer.text = "Kirim ulang OTP dalam waktu 00:${String.format("%02d", timeRemaining)}" if (timeRemaining % 5 == 0) { Log.d(TAG, "Cooldown remaining: $timeRemaining seconds") } @@ -188,7 +188,7 @@ class RegisterStep2Fragment : Fragment() { override fun onFinish() { Log.d(TAG, "Cooldown finished, enabling resend button") - binding.tvTimer.text = "You can now resend the code" + binding.tvTimer.text = "Dapat mengirim ulang kode OTP" binding.tvResendOtp.isEnabled = true binding.tvResendOtp.setTextColor(ContextCompat.getColor(requireContext(), R.color.blue1)) timeRemaining = 0 @@ -222,7 +222,8 @@ class RegisterStep2Fragment : Fragment() { binding.btnVerify.isEnabled = true // Show error message - Toast.makeText(requireContext(), "Registration Failed: ${result.exception.message}", Toast.LENGTH_SHORT).show() + Log.e(TAG, "Registration Failed: ${result.exception.message}") + Toast.makeText(requireContext(), "Gagal melakukan regsitrasi", Toast.LENGTH_SHORT).show() } else -> { Log.d(TAG, "Registration: Unknown state") @@ -269,7 +270,7 @@ class RegisterStep2Fragment : Fragment() { // Show error message but continue to Step 3 anyway Log.e(TAG, "Login failed but proceeding to Step 3", result.exception) - Toast.makeText(requireContext(), "Note: Auto-login failed, but registration was successful", Toast.LENGTH_SHORT).show() + Toast.makeText(requireContext(), "Gagal login, namun berhasil membuat akun", Toast.LENGTH_SHORT).show() // Proceed to Step 3 (activity as? RegisterActivity)?.navigateToStep(3, null) diff --git a/app/src/main/java/com/alya/ecommerce_serang/ui/auth/fragments/RegisterStep3Fragment.kt b/app/src/main/java/com/alya/ecommerce_serang/ui/auth/fragments/RegisterStep3Fragment.kt index e73281e..f5757a1 100644 --- a/app/src/main/java/com/alya/ecommerce_serang/ui/auth/fragments/RegisterStep3Fragment.kt +++ b/app/src/main/java/com/alya/ecommerce_serang/ui/auth/fragments/RegisterStep3Fragment.kt @@ -23,7 +23,9 @@ import com.alya.ecommerce_serang.ui.auth.LoginActivity import com.alya.ecommerce_serang.ui.auth.RegisterActivity import com.alya.ecommerce_serang.ui.order.address.CityAdapter import com.alya.ecommerce_serang.ui.order.address.ProvinceAdapter +import com.alya.ecommerce_serang.ui.order.address.SubdsitrictAdapter import com.alya.ecommerce_serang.ui.order.address.ViewState +import com.alya.ecommerce_serang.ui.order.address.VillagesAdapter import com.alya.ecommerce_serang.utils.BaseViewModelFactory import com.alya.ecommerce_serang.utils.SessionManager import com.alya.ecommerce_serang.utils.viewmodel.RegisterViewModel @@ -49,6 +51,8 @@ class RegisterStep3Fragment : Fragment() { // For province and city selection private val provinceAdapter by lazy { ProvinceAdapter(requireContext()) } private val cityAdapter by lazy { CityAdapter(requireContext()) } + private val subdistrictAdapter by lazy { SubdsitrictAdapter(requireContext()) } + private val villagesAdapter by lazy { VillagesAdapter(requireContext()) } companion object { private const val TAG = "RegisterStep3Fragment" @@ -114,7 +118,7 @@ class RegisterStep3Fragment : Fragment() { // Observe address submission state observeAddressSubmissionState() - // Load provinces + // Load provinces from raja ongkir Log.d(TAG, "Requesting provinces data") registerViewModel.getProvinces() setupProvinceObserver() @@ -171,9 +175,10 @@ class RegisterStep3Fragment : Fragment() { } private fun setupAutoComplete() { - // Same implementation as before binding.autoCompleteProvinsi.setAdapter(provinceAdapter) binding.autoCompleteKabupaten.setAdapter(cityAdapter) + binding.autoCompleteKecamatan.setAdapter(subdistrictAdapter) + binding.autoCompleteDesa.setAdapter(villagesAdapter) binding.autoCompleteProvinsi.setOnClickListener { binding.autoCompleteProvinsi.showDropDown() @@ -188,6 +193,24 @@ class RegisterStep3Fragment : Fragment() { } } + binding.autoCompleteKecamatan.setOnClickListener { + if (subdistrictAdapter.count > 0) { + Log.d(TAG, "Subdistrict dropdown clicked, showing ${subdistrictAdapter.count} cities") + binding.autoCompleteKecamatan.showDropDown() + } else { + Toast.makeText(requireContext(), "Pilih kabupaten / kota terlebih dahulu", Toast.LENGTH_SHORT).show() + } + } + + binding.autoCompleteDesa.setOnClickListener { + if (villagesAdapter.count > 0) { + Log.d(TAG, "Village dropdown clicked, showing ${villagesAdapter.count} cities") + binding.autoCompleteDesa.showDropDown() + } else { + Toast.makeText(requireContext(), "Pilih kecamatan terlebih dahulu", Toast.LENGTH_SHORT).show() + } + } + binding.autoCompleteProvinsi.setOnItemClickListener { _, _, position, _ -> val provinceId = provinceAdapter.getProvinceId(position) Log.d(TAG, "Province selected at position $position, ID: $provinceId") @@ -206,13 +229,44 @@ class RegisterStep3Fragment : Fragment() { cityId?.let { id -> Log.d(TAG, "Selected city ID set to: $id") - registerViewModel.selectedCityId = id + registerViewModel.updateSelectedCityId(id) + registerViewModel.getSubdistrict(id) + binding.autoCompleteKecamatan.text.clear() } } + + binding.autoCompleteKecamatan.setOnItemClickListener{ _, _, position, _ -> + val subdistrictId = subdistrictAdapter.getSubdistrictId(position) + Log.d(TAG, "Subdistrict selected at position $position, ID: $subdistrictId") + + subdistrictId?.let { id -> + Log.d(TAG, "Selected subdistrict ID set to: $id") + registerViewModel.selectedSubdistrict = id + registerViewModel.getVillages(id) + binding.autoCompleteDesa.text.clear() + } + } + + binding.autoCompleteDesa.setOnItemClickListener{ _, _, position, _ -> + val villageId = villagesAdapter.getVillageId(position) + val postalCode = villagesAdapter.getPostalCode(position) + Log.d(TAG, "Village selected at position $position, ID: $villageId") + + villageId?.let { id -> + Log.d(TAG, "Selected village ID set to: $id") + registerViewModel.selectedVillages = id + } + + postalCode?.let { postCode -> + registerViewModel.selectedPostalCode = postCode + } + + binding.etKodePos.setText(registerViewModel.selectedPostalCode ?: "") + } } private fun setupProvinceObserver() { - // Same implementation as before + // pake raja ongkir registerViewModel.provincesState.observe(viewLifecycleOwner) { state -> when (state) { is ViewState.Loading -> { @@ -256,8 +310,46 @@ class RegisterStep3Fragment : Fragment() { } } } + registerViewModel.subdistrictState.observe(viewLifecycleOwner) { state -> + when (state) { + is ViewState.Loading -> { + binding.progressBarKecamatan.visibility = View.VISIBLE + } + is ViewState.Success -> { + Log.d(TAG, "Subdistrict: Success - received ${state.data.size} kecamatan") + binding.progressBarKecamatan.visibility = View.GONE + subdistrictAdapter.updateData(state.data) + Log.d(TAG, "Updated subdistrict adapter with ${state.data.size} items") + } + is ViewState.Error -> { + Log.e(TAG, "Subdistrict: Error - ${state.message}") + binding.progressBarKecamatan.visibility = View.GONE + showError("Failed to load kecamatan: ${state.message}") + } + } + } + + registerViewModel.villagesState.observe(viewLifecycleOwner) { state -> + when (state) { + is ViewState.Loading -> { + binding.progressBarDesa.visibility = View.VISIBLE + } + is ViewState.Success -> { + Log.d(TAG, "Village: Success - received ${state.data.size} desa") + binding.progressBarDesa.visibility = View.GONE + villagesAdapter.updateData(state.data) + Log.d(TAG, "Updated village adapter with ${state.data.size} items") + } + is ViewState.Error -> { + Log.e(TAG, "Village: Error - ${state.message}") + binding.progressBarDesa.visibility = View.GONE + showError("Failed to load desa: ${state.message}") + } + } + } } + private fun submitAddress() { Log.d(TAG, "submitAddress called") if (!validateAddressForm()) { @@ -276,13 +368,13 @@ class RegisterStep3Fragment : Fragment() { Log.d(TAG, "Using user ID: $userId") val street = binding.etDetailAlamat.text.toString().trim() - val subDistrict = binding.etKecamatan.text.toString().trim() - val postalCode = binding.etKodePos.text.toString().trim() val recipient = binding.etNamaPenerima.text.toString().trim() val phone = binding.etNomorHp.text.toString().trim() val provinceId = registerViewModel.selectedProvinceId?.toInt() ?: 0 - val cityId = registerViewModel.selectedCityId?.toInt() ?: 0 + val cityId = registerViewModel.selectedCityId.toString() + val subDistrict = registerViewModel.selectedSubdistrict.toString() + val postalCode = registerViewModel.selectedPostalCode.toString() Log.d(TAG, "Address data - Street: $street, SubDistrict: $subDistrict, PostalCode: $postalCode") Log.d(TAG, "Address data - Recipient: $recipient, Phone: $phone") @@ -318,13 +410,13 @@ class RegisterStep3Fragment : Fragment() { private fun validateAddressForm(): Boolean { val street = binding.etDetailAlamat.text.toString().trim() - val subDistrict = binding.etKecamatan.text.toString().trim() - val postalCode = binding.etKodePos.text.toString().trim() val recipient = binding.etNamaPenerima.text.toString().trim() val phone = binding.etNomorHp.text.toString().trim() val provinceId = registerViewModel.selectedProvinceId val cityId = registerViewModel.selectedCityId + val subDistrict = registerViewModel.selectedSubdistrict.toString() + val postalCode = registerViewModel.selectedPostalCode Log.d(TAG, "Validating - Street: $street, SubDistrict: $subDistrict, PostalCode: $postalCode") Log.d(TAG, "Validating - Recipient: $recipient, Phone: $phone") @@ -409,8 +501,4 @@ class RegisterStep3Fragment : Fragment() { ViewCompat.setWindowInsetsAnimationCallback(binding.root, null) _binding = null } -// -// // Data classes for province and city -// data class Province(val id: String, val name: String) -// data class City(val id: String, val name: String) } \ No newline at end of file diff --git a/app/src/main/java/com/alya/ecommerce_serang/ui/home/SearchResultAdapter.kt b/app/src/main/java/com/alya/ecommerce_serang/ui/home/SearchResultAdapter.kt index 89d8e22..6baa2b0 100644 --- a/app/src/main/java/com/alya/ecommerce_serang/ui/home/SearchResultAdapter.kt +++ b/app/src/main/java/com/alya/ecommerce_serang/ui/home/SearchResultAdapter.kt @@ -2,6 +2,7 @@ package com.alya.ecommerce_serang.ui.home import android.util.Log import android.view.LayoutInflater +import android.view.View import android.view.ViewGroup import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.ListAdapter @@ -65,6 +66,16 @@ class SearchResultsAdapter( val storeName = product.storeId?.let { storeMap[it]?.storeName } ?: "Unknown Store" binding.tvStoreName.text = storeName + val ratingStr = product.rating + val ratingValue = ratingStr?.toFloatOrNull() + + if (ratingValue != null && ratingValue > 0f) { + binding.rating.text = String.format("%.1f", ratingValue) + binding.rating.visibility = View.VISIBLE + } else { + binding.rating.text = "Belum ada rating" + binding.rating.setCompoundDrawablesWithIntrinsicBounds(null, null, null, null) + } } } diff --git a/app/src/main/java/com/alya/ecommerce_serang/ui/order/CheckoutViewModel.kt b/app/src/main/java/com/alya/ecommerce_serang/ui/order/CheckoutViewModel.kt index 694fa0f..38a0b28 100644 --- a/app/src/main/java/com/alya/ecommerce_serang/ui/order/CheckoutViewModel.kt +++ b/app/src/main/java/com/alya/ecommerce_serang/ui/order/CheckoutViewModel.kt @@ -64,7 +64,7 @@ class CheckoutViewModel(private val repository: OrderRepository) : ViewModel() { shipPrice = 0, // Will be set when user selects shipping shipName = "", shipService = "", - isNego = false, // Default value + isNego = false, // Default value productId = productId, quantity = quantity, shipEtd = "", diff --git a/app/src/main/java/com/alya/ecommerce_serang/ui/order/address/AddAddressActivity.kt b/app/src/main/java/com/alya/ecommerce_serang/ui/order/address/AddAddressActivity.kt index 9d9c4a3..4c8f0c1 100644 --- a/app/src/main/java/com/alya/ecommerce_serang/ui/order/address/AddAddressActivity.kt +++ b/app/src/main/java/com/alya/ecommerce_serang/ui/order/address/AddAddressActivity.kt @@ -289,7 +289,7 @@ class AddAddressActivity : AppCompatActivity() { val isStoreLocation = false val provinceId = viewModel.selectedProvinceId - val cityId = viewModel.selectedCityId + val cityId = viewModel.selectedCityId.toString() Log.d(TAG, "Form data: street=$street, subDistrict=$subDistrict, postalCode=$postalCode, " + "recipient=$recipient, phone=$phone, userId=$userId, provinceId=$provinceId, cityId=$cityId, " + diff --git a/app/src/main/java/com/alya/ecommerce_serang/ui/order/address/AddAddressViewModel.kt b/app/src/main/java/com/alya/ecommerce_serang/ui/order/address/AddAddressViewModel.kt index 7fcb067..0a0676e 100644 --- a/app/src/main/java/com/alya/ecommerce_serang/ui/order/address/AddAddressViewModel.kt +++ b/app/src/main/java/com/alya/ecommerce_serang/ui/order/address/AddAddressViewModel.kt @@ -36,8 +36,8 @@ class AddAddressViewModel(private val repository: OrderRepository, private val u get() = savedStateHandle.get("selectedProvinceId") set(value) { savedStateHandle["selectedProvinceId"] = value } - var selectedCityId: Int? - get() = savedStateHandle.get("selectedCityId") + var selectedCityId: String? + get() = savedStateHandle.get("selectedCityId") set(value) { savedStateHandle["selectedCityId"] = value } init { @@ -129,7 +129,7 @@ class AddAddressViewModel(private val repository: OrderRepository, private val u selectedProvinceId = id } - fun setSelectedCityId(id: Int) { + fun updateSelectedCityId(id: String) { selectedCityId = id } diff --git a/app/src/main/java/com/alya/ecommerce_serang/ui/order/address/ProvinceAdapter.kt b/app/src/main/java/com/alya/ecommerce_serang/ui/order/address/ProvinceAdapter.kt index 06bbeee..20d5718 100644 --- a/app/src/main/java/com/alya/ecommerce_serang/ui/order/address/ProvinceAdapter.kt +++ b/app/src/main/java/com/alya/ecommerce_serang/ui/order/address/ProvinceAdapter.kt @@ -5,6 +5,8 @@ import android.util.Log import android.widget.ArrayAdapter import com.alya.ecommerce_serang.data.api.response.customer.order.CitiesItem import com.alya.ecommerce_serang.data.api.response.customer.order.ProvincesItem +import com.alya.ecommerce_serang.data.api.response.customer.order.SubdistrictsItem +import com.alya.ecommerce_serang.data.api.response.customer.order.VillagesItem // UI adapters and helpers class ProvinceAdapter( @@ -12,6 +14,86 @@ class ProvinceAdapter( resource: Int = android.R.layout.simple_dropdown_item_1line ) : ArrayAdapter(context, resource, ArrayList()) { +// companion object { +// private const val TAG = "ProvinceAdapter" +// } +// +// // --- Static list of provinces --------------------------------------------------------------- +// private val provinces = listOf( +// ProvincesItem(1, "Aceh"), +// ProvincesItem(2, "Sumatera Utara"), +// ProvincesItem(3, "Sumatera Barat"), +// ProvincesItem(4, "Riau"), +// ProvincesItem(5, "Kepulauan Riau"), +// ProvincesItem(6, "Jambi"), +// ProvincesItem(7, "Sumatera Selatan"), +// ProvincesItem(8, "Kepulauan Bangka Belitung"), +// ProvincesItem(9, "Bengkulu"), +// ProvincesItem(10, "Lampung"), +// ProvincesItem(11, "DKI Jakarta"), +// ProvincesItem(12, "Jawa Barat"), +// ProvincesItem(13, "Banten"), +// ProvincesItem(14, "Jawa Tengah"), +// ProvincesItem(15, "Daerah Istimewa Yogyakarta"), +// ProvincesItem(16, "Jawa Timur"), +// ProvincesItem(17, "Bali"), +// ProvincesItem(18, "Nusa Tenggara Barat"), +// ProvincesItem(19, "Nusa Tenggara Timur"), +// ProvincesItem(20, "Kalimantan Barat"), +// ProvincesItem(21, "Kalimantan Tengah"), +// ProvincesItem(22, "Kalimantan Selatan"), +// ProvincesItem(23, "Kalimantan Timur"), +// ProvincesItem(24, "Kalimantan Utara"), +// ProvincesItem(25, "Sulawesi Utara"), +// ProvincesItem(26, "Gorontalo"), +// ProvincesItem(27, "Sulawesi Tengah"), +// ProvincesItem(28, "Sulawesi Barat"), +// ProvincesItem(29, "Sulawesi Selatan"), +// ProvincesItem(30, "Sulawesi Tenggara"), +// ProvincesItem(31, "Maluku"), +// ProvincesItem(32, "Maluku Utara"), +// ProvincesItem(33, "Papua Barat"), +// ProvincesItem(34, "Papua"), +// ProvincesItem(35, "Papua Tengah"), +// ProvincesItem(36, "Papua Pegunungan"), +// ProvincesItem(37, "Papua Selatan"), +// ProvincesItem(38, "Papua Barat Daya") +// ) +// +// // --- Init block ----------------------------------------------------------------------------- +// init { +// addAll(getProvinceNames()) // pre‑populate adapter +// Log.d(TAG, "Adapter created with ${count} provinces") +// } +// +// // --- Public helper functions ---------------------------------------------------------------- +// fun updateData(newProvinces: List) { +// // If you actually want to replace the list, comment this line +// // provinces = newProvinces // (make `provinces` var instead of val) +// +// clear() +// addAll(newProvinces.map { it.province }) +// notifyDataSetChanged() +// +// Log.d(TAG, "updateData(): updated with ${newProvinces.size} provinces") +// } +// +// fun getProvinceId(position: Int): Int? { +// val id = provinces.getOrNull(position)?.provinceId +// Log.d(TAG, "getProvinceId(): position=$position, id=$id") +// return id +// } +// +// fun getProvinceItem(position: Int): ProvincesItem? { +// val item = provinces.getOrNull(position) +// Log.d(TAG, "getProvinceItem(): position=$position, item=$item") +// return item +// } +// +// // --- Private helpers ------------------------------------------------------------------------ +// private fun getProvinceNames(): List = provinces.map { it.province } + + //call from endpoint private val provinces = ArrayList() fun updateData(newProvinces: List) { @@ -46,7 +128,52 @@ class CityAdapter( notifyDataSetChanged() } - fun getCityId(position: Int): Int? { - return cities.getOrNull(position)?.cityId?.toIntOrNull() + fun getCityId(position: Int): String? { + return cities.getOrNull(position)?.cityId?.toString() + } +} + +class SubdsitrictAdapter( + context: Context, + resource: Int = android.R.layout.simple_dropdown_item_1line +) : ArrayAdapter(context, resource, ArrayList()) { + + private val cities = ArrayList() + + fun updateData(newCities: List) { + cities.clear() + cities.addAll(newCities) + + clear() + addAll(cities.map { it.subdistrictName }) + notifyDataSetChanged() + } + + fun getSubdistrictId(position: Int): String? { + return cities.getOrNull(position)?.subdistrictId?.toString() + } +} + +class VillagesAdapter( + context: Context, + resource: Int = android.R.layout.simple_dropdown_item_1line +) : ArrayAdapter(context, resource, ArrayList()) { + + private val villages = ArrayList() + + fun updateData(newCities: List) { + villages.clear() + villages.addAll(newCities) + + clear() + addAll(villages.map { it.villageName }) + notifyDataSetChanged() + } + + fun getVillageId(position: Int): String? { + return villages.getOrNull(position)?.villageId?.toString() + } + fun getPostalCode(position: Int): String?{ + return villages.getOrNull(position)?.postalCode } } \ No newline at end of file diff --git a/app/src/main/java/com/alya/ecommerce_serang/ui/order/detail/AddEvidencePaymentActivity.kt b/app/src/main/java/com/alya/ecommerce_serang/ui/order/detail/AddEvidencePaymentActivity.kt index 1329a95..24a940a 100644 --- a/app/src/main/java/com/alya/ecommerce_serang/ui/order/detail/AddEvidencePaymentActivity.kt +++ b/app/src/main/java/com/alya/ecommerce_serang/ui/order/detail/AddEvidencePaymentActivity.kt @@ -39,7 +39,6 @@ import okhttp3.MultipartBody import okhttp3.RequestBody.Companion.asRequestBody import okhttp3.RequestBody.Companion.toRequestBody import java.io.File -import java.text.NumberFormat import java.text.SimpleDateFormat import java.util.Calendar import java.util.Locale @@ -63,7 +62,6 @@ class AddEvidencePaymentActivity : AppCompatActivity() { private val paymentMethods = arrayOf( "Transfer Bank", - "E-Wallet", "QRIS", ) @@ -129,7 +127,7 @@ class AddEvidencePaymentActivity : AppCompatActivity() { } private fun setupUI() { - val paymentMethods = listOf("Transfer Bank", "COD", "QRIS") + val paymentMethods = listOf("Transfer Bank", "QRIS") val adapter = SpinnerCardAdapter(this, paymentMethods) binding.spinnerPaymentMethod.adapter = adapter } @@ -320,11 +318,12 @@ class AddEvidencePaymentActivity : AppCompatActivity() { Toast.makeText(this, "Silahkan pilih metode pembayaran", Toast.LENGTH_SHORT).show() return } + binding.etAccountNumber.visibility = View.GONE - if (binding.etAccountNumber.text.toString().trim().isEmpty()) { - Toast.makeText(this, "Silahkan isi nomor rekening/HP", Toast.LENGTH_SHORT).show() - return - } +// if (binding.etAccountNumber.text.toString().trim().isEmpty()) { +// Toast.makeText(this, "Silahkan isi nomor rekening/HP", Toast.LENGTH_SHORT).show() +// return +// } if (binding.tvPaymentDate.text.toString() == "Pilih tanggal") { Toast.makeText(this, "Silahkan pilih tanggal pembayaran", Toast.LENGTH_SHORT).show() diff --git a/app/src/main/java/com/alya/ecommerce_serang/ui/order/history/OrderHistoryAdapter.kt b/app/src/main/java/com/alya/ecommerce_serang/ui/order/history/OrderHistoryAdapter.kt index f395ec2..905fd70 100644 --- a/app/src/main/java/com/alya/ecommerce_serang/ui/order/history/OrderHistoryAdapter.kt +++ b/app/src/main/java/com/alya/ecommerce_serang/ui/order/history/OrderHistoryAdapter.kt @@ -213,14 +213,15 @@ 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()) - viewModel.refreshOrders() - } - } + // gabisa complaint +// btnLeft.apply { +// visibility = View.VISIBLE +// text = itemView.context.getString(R.string.canceled_order_btn) +// setOnClickListener { +// showCancelOrderDialog(order.orderId.toString()) +// viewModel.refreshOrders() +// } +// } } "shipped" -> { // Untuk status shipped, tampilkan "Lacak Pengiriman" dan "Terima Barang" @@ -268,13 +269,21 @@ class OrderHistoryAdapter( text = itemView.context.getString(R.string.dl_shipped) } btnRight.apply { - visibility = View.VISIBLE - text = itemView.context.getString(R.string.add_review) - setOnClickListener { - addReviewProduct(order) - viewModel.refreshOrders() - // Handle click event + val checkReview = order.orderItems[0].reviewId + if (checkReview > 0){ + visibility = View.VISIBLE + text = itemView.context.getString(R.string.add_review) + setOnClickListener { + + addReviewProduct(order) +// viewModel.refreshOrders() + // Handle click event + } + } else { + visibility = View.GONE } + + } deadlineDate.apply { visibility = View.VISIBLE @@ -518,7 +527,7 @@ class OrderHistoryAdapter( } } - // Create and show the bottom sheet using the obtained FragmentManager + // cancel sebelum bayar val bottomSheet = CancelOrderBottomSheet( orderId = orderId, onOrderCancelled = { @@ -531,6 +540,7 @@ class OrderHistoryAdapter( bottomSheet.show(fragmentActivity.supportFragmentManager, CancelOrderBottomSheet.TAG) } + // tambah review / ulasan private fun addReviewProduct(order: OrdersItem) { // Use ViewModel to fetch order details viewModel.getOrderDetails(order.orderId) @@ -550,7 +560,7 @@ class OrderHistoryAdapter( } } - // Observe the order details result + // Observe order items viewModel.orderItems.observe(itemView.findViewTreeLifecycleOwner()!!) { orderItems -> if (orderItems != null && orderItems.isNotEmpty()) { // For single item review diff --git a/app/src/main/java/com/alya/ecommerce_serang/ui/order/history/cancelorder/CancelOrderBottomSheet.kt b/app/src/main/java/com/alya/ecommerce_serang/ui/order/history/cancelorder/CancelOrderBottomSheet.kt index 99f25de..8fd0376 100644 --- a/app/src/main/java/com/alya/ecommerce_serang/ui/order/history/cancelorder/CancelOrderBottomSheet.kt +++ b/app/src/main/java/com/alya/ecommerce_serang/ui/order/history/cancelorder/CancelOrderBottomSheet.kt @@ -55,7 +55,7 @@ class CancelOrderBottomSheet( val btnConfirm = view.findViewById