core/client/src/jsMain/kotlin/dev/inmo/postssystem/client/fsm/ui/AuthView.kt

121 lines
5.1 KiB
Kotlin

package dev.inmo.postssystem.client.fsm.ui
import dev.inmo.postssystem.client.ui.fsm.*
import dev.inmo.postssystem.client.utils.HTMLViewContainer
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 kotlinx.browser.document
import kotlinx.coroutines.*
import kotlinx.dom.clear
import kotlinx.html.*
import kotlinx.html.dom.append
import kotlinx.html.js.form
import kotlinx.html.js.onClickFunction
import org.w3c.dom.*
class AuthView(
private val viewModel: AuthUIViewModel,
private val uiScope: CoroutineScope
) : JSView<AuthUIFSMState>() {
private val usernameInput
get() = document.getElementById("authUsername") as? HTMLInputElement
private val passwordInput
get() = document.getElementById("authPassword") as? HTMLInputElement
private val authButton
get() = document.getElementById("authButton")
private val errorBadge
get() = document.getElementById("errorBadge") as? HTMLElement
private val progressBarDiv
get() = document.getElementById("progressBar") as? HTMLDivElement
override suspend fun StatesMachine<in UIFSMState>.safeHandleState(
htmlElement: HTMLElement,
container: HTMLViewContainer,
state: AuthUIFSMState
): UIFSMState? {
val completion = CompletableDeferred<UIFSMState?>()
htmlElement.clear()
htmlElement.append {
form(classes = "vertical_container") {
div(classes = "mdl-textfield mdl-js-textfield mdl-textfield--floating-label") {
input(type = InputType.text, classes = "mdl-textfield__input") {
id = "authUsername"
}
label(classes = "mdl-textfield__label") {
+"Имя пользователя"
}
}
div(classes = "mdl-textfield mdl-js-textfield mdl-textfield--floating-label") {
input(type = InputType.password, classes = "mdl-textfield__input") {
id = "authPassword"
}
label(classes = "mdl-textfield__label") {
+"Пароль"
}
}
div(classes = "mdl-progress mdl-js-progress") {
id = "progressBar"
}
span(classes = "material-icons mdl-badge mdl-badge--overlap gone") {
id = "errorBadge"
attributes["data-badge"] = "!"
}
button(classes = "mdl-button mdl-js-button mdl-button--raised") {
+"Авторизоваться"
id = "authButton"
onClickFunction = {
it.preventDefault()
val serverUrl = document.location ?.run { "$hostname:$port" }
val username = usernameInput ?.value
val password = passwordInput ?.value
if (serverUrl != null && username != null && password != null) {
uiScope.launchSafelyWithoutExceptions { viewModel.initAuth(serverUrl, username, password) }
}
}
}
}
}
val viewJob = viewModel.currentState.subscribeSafelyWithoutExceptions(uiScope) {
when (it) {
is InitAuthUIState -> {
usernameInput ?.removeAttribute("disabled")
passwordInput ?.removeAttribute("disabled")
authButton ?.removeAttribute("disabled")
errorBadge ?.apply {
when (it.showError) {
ServerUnavailableAuthUIError -> {
classList.remove("gone")
innerText = "Сервер недоступен"
}
AuthIncorrectAuthUIError -> {
classList.remove("gone")
innerText = "Данные некорректны"
}
null -> classList.add("gone")
}
}
progressBarDiv ?.classList ?.add("gone")
}
LoadingAuthUIState -> {
usernameInput ?.setAttribute("disabled", "")
passwordInput ?.setAttribute("disabled", "")
authButton ?.setAttribute("disabled", "")
errorBadge ?.classList ?.add("gone")
progressBarDiv ?.classList ?.remove("gone")
}
AuthorizedAuthUIState -> {
htmlElement.clear()
completion.complete(state.from)
}
}
}
return completion.await().also {
viewJob.cancel()
}
}
}