All files / app/src/shared/ui/datepicker datepicker.tsx

100% Statements 84/84
100% Branches 9/9
100% Functions 4/4
100% Lines 84/84

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 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 1251x                           1x                             1x 8x 8x 8x 8x 8x 8x 8x 8x 8x 8x 8x 8x 8x   8x 8x   8x 8x 8x 24x 24x 24x 24x 24x 24x   24x 24x 24x 24x 24x 24x 24x 24x 24x 24x 24x 24x 24x   24x 24x 24x 24x 24x 24x 24x 24x   24x 24x 24x 24x     24x 24x 24x 24x   24x 24x 24x 24x   24x 24x 24x 24x 24x   24x 24x 24x 24x 24x   24x 24x 24x 24x 2x 2x 2x 24x 24x 24x 24x 24x   8x   8x  
import { PickerPanel } from 'rc-picker'
import { Popover, Transition } from '@headlessui/react'
import { FCWithClassName, Nullable } from '@/shared/@types'
import { DEFAULT_DATE_FORMAT, SHORT_MONTHS_NAME, SHORT_WEEK_DAYS_NAME } from '@/shared/config'
import { Input, InputProps } from '../input'
import { Button } from '../button'
import { PickerPanelDateProps } from 'rc-picker/lib/PickerPanel'
import dayjs, { Dayjs } from 'dayjs'
import ArrowIcon from '@/shared/assets/icons/common/select-arrow.svg'
import generateConfig from 'rc-picker/lib/generate/dayjs'
import ruRu from 'rc-picker/lib/locale/ru_RU'
import cn from 'classnames'
import utc from 'dayjs/plugin/utc'
 
dayjs.extend(utc)
 
export interface DatepickerProps
  extends Omit<PickerPanelDateProps<Dayjs>, 'value' | 'onChange' | 'locale' | 'generateConfig'> {
  name: string
  label?: string
  value?: Nullable<string>
  disabled?: boolean
  isSaved?: boolean
  inputProps?: Omit<InputProps, 'name'>
  rangePickerClassName?: string
  onChange?: (value: Nullable<string>) => void
}
 
// Если брать этот компонент для формы, то только через Controller
export const Datepicker: FCWithClassName<DatepickerProps> = ({
  name,
  label,
  value,
  className,
  disabled,
  isSaved,
  inputProps,
  rangePickerClassName,
  onChange,
  ...rest
}) => {
  Object.assign(ruRu, { shortWeekDays: SHORT_WEEK_DAYS_NAME })
  Object.assign(ruRu, { shortMonths: SHORT_MONTHS_NAME })
 
  const inputValue = value ? dayjs(value).utc(true).format(DEFAULT_DATE_FORMAT) : ''
  const datepickerValue = value ? dayjs(value).utc(true) : null
 
  return (
    <Popover className={cn('relative w-full z-20', className)}>
      {({ open, close }) => (
        <>
          <Popover.Button
            disabled={disabled || isSaved}
            className={cn('w-full text-left outline-none', {
              'cursor-text': isSaved,
            })}
          >
            <Input
              {...inputProps}
              name={name}
              value={inputValue}
              type='datepicker'
              readOnly
              isSaved={isSaved}
              isDropdownOpen={open}
              className={cn({ 'bg-background': open && value }, inputProps?.className)}
              disabled={disabled}
              reset={() => onChange?.(null)}
            />
          </Popover.Button>
 
          <Transition
            enter='transition duration-100 ease-out'
            enterFrom='transform scale-95 opacity-0'
            enterTo='transform scale-100 opacity-100'
            leave='transition duration-75 ease-out'
            leaveFrom='transform scale-100 opacity-100'
            leaveTo='transform scale-95 opacity-0'
            className='absolute top-[84px] right-0 origin-top-left'
          >
            <Popover.Panel>
              <PickerPanel
                {...rest}
                locale={ruRu}
                // В либе не правильно описаны пропсы
                // @ts-expect-error
                prevIcon={
                  <Button variant='icon' color='secondary'>
                    <ArrowIcon className='rotate-90 stroke-currentColor' />
                  </Button>
                }
                nextIcon={
                  <Button variant='icon' color='secondary'>
                    <ArrowIcon className='-rotate-90 stroke-currentColor' />
                  </Button>
                }
                superPrevIcon={
                  <Button variant='icon' color='secondary' childrenClassName='flex items-center'>
                    <ArrowIcon className='-mr-3 rotate-90 stroke-currentColor' />
                    <ArrowIcon className='rotate-90 stroke-currentColor' />
                  </Button>
                }
                superNextIcon={
                  <Button variant='icon' color='secondary' childrenClassName='flex items-center'>
                    <ArrowIcon className='-rotate-90 stroke-currentColor' />
                    <ArrowIcon className='-ml-3 -rotate-90 stroke-currentColor' />
                  </Button>
                }
                className={rangePickerClassName}
                showTime={false}
                value={datepickerValue}
                onChange={value => {
                  onChange?.(value.startOf('D').utc(true).format())
                  close()
                }}
                generateConfig={generateConfig}
              />
            </Popover.Panel>
          </Transition>
        </>
      )}
    </Popover>
  )
}