|
|
|
@@ -3,7 +3,7 @@ import { trainingReportSchema, courseEventAttendeeSchema } from '@shared/schemas
|
|
|
|
import { Course, CourseAttendee, CourseAttendeeRole, CourseEventDetails } from '@shared/types/course'
|
|
|
|
import { Course, CourseAttendee, CourseAttendeeRole, CourseEventDetails } from '@shared/types/course'
|
|
|
|
import { useForm, useFieldArray, FieldArray as VeeFieldArray, ErrorMessage, Field as VeeField } from 'vee-validate'
|
|
|
|
import { useForm, useFieldArray, FieldArray as VeeFieldArray, ErrorMessage, Field as VeeField } from 'vee-validate'
|
|
|
|
import { toTypedSchema } from '@vee-validate/zod'
|
|
|
|
import { toTypedSchema } from '@vee-validate/zod'
|
|
|
|
import { computed, onMounted, ref } from 'vue'
|
|
|
|
import { computed, onMounted, ref, watch } from 'vue'
|
|
|
|
import { getAllAttendeeRoles, getAllTrainings, postTrainingReport } from '@/api/trainingReport'
|
|
|
|
import { getAllAttendeeRoles, getAllTrainings, postTrainingReport } from '@/api/trainingReport'
|
|
|
|
import { getMembers, Member } from '@/api/member'
|
|
|
|
import { getMembers, Member } from '@/api/member'
|
|
|
|
import FieldGroup from '../ui/field/FieldGroup.vue'
|
|
|
|
import FieldGroup from '../ui/field/FieldGroup.vue'
|
|
|
|
@@ -18,8 +18,11 @@ import FieldSet from '../ui/field/FieldSet.vue'
|
|
|
|
import FieldLegend from '../ui/field/FieldLegend.vue'
|
|
|
|
import FieldLegend from '../ui/field/FieldLegend.vue'
|
|
|
|
import FieldDescription from '../ui/field/FieldDescription.vue'
|
|
|
|
import FieldDescription from '../ui/field/FieldDescription.vue'
|
|
|
|
import Checkbox from '../ui/checkbox/Checkbox.vue'
|
|
|
|
import Checkbox from '../ui/checkbox/Checkbox.vue'
|
|
|
|
|
|
|
|
import Select from '../ui/select/Select.vue'
|
|
|
|
|
|
|
|
import { SelectContent, SelectItem, SelectTrigger, SelectValue } from 'reka-ui'
|
|
|
|
|
|
|
|
import FieldContent from '../ui/field/FieldContent.vue'
|
|
|
|
|
|
|
|
|
|
|
|
const { handleSubmit, resetForm, errors , values } = useForm({
|
|
|
|
const { handleSubmit, resetForm, errors, values } = useForm({
|
|
|
|
validationSchema: toTypedSchema(trainingReportSchema),
|
|
|
|
validationSchema: toTypedSchema(trainingReportSchema),
|
|
|
|
initialValues: {
|
|
|
|
initialValues: {
|
|
|
|
course_id: null,
|
|
|
|
course_id: null,
|
|
|
|
@@ -29,6 +32,11 @@ const { handleSubmit, resetForm, errors , values } = useForm({
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
watch(errors, (e) => {
|
|
|
|
|
|
|
|
console.warn("Validation errors:", e);
|
|
|
|
|
|
|
|
}, { deep: true });
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const submitForm = handleSubmit(onSubmit);
|
|
|
|
const submitForm = handleSubmit(onSubmit);
|
|
|
|
|
|
|
|
|
|
|
|
function toMySQLDateTime(date: Date): string {
|
|
|
|
function toMySQLDateTime(date: Date): string {
|
|
|
|
@@ -55,7 +63,7 @@ function onSubmit(vals) {
|
|
|
|
|
|
|
|
|
|
|
|
const { remove, push, fields } = useFieldArray('attendees');
|
|
|
|
const { remove, push, fields } = useFieldArray('attendees');
|
|
|
|
|
|
|
|
|
|
|
|
const selectedCourse = computed<Course | undefined>(() => {return trainings.value?.find(c => c.id == values.course_id)})
|
|
|
|
const selectedCourse = computed<Course | undefined>(() => { return trainings.value?.find(c => c.id == values.course_id) })
|
|
|
|
|
|
|
|
|
|
|
|
const trainings = ref<Course[] | null>(null);
|
|
|
|
const trainings = ref<Course[] | null>(null);
|
|
|
|
const members = ref<Member[] | null>(null);
|
|
|
|
const members = ref<Member[] | null>(null);
|
|
|
|
@@ -70,14 +78,15 @@ onMounted(async () => {
|
|
|
|
})
|
|
|
|
})
|
|
|
|
</script>
|
|
|
|
</script>
|
|
|
|
<template>
|
|
|
|
<template>
|
|
|
|
<form id="trainingForm" @submit.prevent="submitForm" class="flex flex-col gap-5">
|
|
|
|
<form id="trainingForm" @submit.prevent="submitForm" class="flex flex-col gap-5 pl-2">
|
|
|
|
|
|
|
|
|
|
|
|
<FieldGroup>
|
|
|
|
<FieldGroup>
|
|
|
|
<VeeField v-slot="{ field, errors }" name="course_id">
|
|
|
|
<VeeField v-slot="{ field, errors }" name="course_id">
|
|
|
|
<Field :data-invalid="!!errors.length">
|
|
|
|
<Field :data-invalid="!!errors.length">
|
|
|
|
<FieldLabel>Training Course</FieldLabel>
|
|
|
|
<FieldLabel>Training Course</FieldLabel>
|
|
|
|
|
|
|
|
|
|
|
|
<select v-bind="field" class="border rounded p-2 w-full">
|
|
|
|
<select v-bind="field"
|
|
|
|
|
|
|
|
class="border rounded p-2 w-full focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] bg-background outline-none">
|
|
|
|
<option value="" disabled>Select a course</option>
|
|
|
|
<option value="" disabled>Select a course</option>
|
|
|
|
<option v-for="course in trainings" :key="course.id" :value="course.id">
|
|
|
|
<option v-for="course in trainings" :key="course.id" :value="course.id">
|
|
|
|
{{ course.name }}
|
|
|
|
{{ course.name }}
|
|
|
|
@@ -92,7 +101,8 @@ onMounted(async () => {
|
|
|
|
<VeeField v-slot="{ field, errors }" name="event_date">
|
|
|
|
<VeeField v-slot="{ field, errors }" name="event_date">
|
|
|
|
<Field :data-invalid="!!errors.length">
|
|
|
|
<Field :data-invalid="!!errors.length">
|
|
|
|
<FieldLabel>Event Date</FieldLabel>
|
|
|
|
<FieldLabel>Event Date</FieldLabel>
|
|
|
|
<input type="date" v-bind="field" class="border rounded p-2 w-full" />
|
|
|
|
<input type="date" v-bind="field"
|
|
|
|
|
|
|
|
class="border rounded p-2 w-full focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] bg-background outline-none" />
|
|
|
|
<FieldError v-if="errors.length" :errors="errors" />
|
|
|
|
<FieldError v-if="errors.length" :errors="errors" />
|
|
|
|
</Field>
|
|
|
|
</Field>
|
|
|
|
</VeeField>
|
|
|
|
</VeeField>
|
|
|
|
@@ -125,7 +135,8 @@ onMounted(async () => {
|
|
|
|
<!-- Member Select -->
|
|
|
|
<!-- Member Select -->
|
|
|
|
<VeeField :name="`attendees[${index}].attendee_id`" v-slot="{ field: f, errors: e }">
|
|
|
|
<VeeField :name="`attendees[${index}].attendee_id`" v-slot="{ field: f, errors: e }">
|
|
|
|
<div>
|
|
|
|
<div>
|
|
|
|
<select v-bind="f" class="w-full border p-2 rounded-md">
|
|
|
|
<select v-bind="f"
|
|
|
|
|
|
|
|
class="border rounded p-2 w-full focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] bg-background outline-none">
|
|
|
|
<option value="">Select member...</option>
|
|
|
|
<option value="">Select member...</option>
|
|
|
|
<option v-for="m in members" :key="m.member_id" :value="m.member_id">
|
|
|
|
<option v-for="m in members" :key="m.member_id" :value="m.member_id">
|
|
|
|
{{ m.member_name }}
|
|
|
|
{{ m.member_name }}
|
|
|
|
@@ -138,7 +149,8 @@ onMounted(async () => {
|
|
|
|
<!-- Role Select -->
|
|
|
|
<!-- Role Select -->
|
|
|
|
<VeeField :name="`attendees[${index}].attendee_role_id`" v-slot="{ field: f, errors: e }">
|
|
|
|
<VeeField :name="`attendees[${index}].attendee_role_id`" v-slot="{ field: f, errors: e }">
|
|
|
|
<div>
|
|
|
|
<div>
|
|
|
|
<select v-bind="f" class="w-full border p-2 rounded-md">
|
|
|
|
<select v-bind="f"
|
|
|
|
|
|
|
|
class="border rounded p-2 w-full focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] bg-background outline-none">
|
|
|
|
<option value="">Select role...</option>
|
|
|
|
<option value="">Select role...</option>
|
|
|
|
<option v-for="r in eventRoles" :key="r.id" :value="r.id">
|
|
|
|
<option v-for="r in eventRoles" :key="r.id" :value="r.id">
|
|
|
|
{{ r.name }}
|
|
|
|
{{ r.name }}
|
|
|
|
@@ -149,20 +161,26 @@ onMounted(async () => {
|
|
|
|
</VeeField>
|
|
|
|
</VeeField>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- Passed Checkbox -->
|
|
|
|
<!-- Passed Checkbox -->
|
|
|
|
<VeeField v-if="selectedCourse?.hasBookwork" v-slot="{ field }" :name="`attendees[${index}].passed`" type="checkbox"
|
|
|
|
<VeeField v-if="selectedCourse?.hasBookwork" v-slot="{ field }"
|
|
|
|
:value="true" :unchecked-value="false">
|
|
|
|
:name="`attendees[${index}].passed_bookwork`" type="checkbox" :value="true"
|
|
|
|
|
|
|
|
:unchecked-value="false">
|
|
|
|
<label>
|
|
|
|
<label>
|
|
|
|
<input type="checkbox" :name="`attendees[${index}].passed`" v-bind="field"
|
|
|
|
<input type="checkbox" :name="`attendees[${index}].passed_bookwork`" v-bind="field"
|
|
|
|
:value="true" />
|
|
|
|
:value="true" />
|
|
|
|
|
|
|
|
<!-- <Checkbox :name="`attendees[${index}].passed_bookwork`" v-bind="field" :value="true">
|
|
|
|
|
|
|
|
</Checkbox> -->
|
|
|
|
|
|
|
|
|
|
|
|
</label>
|
|
|
|
</label>
|
|
|
|
</VeeField>
|
|
|
|
</VeeField>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- Passed Checkbox -->
|
|
|
|
<!-- Passed Checkbox -->
|
|
|
|
<VeeField v-if="selectedCourse?.hasQual" v-slot="{ field }" :name="`attendees[${index}].passed`" type="checkbox"
|
|
|
|
<VeeField v-if="selectedCourse?.hasQual" v-slot="{ field }"
|
|
|
|
:value="true" :unchecked-value="false">
|
|
|
|
:name="`attendees[${index}].passed_qual`" type="checkbox" :value="true"
|
|
|
|
|
|
|
|
:unchecked-value="false">
|
|
|
|
<label>
|
|
|
|
<label>
|
|
|
|
<input type="checkbox" :name="`attendees[${index}].passed`" v-bind="field"
|
|
|
|
<input type="checkbox" :name="`attendees[${index}].passed_qual`" v-bind="field"
|
|
|
|
:value="true" />
|
|
|
|
:value="true" />
|
|
|
|
|
|
|
|
<!-- <Checkbox :name="`attendees[${index}].passed_qual`" v-bind="field"></Checkbox> -->
|
|
|
|
</label>
|
|
|
|
</label>
|
|
|
|
</VeeField>
|
|
|
|
</VeeField>
|
|
|
|
|
|
|
|
|
|
|
|
@@ -185,7 +203,7 @@ onMounted(async () => {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<Button type="button" size="sm" variant="outline"
|
|
|
|
<Button type="button" size="sm" variant="outline"
|
|
|
|
@click="push({ attendee_id: null, attendee_role_id: null, passed: false, remarks: '' })">
|
|
|
|
@click="push({ attendee_id: null, attendee_role_id: null, passed_bookwork: false, passed_qual: false, remarks: '' })">
|
|
|
|
<Plus class="mr-1 h-4 w-4" />
|
|
|
|
<Plus class="mr-1 h-4 w-4" />
|
|
|
|
Add Attendee
|
|
|
|
Add Attendee
|
|
|
|
</Button>
|
|
|
|
</Button>
|
|
|
|
|