feat(fullstack): Add application form status, add submissions of forms, update DB schema

This commit is contained in:
2025-08-02 18:00:59 +02:00
parent f9851f01d9
commit a5eae07eaf
13 changed files with 278 additions and 91 deletions

View File

@@ -193,6 +193,37 @@ paths:
"503": "503":
$ref: "https://api.swaggerhub.com/domains/smartbear-public/ProblemDetails/1.0.0#/components/responses/ServiceUnavailable" $ref: "https://api.swaggerhub.com/domains/smartbear-public/ProblemDetails/1.0.0#/components/responses/ServiceUnavailable"
/application-forms/{id}/submit:
post:
summary: Submit an application form
operationId: submitApplicationForm
tags:
- application-form
parameters:
- name: id
in: path
required: true
schema:
type: string
format: uuid
responses:
"200":
description: Application form successfully submitted
content:
application/json:
schema:
$ref: "#/components/schemas/ApplicationFormDto"
"400":
$ref: "https://api.swaggerhub.com/domains/smartbear-public/ProblemDetails/1.0.0#/components/responses/BadRequest"
"401":
$ref: "https://api.swaggerhub.com/domains/smartbear-public/ProblemDetails/1.0.0#/components/responses/Unauthorized"
"404":
$ref: "https://api.swaggerhub.com/domains/smartbear-public/ProblemDetails/1.0.0#/components/responses/NotFound"
"500":
$ref: "https://api.swaggerhub.com/domains/smartbear-public/ProblemDetails/1.0.0#/components/responses/ServerError"
"503":
$ref: "https://api.swaggerhub.com/domains/smartbear-public/ProblemDetails/1.0.0#/components/responses/ServiceUnavailable"
####### Application Form Templates ####### ####### Application Form Templates #######
/application-form-templates: /application-form-templates:
get: get:
@@ -672,6 +703,7 @@ components:
- lastModifiedBy - lastModifiedBy
- createdAt - createdAt
- modifiedAt - modifiedAt
- status
properties: properties:
id: id:
type: string type: string
@@ -696,6 +728,8 @@ components:
modifiedAt: modifiedAt:
type: string type: string
format: date-time format: date-time
status:
$ref: "#/components/schemas/ApplicationFormStatus"
CreateApplicationFormDto: CreateApplicationFormDto:
required: required:
@@ -715,6 +749,9 @@ components:
default: false default: false
organizationId: organizationId:
type: string type: string
status:
$ref: "#/components/schemas/ApplicationFormStatus"
default: DRAFT
PagedApplicationFormDto: PagedApplicationFormDto:
type: object type: object
@@ -1009,6 +1046,15 @@ components:
- WARNING - WARNING
- CRITICAL - CRITICAL
ApplicationFormStatus:
type: string
enum:
- DRAFT
- SUBMITTED
- APPROVED
- REJECTED
- SIGNED
####### Supporting components ####### ####### Supporting components #######
Page: Page:
type: object type: object

View File

@@ -2,12 +2,15 @@ package com.betriebsratkanzlei.legalconsenthub.application_form
import com.betriebsratkanzlei.legalconsenthub.form_element.FormElementSection import com.betriebsratkanzlei.legalconsenthub.form_element.FormElementSection
import com.betriebsratkanzlei.legalconsenthub.user.User import com.betriebsratkanzlei.legalconsenthub.user.User
import com.betriebsratkanzlei.legalconsenthub_api.model.ApplicationFormStatus
import jakarta.persistence.AttributeOverride import jakarta.persistence.AttributeOverride
import jakarta.persistence.AttributeOverrides import jakarta.persistence.AttributeOverrides
import jakarta.persistence.CascadeType import jakarta.persistence.CascadeType
import jakarta.persistence.Column import jakarta.persistence.Column
import jakarta.persistence.Entity import jakarta.persistence.Entity
import jakarta.persistence.EntityListeners import jakarta.persistence.EntityListeners
import jakarta.persistence.Enumerated
import jakarta.persistence.EnumType
import jakarta.persistence.GeneratedValue import jakarta.persistence.GeneratedValue
import jakarta.persistence.Id import jakarta.persistence.Id
import jakarta.persistence.OneToMany import jakarta.persistence.OneToMany
@@ -36,6 +39,10 @@ class ApplicationForm(
var organizationId: String = "", var organizationId: String = "",
@Enumerated(EnumType.STRING)
@Column(nullable = false)
var status: ApplicationFormStatus = ApplicationFormStatus.DRAFT,
@Embedded @Embedded
@AttributeOverrides( @AttributeOverrides(
AttributeOverride(name = "id", column = Column(name = "created_by_id", nullable = false)), AttributeOverride(name = "id", column = Column(name = "created_by_id", nullable = false)),

View File

@@ -77,4 +77,12 @@ class ApplicationFormController(
applicationFormService.deleteApplicationFormByID(id) applicationFormService.deleteApplicationFormByID(id)
return ResponseEntity.noContent().build() return ResponseEntity.noContent().build()
} }
override fun submitApplicationForm(id: UUID): ResponseEntity<ApplicationFormDto> {
return ResponseEntity.ok(
applicationFormMapper.toApplicationFormDto(
applicationFormService.submitApplicationForm(id)
)
)
}
} }

