fix(frontend): Keep dirty state when switching sections

This commit is contained in:
2025-07-14 06:37:13 +02:00
parent db654695f2
commit bd49291bf2
2 changed files with 27 additions and 44 deletions

View File

@@ -72,6 +72,16 @@ const { getApplicationFormById, updateApplicationForm } = useApplicationForm()
const route = useRoute() const route = useRoute()
const { user } = useAuth() const { user } = useAuth()
definePageMeta({
// Prevent whole page from re-rendering when navigating between sections to keep state
key: (route) => `${route.params.id}`,
})
onMounted(() => {
const sectionIndex = parseInt(route.params.sectionIndex[0])
activeStepperItemIndex.value = !isNaN(sectionIndex) ? sectionIndex : 0
})
const items = [ const items = [
[ [
{ {
@@ -85,25 +95,12 @@ const items = [
const stepper = useTemplateRef('stepper') const stepper = useTemplateRef('stepper')
const activeStepperItemIndex = ref<number>(0) const activeStepperItemIndex = ref<number>(0)
const currentFormElementSection = computed<FormElementSectionDto>(() => { const currentFormElementSection = computed<FormElementSectionDto>(
return applicationForm.value?.formElementSections[activeStepperItemIndex.value] () => applicationForm.value?.formElementSections[activeStepperItemIndex.value]
})
watch(activeStepperItemIndex, async (newActiveStepperItem: number) => {
activeStepperItemIndex.value = newActiveStepperItem
await navigateTo(`/application-forms/${route.params.id}/${newActiveStepperItem}`)
})
watch(
() => route.path,
(_) => {
const sectionIndex = parseInt(route.params.sectionIndex[0])
activeStepperItemIndex.value = !isNaN(sectionIndex) ? sectionIndex : 0
},
{ immediate: true }
) )
const { data, error } = await useAsyncData<ApplicationFormDto>(async () => { 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) return await getApplicationFormById(Array.isArray(route.params.id) ? route.params.id[0] : route.params.id)
}) })
@@ -111,14 +108,7 @@ if (error.value) {
throw createError({ statusText: error.value.message }) throw createError({ statusText: error.value.message })
} }
const applicationForm = computed<ApplicationFormDto>({ const applicationForm = computed<ApplicationFormDto>(() => data?.value as ApplicationFormDto)
get: () => data?.value as ApplicationFormDto,
set: (val: ApplicationFormDto) => {
if (val && data.value) {
data.value = val
}
}
})
const isReadOnly = computed(() => { const isReadOnly = computed(() => {
return applicationForm.value?.createdBy.id !== user.value?.id return applicationForm.value?.createdBy.id !== user.value?.id
@@ -126,7 +116,7 @@ const isReadOnly = computed(() => {
const stepperItems = computed(() => { const stepperItems = computed(() => {
const stepperItems: StepperItem[] = [] const stepperItems: StepperItem[] = []
applicationForm.value.formElementSections.forEach((section: FormElementSectionDto, index: number, _) => { applicationForm.value.formElementSections.forEach((section: FormElementSectionDto) => {
stepperItems.push({ stepperItems.push({
title: section.shortTitle, title: section.shortTitle,
description: section.description description: section.description
@@ -141,9 +131,7 @@ async function navigateStepper(direction: 'forward' | 'backward') {
} else { } else {
stepper.value?.prev() stepper.value?.prev()
} }
const targetSectionIndex = await navigateTo(`/application-forms/${route.params.id}/${activeStepperItemIndex.value}`)
direction === 'forward' ? activeStepperItemIndex.value + 1 : activeStepperItemIndex.value - 1
await navigateTo(`/application-forms/${route.params.id}/${targetSectionIndex}`)
} }
async function onSubmit() { async function onSubmit() {

View File

@@ -26,7 +26,7 @@
<UFormField label="Name"> <UFormField label="Name">
<UInput v-if="applicationFormTemplate" v-model="applicationFormTemplate.name" /> <UInput v-if="applicationFormTemplate" v-model="applicationFormTemplate.name" />
</UFormField> </UFormField>
<UStepper ref="stepper" v-model="activeStepperItem" :items="stepperItems" class="w-full" /> <UStepper ref="stepper" v-model="activeStepperItemIndex" :items="stepperItems" class="w-full" />
<h1 v-if="currentFormElementSection?.title" 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 }} {{ currentFormElementSection.title }}
</h1> </h1>
@@ -72,14 +72,14 @@ const { validateFormElements, getHighestComplianceStatus } = useApplicationFormV
const { userDto, selectedOrganization } = useAuth() const { userDto, selectedOrganization } = useAuth()
const stepper = useTemplateRef('stepper') const stepper = useTemplateRef('stepper')
const activeStepperItem = ref<number>(0) const activeStepperItemIndex = ref<number>(0)
const currentFormElementSection = computed(() => { const currentFormElementSection = computed(
return applicationFormTemplate.value?.formElementSections[activeStepperItem.value] () => applicationFormTemplate.value?.formElementSections[activeStepperItemIndex.value]
}) )
watch(activeStepperItem, async (newActiveStepperItem: number) => { watch(activeStepperItemIndex, async (newActiveStepperItem: number) => {
activeStepperItem.value = newActiveStepperItem activeStepperItemIndex.value = newActiveStepperItem
}) })
const { data, error } = await useAsyncData<PagedApplicationFormDto>(async () => { const { data, error } = await useAsyncData<PagedApplicationFormDto>(async () => {
@@ -113,15 +113,10 @@ async function navigateStepper(direction: 'forward' | 'backward') {
} }
} }
const applicationFormTemplate = computed({ const applicationFormTemplate = computed(
// TODO: Don't select always the first item, allow user to select a template // TODO: Don't select always the first item, allow user to select a template
get: () => data?.value?.content[0] ?? undefined, () => data?.value?.content[0] ?? undefined
set: (val) => { )
if (val && data.value) {
data.value.content[0] = val
}
}
})
const formElements = computed({ const formElements = computed({
get: () => currentFormElementSection?.value?.formElements ?? [], get: () => currentFormElementSection?.value?.formElements ?? [],