documentation added properly. (#2979)

This commit is contained in:
Sayam Sharma 2025-10-17 16:04:26 +05:30 committed by GitHub
parent 7702fcb6ea
commit ddab8ad444
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
25 changed files with 689 additions and 17 deletions

View File

@ -10,7 +10,7 @@
</option>
<option name="taskNames">
<list>
<option value=":cmp-web:wasmJsBrowserRun" />
<option value=":cmp-web:wasmJsBrowserDevelopmentRun" />
</list>
</option>
<option name="vmOptions" />

0
ci-prepush.sh Normal file → Executable file
View File

View File

@ -0,0 +1,20 @@
/*
* Copyright 2025 Mifos Initiative
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*
* See https://github.com/openMF/mobile-mobile/blob/master/LICENSE.md
*/
package cmp.navigation.authenticated
import org.mifos.mobile.feature.beneficiary.beneficiaryApplicationConfirmation.BeneficiaryApplicationConfirmationNavRoute
import org.mifos.mobile.feature.loan.application.confirmDetails.ConfirmDetailsRoute
import org.mifos.mobile.feature.transfer.process.transferProcess.TransferProcessRoute
actual fun getPopRules(): Map<String, Int> = mapOf(
ConfirmDetailsRoute::class.qualifiedName.orEmpty() to 2,
TransferProcessRoute::class.qualifiedName.orEmpty() to 2,
BeneficiaryApplicationConfirmationNavRoute::class.qualifiedName.orEmpty() to 2,
)

View File

@ -0,0 +1,20 @@
/*
* Copyright 2025 Mifos Initiative
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*
* See https://github.com/openMF/mobile-mobile/blob/master/LICENSE.md
*/
package cmp.navigation.authenticated
import org.mifos.mobile.feature.beneficiary.beneficiaryApplicationConfirmation.BeneficiaryApplicationConfirmationNavRoute
import org.mifos.mobile.feature.loan.application.confirmDetails.ConfirmDetailsRoute
import org.mifos.mobile.feature.transfer.process.transferProcess.TransferProcessRoute
actual fun getPopRules(): Map<String, Int> = mapOf(
ConfirmDetailsRoute::class.qualifiedName.orEmpty() to 2,
TransferProcessRoute::class.qualifiedName.orEmpty() to 2,
BeneficiaryApplicationConfirmationNavRoute::class.qualifiedName.orEmpty() to 2,
)

View File

@ -33,7 +33,6 @@ import org.mifos.mobile.feature.accounts.accounts.navigateToAccountsScreen
import org.mifos.mobile.feature.auth.login.navigateToLoginScreen
import org.mifos.mobile.feature.auth.navigation.AuthGraphRoute
import org.mifos.mobile.feature.beneficiary.beneficiaryApplication.navigateToManualBeneficiaryAddScreen
import org.mifos.mobile.feature.beneficiary.beneficiaryApplicationConfirmation.BeneficiaryApplicationConfirmationNavRoute
import org.mifos.mobile.feature.beneficiary.navigation.BeneficiaryNavRoute
import org.mifos.mobile.feature.beneficiary.navigation.beneficiaryNavGraph
import org.mifos.mobile.feature.beneficiary.navigation.navigateToBeneficiaryNavGraph
@ -41,7 +40,6 @@ import org.mifos.mobile.feature.charge.charges.navigateToClientChargeScreen
import org.mifos.mobile.feature.charge.navigation.clientChargeNavGraph
import org.mifos.mobile.feature.charge.navigation.navigateToChargeGraph
import org.mifos.mobile.feature.home.navigation.HomeNavigationDestination
import org.mifos.mobile.feature.loan.application.confirmDetails.ConfirmDetailsRoute
import org.mifos.mobile.feature.loan.application.navigation.loanApplicationNavGraph
import org.mifos.mobile.feature.loan.application.navigation.navigateToLoanApplicationGraph
import org.mifos.mobile.feature.loanaccount.loanAccountDetails.navigateToLoanAccountDetailsScreen
@ -69,13 +67,14 @@ import org.mifos.mobile.feature.status.navigation.statusDestination
import org.mifos.mobile.feature.third.party.transfer.navigation.TptNavigationDestination
import org.mifos.mobile.feature.transfer.process.makeTransfer.makeTransferDestination
import org.mifos.mobile.feature.transfer.process.makeTransfer.navigateToMakeTransferScreen
import org.mifos.mobile.feature.transfer.process.transferProcess.TransferProcessRoute
import org.mifos.mobile.feature.transfer.process.transferProcess.navigateToTransferProcessScreen
import org.mifos.mobile.feature.transfer.process.transferProcess.transferProcessDestination
@Serializable
internal data object AuthenticatedGraphRoute
expect fun getPopRules(): Map<String, Int>
internal fun NavController.navigateToAuthenticatedGraph(navOptions: NavOptions? = null) {
navigate(route = AuthenticatedGraphRoute, navOptions = navOptions)
}
@ -471,11 +470,7 @@ fun NavController.navigateToBeneficiaryFromStatus() {
}
fun NavController.popScreens(
popRules: Map<String, Int> = mapOf(
ConfirmDetailsRoute::class.qualifiedName.orEmpty() to 2,
TransferProcessRoute::class.qualifiedName.orEmpty() to 2,
BeneficiaryApplicationConfirmationNavRoute::class.qualifiedName.orEmpty() to 2,
),
popRules: Map<String, Int> = getPopRules(),
) {
val lastEntry = previousBackStackEntry?.destination?.route

View File

@ -0,0 +1,20 @@
/*
* Copyright 2025 Mifos Initiative
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*
* See https://github.com/openMF/mobile-mobile/blob/master/LICENSE.md
*/
package cmp.navigation.authenticated
import org.mifos.mobile.feature.beneficiary.beneficiaryApplicationConfirmation.BeneficiaryApplicationConfirmationNavRoute
import org.mifos.mobile.feature.loan.application.confirmDetails.ConfirmDetailsRoute
import org.mifos.mobile.feature.transfer.process.transferProcess.TransferProcessRoute
actual fun getPopRules(): Map<String, Int> = mapOf(
ConfirmDetailsRoute::class.qualifiedName.orEmpty() to 2,
TransferProcessRoute::class.qualifiedName.orEmpty() to 2,
BeneficiaryApplicationConfirmationNavRoute::class.qualifiedName.orEmpty() to 2,
)

View File

@ -0,0 +1,16 @@
/*
* Copyright 2025 Mifos Initiative
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*
* See https://github.com/openMF/mobile-mobile/blob/master/LICENSE.md
*/
package cmp.navigation.authenticated
actual fun getPopRules(): Map<String, Int> = mapOf(
"cmp.navigation.authenticated.ConfirmDetailsRoute" to 2,
"cmp.navigation.authenticated.TransferProcessRoute" to 2,
"cmp.navigation.authenticated.BeneficiaryApplicationConfirmationNavRoute" to 2,
)

View File

@ -0,0 +1,16 @@
/*
* Copyright 2025 Mifos Initiative
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*
* See https://github.com/openMF/mobile-mobile/blob/master/LICENSE.md
*/
package cmp.navigation.authenticated
actual fun getPopRules(): Map<String, Int> = mapOf(
"cmp.navigation.authenticated.ConfirmDetailsRoute" to 2,
"cmp.navigation.authenticated.TransferProcessRoute" to 2,
"cmp.navigation.authenticated.BeneficiaryApplicationConfirmationNavRoute" to 2,
)

View File

@ -59,6 +59,10 @@ kotlin {
}
}
tasks.register("jsBrowserRun") {
dependsOn("jsBrowserDevelopmentRun")
}
compose.resources {
publicResClass = true
generateResClass = always

View File

@ -50,6 +50,13 @@ import org.mifos.mobile.core.designsystem.theme.MifosTypography
import org.mifos.mobile.core.model.enums.BeneficiaryState
import org.mifos.mobile.core.ui.component.MifosDropDownTextField
/**
* Composable function to display a beneficiary application form.
*
* @param state The current state of the beneficiary application form.
* @param onAction A callback to handle actions from the form.
* @param modifier The modifier to apply to the composable.
*/
@Composable
@Suppress("CyclomaticComplexMethod", "ComplexCondition")
internal fun BeneficiaryApplicationContent(

View File

@ -15,7 +15,16 @@ import androidx.navigation.NavOptions
import kotlinx.serialization.Serializable
import org.mifos.mobile.core.model.enums.BeneficiaryState
import org.mifos.mobile.core.ui.composableWithSlideTransitions
/**
* Data class representing the navigation route for the beneficiary application screen.
*
* @property beneficiaryId the ID of the beneficiary.
* @property beneficiaryState the state of the beneficiary.
* @property name the name of the beneficiary.
* @property accountType the account type of the beneficiary.
* @property accountNumber the account number of the beneficiary.
* @property officeName the office name of the beneficiary.
*/
@Serializable
data class BeneficiaryApplicationNavRoute(
val beneficiaryId: Long = -1L,
@ -26,6 +35,17 @@ data class BeneficiaryApplicationNavRoute(
val officeName: String = "",
)
/**
* Navigate to the manual beneficiary add screen.
*
* @param beneficiaryId the ID of the beneficiary.
* @param name the name of the beneficiary.
* @param accountType the account type of the beneficiary.
* @param accountNumber the account number of the beneficiary.
* @param officeName the office name of the beneficiary.
* @param beneficiaryState the state of the beneficiary.
* @param navOptions the navigation options.
*/
fun NavController.navigateToManualBeneficiaryAddScreen(
beneficiaryId: Long = -1L,
name: String = "",
@ -48,6 +68,13 @@ fun NavController.navigateToManualBeneficiaryAddScreen(
)
}
/**
* Composable function to define the manual beneficiary add destination in the navigation graph.
*
* @param navigateBack a function to navigate back to the previous screen.
* @param navigateToQR a function to navigate to the QR code screen.
* @param navigateToConfirmationScreen a function to navigate to the confirmation screen.
*/
fun NavGraphBuilder.manualBeneficiaryAddDestination(
navigateBack: () -> Unit,
navigateToQR: () -> Unit,

View File

@ -31,6 +31,15 @@ import org.mifos.mobile.core.ui.component.MifosProgressIndicator
import org.mifos.mobile.core.ui.utils.EventsEffect
import org.mifos.mobile.core.ui.utils.ScreenUiState
/**
* Composable function to display the beneficiary application screen.
*
* @param navigateBack a function to navigate back to the previous screen.
* @param navigateToQR a function to navigate to the QR code screen.
* @param navigateToConfirmationScreen a function to navigate to the confirmation screen.
* @param modifier the modifier to apply to the composable.
* @param viewModel the [BeneficiaryApplicationViewModel] to use for the composable.
*/
@Composable
internal fun BeneficiaryApplicationScreen(
navigateBack: () -> Unit,
@ -86,6 +95,12 @@ internal fun BeneficiaryApplicationScreen(
)
}
/**
* Composable function to display dialogs for the beneficiary application screen.
*
* @param state the current state of the screen.
* @param onAction a function to handle user actions.
*/
@Composable
private fun BeneficiaryApplicationDialogs(
state: BeneficiaryApplicationState,
@ -104,6 +119,16 @@ private fun BeneficiaryApplicationDialogs(
}
}
/**
* Composable function to display the beneficiary application screen.
*
* It displays a progress indicator when the UI state is loading, a network error component
* when the network status is false, and the beneficiary application content when the UI state is success.
*
* @param state the current state of the screen.
* @param onAction a function to handle user actions.
* @param modifier the modifier to apply to the composable.
*/
@Composable
private fun BeneficiaryApplicationScreen(
state: BeneficiaryApplicationState,

View File

@ -379,6 +379,31 @@ internal class BeneficiaryApplicationViewModel(
}
}
/**
* Data class to represent the state of the beneficiary application screen.
*
* @param topBarTitle the title to display in the top bar.
* @param beneficiaryId the ID of the beneficiary.
* @param networkUnavailable a flag to indicate if the network is unavailable.
* @param template the beneficiary template.
* @param beneficiary the beneficiary.
* @param beneficiaryState the state of the beneficiary.
* @param dialogState the state of the dialog.
* @param accountTypeError the error message for the account type.
* @param accountNumberError the error message for the account number.
* @param officeNameError the error message for the office name.
* @param transferLimitError the error message for the transfer limit.
* @param beneficiaryNameError the error message for the beneficiary name.
* @param accountType the account type of the beneficiary.
* @param accountNumber the account number of the beneficiary.
* @param officeName the office name of the beneficiary.
* @param transferLimit the transfer limit of the beneficiary.
* @param beneficiaryName the beneficiary name.
* @param networkStatus the network status.
* @param uiState the UI state of the screen.
* @param shoeOverlay the overlay to display.
*/
data class BeneficiaryApplicationState(
val topBarTitle: StringResource = Res.string.add_beneficiary,
val beneficiaryId: Long = -1L,
@ -414,8 +439,16 @@ data class BeneficiaryApplicationState(
beneficiaryName.isNotEmpty()
}
/**
* Data class to represent the events of the beneficiary application screen.
*
* @param Navigate navigate to the next screen.
* @param SubmitBeneficiary submit the beneficiary application.
* @param NavigateToQR navigate to the QR screen.
*/
sealed interface BeneficiaryApplicationEvent {
data object Navigate : BeneficiaryApplicationEvent
data class SubmitBeneficiary(
val beneficiaryId: Long,
val beneficiaryState: String,
@ -425,20 +458,39 @@ sealed interface BeneficiaryApplicationEvent {
val accountNumber: String,
val transferLimit: Int,
) : BeneficiaryApplicationEvent
data object NavigateToQR : BeneficiaryApplicationEvent
}
/***
* Data class to represent the actions of the beneficiary application screen.
*
* @param LoadBeneficiaryTemplate load the beneficiary template.
* @param SubmitBeneficiary submit the beneficiary application.
* @param OnNavigate navigate to the next screen.
* @param OnRetry retry the operation.
* @param NavigateToQR navigate to the QR screen.
*/
sealed interface BeneficiaryApplicationAction {
data object LoadBeneficiaryTemplate : BeneficiaryApplicationAction
data object SubmitBeneficiary : BeneficiaryApplicationAction
data object OnNavigate : BeneficiaryApplicationAction
data object OnRetry : BeneficiaryApplicationAction
data object NavigateToQR : BeneficiaryApplicationAction
data class OnAccountTypeChanged(val accountType: Int) : BeneficiaryApplicationAction
data class OnAccountNumberChanged(val accountNumber: String) : BeneficiaryApplicationAction
data class OnOfficeNameChanged(val officeName: String) : BeneficiaryApplicationAction
data class OnTransferLimitChanged(val transferLimit: String) : BeneficiaryApplicationAction
data class OnBeneficiaryNameChanged(val beneficiaryName: String) : BeneficiaryApplicationAction
data class ReceiveNetworkStatus(val isOnline: Boolean) : BeneficiaryApplicationAction

View File

@ -17,6 +17,17 @@ import androidx.navigation.NavOptions
import kotlinx.serialization.Serializable
import org.mifos.mobile.core.ui.composableWithSlideTransitions
/**
* Data class representing the navigation route for the beneficiary application confirmation screen.
*
* @property beneficiaryId the ID of the beneficiary.
* @property beneficiaryState the state of the beneficiary.
* @property name the name of the beneficiary.
* @property officeName the office name of the beneficiary.
* @property accountType the account type of the beneficiary.
* @property accountNumber the account number of the beneficiary.
* @property transferLimit the transfer limit of the beneficiary.
*/
@Serializable
data class BeneficiaryApplicationConfirmationNavRoute(
val beneficiaryId: Long = -1L,
@ -28,6 +39,18 @@ data class BeneficiaryApplicationConfirmationNavRoute(
val transferLimit: Int,
)
/**
* Navigates to the beneficiary application confirmation screen.
*
* @param beneficiaryId the ID of the beneficiary.
* @param beneficiaryState the state of the beneficiary.
* @param name the name of the beneficiary.
* @param officeName the office name of the beneficiary.
* @param accountType the account type of the beneficiary.
* @param accountNumber the account number of the beneficiary.
* @param transferLimit the transfer limit of the beneficiary.
* @param navOptions the navigation options.
*/
fun NavController.navigateToBeneficiaryApplicationAddConfirmationScreen(
beneficiaryId: Long = -1L,
beneficiaryState: String,
@ -52,6 +75,13 @@ fun NavController.navigateToBeneficiaryApplicationAddConfirmationScreen(
)
}
/**
* Adds a destination to the navigation graph for the beneficiary application confirmation screen.
*
* @param navigateBack a function to navigate back to the previous screen.
* @param navigateToStatusScreen a function to navigate to the status screen.
* @param navigateToAuthenticateScreen a function to navigate to the authentication screen.
*/
fun NavGraphBuilder.beneficiaryAddConfirmationDestination(
navigateBack: () -> Unit,
navigateToStatusScreen: (String, String, String, String, String) -> Unit,

View File

@ -38,6 +38,14 @@ import org.mifos.mobile.core.ui.component.MifosProgressIndicatorOverlay
import org.mifos.mobile.core.ui.utils.EventsEffect
import org.mifos.mobile.core.ui.utils.ScreenUiState
/**
* Composable function to render the beneficiary application confirmation screen.
*
* @param navigateBack a function to navigate back to the previous screen.
* @param navigateToStatusScreen a function to navigate to the status screen.
* @param navigateToAuthenticateScreen a function to navigate to the authenticate screen.
* @param viewModel the view model for the beneficiary application confirmation screen.
*/
@Composable
internal fun BeneficiaryApplicationConfirmationScreen(
navigateBack: () -> Unit,
@ -80,6 +88,11 @@ internal fun BeneficiaryApplicationConfirmationScreen(
)
}
/**
* Composable function to display error dialogs for the Beneficiary Application Confirmation screen.
* @param state the state of the Beneficiary Application Confirmation screen.
* @return a Unit or null if no dialog should be shown.
*/
@Composable
private fun BeneficiaryApplicationConfirmationScreenDialogs(
state: BeneficiaryApplicationConfirmationState,
@ -94,6 +107,14 @@ private fun BeneficiaryApplicationConfirmationScreenDialogs(
}
}
/**
* Composable function to render the content of the Beneficiary Application confirmation screen.
*
* @param state the state of the Beneficiary Application confirmation screen.
* @param modifier the modifier to apply to the content.
* @param onAction the action to perform when the confirm button is clicked.
* @return a Unit or null if no content should be rendered.
*/
@Composable
fun BeneficiaryApplicationConfirmationScreenContent(
state: BeneficiaryApplicationConfirmationState,

View File

@ -164,6 +164,11 @@ internal class BeneficiaryApplicationConfirmationViewModel(
}
}
/**
* Handles the result of the beneficiary creation API call.
* If the API call is successful, navigates the user to the beneficiary status screen.
* If the API call fails, navigates the user to the previous screen with an error message.
*/
private fun processSubmitBeneficiaryResult(response: DataState<String>) {
viewModelScope.launch {
when (response) {
@ -226,6 +231,12 @@ internal class BeneficiaryApplicationConfirmationViewModel(
}
}
/**
* Processes the result of an update beneficiary API call.
* Handles success, failure and loading states.
* Shows an overlay during the loading state.
* Shows a success or failure message on the status screen depending on the result.
*/
private fun processUpdateBeneficiaryResult(response: DataState<String>) {
viewModelScope.launch {
when (response) {
@ -325,6 +336,11 @@ internal class BeneficiaryApplicationConfirmationViewModel(
}
}
/**
* Initializes the map details state variable with the route details.
*
* @param savedStateHandle the SavedStateHandle containing the route details.
*/
private suspend fun initializeMapDetails() {
val route = savedStateHandle.toRoute<BeneficiaryApplicationConfirmationNavRoute>()
val details = mapOf(
@ -363,6 +379,25 @@ internal class BeneficiaryApplicationConfirmationViewModel(
}
}
/**
* Represents the state of the Beneficiary Application Confirmation screen.
*
* @param details the map of beneficiary details to display on the screen.
* @param topBarTitle the title to display on the top bar of the screen.
* @param beneficiaryId the ID of the beneficiary being updated or added.
* @param name the name of the beneficiary.
* @param officeName the name of the office where the beneficiary is registered.
* @param accountType the type of account the beneficiary has (e.g. savings, loan).
* @param accountNumber the account number of the beneficiary.
* @param transferLimit the transfer limit of the beneficiary.
* @param networkUnavailable indicates whether the network is unavailable.
* @param beneficiaryState the state of the beneficiary (e.g. updating, adding).
* @param dialogState the state of any dialogs to display on the screen.
* @param uiState the current UI state of the screen (e.g. loading, error, success).
* @param showOverlay indicates whether to show an overlay on the screen.
* @param networkStatus indicates whether the network is available.
*/
data class BeneficiaryApplicationConfirmationState(
val details: Map<StringResource, String> = emptyMap(),
val topBarTitle: StringResource = Res.string.add_beneficiary,
@ -386,20 +421,47 @@ data class BeneficiaryApplicationConfirmationState(
}
}
/*
* Represents the events that can occur on the Beneficiary Application Confirmation screen.
*/
sealed interface BeneficiaryApplicationConfirmationEvent {
/**
* Represents the event of navigating back to the previous screen.
*/
data object Navigate : BeneficiaryApplicationConfirmationEvent
/**
* Represents the event of navigating to the Beneficiary Status screen.
*
* @param eventType the type of event (e.g. success, error).
* @param eventDestination the destination to navigate to.
* @param title the title to display on the screen.
* @param subtitle the subtitle to display on the screen.
* @param buttonText the text to display on the button.
*/
data class NavigateToStatus(
val eventType: String,
val eventDestination: String,
val title: String,
val subtitle: String,
val buttonText: String,
) : BeneficiaryApplicationConfirmationEvent
data class NavigateToAuthenticate(
val status: String = EventType.SUCCESS.name,
) : BeneficiaryApplicationConfirmationEvent
}
/**
* Represents the actions that can be performed on the Beneficiary Application Confirmation screen.
*
* @param SubmitBeneficiary the action of submitting the beneficiary application.
* @param ReceiveNetworkStatus the action of receiving the network status.
* @param OnNavigate the action of navigating back to the previous screen.
*/
sealed interface BeneficiaryApplicationConfirmationAction {
data object SubmitBeneficiary : BeneficiaryApplicationConfirmationAction
@ -408,9 +470,18 @@ sealed interface BeneficiaryApplicationConfirmationAction {
data object OnNavigate : BeneficiaryApplicationConfirmationAction
/**
* Represents the internal actions that can be performed on the Beneficiary Application Confirmation screen.
*
* @param ReceiveAuthenticationResult the action of receiving the authentication result.
* @param ReceiveSubmitBeneficiary the action of receiving the result of submitting the beneficiary application.
* @param ReceiveUpdateBeneficiary the action of receiving the result of updating the beneficiary application.
*/
sealed interface Internal : BeneficiaryApplicationConfirmationAction {
data class ReceiveAuthenticationResult(val result: Boolean) : Internal
data class ReceiveSubmitBeneficiary(val result: DataState<String>) : Internal
data class ReceiveUpdateBeneficiary(val result: DataState<String>) : Internal
}
}

View File

@ -43,6 +43,13 @@ import org.mifos.mobile.core.designsystem.theme.MifosMobileTheme
import org.mifos.mobile.core.designsystem.theme.MifosTypography
import org.mifos.mobile.core.ui.component.MifosBeneficiaryTopCard
/**
* Composable function to display beneficiary details.
*
* @param state The state of the beneficiary screen.
* @param onAction The callback to handle actions on the beneficiary screen.
* @param modifier The modifier for the composable.
*/
@Composable
internal fun BeneficiaryDetailContent(
state: BeneficiaryDetailState?,
@ -116,6 +123,12 @@ internal fun BeneficiaryDetailContent(
}
}
/**
* A composable function to display a row of actions for the beneficiary detail screen.
*
* @param onAction A callback to handle actions from the beneficiary detail screen.
* @param modifier The modifier to apply to the composable.
*/
@Composable
internal fun ActionBar(
onAction: (BeneficiaryDetailAction) -> Unit,

View File

@ -35,6 +35,15 @@ import org.mifos.mobile.core.ui.component.MifosProgressIndicator
import org.mifos.mobile.core.ui.utils.EventsEffect
import org.mifos.mobile.core.ui.utils.ScreenUiState
/**
* A composable function to display the beneficiary detail screen.
*
* @param navigateBack A callback to navigate back from the beneficiary detail screen.
* @param updateBeneficiary A callback to update a beneficiary.
* @param modifier The modifier to apply to the composable.
* @param viewModel The view model to use for the beneficiary detail screen.
*/
@Composable
internal fun BeneficiaryDetailScreen(
navigateBack: () -> Unit,
@ -69,6 +78,12 @@ internal fun BeneficiaryDetailScreen(
)
}
/**
* A composable function to display the beneficiary detail dialogs.
*
* @param state The view state to use for the beneficiary detail dialogs.
* @param onAction A callback to handle the dialog actions.
*/
@Composable
private fun BeneficiaryDialogs(
state: BeneficiaryDetailState,
@ -100,6 +115,13 @@ private fun BeneficiaryDialogs(
}
}
/**
* A composable function to display the beneficiary detail screen.
*
* @param state The view state to use for the beneficiary detail screen.
* @param onAction A callback to handle the actions from the view state.
* @param modifier The modifier to apply to the composable.
*/
@Composable
private fun BeneficiaryDetailScreen(
state: BeneficiaryDetailState,

View File

@ -28,6 +28,13 @@ import org.mifos.mobile.core.model.entity.beneficiary.Beneficiary
import org.mifos.mobile.core.ui.utils.BaseViewModel
import org.mifos.mobile.core.ui.utils.ScreenUiState
/**
* A view model for the beneficiary detail screen.
*
* @param beneficiaryRepositoryImp The repository for beneficiary data.
* @param networkMonitor The network monitor to use for network status.
* @param savedStateHandle The saved state handle to use for navigation.
*/
internal class BeneficiaryDetailViewModel(
private val beneficiaryRepositoryImp: BeneficiaryRepository,
private val networkMonitor: NetworkMonitor,
@ -41,6 +48,9 @@ internal class BeneficiaryDetailViewModel(
},
) {
/**
* Initialize the view model.
*/
init {
observeNetwork()
}
@ -84,14 +94,27 @@ internal class BeneficiaryDetailViewModel(
}
}
/**
* Updates the view model state using the provided lambda transformation.
* @param update The lambda transformation to apply to the current state.
*/
private fun updateState(update: (BeneficiaryDetailState) -> BeneficiaryDetailState) {
mutableStateFlow.update(update)
}
/**
* Updates the beneficiary dialog state in the view model state.
*
* @param dialogState The new dialog state to set. If null, the dialog state will be cleared.
*/
private fun setDialogState(dialogState: BeneficiaryDetailState.DialogState?) {
updateState { it.copy(beneficiaryDialog = dialogState) }
}
/*
* Update the view model state to show a loading state and then
* an internal action to handle the list is sent.
* */
private fun loadBeneficiary() {
updateState {
it.copy(
@ -105,6 +128,13 @@ internal class BeneficiaryDetailViewModel(
}
}
/**
* Handles the response from the beneficiary list API and updates the view model state accordingly.
* If the response is successful, the view model state is updated to show a success state and
* the beneficiary is updated to the one with the matching ID.
*
* @param beneficiary The response from the beneficiary list API.
*/
private fun handleResponse(beneficiary: DataState<List<Beneficiary>>) {
when (beneficiary) {
DataState.Loading -> {
@ -138,6 +168,14 @@ internal class BeneficiaryDetailViewModel(
}
}
/**
* Deletes a beneficiary with the given ID.
*
* This function updates the view model state to show an overlay and then
* sends an internal action to handle the response from the delete beneficiary API.
*
* @param beneficiaryId The ID of the beneficiary to delete.
*/
private fun deleteBeneficiary(beneficiaryId: Long?) {
viewModelScope.launch {
updateState {
@ -154,6 +192,16 @@ internal class BeneficiaryDetailViewModel(
}
}
/**
* Processes the result of the delete beneficiary API.
*
* If the response is loading, the view model state is updated to show an overlay.
* If the response is an error, the view model state is updated to show an error state and a dialog
* is shown with a generic error message.
* If the response is successful, the view model state is updated to navigate back to the previous screen.
*
* @param response The response from the delete beneficiary API.
*/
private fun processDeleteBeneficiaryResult(response: DataState<String>) {
viewModelScope.launch {
when (response) {
@ -183,6 +231,11 @@ internal class BeneficiaryDetailViewModel(
}
}
/**
* Handles actions from the UI.
*
* @param action The action to handle.
*/
override fun handleAction(action: BeneficiaryDetailAction) {
when (action) {
is BeneficiaryDetailAction.ReceiveNetworkStatus -> handleNetworkStatus(action.isOnline)
@ -211,6 +264,9 @@ internal class BeneficiaryDetailViewModel(
}
}
/**
* Shows a confirmation dialog before deleting a beneficiary.
*/
private fun showDeleteConfirmation() {
viewModelScope.launch {
val message = getString(Res.string.delete_beneficiary_confirmation)
@ -223,6 +279,16 @@ internal class BeneficiaryDetailViewModel(
}
}
/**
* Represents the state of the Beneficiary Detail screen.
*
* @property beneficiaryId The ID of the beneficiary to display.
* @property beneficiary The beneficiary to display.
* @property beneficiaryDialog The dialog state of the beneficiary detail screen.
* @property networkStatus The current network status of the device.
* @property uiState The current UI state of the beneficiary detail screen.
* @property showOverlay Whether to show the overlay or not.
*/
data class BeneficiaryDetailState(
val beneficiaryId: Long = -1L,
val beneficiary: Beneficiary? = null,
@ -239,22 +305,52 @@ data class BeneficiaryDetailState(
}
}
/*
* Represents the events that can be triggered from the Beneficiary Detail screen.
*
* @property NavigateBack Navigates back to the previous screen.
* @property UpdateBeneficiary Updates the beneficiary with the given ID.
* */
sealed interface BeneficiaryDetailEvent {
data object NavigateBack : BeneficiaryDetailEvent
data class UpdateBeneficiary(val beneficiaryId: Long) : BeneficiaryDetailEvent
}
/*
* Represents the actions that can be triggered from the Beneficiary Detail screen.
*
* @property OnRefresh Refreshes the beneficiary list.
* @property OnUpdateBeneficiary Updates the beneficiary with the given ID.
* @property DeleteBeneficiary Deletes the beneficiary with the given ID.
* @property OnNavigate Navigates to the beneficiary list screen.
* @property ErrorDialogDismiss Dismisses the error dialog.
* @property ShowDeleteConfirmation Shows the delete confirmation dialog.
* @property ReceiveNetworkStatus Receives the network status.
* @property Internal Internal actions.
* */
sealed interface BeneficiaryDetailAction {
data object OnRefresh : BeneficiaryDetailAction
data object OnUpdateBeneficiary : BeneficiaryDetailAction
data object DeleteBeneficiary : BeneficiaryDetailAction
data object OnNavigate : BeneficiaryDetailAction
data object ErrorDialogDismiss : BeneficiaryDetailAction
data object ShowDeleteConfirmation : BeneficiaryDetailAction
data class ReceiveNetworkStatus(val isOnline: Boolean) : BeneficiaryDetailAction
sealed interface Internal : BeneficiaryDetailAction {
data class ReceiveBeneficiaryResult(val result: DataState<List<Beneficiary>>) : Internal
data class ReceiveDeleteBeneficiary(val result: DataState<String>) : Internal
}
}

View File

@ -17,11 +17,23 @@ import androidx.navigation.NavOptions
import kotlinx.serialization.Serializable
import org.mifos.mobile.core.ui.composableWithSlideTransitions
/**
* Represents the navigation route for the Beneficiary Detail screen.
*
* @property beneficiaryId The ID of the beneficiary to display.
*/
@Serializable
data class BeneficiaryDetailNavRoute(
val beneficiaryId: Long = -1L,
)
/**
* Navigates to the Beneficiary Detail screen.
*
* @param beneficiaryId The ID of the beneficiary to display.
* @param navOptions The navigation options to use for navigation.
*/
fun NavController.navigateToBeneficiaryDetailScreen(
beneficiaryId: Long = -1L,
navOptions: NavOptions? = null,
@ -29,6 +41,12 @@ fun NavController.navigateToBeneficiaryDetailScreen(
this.navigate(BeneficiaryDetailNavRoute(beneficiaryId), navOptions)
}
/**
* Adds a destination to the navigation graph for the Beneficiary Detail screen.
*
* @param navigateBack a function to navigate back to the previous screen.
* @param updateBeneficiary a function to update a beneficiary with the given ID.
*/
fun NavGraphBuilder.beneficiaryDetailScreenDestination(
navigateBack: () -> Unit,
updateBeneficiary: (beneficiaryId: Long) -> Unit,

View File

@ -19,10 +19,21 @@ import org.mifos.mobile.core.ui.composableWithPushTransitions
@Serializable
data object BeneficiaryListNavRoute
/**
* Navigates to the beneficiary list screen.
*/
fun NavController.navigateToBeneficiaryListScreen() {
this.navigate(BeneficiaryListNavRoute)
}
/**
* Adds a destination to the navigation graph for the beneficiary list screen.
*
* @param navigateBack a function to navigate back to the previous screen.
* @param addBeneficiaryClicked a function to navigate to the add beneficiary screen.
* @param onBeneficiaryItemClick a function to navigate to a beneficiary detail screen when a
* beneficiary item is clicked.
*/
fun NavGraphBuilder.beneficiaryListScreen(
navigateBack: () -> Unit,
addBeneficiaryClicked: () -> Unit,

View File

@ -75,7 +75,16 @@ import org.mifos.mobile.core.ui.component.MifosPoweredCard
import org.mifos.mobile.core.ui.component.MifosProgressIndicator
import org.mifos.mobile.core.ui.utils.EventsEffect
import org.mifos.mobile.core.ui.utils.ScreenUiState
/**
* Composable function to display the beneficiary list screen.
*
* @param navigateBack The callback to navigate back to the previous screen.
* @param addBeneficiaryClicked The callback to navigate to the add beneficiary screen.
* @param onBeneficiaryItemClick The callback to navigate to a beneficiary detail screen when a
* beneficiary item is clicked.
* @param modifier The modifier to apply to the composable.
* @param viewModel The view model to use for the beneficiary list screen.
*/
@Composable
internal fun BeneficiaryListScreen(
navigateBack: () -> Unit,
@ -113,6 +122,13 @@ internal fun BeneficiaryListScreen(
)
}
/**
* Composable function to display the dialogs for the beneficiary list screen.
*
* @param state the state of the beneficiary list screen.
* @param onAction the callback to handle user actions.
* @return a Unit or null if no dialog should be shown.
*/
@Composable
private fun BeneficiaryListDialog(
state: BeneficiaryListState,
@ -130,6 +146,13 @@ private fun BeneficiaryListDialog(
}
}
/**
* Composable function to display the beneficiary list screen.
*
* @param state The state of the beneficiary list screen.
* @param onAction The callback to handle user actions.
* @param modifier The modifier to apply to the composable function.
*/
@Composable
private fun BeneficiaryListScreen(
state: BeneficiaryListState,
@ -158,6 +181,13 @@ private fun BeneficiaryListScreen(
}
}
/**
* Composable function to display the beneficiary list content.
*
* @param state The state of the beneficiary list content.
* @param onAction The callback to handle user actions.
* @param modifier The modifier to apply to the composable function.
*/
@Composable
fun BeneficiaryListContent(
state: BeneficiaryListState,
@ -253,6 +283,12 @@ fun BeneficiaryListContent(
}
}
/**
* A composable function to display the action bar with add and filter buttons.
*
* @param onAction The callback to handle user actions.
* @param modifier The modifier to apply to the composable function.
*/
@Composable
internal fun ActionBar(
onAction: (BeneficiaryListAction) -> Unit,
@ -313,6 +349,13 @@ internal fun ActionBar(
}
}
/**
* A composable function to display the beneficiary filters.
*
* @param state The view state to use for the beneficiary filters.
* @param onAction A callback to handle user actions.
* @param modifier The modifier to apply to the composable function.
*/
@Composable
internal fun BeneficiaryFilters(
state: BeneficiaryListState,
@ -383,6 +426,17 @@ internal fun BeneficiaryFilters(
}
}
/**
* A composable function to display a filter section.
*
* @param title The title of the filter section.
* @param selectedFilters The list of selected filters.
* @param isExpanded Whether the filter section is expanded or not.
* @param onToggle The callback to toggle the filter section.
* @param filters The list of filters to display.
* @param onCheckChanged The callback to handle the check changed event of the filters.
* @param modifier The modifier to apply to the composable.
*/
@Composable
internal fun FilterSection(
title: String,

View File

@ -26,6 +26,12 @@ import org.mifos.mobile.core.model.entity.templates.beneficiary.BeneficiaryTempl
import org.mifos.mobile.core.ui.utils.BaseViewModel
import org.mifos.mobile.core.ui.utils.ScreenUiState
/**
* ViewModel for BeneficiaryListScreen
*
* @param beneficiaryRepositoryImp The repository for beneficiary data.
* @param networkMonitor The monitor for network connectivity.
*/
internal class BeneficiaryListViewModel(
private val beneficiaryRepositoryImp: BeneficiaryRepository,
private val networkMonitor: NetworkMonitor,
@ -33,6 +39,16 @@ internal class BeneficiaryListViewModel(
initialState = BeneficiaryListState(),
) {
/**
* Initialize the view model.
*/
init {
observeNetwork()
}
/**
* Initialize the view model.
*/
init {
observeNetwork()
}
@ -107,10 +123,18 @@ internal class BeneficiaryListViewModel(
}
}
/**
* Update the state of the view model.
*
* @param update The function to update the state.
*/
private fun updateState(update: (BeneficiaryListState) -> BeneficiaryListState) {
mutableStateFlow.update(update)
}
/**
* Fetch the list of beneficiaries from the repository.
*/
private fun fetchBeneficiaries() {
updateState {
it.copy(
@ -124,6 +148,11 @@ internal class BeneficiaryListViewModel(
}
}
/**
* Process the list of beneficiaries.
*
* @param beneficiaryList The list of beneficiaries.
*/
private fun processBeneficiaryList(beneficiaryList: DataState<List<Beneficiary>>) {
when (beneficiaryList) {
DataState.Loading -> updateState {
@ -171,18 +200,32 @@ internal class BeneficiaryListViewModel(
}
}
/**
* Handle the click on the add beneficiary button.
*/
private fun handleAddBeneficiaryClick() {
sendEvent(BeneficiaryListEvent.AddBeneficiaryClicked)
}
/**
* Handle the click on a beneficiary item.
*
* @param action The action to handle.
*/
private fun handleBeneficiaryItemClick(action: BeneficiaryListAction.OnBeneficiaryItemClick) {
sendEvent(BeneficiaryListEvent.BeneficiaryItemClick(action.position))
}
/**
* Handle the click on the navigate button.
*/
private fun handleNavigate() {
sendEvent(BeneficiaryListEvent.Navigate)
}
/**
* Handle the click on the get filter results button.
*/
private fun handleGetFilterResults() {
val filteredAccounts = if (state.selectedAccounts.isNotEmpty()) {
state.beneficiaries.filter {
@ -209,6 +252,11 @@ internal class BeneficiaryListViewModel(
}
}
/**
* Handle the change of the selected accounts.
*
* @param action The action to handle.
*/
private fun handleAccountChange(action: BeneficiaryListAction.OnAccountChange) {
val currentAccounts = state.selectedAccounts
val updatedAccounts = if (currentAccounts.contains(action.account)) {
@ -222,6 +270,11 @@ internal class BeneficiaryListViewModel(
}
}
/**
* Handle the change of the selected offices.
*
* @param action The action to handle.
*/
private fun handleOfficeChange(action: BeneficiaryListAction.OnOfficeChange) {
val currentOffices = state.selectedOffices
val updatedOffices = if (currentOffices.contains(action.office)) {
@ -253,6 +306,9 @@ internal class BeneficiaryListViewModel(
}
}
/**
* Handle the click on the toggle filter dialog button.
*/
private fun handleToggleFilterDialog() {
updateState {
it.copy(
@ -272,6 +328,9 @@ internal class BeneficiaryListViewModel(
}
}
/**
* Reset the filters.
*/
private fun resetFilters() {
updateState {
it.copy(
@ -282,6 +341,9 @@ internal class BeneficiaryListViewModel(
}
}
/**
* Dismiss the dialog.
*/
private fun dismissDialog() {
updateState {
it.copy(
@ -291,6 +353,23 @@ internal class BeneficiaryListViewModel(
}
}
/**
* State class for the beneficiary list screen.
*
* @param networkStatus The network status.
* @param isRefreshing Whether the screen is refreshing.
* @param beneficiaries The list of beneficiaries.
* @param template The beneficiary template.
* @param selectedAccounts The selected accounts.
* @param selectedOffices The selected offices.
* @param offices The list of offices.
* @param isEmpty Whether the list of beneficiaries is empty.
* @param isFilteredEmpty Whether the filtered list of beneficiaries is empty.
* @param filteredBeneficiaries The filtered list of beneficiaries.
* @param dialogState The dialog state.
* @param uiState The screen UI state.
*/
data class BeneficiaryListState(
val networkStatus: Boolean = false,
val isRefreshing: Boolean = false,
@ -313,28 +392,58 @@ data class BeneficiaryListState(
val isAnyFilterSelected = selectedAccounts.isNotEmpty() || selectedOffices.isNotEmpty()
}
/**
* Action class for the beneficiary list screen.
*
* @param RefreshBeneficiaries Refresh the list of beneficiaries.
* @param OnAddBeneficiaryClicked Add a new beneficiary.
* @param OnBeneficiaryItemClick Click on a beneficiary item.
* @param OnNavigate Navigate to another screen.
* @param ToggleFilter Toggle the filter dialog.
* @param ResetFilters Reset the filters.
* @param GetFilterResults Get the filter results.
* @param DismissDialog Dismiss the dialog.
* @param OnAccountChange Change the selected account.
*/
sealed interface BeneficiaryListAction {
data object RefreshBeneficiaries : BeneficiaryListAction
data object OnAddBeneficiaryClicked : BeneficiaryListAction
data class OnBeneficiaryItemClick(val position: Long) : BeneficiaryListAction
data object OnNavigate : BeneficiaryListAction
data object ToggleFilter : BeneficiaryListAction
data object ResetFilters : BeneficiaryListAction
data object GetFilterResults : BeneficiaryListAction
data object DismissDialog : BeneficiaryListAction
data class OnAccountChange(val account: String) : BeneficiaryListAction
data class OnOfficeChange(val office: String) : BeneficiaryListAction
data object LoadBeneficiaries : BeneficiaryListAction
data class ReceiveNetworkStatus(val isOnline: Boolean) : BeneficiaryListAction
sealed interface Internal : BeneficiaryListAction {
data class ReceiveBeneficiaryResult(
val beneficiaryList: DataState<List<Beneficiary>>,
) : Internal
}
}
/**
* Event class for the beneficiary list screen.
*
* @param AddBeneficiaryClicked Add a new beneficiary.
* @param BeneficiaryItemClick Click on a beneficiary item.
* @param Navigate Navigate to another screen.
*/
sealed interface BeneficiaryListEvent {
data object AddBeneficiaryClicked : BeneficiaryListEvent
data class BeneficiaryItemClick(val position: Long) : BeneficiaryListEvent

View File

@ -24,12 +24,42 @@ import org.mifos.mobile.feature.beneficiary.beneficiaryDetail.navigateToBenefici
import org.mifos.mobile.feature.beneficiary.beneficiaryList.BeneficiaryListNavRoute
import org.mifos.mobile.feature.beneficiary.beneficiaryList.beneficiaryListScreen
/**
* Data class representing the navigation route for the beneficiary feature.
*
* @property BeneficiaryNavRoute the navigation route for the beneficiary feature.
*/
@Serializable
data object BeneficiaryNavRoute
/**
* Navigate to the beneficiary navigation graph.
*
* @param navOptions the navigation options to use when navigating to the beneficiary navigation graph.
*/
fun NavController.navigateToBeneficiaryNavGraph(navOptions: NavOptions? = null) =
navigate(BeneficiaryNavRoute, navOptions)
/**
* Adds a navigation graph for the beneficiary feature.
*
* The navigation graph has the following destinations:
* - Beneficiary List Screen: The screen that displays the list of all beneficiaries.
* - Manual Beneficiary Add Screen: The screen that allows the user to manually add a beneficiary.
* - Beneficiary Application Confirmation Screen: The screen that confirms the addition of a beneficiary.
* - Beneficiary Detail Screen: The screen that displays the details of a beneficiary.
*
* The navigation graph is structured as follows:
* - The Beneficiary List Screen is the starting point of the graph.
* - The Manual Beneficiary Add Screen is reachable from the Beneficiary List Screen.
* - The Beneficiary Application Confirmation Screen is reachable from the Manual Beneficiary Add Screen.
* - The Beneficiary Detail Screen is reachable from the Beneficiary List Screen and the Manual Beneficiary Add Screen.
*
* @param navController The navigation controller to use for navigation.
* @param navigateToQR A function to navigate to the QR code screen.
* @param navigateToStatusScreen A function to navigate to the status screen.
* @param navigateToAuthenticateScreen A function to navigate to the authentication screen.
*/
fun NavGraphBuilder.beneficiaryNavGraph(
navController: NavController,
navigateToQR: () -> Unit,

View File

@ -2848,11 +2848,6 @@ ws@8.18.0, ws@^8.13.0:
resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.0.tgz#0d7505a6eafe2b0e712d232b42279f53bc289bbc"
integrity sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==
ws@8.5.0:
version "8.5.0"
resolved "https://registry.yarnpkg.com/ws/-/ws-8.5.0.tgz#bfb4be96600757fe5382de12c670dab984a1ed4f"
integrity sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==
ws@~8.17.1:
version "8.17.1"
resolved "https://registry.yarnpkg.com/ws/-/ws-8.17.1.tgz#9293da530bb548febc95371d90f9c878727d919b"