View File

@@ -22,7 +22,8 @@ class ApplicationFormMapper(private val formElementSectionMapper: FormElementSec
createdBy = userMapper.toUserDto(applicationForm.createdBy), createdBy = userMapper.toUserDto(applicationForm.createdBy),
lastModifiedBy = userMapper.toUserDto(applicationForm.lastModifiedBy), lastModifiedBy = userMapper.toUserDto(applicationForm.lastModifiedBy),
createdAt = applicationForm.createdAt ?: LocalDateTime.now(), createdAt = applicationForm.createdAt ?: LocalDateTime.now(),
modifiedAt = applicationForm.modifiedAt ?: LocalDateTime.now() modifiedAt = applicationForm.modifiedAt ?: LocalDateTime.now(),
status = applicationForm.status
) )
} }
@@ -33,6 +34,7 @@ class ApplicationFormMapper(private val formElementSectionMapper: FormElementSec
formElementSections = applicationForm.formElementSections.map { formElementSectionMapper.toFormElementSection(it) }.toMutableList(), formElementSections = applicationForm.formElementSections.map { formElementSectionMapper.toFormElementSection(it) }.toMutableList(),
isTemplate = applicationForm.isTemplate, isTemplate = applicationForm.isTemplate,
organizationId = applicationForm.organizationId, organizationId = applicationForm.organizationId,
status = applicationForm.status,
createdBy = userMapper.toUser(applicationForm.createdBy), createdBy = userMapper.toUser(applicationForm.createdBy),
lastModifiedBy = userMapper.toUser(applicationForm.lastModifiedBy), lastModifiedBy = userMapper.toUser(applicationForm.lastModifiedBy),
createdAt = applicationForm.createdAt, createdAt = applicationForm.createdAt,
@@ -50,6 +52,7 @@ class ApplicationFormMapper(private val formElementSectionMapper: FormElementSec
name = createApplicationFormDto.name, name = createApplicationFormDto.name,
isTemplate = createApplicationFormDto.isTemplate, isTemplate = createApplicationFormDto.isTemplate,
organizationId = createApplicationFormDto.organizationId ?: "", organizationId = createApplicationFormDto.organizationId ?: "",
status = createApplicationFormDto.status ?: com.betriebsratkanzlei.legalconsenthub_api.model.ApplicationFormStatus.DRAFT,
createdBy = createdBy, createdBy = createdBy,
lastModifiedBy = lastModifiedBy, lastModifiedBy = lastModifiedBy,
) )

View File

