feat(15): submitting form data on step back

This commit is contained in:
efim 2023-07-15 12:05:04 +00:00
parent 5f260455cb
commit 076dc76ca4
6 changed files with 40 additions and 76 deletions

View File

@ -39,9 +39,9 @@
class="flex flex-col items-center w-screen h-screen md:grid md:items-start md:p-5 md:bg-white md:rounded-2xl md:grid-cols-[auto_1fr] md:w-desktop-form md:h-desktop-form md:drop-shadow-2xl" class="flex flex-col items-center w-screen h-screen md:grid md:items-start md:p-5 md:bg-white md:rounded-2xl md:grid-cols-[auto_1fr] md:w-desktop-form md:h-desktop-form md:drop-shadow-2xl"
id="form-step" id="form-step"
th:fragment="formFragment(formData)" th:fragment="formFragment(formData)"
hx-post="/submit-step/1" hx-post="/submit-step/1/2"
hx-swap="outerHTML" hx-swap="outerHTML"
action="/submit-step/1" action="/submit-step/1/2"
method="post" method="post"
> >
<summary <summary

View File

@ -39,9 +39,9 @@
<form <form
class="flex flex-col items-center w-screen h-screen md:grid md:items-start md:p-5 md:bg-white md:rounded-2xl md:grid-cols-[auto_1fr] md:w-desktop-form md:h-desktop-form md:drop-shadow-2xl" class="flex flex-col items-center w-screen h-screen md:grid md:items-start md:p-5 md:bg-white md:rounded-2xl md:grid-cols-[auto_1fr] md:w-desktop-form md:h-desktop-form md:drop-shadow-2xl"
id="form-step" id="form-step"
hx-post="/submit-step/2" hx-post="/submit-step/2/3"
hx-swap="outerHTML" hx-swap="outerHTML"
action="/submit-step/2" action="/submit-step/2/3"
method="post" method="post"
th:fragment="formFragment(formData)" th:fragment="formFragment(formData)"
> >
@ -119,7 +119,7 @@
name="plan-type" name="plan-type"
value="Arcade" value="Arcade"
class="hidden peer" class="hidden peer"
th:checked="${formData.step2.planType.toString()} == 'Acrade'" th:checked="${formData.step2.planType.toString()} == 'Arcade'"
checked checked
/> />
<div <div
@ -187,9 +187,9 @@
class="flex flex-row items-center py-4 w-full bg-white md:items-end md:h-full" class="flex flex-row items-center py-4 w-full bg-white md:items-end md:h-full"
> >
<a <a
hx-get="/get-form/1" hx-post="/submit-step/2/1"
hx-target="#form-step"
hx-swap="outerHTML" hx-swap="outerHTML"
hx-target="#form-step"
href="step1.html" href="step1.html"
class="ml-6 text-sm font-semibold md:pb-3 md:ml-20 md:text-base text-cool-gray" class="ml-6 text-sm font-semibold md:pb-3 md:ml-20 md:text-base text-cool-gray"
>Go Back</a >Go Back</a

View File

@ -39,9 +39,9 @@
<form <form
class="flex flex-col items-center w-screen h-screen md:grid md:items-start md:p-5 md:bg-white md:rounded-2xl md:grid-cols-[auto_1fr] md:w-desktop-form md:h-desktop-form md:drop-shadow-2xl" class="flex flex-col items-center w-screen h-screen md:grid md:items-start md:p-5 md:bg-white md:rounded-2xl md:grid-cols-[auto_1fr] md:w-desktop-form md:h-desktop-form md:drop-shadow-2xl"
id="form-step" id="form-step"
hx-post="/submit-step/3" hx-post="/submit-step/3/4"
hx-swap="outerHTML" hx-swap="outerHTML"
action="/submit-step/3" action="/submit-step/3/4"
method="post" method="post"
th:fragment="formFragment(formData)" th:fragment="formFragment(formData)"
> >
@ -191,9 +191,9 @@
class="flex flex-row items-center py-4 w-full bg-white md:items-end md:h-full" class="flex flex-row items-center py-4 w-full bg-white md:items-end md:h-full"
> >
<a <a
hx-get="/get-form/2" hx-post="/submit-step/3/2"
hx-target="#form-step"
hx-swap="outerHTML" hx-swap="outerHTML"
hx-target="#form-step"
href="step2.html" href="step2.html"
class="ml-6 text-sm font-semibold md:pb-3 md:ml-20 md:text-base text-cool-gray" class="ml-6 text-sm font-semibold md:pb-3 md:ml-20 md:text-base text-cool-gray"
>Go Back</a >Go Back</a

