diff --git a/shared/schemas/trainingReportSchema.ts b/shared/schemas/trainingReportSchema.ts index 5bfb1fd..7dd7baa 100644 --- a/shared/schemas/trainingReportSchema.ts +++ b/shared/schemas/trainingReportSchema.ts @@ -1,11 +1,11 @@ import { z } from "zod"; export const courseEventAttendeeSchema = z.object({ - attendee_id: z.number({invalid_type_error: "Must select a member"}).int().positive(), + attendee_id: z.number({ invalid_type_error: "Must select a member" }).int().positive(), passed_bookwork: z.boolean(), passed_qual: z.boolean(), remarks: z.string(), - attendee_role_id: z.number({invalid_type_error: "Must select a role"}).int().positive() + attendee_role_id: z.number({ invalid_type_error: "Must select a role" }).int().positive() }) export const trainingReportSchema = z.object({ @@ -19,5 +19,42 @@ export const trainingReportSchema = z.object({ ), remarks: z.string().nullable().optional(), attendees: z.array(courseEventAttendeeSchema).default([]), +}).superRefine((data, ctx) => { + const trainerRole = 1; + const traineeRole = 2; + + const hasTrainer = data.attendees.some((a) => a.attendee_role_id === trainerRole); + const hasTrainee = data.attendees.some((a) => a.attendee_role_id === traineeRole); + + if (!hasTrainer) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + path: ["attendees"], + message: "At least one Primary Trainer is required.", + }); + } + + if (!hasTrainee) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + path: ["attendees"], + message: "At least one Trainee is required.", + }); + } + + //no duplicates + const idCounts = new Map(); + + data.attendees.forEach((a, index) => { + idCounts.set(a.attendee_id, (idCounts.get(a.attendee_id) ?? 0) + 1); + + if (idCounts.get(a.attendee_id)! > 1) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + path: ["attendees"], + message: "Cannot have duplicate attendee.", + }); + } + }) }) diff --git a/ui/src/components/trainingReport/trainingReportForm.vue b/ui/src/components/trainingReport/trainingReportForm.vue index 79b7933..26ef3c1 100644 --- a/ui/src/components/trainingReport/trainingReportForm.vue +++ b/ui/src/components/trainingReport/trainingReportForm.vue @@ -18,10 +18,12 @@ import FieldSet from '../ui/field/FieldSet.vue' import FieldLegend from '../ui/field/FieldLegend.vue' import FieldDescription from '../ui/field/FieldDescription.vue' import Checkbox from '../ui/checkbox/Checkbox.vue' +import { configure } from 'vee-validate' const { handleSubmit, resetForm, errors, values, setFieldValue } = useForm({ validationSchema: toTypedSchema(trainingReportSchema), + validateOnMount: false, initialValues: { course_id: null, event_date: "", @@ -129,8 +131,17 @@ onMounted(async () => {
- Attendees - Add members who attended this session. +
+ Attendees + Add members who attended this session. +
+
+ {{ errors.attendees }} +
+
+
+