"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.FileUploader = FileUploader;
var _react = _interopRequireWildcard(require("react"));
var _classnames = _interopRequireDefault(require("classnames"));
var _uniqueId = _interopRequireDefault(require("lodash-es/uniqueId"));
var _faTrashCan = require("@fortawesome/free-solid-svg-icons/faTrashCan");
var _faCloudUploadAlt = require("@fortawesome/free-solid-svg-icons/faCloudUploadAlt");
var _faFileLines = require("@fortawesome/free-solid-svg-icons/faFileLines");
var _faFolder = require("@fortawesome/free-solid-svg-icons/faFolder");
var _fontAwesomeIcon = require("../font-awesome-icon");
var _fileUploaderHelpers = require("./file-uploader-helpers");
var _usePrevious = require("../hooks/use-previous");
var _fileUploaderStatusMessage = _interopRequireDefault(require("./file-uploader-status-message"));
var _fileUploaderConstants = require("./file-uploader-constants");
var _fileUploaderHook = require("./file-uploader-hook");
var _dragAndDropWrapper = require("../drag-and-drop-wrapper");
var _truncateString = require("../truncate-string");
var _hooks = require("../hooks");
var _button = require("../button");
var _dropdownMenu = require("../dropdown-menu");
var _listCard = require("../list-card");
var _message = require("../message");
var _dropdown = require("../dropdown");
var _useTranslation = require("../hooks/use-translation");
var _truncateString2 = require("../truncate-string/truncate-string");
var _jsxRuntime = require("react/jsx-runtime");
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
const isFolderUploadSupported = (0, _fileUploaderHelpers.supportsFolderUpload)();
/** A unified file uploader component.
 * @midnight-gray-supported
 * @alpine-light-supported
 * */
