Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
[[PM127]](#127) Re authored the SignUpService to accommodate the new …
…designs
  • Loading branch information
andylamax committed Oct 7, 2021
commit ef6294c7a91f27a7e047ef181178f055907ce2ce
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## PiMonitor Client SDK Core

- [[PM127]](https://github.com/picortex/bitframe/issues/127) Re authored the SignUpService to accommodate the new designs
- [[PM103]](https://github.com/picortex/bitframe/issues/103) Moved SignUpTest to commonMain

## PiMonitor Client Browser Web
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
@file:JsExport

package bitframe.presenters.fields

import kotlin.js.JsExport
import kotlin.js.JsName

data class DropDownInputField(
val options: List<Option>
) {
@JsName("from")
constructor(vararg options: Option) : this(options.toList())

val items get() = options.toTypedArray()

data class Option(
val label: String, val value: String = label, val selected: Boolean = false
)
}
6 changes: 5 additions & 1 deletion pi-monitor/pi-monitor-client/browser/react/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import com.bmuschko.gradle.docker.tasks.image.DockerBuildImage
import com.bmuschko.gradle.docker.tasks.image.Dockerfile
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin
import org.jetbrains.kotlin.gradle.targets.js.yarn.YarnRootExtension

plugins {
kotlin("multiplatform")
Expand All @@ -18,7 +19,10 @@ applikation {
}

rootProject.plugins.withType(NodeJsRootPlugin::class.java) {
rootProject.the<NodeJsRootExtension>().versions.webpackDevServer.version = "4.1.0"
rootProject.the<NodeJsRootExtension>().versions.apply {
webpackDevServer.version = "4.1.0"
webpackCli.version = "4.9.0"
}
}

kotlin {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import kotlinx.extensions.onDesktop
import kotlinx.extensions.onMobile
import kotlinx.extensions.text
import kotlinx.html.InputType
import pimonitor.authentication.signup.legacy.IndividualFormFields
import react.RBuilder
import reakt.*
import styled.css
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import kotlinx.extensions.onDesktop
import kotlinx.extensions.onMobile
import kotlinx.extensions.text
import kotlinx.html.InputType
import pimonitor.authentication.signup.legacy.OrganisationFormFields
import react.RBuilder
import reakt.*
import styled.css
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ package pimonitor.authentication.signup
import kotlinx.css.minHeight
import kotlinx.css.vh
import pimonitor.PiMonitorService
import pimonitor.authentication.signup.SignUpState.*
import pimonitor.authentication.signup.legacy.SignUpState.*
import pimonitor.authentication.signup.exports.SignUpScope
import pimonitor.authentication.signup.SignUpIntent as Intent
import pimonitor.authentication.signup.legacy.SignUpIntent as Intent
import react.Props
import react.RBuilder
import react.fc
Expand Down
1 change: 1 addition & 0 deletions pi-monitor/pi-monitor-client/sdks/full/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ kotlin {

val commonTest by getting {
dependencies {
implementation(project(":pi-monitor-test-testing"))
implementation(asoft("viewmodel-test-expect", vers.asoft.viewmodel))
implementation(asoft("expect-core", vers.asoft.expect))
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
@file:JsExport

package pimonitor.authentication.signup

import bitframe.presenters.fields.ButtonInputField
import bitframe.presenters.fields.DropDownInputField
import bitframe.presenters.fields.DropDownInputField.Option
import bitframe.presenters.fields.TextInputField
import kotlin.js.JsExport

data class BusinessFormFields(
val title: String = "Create Your Account",
val select: DropDownInputField = DropDownInputField(
Option("Select account type"),
Option("Register as Business", selected = true),
Option("Register as Individual")
),
val businessName: TextInputField = TextInputField("Business Name"),
val individualName: TextInputField = TextInputField("Your Name"),
val individualEmail: TextInputField = TextInputField("Your Email"),
val password: TextInputField = TextInputField("Password"),
val submitButton: ButtonInputField = ButtonInputField("Get Started"),
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package pimonitor.authentication.signup

fun BusinessFormFields.copy(i: SignUpIntent.Submit.BusinessForm) = copy(
businessName = businessName.copy(value = i.params.businessName),
individualName = individualName.copy(value = i.params.individualName),
individualEmail = individualEmail.copy(value = i.params.individualEmail),
password = password.copy(value = i.params.password)
)
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,24 @@
package pimonitor.authentication.signup

import bitframe.presenters.fields.ButtonInputField
import bitframe.presenters.fields.DropDownInputField
import bitframe.presenters.fields.DropDownInputField.Option
import bitframe.presenters.fields.TextInputField
import kotlin.js.JsExport

data class IndividualFormFields(
val title: String = "Enter your personal information",
val title: String = "Create Your Account",
val select: DropDownInputField = DropDownInputField(
Option("Select account type"),
Option("Register as Business"),
Option("Register as Individual", selected = true)
),
val name: TextInputField = TextInputField(
label = "Name",
hint = "John Doe"
label = "Name", hint = "Full Name"
),
val email: TextInputField = TextInputField(
label = "Email",
hint = "[email protected]"
),
val password: TextInputField = TextInputField(
label = "Password",
hint = "secure-password"
label = "Email", hint = "Email Address"
),
val nextButton: ButtonInputField = ButtonInputField("Submit"),
val prevButton: ButtonInputField = ButtonInputField("Back")
) {
internal fun copy(params: IndividualRegistrationParams) = copy(
name = name.copy(value = params.name),
email = email.copy(value = params.email),
password = email.copy(value = params.password)
)
}
val password: TextInputField = TextInputField("Password"),
val submitButton: ButtonInputField = ButtonInputField("Get Started"),
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package pimonitor.authentication.signup

fun IndividualFormFields.copy(i: SignUpIntent.Submit.IndividualForm) = copy(
name = name.copy(value = i.params.name),
email = email.copy(value = i.params.email),
password = password.copy(value = i.params.password)
)
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,17 @@

package pimonitor.authentication.signup

import pimonitor.authentication.signup.legacy.IndividualFormFields
import pimonitor.authentication.signup.legacy.OrganisationFormFields
import pimonitor.monitors.SignUpParams
import kotlin.js.JsExport

sealed class SignUpIntent {
object SelectRegistrationType : SignUpIntent()
data class RegisterAsIndividual(val fields: IndividualFormFields?) : SignUpIntent()
data class RegisterAsOrganization(val fields: OrganisationFormFields?) : SignUpIntent()
data class SubmitIndividualForm(val params: IndividualRegistrationParams) : SignUpIntent()
data class SubmitBusinessForm(val params: MonitorBusinessParams) : SignUpIntent()
data class SelectRegisterAsIndividual(val fields: IndividualFormFields?) : SignUpIntent()
data class SelectRegisterAsBusiness(val fields: OrganisationFormFields?) : SignUpIntent()

sealed class Submit(open val params: SignUpParams) : SignUpIntent() {
data class IndividualForm(override val params: SignUpParams.Individual) : Submit(params)
data class BusinessForm(override val params: SignUpParams.Business) : Submit(params)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,16 @@

package pimonitor.authentication.signup

import bitframe.presenters.feedbacks.FormFeedback
import kotlin.js.JsExport

sealed class SignUpState {

data class Loading(val message: String) : SignUpState()

object SelectRegistrationType : SignUpState()

data class IndividualForm(
val fields: IndividualFormFields,
val organisationForm: OrganisationForm?
val fields: IndividualFormFields, val status: FormFeedback?
) : SignUpState()

data class OrganisationForm(val fields: OrganisationFormFields) : SignUpState()

data class Success(val message: String) : SignUpState()

data class Failure(val cause: Throwable, val message: String? = cause.message) : SignUpState()
data class BusinessForm(
val fields: BusinessFormFields, val status: FormFeedback?
) : SignUpState()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package pimonitor.authentication.signup

import bitframe.presenters.feedbacks.FormFeedback

fun SignUpState.IndividualForm.copy(
i: SignUpIntent.Submit.IndividualForm, status: FormFeedback?
) = copy(
fields = fields.copy(i), status = status
)

fun SignUpState.BusinessForm.copy(
i: SignUpIntent.Submit.BusinessForm, status: FormFeedback?
) = copy(
fields = fields.copy(i), status = status
)

fun SignUpState.copy(i: SignUpIntent.Submit.BusinessForm, status: FormFeedback?) = when (this) {
is SignUpState.IndividualForm -> error("Can't submit a business form while the viewmodel is in individual form state")
is SignUpState.BusinessForm -> copy(i, status)
}

fun SignUpState.copy(i: SignUpIntent.Submit.IndividualForm, status: FormFeedback?) = when (this) {
is SignUpState.IndividualForm -> copy(i, status)
is SignUpState.BusinessForm -> error("Can't submit an individual's form while the viewmodel is in business form state")
}

fun SignUpState.copy(i: SignUpIntent.Submit, status: FormFeedback?) = when (i) {
is SignUpIntent.Submit.IndividualForm -> copy(i, status)
is SignUpIntent.Submit.BusinessForm -> copy(i, status)
}
Original file line number Diff line number Diff line change
@@ -1,84 +1,49 @@
package pimonitor.authentication.signup

import bitframe.presenters.feedbacks.FormFeedback.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.launch
import later.await
import bitframe.presenters.fields.ButtonInputField
import pimonitor.authentication.signup.SignUpIntent.*
import viewmodel.ViewModel
import pimonitor.authentication.signup.SignUpIntent as Intent
import pimonitor.authentication.signup.SignUpState as State

class SignUpViewModel(
private val service: SignUpService
) : ViewModel<Intent, State>(State.SelectRegistrationType) {

private val recoveryTime = 3000
val service: SignUpService
) : ViewModel<Intent, State>(State.IndividualForm(IndividualFormFields(), null)) {
val recoveryTime = 3000L

override fun CoroutineScope.execute(i: Intent): Any = when (i) {
SelectRegistrationType -> ui.value = State.SelectRegistrationType
is RegisterAsIndividual -> ui.value = State.IndividualForm(
fields = i.fields ?: IndividualFormFields(
prevButton = ButtonInputField("Back") { post(SelectRegistrationType) }
),
organisationForm = null
)
is RegisterAsOrganization -> ui.value = State.OrganisationForm(
fields = i.fields ?: OrganisationFormFields(
prevButton = ButtonInputField("Back") { post(SelectRegistrationType) }
)
)
is SubmitIndividualForm -> submitPersonalInfo(i, ui.value as State.IndividualForm)
is SubmitBusinessForm -> submitBusinessInfo(i, ui.value as State.OrganisationForm)
is Intent.SelectRegisterAsIndividual -> selectRegisterAsIndividual(i)
is Intent.SelectRegisterAsBusiness -> selectRegisterAsBusiness(i)
is Intent.Submit.IndividualForm -> submitForm(i)
is Intent.Submit.BusinessForm -> submitForm(i)
}

private fun CoroutineScope.submitPersonalInfo(
i: SubmitIndividualForm,
state: State.IndividualForm
) = launch {
private fun CoroutineScope.submitForm(i: Intent.Submit) = launch {
val state = ui.value
flow {
emit(State.Loading("Submitting your registration, Please wait . . ."))
val person = i.params.toPerson()
val organisationFields = state.organisationForm?.fields
if (organisationFields != null) {
val business = organisationFields.toParams().toBusiness()
service.register(business, representedBy = person).await()
} else {
service.registerIndividuallyAs(i.params).await()
}
emit(State.Success("Registration completed successfully"))
emit(state.copy(i, Loading("Creating your account, please wait . . .")))
service.signUp(i.params).await()
emit(state.copy(i, Success("Your registration completed successfully")))
}.catch {
emit(State.Failure(it, "Registration failed"))
delay(recoveryTime.toLong())
emit(state.copy(fields = state.fields.copy(i.params)))
emit(state.copy(i, Failure(it, "Failed to create your account")))
delay(recoveryTime)
emit(state.copy(i, null))
}.collect {
ui.value = it
}
}

private fun CoroutineScope.submitBusinessInfo(
i: SubmitBusinessForm,
state: State.OrganisationForm
) = launch {
flow {
emit(State.Loading("Validating business input"))
i.params.toBusiness()
val params = IndividualFormFields(
prevButton = ButtonInputField("Back") {
ui.value = state.copy(fields = state.fields.copy(i.params))
}
)
emit(State.IndividualForm(params, state.copy(fields = state.fields.copy(i.params))))
}.catch {
emit(State.Failure(it, "Validation Failed"))
delay(recoveryTime.toLong())
emit(state.copy(fields = state.fields.copy(i.params)))
}.collect {
ui.value = it
}
private fun selectRegisterAsIndividual(i: Intent.SelectRegisterAsIndividual) {
ui.value = State.IndividualForm(IndividualFormFields(), null)
}

private fun selectRegisterAsBusiness(i: Intent.SelectRegisterAsBusiness) {
ui.value = State.BusinessForm(BusinessFormFields(), null)
}
}
Loading