feat(#5): Add title-body control element that can be added dynamically, refactored sectionIndex/create

This commit is contained in:
2025-11-02 10:32:46 +01:00
parent 4d371be2e3
commit 736cd17789
12 changed files with 407 additions and 88 deletions

View File

@@ -31,15 +31,16 @@
<template #body>
<div class="flex flex-col w-full lg:max-w-4xl mx-auto">
<UStepper ref="stepper" v-model="activeStepperItemIndex" :items="stepperItems" class="w-full" />
<h1 class="text-xl text-pretty font-bold text-highlighted">
<h1 v-if="currentFormElementSection?.title" class="text-xl text-pretty font-bold text-highlighted">
{{ currentFormElementSection.title }}
</h1>
<UCard variant="subtle">
<FormEngine
v-if="applicationForm"
v-if="applicationForm && currentFormElementSection?.formElements"
v-model="currentFormElementSection.formElements"
:application-form-id="applicationForm.id"
:disabled="isReadOnly"
@add:input-form="handleAddInputForm"
/>
<div class="flex gap-2 justify-between mt-4">
<UButton
@@ -75,8 +76,7 @@
</template>
<script setup lang="ts">
import type { ApplicationFormDto, FormElementSectionDto } from '~/.api-client'
import type { StepperItem } from '@nuxt/ui'
import type { ApplicationFormDto } from '~/.api-client'
const { getApplicationFormById, updateApplicationForm, submitApplicationForm } = useApplicationForm()
const route = useRoute()
@@ -90,11 +90,6 @@ definePageMeta({
key: (route) => `${route.params.id}`
})
onMounted(() => {
const sectionIndex = parseInt(route.params.sectionIndex[0])
activeStepperItemIndex.value = !isNaN(sectionIndex) ? sectionIndex : 0
})
const items = [
[
{
@@ -105,13 +100,6 @@ const items = [
]
]
const stepper = useTemplateRef('stepper')
const activeStepperItemIndex = ref<number>(0)
const currentFormElementSection = computed<FormElementSectionDto>(
() => applicationForm.value?.formElementSections[activeStepperItemIndex.value]
)
const { data, error } = await useAsyncData<ApplicationFormDto>(`application-form-${route.params.id}`, async () => {
console.log('Fetching application form with ID:', route.params.id)
return await getApplicationFormById(Array.isArray(route.params.id) ? route.params.id[0] : route.params.id)
@@ -124,29 +112,35 @@ if (error.value) {
const applicationForm = computed<ApplicationFormDto>(() => data?.value as ApplicationFormDto)
const isReadOnly = computed(() => {
return applicationForm.value?.createdBy.id !== user.value?.id
return applicationForm.value?.createdBy.keycloakId !== user.value?.keycloakId
})
const stepperItems = computed(() => {
const stepperItems: StepperItem[] = []
applicationForm.value.formElementSections.forEach((section: FormElementSectionDto) => {
stepperItems.push({
title: section.shortTitle,
description: section.description
})
})
return stepperItems
})
async function navigateStepper(direction: 'forward' | 'backward') {
if (direction === 'forward') {
stepper.value?.next()
} else {
stepper.value?.prev()
const { stepper, activeStepperItemIndex, stepperItems, currentFormElementSection, navigateStepper } = useFormStepper(
computed(() => applicationForm.value?.formElementSections),
{
onNavigate: async () => {
await navigateTo(`/application-forms/${route.params.id}/${activeStepperItemIndex.value}`)
}
}
)
const { addInputFormToApplicationForm } = useFormElementManagement(
currentFormElementSection,
applicationForm.value?.id
)
async function handleAddInputForm(position: number) {
const updatedForm = await addInputFormToApplicationForm(position)
if (updatedForm) {
data.value = updatedForm
}
await navigateTo(`/application-forms/${route.params.id}/${activeStepperItemIndex.value}`)
}
onMounted(() => {
const sectionIndex = parseInt(route.params.sectionIndex[0])
activeStepperItemIndex.value = !isNaN(sectionIndex) ? sectionIndex : 0
})
async function onSave() {
if (data?.value) {
await updateApplicationForm(data.value.id, data.value)

View File

@@ -39,6 +39,7 @@
<FormEngine
v-if="currentFormElementSection?.formElements"
v-model="currentFormElementSection.formElements"
@add:input-form="addInputFormToApplicationForm"
/>
<div class="flex gap-2 justify-between mt-4">
<UButton
@@ -71,10 +72,9 @@
</template>
<script setup lang="ts">
import { ComplianceStatus, type FormElementSectionDto, type PagedApplicationFormDto } from '~/.api-client'
import { ComplianceStatus, type PagedApplicationFormDto } from '~/.api-client'
import { useApplicationFormValidator } from '~/composables/useApplicationFormValidator'
import type { FormElementId } from '~/types/formElement'
import type { StepperItem } from '@nuxt/ui'
const { getAllApplicationFormTemplates } = await useApplicationFormTemplate()
const { createApplicationForm, submitApplicationForm } = useApplicationForm()
@@ -84,17 +84,6 @@ const userStore = useUserStore()
const { selectedOrganization } = storeToRefs(userStore)
const toast = useToast()
const stepper = useTemplateRef('stepper')
const activeStepperItemIndex = ref<number>(0)
const currentFormElementSection = computed(
() => applicationFormTemplate.value?.formElementSections[activeStepperItemIndex.value]
)
watch(activeStepperItemIndex, async (newActiveStepperItem: number) => {
activeStepperItemIndex.value = newActiveStepperItem
})
const { data, error } = await useAsyncData<PagedApplicationFormDto>(async () => {
return await getAllApplicationFormTemplates()
})
@@ -103,34 +92,17 @@ if (error.value) {
throw createError({ statusText: error.value.message })
}
const stepperItems = computed(() => {
const stepperItems: StepperItem[] = []
if (!applicationFormTemplate.value) {
return stepperItems
}
applicationFormTemplate.value.formElementSections.forEach((section: FormElementSectionDto) => {
stepperItems.push({
title: section.shortTitle,
description: section.description
})
})
return stepperItems
})
async function navigateStepper(direction: 'forward' | 'backward') {
if (direction === 'forward') {
stepper.value?.next()
} else {
stepper.value?.prev()
}
}
const applicationFormTemplate = computed(
// TODO: Don't select always the first item, allow user to select a template
() => data?.value?.content[0] ?? undefined
)
const { stepper, activeStepperItemIndex, stepperItems, currentFormElementSection, navigateStepper } = useFormStepper(
computed(() => applicationFormTemplate.value?.formElementSections)
)
const { addInputFormToApplicationForm } = useFormElementManagement(currentFormElementSection)
const formElements = computed({
get: () => currentFormElementSection?.value?.formElements ?? [],
set: (val) => {