@@ -1,10 +1,12 @@
package com.betriebsratkanzlei.legalconsenthub.application_form package com.betriebsratkanzlei.legalconsenthub.application_form
import com.betriebsratkanzlei.legalconsenthub.error.ApplicationFormInvalidStateException
import com.betriebsratkanzlei.legalconsenthub.error.ApplicationFormNotCreatedException import com.betriebsratkanzlei.legalconsenthub.error.ApplicationFormNotCreatedException
import com.betriebsratkanzlei.legalconsenthub.error.ApplicationFormNotDeletedException import com.betriebsratkanzlei.legalconsenthub.error.ApplicationFormNotDeletedException
import com.betriebsratkanzlei.legalconsenthub.error.ApplicationFormNotFoundException import com.betriebsratkanzlei.legalconsenthub.error.ApplicationFormNotFoundException
import com.betriebsratkanzlei.legalconsenthub.error.ApplicationFormNotUpdatedException import com.betriebsratkanzlei.legalconsenthub.error.ApplicationFormNotUpdatedException
import com.betriebsratkanzlei.legalconsenthub_api.model.ApplicationFormDto import com.betriebsratkanzlei.legalconsenthub_api.model.ApplicationFormDto
import com.betriebsratkanzlei.legalconsenthub_api.model.ApplicationFormStatus
import com.betriebsratkanzlei.legalconsenthub_api.model.CreateApplicationFormDto import com.betriebsratkanzlei.legalconsenthub_api.model.CreateApplicationFormDto
import org.springframework.data.domain.Page import org.springframework.data.domain.Page
import org.springframework.data.domain.PageRequest import org.springframework.data.domain.PageRequest
@@ -59,4 +61,25 @@ class ApplicationFormService(
throw ApplicationFormNotDeletedException(e) throw ApplicationFormNotDeletedException(e)
} }
} }
fun submitApplicationForm(id: UUID): ApplicationForm {
val applicationForm = getApplicationFormById(id)
if (applicationForm.status != ApplicationFormStatus.DRAFT) {
throw ApplicationFormInvalidStateException(
applicationFormId = id,
currentState = applicationForm.status,
expectedState = ApplicationFormStatus.DRAFT,
operation = "submit"
)
}
applicationForm.status = ApplicationFormStatus.SUBMITTED
return try {
applicationFormRepository.save(applicationForm)
} catch (e: Exception) {
throw ApplicationFormNotUpdatedException(e, id)
}
}
} }

View File

@@ -0,0 +1,11 @@
package com.betriebsratkanzlei.legalconsenthub.error
import com.betriebsratkanzlei.legalconsenthub_api.model.ApplicationFormStatus
import java.util.UUID
class ApplicationFormInvalidStateException(
val applicationFormId: UUID,
val currentState: ApplicationFormStatus,
val expectedState: ApplicationFormStatus,
val operation: String
) : RuntimeException("Cannot $operation application form with ID $applicationFormId. Current state: $currentState, expected state: $expectedState")

View File

@@ -31,6 +31,22 @@ class ExceptionHandler {
) )
} }
@ResponseBody
@ExceptionHandler(ApplicationFormInvalidStateException::class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
fun handleInvalidStateError(e: ApplicationFormInvalidStateException): ResponseEntity<ProblemDetails> {
logger.warn(e.message, e)
return ResponseEntity.status(HttpStatus.BAD_REQUEST).contentType(MediaType.APPLICATION_PROBLEM_JSON)
.body(
ProblemDetails(
title = "Invalid State",
status = HttpStatus.BAD_REQUEST.value(),
type = URI.create("about:blank"),
detail = e.message ?: "Operation not allowed in current state"
)
)
}
@ResponseBody @ResponseBody
@ExceptionHandler( @ExceptionHandler(
ApplicationFormNotCreatedException::class, ApplicationFormNotCreatedException::class,

View File

@@ -10,18 +10,20 @@ create table application_form
last_modified_by_name varchar(255) not null, last_modified_by_name varchar(255) not null,
name varchar(255) not null, name varchar(255) not null,
organization_id varchar(255), organization_id varchar(255),
status enum ('APPROVED','DRAFT','REJECTED','SIGNED','SUBMITTED') not null,
primary key (id) primary key (id)
); );
create table comment create table comment
( (
created_at timestamp(6) not null, created_at timestamp(6) not null,
modified_at timestamp(6) not null, modified_at timestamp(6) not null,
form_element_id uuid not null, application_form_id uuid not null,
id uuid not null, form_element_id uuid not null,
created_by_id varchar(255) not null, id uuid not null,
created_by_name varchar(255) not null, created_by_id varchar(255) not null,
message varchar(255) not null, created_by_name varchar(255) not null,
message varchar(255) not null,
primary key (id) primary key (id)
); );
@@ -36,12 +38,29 @@ create table form_element_options
create table form_element create table form_element
( (
type tinyint not null check (type between 0 and 4), type tinyint not null check (type between 0 and 4),
application_form_id uuid not null, form_element_section_id uuid not null,
id uuid not null, id uuid not null,
description varchar(255),
title varchar(255),
primary key (id) primary key (id)
); );
create table form_element_section
(
application_form_id uuid not null,
id uuid not null,
description varchar(255),
short_title varchar(255),
title varchar(255) not null,
primary key (id)
);
alter table if exists comment
add constraint FKlavy9axrt26sepreg5lqtuoap
foreign key (application_form_id)
references application_form;
alter table if exists comment alter table if exists comment
add constraint FKfg84w0i76tw9os13950272c6f add constraint FKfg84w0i76tw9os13950272c6f
foreign key (form_element_id) foreign key (form_element_id)
@@ -53,6 +72,11 @@ alter table if exists form_element_options
references form_element; references form_element;
alter table if exists form_element alter table if exists form_element
add constraint FKdniyq3l10lncw48tft15js5gb add constraint FKdpr6k93m4hqllqjsvoa4or6mp
foreign key (form_element_section_id)
references form_element_section;
alter table if exists form_element_section
add constraint FKtn0lreovauwf2v29doo70o3qs
foreign key (application_form_id) foreign key (application_form_id)
references application_form; references application_form;

View File

@@ -83,11 +83,29 @@ export function useApplicationForm() {
} }
} }
async function submitApplicationForm(id: string): Promise<ApplicationFormDto> {
if (!id) {
return Promise.reject(new Error('ID missing'))
}
try {
return await applicationFormApi.submitApplicationForm(id)
} catch (e: unknown) {
if (e instanceof ResponseError) {
console.error(`Failed submitting application form with ID ${id}:`, e.response)
} else {
console.error(`Failed submitting application form with ID ${id}:`, e)
}
return Promise.reject(e)
}
}
return { return {
createApplicationForm, createApplicationForm,
getAllApplicationForms, getAllApplicationForms,
getApplicationFormById, getApplicationFormById,
updateApplicationForm, updateApplicationForm,
deleteApplicationFormById deleteApplicationFormById,
submitApplicationForm
} }
} }

