Get the invalid yup item's index from error

Viewed 562

I'm currently processing a form with Formik and Yup that contains more than 700 complex entries. I want to print exactly the item which was affected. E.g: If item #548 was invalid, I'd like to get the item index (which should be 547) and then print it out to the user.

I tried using ${path} interpolation in Yup, which almost does what I want, but I'd like to get only the index or be able to transform the output before it goes out of Yup (Or I'd have to modify the other components, and I don't want it to feel like a hack).

Here's my schema:

const toGradeSchema = yup.lazy((_toGrade: any) => {
  const toGrade = _toGrade as ToGradeInput | undefined;
  const isGradeSet = toGrade?.gradeId || toGrade?.section;
  const gradeId = yup
    .string()
    .test('gradeId', 'Debe de colocar el grado', (val?: any) => {
      return (!isGradeSet && !val) || (val && isGradeSet);
    });
  const section = yup
    .string()
    .oneOf(sectionList)
    .test('gradeId', 'Debe de colocar la sección', (val?: any) => {
      return (!isGradeSet && !val) || (val && isGradeSet);
    });
  const base = yup.object().shape({
    gradeId,
    section,
  });

  return base;
});

const newStudentsSchema = yup.array().of(
  yup
    .object()
    .shape({
      name: yup.object().shape({
        firstName: yup
          .string()
          .required('El primer nombre es requerido ${path}'),
        lastName: yup.string().required('El apellido es requerido'),
        fullName: yup.string().notRequired(),
      }),
      email: yup
        .string()
        .email('El correo electrónico es inválido')
        .required('Debe de colocar un correo electrónico ${path}'),
      password: yup
        .string()
        .required(() => 'Debe de colocar una contraseña ${path}')
        .test(
          'password is valid',
          'La contraseña debe de contener por lo menos una letra en mayúscula, una en minúscula y al menos un dígito',
          (pass: string | undefined | null) => {
            if (!pass) {
              return false;
            }
            return validatePassword(pass);
          },
        ),
      gender: yup.mixed().oneOf(genderValues),
      // The order in the attendance that must not change
      birthDate: yup.date().notRequired(),
      allergies: yup.string().notRequired(),
      diseases: yup.string().notRequired(),
      toGrade: toGradeSchema,
    })
    .notRequired(),
);

const existingStudentSchema = yup.array().of(
  yup.object().shape({
    studentId: yup.string().required('Debe de colocar el ID del estudiante'),
    toGrade: toGradeSchema,
  }),
);

export const bulkStudentCreateSchema = yup.object().shape({
  students: yup.object().shape({
    newStudents: newStudentsSchema,
    existingStudents: existingStudentSchema,
  }),
});

Any ideas?

0 Answers
Related