diff --git a/client/modules/IDE/components/FileNode.jsx b/client/modules/IDE/components/FileNode.jsx index 0b6424a783..010bc59a40 100644 --- a/client/modules/IDE/components/FileNode.jsx +++ b/client/modules/IDE/components/FileNode.jsx @@ -1,5 +1,5 @@ import PropTypes from 'prop-types'; -import React from 'react'; +import React, { useState, useRef } from 'react'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; import classNames from 'classnames'; @@ -63,49 +63,46 @@ FileName.propTypes = { name: PropTypes.string.isRequired }; -class FileNode extends React.Component { - constructor(props) { - super(props); +function FileNode(props) { + const [isOptionsOpen, setIsOptionsOpen] = useState(false); + const [isEditingName, setIsEditingName] = useState(false); + const [isFocused, setIsFocused] = useState(false); + const [isDeleting, setIsDeleting] = useState(false); + const [updatedName, setUpdatedName] = useState(props.name); + const fileNameInputRef = useRef(null); + const fileOptionsRef = useRef(null); + + const onFocusComponent = () => { + setIsFocused(true); + }; - this.state = { - isOptionsOpen: false, - isEditingName: false, - isFocused: false, - isDeleting: false, - updatedName: this.props.name - }; - } + const hideFileOptions = () => { + setIsOptionsOpen(false); + }; - onFocusComponent = () => { - this.setState({ isFocused: true }); + const hideEditFileName = () => { + setIsEditingName(false); }; - onBlurComponent = () => { - this.setState({ isFocused: false }); + const onBlurComponent = () => { + setIsFocused(false); setTimeout(() => { - if (!this.state.isFocused) { - this.hideFileOptions(); + if (!isFocused) { + hideFileOptions(); } }, 200); }; - setUpdatedName = (updatedName) => { - this.setState({ updatedName }); - }; - - saveUpdatedFileName = () => { - const { updatedName } = this.state; - const { name, updateFileName, id } = this.props; - + const saveUpdatedFileName = () => { + const { name, updateFileName, id } = props; if (updatedName !== name) { updateFileName(id, updatedName); } }; - handleFileClick = (event) => { + const handleFileClick = (event) => { event.stopPropagation(); - const { isDeleting } = this.state; - const { id, setSelectedFile, name, onClickFile } = this.props; + const { id, setSelectedFile, name, onClickFile } = props; if (name !== 'root' && !isDeleting) { setSelectedFile(id); } @@ -116,67 +113,13 @@ class FileNode extends React.Component { } }; - handleFileNameChange = (event) => { - const newName = event.target.value; - this.setUpdatedName(newName); - }; - - handleFileNameBlur = () => { - this.validateFileName(); - this.hideEditFileName(); - }; - - handleClickRename = () => { - this.setUpdatedName(this.props.name); - this.showEditFileName(); - setTimeout(() => this.fileNameInput.focus(), 0); - setTimeout(() => this.hideFileOptions(), 0); - }; - - handleClickAddFile = () => { - this.props.newFile(this.props.id); - setTimeout(() => this.hideFileOptions(), 0); - }; - - handleClickAddFolder = () => { - this.props.newFolder(this.props.id); - setTimeout(() => this.hideFileOptions(), 0); - }; - - handleClickUploadFile = () => { - this.props.openUploadFileModal(this.props.id); - setTimeout(this.hideFileOptions, 0); - }; - - handleClickDelete = () => { - const prompt = this.props.t('Common.DeleteConfirmation', { - name: this.props.name - }); - - if (window.confirm(prompt)) { - this.setState({ isDeleting: true }); - this.props.resetSelectedFile(this.props.id); - setTimeout( - () => this.props.deleteFile(this.props.id, this.props.parentId), - 100 - ); - } - }; - - handleKeyPress = (event) => { - if (event.key === 'Enter') { - this.hideEditFileName(); - } - }; - - validateFileName = () => { - const currentName = this.props.name; - const { updatedName } = this.state; + const validateFileName = () => { + const currentName = props.name; const oldFileExtension = currentName.match(/\.[0-9a-z]+$/i); const newFileExtension = updatedName.match(/\.[0-9a-z]+$/i); const hasPeriod = updatedName.match(/\.+/); const hasNoExtension = oldFileExtension && !newFileExtension; - const hasExtensionIfFolder = this.props.fileType === 'folder' && hasPeriod; + const hasExtensionIfFolder = props.fileType === 'folder' && hasPeriod; const notSameExtension = oldFileExtension && newFileExtension && @@ -191,219 +134,251 @@ class FileNode extends React.Component { hasOnlyExtension || hasExtensionIfFolder ) { - this.setUpdatedName(currentName); + setUpdatedName(currentName); } else { - this.saveUpdatedFileName(); + saveUpdatedFileName(); } }; - toggleFileOptions = (event) => { - event.preventDefault(); - if (!this.props.canEdit) { - return; - } - if (this.state.isOptionsOpen) { - this.setState({ isOptionsOpen: false }); - } else { - this[`fileOptions-${this.props.id}`].focus(); - this.setState({ isOptionsOpen: true }); - } + const handleFileNameChange = (event) => { + const newName = event.target.value; + setUpdatedName(newName); + }; + + const handleFileNameBlur = () => { + validateFileName(); + hideEditFileName(); }; - hideFileOptions = () => { - this.setState({ isOptionsOpen: false }); + const showEditFileName = () => { + setIsEditingName(true); }; - showEditFileName = () => { - this.setState({ isEditingName: true }); + const handleClickRename = () => { + setUpdatedName(props.name); + showEditFileName(); + setTimeout(() => fileNameInputRef.current.focus(), 0); + setTimeout(() => hideFileOptions(), 0); }; - hideEditFileName = () => { - this.setState({ isEditingName: false }); + const handleClickAddFile = () => { + props.newFile(props.id); + setTimeout(() => hideFileOptions(), 0); }; - showFolderChildren = () => { - this.props.showFolderChildren(this.props.id); + const handleClickAddFolder = () => { + props.newFolder(props.id); + setTimeout(() => hideFileOptions(), 0); }; - hideFolderChildren = () => { - this.props.hideFolderChildren(this.props.id); + const handleClickUploadFile = () => { + props.openUploadFileModal(props.id); + setTimeout(hideFileOptions, 0); }; - renderChild = (childId) => ( + const handleClickDelete = () => { + const prompt = props.t('Common.DeleteConfirmation', { + name: props.name + }); + + if (window.confirm(prompt)) { + setIsDeleting(true); + props.resetSelectedFile(props.id); + setTimeout(() => props.deleteFile(props.id, props.parentId), 100); + } + }; + + const handleKeyPress = (event) => { + if (event.key === 'Enter') { + hideEditFileName(); + } + }; + + const toggleFileOptions = (event) => { + event.preventDefault(); + if (!props.canEdit) { + return; + } + if (isOptionsOpen) { + setIsOptionsOpen(false); + } else { + fileOptionsRef.current.focus(); + setIsOptionsOpen(true); + } + }; + + const showFolderChildren = () => { + props.showFolderChildren(props.id); + }; + + const hideFolderChildren = () => { + props.hideFolderChildren(props.id); + }; + + const renderChild = (childId) => (
  • ); - render() { - const itemClass = classNames({ - 'sidebar__root-item': this.props.name === 'root', - 'sidebar__file-item': this.props.name !== 'root', - 'sidebar__file-item--selected': this.props.isSelectedFile, - 'sidebar__file-item--open': this.state.isOptionsOpen, - 'sidebar__file-item--editing': this.state.isEditingName, - 'sidebar__file-item--closed': this.props.isFolderClosed - }); - - const isFile = this.props.fileType === 'file'; - const isFolder = this.props.fileType === 'folder'; - const isRoot = this.props.name === 'root'; + const itemClass = classNames({ + 'sidebar__root-item': props.name === 'root', + 'sidebar__file-item': props.name !== 'root', + 'sidebar__file-item--selected': props.isSelectedFile, + 'sidebar__file-item--open': isOptionsOpen, + 'sidebar__file-item--editing': isEditingName, + 'sidebar__file-item--closed': props.isFolderClosed + }); - const { t } = this.props; + const isFile = props.fileType === 'file'; + const isFolder = props.fileType === 'folder'; + const isRoot = props.name === 'root'; + const { t } = props; - return ( -
    - {!isRoot && ( -
    + {!isRoot && ( +
    + + {isFile && ( + + + )} + {isFolder && ( +
    + + +
    + )} + + + +
    +
      + {isFolder && ( + +
    • + +
    • +
    • + +
    • + {props.authenticated && ( +
    • + +
    • + )} +
      + )} +
    • +
    • +
    • -
    - )} - - { - this.fileNameInput = element; - }} - onBlur={this.handleFileNameBlur} - onKeyPress={this.handleKeyPress} - /> - -
    -
      - {isFolder && ( - -
    • - -
    • -
    • - -
    • - {this.props.authenticated && ( -
    • - -
    • - )} -
      - )} -
    • - -
    • -
    • - -
    • -
    -
    + +
    - )} - {this.props.children && ( - - )} -
    - ); - } +
    + )} + {props.children && ( + + )} + + ); } FileNode.propTypes = {