diff --git a/core/designsystem/src/main/java/com/mifos/core/designsystem/component/MifosEditTextField.kt b/core/designsystem/src/main/java/com/mifos/core/designsystem/component/MifosEditTextField.kt index 69e2d4ce230..d4d616fba20 100644 --- a/core/designsystem/src/main/java/com/mifos/core/designsystem/component/MifosEditTextField.kt +++ b/core/designsystem/src/main/java/com/mifos/core/designsystem/component/MifosEditTextField.kt @@ -207,13 +207,15 @@ fun MifosOutlinedTextField( value: String, onValueChange: (String) -> Unit, maxLines: Int = 1, + readOnly : Boolean = false, singleLine: Boolean = true, icon: ImageVector? = null, label: String, visualTransformation: VisualTransformation = VisualTransformation.None, trailingIcon: @Composable (() -> Unit)? = null, keyboardType: KeyboardType = KeyboardType.Text, - error: Int? + error: Int?, + enabled: Boolean = true ) { OutlinedTextField( @@ -221,6 +223,8 @@ fun MifosOutlinedTextField( onValueChange = onValueChange, label = { Text(label) }, modifier = modifier, + readOnly = readOnly, + enabled = enabled, leadingIcon = if (icon != null) { { Icon( diff --git a/core/designsystem/src/main/java/com/mifos/core/designsystem/component/MifosSweetError.kt b/core/designsystem/src/main/java/com/mifos/core/designsystem/component/MifosSweetError.kt index 77e826ff372..7331444852b 100644 --- a/core/designsystem/src/main/java/com/mifos/core/designsystem/component/MifosSweetError.kt +++ b/core/designsystem/src/main/java/com/mifos/core/designsystem/component/MifosSweetError.kt @@ -39,6 +39,7 @@ import com.mifos.core.designsystem.theme.DarkGray fun MifosSweetError( message: String, isRetryEnabled : Boolean = true, + buttonText : String = stringResource(id = R.string.core_designsystem_try_again), onclick: () -> Unit ) { Column( @@ -87,7 +88,7 @@ fun MifosSweetError( ) { Text( modifier = Modifier.padding(start = 20.dp, end = 20.dp), - text = stringResource(id = R.string.core_designsystem_try_again), + text = buttonText, fontSize = 15.sp ) } diff --git a/core/designsystem/src/main/java/com/mifos/core/designsystem/component/MifosTextFieldDropdown.kt b/core/designsystem/src/main/java/com/mifos/core/designsystem/component/MifosTextFieldDropdown.kt index 80cb75f0788..d9137341c48 100644 --- a/core/designsystem/src/main/java/com/mifos/core/designsystem/component/MifosTextFieldDropdown.kt +++ b/core/designsystem/src/main/java/com/mifos/core/designsystem/component/MifosTextFieldDropdown.kt @@ -54,7 +54,8 @@ fun MifosTextFieldDropdown( maxLines = 1, colors = OutlinedTextFieldDefaults.colors( focusedBorderColor = if (isSystemInDarkTheme()) BluePrimaryDark else BluePrimary, - ), + focusedLabelColor = if (isSystemInDarkTheme()) BluePrimaryDark else BluePrimary, + ), textStyle = LocalDensity.current.run { TextStyle(fontSize = 18.sp) }, diff --git a/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/savingsaccount/SavingAccountUiState.kt b/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/savingsaccount/SavingAccountUiState.kt index 8cbfcf6d2cd..7102b734e92 100644 --- a/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/savingsaccount/SavingAccountUiState.kt +++ b/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/savingsaccount/SavingAccountUiState.kt @@ -3,6 +3,7 @@ package com.mifos.mifosxdroid.online.savingsaccount import com.mifos.core.objects.client.Savings import com.mifos.core.objects.organisation.ProductSavings import com.mifos.core.objects.templates.savings.SavingProductsTemplate +import com.mifos.core.objects.zipmodels.SavingProductsAndTemplate /** * Created by Aditya Gupta on 08/08/23. @@ -13,10 +14,7 @@ sealed class SavingAccountUiState { data class ShowFetchingError(val message: Int) : SavingAccountUiState() - data class ShowSavingsAccounts(val getProductSaving: List?) : - SavingAccountUiState() - - data class ShowSavingsAccountTemplateByProduct(val savingProductsTemplate: SavingProductsTemplate) : + data class LoadAllSavings(val savingsTemplate: SavingProductsAndTemplate) : SavingAccountUiState() data class ShowSavingsAccountCreatedSuccessfully(val savings: Savings?) : SavingAccountUiState() diff --git a/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/savingsaccount/SavingAccountViewModel.kt b/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/savingsaccount/SavingAccountViewModel.kt index 275dad6237f..75a64e351d2 100644 --- a/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/savingsaccount/SavingAccountViewModel.kt +++ b/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/savingsaccount/SavingAccountViewModel.kt @@ -1,8 +1,8 @@ package com.mifos.mifosxdroid.online.savingsaccount -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData +import android.util.Log import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope import com.mifos.core.data.SavingsPayload import com.mifos.core.objects.accounts.savings.FieldOfficerOptions import com.mifos.core.objects.client.Savings @@ -12,6 +12,11 @@ import com.mifos.core.objects.templates.savings.SavingProductsTemplate import com.mifos.core.objects.zipmodels.SavingProductsAndTemplate import com.mifos.mifosxdroid.R import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.launch import rx.Observable import rx.Subscriber import rx.android.schedulers.AndroidSchedulers @@ -25,10 +30,23 @@ import javax.inject.Inject class SavingAccountViewModel @Inject constructor(private val repository: SavingsAccountRepository) : ViewModel() { - private val _savingAccountUiState = MutableLiveData() + private val _savingAccountUiState = MutableStateFlow(SavingAccountUiState.ShowProgress) + val savingAccountUiState: StateFlow get() = _savingAccountUiState - val savingAccountUiState: LiveData - get() = _savingAccountUiState + var clientId = 0 + var groupId = 0 + var isGroupAccount = false + + private val _savingProductsTemplate = MutableStateFlow(SavingProductsTemplate()) + val savingProductsTemplate = _savingProductsTemplate.asStateFlow() + + fun loadLoanTemplateByProduct(productId: Int) { + if (isGroupAccount) { + loadGroupSavingAccountTemplateByProduct(groupId, productId) + } else { + loadClientSavingAccountTemplateByProduct(clientId, productId) + } + } fun loadSavingsAccountsAndTemplate() { _savingAccountUiState.value = SavingAccountUiState.ShowProgress @@ -46,14 +64,15 @@ class SavingAccountViewModel @Inject constructor(private val repository: Savings } override fun onNext(productsAndTemplate: SavingProductsAndTemplate?) { - _savingAccountUiState.value = - SavingAccountUiState.ShowSavingsAccounts(productsAndTemplate?.getmProductSavings()) + if (productsAndTemplate != null) { + _savingAccountUiState.value = + SavingAccountUiState.LoadAllSavings(productsAndTemplate) + } } }) } - fun loadClientSavingAccountTemplateByProduct(clientId: Int, productId: Int) { - _savingAccountUiState.value = SavingAccountUiState.ShowProgress + private fun loadClientSavingAccountTemplateByProduct(clientId: Int, productId: Int) { repository.getClientSavingsAccountTemplateByProduct(clientId, productId) .observeOn(AndroidSchedulers.mainThread()) .subscribeOn(Schedulers.io()) @@ -67,17 +86,13 @@ class SavingAccountViewModel @Inject constructor(private val repository: Savings } override fun onNext(savingProductsTemplate: SavingProductsTemplate?) { - _savingAccountUiState.value = savingProductsTemplate?.let { - SavingAccountUiState.ShowSavingsAccountTemplateByProduct( - it - ) - } + _savingProductsTemplate.value = + savingProductsTemplate ?: SavingProductsTemplate() } }) } - fun loadGroupSavingAccountTemplateByProduct(groupId: Int, productId: Int) { - _savingAccountUiState.value = SavingAccountUiState.ShowProgress + private fun loadGroupSavingAccountTemplateByProduct(groupId: Int, productId: Int) { repository.getGroupSavingsAccountTemplateByProduct(groupId, productId) .observeOn(AndroidSchedulers.mainThread()) .subscribeOn(Schedulers.io()) @@ -91,11 +106,8 @@ class SavingAccountViewModel @Inject constructor(private val repository: Savings } override fun onNext(savingProductsTemplate: SavingProductsTemplate?) { - _savingAccountUiState.value = savingProductsTemplate?.let { - SavingAccountUiState.ShowSavingsAccountTemplateByProduct( - it - ) - } + _savingProductsTemplate.value = + savingProductsTemplate ?: SavingProductsTemplate() } }) } @@ -118,32 +130,4 @@ class SavingAccountViewModel @Inject constructor(private val repository: Savings } }) } - - fun filterSpinnerOptions(interestTypes: List?): List { - val interestNameList = ArrayList() - Observable.from(interestTypes) - .subscribe { interestType -> interestType.value?.let { interestNameList.add(it) } } - return interestNameList - } - - fun filterSavingProductsNames(productSavings: List?): List { - val productsNames = ArrayList() - Observable.from(productSavings) - .subscribe { product -> product.name?.let { productsNames.add(it) } } - return productsNames - } - - fun filterFieldOfficerNames(fieldOfficerOptions: List?): List { - val fieldOfficerNames = ArrayList() - Observable.from(fieldOfficerOptions) - .subscribe { fieldOfficerOptions -> - fieldOfficerOptions.displayName?.let { - fieldOfficerNames.add( - it - ) - } - } - return fieldOfficerNames - } - } \ No newline at end of file diff --git a/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/savingsaccount/SavingsAccountFragment.kt b/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/savingsaccount/SavingsAccountFragment.kt index 4f3fad4f63f..11862311695 100755 --- a/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/savingsaccount/SavingsAccountFragment.kt +++ b/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/savingsaccount/SavingsAccountFragment.kt @@ -12,17 +12,22 @@ import android.widget.AdapterView import android.widget.AdapterView.OnItemSelectedListener import android.widget.ArrayAdapter import android.widget.Toast +import androidx.compose.ui.platform.ComposeView +import androidx.compose.ui.platform.ViewCompositionStrategy import androidx.fragment.app.DialogFragment -import androidx.lifecycle.ViewModelProvider +import androidx.fragment.app.viewModels +import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.navArgs import com.mifos.core.data.SavingsPayload import com.mifos.core.objects.client.Savings import com.mifos.core.objects.organisation.ProductSavings import com.mifos.core.objects.templates.savings.SavingProductsTemplate import com.mifos.mifosxdroid.R +import com.mifos.mifosxdroid.core.MifosBaseFragment import com.mifos.mifosxdroid.core.ProgressableDialogFragment import com.mifos.mifosxdroid.core.util.Toaster import com.mifos.mifosxdroid.databinding.FragmentAddSavingsAccountBinding +import com.mifos.mifosxdroid.online.loanrepaymentschedule.LoanRepaymentScheduleScreen import com.mifos.mifosxdroid.uihelpers.MFDatePicker import com.mifos.mifosxdroid.uihelpers.MFDatePicker.OnDatePickListener import com.mifos.utils.DateHelper @@ -37,32 +42,16 @@ import dagger.hilt.android.AndroidEntryPoint * Use this Dialog Fragment to Create and/or Update charges */ @AndroidEntryPoint -class SavingsAccountFragment : ProgressableDialogFragment(), OnDatePickListener, - OnItemSelectedListener { +class SavingsAccountFragment : MifosBaseFragment() { - private lateinit var binding: FragmentAddSavingsAccountBinding private val arg: SavingsAccountFragmentArgs by navArgs() + val viewmodel : SavingAccountViewModel by viewModels() - private lateinit var viewModel: SavingAccountViewModel - - private var mfDatePicker: DialogFragment? = null - private var productId: Int? = 0 - private var clientId = 0 - private var fieldOfficerId: Int? = 0 - private var groupId = 0 - private var submission_date: String? = null - private var mFieldOfficerNames: MutableList = ArrayList() - private var mListSavingProductsNames: MutableList = ArrayList() - private var mFieldOfficerAdapter: ArrayAdapter? = null - private var mSavingProductsAdapter: ArrayAdapter? = null - private var mSavingProductsTemplateByProductId: SavingProductsTemplate? = null - private var mProductSavings: List? = null - private var isGroupAccount = false override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - isGroupAccount = arg.isGroupAccount - clientId = arg.id - groupId = arg.id + viewmodel.clientId = arg.id + viewmodel.groupId = arg.id + viewmodel.isGroupAccount = arg.isGroupAccount } override fun onCreateView( @@ -70,222 +59,23 @@ class SavingsAccountFragment : ProgressableDialogFragment(), OnDatePickListener, container: ViewGroup?, savedInstanceState: Bundle? ): View { - binding = FragmentAddSavingsAccountBinding.inflate(inflater, container, false) - viewModel = ViewModelProvider(this)[SavingAccountViewModel::class.java] - inflateSubmissionDate() - inflateSavingsSpinners() - viewModel.loadSavingsAccountsAndTemplate() - - viewModel.savingAccountUiState.observe(viewLifecycleOwner) { - when (it) { - is SavingAccountUiState.ShowFetchingError -> { - showProgressbar(false) - showFetchingError(it.message) - } - - is SavingAccountUiState.ShowFetchingErrorString -> { - showProgressbar(false) - showFetchingError(it.message) - } - - is SavingAccountUiState.ShowProgress -> showProgressbar(true) - is SavingAccountUiState.ShowSavingsAccountCreatedSuccessfully -> { - showProgressbar(false) - showSavingsAccountCreatedSuccessfully(it.savings) - } - - is SavingAccountUiState.ShowSavingsAccountTemplateByProduct -> { - showProgressbar(false) - showSavingsAccountTemplateByProduct(it.savingProductsTemplate) - } - - is SavingAccountUiState.ShowSavingsAccounts -> { - showProgressbar(false) - showSavingsAccounts(it.getProductSaving) + return ComposeView(requireContext()).apply { + setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed) + setContent { + SavingsAccountScreen { + findNavController().popBackStack() } } } - return binding.root - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - binding.cbEnforceRequiredBalance.setOnCheckedChangeListener { compoundButton, b -> - onClickOverdraftAllowedCheckBox() - } - - binding.tvSubmittedonDate.setOnClickListener { - onClickTextViewSubmissionDate() - } - - binding.btnSubmit.setOnClickListener { - submitSavingsAccount() - } - - binding.cbOverdraftAllowed.setOnCheckedChangeListener { compoundButton, b -> - onClickMinRequiredCheckBox() - } - - } - - private fun onClickOverdraftAllowedCheckBox() { - binding.etMinRequiredBalance.visibility = - if (binding.cbEnforceRequiredBalance.isChecked) View.VISIBLE else View.GONE - } - - private fun onClickMinRequiredCheckBox() { - binding.etMaxOverdraftAmount.visibility = - if (binding.cbOverdraftAllowed.isChecked) View.VISIBLE else View.GONE - binding.etNominalAnnualOverdraft.visibility = - if (binding.cbOverdraftAllowed.isChecked) View.VISIBLE else View.GONE - binding.etMinOverdraftRequired.visibility = - if (binding.cbOverdraftAllowed.isChecked) View.VISIBLE else View.GONE - } - - private fun inflateSavingsSpinners() { - mFieldOfficerAdapter = ArrayAdapter( - requireActivity(), - android.R.layout.simple_spinner_item, mFieldOfficerNames - ) - mFieldOfficerAdapter - ?.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) - binding.spFieldOfficer.adapter = mFieldOfficerAdapter - binding.spFieldOfficer.onItemSelectedListener = this - mSavingProductsAdapter = ArrayAdapter( - requireActivity(), - android.R.layout.simple_spinner_item, - mListSavingProductsNames - ) - mSavingProductsAdapter?.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) - binding.spProduct.adapter = mSavingProductsAdapter - binding.spProduct.onItemSelectedListener = this - } - - private fun submitSavingsAccount() { - if (Network.isOnline(requireContext())) { - val savingsPayload = SavingsPayload() - savingsPayload.externalId = binding.etClientExternalId.editableText.toString() - savingsPayload.locale = "en" - savingsPayload.submittedOnDate = submission_date - savingsPayload.dateFormat = "dd MMMM yyyy" - if (isGroupAccount) { - savingsPayload.groupId = groupId - } else { - savingsPayload.clientId = clientId - } - savingsPayload.productId = productId - savingsPayload.fieldOfficerId = fieldOfficerId - savingsPayload.nominalAnnualInterestRate = binding.etNominalAnnual.editableText - .toString() - savingsPayload.allowOverdraft = binding.cbOverdraftAllowed.isChecked - savingsPayload.nominalAnnualInterestRateOverdraft = - binding.etNominalAnnualOverdraft.editableText.toString() - savingsPayload.overdraftLimit = binding.etMaxOverdraftAmount.editableText - .toString() - savingsPayload.minOverdraftForInterestCalculation = - binding.etMinOverdraftRequired.editableText.toString() - savingsPayload.enforceMinRequiredBalance = binding.cbEnforceRequiredBalance.isChecked - savingsPayload.minRequiredOpeningBalance = binding.etMinRequiredBalance.editableText - .toString() - viewModel.createSavingsAccount(savingsPayload) - } else { - Toaster.show(binding.root, R.string.error_network_not_available) - } - } - - override fun onDatePicked(date: String?) { - binding.tvSubmittedonDate.text = date - submission_date = date - setSubmissionDate() - } - - private fun inflateSubmissionDate() { - mfDatePicker = MFDatePicker.newInsance(this) - binding.tvSubmittedonDate.text = MFDatePicker.datePickedAsString - setSubmissionDate() - } - - private fun onClickTextViewSubmissionDate() { - mfDatePicker?.show( - requireActivity().supportFragmentManager, - FragmentConstants.DFRAG_DATE_PICKER - ) - } - - private fun setSubmissionDate() { - submission_date = binding.tvSubmittedonDate.text.toString() - submission_date = DateHelper.getDateAsStringUsedForCollectionSheetPayload(submission_date) - .replace("-", " ") - } - - private fun showSavingsAccounts(productSavings: List?) { - mProductSavings = productSavings - viewModel - .filterSavingProductsNames(productSavings).let { mListSavingProductsNames.addAll(it) } - mSavingProductsAdapter?.notifyDataSetChanged() } - private fun showSavingsAccountTemplateByProduct(savingProductsTemplate: SavingProductsTemplate) { - mSavingProductsTemplateByProductId = savingProductsTemplate - mFieldOfficerNames.addAll( - viewModel.filterFieldOfficerNames( - savingProductsTemplate.fieldOfficerOptions - ) - ) - mFieldOfficerAdapter?.notifyDataSetChanged() - binding.tvInterestCalc.text = savingProductsTemplate.interestCalculationType?.value - binding.tvInterestComp.text = savingProductsTemplate.interestCompoundingPeriodType?.value - binding.tvInterestPPeriod.text = savingProductsTemplate.interestPostingPeriodType?.value - binding.tvDaysInYear.text = savingProductsTemplate.interestCalculationDaysInYearType?.value + override fun onResume() { + super.onResume() + toolbar?.visibility = View.GONE } - private fun showSavingsAccountCreatedSuccessfully(savings: Savings?) { - Toast.makeText( - activity, - resources.getString(R.string.savings_account_submitted_for_approval), - Toast.LENGTH_LONG - ).show() - requireActivity().supportFragmentManager.popBackStackImmediate() + override fun onStop() { + super.onStop() + toolbar?.visibility = View.VISIBLE } - - private fun showFetchingError(errorMessage: Int) { - Toaster.show(binding.root, resources.getString(errorMessage)) - } - - private fun showFetchingError(errorMessage: String?) { - Toaster.show(binding.root, errorMessage) - } - - private fun showProgressbar(b: Boolean) { - showProgress(b) - } - - override fun onItemSelected(parent: AdapterView<*>, view: View, position: Int, id: Long) { - when (parent.id) { - R.id.sp_field_officer -> fieldOfficerId = mSavingProductsTemplateByProductId - ?.fieldOfficerOptions?.get(position)?.id - - R.id.sp_product -> { - productId = mProductSavings!![position].id - if (isGroupAccount) { - productId?.let { - viewModel.loadGroupSavingAccountTemplateByProduct( - groupId, - it - ) - } - } else { - productId?.let { - viewModel.loadClientSavingAccountTemplateByProduct( - clientId, - it - ) - } - } - } - } - } - - override fun onNothingSelected(parent: AdapterView<*>?) {} } \ No newline at end of file diff --git a/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/savingsaccount/SavingsAccountFragmentOld.kt b/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/savingsaccount/SavingsAccountFragmentOld.kt new file mode 100644 index 00000000000..230b67290ca --- /dev/null +++ b/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/savingsaccount/SavingsAccountFragmentOld.kt @@ -0,0 +1,289 @@ +///* +// * This project is licensed under the open source MPL V2. +// * See https://github.com/openMF/android-client/blob/master/LICENSE.md +// */ +//package com.mifos.mifosxdroid.online.savingsaccount +// +//import android.os.Bundle +//import android.view.LayoutInflater +//import android.view.View +//import android.view.ViewGroup +//import android.widget.AdapterView +//import android.widget.AdapterView.OnItemSelectedListener +//import android.widget.ArrayAdapter +//import android.widget.Toast +//import androidx.fragment.app.DialogFragment +//import androidx.lifecycle.ViewModelProvider +//import androidx.navigation.fragment.navArgs +//import com.mifos.core.data.SavingsPayload +//import com.mifos.core.objects.client.Savings +//import com.mifos.core.objects.organisation.ProductSavings +//import com.mifos.core.objects.templates.savings.SavingProductsTemplate +//import com.mifos.mifosxdroid.R +//import com.mifos.mifosxdroid.core.ProgressableDialogFragment +//import com.mifos.mifosxdroid.core.util.Toaster +//import com.mifos.mifosxdroid.databinding.FragmentAddSavingsAccountBinding +//import com.mifos.mifosxdroid.uihelpers.MFDatePicker +//import com.mifos.mifosxdroid.uihelpers.MFDatePicker.OnDatePickListener +//import com.mifos.utils.DateHelper +//import com.mifos.utils.FragmentConstants +//import com.mifos.utils.Network +//import dagger.hilt.android.AndroidEntryPoint +// +///** +// * Created by nellyk on 1/22/2016. +// * +// * +// * Use this Dialog Fragment to Create and/or Update charges +// */ +//@AndroidEntryPoint +//class SavingsAccountFragment : ProgressableDialogFragment(), OnDatePickListener, +// OnItemSelectedListener { +// +// private lateinit var binding: FragmentAddSavingsAccountBinding +// private val arg: SavingsAccountFragmentArgs by navArgs() +// +// private lateinit var viewModel: SavingAccountViewModel +// +// private var mfDatePicker: DialogFragment? = null +// private var productId: Int? = 0 +// private var clientId = 0 +// private var fieldOfficerId: Int? = 0 +// private var groupId = 0 +// private var submission_date: String? = null +// private var mFieldOfficerNames: MutableList = ArrayList() +// private var mListSavingProductsNames: MutableList = ArrayList() +// private var mFieldOfficerAdapter: ArrayAdapter? = null +// private var mSavingProductsAdapter: ArrayAdapter? = null +// private var mSavingProductsTemplateByProductId: SavingProductsTemplate? = null +// private var mProductSavings: List? = null +// private var isGroupAccount = false +// override fun onCreate(savedInstanceState: Bundle?) { +// super.onCreate(savedInstanceState) +// isGroupAccount = arg.isGroupAccount +// clientId = arg.id +// groupId = arg.id +// } +// +// override fun onCreateView( +// inflater: LayoutInflater, +// container: ViewGroup?, +// savedInstanceState: Bundle? +// ): View { +// binding = FragmentAddSavingsAccountBinding.inflate(inflater, container, false) +// viewModel = ViewModelProvider(this)[SavingAccountViewModel::class.java] +// inflateSubmissionDate() +// inflateSavingsSpinners() +// viewModel.loadSavingsAccountsAndTemplate() +// +// viewModel.savingAccountUiState.observe(viewLifecycleOwner) { +// when (it) { +// is SavingAccountUiState.ShowFetchingError -> { +// showProgressbar(false) +// showFetchingError(it.message) +// } +// +// is SavingAccountUiState.ShowFetchingErrorString -> { +// showProgressbar(false) +// showFetchingError(it.message) +// } +// +// is SavingAccountUiState.ShowProgress -> showProgressbar(true) +// is SavingAccountUiState.ShowSavingsAccountCreatedSuccessfully -> { +// showProgressbar(false) +// showSavingsAccountCreatedSuccessfully(it.savings) +// } +// +// is SavingAccountUiState.ShowSavingsAccountTemplateByProduct -> { +// showProgressbar(false) +// showSavingsAccountTemplateByProduct(it.savingProductsTemplate) +// } +// +// is SavingAccountUiState.ShowSavingsAccounts -> { +// showProgressbar(false) +// showSavingsAccounts(it.getProductSaving) +// } +// } +// } +// return binding.root +// } +// +// override fun onViewCreated(view: View, savedInstanceState: Bundle?) { +// super.onViewCreated(view, savedInstanceState) +// +// binding.cbEnforceRequiredBalance.setOnCheckedChangeListener { compoundButton, b -> +// onClickOverdraftAllowedCheckBox() +// } +// +// binding.tvSubmittedonDate.setOnClickListener { +// onClickTextViewSubmissionDate() +// } +// +// binding.btnSubmit.setOnClickListener { +// submitSavingsAccount() +// } +// +// binding.cbOverdraftAllowed.setOnCheckedChangeListener { compoundButton, b -> +// onClickMinRequiredCheckBox() +// } +// +// } +// +// private fun onClickOverdraftAllowedCheckBox() { +// binding.etMinRequiredBalance.visibility = +// if (binding.cbEnforceRequiredBalance.isChecked) View.VISIBLE else View.GONE +// } +// +// private fun onClickMinRequiredCheckBox() { +// binding.etMaxOverdraftAmount.visibility = +// if (binding.cbOverdraftAllowed.isChecked) View.VISIBLE else View.GONE +// binding.etNominalAnnualOverdraft.visibility = +// if (binding.cbOverdraftAllowed.isChecked) View.VISIBLE else View.GONE +// binding.etMinOverdraftRequired.visibility = +// if (binding.cbOverdraftAllowed.isChecked) View.VISIBLE else View.GONE +// } +// +// private fun inflateSavingsSpinners() { +// mFieldOfficerAdapter = ArrayAdapter( +// requireActivity(), +// android.R.layout.simple_spinner_item, mFieldOfficerNames +// ) +// mFieldOfficerAdapter +// ?.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) +// binding.spFieldOfficer.adapter = mFieldOfficerAdapter +// binding.spFieldOfficer.onItemSelectedListener = this +// mSavingProductsAdapter = ArrayAdapter( +// requireActivity(), +// android.R.layout.simple_spinner_item, +// mListSavingProductsNames +// ) +// mSavingProductsAdapter?.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) +// binding.spProduct.adapter = mSavingProductsAdapter +// binding.spProduct.onItemSelectedListener = this +// } +// +// private fun submitSavingsAccount() { +// if (Network.isOnline(requireContext())) { +// val savingsPayload = SavingsPayload() +// savingsPayload.externalId = binding.etClientExternalId.editableText.toString() +// savingsPayload.locale = "en" +// savingsPayload.submittedOnDate = submission_date +// savingsPayload.dateFormat = "dd MMMM yyyy" +// if (isGroupAccount) { +// savingsPayload.groupId = groupId +// } else { +// savingsPayload.clientId = clientId +// } +// savingsPayload.productId = productId +// savingsPayload.fieldOfficerId = fieldOfficerId +// savingsPayload.nominalAnnualInterestRate = binding.etNominalAnnual.editableText.toString() +// savingsPayload.allowOverdraft = binding.cbOverdraftAllowed.isChecked +// savingsPayload.nominalAnnualInterestRateOverdraft = binding.etNominalAnnualOverdraft.editableText.toString() +// savingsPayload.overdraftLimit = binding.etMaxOverdraftAmount.editableText +// .toString() +// savingsPayload.minOverdraftForInterestCalculation = +// binding.etMinOverdraftRequired.editableText.toString() +// savingsPayload.enforceMinRequiredBalance = binding.cbEnforceRequiredBalance.isChecked +// savingsPayload.minRequiredOpeningBalance = binding.etMinRequiredBalance.editableText +// .toString() +// viewModel.createSavingsAccount(savingsPayload) +// } else { +// Toaster.show(binding.root, R.string.error_network_not_available) +// } +// } +// +// override fun onDatePicked(date: String?) { +// binding.tvSubmittedonDate.text = date +// submission_date = date +// setSubmissionDate() +// } +// +// private fun inflateSubmissionDate() { +// mfDatePicker = MFDatePicker.newInsance(this) +// binding.tvSubmittedonDate.text = MFDatePicker.datePickedAsString +// setSubmissionDate() +// } +// +// private fun onClickTextViewSubmissionDate() { +// mfDatePicker?.show( +// requireActivity().supportFragmentManager, +// FragmentConstants.DFRAG_DATE_PICKER +// ) +// } +// +// private fun setSubmissionDate() { +// submission_date = binding.tvSubmittedonDate.text.toString() +// submission_date = DateHelper.getDateAsStringUsedForCollectionSheetPayload(submission_date) +// .replace("-", " ") +// } +// +// private fun showSavingsAccounts(productSavings: List?) { +// mProductSavings = productSavings +// viewModel +// .filterSavingProductsNames(productSavings).let { mListSavingProductsNames.addAll(it) } +// mSavingProductsAdapter?.notifyDataSetChanged() +// } +// +// private fun showSavingsAccountTemplateByProduct(savingProductsTemplate: SavingProductsTemplate) { +// mSavingProductsTemplateByProductId = savingProductsTemplate +// mFieldOfficerNames.addAll( +// viewModel.filterFieldOfficerNames( +// savingProductsTemplate.fieldOfficerOptions +// ) +// ) +// mFieldOfficerAdapter?.notifyDataSetChanged() +// binding.tvInterestCalc.text = savingProductsTemplate.interestCalculationType?.value +// binding.tvInterestComp.text = savingProductsTemplate.interestCompoundingPeriodType?.value +// binding.tvInterestPPeriod.text = savingProductsTemplate.interestPostingPeriodType?.value +// binding.tvDaysInYear.text = savingProductsTemplate.interestCalculationDaysInYearType?.value +// } +// +// private fun showSavingsAccountCreatedSuccessfully(savings: Savings?) { +// Toast.makeText( +// activity, +// resources.getString(R.string.savings_account_submitted_for_approval), +// Toast.LENGTH_LONG +// ).show() +// requireActivity().supportFragmentManager.popBackStackImmediate() +// } +// +// private fun showFetchingError(errorMessage: Int) { +// Toaster.show(binding.root, resources.getString(errorMessage)) +// } +// +// private fun showFetchingError(errorMessage: String?) { +// Toaster.show(binding.root, errorMessage) +// } +// +// private fun showProgressbar(b: Boolean) { +// showProgress(b) +// } +// +// override fun onItemSelected(parent: AdapterView<*>, view: View, position: Int, id: Long) { +// when (parent.id) { +// R.id.sp_field_officer -> fieldOfficerId = mSavingProductsTemplateByProductId +// ?.fieldOfficerOptions?.get(position)?.id +// +// R.id.sp_product -> { +// productId = mProductSavings!![position].id +// if (isGroupAccount) { +// productId?.let { +// viewModel.loadGroupSavingAccountTemplateByProduct( +// groupId, +// it +// ) +// } +// } else { +// productId?.let { +// viewModel.loadClientSavingAccountTemplateByProduct( +// clientId, +// it +// ) +// } +// } +// } +// } +// } +// +// override fun onNothingSelected(parent: AdapterView<*>?) {} +//} \ No newline at end of file diff --git a/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/savingsaccount/SavingsAccountScreen.kt b/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/savingsaccount/SavingsAccountScreen.kt new file mode 100644 index 00000000000..c9ddd631e64 --- /dev/null +++ b/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/savingsaccount/SavingsAccountScreen.kt @@ -0,0 +1,599 @@ +package com.mifos.mifosxdroid.online.savingsaccount + +import android.widget.Toast +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.expandVertically +import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut +import androidx.compose.animation.shrinkVertically +import androidx.compose.animation.slideInVertically +import androidx.compose.animation.slideOutVertically +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.heightIn +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.Button +import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.Checkbox +import androidx.compose.material3.CheckboxDefaults +import androidx.compose.material3.DatePicker +import androidx.compose.material3.DatePickerDialog +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.SelectableDates +import androidx.compose.material3.SnackbarHostState +import androidx.compose.material3.Text +import androidx.compose.material3.TextButton +import androidx.compose.material3.rememberDatePickerState +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableLongStateOf +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.input.KeyboardType +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.tooling.preview.PreviewParameter +import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import androidx.compose.ui.unit.dp +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.mifos.core.common.utils.Network +import com.mifos.core.data.SavingsPayload +import com.mifos.core.designsystem.component.MifosCircularProgress +import com.mifos.core.designsystem.component.MifosDatePickerTextField +import com.mifos.core.designsystem.component.MifosOutlinedTextField +import com.mifos.core.designsystem.component.MifosScaffold +import com.mifos.core.designsystem.component.MifosSweetError +import com.mifos.core.designsystem.component.MifosTextFieldDropdown +import com.mifos.core.designsystem.icon.MifosIcons +import com.mifos.core.designsystem.theme.BluePrimary +import com.mifos.core.designsystem.theme.BluePrimaryDark +import com.mifos.core.objects.accounts.savings.FieldOfficerOptions +import com.mifos.core.objects.client.Savings +import com.mifos.core.objects.organisation.ProductSavings +import com.mifos.core.objects.templates.loans.LoanTransactionTemplate +import com.mifos.core.objects.templates.savings.SavingProductsTemplate +import com.mifos.core.objects.zipmodels.SavingProductsAndTemplate +import com.mifos.mifosxdroid.R +import com.mifos.mifosxdroid.online.loanaccountdisbursement.LoanAccountDisbursementScreen +import com.mifos.mifosxdroid.online.loanaccountdisbursement.LoanAccountDisbursementScreenPreviewProvider +import com.mifos.mifosxdroid.online.loanaccountdisbursement.LoanAccountDisbursementUiState +import java.text.SimpleDateFormat +import java.util.Locale + +/** + * Created by Pronay Sarker on 14/07/2024 (12:04 AM) + */ + +@Composable +fun SavingsAccountScreen( + navigateBack: () -> Unit +) { + val viewModel: SavingAccountViewModel = hiltViewModel() + val uiState by viewModel.savingAccountUiState.collectAsStateWithLifecycle() + val savingProductsTemplate by viewModel.savingProductsTemplate.collectAsStateWithLifecycle() + + LaunchedEffect(key1 = Unit) { + viewModel.loadSavingsAccountsAndTemplate() + } + + SavingsAccountScreen( + uiState = uiState, + savingProductsTemplate = savingProductsTemplate, + navigateBack = navigateBack, + onRetry = { + viewModel.loadSavingsAccountsAndTemplate() + }, + onSavingsProductSelected = { + viewModel.loadLoanTemplateByProduct(it) + }, + fetchTemplate = { + viewModel.loadLoanTemplateByProduct(it) + }, + clientId = viewModel.clientId, + groupId = viewModel.groupId, + isGroupAccount = viewModel.isGroupAccount, + createSavingsAccount = { savingsPayload -> + viewModel.createSavingsAccount(savingsPayload) + } + ) +} + +@Composable +fun SavingsAccountScreen( + uiState: SavingAccountUiState, + savingProductsTemplate: SavingProductsTemplate, + onSavingsProductSelected: (Int) -> Unit, + navigateBack: () -> Unit, + onRetry: () -> Unit, + fetchTemplate: (Int) -> Unit, + isGroupAccount: Boolean, + clientId: Int, + groupId: Int, + createSavingsAccount: (savingsPayload: SavingsPayload) -> Unit, +) { + val snackBarHostState = remember { + SnackbarHostState() + } + val context = LocalContext.current + + MifosScaffold( + snackbarHostState = snackBarHostState, + title = stringResource(id = R.string.create_savings_account), + icon = MifosIcons.arrowBack, + onBackPressed = navigateBack + ) { + Box( + modifier = Modifier + .padding(it) + .fillMaxSize() + ) { + when (uiState) { + is SavingAccountUiState.ShowProgress -> { + MifosCircularProgress() + } + + is SavingAccountUiState.ShowFetchingError -> { + MifosSweetError(message = stringResource(id = uiState.message)) { + onRetry() + } + } + + is SavingAccountUiState.ShowFetchingErrorString -> { + MifosSweetError( + message = uiState.message, + buttonText = stringResource(id = R.string.go_back), + onclick = { onRetry() } + ) + } + + is SavingAccountUiState.LoadAllSavings -> { + val productSavingsList = uiState.savingsTemplate.getmProductSavings() + + SavingsAccountContent( + clientId = clientId, + groupId = groupId, + isGroupAccount = isGroupAccount, + fieldOfficerOptions = savingProductsTemplate.fieldOfficerOptions + ?: emptyList(), + savingProductsTemplate = uiState.savingsTemplate, + productSavings = productSavingsList, + onSavingsProductSelected = onSavingsProductSelected, + createSavingsAccount = createSavingsAccount + ) + + productSavingsList[0].id?.let { it2 -> fetchTemplate.invoke(it2) } + } + + is SavingAccountUiState.ShowSavingsAccountCreatedSuccessfully -> { + Toast.makeText( + context, + context.resources.getString(R.string.savings_account_submitted_for_approval), + Toast.LENGTH_LONG + ).show() + + navigateBack() + } + } + } + } +} + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun SavingsAccountContent( + clientId: Int, + groupId: Int, + isGroupAccount: Boolean, + fieldOfficerOptions: List, + productSavings: List, + savingProductsTemplate: SavingProductsAndTemplate, + onSavingsProductSelected: (Int) -> Unit, + createSavingsAccount: (savingsPayload: SavingsPayload) -> Unit +) { + var selectedSavingsProduct by rememberSaveable { + mutableStateOf("") + } + var selectedFieldOfficer by rememberSaveable { + mutableStateOf("") + } + var overDraftAllowed by rememberSaveable { + mutableStateOf(false) + } + var enforceMinimumBalance by rememberSaveable { + mutableStateOf(false) + } + var externalId by rememberSaveable { + mutableStateOf("") + } + var maximumOverdraftAmount by rememberSaveable { + mutableStateOf("") + } + var nominalAnnualInterest by rememberSaveable { + mutableStateOf("") + } + var minimumOverdraftAmount by rememberSaveable { + mutableStateOf("") + } + var minimumRequiredBalance by rememberSaveable { + mutableStateOf("") + } + var interestCalculatedUsing by rememberSaveable { + mutableStateOf("") + } + var interestPostingPeriod by rememberSaveable { + mutableStateOf("") + } + var fieldOfficerId by rememberSaveable { + mutableStateOf(0) + } + var selectedSavingsProductID by rememberSaveable { + mutableStateOf(0) + } + var nominalAnnualInterestOverdraft by rememberSaveable { + mutableStateOf("") + } + + val context = LocalContext.current + val density = LocalDensity.current + val scrollState = rememberScrollState() + + var submittedOnDate by rememberSaveable { mutableLongStateOf(System.currentTimeMillis()) } + var pickSubmitDate by rememberSaveable { mutableStateOf(false) } + val datePickerState = rememberDatePickerState( + initialSelectedDateMillis = submittedOnDate, + selectableDates = object : SelectableDates { + override fun isSelectableDate(utcTimeMillis: Long): Boolean { + return utcTimeMillis >= System.currentTimeMillis() + } + } + ) + + if (pickSubmitDate) { + DatePickerDialog( + onDismissRequest = { + pickSubmitDate = false + }, + confirmButton = { + TextButton( + onClick = { + datePickerState.selectedDateMillis?.let { + submittedOnDate = it + } + pickSubmitDate = false + } + ) { Text(stringResource(id = R.string.select_date)) } + }, + dismissButton = { + TextButton( + onClick = { + pickSubmitDate = false + } + ) { Text(stringResource(id = R.string.cancel)) } + } + ) + { + DatePicker(state = datePickerState) + } + } + + Column( + modifier = Modifier + .fillMaxSize() + .verticalScroll(scrollState) + ) { + Spacer(modifier = Modifier.height(16.dp)) + + MifosTextFieldDropdown( + value = selectedSavingsProduct, + onValueChanged = { + selectedSavingsProduct = it + }, + onOptionSelected = { index, value -> + selectedSavingsProduct = value + productSavings[index].id?.let { + selectedSavingsProductID = it + onSavingsProductSelected.invoke(it) + } + + }, + label = R.string.product, + options = productSavings.map { it.name.toString() }, + readOnly = true + ) + + Spacer(modifier = Modifier.height(16.dp)) + + MifosTextFieldDropdown( + value = selectedFieldOfficer, + onValueChanged = { + selectedFieldOfficer = it + }, + onOptionSelected = { index, value -> + selectedFieldOfficer = value + fieldOfficerOptions[index].id?.let { + fieldOfficerId = it + } + }, + label = R.string.field_officer, + options = fieldOfficerOptions.map { it.displayName.toString() }, + readOnly = true + ) + + Spacer(modifier = Modifier.height(16.dp)) + + MifosOutlinedTextField( + value = externalId, + onValueChange = { externalId = it }, + label = stringResource(id = R.string.external_id), + error = null + ) + + Spacer(modifier = Modifier.height(16.dp)) + + MifosDatePickerTextField( + value = SimpleDateFormat( + "dd MMMM yyyy", Locale.getDefault() + ).format(submittedOnDate), + label = R.string.submitted_on + ) { + pickSubmitDate = true + } + + Spacer(modifier = Modifier.height(16.dp)) + + + MifosOutlinedTextField( + value = nominalAnnualInterest, + onValueChange = { nominalAnnualInterest = it }, + label = stringResource(id = R.string.nominal), + error = null, + keyboardType = KeyboardType.Number + ) + + Spacer(modifier = Modifier.height(16.dp)) + + MifosOutlinedTextField( + value = savingProductsTemplate.mSavingProductsTemplate.interestCalculationType?.value.toString(), + onValueChange = { interestCalculatedUsing = it }, + label = stringResource(id = R.string.interest_calc), + error = null, + readOnly = true + ) + + Spacer(modifier = Modifier.height(16.dp)) + + MifosOutlinedTextField( + value = savingProductsTemplate.mSavingProductsTemplate.interestCompoundingPeriodType?.value.toString(), + onValueChange = { }, + label = stringResource(id = R.string.interest_comp), + error = null, + readOnly = true, + ) + + Spacer(modifier = Modifier.height(16.dp)) + + MifosOutlinedTextField( + value = savingProductsTemplate.mSavingProductsTemplate.interestPostingPeriodType?.value.toString(), + onValueChange = { interestPostingPeriod = it }, + label = stringResource(id = R.string.interest_p_period), + error = null, + readOnly = true + ) + + Spacer(modifier = Modifier.height(16.dp)) + + MifosOutlinedTextField( + value = savingProductsTemplate.mSavingProductsTemplate.interestCalculationDaysInYearType?.value.toString(), + onValueChange = { }, + label = stringResource(id = R.string.days_in_year), + error = null, + readOnly = true + ) + + Spacer(modifier = Modifier.height(16.dp)) + + Row( + modifier = Modifier.fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically + ) { + Checkbox( + checked = enforceMinimumBalance, + onCheckedChange = { enforceMinimumBalance = !enforceMinimumBalance }, + colors = CheckboxDefaults.colors( + checkedColor = if (isSystemInDarkTheme()) BluePrimaryDark else BluePrimary + ) + ) + + Text(text = stringResource(id = R.string.saving_min_required_balance)) + } + + AnimatedVisibility( + visible = enforceMinimumBalance, + enter = slideInVertically { + with(density) { -40.dp.roundToPx() } + } + expandVertically( + expandFrom = Alignment.Top + ) + fadeIn( + initialAlpha = 0.3f + ), + exit = slideOutVertically() + shrinkVertically() + fadeOut() + ) { + Spacer(modifier = Modifier.height(16.dp)) + + MifosOutlinedTextField( + value = minimumRequiredBalance, + onValueChange = { minimumRequiredBalance = it }, + label = stringResource(id = R.string.saving_min_required_balance), + error = null, + keyboardType = KeyboardType.Number + ) + } + + Spacer(modifier = Modifier.height(16.dp)) + + Row( + modifier = Modifier.fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically + ) { + Checkbox( + checked = overDraftAllowed, + onCheckedChange = { overDraftAllowed = !overDraftAllowed }, + colors = CheckboxDefaults.colors( + checkedColor = if (isSystemInDarkTheme()) BluePrimaryDark else BluePrimary + ) + ) + + Text(text = stringResource(id = R.string.saving_overdraft_allowed)) + } + + AnimatedVisibility( + visible = overDraftAllowed, + enter = slideInVertically { + with(density) { -40.dp.roundToPx() } + } + expandVertically( + expandFrom = Alignment.Top + ) + fadeIn( + initialAlpha = 0.3f + ), + exit = slideOutVertically() + shrinkVertically() + fadeOut() + ) { + Column { + Spacer(modifier = Modifier.height(16.dp)) + + MifosOutlinedTextField( + value = maximumOverdraftAmount, + onValueChange = { maximumOverdraftAmount = it }, + label = stringResource(id = R.string.maxoverdraft), + error = null, + keyboardType = KeyboardType.Number + ) + + Spacer(modifier = Modifier.height(16.dp)) + + MifosOutlinedTextField( + value = nominalAnnualInterestOverdraft, + onValueChange = { nominalAnnualInterestOverdraft = it }, + label = stringResource(id = R.string.nominal_overdraft), + error = null, + keyboardType = KeyboardType.Number + ) + + Spacer(modifier = Modifier.height(16.dp)) + + MifosOutlinedTextField( + value = minimumOverdraftAmount, + onValueChange = { minimumOverdraftAmount = it }, + label = stringResource(id = R.string.min_overdraft), + error = null, + keyboardType = KeyboardType.Number + ) + } + } + + Spacer(modifier = Modifier.height(16.dp)) + + Button( + modifier = Modifier + .fillMaxWidth() + .heightIn(44.dp) + .padding(horizontal = 16.dp), + contentPadding = PaddingValues(), + colors = ButtonDefaults.buttonColors( + containerColor = if (isSystemInDarkTheme()) BluePrimaryDark else BluePrimary + ), + onClick = { + if (Network.isOnline(context)) { + val savingsPayload = SavingsPayload() + + savingsPayload.externalId = externalId + savingsPayload.locale = "en" + savingsPayload.submittedOnDate = SimpleDateFormat( + "dd MMMM yyyy", Locale.getDefault() + ).format(submittedOnDate) + savingsPayload.dateFormat = "dd MMMM yyyy" + if (isGroupAccount) { + savingsPayload.groupId = groupId + } else { + savingsPayload.clientId = clientId + } + savingsPayload.productId = selectedSavingsProductID + savingsPayload.fieldOfficerId = fieldOfficerId + savingsPayload.nominalAnnualInterestRate = nominalAnnualInterest + savingsPayload.allowOverdraft = overDraftAllowed + savingsPayload.nominalAnnualInterestRateOverdraft = nominalAnnualInterestOverdraft + savingsPayload.overdraftLimit = maximumOverdraftAmount + savingsPayload.minOverdraftForInterestCalculation = minimumOverdraftAmount + savingsPayload.enforceMinRequiredBalance = enforceMinimumBalance + savingsPayload.minRequiredOpeningBalance = minimumRequiredBalance + + createSavingsAccount.invoke(savingsPayload) + } else { + Toast.makeText( + context, + context.resources.getString(R.string.error_not_connected_internet), + Toast.LENGTH_SHORT + ).show() + } + } + ) { + Text(text = stringResource(id = R.string.submit)) + } + } +} + + +class SavingsAccountScreenPreviewProvider : PreviewParameterProvider { + override val values: Sequence + get() = sequenceOf( + SavingAccountUiState.ShowProgress, + SavingAccountUiState.LoadAllSavings(SavingProductsAndTemplate( + mProductSavings = listOf( + ProductSavings( + id = 0, + name = "Product" + ) + ), + mSavingProductsTemplate = SavingProductsTemplate() + )), + SavingAccountUiState.ShowFetchingErrorString("F"), + SavingAccountUiState.ShowSavingsAccountCreatedSuccessfully(Savings()), + SavingAccountUiState.ShowFetchingError(R.string.savings_account_submitted_for_approval) + ) +} + +@Composable +@Preview(showSystemUi = true) +fun PreviewSavingsAccountScreen( + @PreviewParameter(SavingsAccountScreenPreviewProvider::class) savingAccountUiState: SavingAccountUiState +) { + SavingsAccountScreen( + uiState = savingAccountUiState, + savingProductsTemplate = SavingProductsTemplate(), + onSavingsProductSelected = { } , + navigateBack = { }, + onRetry = { }, + fetchTemplate = { }, + isGroupAccount = true, + clientId = 0, + groupId = 0 + ) { + + } +} \ No newline at end of file diff --git a/mifosng-android/src/main/res/layout/fragment_add_savings_account.xml b/mifosng-android/src/main/res/layout/fragment_add_savings_account.xml index 9c368e659b3..0f7bd051b58 100755 --- a/mifosng-android/src/main/res/layout/fragment_add_savings_account.xml +++ b/mifosng-android/src/main/res/layout/fragment_add_savings_account.xml @@ -6,11 +6,11 @@ android:outAnimation="@android:anim/fade_out"> - + + + + + @@ -193,7 +193,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="10dp" - android:checked="false" + android:checked="true" android:paddingTop="10dp" android:text="@string/saving_overdraft_allowed" /> @@ -222,7 +222,7 @@ android:inputType="number" android:maxLines="1" android:paddingBottom="16dp" - android:visibility="gone" /> + android:visibility="visible" /> @@ -236,7 +236,7 @@ android:inputType="number" android:maxLines="1" android:paddingBottom="16dp" - android:visibility="gone" /> + android:visibility="visible" /> diff --git a/mifosng-android/src/main/res/navigation/nav_graph.xml b/mifosng-android/src/main/res/navigation/nav_graph.xml index 8c0006b1e38..84c79bb01c8 100644 --- a/mifosng-android/src/main/res/navigation/nav_graph.xml +++ b/mifosng-android/src/main/res/navigation/nav_graph.xml @@ -194,7 +194,7 @@ - @@ -204,7 +204,7 @@ - + durée du prêt sélectionnez un terme de prêt intérêt annuel nominal - soumis le + soumis le enquête créer un client ajouter un compte d\'épargne diff --git a/mifosng-android/src/main/res/values-hi/strings.xml b/mifosng-android/src/main/res/values-hi/strings.xml index d384a4f8917..04f69dee3f9 100644 --- a/mifosng-android/src/main/res/values-hi/strings.xml +++ b/mifosng-android/src/main/res/values-hi/strings.xml @@ -392,7 +392,7 @@ ट्रैकिंग रोकें जमा करें जमा करने की तारीख - जमा करने कि तिथी + जमा करने कि तिथी सर्वेक्षण जमा करें सर्वेक्षण जमा करी जा रही है सारांश पर जानकारी diff --git a/mifosng-android/src/main/res/values-kn/strings.xml b/mifosng-android/src/main/res/values-kn/strings.xml index 399568f344d..a4595172152 100644 --- a/mifosng-android/src/main/res/values-kn/strings.xml +++ b/mifosng-android/src/main/res/values-kn/strings.xml @@ -170,7 +170,7 @@ ಸಾಲ ಅವಧಿ ಸಾಲ ಅವಧಿಯನ್ನು ಆಯ್ಕೆಮಾಡಿ ನಾಮಮಾತ್ರ ವಾರ್ಷಿಕ ಆಸಕ್ತಿ - ಸಲ್ಲಿಸಲಾಗಿದೆ + ಸಲ್ಲಿಸಲಾಗಿದೆ ಸಮೀಕ್ಷೆ ಕ್ಲೈಂಟ್ ರಚಿಸಿ ಉಳಿತಾಯ ಖಾತೆ ಸೇರಿಸಿ diff --git a/mifosng-android/src/main/res/values-sw/strings.xml b/mifosng-android/src/main/res/values-sw/strings.xml index 2c0d7886754..45a1950093b 100644 --- a/mifosng-android/src/main/res/values-sw/strings.xml +++ b/mifosng-android/src/main/res/values-sw/strings.xml @@ -33,7 +33,7 @@ Aina ya mkopo Cha Kimsingi Muda wa mkopo - Kiliwasilishwa siku ya + Kiliwasilishwa siku ya Tarehe ya uanzishaji Ofisi Kundi diff --git a/mifosng-android/src/main/res/values-zh/strings.xml b/mifosng-android/src/main/res/values-zh/strings.xml index d8970b7c957..e556b08932a 100755 --- a/mifosng-android/src/main/res/values-zh/strings.xml +++ b/mifosng-android/src/main/res/values-zh/strings.xml @@ -47,7 +47,7 @@ 贷款期限 选择贷款期限 名义年利率 - 提交 + 提交 激活日期 办公室 群组 diff --git a/mifosng-android/src/main/res/values/strings.xml b/mifosng-android/src/main/res/values/strings.xml index c966b98d994..da996d14053 100755 --- a/mifosng-android/src/main/res/values/strings.xml +++ b/mifosng-android/src/main/res/values/strings.xml @@ -47,7 +47,7 @@ Loan Term Select Loan Term Nominal annual interest - Submitted On + Submitted On Activation Date Office Group @@ -925,6 +925,7 @@ GOT IT + Go Back FINISH Filter out the results using this dropdown To get the result matching exactly the keyword entered.\n Simply check this box