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:
parent
f9c32fd7dc
commit
6d827365ac
|
@ -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"
|
||||||
|
|
|
@ -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 =>
|
||||||
|
|
Loading…
Reference in New Issue