feat(feature/auth): migrate LoginViewModel to SubmitHandler - #2685
feat(feature/auth): migrate LoginViewModel to SubmitHandler#2685therajanmaurya wants to merge 2 commits into
Conversation
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.
…data re-exports
Establishes the app-facing dependency chain for Store5 submission primitives:
core-base/store -> core/store -> core/data -> feature/*
Feature modules consume Store5 abstractions through 'com.mifos.core.data.store'
re-exports — they never import 'template.core.base.store.*' directly.
New file: core/data/src/commonMain/.../store/SubmitTypes.kt
- typealias SubmitHandler<R> = template.core.base.store.submit.SubmitHandler<R>
- typealias SubmitState<R> = template.core.base.store.submit.SubmitState<R>
- fun CoroutineScope.submitHandler<R>(): SubmitHandler<R> (delegates)
core/data/build.gradle.kts:
- api(projects.coreBase.store) -> api(projects.core.store)
Routes the framework primitives through core/store (the consumer seam)
instead of bypassing it.
feature/auth/build.gradle.kts:
No new dep required — Store5 types flow in via projects.core.data's api.
LoginViewModel:
- Replaces .collect { when (DataState) } with SubmitHandler<PostAuthenticationResponse>
- submit.state collected in init via launchIn + onEach; maps SubmitState
to existing LoginUiState (Empty / ShowProgress / ShowError / ShowValidationError /
PassCodeActivityIntent). Screen API unchanged.
- Validation logic untouched (pre-submit gate, not a Submit state)
- LoginUseCase Flow<DataState<T>> bridged via .first { !Loading } + throw on Error
- Auth-rejected case (DataState.Success but authenticated != true) throws a
sentinel LoginRejectedException — handled by SubmitState.Failed
- Persists user via prefManager.updateUser, then sets PassCodeActivityIntent
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. 🗂️ Base branches to auto review (1)
Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
|
Closing — superseded by the revised end-to-end plan. Wave 2 (auth) will be re-opened after Wave 1 (activate) lands. |



Summary
Phase C Wave 2 — migrates
LoginViewModeltoSubmitHandler<PostAuthenticationResponse>, consuming Store5 primitives throughcom.mifos.core.data.storere-exports (the architectural pattern established in Wave 1 #2684).Chained on Wave 1 #2684 — merge that first. This PR contains only the auth-specific change.
Changes (1 file, +57 / -49)
feature/auth/.../login/LoginViewModel.kt:SubmitHandler<PostAuthenticationResponse>(viacom.mifos.core.data.store.submitHandler) replacesviewModelScope.launch { ... .collect { ... } }submit.statecollected ininit { ... }vialaunchIn(viewModelScope)+onEach— mapsSubmitStatetoLoginUiState:Submitting→ShowProgressSubmitted<PostAuthenticationResponse>→ persists user viaprefManager.updateUser, thenPassCodeActivityIntentFailed→ShowError(logs the actual error throwable)ShowValidationErrordirectly)LoginUseCaseFlow<DataState<T>>bridged via.first { it !is DataState.Loading }:DataState.Error→ throwterminal.exceptionDataState.Successwithauthenticated == true→ return responseDataState.Successwithauthenticated != true→ throw sentinelLoginRejectedExceptionfeature/auth/build.gradle.ktschanges needed — theimplementation(projects.core.data)dep already present exposes thecom.mifos.core.data.store.*re-exportsWhat this PR does NOT change
LoginUiState.kt— sealed-class definition unchanged (Empty, ShowProgress, ShowError, ShowValidationError, PassCodeActivityIntent)LoginScreen.kt— Screen-side consumer code unchangedLoginUseCase/UsernameValidationUseCase/PasswordValidationUseCase— domain layer untouchedPattern proven on second feature
Wave 1 established the pattern on
activate(3 isolated submit methods withActivateUiStatemapping). Wave 2 validates the same pattern onauthwith extra complexity:PostAuthenticationResponse) consumed inSubmittedhandler for a follow-up side effect (prefManager.updateUser)ShowValidationErrorset outsideSubmitHandler.stateflow (pre-submit gate),ShowProgress/ShowError/PassCodeActivityIntentdriven bySubmitHandlerstateThis validates that the re-export layer +
SubmitHandlerare flexible enough for both "fire-and-forget" (activate) and "act-on-success-response" (auth) flows.Test plan
./gradlew :feature:auth:buildcompiles cleanlytemplate.core.base.store.*imports infeature/auth/**authenticated != true): ShowError (sentinel exception path)Phase status
#2684—activate)auth)Related
#2684(must merge first — this branch is chained on it)