function FileUploader({
  serviceHandler,
  children,
  onFileDropdownClose,
  onFileDropdownOpen,
  onFileUploadSuccess = () => {},
  onFileUploadFailure = () => {},
  acceptedFilesList = [],
  isMultiple = false,
  isFolderUpload = false,
  initialFiles = [],
  onFileUpload = () => {},
  onFileDelete = () => {},
  onFileCancel = () => {},
  isExpandedSingleFileUpload = false,
  showAcceptedFilesList = false,
  dragAndDropContainerClassName = '',
  inputTestId = 'file-uploader-input',
  dropdownMenuOptions = [],
  progressBarFiles = [],
  isDisabled = false,
  disableDragNDrop = false,
  showFileList = true,
  placeholderLabel: placeholderLabelParams,
  controlsContent = null,
  isCancelAllowed = true,
  errorMessages: errorMessagesParams = {},
  deleteLabelText: deleteLabelTextParams,
  cancelLabelText: cancelLabelTextParams,
  chooseFileLabelText: chooseFileLabelTextParams,
  acceptedFormatsLabelText: acceptedFormatsLabelTextParams,
  isRequired = false,
  isTouched = false,
  label = '',
  helperText = ''
}) {
  const {
    t
  } = (0, _useTranslation.useTranslation)();
  const errors = (0, _fileUploaderConstants.useFileUploaderErrors)();
  const errorMessages = {
    ...errors,
    ...errorMessagesParams
  };
  const placeholderLabel = placeholderLabelParams ?? t('Drop file(s) here to upload or');
  const deleteLabelText = deleteLabelTextParams ?? t('Delete');
  const cancelLabelText = cancelLabelTextParams ?? t('Cancel');
  const chooseFileLabelText = chooseFileLabelTextParams ?? t('Choose file');
  const acceptedFormatsLabelText = acceptedFormatsLabelTextParams ?? t('Accepted formats: {{formats}}', {
    formats: acceptedFilesList.join(', ')
  });
  const [isHidden, setIsHidden] = (0, _react.useState)(!isMultiple && !isExpandedSingleFileUpload && initialFiles.length === 1);
  const [errorMessage, setErrorMessage] = (0, _react.useState)('');
  const [fileInputKey, setFileInputKey] = (0, _react.useState)((0, _uniqueId.default)());
  const [dropdownMenuKey, setDropdownMenuKey] = (0, _react.useState)((0, _uniqueId.default)());
  const showExpandedSingleFileUpload = isExpandedSingleFileUpload && !isMultiple;
  const {
    addedFileStructure,
    collectedFileStructure,
    generateFileStructure,
    removeFileFromStructure,
    updateFileStructure
  } = (0, _fileUploaderHook.useFileUploader)({
    isMultiple,
    initialFiles: [],
    setErrorMessage
  });
  const inputRef = _react.default.useRef(null);
  const collectedFileStructureLength = collectedFileStructure.length;
  (0, _react.useEffect)(() => {
    if (!!inputRef.current && isFolderUploadSupported && isFolderUpload) {
      inputRef.current.setAttribute('webkitdirectory', isFolderUpload.toString());
    }
  }, [inputRef]);
  const removeFile = file => {
    const {
      name
    } = file;
    if (collectedFileStructureLength <= 1) {
      setIsHidden(false);
    }
    removeFileFromStructure(name);
    setFileInputKey((0, _uniqueId.default)());
  };
  const filesValidation = files => {
    if (!acceptedFilesList.length) {
      return files;
    }
    return files.filter(file => {
      if (!file?.skipTypeValidation) {
        const fileExtensionByName = file.name.match(/\.[0-9a-z]+$/i);
        const {
          FILE_TYPE_IS_NOT_ALLOWED
        } = _fileUploaderConstants.ERROR_TYPES;
        if (!fileExtensionByName || !acceptedFilesList.some(extension => fileExtensionByName[0].toLowerCase() === extension)) {
          updateFileStructure(file.name, {
            completed: true,
            error: errorMessages[FILE_TYPE_IS_NOT_ALLOWED]
          });
          onFileUploadFailure({
            error: FILE_TYPE_IS_NOT_ALLOWED
          });
          return false;
        }
      }
      return true;
    });
  };
  const onHandleFileUploadSuccess = (data, file) => {
    const name = file?.name ?? '';
    updateFileStructure(name, {
      completed: true
    });
    onFileUploadSuccess(data);
  };
  const onHandleFileUploadFailure = (data, file) => {
    const {
      name
    } = file;
    const {
      error
    } = data;
    const message = error || errorMessages[_fileUploaderConstants.ERROR_TYPES.DEFAULT_UPLOAD_ERROR];
    updateFileStructure(name, {
      completed: true,
      error: message
    });
    onFileUploadFailure(data);
  };
  const uploadFiles = files => {
    if (serviceHandler) {
      files.forEach(file => {
        serviceHandler(file).then(data => onHandleFileUploadSuccess(data, file)).catch(error => onHandleFileUploadFailure(error, file));
      });
    }
  };
  const handleFileUpload = files => {
    setErrorMessage('');
    setDropdownMenuKey((0, _uniqueId.default)());
    if (showExpandedSingleFileUpload) {
      setIsHidden(false);
    } else if (!isMultiple) {
      setIsHidden(true);
    }
    const validatedFiles = filesValidation(files);
    if (!!validatedFiles.length) {
      uploadFiles(validatedFiles);
      onFileUpload(validatedFiles);
    }
  };
  const handleFileDelete = deleteFile => {
    if (collectedFileStructureLength === 1 && isRequired) {
      setErrorMessage(errorMessages[_fileUploaderConstants.ERROR_TYPES.IS_REQUIRED] ?? '');
    } else {
      setErrorMessage('');
    }
    onFileDelete(deleteFile);
    removeFile(deleteFile);
  };
  const handleFileCancel = cancelFile => {
    if (collectedFileStructureLength === 1 && !collectedFileStructure[0].completed && isRequired) {
      setErrorMessage(errorMessages[_fileUploaderConstants.ERROR_TYPES.IS_REQUIRED] ?? '');
    }
    onFileCancel(cancelFile);
    removeFile(cancelFile);
  };

  // update file list with initial or new files
  const prevInitialFiles = (0, _usePrevious.usePrevious)(initialFiles);
  (0, _react.useEffect)(() => {
    const newInitialFiles = initialFiles.filter(item => !(0, _fileUploaderHook.findByName)(prevInitialFiles || [], item.name));
    if (newInitialFiles.length && (isMultiple || !collectedFileStructureLength)) {
      generateFileStructure({
        files: isMultiple ? newInitialFiles : [newInitialFiles[0]]
      });
    } else if (!initialFiles?.length && prevInitialFiles?.length) {
      // clean up after initial files were removed
      prevInitialFiles.forEach(({
        name
      }) => {
        removeFileFromStructure(name);
      });
    }
  }, [initialFiles]);

  // add file to structure
  (0, _react.useEffect)(() => {
    if (!!addedFileStructure.length) {
      handleFileUpload(addedFileStructure);
    }
  }, [addedFileStructure]);
  (0, _react.useEffect)(() => {
    if (!collectedFileStructureLength && isRequired && isTouched) {
      setErrorMessage(errorMessages[_fileUploaderConstants.ERROR_TYPES.IS_REQUIRED] ?? '');
    }
  }, [collectedFileStructure, isRequired, isTouched]);
  const handleFileInputChange = event => {
    generateFileStructure(event.target);
  };
  const handleOnDropdownMenuSelect = (option, files) => {
    if (option && option.id) {
      if (!!option.onOptionSelect) {
        option.onOptionSelect();
      } else if (files?.selectedFiles?.length) {
        generateFileStructure({
          files: files.selectedFiles
        });
      }
    }
  };
  const {
    name,
    completed,
    size,
    details,
    error,
    showFileSize
  } = collectedFileStructure[0] || {};
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
    className: "file-uploader",
    children: [label && /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
      className: "file-uploader-label",
      children: label
    }), helperText && /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
      className: "file-uploader-helper-text",
      children: helperText
    }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_dragAndDropWrapper.DragNDropWrapper, {
      onDropAction: generateFileStructure,
      containerClassName: (0, _classnames.default)('file-uploader-input', dragAndDropContainerClassName, {
        expanded: showExpandedSingleFileUpload,
        'expanded-has-file': showExpandedSingleFileUpload && collectedFileStructureLength === 1,
        hidden: isHidden,
        error: !!errorMessage,
        disabled: isDisabled || disableDragNDrop
      }),
      isDropAllowed: () => !isDisabled && !disableDragNDrop,
      onDragClassName: (0, _classnames.default)({
        'file-uploader-input-on-drag': !isDisabled
      }),
      children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
        className: (0, _classnames.default)('file-uploader-drop-section', {
          expanded: showExpandedSingleFileUpload,
          disabled: isDisabled
        }),
        children: showExpandedSingleFileUpload && collectedFileStructureLength === 1 && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
          children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_truncateString.TruncateString, {
            text: name,
            truncateAt: _truncateString2.ELLIPSIS_PLACE_TYPES.MIDDLE,
            testId: "file-uploader-single-file-label",
            className: "file-uploader-single-file-name-label"
          }), error && /*#__PURE__*/(0, _jsxRuntime.jsx)(_message.Message, {
            testId: "file-uploader-single-file-error-message",
            className: "file-uploader-error",
            type: _message.MESSAGE_TYPES.ERROR,
            children: error
          }) || /*#__PURE__*/(0, _jsxRuntime.jsx)(_fileUploaderStatusMessage.default, {
            isExpanded: showExpandedSingleFileUpload,
            completed: completed,
            size: size,
            details: details,
            progressBarFile: (0, _fileUploaderHook.findByName)(progressBarFiles, name),
            showProgressBar: !!progressBarFiles.length,
            showFileSize: showFileSize
          }), completed && /*#__PURE__*/(0, _jsxRuntime.jsx)(_button.Button, {
            accentType: _button.ACCENT_TYPES.COMMAND,
            className: "file-uploader-single-file-remove-button",
            testId: `file-uploader-delete-button-${name}`,
            "aria-label": deleteLabelText,
            onClick: () => handleFileDelete(collectedFileStructure[0]),
            leftIcon: _faTrashCan.faTrashCan,
            children: deleteLabelText
          }), !completed && isCancelAllowed && /*#__PURE__*/(0, _jsxRuntime.jsx)(_button.Button, {
            accentType: _button.ACCENT_TYPES.COMMAND,
            className: "single-file-cancel-button",
            testId: `file-uploader-cancel-button-${name}`,
            "aria-label": cancelLabelText,
            onClick: () => handleFileCancel(collectedFileStructure[0]),
            children: cancelLabelText
          })]
        }) || /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
          children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_fontAwesomeIcon.FontAwesomeIcon, {
            icon: _faCloudUploadAlt.faCloudUploadAlt,
            className: "file-uploader-cloud-icon"
          }), /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
            className: "file-uploader-description",
            "test-id": "file-uploader-description",
            children: placeholderLabel
          }), dropdownMenuOptions.length && /*#__PURE__*/(0, _jsxRuntime.jsx)(_dropdownMenu.DropdownMenu, {
            triggerClassName: "file-uploader-dropdown-menu-trigger",
            triggerTestId: "file-uploader-dropdown-menu-trigger",
            contentTestId: "file-uploader-dropdown-menu-content",
            options: dropdownMenuOptions,
            onSelect: handleOnDropdownMenuSelect,
            placement: _dropdown.DROPDOWN_PLACEMENT_TYPES.BOTTOM,
            defaultTriggerText: chooseFileLabelText,
            onClose: onFileDropdownClose,
            onOpen: onFileDropdownOpen,
            isDisabled: isDisabled,
            triggerDynamicContent: () => /*#__PURE__*/(0, _jsxRuntime.jsxs)("span", {
              className: "file-uploader-dropdown-menu-trigger-text-container",
              children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_fontAwesomeIcon.FontAwesomeIcon, {
                icon: _faFolder.faFolder
              }), /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
                children: chooseFileLabelText
              })]
            })
          }, dropdownMenuKey) || /*#__PURE__*/(0, _jsxRuntime.jsx)(_button.Button, {
            accentType: _button.ACCENT_TYPES.COMMAND,
            isDisabled: isDisabled,
            leftIcon: _faFolder.faFolder,
            className: "file-uploader-choose-file-button",
            onKeyDown: event => {
              if ((0, _hooks.shouldSubmitViaKeyDown)(event) && !isDisabled) {
                event.stopPropagation();
                event.preventDefault();
                inputRef.current?.click?.();
              }
            },
            children: /*#__PURE__*/(0, _jsxRuntime.jsx)("label", {
              className: "browse-file",
              htmlFor: `browseFile-${fileInputKey}`,
              children: chooseFileLabelText
            })
          }), /*#__PURE__*/(0, _jsxRuntime.jsx)("input", {
            ref: inputRef,
            type: "file",
            id: `browseFile-${fileInputKey}`,
            accept: acceptedFilesList.toString(),
            name: "file",
            onChange: handleFileInputChange,
            multiple: isMultiple,
            "test-id": inputTestId,
            disabled: isDisabled,
            "aria-hidden": true
          }, fileInputKey)]
        })
      }), showAcceptedFilesList && collectedFileStructureLength === 0 && !!acceptedFilesList.length && /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
        className: "file-uploader-accepted-files",
        "test-id": "file-uploader-accepted-files",
        children: acceptedFormatsLabelText
      })]
    }), errorMessage && /*#__PURE__*/(0, _jsxRuntime.jsx)(_message.Message, {
      type: _message.MESSAGE_TYPES.ERROR,
      className: "file-uploader-error",
      testId: "file-uploader-error",
      children: errorMessage
    }), !showExpandedSingleFileUpload && showFileList && collectedFileStructure && /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
      className: "file-uploader-dropped-files-section",
      children: collectedFileStructure.map(item => /*#__PURE__*/(0, _jsxRuntime.jsx)(_listCard.ListCard, {
        testId: "file-uploader-list-card",
        isInteractive: false,
        icon: _faFileLines.faFileLines,
        isDisabled: isDisabled,
        titleContent: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
          children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_truncateString.TruncateString, {
            truncateAt: _truncateString2.ELLIPSIS_PLACE_TYPES.MIDDLE,
            text: item.name
          }), !item.completed && isCancelAllowed && /*#__PURE__*/(0, _jsxRuntime.jsx)(_button.Button, {
            isDisabled: isDisabled,
            accentType: _button.ACCENT_TYPES.COMMAND,
            className: "list-card-cancel-button",
            testId: `file-uploader-cancel-button-${item.name}`,
            "aria-label": cancelLabelText,
            onClick: () => handleFileCancel(item),
            children: cancelLabelText
          })]
        }),
        hasErrored: !!item.error,
        errorMessage: item.error,
        showChevron: false,
        ariaLabelLoading: item.ariaLabelLoading,
        detailsContent: /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
          className: "file-uploader-details-content",
          children: !item.error ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_fileUploaderStatusMessage.default, {
            completed: item.completed,
            size: item.size,
            details: item.details,
            progressBarFile: (0, _fileUploaderHook.findByName)(progressBarFiles, item.name),
            showProgressBar: !!progressBarFiles.length,
            showFileSize: item.showFileSize
          }) : null
        }),
        controlsContent: item.completed && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
          children: [controlsContent, /*#__PURE__*/(0, _jsxRuntime.jsx)(_button.Button, {
            accentType: _button.ACCENT_TYPES.ROUND_ICON,
            testId: `file-uploader-delete-button-${item.name}`,
            "aria-label": deleteLabelText,
            onClick: () => handleFileDelete(item),
            isDisabled: isDisabled,
            children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_fontAwesomeIcon.FontAwesomeIcon, {
              icon: _faTrashCan.faTrashCan
            })
          })]
        })
      }, item.name))
    }), typeof children === 'function' && children({
      handleFilesSelected: generateFileStructure
    })]
  });
}