diff --git a/cocode/src/actions/Project.js b/cocode/src/actions/Project.js index f9353dd8..33474e62 100644 --- a/cocode/src/actions/Project.js +++ b/cocode/src/actions/Project.js @@ -6,7 +6,8 @@ import { CREATE_FILE, DELETE_FILE, MOVE_FILE, - INSTALL_DEPENDENCY + INSTALL_DEPENDENCY, + WAITING_INSTALL_DEPENDENCY } from './types'; function fetchProjectActionCreator(payload) { @@ -41,6 +42,10 @@ function installDependencyActionCreator(payload) { return { type: INSTALL_DEPENDENCY, payload }; } +function waitingInstallDependencyActionCreator(payload) { + return { type: WAITING_INSTALL_DEPENDENCY, payload }; +} + export { updateCodeActionCreator, fetchProjectActionCreator, @@ -49,5 +54,6 @@ export { createFileActionCreator, deleteFileActionCreator, moveFileActionCreator, - installDependencyActionCreator + installDependencyActionCreator, + waitingInstallDependencyActionCreator }; diff --git a/cocode/src/actions/types.js b/cocode/src/actions/types.js index b42807c3..90663fad 100644 --- a/cocode/src/actions/types.js +++ b/cocode/src/actions/types.js @@ -13,6 +13,7 @@ const UPDATE_FILE_NAME = 'updateFileName'; const DELETE_FILE = 'deleteFile'; const MOVE_FILE = 'moveFile'; const INSTALL_DEPENDENCY = 'installDependency'; +const WAITING_INSTALL_DEPENDENCY = 'waitingInstallDependency'; //DashBoard const FETCH_COCONUT = 'fetchCoconut'; @@ -32,6 +33,7 @@ export { DELETE_FILE, MOVE_FILE, INSTALL_DEPENDENCY, + WAITING_INSTALL_DEPENDENCY, FETCH_COCONUT, UPDATE_COCONUT_NAME, DELETE_COCONUT diff --git a/cocode/src/apis/Project.js b/cocode/src/apis/Project.js index 7938e45e..9b9b11b5 100644 --- a/cocode/src/apis/Project.js +++ b/cocode/src/apis/Project.js @@ -15,11 +15,15 @@ function forkProjectAPICreator(data) { }; } -function getDenpendencyList(name) { +function getDenpendencyListAPICreator(name) { return { url: `${API.dependency(name)}`, method: 'get' }; } -export { getProjectInfoAPICreator, forkProjectAPICreator, getDenpendencyList }; +export { + getProjectInfoAPICreator, + forkProjectAPICreator, + getDenpendencyListAPICreator +}; diff --git a/cocode/src/bundler/pathParser.js b/cocode/src/bundler/pathParser.js index 605d0552..537ee479 100644 --- a/cocode/src/bundler/pathParser.js +++ b/cocode/src/bundler/pathParser.js @@ -3,6 +3,8 @@ import path from 'path'; const DEPENDENCY_PATH = '/node_modules/'; function pathParser(param) { + const moduleName = param; + if (param[0] !== '.' && param[0] !== '/') { param = `${DEPENDENCY_PATH}${param}`; } @@ -15,7 +17,7 @@ function pathParser(param) { } else if (fileSystem[`${param}/index.js`]) { return [`${param}/index.js`, param]; } else { - throw Error('path error'); + throw Error(`Module not found: '${moduleName}'`); } } else { return [param, path.dirname(param)]; diff --git a/cocode/src/bundler/require.js b/cocode/src/bundler/require.js index 842489b0..0ee9a059 100644 --- a/cocode/src/bundler/require.js +++ b/cocode/src/bundler/require.js @@ -2,12 +2,33 @@ import { pathStack } from './global'; import { pathParser } from './pathParser'; import { transformCode } from './core'; +const executeCodeTemplate = code => /*javascript*/ ` +(() => { + const exports = {}; + try { + ${code} + return Object.keys(exports).length ? exports : module.exports; + } catch (e) { + const ignoreErrorList = [ + 'Cannot redefine property', + 'Cannot read property', + 'Cannot set property default of # which has only a getter' + ]; + const errorType = e.message; + const isExistInIgnoreList = ignoreErrorList.some(ignoreError => + errorType.startsWith(ignoreError) + ); + + if(!isExistInIgnoreList) throw e; + } +})()`; + function require(path) { - if (path.length < 3) throw Error('path error'); + if (path === '.') throw Error('Recursive path parsing error'); const [newPath, newPathParent] = pathParser(path); - if (exports[newPath]) { - return exports[newPath]; - } + + if (exports[newPath]) return exports[newPath]; + pathStack.push(newPathParent); const code = transformCode(fileSystem[newPath].contents).value; @@ -15,20 +36,14 @@ function require(path) { let stackLength = 0; try { stackLength = pathStack.length; - result = eval(` - (() =>{const exports = {}; - try { - ${code} - return Object.keys(exports).length ? exports : module.exports - }catch(e) {} - })()`); + result = eval(executeCodeTemplate(code)); } catch (error) { while (stackLength < pathStack.length) pathStack.pop(); result = eval(code); } + exports[newPath] = result; pathStack.pop(); - return result; } diff --git a/cocode/src/components/Common/CoconutSpinner/index.js b/cocode/src/components/Common/CoconutSpinner/index.js new file mode 100644 index 00000000..37c7f43c --- /dev/null +++ b/cocode/src/components/Common/CoconutSpinner/index.js @@ -0,0 +1,17 @@ +import React from 'react'; +import * as Styled from './style'; + +import TinyCoconutLogo from 'components/Common/TinyCoconutLogo'; + +function Spinner() { + return ( + + + + + + + ); +} + +export default Spinner; diff --git a/cocode/src/components/Common/CoconutSpinner/style.js b/cocode/src/components/Common/CoconutSpinner/style.js new file mode 100644 index 00000000..3dfae08b --- /dev/null +++ b/cocode/src/components/Common/CoconutSpinner/style.js @@ -0,0 +1,40 @@ +import styled from 'styled-components'; + +const Container = styled.div` + position: relative; + + width: 3.5rem; + height: 3.5rem; +`; + +const Content = styled.div` + position: absolute; + top: 1.1rem; + left: 0.8rem; +`; + +const SpinningArc = styled.div` + position: absolute; + width: 3.5rem; + height: 3.5rem; + background-color: transparent; + + box-sizing: content-box; + border: 3px solid white; + border-radius: 100%; + border-bottom-color: transparent; + + animation: 1s linear 0s infinite normal both running spin; + + @keyframes spin { + 0% { + transform: rotate(0deg); + } + + 100% { + transform: rotate(360deg); + } + } +`; + +export { Container, Content, SpinningArc }; diff --git a/cocode/src/components/Common/TinyCoconutLogo/index.js b/cocode/src/components/Common/TinyCoconutLogo/index.js new file mode 100644 index 00000000..7daf3751 --- /dev/null +++ b/cocode/src/components/Common/TinyCoconutLogo/index.js @@ -0,0 +1,105 @@ +import React from 'react'; + +function TinyCoconutLogo() { + return ( + + + + + + + + + + + + + + + + + + ); +} + +export default TinyCoconutLogo; diff --git a/cocode/src/components/Project/BrowserV2/index.js b/cocode/src/components/Project/BrowserV2/index.js index b4b73b0f..fc7992c4 100644 --- a/cocode/src/components/Project/BrowserV2/index.js +++ b/cocode/src/components/Project/BrowserV2/index.js @@ -7,31 +7,35 @@ import ProjectContext from 'contexts/ProjectContext'; function BrowserV2({ ...props }) { const { project } = useContext(ProjectContext); - const { files, root } = project; + const { files, root, dependencyInstalling } = project; const [isChange, setIsChange] = useState(false); - const [fileSystem, setFileSystem] = useState({}); const [errorDescription, setErrorDescription] = useState(null); - useEffect(() => { - function fileParser(path, id) { - if (files[id].type !== 'directory') { - fileSystem[path] = { - contents: files[id].contents - }; - delete exports[path]; - } else if (files[id].child) { - files[id].child.forEach(id => { - const path = files[id].path; - fileParser(path, id); - }); - } + function fileParser(path, id) { + if (files[id].type !== 'directory') { + fileSystem[path] = { + contents: files[id].contents + }; + delete exports[path]; + } else if (files[id].child) { + files[id].child.forEach(id => { + const path = files[id].path; + fileParser(path, id); + }); } + } + + const handleEndInstallDependency = () => { + if (!dependencyInstalling) setIsChange(true); + }; + + const handleParsingProject = () => { const rootPath = files[root].path; if (project) fileParser(rootPath, project.root); setIsChange(true); - }, [files]); + }; - useEffect(() => { + const handleBuildProject = () => { if (isChange) { setIsChange(false); try { @@ -42,7 +46,11 @@ function BrowserV2({ ...props }) { setErrorDescription(error.stack); } } - }, [isChange]); + }; + + useEffect(handleEndInstallDependency, [dependencyInstalling]); + useEffect(handleParsingProject, [files]); + useEffect(handleBuildProject, [isChange]); return ( diff --git a/cocode/src/components/Project/BrowserV2/style.js b/cocode/src/components/Project/BrowserV2/style.js index 3622b2b6..aba5e626 100644 --- a/cocode/src/components/Project/BrowserV2/style.js +++ b/cocode/src/components/Project/BrowserV2/style.js @@ -8,7 +8,7 @@ const Frame = styled.div` const ErrorDisplay = styled.div` & { position: absolute; - z-index: 1; + z-index: ${({ errorDescription }) => (errorDescription ? 1 : -1)}; overflow-x: scroll; padding: 1rem; diff --git a/cocode/src/components/Project/Dependency/style.js b/cocode/src/components/Project/Dependency/style.js index 109877c3..4f90de17 100644 --- a/cocode/src/components/Project/Dependency/style.js +++ b/cocode/src/components/Project/Dependency/style.js @@ -2,17 +2,17 @@ import styled from 'styled-components'; import { TAB_CONTAINER_THEME } from 'constants/theme'; const Header = styled.header` - & { - display: flex; - align-items: center; - background-color: ${TAB_CONTAINER_THEME.tabContainerHeaderBGColor}; - } + & { + display: flex; + align-items: center; + background-color: ${TAB_CONTAINER_THEME.tabContainerHeaderBGColor}; + } `; const Title = styled.h1` & { - padding: 0.7rem 1rem; - + padding: 0.7rem 1rem; + color: ${TAB_CONTAINER_THEME.tabContainerTitleColor}; font-size: ${TAB_CONTAINER_THEME.tabContainerTitleSize}; font-weight: ${TAB_CONTAINER_THEME.tabContainerTitleWeight}; @@ -20,14 +20,10 @@ const Title = styled.h1` `; const Body = styled.div` - & { - display: ${({ toggle }) => toggle ? 'block' : 'none'}; - padding: 0.5rem 0; - } + & { + display: ${({ toggle }) => (toggle ? 'block' : 'none')}; + padding: 0; + } `; -export { - Header, - Title, - Body -}; \ No newline at end of file +export { Header, Title, Body }; diff --git a/cocode/src/components/Project/DependencySearch/index.js b/cocode/src/components/Project/DependencySearch/index.js index 5ec9ded7..3c03e4d9 100644 --- a/cocode/src/components/Project/DependencySearch/index.js +++ b/cocode/src/components/Project/DependencySearch/index.js @@ -1,20 +1,21 @@ import React, { useEffect, useRef, useState } from 'react'; import * as Styled from './style'; +import CoconutSpinner from 'components/Common/CoconutSpinner'; import DependencySearchItem from 'components/Project/DependencySearchItem'; import { KEY_CODE_ENTER } from 'constants/keyCode'; -import { getDenpendencyList } from 'apis/Project'; +import { getDenpendencyListAPICreator } from 'apis/Project'; import useFetch from 'hooks/useFetch'; function DependencySearch() { const searchInput = useRef(false); - const [{ data }, setRequest] = useFetch({}); + const [{ data, loading }, setRequest] = useFetch({}); const [dependencySearchList, setDependencySearchList] = useState([]); const handleSearchTypingEnd = () => { const name = searchInput.current.value; - setRequest(getDenpendencyList(name)); + setRequest(getDenpendencyListAPICreator(name)); }; const handleKeyDown = e => { @@ -28,23 +29,30 @@ function DependencySearch() { return (
- - {dependencySearchList.map( - ({ name, version, versions, github, npm }, index) => { - return ( - - ); - } - )} - + {loading && ( + + + + )} + {data && ( + + {dependencySearchList.map( + ({ name, version, versions, github, npm }, index) => { + return ( + + ); + } + )} + + )}
); } diff --git a/cocode/src/components/Project/DependencySearch/style.js b/cocode/src/components/Project/DependencySearch/style.js index 07fb29d4..8611a8d1 100644 --- a/cocode/src/components/Project/DependencySearch/style.js +++ b/cocode/src/components/Project/DependencySearch/style.js @@ -3,25 +3,28 @@ import { DEPENDENCY_TAB_THEME } from 'constants/theme'; const SearchBar = styled.input.attrs(() => ({ type: 'text', - placeholder: 'Search on enter npm dependency', + placeholder: 'Search on enter npm dependency' }))` - width: -webkit-fill-available; - margin: 0.5rem 1rem; - padding: 0.8rem; - background-color: ${DEPENDENCY_TAB_THEME.dependencyTabInputBGColor}; - font-size: 0.8rem; - color: white; + width: -webkit-fill-available; + margin: 0.5rem 1rem; + padding: 0.8rem; + background-color: ${DEPENDENCY_TAB_THEME.dependencyTabInputBGColor}; + font-size: 0.8rem; + color: white; +`; + +const SpinnerContainer = styled.div` + & > * { + margin: 1rem auto; + } `; const DependencySearchList = styled.ul` - & { - list-style: none; - overflow: scroll; - height: 50vh; - } + & { + list-style: none; + overflow: scroll; + height: 50vh; + } `; -export { - SearchBar, - DependencySearchList -}; +export { SearchBar, SpinnerContainer, DependencySearchList }; diff --git a/cocode/src/components/Project/DependencySearchItem/index.js b/cocode/src/components/Project/DependencySearchItem/index.js index 4396e7af..f073892d 100644 --- a/cocode/src/components/Project/DependencySearchItem/index.js +++ b/cocode/src/components/Project/DependencySearchItem/index.js @@ -9,12 +9,19 @@ import DependencySelector from 'components/Project/DependencySelector'; import { getModule } from 'apis/Dependency'; import useFetch from 'hooks/useFetch'; -import { installDependencyActionCreator } from 'actions/Project'; +// Constants +const MIN_WAIT_TIME = 1000; + +import { + installDependencyActionCreator, + waitingInstallDependencyActionCreator +} from 'actions/Project'; import { ProjectContext } from 'contexts'; function DependencySearchItem({ name, latestVersion, github, npm }) { const { project, dispatchProject } = useContext(ProjectContext); - const [{ data }, setRequest] = useFetch({}); + const [{ data, loading }, setRequest] = useFetch({}); + const handleFetchModule = () => { const moduleName = name; const moduleVersion = latestVersion; @@ -22,19 +29,33 @@ function DependencySearchItem({ name, latestVersion, github, npm }) { }; const { dependency } = project; - useEffect(() => { - if (data) { - Object.entries(data).forEach(([key, value]) => { - fileSystem[key] = value; - }); - dispatchProject( - installDependencyActionCreator({ - moduleName: name, - moduleVersion: latestVersion - }) + const successInstallDependency = dependency => { + Object.entries(dependency).forEach(([key, value]) => { + fileSystem[key] = value; + }); + dispatchProject( + installDependencyActionCreator({ + moduleName: name, + moduleVersion: latestVersion + }) + ); + }; + + const handleSuccesResponse = () => { + if (data) + setTimeout( + successInstallDependency.bind(undefined, data), + MIN_WAIT_TIME ); - } - }, [data]); + }; + + const handleStartInstall = () => { + if (!loading) return; + dispatchProject(waitingInstallDependencyActionCreator()); + }; + + useEffect(handleSuccesResponse, [data]); + useEffect(handleStartInstall, [loading]); return ( diff --git a/cocode/src/components/Project/Directory/index.js b/cocode/src/components/Project/Directory/index.js index e0be94ed..756e6b84 100644 --- a/cocode/src/components/Project/Directory/index.js +++ b/cocode/src/components/Project/Directory/index.js @@ -36,6 +36,15 @@ function isProtectedFile({ files, root, entry, fileId }) { return false; } +function isFileNotMoveable({ files, fileId, newParentId }) { + const fileName = files[fileId].name; + const childsOfNewParent = files[newParentId].child; + + return childsOfNewParent + .map(id => files[id].name) + .some(name => name === fileName); +} + function Directory({ id, childIds, @@ -93,7 +102,11 @@ function Directory({ const handleDragLeave = () => setIsFileInDropZone(false); const handleDrop = fileId => { setIsFileInDropZone(false); - if (fileId === id || isProtectedFile({ files, root, entry, fileId })) + if ( + fileId === id || + isProtectedFile({ files, root, entry, fileId }) || + isFileNotMoveable({ files, fileId, newParentId: id }) + ) return alert(WARNING_PREVENT_MOVE_NOTIFICATION); requestMoveFile(fileId); diff --git a/cocode/src/components/Project/File/index.js b/cocode/src/components/Project/File/index.js index 5063196f..2c05cb46 100644 --- a/cocode/src/components/Project/File/index.js +++ b/cocode/src/components/Project/File/index.js @@ -1,4 +1,4 @@ -import React, { useState, useRef, useEffect } from 'react'; +import React, { useState, useRef, useEffect, useContext } from 'react'; import { useParams } from 'react-router-dom'; import * as Styled from './style'; @@ -23,11 +23,21 @@ import { deleteFileAPICreator, updateFileAPICreator } from 'apis/File'; import { DELETE_FILE, UPDATE_FILE_NAME } from 'actions/types'; +import ProjectContext from 'contexts/ProjectContext'; + // Constants const ACCEPT_DELETE_NOTIFICATION = '이 파일을 지우시겠습니까?'; const WARNING_PREVENT_NOTIFICATION = '해당 파일은 이름을 변경하거나 삭제할 수 없습니다.'; +function isNotChangeableFileName({ files, changedName, parentId }) { + const childsOfParent = files[parentId].child; + + return childsOfParent + .map(id => files[id].name) + .some(name => name === changedName); +} + function File({ isDirectory, isProtectedFile, @@ -50,6 +60,10 @@ function File({ const nameEditReferenece = useRef(null); const [{ data, error }, setRequest] = useFetch({}); + const { + project: { files } + } = useContext(ProjectContext); + // Variables const successHandler = { [DELETE_FILE]: handleDeleteFile, @@ -73,10 +87,16 @@ function File({ const handleEditFileNameEnd = ({ currentTarget }) => { setToggleEdit(false); - nameEditReferenece.current.contentEditable = false; + currentTarget.contentEditable = false; const changedName = currentTarget.textContent; - const updateFileId = _id; + + if (isNotChangeableFileName({ files, parentId, changedName })) { + const originFileName = files[updateFileId].name; + currentTarget.textContent = originFileName; + return; + } + const updateFileAPI = updateFileAPICreator(projectId, updateFileId, { name: changedName }); diff --git a/cocode/src/containers/Project/DependencyTab/index.js b/cocode/src/containers/Project/DependencyTab/index.js index d22bddec..d027436c 100644 --- a/cocode/src/containers/Project/DependencyTab/index.js +++ b/cocode/src/containers/Project/DependencyTab/index.js @@ -1,22 +1,43 @@ -import React from 'react'; +import React, { useContext } from 'react'; +import * as Styled from './style'; +import CoconutSpinner from 'components/Common/CoconutSpinner'; import Dependency from 'components/Project/Dependency'; import DependencyNow from 'components/Project/DependencyNow'; import DependencySearch from 'components/Project/DependencySearch'; +import ProjectContext from 'contexts/ProjectContext'; + const TabTitleFirst = 'DEPENDENCIES'; const TabTitleSecond = 'SEARCH DEPENDENCY'; +function InstallingDisplay() { + return ( + + + + Please wait to install module... + + + ); +} + function DependencyTab() { + const { project } = useContext(ProjectContext); + const { dependencyInstalling } = project; + return ( - <> - - - - - - - + + {dependencyInstalling && } + + + + + + + + + ); } diff --git a/cocode/src/containers/Project/DependencyTab/style.js b/cocode/src/containers/Project/DependencyTab/style.js new file mode 100644 index 00000000..f036d895 --- /dev/null +++ b/cocode/src/containers/Project/DependencyTab/style.js @@ -0,0 +1,47 @@ +import styled from 'styled-components'; + +const Frame = styled.div` + & { + position: relative; + + height: 100%; + } + + & > * { + width: 100%; + } +`; + +const InstallingDisplay = styled.div` + & { + position: absolute; + z-index: 1; + + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + + height: 100%; + width: 100%; + + background-color: rgba(0, 0, 0, 0.7); + } +`; + +const InstallPhrase = styled.p` + & { + margin-top: 2rem; + + font-size: 1rem; + font-weight: lighter; + } +`; + +const DependencyArea = styled.div` + & { + position: absolute; + } +`; + +export { Frame, InstallingDisplay, InstallPhrase, DependencyArea }; diff --git a/cocode/src/containers/Project/Editor/index.js b/cocode/src/containers/Project/Editor/index.js index 5bf5d4d2..3c7a951c 100644 --- a/cocode/src/containers/Project/Editor/index.js +++ b/cocode/src/containers/Project/Editor/index.js @@ -12,7 +12,9 @@ import useFetch from 'hooks/useFetch'; import { updateFileAPICreator } from 'apis/File'; +// Constatnts let timer; +const DEBOUNCING_TIME = 1000; function Editor() { const { projectId } = useParams(); @@ -35,7 +37,10 @@ function Editor() { const handleUpdateCode = (_, changedCode) => { if (timer) clearTimeout(timer); - timer = setTimeout(debouncedHandlerUpdateCode(changedCode), 300); + timer = setTimeout( + debouncedHandlerUpdateCode(changedCode), + DEBOUNCING_TIME + ); }; const handleChangedSelectedFile = () => setCode(project.editingCode); diff --git a/cocode/src/containers/Project/TabBar/index.js b/cocode/src/containers/Project/TabBar/index.js index 25df6c0a..89865b00 100644 --- a/cocode/src/containers/Project/TabBar/index.js +++ b/cocode/src/containers/Project/TabBar/index.js @@ -16,22 +16,22 @@ function TabBar({ theme }) { const handleSetClickedIndex = index => setClickedTabIndex(index); const tabIcons = [ - { - name: 'info', - icon: Info, - }, + // { + // name: 'info', + // icon: Info, + // }, { name: 'explorer', - icon: Explorer, + icon: Explorer }, { name: 'dependency', - icon: Dependency, - }, - { - name: 'live', - icon: Live, + icon: Dependency } + // { + // name: 'live', + // icon: Live, + // } ]; return ( diff --git a/cocode/src/hooks/useFetch.js b/cocode/src/hooks/useFetch.js index f0b8418b..ad3522da 100644 --- a/cocode/src/hooks/useFetch.js +++ b/cocode/src/hooks/useFetch.js @@ -21,7 +21,7 @@ function useFetch({ method, url, data = {} }) { }); const requestToServer = () => { - dispatchFetchState(fetchLoadActionCreator); + dispatchFetchState(fetchLoadActionCreator()); API(request) .then(res => dispatchFetchState(fetchSuccessActionCreator(res))) .catch(error => dispatchFetchState(fetchFailActionCreator(error))); diff --git a/cocode/src/pages/Project/index.js b/cocode/src/pages/Project/index.js index 22e7ca85..8b7c0623 100644 --- a/cocode/src/pages/Project/index.js +++ b/cocode/src/pages/Project/index.js @@ -20,7 +20,7 @@ import useFetch from 'hooks/useFetch'; import reactTemplate from 'template/objectIdMapper'; import { getProjectInfoAPICreator, forkProjectAPICreator } from 'apis/Project'; -const DEFAULT_CLICKED_TAB_INDEX = 1; +const DEFAULT_CLICKED_TAB_INDEX = 0; function Project() { const { user } = useContext(UserContext); diff --git a/cocode/src/reducers/ProjectReducer.js b/cocode/src/reducers/ProjectReducer.js index 37b5119e..fc4f81d9 100644 --- a/cocode/src/reducers/ProjectReducer.js +++ b/cocode/src/reducers/ProjectReducer.js @@ -7,7 +7,8 @@ import { UPDATE_FILE_NAME, DELETE_FILE, MOVE_FILE, - INSTALL_DEPENDENCY + INSTALL_DEPENDENCY, + WAITING_INSTALL_DEPENDENCY } from 'actions/types'; import { getFileExtension } from 'utils'; @@ -40,7 +41,8 @@ const fetchProject = (_, { project }) => { files: convertedFilesObject, selectedFileId: entryId, editingCode: convertedFilesObject[entryId].contents, - dependency: {} + dependency: {}, + dependencyInstalling: false }; return fetchedProject; @@ -228,6 +230,16 @@ const moveFile = (state, { directoryId, fileId }) => { }; }; +function waitingInstallDependency(state) { + return { + ...state, + dependency: { + ...state.dependency + }, + dependencyInstalling: true + }; +} + function registerDependency(state, { moduleName, moduleVersion }) { return { ...state, @@ -237,7 +249,8 @@ function registerDependency(state, { moduleName, moduleVersion }) { name: moduleName, version: moduleVersion } - } + }, + dependencyInstalling: false }; } @@ -250,7 +263,8 @@ function ProjectReducer(state, { type, payload }) { [CREATE_FILE]: createFile, [DELETE_FILE]: deleteFile, [MOVE_FILE]: moveFile, - [INSTALL_DEPENDENCY]: registerDependency + [INSTALL_DEPENDENCY]: registerDependency, + [WAITING_INSTALL_DEPENDENCY]: waitingInstallDependency }; const reducer = reducers[type]; diff --git a/cocode/src/template/react.js b/cocode/src/template/react.js index 297b7db4..17fb47c9 100644 --- a/cocode/src/template/react.js +++ b/cocode/src/template/react.js @@ -89,7 +89,11 @@ const template = { ' "browserslist": [">0.2%", "not dead", "not ie <= 11", "not op_mini all"]\n' + '}\n', version1: - 'const { useState } = React;\n' + + '// react, react-dom 라이브러리를 좌측 탭에서 설치해주세여.\n' + + '// 원하시는 라이브러리를 입력하고 enter를 누르시면 검색됩니다.\n' + + '// + 버튼을 누르면 dependency가 설치됩니다!\n' + + 'import React, { useState } from "react";\n' + + 'import ReactDOM from "react-dom";\n' + '\n' + 'function App() {\n' + ' const [state, setState] = useState("Cocode");\n' + diff --git a/env.tar.enc b/env.tar.enc new file mode 100644 index 00000000..460c911c Binary files /dev/null and b/env.tar.enc differ