ilios/frontend

View on GitHub
packages/ilios-common/addon/decorators/validation/after-date.js

Summary

Maintainability
A
0 mins
Test Coverage
import { registerDecorator } from 'class-validator';
import { DateTime } from 'luxon';
import { getOwner } from '@ember/application';

export function AfterDate(property, validationOptions) {
  return function (object, propertyName) {
    registerDecorator({
      name: 'afterDate',
      target: object.constructor,
      propertyName: propertyName,
      constraints: [property],
      options: validationOptions,
      validator: {
        validate(value, { constraints, object: target, property }) {
          if (!constraints[0]) {
            throw new Error(
              `You must pass the name of a property that ${property} is after as the first argument to AfterDate`,
            );
          }
          const afterKey = constraints[0];
          if (!(value instanceof Date)) {
            return false;
          }
          if (!(afterKey in target)) {
            throw new Error(`${afterKey} is not a property of this object`);
          }
          const afterValue = target[afterKey];
          if (!afterValue) {
            //allow the after value to be empty
            return true;
          }
          if (!(afterValue instanceof Date)) {
            throw new Error(`${afterKey} must be a Date()`);
          }

          const granularity = validationOptions?.granularity ?? 'second';
          return (
            DateTime.fromJSDate(value).startOf(granularity) >
            DateTime.fromJSDate(afterValue).startOf(granularity)
          );
        },
        defaultMessage({ constraints, object: target }) {
          const owner = getOwner(target);
          const intl = owner.lookup('service:intl');
          const afterKey = constraints[0];
          const afterValue = target[afterKey];
          const after = DateTime.fromJSDate(afterValue);
          const format = validationOptions?.granularity === 'day' ? 'DDD' : 'LLLL d, yyyy, t a';
          const description = intl.t('errors.description');
          const message = intl.t('errors.after', {
            description,
            after: after.toFormat(format),
          });
          return message;
        },
      },
    });
  };
}