{"version":3,"file":"FileUpload-BB0TI98g.js","sources":["../../Client/legacy/Components/FormGroups/FileUpload.tsx"],"sourcesContent":["import { FormGroup } from '@legacy/Components/FormGroups/Base';\r\nimport { Svg } from '@legacy/Components/Svg';\r\nimport { InlineError } from '@legacy/FormFields';\r\nimport { MimeType } from '@shared/Constants';\r\nimport { Value } from '@webkit/index';\r\nimport { clsx } from 'clsx';\r\nimport * as React from 'react';\r\nimport { ReactElement } from 'react';\r\n\r\nexport interface IFileUploadFormGroupProps {\r\n    /** The identifier for the form group. */\r\n    id: string;\r\n\r\n    /** The name for the file input. */\r\n    name?: string;\r\n\r\n    /** The change handler for when files have been added or removed. */\r\n    onFilesChanged: (files: File[]) => void;\r\n\r\n    /** The list of files. */\r\n    files: Value<File[]>;\r\n\r\n    /** The optional CSS class for the form group. */\r\n    className?: string;\r\n\r\n    /** The optional tab index to support keyboard navigation. */\r\n    tabIndex?: number;\r\n\r\n    /** Optional, pass in the accepted file types as a string to preselect the file type in the file browser (see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file for examples).\r\n     * Note that this does *not* prevent the user from uploading a file of a different type; it just sets the default filter after the file selection dialog opens. Additional validation\r\n     * needs to be present to ensure the correct file type is uploaded. */\r\n    accept?: MimeType[];\r\n\r\n    /** Optional, pass in a boolean controller for displaying an error (if not used, the Value will generate an error based on the rule pattern in FormFields.tsx */\r\n    error?: boolean;\r\n\r\n    /** Optional, pass in a boolean value to hide the tooltip. */\r\n    hideToolTip?: boolean;\r\n\r\n    /** Flag to allow multiple file uploads simultaneously. Defaults to false. */\r\n    multiple?: boolean;\r\n\r\n    /** Optional label for the control. */\r\n    label?: string;\r\n\r\n    /** Optional disabled flag */\r\n    disabled?: boolean;\r\n\r\n    /** Optional message to display when disabled */\r\n    disabledMessage?: string | ReactElement;\r\n\r\n    /** Optional control to disable deleting a previously added file. */\r\n    disableDeleteFile?: boolean;\r\n}\r\n\r\ninterface IFileUploadFormGroupState {\r\n    dragging: boolean;\r\n}\r\n\r\n// TODO: Convert to function component and clean up code - Darius 9/13/23\r\nexport class FileUploadFormGroup extends React.Component<IFileUploadFormGroupProps, IFileUploadFormGroupState> {\r\n    upload: HTMLInputElement;\r\n    dragCounter: number = 0;\r\n\r\n    state = {\r\n        dragging: false,\r\n    };\r\n\r\n    render() {\r\n        const p = this.props;\r\n        return (\r\n            <div className={clsx('form-group-file-upload-cp', p.className, p.disabled ? 'disabled' : '')}>\r\n                {p.label && <FormGroup label={p.label} />}\r\n\r\n                <input\r\n                    id={p.id}\r\n                    type='file'\r\n                    name={p.name}\r\n                    ref={c => {\r\n                        this.upload = c as HTMLInputElement;\r\n                    }}\r\n                    onChange={e => e.target.files && this.onAddFiles(e.target.files)}\r\n                    accept={p.accept?.join(', ')}\r\n                    multiple={p.multiple}\r\n                />\r\n\r\n                <div\r\n                    className={clsx(\r\n                        'form-group-file-upload-drop-cp',\r\n                        this.state.dragging && !p.disabled && 'form-group-file-upload-drop-dragging-cp',\r\n                        p.disabled && 'disabled',\r\n                        p.files.error && 'error'\r\n                    )}\r\n                    onClick={() => {\r\n                        if (this.props.disabled) {\r\n                            return;\r\n                        }\r\n\r\n                        this.upload.click();\r\n                    }}\r\n                    onDragEnter={(e: React.DragEvent<HTMLDivElement>) => this.onDragEnter(e)}\r\n                    onDragLeave={(e: React.DragEvent<HTMLDivElement>) => this.onDragLeave(e)}\r\n                    onDragOver={(e: React.DragEvent<HTMLDivElement>) => this.onDragOver(e)}\r\n                    onDrop={(e: React.DragEvent<HTMLDivElement>) => this.onDrop(e)}\r\n                >\r\n                    {p.disabled && p.disabledMessage ? (\r\n                        p.disabledMessage\r\n                    ) : (\r\n                        <span>\r\n                            <a tabIndex={p.tabIndex}>Drag files here or click to browse</a>.\r\n                        </span>\r\n                    )}\r\n\r\n                    {(p.error === undefined || p.error) && (\r\n                        <InlineError error={p.files.error} noToolTip={p.hideToolTip ? p.hideToolTip : false} />\r\n                    )}\r\n                </div>\r\n\r\n                <div className='form-group-file-upload-list-cp'>\r\n                    {p.files.content.map((f: File) => (\r\n                        <FileWrapper\r\n                            file={f}\r\n                            onDelete={(file: File) => this.onDeleteFile(file)}\r\n                            key={getFileIdentifier(f)}\r\n                            disableDeleteFile={p.disableDeleteFile}\r\n                        />\r\n                    ))}\r\n                </div>\r\n            </div>\r\n        );\r\n    }\r\n\r\n    private onAddFiles(files: FileList) {\r\n        // If disabled, do nothing\r\n        if (this.props.disabled) {\r\n            return;\r\n        }\r\n\r\n        const addedFiles = this.getAddedFiles();\r\n        for (let i = 0; i < files.length; i++) addedFiles[getFileIdentifier(files[i])] = files[i];\r\n        this.props.onFilesChanged(Object.keys(addedFiles).map(key => addedFiles[key]));\r\n    }\r\n\r\n    private onDeleteFile(fileToDelete: File) {\r\n        // If deleting a file is disabled, do nothing\r\n        if (this.props.disableDeleteFile) {\r\n            return;\r\n        }\r\n\r\n        // Delete files from the list and update the parent state\r\n        const files = this.getAddedFiles();\r\n        delete files[getFileIdentifier(fileToDelete)];\r\n        this.props.onFilesChanged(Object.keys(files).map(key => files[key]));\r\n\r\n        // The file list should not be null\r\n        const inputFiles = this.upload.files;\r\n        if (!inputFiles) {\r\n            return;\r\n        }\r\n\r\n        // Remove the file from the input file list\r\n        const inputFileArray = Array.from(inputFiles),\r\n            filteredFileArray = inputFileArray.filter(f => f.name !== fileToDelete.name);\r\n\r\n        // Generate a DataTransfer object to set the new file list (FileList is an illegal constructor)\r\n        // https://stackoverflow.com/questions/52078853/is-it-possible-to-update-filelist\r\n        // https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer\r\n        const dataTransfer = new DataTransfer();\r\n\r\n        // Add the undeleted files to the new dataTransfer file list\r\n        filteredFileArray.forEach(f => dataTransfer.items.add(f));\r\n\r\n        // Set the file input files to the new dataTransfer file list\r\n        this.upload.files = dataTransfer.files;\r\n    }\r\n\r\n    private onDragEnter(e: React.DragEvent<HTMLDivElement>) {\r\n        e.preventDefault();\r\n        e.stopPropagation();\r\n        this.dragCounter++;\r\n        this.setState({ dragging: true });\r\n    }\r\n\r\n    private onDragLeave(e: React.DragEvent<HTMLDivElement>) {\r\n        e.preventDefault();\r\n        e.stopPropagation();\r\n        this.dragCounter--;\r\n        if (this.dragCounter === 0) this.setState({ dragging: false });\r\n    }\r\n\r\n    private onDragOver(e: React.DragEvent<HTMLDivElement>) {\r\n        e.preventDefault();\r\n        e.stopPropagation();\r\n    }\r\n\r\n    private onDrop(e: React.DragEvent<HTMLDivElement>) {\r\n        e.preventDefault();\r\n        e.stopPropagation();\r\n        this.dragCounter = 0;\r\n        this.setState({ dragging: false });\r\n        this.onAddFiles(e.dataTransfer.files);\r\n        this.upload.files = e.dataTransfer.files;\r\n    }\r\n\r\n    private getAddedFiles() {\r\n        const files = {};\r\n        this.props.files.content.forEach(f => {\r\n            files[getFileIdentifier(f)] = f;\r\n        });\r\n        return files;\r\n    }\r\n}\r\n\r\nconst FileWrapper = ({ file, onDelete, disableDeleteFile }) => (\r\n    <div className='form-group-file-upload-file-cp'>\r\n        <div>\r\n            <i onClick={() => onDelete(file)} style={{ cursor: disableDeleteFile ? 'not-allowed' : 'pointer' }}>\r\n                ✕\r\n            </i>\r\n            <Svg className='dropped-file-svg-ly' path='/images/icon-link.svg' alt={`${file.name} uploaded`} />\r\n        </div>\r\n        <span>{file.name}</span>\r\n    </div>\r\n);\r\n\r\nfunction getFileIdentifier(file: File) {\r\n    return file.name + file.size;\r\n}\r\n"],"names":["FileUploadFormGroup","React.Component","__publicField","p","jsxs","clsx","jsx","FormGroup","c","e","_a","InlineError","f","FileWrapper","file","getFileIdentifier","files","addedFiles","i","key","fileToDelete","inputFiles","inputFileArray","filteredFileArray","dataTransfer","onDelete","disableDeleteFile","Svg"],"mappings":"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"}