View File

@ -39,8 +39,8 @@
<form <form
class="flex flex-col items-center w-screen h-screen md:grid md:items-start md:p-5 md:bg-white md:rounded-2xl md:grid-cols-[auto_1fr] md:w-desktop-form md:h-desktop-form md:drop-shadow-2xl" class="flex flex-col items-center w-screen h-screen md:grid md:items-start md:p-5 md:bg-white md:rounded-2xl md:grid-cols-[auto_1fr] md:w-desktop-form md:h-desktop-form md:drop-shadow-2xl"
id="form-step" id="form-step"
hx-post="/submit-step/4" hx-post="/submit-step/4/5"
action="/submit-step/4" action="/submit-step/4/5"
hx-swap="outerHTML" hx-swap="outerHTML"
method="post" method="post"
th:fragment="formFragment(formData)" th:fragment="formFragment(formData)"
@ -134,9 +134,9 @@
class="flex flex-row items-center py-4 w-full bg-white md:items-end md:h-full" class="flex flex-row items-center py-4 w-full bg-white md:items-end md:h-full"
> >
<a <a
hx-get="/get-form/3" hx-post="/submit-step/4/3"
hx-target="#form-step"
hx-swap="outerHTML" hx-swap="outerHTML"
hx-target="#form-step"
href="step3.html" href="step3.html"
class="ml-6 text-sm font-semibold md:pb-3 md:ml-20 md:text-base text-cool-gray" class="ml-6 text-sm font-semibold md:pb-3 md:ml-20 md:text-base text-cool-gray"
>Go Back</a >Go Back</a

View File

