feat(15): dynamic rendering of plan types

currently only on page revisit.
for dynamic - need to use htmx swapping, with separate endpoing getting
updates value from whole element being a fragment
This commit is contained in:
efim 2023-07-15 13:21:26 +00:00
parent f9c32fd7dc
commit 6d827365ac
2 changed files with 46 additions and 19 deletions

View File

@ -109,27 +109,38 @@
<p class="py-3 text-cool-gray"> <p class="py-3 text-cool-gray">
You have the option of monthly or yearly billing. You have the option of monthly or yearly billing.
</p> </p>
<div <div class="flex flex-col w-full md:flex-row">
class="flex flex-col w-full md:flex-row" <label
> for="ArcadePlanType"
<label for="ArcadePlanType" class="relative h-20 md:w-32"> class="relative h-20 md:w-32"
th:each="planType: ${formData.availablePlans}"
th:for="${planType}"
>
<input <input
id="ArcadePlanType" id="ArcadePlanType"
th:id="${planType}"
type="radio" type="radio"
name="plan-type" name="plan-type"
value="Arcade" value="Arcade"
th:value="${planType}"
class="hidden peer" class="hidden peer"
th:checked="${formData.userAnswers.step2.planType.toString()} == 'Arcade'" th:checked="${formData.userAnswers.step2.planType.toString()} == ${planType.toString()}"
checked checked
/> />
<div <div
class="absolute inset-y-0 inset-x-0 rounded-lg border border-cool-gray peer-checked:border-purplish-blue peer-checked:bg-magnolia" class="absolute inset-y-0 inset-x-0 rounded-lg border border-cool-gray peer-checked:border-purplish-blue peer-checked:bg-magnolia"
> >
<h2 class="">Arcade</h2> <h2 th:text="${planType}" class="">Arcade</h2>
<p th:text="|${formData.planCost(planType)}/${formData.periodCostLabel}|">$90/yr</p>
<p th:if="${formData.userAnswers.step2.isYearly}">2 months free</p>
</div> </div>
</label> </label>
<label for="AdvancedPlanType" class="relative h-20 md:w-32"> <label
for="AdvancedPlanType"
class="relative h-20 md:w-32"
th:remove="all"
>
<input <input
id="AdvancedPlanType" id="AdvancedPlanType"
type="radio" type="radio"
@ -145,7 +156,11 @@
</div> </div>
</label> </label>
<label for="ProPlanType" class="relative h-20 md:w-32"> <label
for="ProPlanType"
class="relative h-20 md:w-32"
th:remove="all"
>
<input <input
id="ProPlanType" id="ProPlanType"
type="radio" type="radio"
@ -162,20 +177,30 @@
</label> </label>
</div> </div>
<div class="grid grid-flow-col-dense place-content-center w-full rounded-lg bg-magnolia"> <div
class="grid grid-flow-col-dense place-content-center w-full rounded-lg bg-magnolia"
>
<div <div
class="inline-grid grid-cols-3 place-items-center h-12 text-sm font-bold" class="inline-grid grid-cols-3 place-items-center h-12 text-sm font-bold"
> >
<input <input
class="mr-2 w-9 h-5 ml-2 rounded-full appearance-none mt-[0.3rem] bg-marine-blue after:absolute after:h-3 after:w-3 after:rounded-full after:border-none after:bg-neutral-100 after:transition-[background-color_0.2s,transform_0.2s] checked:after:ml-[1.2rem] after:ml-[0.25rem] after:mt-[0.25rem] hover:cursor-pointer col-start-2 row-start-1 peer" class="mr-2 w-9 h-5 ml-2 rounded-full appearance-none mt-[0.3rem] bg-marine-blue after:absolute after:h-3 after:w-3 after:rounded-full after:border-none after:bg-neutral-100 after:transition-[background-color_0.2s,transform_0.2s] checked:after:ml-[1.2rem] after:ml-[0.25rem] after:mt-[0.25rem] hover:cursor-pointer col-start-2 row-start-1 peer"
type="checkbox" type="checkbox"
name="isPackageYearly" name="isPackageYearly"
role="switch" role="switch"
id="packageDuration" id="packageDuration"
th:checked="${formData.userAnswers.step2.isYearly}" th:checked="${formData.userAnswers.step2.isYearly}"
/> />
<p class="row-start-1 text-marine-blue peer-checked:text-cool-gray">Monthly</p> <p
<p class="row-start-1 text-cool-gray peer-checked:text-marine-blue">Yearly</p> class="row-start-1 text-marine-blue peer-checked:text-cool-gray"
>
Monthly
</p>
<p
class="row-start-1 text-cool-gray peer-checked:text-marine-blue"
>
Yearly
</p>
</div> </div>
</div> </div>
@ -199,7 +224,7 @@
type="submit" type="submit"
class="grid place-content-center mr-3 w-24 h-10 text-sm font-semibold text-white rounded md:mr-24 md:w-32 md:h-12 md:text-base md:rounded-lg bg-marine-blue" class="grid place-content-center mr-3 w-24 h-10 text-sm font-semibold text-white rounded md:mr-24 md:w-32 md:h-12 md:text-base md:rounded-lg bg-marine-blue"
value="Next Step" value="Next Step"
> />
<a <a
th:remove="all" th:remove="all"
href="step3.html" href="step3.html"

View File

@ -19,9 +19,6 @@ object Models {
final case class FormData( final case class FormData(
userAnswers: Answers userAnswers: Answers
) { ) {
def planDiscountMessage: Option[String] =
if (userAnswers.step2.isYearly) Some("2 monts free") else None
// yeah, in real world it will not be this simple // yeah, in real world it will not be this simple
def yearlyCost(monthlyCost: Int): Int = 10 * monthlyCost def yearlyCost(monthlyCost: Int): Int = 10 * monthlyCost
@ -29,8 +26,10 @@ object Models {
if (userAnswers.step2.isYearly) "yr" else "mo" if (userAnswers.step2.isYearly) "yr" else "mo"
} }
def planCost: Int = { def selectedPlanCost: Int = planCost(userAnswers.step2.planType)
val monthlyPlanCost = userAnswers.step2.planType match {
def planCost(plan: PlanType): Int = {
val monthlyPlanCost = plan match {
case PlanType.Arcade => 9 case PlanType.Arcade => 9
case PlanType.Advanced => 12 case PlanType.Advanced => 12
case PlanType.Pro => 15 case PlanType.Pro => 15
@ -56,8 +55,10 @@ object Models {
} }
def fullOrderPrice: Int = { def fullOrderPrice: Int = {
planCost + userAnswers.step3.addons.map(addonCost).sum selectedPlanCost + userAnswers.step3.addons.map(addonCost).sum
} }
def availablePlans = PlanType.values.toList.asJava
} }
final case class Answers( final case class Answers(
@ -73,6 +74,7 @@ object Models {
) { ) {
// 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, nextStep: Int): Answers = { def updateStep(stepNum: Int, rawData: String, nextStep: Int): Answers = {
stepNum match { stepNum match {
case 1 => case 1 =>