mirror of
https://github.com/shaulascr/ecommerce_serang.git
synced 2025-08-16 19:57:25 +00:00
update icon, chat, balance, and count order
This commit is contained in:
@ -5,6 +5,7 @@ import com.alya.ecommerce_serang.data.api.dto.Store
|
||||
import com.alya.ecommerce_serang.data.api.response.auth.ListStoreTypeResponse
|
||||
import com.alya.ecommerce_serang.data.api.response.customer.product.StoreResponse
|
||||
import com.alya.ecommerce_serang.data.api.response.store.profile.StoreDataResponse
|
||||
import com.alya.ecommerce_serang.data.api.response.store.sells.OrderListResponse
|
||||
import com.alya.ecommerce_serang.data.api.retrofit.ApiService
|
||||
import okhttp3.MultipartBody
|
||||
import okhttp3.RequestBody
|
||||
@ -71,4 +72,90 @@ class MyStoreRepository(private val apiService: ApiService) {
|
||||
street, subdistrict, detail, postalCode, latitude, longitude, userPhone, storeType, storeimg
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun getSellList(status: String): Result<OrderListResponse> {
|
||||
return try {
|
||||
Log.d("SellsRepository", "Add Evidence : $status")
|
||||
val response = apiService.getSellList(status)
|
||||
|
||||
if (response.isSuccessful) {
|
||||
val allListSell = response.body()
|
||||
if (allListSell != null) {
|
||||
Log.d("SellsRepository", "Add Evidence successfully: ${allListSell.message}")
|
||||
Result.Success(allListSell)
|
||||
} 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 Add Evidence : $errorBody")
|
||||
Result.Error(Exception(errorBody))
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e("SellsRepository", "Exception Add Evidence ", e)
|
||||
Result.Error(e)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun getBalance(): Result<com.alya.ecommerce_serang.data.api.response.store.StoreResponse> {
|
||||
return try {
|
||||
val response = apiService.getMyStoreData()
|
||||
|
||||
if (response.isSuccessful) {
|
||||
val body = response.body()
|
||||
?: return Result.Error(IllegalStateException("Response body is null"))
|
||||
|
||||
// Validate the balance field
|
||||
val balanceRaw = body.store.balance
|
||||
balanceRaw.toDoubleOrNull()
|
||||
?: return Result.Error(NumberFormatException("Invalid balance format: $balanceRaw"))
|
||||
|
||||
Result.Success(body)
|
||||
} else {
|
||||
Result.Error(
|
||||
Exception("Failed to load balance: ${response.code()} ${response.message()}")
|
||||
)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e("MyStoreRepository", "Error fetching balance", e)
|
||||
Result.Error(e)
|
||||
}
|
||||
}
|
||||
|
||||
// private fun fetchBalance() {
|
||||
// showLoading(true)
|
||||
// lifecycleScope.launch {
|
||||
// try {
|
||||
// val response = ApiConfig.getApiService(sessionManager).getMyStoreData()
|
||||
// if (response.isSuccessful && response.body() != null) {
|
||||
// val storeData = response.body()!!
|
||||
// val balance = storeData.store.balance
|
||||
//
|
||||
// // Format the balance
|
||||
// try {
|
||||
// val balanceValue = balance.toDouble()
|
||||
// binding.tvBalance.text = String.format("Rp%,.0f", balanceValue)
|
||||
// } catch (e: Exception) {
|
||||
// binding.tvBalance.text = "Rp$balance"
|
||||
// }
|
||||
// } else {
|
||||
// Toast.makeText(
|
||||
// this@BalanceActivity,
|
||||
// "Gagal memuat data saldo: ${response.message()}",
|
||||
// Toast.LENGTH_SHORT
|
||||
// ).show()
|
||||
// }
|
||||
// } catch (e: Exception) {
|
||||
// Log.e(TAG, "Error fetching balance", e)
|
||||
// Toast.makeText(
|
||||
// this@BalanceActivity,
|
||||
// "Error: ${e.message}",
|
||||
// Toast.LENGTH_SHORT
|
||||
// ).show()
|
||||
// } finally {
|
||||
// showLoading(false)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
@ -63,6 +63,8 @@ class ChatActivity : AppCompatActivity() {
|
||||
// For image attachment
|
||||
private var tempImageUri: Uri? = null
|
||||
|
||||
private var imageAttach = false
|
||||
|
||||
// Typing indicator handler
|
||||
private val typingHandler = android.os.Handler(android.os.Looper.getMainLooper())
|
||||
private val stopTypingRunnable = Runnable {
|
||||
@ -269,6 +271,7 @@ class ChatActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
// Options button
|
||||
binding.btnOptions.visibility = View.GONE
|
||||
binding.btnOptions.setOnClickListener {
|
||||
showOptionsMenu()
|
||||
}
|
||||
@ -281,6 +284,7 @@ class ChatActivity : AppCompatActivity() {
|
||||
// This will automatically handle product attachment if enabled
|
||||
viewModel.sendMessage(message)
|
||||
binding.editTextMessage.text.clear()
|
||||
binding.layoutAttachImage.visibility = View.GONE
|
||||
|
||||
// Instantly scroll to show new message
|
||||
binding.recyclerChat.postDelayed({
|
||||
@ -291,24 +295,33 @@ class ChatActivity : AppCompatActivity() {
|
||||
|
||||
// Attachment button
|
||||
binding.btnAttachment.setOnClickListener {
|
||||
this.currentFocus?.let { view ->
|
||||
val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as? InputMethodManager
|
||||
imm?.hideSoftInputFromWindow(view.windowToken, 0)
|
||||
}
|
||||
checkPermissionsAndShowImagePicker()
|
||||
}
|
||||
|
||||
binding.btnCloseChat.setOnClickListener{
|
||||
binding.layoutAttachImage.visibility = View.GONE
|
||||
imageAttach = false
|
||||
viewModel.clearSelectedImage()
|
||||
}
|
||||
|
||||
// Product card click to enable/disable product attachment
|
||||
binding.productContainer.setOnClickListener {
|
||||
toggleProductAttachment()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun toggleProductAttachment() {
|
||||
val currentState = viewModel.state.value
|
||||
if (currentState?.hasProductAttachment == true) {
|
||||
// Disable product attachment
|
||||
viewModel.disableProductAttachment()
|
||||
updateProductAttachmentUI(false)
|
||||
Toast.makeText(this, "Product attachment disabled", Toast.LENGTH_SHORT).show()
|
||||
} else {
|
||||
// Enable product attachment
|
||||
viewModel.enableProductAttachment()
|
||||
updateProductAttachmentUI(true)
|
||||
Toast.makeText(this, "Product will be attached to your next message", Toast.LENGTH_SHORT).show()
|
||||
@ -405,7 +418,7 @@ class ChatActivity : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
// Update product info
|
||||
// layout attach product
|
||||
if (!state.productName.isNullOrEmpty()) {
|
||||
binding.tvProductName.text = state.productName
|
||||
binding.tvProductPrice.text = state.productPrice
|
||||
@ -440,15 +453,11 @@ class ChatActivity : AppCompatActivity() {
|
||||
|
||||
// Update attachment hint
|
||||
if (state.hasAttachment) {
|
||||
binding.editTextMessage.hint = getString(R.string.image_attached)
|
||||
binding.layoutAttachImage.visibility = View.VISIBLE
|
||||
} else {
|
||||
binding.editTextMessage.hint = getString(R.string.write_message)
|
||||
}
|
||||
|
||||
// Show typing indicator
|
||||
binding.tvTypingIndicator.visibility =
|
||||
if (state.isOtherUserTyping) View.VISIBLE else View.GONE
|
||||
|
||||
// Show error if any
|
||||
state.error?.let { error ->
|
||||
Toast.makeText(this@ChatActivity, error, Toast.LENGTH_SHORT).show()
|
||||
@ -459,7 +468,7 @@ class ChatActivity : AppCompatActivity() {
|
||||
|
||||
private fun updateInputHint(state: ChatUiState) {
|
||||
binding.editTextMessage.hint = when {
|
||||
state.hasAttachment -> getString(R.string.image_attached)
|
||||
state.hasAttachment -> getString(R.string.write_message)
|
||||
state.hasProductAttachment -> "Type your message (product will be attached)"
|
||||
else -> getString(R.string.write_message)
|
||||
}
|
||||
@ -504,6 +513,7 @@ class ChatActivity : AppCompatActivity() {
|
||||
getString(R.string.cancel)
|
||||
)
|
||||
|
||||
|
||||
AlertDialog.Builder(this)
|
||||
.setTitle(getString(R.string.options))
|
||||
.setItems(options) { dialog, which ->
|
||||
@ -578,7 +588,21 @@ class ChatActivity : AppCompatActivity() {
|
||||
|
||||
private fun handleSelectedImage(uri: Uri) {
|
||||
try {
|
||||
Log.d(TAG, "Processing selected image: $uri")
|
||||
Log.d(TAG, "Processing selected image: ${uri.toString()}")
|
||||
imageAttach = true
|
||||
binding.layoutAttachImage.visibility = View.VISIBLE
|
||||
val fullImageUrl = when (val img = uri.toString()) {
|
||||
is String -> {
|
||||
if (img.startsWith("/")) BASE_URL + img.substring(1) else img
|
||||
}
|
||||
else -> R.drawable.placeholder_image
|
||||
}
|
||||
|
||||
Glide.with(this)
|
||||
.load(fullImageUrl)
|
||||
.placeholder(R.drawable.placeholder_image)
|
||||
.into(binding.ivAttach)
|
||||
Log.d(TAG, "Display attach image: $uri")
|
||||
|
||||
// Always use the copy-to-cache approach for reliability
|
||||
contentResolver.openInputStream(uri)?.use { inputStream ->
|
||||
@ -598,6 +622,7 @@ class ChatActivity : AppCompatActivity() {
|
||||
|
||||
Log.d(TAG, "Image processed successfully: ${outputFile.absolutePath}, size: ${outputFile.length()}")
|
||||
viewModel.setSelectedImageFile(outputFile)
|
||||
|
||||
Toast.makeText(this, "Image selected", Toast.LENGTH_SHORT).show()
|
||||
} else {
|
||||
Log.e(TAG, "Failed to create image file")
|
||||
@ -681,25 +706,4 @@ class ChatActivity : AppCompatActivity() {
|
||||
context.startActivity(intent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//if implement typing status
|
||||
// private fun handleConnectionState(state: ConnectionState) {
|
||||
// when (state) {
|
||||
// is ConnectionState.Connected -> {
|
||||
// binding.tvConnectionStatus.visibility = View.GONE
|
||||
// }
|
||||
// is ConnectionState.Connecting -> {
|
||||
// binding.tvConnectionStatus.visibility = View.VISIBLE
|
||||
// binding.tvConnectionStatus.text = getString(R.string.connecting)
|
||||
// }
|
||||
// is ConnectionState.Disconnected -> {
|
||||
// binding.tvConnectionStatus.visibility = View.VISIBLE
|
||||
// binding.tvConnectionStatus.text = getString(R.string.disconnected_reconnecting)
|
||||
// }
|
||||
// is ConnectionState.Error -> {
|
||||
// binding.tvConnectionStatus.visibility = View.VISIBLE
|
||||
// binding.tvConnectionStatus.text = getString(R.string.connection_error, state.message)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
@ -23,6 +23,28 @@ import java.util.Locale
|
||||
import java.util.TimeZone
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* ChatViewModel - Manages chat functionality for both buyers and store owners
|
||||
*
|
||||
* ARCHITECTURE OVERVIEW:
|
||||
* - Handles real-time messaging via Socket.IO
|
||||
* - Manages chat state using LiveData/MutableLiveData pattern
|
||||
* - Supports multiple message types: TEXT, IMAGE, PRODUCT
|
||||
* - Maintains separate flows for buyer and store owner chat
|
||||
*
|
||||
* KEY RESPONSIBILITIES:
|
||||
* 1. Socket connection management and real-time message handling
|
||||
* 2. Message sending/receiving with different attachment types
|
||||
* 3. Chat history loading and message status updates
|
||||
* 4. Product attachment functionality for commerce integration
|
||||
* 5. User session management and authentication
|
||||
*
|
||||
* STATE MANAGEMENT PATTERN:
|
||||
* - All UI state updates go through updateState() helper function
|
||||
* - State updates are atomic and follow immutable pattern
|
||||
* - Error states are cleared explicitly via clearError()
|
||||
*/
|
||||
|
||||
@HiltViewModel
|
||||
class ChatViewModel @Inject constructor(
|
||||
private val chatRepository: ChatRepository,
|
||||
@ -730,6 +752,19 @@ class ChatViewModel @Inject constructor(
|
||||
Log.d(TAG, "Image attachment ${if (file != null) "selected: ${file.name}" else "cleared"}")
|
||||
}
|
||||
|
||||
fun clearSelectedImage() {
|
||||
Log.d(TAG, "Clearing selected image attachment")
|
||||
|
||||
selectedImageFile?.let { file ->
|
||||
Log.d(TAG, "Clearing image file: ${file.name}")
|
||||
}
|
||||
|
||||
selectedImageFile = null
|
||||
updateState { it.copy(hasAttachment = false) }
|
||||
|
||||
Log.d(TAG, "Image attachment cleared successfully")
|
||||
}
|
||||
|
||||
// convert form chatLine api to UI chat messages
|
||||
private fun convertChatLineToUiMessage(chatLine: ChatLine): ChatUiMessage {
|
||||
val formattedTime = formatTimestamp(chatLine.createdAt)
|
||||
|
@ -7,12 +7,14 @@ import android.widget.Toast
|
||||
import androidx.activity.enableEdgeToEdge
|
||||
import androidx.activity.viewModels
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.alya.ecommerce_serang.BuildConfig.BASE_URL
|
||||
import com.alya.ecommerce_serang.R
|
||||
import com.alya.ecommerce_serang.data.api.dto.Store
|
||||
import com.alya.ecommerce_serang.data.api.retrofit.ApiConfig
|
||||
import com.alya.ecommerce_serang.data.api.retrofit.ApiService
|
||||
import com.alya.ecommerce_serang.data.repository.MyStoreRepository
|
||||
import com.alya.ecommerce_serang.data.repository.Result
|
||||
import com.alya.ecommerce_serang.databinding.ActivityMyStoreBinding
|
||||
import com.alya.ecommerce_serang.ui.profile.mystore.balance.BalanceActivity
|
||||
import com.alya.ecommerce_serang.ui.profile.mystore.chat.ChatListStoreActivity
|
||||
@ -24,6 +26,7 @@ import com.alya.ecommerce_serang.utils.BaseViewModelFactory
|
||||
import com.alya.ecommerce_serang.utils.SessionManager
|
||||
import com.alya.ecommerce_serang.utils.viewmodel.MyStoreViewModel
|
||||
import com.bumptech.glide.Glide
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class MyStoreActivity : AppCompatActivity() {
|
||||
private lateinit var binding: ActivityMyStoreBinding
|
||||
@ -66,6 +69,9 @@ class MyStoreActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
setUpClickListeners()
|
||||
getCountOrder()
|
||||
viewModel.fetchBalance()
|
||||
fetchBalance()
|
||||
}
|
||||
|
||||
private fun myStoreProfileOverview(store: Store){
|
||||
@ -147,6 +153,46 @@ class MyStoreActivity : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun getCountOrder(){
|
||||
lifecycleScope.launch {
|
||||
try {
|
||||
val allCounts = viewModel.getAllStatusCounts()
|
||||
val totalUnpaid = allCounts["unpaid"]
|
||||
val totalPaid = allCounts["paid"]
|
||||
val totalProcessed = allCounts["processed"]
|
||||
Log.d("MyStoreActivity",
|
||||
"Total orders: unpaid=$totalUnpaid, processed=$totalProcessed, paid=$totalPaid")
|
||||
|
||||
binding.tvNumPesananMasuk.text = totalUnpaid.toString()
|
||||
binding.tvNumPembayaran.text = totalPaid.toString()
|
||||
binding.tvNumPerluDikirim.text = totalProcessed.toString()
|
||||
} catch (e:Exception){
|
||||
Log.e("MyStoreActivity", "Error getting order counts: ${e.message}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun fetchBalance(){
|
||||
viewModel.balanceResult.observe(this){result ->
|
||||
when (result) {
|
||||
is com.alya.ecommerce_serang.data.repository.Result.Loading ->
|
||||
null
|
||||
// binding.progressBar.isVisible = true
|
||||
is com.alya.ecommerce_serang.data.repository.Result.Success ->
|
||||
viewModel.formattedBalance.observe(this) {
|
||||
binding.tvBalance.text = it
|
||||
}
|
||||
is Result.Error -> {
|
||||
// binding.progressBar.isVisible = false
|
||||
Log.e(
|
||||
"MyStoreActivity",
|
||||
"Gagal memuat saldo: ${result.exception.localizedMessage}"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val PROFILE_REQUEST_CODE = 100
|
||||
}
|
||||
|
@ -408,6 +408,10 @@ class BalanceActivity : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun navigateTotalBalance(){
|
||||
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val TOP_UP_REQUEST_CODE = 101
|
||||
}
|
||||
|
@ -426,8 +426,8 @@ class ChatStoreActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
// Show typing indicator
|
||||
binding.tvTypingIndicator.visibility =
|
||||
if (state.isOtherUserTyping) View.VISIBLE else View.GONE
|
||||
// binding.tvTypingIndicator.visibility =
|
||||
// if (state.isOtherUserTyping) View.VISIBLE else View.GONE
|
||||
|
||||
// Show error if any
|
||||
state.error?.let { error ->
|
||||
@ -520,6 +520,19 @@ class ChatStoreActivity : AppCompatActivity() {
|
||||
private fun handleSelectedImage(uri: Uri) {
|
||||
try {
|
||||
Log.d(TAG, "Processing selected image: $uri")
|
||||
binding.layoutAttachImage.visibility = View.VISIBLE
|
||||
val fullImageUrl = when (val img = uri.toString()) {
|
||||
is String -> {
|
||||
if (img.startsWith("/")) BASE_URL + img.substring(1) else img
|
||||
}
|
||||
else -> R.drawable.placeholder_image
|
||||
}
|
||||
|
||||
Glide.with(this)
|
||||
.load(fullImageUrl)
|
||||
.placeholder(R.drawable.placeholder_image)
|
||||
.into(binding.ivAttach)
|
||||
Log.d(TAG, "Display attach image: $uri")
|
||||
|
||||
// Always use the copy-to-cache approach for reliability
|
||||
contentResolver.openInputStream(uri)?.use { inputStream ->
|
||||
|
@ -9,6 +9,7 @@ import android.view.ViewGroup
|
||||
import android.widget.Toast
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.alya.ecommerce_serang.data.api.response.store.sells.OrdersItem
|
||||
import com.alya.ecommerce_serang.data.api.retrofit.ApiConfig
|
||||
@ -16,12 +17,14 @@ import com.alya.ecommerce_serang.data.repository.Result
|
||||
import com.alya.ecommerce_serang.data.repository.SellsRepository
|
||||
import com.alya.ecommerce_serang.databinding.FragmentSellsListBinding
|
||||
import com.alya.ecommerce_serang.ui.order.address.ViewState
|
||||
import com.alya.ecommerce_serang.ui.profile.mystore.MyStoreActivity
|
||||
import com.alya.ecommerce_serang.ui.profile.mystore.sells.payment.DetailPaymentActivity
|
||||
import com.alya.ecommerce_serang.ui.profile.mystore.sells.shipment.DetailShipmentActivity
|
||||
import com.alya.ecommerce_serang.utils.BaseViewModelFactory
|
||||
import com.alya.ecommerce_serang.utils.SessionManager
|
||||
import com.alya.ecommerce_serang.utils.viewmodel.SellsViewModel
|
||||
import com.google.gson.Gson
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class SellsListFragment : Fragment() {
|
||||
|
||||
@ -84,6 +87,7 @@ class SellsListFragment : Fragment() {
|
||||
observeSellsList()
|
||||
observePaymentConfirmation()
|
||||
loadSells()
|
||||
// getAllOrderCountsAndNavigate()
|
||||
}
|
||||
|
||||
private fun setupRecyclerView() {
|
||||
@ -183,6 +187,30 @@ class SellsListFragment : Fragment() {
|
||||
context.startActivity(intent)
|
||||
}
|
||||
|
||||
private fun getAllOrderCountsAndNavigate() {
|
||||
lifecycleScope.launch {
|
||||
try {
|
||||
// Show loading if needed
|
||||
binding.progressBar.visibility = View.VISIBLE
|
||||
|
||||
val allCounts = viewModel.getAllStatusCounts()
|
||||
|
||||
binding.progressBar.visibility = View.GONE
|
||||
|
||||
val intent = Intent(requireContext(), MyStoreActivity::class.java)
|
||||
intent.putExtra("total_unpaid", allCounts["unpaid"])
|
||||
intent.putExtra("total_paid", allCounts["paid"])
|
||||
intent.putExtra("total_processed", allCounts["processed"])
|
||||
Log.d("SellsListFragment", "Total orders: unpaid=${allCounts["unpaid"]}, processed=${allCounts["processed"]}, Paid=${allCounts["paid"]}")
|
||||
|
||||
|
||||
} catch (e: Exception) {
|
||||
binding.progressBar.visibility = View.GONE
|
||||
Log.e(TAG, "Error getting order counts: ${e.message}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
_binding = null
|
||||
|
@ -1,11 +1,14 @@
|
||||
package com.alya.ecommerce_serang.utils.viewmodel
|
||||
|
||||
import android.util.Log
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.map
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.alya.ecommerce_serang.data.api.dto.Store
|
||||
import com.alya.ecommerce_serang.data.api.response.auth.StoreTypesItem
|
||||
import com.alya.ecommerce_serang.data.api.response.store.StoreResponse
|
||||
import com.alya.ecommerce_serang.data.api.response.store.profile.StoreDataResponse
|
||||
import com.alya.ecommerce_serang.data.repository.MyStoreRepository
|
||||
import com.alya.ecommerce_serang.data.repository.Result
|
||||
@ -13,6 +16,8 @@ import kotlinx.coroutines.launch
|
||||
import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
||||
import okhttp3.MultipartBody
|
||||
import okhttp3.RequestBody
|
||||
import java.text.NumberFormat
|
||||
import java.util.Locale
|
||||
|
||||
class MyStoreViewModel(private val repository: MyStoreRepository): ViewModel() {
|
||||
private val _myStoreProfile = MutableLiveData<Store?>()
|
||||
@ -30,6 +35,9 @@ class MyStoreViewModel(private val repository: MyStoreRepository): ViewModel() {
|
||||
private val _errorMessage = MutableLiveData<String>()
|
||||
val errorMessage : LiveData<String> = _errorMessage
|
||||
|
||||
private val _balanceResult = MutableLiveData<Result<StoreResponse>>()
|
||||
val balanceResult: LiveData<Result<StoreResponse>> get() = _balanceResult
|
||||
|
||||
fun loadMyStore(){
|
||||
viewModelScope.launch {
|
||||
when (val result = repository.fetchMyStoreProfile()){
|
||||
@ -100,6 +108,56 @@ class MyStoreViewModel(private val repository: MyStoreRepository): ViewModel() {
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun getTotalOrdersByStatus(status: String): Int {
|
||||
return try {
|
||||
when (val result = repository.getSellList(status)) {
|
||||
is Result.Success -> {
|
||||
// Access the orders list from the response
|
||||
result.data.orders.size ?: 0
|
||||
}
|
||||
is Result.Error -> {
|
||||
Log.e("SellsViewModel", "Error getting orders count: ${result.exception.message}")
|
||||
0
|
||||
}
|
||||
is Result.Loading -> 0
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e("SellsViewModel", "Exception getting orders count", e)
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
//count the order
|
||||
suspend fun getAllStatusCounts(): Map<String, Int> {
|
||||
val statuses = listOf( "unpaid", "paid", "processed")
|
||||
val counts = mutableMapOf<String, Int>()
|
||||
|
||||
statuses.forEach { status ->
|
||||
counts[status] = getTotalOrdersByStatus(status)
|
||||
Log.d("SellsViewModel", "Status: $status, countOrder=${counts[status]}")
|
||||
}
|
||||
|
||||
return counts
|
||||
}
|
||||
|
||||
val formattedBalance: LiveData<String> = balanceResult.map { result ->
|
||||
when (result) {
|
||||
is Result.Success -> {
|
||||
val raw = result.data.store.balance.toDouble()
|
||||
NumberFormat.getCurrencyInstance(Locale("in", "ID")).format(raw)
|
||||
}
|
||||
else -> ""
|
||||
}
|
||||
}
|
||||
|
||||
/** Trigger the network call */
|
||||
fun fetchBalance() {
|
||||
viewModelScope.launch {
|
||||
_balanceResult.value = Result.Loading
|
||||
_balanceResult.value = repository.getBalance()
|
||||
}
|
||||
}
|
||||
|
||||
private fun String.toRequestBody(): RequestBody =
|
||||
RequestBody.create("text/plain".toMediaTypeOrNull(), this)
|
||||
}
|
@ -146,6 +146,38 @@ class SellsViewModel(private val repository: SellsRepository) : ViewModel() {
|
||||
|
||||
Log.d(TAG, "========== getSellList method completed ==========")
|
||||
}
|
||||
//get total order each status
|
||||
suspend fun getTotalOrdersByStatus(status: String): Int {
|
||||
return try {
|
||||
when (val result = repository.getSellList(status)) {
|
||||
is Result.Success -> {
|
||||
// Access the orders list from the response
|
||||
result.data.orders.size ?: 0
|
||||
}
|
||||
is Result.Error -> {
|
||||
Log.e("SellsViewModel", "Error getting orders count: ${result.exception.message}")
|
||||
0
|
||||
}
|
||||
is Result.Loading -> 0
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e("SellsViewModel", "Exception getting orders count", e)
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
//count the order
|
||||
suspend fun getAllStatusCounts(): Map<String, Int> {
|
||||
val statuses = listOf( "unpaid", "paid", "processed")
|
||||
val counts = mutableMapOf<String, Int>()
|
||||
|
||||
statuses.forEach { status ->
|
||||
counts[status] = getTotalOrdersByStatus(status)
|
||||
Log.d("SellsViewModel", "Status: $status, countOrder=${counts[status]}")
|
||||
}
|
||||
|
||||
return counts
|
||||
}
|
||||
|
||||
fun getSellDetails(orderId: Int) {
|
||||
Log.d(TAG, "========== Starting getSellDetails ==========")
|
||||
|
Reference in New Issue
Block a user