All files / atom/upload/src index.js

54.16% Statements 13/24
50% Branches 5/10
42.85% Functions 3/7
54.16% Lines 13/24

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 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149                              1x                   5x   5x 3x     5x                                               5x 5x 5x 1x                       1x     5x                               1x   1x                                                                                                                  
import {useEffect, useState} from 'react'
 
import cx from 'classnames'
import PropTypes from 'prop-types'
 
import {
  BASE_CLASS,
  capitalize,
  CLASS_BLOCK_TEXT,
  CLASS_BLOCK_TEXT_MAIN,
  CLASS_BLOCK_TEXT_SECONDARY,
  Dropzone,
  STATUSES
} from './settings.js'
 
const AtomUpload = ({
  status,
  onFilesSelection,
  textExplanation,
  actionButton: Button,
  multiple,
  maxSize,
  accept,
  ...props
}) => {
  const [ready, setReady] = useState(false)
 
  useEffect(() => {
    setReady(true)
  }, [])
 
  const renderStatusBlock = (status, getRootProps, getInputProps) => {
    const classNameIcon = `${BASE_CLASS}-icon${capitalize(status)}`
    const IconStatus = props[`icon${capitalize(status)}`]
    const textStatus = props[`text${capitalize(status)}`]
    const isActive = status === STATUSES.ACTIVE
    const hasTextExplanation = Boolean(textExplanation)
    const hasButton = Boolean(Button)
    return (
      <div className={cx(BASE_CLASS, `${BASE_CLASS}--${status}`)} {...getRootProps()}>
        <input type="hiden" {...getInputProps()} />
        <span className={classNameIcon}>{IconStatus}</span>
        <div className={CLASS_BLOCK_TEXT}>
          <h4 className={CLASS_BLOCK_TEXT_MAIN}>{textStatus}</h4>
          {isActive && (hasTextExplanation || hasButton) && (
            <>
              {Button}
              <p className={CLASS_BLOCK_TEXT_SECONDARY}>{textExplanation}</p>
            </>
          )}
        </div>
      </div>
    )
  }
 
  const hasValidStatus = Object.values(STATUSES).includes(status)
  const shouldRender = hasValidStatus && ready
  const onDrop = handler => {
    Iif (typeof handler === 'function') {
      return (acceptedFiles, rejectedFiles, event) =>
        handler(
          acceptedFiles.map(file =>
            Object.assign(file, {
              preview: URL.createObjectURL(file)
            })
          ),
          rejectedFiles,
          event
        )
    }
    return undefined
  }
 
  return (
    shouldRender && (
      <Dropzone
        accept={accept}
        className={`${BASE_CLASS}-dropzone`}
        disabled={status !== STATUSES.ACTIVE}
        maxSize={maxSize}
        multiple={multiple}
        onDrop={onDrop(onFilesSelection)}
      >
        {({getRootProps, getInputProps}) => renderStatusBlock(status, getRootProps, getInputProps)}
      </Dropzone>
    )
  )
}
 
AtomUpload.displayName = 'AtomUpload'
 
AtomUpload.propTypes = {
  /** Icon (component) to be displayed on active status */
  iconActive: PropTypes.oneOfType([PropTypes.element, PropTypes.func]), // eslint-disable-line react/no-unused-prop-types
 
  /** Icon (component) to be displayed on upload status */
  iconUpload: PropTypes.oneOfType([PropTypes.element, PropTypes.func]), // eslint-disable-line react/no-unused-prop-types
 
  /** Icon (component) to be displayed on success status */
  iconSuccess: PropTypes.oneOfType([PropTypes.element, PropTypes.func]), // eslint-disable-line react/no-unused-prop-types
 
  /** Icon (component) to be displayed on error status */
  iconError: PropTypes.oneOfType([PropTypes.element, PropTypes.func]), // eslint-disable-line react/no-unused-prop-types
 
  /** Text to be displayed on error status */
  textActive: PropTypes.string, // eslint-disable-line react/no-unused-prop-types
 
  /** Text to be displayed on upload status */
  textUpload: PropTypes.string, // eslint-disable-line react/no-unused-prop-types
 
  /** Text to be displayed on success status */
  textSuccess: PropTypes.string, // eslint-disable-line react/no-unused-prop-types
 
  /** Text to be displayed on error status */
  textError: PropTypes.string, // eslint-disable-line react/no-unused-prop-types
 
  /** Button component to be displayed on active status */
  actionButton: PropTypes.node, // eslint-disable-line react/no-unused-prop-types
 
  /** Text to be displayed as explanation on active status */
  textExplanation: PropTypes.string,
 
  /**
   * Status of the upload
   *  ACTIVE → 'active'
   *  UPLOAD →'upload'
   *  SUCCESS → 'success'
   *  ERROR → 'error'
   */
  status: PropTypes.oneOf(Object.values(STATUSES)).isRequired,
 
  /** Callback to be called (with files selected) when there`s a file selection (via click or drag & drop) */
  onFilesSelection: PropTypes.func,
  /**
   * Allow drag 'n' drop (or selection from the file dialog) of multiple files
   */
  multiple: PropTypes.bool,
  /** Maximum file size (in bytes) */
  maxSize: PropTypes.number,
  /**
   * Set accepted file types.
   * See https://github.com/okonet/attr-accept for more information.
   */
  accept: PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.string)])
}
 
export {STATUSES as uploadStatuses}
export default AtomUpload