Skip to content

Commit

Permalink
clean up
Browse files Browse the repository at this point in the history
  • Loading branch information
toluo-stripe committed Oct 7, 2024
1 parent 9851c6a commit ba3ae15
Show file tree
Hide file tree
Showing 8 changed files with 94 additions and 107 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -222,11 +222,9 @@ internal class LinkAccountManager @Inject constructor(
* Whether the user has logged out from any account.
*/
suspend fun hasUserLoggedOut(email: String?): Boolean {
email ?: return true
val linkAccount = linkAccount.value ?: return true
if (email != linkAccount.email) return true
val currentStatus = accountStatus.first()
return currentStatus == AccountStatus.SignedOut
return email == null ||
linkAccount.value?.email != email ||
accountStatus.first() == AccountStatus.SignedOut
}

private fun setAccount(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,11 @@ import com.stripe.android.core.strings.ResolvableString
import com.stripe.android.uicore.elements.PhoneNumberController
import com.stripe.android.uicore.elements.TextFieldController

sealed interface SignUpScreenState {
data class Content(
val emailController: TextFieldController,
val phoneNumberController: PhoneNumberController,
val nameController: TextFieldController,
val signUpEnabled: Boolean,
val signUpState: SignUpState = SignUpState.InputtingPrimaryField,
val errorMessage: ResolvableString? = null
) : SignUpScreenState

data object Loading : SignUpScreenState
}
data class SignUpScreenState(
val emailController: TextFieldController,
val phoneNumberController: PhoneNumberController,
val nameController: TextFieldController,
val signUpEnabled: Boolean,
val signUpState: SignUpState = SignUpState.InputtingPrimaryField,
val errorMessage: ResolvableString? = null
)
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import androidx.lifecycle.viewModelScope
import androidx.navigation.NavHostController
import com.stripe.android.core.Logger
import com.stripe.android.core.model.CountryCode
import com.stripe.android.core.strings.ResolvableString
import com.stripe.android.core.strings.resolvableString
import com.stripe.android.link.LinkActivityContract
import com.stripe.android.link.LinkScreen
Expand All @@ -26,7 +25,6 @@ import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.mapLatest
import kotlinx.coroutines.flow.update
Expand All @@ -41,7 +39,16 @@ internal class SignUpViewModel @Inject constructor(
private val logger: Logger
) : ViewModel() {
internal var navController: NavHostController? = null
private val _state = MutableStateFlow<SignUpScreenState>(SignUpScreenState.Loading)
private val _state = MutableStateFlow(
value = SignUpScreenState(
emailController = EmailConfig.createController(""),
phoneNumberController = PhoneNumberController.createPhoneNumberController(
initiallySelectedCountryCode = args.configuration.customerInfo.billingCountryCode
),
nameController = NameConfig.createController(""),
signUpEnabled = false
)
)

val state: StateFlow<SignUpScreenState> = _state

Expand Down Expand Up @@ -69,25 +76,19 @@ internal class SignUpViewModel @Inject constructor(

private suspend fun loadScreen() {
val isLoggedOut = linkAccountManager.hasUserLoggedOut(args.configuration.customerInfo.email)
val newState = SignUpScreenState.Content(
emailController = EmailConfig.createController(
initialValue = args.configuration.customerInfo.email.takeUnless { isLoggedOut }
),
phoneNumberController = PhoneNumberController.createPhoneNumberController(
initialValue = args.configuration.customerInfo.phone.takeUnless { isLoggedOut }.orEmpty(),
initiallySelectedCountryCode = args.configuration.customerInfo.billingCountryCode,
),
nameController = NameConfig.createController(
initialValue = args.configuration.customerInfo.name.takeUnless { isLoggedOut }
),
signUpEnabled = false
_state.value.emailController.onRawValueChange(
rawValue = args.configuration.customerInfo.email.takeUnless { isLoggedOut } ?: ""
)
_state.value.phoneNumberController.onRawValueChange(
rawValue = args.configuration.customerInfo.email.takeUnless { isLoggedOut } ?: ""
)
_state.value.nameController.onRawValueChange(
rawValue = args.configuration.customerInfo.name.takeUnless { isLoggedOut } ?: ""
)
_state.emit(newState)
}

private suspend fun signUpEnabledListener() {
_state.flatMapLatest { state ->
if (state !is SignUpScreenState.Content) return@flatMapLatest flowOf()
combine(
flow = state.nameController.fieldState.map {
if (requiresNameCollection) {
Expand All @@ -102,13 +103,12 @@ internal class SignUpViewModel @Inject constructor(
nameComplete && emailComplete && phoneComplete
}
}.collectLatest { formValid ->
updateSignUpEnabled(formValid)
updateState { it.copy(signUpEnabled = formValid) }
}
}

private suspend fun emailListener() {
_state.flatMapLatest { state ->
if (state !is SignUpScreenState.Content) return@flatMapLatest flowOf()
state.emailController.formFieldValue.mapLatest { entry ->
entry.takeIf { it.isComplete }?.value
}
Expand All @@ -126,7 +126,7 @@ internal class SignUpViewModel @Inject constructor(
fun onSignUpClick() {
clearError()
viewModelScope.launch {
val state = (_state.value as? SignUpScreenState.Content) ?: return@launch
val state = _state.value
linkAccountManager.signUp(
email = state.emailController.fieldValue.value,
phone = state.phoneNumberController.fieldValue.value,
Expand All @@ -153,7 +153,7 @@ internal class SignUpViewModel @Inject constructor(
navController?.navigate(LinkScreen.Verification.route)
// The sign up screen stays in the back stack.
// Clean up the state in case the user comes back.
(_state.value as SignUpScreenState.Content).emailController.onValueChange("")
_state.value.emailController.onValueChange("")
}
}

Expand All @@ -177,43 +177,34 @@ internal class SignUpViewModel @Inject constructor(

private fun onError(error: Throwable) {
logger.error("Error: ", error)
updateErrorMessage(
error = when (val errorMessage = error.getErrorMessage()) {
is ErrorMessage.FromResources -> {
errorMessage.stringResId.resolvableString
}
is ErrorMessage.Raw -> {
errorMessage.errorMessage.resolvableString
updateState {
it.copy(
errorMessage = when (val errorMessage = error.getErrorMessage()) {
is ErrorMessage.FromResources -> {
errorMessage.stringResId.resolvableString
}
is ErrorMessage.Raw -> {
errorMessage.errorMessage.resolvableString
}
}
}
)
)
}
}

private fun clearError() {
updateErrorMessage(null)
updateState { it.copy(errorMessage = null) }
}

private fun updateSignUpEnabled(enabled: Boolean) {
_state.update { old ->
if (old !is SignUpScreenState.Content) return@update old
old.copy(signUpEnabled = enabled)
}
private fun updateState(produceValue: (SignUpScreenState) -> SignUpScreenState) {
_state.update(produceValue)
}

private fun updateSignUpState(signUpState: SignUpState) {
_state.update { old ->
if (old !is SignUpScreenState.Content) return@update old
updateState { old ->
old.copy(signUpState = signUpState)
}
}

private fun updateErrorMessage(error: ResolvableString?) {
_state.update { old ->
if (old !is SignUpScreenState.Content) return@update old
old.copy(errorMessage = error)
}
}

companion object {
// How long to wait before triggering a call to lookup the email
internal val LOOKUP_DEBOUNCE = 1.seconds
Expand Down
Loading

0 comments on commit ba3ae15

Please sign in to comment.