All files / app/src/shared/lib/form lib.ts

66.66% Statements 52/78
75% Branches 12/16
69.23% Functions 9/13
66.66% Lines 52/78

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 961x           1x 1x 1x 1x         1x   1x 23x   1x     1x 63x 63x 63x 63x 63x 63x 63x           63x 63x   1x 15x 15x 15x 2x 2x   2x 15x 15x 15x   1x 2x 2x 2x           2x 2x 2x   1x 3x 3x 3x 3x 3x 2x 3x 3x 3x 3x         3x 3x 3x 3x   1x                        
import { BaseEntity, TFunction } from '@/shared/@types'
import { MAXIMUM_BACKEND_NUMBER, MINIMUM_BACKEND_NUMBER } from '@/shared/config'
import * as yup from 'yup'
import dayjs from 'dayjs'
import { removeTimezone } from '@/shared/helpers'
 
export enum FormMode {
  Read = 'read',
  Create = 'create',
  Update = 'update',
}
 
// parentName должен иметь в кноце . , так сделано,
// чтобы можно было использовать вложенные блоки формы без вложенности
export const getNestedFieldName = (parentName?: string, fieldName?: string) => `${parentName}${fieldName}`
 
export const getOptionalRequired = (schema: yup.Schema, t: TFunction, required?: boolean) =>
  required ? schema.required(t('common:Required_field')) : schema.notRequired()
 
export const getNestedArrayFieldName = (parentName: string, index: number, fieldName: string) =>
  `${parentName}${index}.${fieldName}`
 
export const validateSelect = (t: TFunction, required = true) => {
  return yup
    .mixed()
    .nullable()
    .when({
      is: (value: string | BaseEntity) => typeof value === 'string' || value === null,
      then: schema => getOptionalRequired(schema, t, required),
      otherwise: schema =>
        getOptionalRequired(
          schema.transform((option: BaseEntity) => option['@id']),
          t,
          required
        ),
    })
}
 
export const isFutureDate = (t: TFunction) => {
  return yup
    .string()
    .test('is-future', t('common:Date_must_be_not_in_the_future'), function (value) {
      const { path, createError } = this
      return value && dayjs(removeTimezone(value)).isAfter(dayjs())
        ? createError({ path, message: t('common:Date_must_be_not_in_the_future') })
        : true
    })
    .required(t('common:Required_field'))
}
 
export const isPastDate = (t: TFunction) => {
  return yup
    .string()
    .test('is-past', t('common:Date_must_be_not_in_the_past'), function (value) {
      const { path, createError } = this
 
      return value && dayjs(removeTimezone(value)).isBefore(dayjs().startOf('day'))
        ? createError({ path, message: t('common:Date_must_be_not_in_the_past') })
        : true
    })
    .required(t('common:Required_field'))
}
 
export const transformInputNumberValueToNumber = (t: TFunction, required?: boolean) =>
  getOptionalRequired(
    yup
      .mixed()
      .nullable()
      .transform(value => {
        return Number.isNaN(value) || value === null || !value ? null : +value
      })
      .when({
        is: (value: unknown) => typeof value === 'number',
        then: () =>
          yup
            .number()
            .min(MINIMUM_BACKEND_NUMBER, t('common:The_number_cannot_be_less_than'))
            .max(MAXIMUM_BACKEND_NUMBER, t('common:The_number_cannot_be_greater_than')),
      }),
    t,
    required
  )
 
export const transformInputMinutesValueToSeconds = (t: TFunction, required?: boolean) =>
  getOptionalRequired(
    yup.mixed().transform(value => {
      const time = value?.toString().split(' ')
      const minutes = time?.[0]
      const seconds = time?.[2]
      if (minutes === '00' && seconds) return +seconds
      return minutes && seconds ? +minutes * 60 + +seconds : +minutes * 60
    }),
    t,
    required
  )