@ -4,45 +4,48 @@ import java.util.UUID
object Models { object Models {
val testAnsw = Answers( val testAnsw = Answers(
sessionId= "id1", sessionId = "id1",
currentStep = 1, currentStep = 1,
step1 = StepAnswers.Step1("Test Name", "some@email.com", "+9876", true), step1 = StepAnswers.Step1("Test Name", "some@email.com", "+9876", true),
step2 = StepAnswers.Step2(PlanType.Advanced, true, true), step2 = StepAnswers.Step2(PlanType.Advanced, true, true),
step3 = StepAnswers.Step3(Set(Addons.LargerStorage), true), step3 = StepAnswers.Step3(Set(Addons.LargerStorage), true),
step4 = StepAnswers.Step4(true) step4 = StepAnswers.Step4(true)
) )
final case class Answers( final case class Answers(
sessionId: String = "id1", sessionId: String = "id1",
currentStep: Int = 1, currentStep: Int = 1,
step1: StepAnswers.Step1 = StepAnswers.Step1("Test Name", "some@email.com", "+9876", true), step1: StepAnswers.Step1 =
step2: StepAnswers.Step2 = StepAnswers.Step2(PlanType.Advanced, true, true), StepAnswers.Step1("Test Name", "some@email.com", "+9876", true),
step3: StepAnswers.Step3 = StepAnswers.Step3(Set(Addons.LargerStorage), true), step2: StepAnswers.Step2 =
StepAnswers.Step2(PlanType.Advanced, true, true),
step3: StepAnswers.Step3 =
StepAnswers.Step3(Set(Addons.LargerStorage), true),
step4: StepAnswers.Step4 = StepAnswers.Step4() step4: StepAnswers.Step4 = StepAnswers.Step4()
) { ) {
// this is not enforced by compiler, sad, maintain by hand in html template files // this is not enforced by compiler, sad, maintain by hand in html template files
def fragmentName: String = s"step${currentStep}" def fragmentName: String = s"step${currentStep}"
def updateStep(stepNum: Int, rawData: String): Answers = { def updateStep(stepNum: Int, rawData: String, nextStep: Int): Answers = {
stepNum match { stepNum match {
case 1 => case 1 =>
this.copy( this.copy(
step1 = this.step1.fromFormData(rawData), step1 = this.step1.fromFormData(rawData),
currentStep = stepNum + 1 currentStep = nextStep
) )
case 2 => case 2 =>
this.copy( this.copy(
step2 = this.step2.fromFormData(rawData), step2 = this.step2.fromFormData(rawData),
currentStep = stepNum + 1 currentStep = nextStep
) )
case 3 => case 3 =>
this.copy( this.copy(
step3 = this.step3.fromFormData(rawData), step3 = this.step3.fromFormData(rawData),
currentStep = stepNum + 1 currentStep = nextStep
) )
case 4 => case 4 =>
this.copy( this.copy(
currentStep = stepNum + 1, step4 = this.step4,
step4 = this.step4 currentStep = nextStep
) )
case _ => this case _ => this
} }

View File

@ -7,6 +7,8 @@ import cask.endpoints.ParamReader
import java.util.UUID import java.util.UUID
import scala.jdk.CollectionConverters._ import scala.jdk.CollectionConverters._
import multistepform.Models.Answers import multistepform.Models.Answers
import scala.annotation.internal.requiresCapability
import java.net.URLDecoder
case class Routes()(implicit cc: castor.Context, log: cask.Logger) case class Routes()(implicit cc: castor.Context, log: cask.Logger)
extends cask.Routes { extends cask.Routes {
@ -85,54 +87,11 @@ case class Routes()(implicit cc: castor.Context, log: cask.Logger)
) )
} }
@cask.get("/get-form/:stepNum") @cask.post("/submit-step/:stepNum/:nextStep")
def getFormByStep(stepNum: Int, sessionId: cask.Cookie) = {
val id = sessionId.value
val answersData = Sessions.sessionReplies.get(id)
println(s"returning to step $stepNum with data $answersData")
answersData match {
case Some(state) => {
val stepData = stepNum match {
case 1 => state.step1
case 2 => state.step2
case 3 => state.step3
case 4 => state.step4
}
if (!stepData.submitted) {
cask.Response(
s"Your previous answer for step $stepNum not found, please reload the page"
)
} else {
val context = new Context()
val updatedState = state.copy(currentStep = stepNum)
Sessions.sessionReplies.update(id, updatedState)
context.setVariable(formDataContextVarName, updatedState)
val formFragment = templateEngine.process(
updatedState.fragmentName,
Set("formFragment").asJava,
context
)
cask.Response(
formFragment,
headers = Seq("Content-Type" -> "text/html;charset=UTF-8")
)
}
}
case None =>
cask.Response(
"Your previous answers not found, please reload the page",
404
)
}
}
// i guess let's make step a hidden input?
@cask.post("/submit-step/:stepNum")
def submitStep( def submitStep(
sessionId: cask.Cookie, sessionId: cask.Cookie,
stepNum: Int, stepNum: Int,
nextStep: Int,
request: cask.Request request: cask.Request
) = { ) = {
val id = sessionId.value val id = sessionId.value
@ -140,7 +99,9 @@ case class Routes()(implicit cc: castor.Context, log: cask.Logger)
val userAnswers = Sessions.sessionReplies.getOrElse(id, Answers(id)) val userAnswers = Sessions.sessionReplies.getOrElse(id, Answers(id))
val updatedAnswers = userAnswers.updateStep(stepNum, request.text()) val submittedData = URLDecoder.decode(request.text() , "UTF-8")
val updatedAnswers = userAnswers.updateStep(stepNum, submittedData, nextStep)
Sessions.sessionReplies.update(id, updatedAnswers) Sessions.sessionReplies.update(id, updatedAnswers)