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) => (