View File

@@ -45,11 +45,16 @@ export function useApplicationFormApi() {
return applicationFormApiClient.deleteApplicationForm({ id }) return applicationFormApiClient.deleteApplicationForm({ id })
} }
async function submitApplicationForm(id: string): Promise<ApplicationFormDto> {
return applicationFormApiClient.submitApplicationForm({ id })
}
return { return {
createApplicationForm, createApplicationForm,
getAllApplicationForms, getAllApplicationForms,
getApplicationFormById, getApplicationFormById,
updateApplicationForm, updateApplicationForm,
deleteApplicationFormById deleteApplicationFormById,
submitApplicationForm
} }
} }

View File

@@ -15,7 +15,15 @@
<UDashboardToolbar> <UDashboardToolbar>
<template #right> <template #right>
<UButton icon="i-lucide-file-text" size="md" color="primary" variant="solid" target="_blank" :to="`/api/application-forms/${applicationForm.id}/pdf`">PDF Vorschau</UButton> <UButton
icon="i-lucide-file-text"
size="md"
color="primary"
variant="solid"
target="_blank"
:to="`/api/application-forms/${applicationForm.id}/pdf`"
>PDF Vorschau</UButton
>
</template> </template>
</UDashboardToolbar> </UDashboardToolbar>
</template> </template>
@@ -51,14 +59,15 @@
> >
Next Next
</UButton> </UButton>
<UButton
v-if="!stepper?.hasNext" <div v-if="!stepper?.hasNext" class="flex flex-wrap items-center gap-1.5">
trailing-icon="i-lucide-send-horizontal" <UButton trailing-icon="i-lucide-save" :disabled="isReadOnly" variant="outline" @click="onSave">
:disabled="isReadOnly" Save
@click="onSubmit" </UButton>
> <UButton trailing-icon="i-lucide-send-horizontal" :disabled="isReadOnly" @click="onSubmit">
Submit Submit
</UButton> </UButton>
</div>
</div> </div>
</UCard> </UCard>
</div> </div>
@@ -70,13 +79,14 @@
import type { ApplicationFormDto, FormElementSectionDto } from '~/.api-client' import type { ApplicationFormDto, FormElementSectionDto } from '~/.api-client'
import type { StepperItem } from '@nuxt/ui' import type { StepperItem } from '@nuxt/ui'
const { getApplicationFormById, updateApplicationForm } = useApplicationForm() const { getApplicationFormById, updateApplicationForm, submitApplicationForm } = useApplicationForm()
const route = useRoute() const route = useRoute()
const { user } = useAuth() const { user } = useAuth()
const toast = useToast()
definePageMeta({ definePageMeta({
// Prevent whole page from re-rendering when navigating between sections to keep state // Prevent whole page from re-rendering when navigating between sections to keep state
key: (route) => `${route.params.id}`, key: (route) => `${route.params.id}`
}) })
onMounted(() => { onMounted(() => {
@@ -136,10 +146,18 @@ async function navigateStepper(direction: 'forward' | 'backward') {
await navigateTo(`/application-forms/${route.params.id}/${activeStepperItemIndex.value}`) await navigateTo(`/application-forms/${route.params.id}/${activeStepperItemIndex.value}`)
} }
async function onSubmit() { async function onSave() {
if (data?.value) { if (data?.value) {
await updateApplicationForm(data.value.id, data.value) await updateApplicationForm(data.value.id, data.value)
toast.add({ title: 'Success', description: 'Application form saved', color: 'success' })
}
}
async function onSubmit() {
if (data?.value) {
await submitApplicationForm(data.value.id)
await navigateTo('/') await navigateTo('/')
toast.add({ title: 'Success', description: 'Application form submitted', color: 'success' })
} }
} }

View File

@@ -16,14 +16,11 @@
<template #body> <template #body>
<div class="flex flex-col gap-4 sm:gap-6 lg:gap-12 w-full lg:max-w-4xl mx-auto"> <div class="flex flex-col gap-4 sm:gap-6 lg:gap-12 w-full lg:max-w-4xl mx-auto">
<!-- Permission Guard using Better Auth's native system -->
<div v-if="!canCreateApplicationForm" class="text-center py-12"> <div v-if="!canCreateApplicationForm" class="text-center py-12">
<UIcon name="i-lucide-shield-x" class="w-16 h-16 mx-auto text-red-400 mb-4" /> <UIcon name="i-lucide-shield-x" class="w-16 h-16 mx-auto text-red-400 mb-4" />
<h2 class="text-2xl font-semibold text-gray-700 mb-2">Keine Berechtigung</h2> <h2 class="text-2xl font-semibold text-gray-700 mb-2">Keine Berechtigung</h2>
<p class="text-gray-500 mb-4"> <p class="text-gray-500 mb-4">Sie haben keine Berechtigung zum Erstellen von Anträgen.</p>
Sie haben keine Berechtigung zum Erstellen von Anträgen. <UAlert
</p>
<UAlert
v-if="currentRoleInfo" v-if="currentRoleInfo"
:title="`Ihre aktuelle Rolle: ${currentRoleInfo.name}`" :title="`Ihre aktuelle Rolle: ${currentRoleInfo.name}`"
:description="currentRoleInfo.description" :description="currentRoleInfo.description"
@@ -32,59 +29,48 @@
class="max-w-md mx-auto" class="max-w-md mx-auto"
/> />
</div> </div>
<div v-else> <div v-else>
Erstelle Formular für Organisation: {{ selectedOrganization?.name }}
<!-- Role Context Alert -->
<UAlert
v-if="currentRoleInfo"
:title="`Erstellen als: ${currentRoleInfo.name}`"
:description="`${currentRoleInfo.description} - Sie können Anträge erstellen und bearbeiten.`"
:color="currentRoleInfo.color"
variant="soft"
:icon="currentRoleInfo.icon"
class="mb-4"
/>
<UPageCard title="Ampelstatus" variant="naked" orientation="horizontal" class="mb-4"> <UPageCard title="Ampelstatus" variant="naked" orientation="horizontal" class="mb-4">
{{ ampelStatusEmoji }} {{ trafficLightStatusEmoji }}
</UPageCard> </UPageCard>
<UPageCard variant="subtle"> <UPageCard variant="subtle">
<UForm class="space-y-4" :state="{}" @submit="onSubmit"> <UForm class="space-y-4" :state="{}" @submit="onSubmit">
<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="activeStepperItemIndex" :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>
<FormEngine <FormEngine
v-if="currentFormElementSection?.formElements" v-if="currentFormElementSection?.formElements"
v-model="currentFormElementSection.formElements" v-model="currentFormElementSection.formElements"
/> />
<div class="flex gap-2 justify-between mt-4"> <div class="flex gap-2 justify-between mt-4">
<UButton <UButton
leading-icon="i-lucide-arrow-left" leading-icon="i-lucide-arrow-left"
:disabled="!stepper?.hasPrev" :disabled="!stepper?.hasPrev"
@click="navigateStepper('backward')" @click="navigateStepper('backward')"
> >
Prev Prev
</UButton> </UButton>
<UButton <UButton
v-if="stepper?.hasNext" v-if="stepper?.hasNext"
trailing-icon="i-lucide-arrow-right" trailing-icon="i-lucide-arrow-right"
:disabled="!stepper?.hasNext" :disabled="!stepper?.hasNext"
@click="navigateStepper('forward')" @click="navigateStepper('forward')"
> >
Next Next
</UButton> </UButton>
<UButton v-if="!stepper?.hasNext" @click="onSubmit"> Submit </UButton> <div v-if="!stepper?.hasNext" class="flex flex-wrap items-center gap-1.5">
</div> <UButton trailing-icon="i-lucide-save" variant="outline" @click="onSave"> Save </UButton>
</UForm> <UButton trailing-icon="i-lucide-send-horizontal" @click="onSubmit"> Submit </UButton>
</UPageCard> </div>
</div>
</UForm>
</UPageCard>
</div> </div>
</div> </div>
</template> </template>
@@ -98,10 +84,11 @@ import type { FormElementId } from '~/types/FormElement'
import type { StepperItem } from '@nuxt/ui' import type { StepperItem } from '@nuxt/ui'
const { getAllApplicationFormTemplates } = useApplicationFormTemplate() const { getAllApplicationFormTemplates } = useApplicationFormTemplate()
const { createApplicationForm } = useApplicationForm() const { createApplicationForm, submitApplicationForm } = useApplicationForm()
const { validateFormElements, getHighestComplianceStatus } = useApplicationFormValidator() const { validateFormElements, getHighestComplianceStatus } = useApplicationFormValidator()
const { userDto, selectedOrganization } = useAuth() const { userDto, selectedOrganization } = useAuth()
const { canCreateApplicationForm, getCurrentRoleInfo } = usePermissions() const { canCreateApplicationForm, getCurrentRoleInfo } = usePermissions()
const toast = useToast()
// Get current role information for display // Get current role information for display
const currentRoleInfo = computed(() => getCurrentRoleInfo()) const currentRoleInfo = computed(() => getCurrentRoleInfo())
@@ -174,7 +161,7 @@ watch(
{ deep: true } { deep: true }
) )
const ampelStatusEmoji = computed(() => { const trafficLightStatusEmoji = computed(() => {
switch (validationStatus.value) { switch (validationStatus.value) {
case ComplianceStatus.Critical: case ComplianceStatus.Critical:
return '🔴' return '🔴'
@@ -187,16 +174,32 @@ const ampelStatusEmoji = computed(() => {
} }
}) })
async function onSubmit() { async function onSave() {
if (applicationFormTemplate.value) { const applicationForm = await prepareAndCreateApplicationForm()
applicationFormTemplate.value.createdBy = userDto.value if (applicationForm) {
applicationFormTemplate.value.lastModifiedBy = userDto.value toast.add({ title: 'Success', description: 'Application form saved', color: 'success' })
applicationFormTemplate.value.organizationId = selectedOrganization.value?.id ?? ''
await createApplicationForm(applicationFormTemplate.value)
await navigateTo('/')
} else {
console.error('Application form data is undefined')
} }
} }
async function onSubmit() {
const applicationForm = await prepareAndCreateApplicationForm()
if (applicationForm) {
await submitApplicationForm(applicationForm.id)
await navigateTo('/')
toast.add({ title: 'Success', description: 'Application form submitted', color: 'success' })
}
}
async function prepareAndCreateApplicationForm() {
if (!applicationFormTemplate.value) {
console.error('Application form data is undefined')
return null
}
applicationFormTemplate.value.createdBy = userDto.value
applicationFormTemplate.value.lastModifiedBy = userDto.value
applicationFormTemplate.value.organizationId = selectedOrganization.value?.id ?? ''
return await createApplicationForm(applicationFormTemplate.value)
}
</script> </script>

View File

@@ -49,6 +49,11 @@
<p class="text-(--ui-text-muted) text-sm"> <p class="text-(--ui-text-muted) text-sm">
Erstellt von {{ applicationFormElem.createdBy.name }} am {{ formatDate(applicationFormElem.createdAt) }} Erstellt von {{ applicationFormElem.createdBy.name }} am {{ formatDate(applicationFormElem.createdAt) }}
</p> </p>
<div class="mt-2">
<UChip size="sm">
{{ applicationFormElem.status }}
</UChip>
</div>
</div> </div>
<div> <div>
<UPageLinks :links="getLinksForApplicationForm(applicationFormElem)" /> <UPageLinks :links="getLinksForApplicationForm(applicationFormElem)" />