Skip to content

Commit 401a017

Browse files
authored
refactor(feature:client): merge dialog ViewModel into main ViewModel in client identifiers (#2438)
1 parent d40dd1a commit 401a017

File tree

5 files changed

+97
-161
lines changed

5 files changed

+97
-161
lines changed

feature/client/src/commonMain/kotlin/com/mifos/feature/client/clientIdentifiers/ClientIdentifiersScreen.kt

Lines changed: 30 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,11 @@ import com.mifos.core.designsystem.icon.MifosIcons
6363
import com.mifos.core.designsystem.theme.identifierTextStyleDark
6464
import com.mifos.core.designsystem.theme.identifierTextStyleLight
6565
import com.mifos.core.model.objects.noncoreobjects.Identifier
66+
import com.mifos.core.model.objects.noncoreobjects.IdentifierPayload
6667
import com.mifos.core.ui.components.MifosEmptyUi
6768
import com.mifos.core.ui.util.DevicePreview
69+
import com.mifos.feature.client.clientIdentifiersDialog.ClientIdentifierDialogUiState
6870
import com.mifos.feature.client.clientIdentifiersDialog.ClientIdentifiersDialogScreen
69-
import com.mifos.feature.client.clientIdentifiersDialog.ClientIdentifiersDialogViewModel
7071
import kotlinx.coroutines.launch
7172
import org.jetbrains.compose.resources.getString
7273
import org.jetbrains.compose.resources.stringResource
@@ -78,55 +79,44 @@ import org.koin.compose.viewmodel.koinViewModel
7879
internal fun ClientIdentifiersScreen(
7980
onBackPressed: () -> Unit,
8081
onDocumentClicked: (Int) -> Unit,
81-
clientIdentifiersviewModel: ClientIdentifiersViewModel = koinViewModel(),
82-
clientIdentifiersDialogViewModel: ClientIdentifiersDialogViewModel = koinViewModel(),
82+
viewModel: ClientIdentifiersViewModel = koinViewModel(),
8383
) {
84-
val clientId by clientIdentifiersviewModel.clientId.collectAsStateWithLifecycle()
85-
val state by clientIdentifiersviewModel.clientIdentifiersUiState.collectAsStateWithLifecycle()
86-
val refreshState by clientIdentifiersviewModel.isRefreshing.collectAsStateWithLifecycle()
84+
val clientIdentifiersUiState by viewModel.clientIdentifiersUiState.collectAsStateWithLifecycle()
85+
val clientIdentifiersDialogUiState by viewModel.clientIdentifierDialogUiState.collectAsStateWithLifecycle()
86+
val refreshState by viewModel.isRefreshing.collectAsStateWithLifecycle()
8787

8888
ClientIdentifiersScreen(
89-
clientId = clientId,
90-
state = state,
89+
state = clientIdentifiersUiState,
90+
dialogState = clientIdentifiersDialogUiState,
91+
onShowDialog = viewModel::loadClientIdentifierTemplate,
9192
onBackPressed = onBackPressed,
9293
onDeleteIdentifier = { identifierId ->
93-
clientIdentifiersviewModel.deleteIdentifier(clientId, identifierId)
94-
},
95-
refreshState = refreshState,
96-
onRefresh = {
97-
clientIdentifiersviewModel.refreshIdentifiersList(clientId)
94+
viewModel.deleteIdentifier(identifierId)
9895
},
99-
onRetry = {
100-
clientIdentifiersviewModel.loadIdentifiers(clientId)
101-
},
102-
onIdentifierCreated = {
103-
// resetUiState() is needed here to clear the success state immediately after successful
104-
// client identifier creation, so that reopening the dialog doesn’t reuse stale state and
105-
// accidentally retrigger main screen loading.
106-
// Downside: this causes two back-to-back loading states — one in the dialog and one on
107-
// the main screen.
108-
clientIdentifiersDialogViewModel.resetUiState()
109-
clientIdentifiersviewModel.loadIdentifiers(clientId)
96+
onCreateIdentifier = { identifierPayload ->
97+
viewModel.createClientIdentifier(identifierPayload)
11098
},
99+
refreshState = refreshState,
100+
onRefresh = viewModel::refreshIdentifiersList,
101+
onRetry = viewModel::loadIdentifiers,
111102
onDocumentClicked = onDocumentClicked,
112-
onIdentifierDeleted = {
113-
clientIdentifiersviewModel.loadIdentifiers(clientId)
114-
},
103+
reloadIdentifiers = viewModel::loadIdentifiers,
115104
)
116105
}
117106

118107
@Composable
119108
internal fun ClientIdentifiersScreen(
120-
clientId: Int,
121109
state: ClientIdentifiersUiState,
110+
dialogState: ClientIdentifierDialogUiState,
111+
onShowDialog: () -> Unit,
122112
onBackPressed: () -> Unit,
123113
onDeleteIdentifier: (Int) -> Unit,
114+
onCreateIdentifier: (IdentifierPayload) -> Unit,
124115
refreshState: Boolean,
125116
onRefresh: () -> Unit,
126117
onRetry: () -> Unit,
127-
onIdentifierCreated: () -> Unit,
128118
onDocumentClicked: (Int) -> Unit,
129-
onIdentifierDeleted: () -> Unit,
119+
reloadIdentifiers: () -> Unit,
130120
) {
131121
val snackbarHostState = remember { SnackbarHostState() }
132122
val pullToRefreshState = rememberPullToRefreshState()
@@ -136,13 +126,15 @@ internal fun ClientIdentifiersScreen(
136126

137127
if (showCreateIdentifierDialog) {
138128
ClientIdentifiersDialogScreen(
139-
clientId = clientId,
129+
state = dialogState,
140130
onDismiss = { showCreateIdentifierDialog = false },
141131
onIdentifierCreated = {
142132
showCreateIdentifierDialog = false
143133
showCreateSuccessMessage = true
144-
onIdentifierCreated()
134+
reloadIdentifiers()
145135
},
136+
onRetry = onRetry,
137+
onCreateIdentifier = onCreateIdentifier,
146138
)
147139
}
148140

@@ -152,6 +144,7 @@ internal fun ClientIdentifiersScreen(
152144
actions = {
153145
IconButton(
154146
onClick = {
147+
onShowDialog()
155148
showCreateIdentifierDialog = true
156149
},
157150
) {
@@ -196,7 +189,7 @@ internal fun ClientIdentifiersScreen(
196189
}
197190

198191
is ClientIdentifiersUiState.IdentifierDeletedSuccessfully -> {
199-
onIdentifierDeleted()
192+
reloadIdentifiers()
200193
scope.launch {
201194
snackbarHostState.showSnackbar(
202195
message = getString(state.message),
@@ -351,16 +344,17 @@ private fun ClientIdentifiersScreenPreview(
351344
@PreviewParameter(ClientIdentifiersUiStateProvider::class) state: ClientIdentifiersUiState,
352345
) {
353346
ClientIdentifiersScreen(
354-
clientId = 1,
355347
state = state,
348+
dialogState = ClientIdentifierDialogUiState.Loading,
356349
onBackPressed = {},
357350
onDeleteIdentifier = {},
358351
refreshState = true,
359352
onRefresh = {},
360353
onRetry = {},
361-
onIdentifierCreated = {},
362354
onDocumentClicked = {},
363-
onIdentifierDeleted = {},
355+
onShowDialog = {},
356+
reloadIdentifiers = {},
357+
onCreateIdentifier = {},
364358
)
365359
}
366360
val sampleClientIdentifiers = List(10) {

feature/client/src/commonMain/kotlin/com/mifos/feature/client/clientIdentifiers/ClientIdentifiersViewModel.kt

Lines changed: 59 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,23 +10,31 @@
1010
package com.mifos.feature.client.clientIdentifiers
1111

1212
import androidclient.feature.client.generated.resources.Res
13+
import androidclient.feature.client.generated.resources.feature_client_failed_to_create_identifier
1314
import androidclient.feature.client.generated.resources.feature_client_failed_to_delete_identifier
1415
import androidclient.feature.client.generated.resources.feature_client_failed_to_load_client_identifiers
16+
import androidclient.feature.client.generated.resources.feature_client_failed_to_load_identifiers
1517
import androidclient.feature.client.generated.resources.feature_client_identifier_deleted_successfully
1618
import androidx.lifecycle.SavedStateHandle
1719
import androidx.lifecycle.ViewModel
1820
import androidx.lifecycle.viewModelScope
1921
import com.mifos.core.common.utils.Constants
2022
import com.mifos.core.common.utils.DataState
2123
import com.mifos.core.data.repository.ClientIdentifiersRepository
24+
import com.mifos.core.domain.useCases.CreateClientIdentifierUseCase
2225
import com.mifos.core.domain.useCases.DeleteIdentifierUseCase
26+
import com.mifos.core.domain.useCases.GetClientIdentifierTemplateUseCase
27+
import com.mifos.core.model.objects.noncoreobjects.IdentifierPayload
28+
import com.mifos.feature.client.clientIdentifiersDialog.ClientIdentifierDialogUiState
2329
import kotlinx.coroutines.flow.MutableStateFlow
2430
import kotlinx.coroutines.flow.asStateFlow
2531
import kotlinx.coroutines.launch
2632

2733
class ClientIdentifiersViewModel(
2834
private val clientIdentifiersRepository: ClientIdentifiersRepository,
2935
private val deleteIdentifierUseCase: DeleteIdentifierUseCase,
36+
private val getClientIdentifierTemplateUseCase: GetClientIdentifierTemplateUseCase,
37+
private val createClientIdentifierUseCase: CreateClientIdentifierUseCase,
3038
private val savedStateHandle: SavedStateHandle,
3139
) : ViewModel() {
3240

@@ -36,21 +44,25 @@ class ClientIdentifiersViewModel(
3644
MutableStateFlow<ClientIdentifiersUiState>(ClientIdentifiersUiState.Loading)
3745
val clientIdentifiersUiState = _clientIdentifiersUiState.asStateFlow()
3846

47+
private val _clientIdentifierDialogUiState =
48+
MutableStateFlow<ClientIdentifierDialogUiState>(ClientIdentifierDialogUiState.Loading)
49+
val clientIdentifierDialogUiState = _clientIdentifierDialogUiState.asStateFlow()
50+
3951
private val _isRefreshing = MutableStateFlow(false)
4052
val isRefreshing = _isRefreshing.asStateFlow()
4153

4254
init {
43-
loadIdentifiers(clientId = clientId.value)
55+
loadIdentifiers()
4456
}
4557

46-
fun refreshIdentifiersList(clientId: Int) {
58+
fun refreshIdentifiersList() {
4759
_isRefreshing.value = true
48-
loadIdentifiers(clientId = clientId)
60+
loadIdentifiers()
4961
_isRefreshing.value = false
5062
}
5163

52-
fun loadIdentifiers(clientId: Int) = viewModelScope.launch {
53-
clientIdentifiersRepository.getClientIdentifiers(clientId).collect { result ->
64+
fun loadIdentifiers() = viewModelScope.launch {
65+
clientIdentifiersRepository.getClientIdentifiers(clientId.value).collect { result ->
5466
when (result) {
5567
is DataState.Error ->
5668
_clientIdentifiersUiState.value =
@@ -67,8 +79,8 @@ class ClientIdentifiersViewModel(
6779
}
6880
}
6981

70-
fun deleteIdentifier(clientId: Int, identifierId: Int) = viewModelScope.launch {
71-
deleteIdentifierUseCase(clientId, identifierId).collect { result ->
82+
fun deleteIdentifier(identifierId: Int) = viewModelScope.launch {
83+
deleteIdentifierUseCase(clientId.value, identifierId).collect { result ->
7284
when (result) {
7385
is DataState.Error ->
7486
_clientIdentifiersUiState.value =
@@ -86,4 +98,44 @@ class ClientIdentifiersViewModel(
8698
}
8799
}
88100
}
101+
102+
fun loadClientIdentifierTemplate() = viewModelScope.launch {
103+
getClientIdentifierTemplateUseCase(clientId.value).collect { result ->
104+
when (result) {
105+
is DataState.Error ->
106+
_clientIdentifierDialogUiState.value =
107+
ClientIdentifierDialogUiState.Error(Res.string.feature_client_failed_to_load_identifiers)
108+
109+
is DataState.Loading ->
110+
_clientIdentifierDialogUiState.value =
111+
ClientIdentifierDialogUiState.Loading
112+
113+
is DataState.Success ->
114+
_clientIdentifierDialogUiState.value =
115+
ClientIdentifierDialogUiState.ClientIdentifierTemplate(
116+
result.data,
117+
)
118+
}
119+
}
120+
}
121+
122+
fun createClientIdentifier(identifierPayload: IdentifierPayload) =
123+
viewModelScope.launch {
124+
createClientIdentifierUseCase(clientId.value, identifierPayload).collect { result ->
125+
when (result) {
126+
is DataState.Error ->
127+
_clientIdentifierDialogUiState.value =
128+
ClientIdentifierDialogUiState.Error(Res.string.feature_client_failed_to_create_identifier)
129+
130+
is DataState.Loading ->
131+
_clientIdentifierDialogUiState.value =
132+
ClientIdentifierDialogUiState.Loading
133+
134+
is DataState.Success ->
135+
_clientIdentifierDialogUiState.value =
136+
ClientIdentifierDialogUiState
137+
.IdentifierCreatedSuccessfully
138+
}
139+
}
140+
}
89141
}

feature/client/src/commonMain/kotlin/com/mifos/feature/client/clientIdentifiersDialog/ClientIdentifiersDialogScreen.kt

Lines changed: 8 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ import androidx.compose.material3.MaterialTheme
3737
import androidx.compose.material3.Surface
3838
import androidx.compose.material3.Text
3939
import androidx.compose.runtime.Composable
40-
import androidx.compose.runtime.LaunchedEffect
4140
import androidx.compose.runtime.getValue
4241
import androidx.compose.runtime.mutableStateOf
4342
import androidx.compose.runtime.saveable.rememberSaveable
@@ -46,7 +45,6 @@ import androidx.compose.ui.Alignment
4645
import androidx.compose.ui.Modifier
4746
import androidx.compose.ui.unit.dp
4847
import androidx.compose.ui.window.Dialog
49-
import androidx.lifecycle.compose.collectAsStateWithLifecycle
5048
import com.mifos.core.designsystem.component.MifosCircularProgress
5149
import com.mifos.core.designsystem.component.MifosOutlinedTextField
5250
import com.mifos.core.designsystem.component.MifosSweetError
@@ -58,46 +56,14 @@ import com.mifos.core.ui.util.DevicePreview
5856
import org.jetbrains.compose.resources.stringResource
5957
import org.jetbrains.compose.ui.tooling.preview.PreviewParameter
6058
import org.jetbrains.compose.ui.tooling.preview.PreviewParameterProvider
61-
import org.koin.compose.viewmodel.koinViewModel
62-
63-
@Composable
64-
internal fun ClientIdentifiersDialogScreen(
65-
clientId: Int,
66-
onDismiss: () -> Unit,
67-
onIdentifierCreated: () -> Unit,
68-
viewModel: ClientIdentifiersDialogViewModel = koinViewModel(),
69-
) {
70-
val state by viewModel.clientIdentifierDialogUiState.collectAsStateWithLifecycle()
71-
72-
LaunchedEffect(Unit) {
73-
viewModel.loadClientIdentifierTemplate(clientId)
74-
}
75-
76-
if (state is ClientIdentifierDialogUiState.IdentifierCreatedSuccessfully) {
77-
LaunchedEffect(Unit) {
78-
onIdentifierCreated()
79-
}
80-
return
81-
}
82-
83-
ClientIdentifiersDialogScreen(
84-
state = state,
85-
onDismiss = onDismiss,
86-
onRetry = {
87-
viewModel.loadClientIdentifierTemplate(clientId = clientId)
88-
},
89-
onCreate = {
90-
viewModel.createClientIdentifier(clientId, it)
91-
},
92-
)
93-
}
9459

9560
@Composable
9661
internal fun ClientIdentifiersDialogScreen(
9762
state: ClientIdentifierDialogUiState,
9863
onDismiss: () -> Unit,
9964
onRetry: () -> Unit,
100-
onCreate: (IdentifierPayload) -> Unit,
65+
onCreateIdentifier: (IdentifierPayload) -> Unit,
66+
onIdentifierCreated: () -> Unit,
10167
) {
10268
Dialog(
10369
onDismissRequest = { onDismiss() },
@@ -140,7 +106,7 @@ internal fun ClientIdentifiersDialogScreen(
140106
is ClientIdentifierDialogUiState.ClientIdentifierTemplate -> {
141107
ClientIdentifiersContent(
142108
clientIdentifierTemplate = state.identifierTemplate,
143-
onCreate = onCreate,
109+
onCreate = onCreateIdentifier,
144110
)
145111
}
146112

@@ -150,7 +116,9 @@ internal fun ClientIdentifiersDialogScreen(
150116
onRetry()
151117
}
152118

153-
is ClientIdentifierDialogUiState.IdentifierCreatedSuccessfully -> {}
119+
is ClientIdentifierDialogUiState.IdentifierCreatedSuccessfully -> {
120+
onIdentifierCreated()
121+
}
154122

155123
is ClientIdentifierDialogUiState.Loading -> MifosCircularProgress()
156124
}
@@ -305,6 +273,7 @@ private fun ClientIdentifiersDialogScreenPreview(
305273
state = state,
306274
onDismiss = {},
307275
onRetry = {},
308-
onCreate = {},
276+
onCreateIdentifier = {},
277+
onIdentifierCreated = {},
309278
)
310279
}

0 commit comments

Comments
 (0)