file-tree-mutable.js 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. import React, {
  2. createContext,
  3. useCallback,
  4. useReducer,
  5. useContext
  6. } from 'react'
  7. import PropTypes from 'prop-types'
  8. import {
  9. renameInTree,
  10. deleteInTree,
  11. moveInTree,
  12. createEntityInTree
  13. } from '../util/mutate-in-tree'
  14. const FileTreeMutableContext = createContext()
  15. const ACTION_TYPES = {
  16. RENAME: 'RENAME',
  17. DELETE: 'DELETE',
  18. MOVE: 'MOVE',
  19. CREATE_ENTITY: 'CREATE_ENTITY'
  20. }
  21. function fileTreeMutableReducer({ fileTreeData }, action) {
  22. switch (action.type) {
  23. case ACTION_TYPES.RENAME:
  24. return {
  25. fileTreeData: renameInTree(fileTreeData, action.id, {
  26. newName: action.newName
  27. })
  28. }
  29. case ACTION_TYPES.DELETE:
  30. return {
  31. fileTreeData: deleteInTree(fileTreeData, action.id)
  32. }
  33. case ACTION_TYPES.MOVE:
  34. return {
  35. fileTreeData: moveInTree(
  36. fileTreeData,
  37. action.entityId,
  38. action.toFolderId
  39. )
  40. }
  41. case ACTION_TYPES.CREATE_ENTITY:
  42. return {
  43. fileTreeData: createEntityInTree(
  44. fileTreeData,
  45. action.parentFolderId,
  46. action.entity
  47. )
  48. }
  49. default:
  50. throw new Error(`Unknown mutable file tree action type: ${action.type}`)
  51. }
  52. }
  53. export const FileTreeMutableProvider = function({ rootFolder, children }) {
  54. const [{ fileTreeData }, dispatch] = useReducer(fileTreeMutableReducer, {
  55. fileTreeData: rootFolder[0]
  56. })
  57. return (
  58. <FileTreeMutableContext.Provider value={{ fileTreeData, dispatch }}>
  59. {children}
  60. </FileTreeMutableContext.Provider>
  61. )
  62. }
  63. FileTreeMutableProvider.propTypes = {
  64. rootFolder: PropTypes.array.isRequired,
  65. children: PropTypes.oneOfType([
  66. PropTypes.arrayOf(PropTypes.node),
  67. PropTypes.node
  68. ]).isRequired
  69. }
  70. export function useFileTreeMutable() {
  71. const { fileTreeData, dispatch } = useContext(FileTreeMutableContext)
  72. const dispatchCreateFolder = useCallback(
  73. (parentFolderId, entity) => {
  74. entity.type = 'folder'
  75. dispatch({
  76. type: ACTION_TYPES.CREATE_ENTITY,
  77. parentFolderId,
  78. entity
  79. })
  80. },
  81. [dispatch]
  82. )
  83. const dispatchCreateDoc = useCallback(
  84. (parentFolderId, entity) => {
  85. entity.type = 'doc'
  86. dispatch({
  87. type: ACTION_TYPES.CREATE_ENTITY,
  88. parentFolderId,
  89. entity
  90. })
  91. },
  92. [dispatch]
  93. )
  94. const dispatchCreateFile = useCallback(
  95. (parentFolderId, entity) => {
  96. entity.type = 'fileRef'
  97. dispatch({
  98. type: ACTION_TYPES.CREATE_ENTITY,
  99. parentFolderId,
  100. entity
  101. })
  102. },
  103. [dispatch]
  104. )
  105. const dispatchRename = useCallback(
  106. (id, newName) => {
  107. dispatch({
  108. type: ACTION_TYPES.RENAME,
  109. newName,
  110. id
  111. })
  112. },
  113. [dispatch]
  114. )
  115. const dispatchDelete = useCallback(
  116. id => {
  117. dispatch({ type: ACTION_TYPES.DELETE, id })
  118. },
  119. [dispatch]
  120. )
  121. const dispatchMove = useCallback(
  122. (entityId, toFolderId) => {
  123. dispatch({ type: ACTION_TYPES.MOVE, entityId, toFolderId })
  124. },
  125. [dispatch]
  126. )
  127. return {
  128. fileTreeData,
  129. dispatchRename,
  130. dispatchDelete,
  131. dispatchMove,
  132. dispatchCreateFolder,
  133. dispatchCreateDoc,
  134. dispatchCreateFile
  135. }
  136. }