package dev.inmo.postssystem.client.fsm.ui import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import dev.inmo.jsuikit.elements.* import dev.inmo.jsuikit.modifiers.* import dev.inmo.jsuikit.utils.Attrs import dev.inmo.postssystem.client.ui.fsm.* import dev.inmo.postssystem.features.auth.client.ui.* import dev.inmo.micro_utils.coroutines.launchSafelyWithoutExceptions import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions import dev.inmo.micro_utils.fsm.common.StatesMachine import dev.inmo.postssystem.client.utils.renderComposableAndLinkToContext import kotlinx.browser.document import kotlinx.coroutines.* import kotlinx.dom.* import org.jetbrains.compose.web.attributes.InputType import org.jetbrains.compose.web.dom.* import org.jetbrains.compose.web.dom.Text import org.w3c.dom.* class AuthView( private val viewModel: AuthUIViewModel, private val uiScope: CoroutineScope ) : JSView() { override suspend fun StatesMachine.safeHandleState( htmlElement: HTMLElement, state: AuthUIFSMState ): UIFSMState? { val completion = CompletableDeferred() val usernameState = mutableStateOf("") val passwordState = mutableStateOf("") val disabled = mutableStateOf(true) val errorText = mutableStateOf(null) val root = htmlElement.appendElement("div") {} val composition = renderComposableAndLinkToContext(root) { val authBtnDisabled = usernameState.value.isBlank() || passwordState.value.isBlank() Flex( UIKitFlex.Alignment.Horizontal.Center ) { Card( Attrs(UIKitText.Alignment.Horizontal.Center), bodyAttrs = Attrs(UIKitWidth.Fixed.Medium), ) { CardTitle { Text("Log in") } if (errorText.value != null) { CardBadge(Attrs(UIKitLabel.Error)) { Text(errorText.value.toString()) } } TextField( InputType.Text, usernameState, disabled, "Username", ) TextField( InputType.Password, passwordState, disabled, "Password" ) DefaultButton("Authorise", UIKitButton.Type.Primary, UIKitMargin.Small, disabled = authBtnDisabled) { it.nativeEvent.preventDefault() val serverUrl = document.location ?.run { "$hostname:$port" } if (serverUrl != null) { uiScope.launchSafelyWithoutExceptions { viewModel.initAuth(serverUrl, usernameState.value, passwordState.value) } } } } } } val viewJob = viewModel.currentState.subscribeSafelyWithoutExceptions(uiScope) { when (it) { is InitAuthUIState -> { disabled.value = false errorText.value = when (it.showError) { ServerUnavailableAuthUIError -> "Server unavailable" AuthIncorrectAuthUIError -> { passwordState.value = "" "Username or password is incorrect" } null -> null } } LoadingAuthUIState -> { disabled.value = true errorText.value = null } AuthorizedAuthUIState -> { completion.complete(state.from) } } } return completion.await().also { composition.dispose() viewJob.cancel() } } }