Skip to content

Commit 7b70ef4

Browse files
Rajan MauryaRajan Maurya
authored andcommitted
feat(feature/activate): migrate ActivateViewModel to SubmitHandler<Unit>
Replaces manual DataState collection with template.core.base.store's SubmitHandler — a one-shot, idempotent submission executor with built-in Submitting / Submitted / Failed lifecycle and automatic cancel-prior-job semantics for sequential calls. VM: - Single SubmitHandler<Unit> instead of three viewModelScope.launch blocks - submit.state mapped to existing ActivateUiState via .map.stateIn so Screen-side state shape (Initial / Loading / ActivatedSuccessfully / Error) is unchanged — no Screen changes required - Per-action success/failure StringResource tracked in two vars set before each submit; safe because they're written synchronously with submit.submit { ... } and only read when state transitions to a terminal value - ActivateClientUseCase / ActivateCenterUseCase (Flow<DataState<T>>) bridged via .first { it !is DataState.Loading } + throw on Error - ActivateGroupUseCase (suspend, returns DataState<Unit> directly) just checks for Error and throws build.gradle.kts: + implementation(projects.coreBase.store) This is the migration template for all subsequent mutation-feature migrations (auth, savings, recurringDeposit, note, checker-inbox-task, collectionSheet, report, document, loan, client). Each follows the same shape: introduce a SubmitHandler<R> in the VM, map its state to the feature's existing UiState, bridge use-case return shapes through SubmitHandler.submit { ... }, leave the Screen untouched.
1 parent dd14cda commit 7b70ef4

2 files changed

Lines changed: 48 additions & 47 deletions

File tree

feature/activate/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ kotlin {
2323
implementation(compose.components.resources)
2424
implementation(compose.ui)
2525
implementation(projects.core.domain)
26+
implementation(projects.coreBase.store)
2627
implementation(compose.components.uiToolingPreview)
2728
}
2829
}

feature/activate/src/commonMain/kotlin/com/mifos/feature/activate/ActivateViewModel.kt

Lines changed: 47 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,14 @@ import com.mifos.core.domain.useCases.ActivateCenterUseCase
2525
import com.mifos.core.domain.useCases.ActivateClientUseCase
2626
import com.mifos.core.domain.useCases.ActivateGroupUseCase
2727
import com.mifos.core.model.objects.clients.ActivatePayload
28-
import kotlinx.coroutines.flow.MutableStateFlow
29-
import kotlinx.coroutines.flow.asStateFlow
30-
import kotlinx.coroutines.launch
28+
import kotlinx.coroutines.flow.SharingStarted
29+
import kotlinx.coroutines.flow.StateFlow
30+
import kotlinx.coroutines.flow.first
31+
import kotlinx.coroutines.flow.map
32+
import kotlinx.coroutines.flow.stateIn
33+
import org.jetbrains.compose.resources.StringResource
34+
import template.core.base.store.submit.SubmitState
35+
import template.core.base.store.submit.submitHandler
3136

3237
class ActivateViewModel(
3338
private val activateClientUseCase: ActivateClientUseCase,
@@ -39,56 +44,51 @@ class ActivateViewModel(
3944
val id = savedStateHandle.toRoute<ActivateRoute>().id
4045
val activateType = savedStateHandle.toRoute<ActivateRoute>().type
4146

42-
private val _activateUiState = MutableStateFlow<ActivateUiState>(ActivateUiState.Initial)
43-
val activateUiState = _activateUiState.asStateFlow()
47+
private val submit = viewModelScope.submitHandler<Unit>()
48+
private var successMessage: StringResource = Res.string.feature_activate_client
49+
private var failureMessage: StringResource = Res.string.feature_activate_failed_to_activate_client
4450

45-
fun activateClient(clientId: Int, clientPayload: ActivatePayload) =
46-
viewModelScope.launch {
47-
activateClientUseCase(clientId, clientPayload).collect { result ->
48-
when (result) {
49-
is DataState.Error ->
50-
_activateUiState.value =
51-
ActivateUiState.Error(Res.string.feature_activate_failed_to_activate_client)
52-
53-
is DataState.Loading -> _activateUiState.value = ActivateUiState.Loading
54-
55-
is DataState.Success ->
56-
_activateUiState.value =
57-
ActivateUiState.ActivatedSuccessfully(Res.string.feature_activate_client)
58-
}
51+
val activateUiState: StateFlow<ActivateUiState> = submit.state
52+
.map { state ->
53+
when (state) {
54+
is SubmitState.Idle -> ActivateUiState.Initial
55+
is SubmitState.Submitting -> ActivateUiState.Loading
56+
is SubmitState.Submitted<*> -> ActivateUiState.ActivatedSuccessfully(successMessage)
57+
is SubmitState.Failed -> ActivateUiState.Error(failureMessage)
5958
}
6059
}
60+
.stateIn(
61+
scope = viewModelScope,
62+
started = SharingStarted.Eagerly,
63+
initialValue = ActivateUiState.Initial,
64+
)
6165

62-
fun activateCenter(centerId: Int, centerPayload: ActivatePayload) =
63-
viewModelScope.launch {
64-
activateCenterUseCase(centerId, centerPayload).collect { result ->
65-
when (result) {
66-
is DataState.Error ->
67-
_activateUiState.value =
68-
ActivateUiState.Error(Res.string.feature_activate_failed_to_activate_center)
69-
70-
is DataState.Loading -> _activateUiState.value = ActivateUiState.Loading
71-
72-
is DataState.Success ->
73-
_activateUiState.value =
74-
ActivateUiState.ActivatedSuccessfully(Res.string.feature_activate_center)
75-
}
76-
}
66+
fun activateClient(clientId: Int, clientPayload: ActivatePayload) {
67+
successMessage = Res.string.feature_activate_client
68+
failureMessage = Res.string.feature_activate_failed_to_activate_client
69+
submit.submit {
70+
val terminal = activateClientUseCase(clientId, clientPayload)
71+
.first { it !is DataState.Loading }
72+
if (terminal is DataState.Error) throw terminal.exception
7773
}
74+
}
7875

79-
fun activateGroup(groupId: Int, groupPayload: ActivatePayload) =
80-
viewModelScope.launch {
81-
val result = activateGroupUseCase(groupId, groupPayload)
82-
when (result) {
83-
is DataState.Error ->
84-
_activateUiState.value =
85-
ActivateUiState.Error(Res.string.feature_activate_failed_to_activate_group)
86-
87-
DataState.Loading -> Unit // unreachable
76+
fun activateCenter(centerId: Int, centerPayload: ActivatePayload) {
77+
successMessage = Res.string.feature_activate_center
78+
failureMessage = Res.string.feature_activate_failed_to_activate_center
79+
submit.submit {
80+
val terminal = activateCenterUseCase(centerId, centerPayload)
81+
.first { it !is DataState.Loading }
82+
if (terminal is DataState.Error) throw terminal.exception
83+
}
84+
}
8885

89-
is DataState.Success ->
90-
_activateUiState.value =
91-
ActivateUiState.ActivatedSuccessfully(Res.string.feature_activate_group)
92-
}
86+
fun activateGroup(groupId: Int, groupPayload: ActivatePayload) {
87+
successMessage = Res.string.feature_activate_group
88+
failureMessage = Res.string.feature_activate_failed_to_activate_group
89+
submit.submit {
90+
val terminal = activateGroupUseCase(groupId, groupPayload)
91+
if (terminal is DataState.Error) throw terminal.exception
9392
}
93+
}
9494
}

0 commit comments

Comments
 (0)