1
1
import PropTypes from 'prop-types' ;
2
2
import classNames from 'classnames' ;
3
3
import React , { useState , useRef } from 'react' ;
4
- import { useDispatch , useSelector } from 'react-redux' ;
4
+ import { connect } from 'react-redux' ;
5
5
import { useTranslation } from 'react-i18next' ;
6
6
7
7
import * as IDEActions from '../actions/ide' ;
8
8
import * as FileActions from '../actions/files' ;
9
- import parseFileName from '../utils/parseFileName' ;
10
9
import DownArrowIcon from '../../../images/down-filled-triangle.svg' ;
11
10
import FolderRightIcon from '../../../images/triangle-arrow-right.svg' ;
12
11
import FolderDownIcon from '../../../images/triangle-arrow-down.svg' ;
13
12
import FileTypeIcon from './FileTypeIcon' ;
14
13
14
+ function parseFileName ( name ) {
15
+ const nameArray = name . split ( '.' ) ;
16
+ if ( nameArray . length > 1 ) {
17
+ const extension = `.${ nameArray [ nameArray . length - 1 ] } ` ;
18
+ const baseName = nameArray . slice ( 0 , - 1 ) . join ( '.' ) ;
19
+ const firstLetter = baseName [ 0 ] ;
20
+ const lastLetter = baseName [ baseName . length - 1 ] ;
21
+ const middleText = baseName . slice ( 1 , - 1 ) ;
22
+ return {
23
+ baseName,
24
+ firstLetter,
25
+ lastLetter,
26
+ middleText,
27
+ extension
28
+ } ;
29
+ }
30
+ const firstLetter = name [ 0 ] ;
31
+ const lastLetter = name [ name . length - 1 ] ;
32
+ const middleText = name . slice ( 1 , - 1 ) ;
33
+ return {
34
+ baseName : name ,
35
+ firstLetter,
36
+ lastLetter,
37
+ middleText
38
+ } ;
39
+ }
40
+
15
41
function FileName ( { name } ) {
16
42
const {
17
43
baseName,
@@ -36,35 +62,40 @@ FileName.propTypes = {
36
62
name : PropTypes . string . isRequired
37
63
} ;
38
64
39
- const FileNode = ( { id, canEdit, onClickFile } ) => {
40
- const dispatch = useDispatch ( ) ;
41
- const { t } = useTranslation ( ) ;
42
-
43
- const fileNode =
44
- useSelector ( ( state ) => state . files . find ( ( file ) => file . id === id ) ) || { } ;
45
- const authenticated = useSelector ( ( state ) => state . user . authenticated ) ;
46
-
47
- const {
48
- name = '' ,
49
- parentId = null ,
50
- children = [ ] ,
51
- fileType = 'file' ,
52
- isSelectedFile = false ,
53
- isFolderClosed = false
54
- } = fileNode ;
55
-
65
+ const FileNode = ( {
66
+ id,
67
+ parentId,
68
+ children,
69
+ name,
70
+ fileType,
71
+ isSelectedFile,
72
+ isFolderClosed,
73
+ setSelectedFile,
74
+ deleteFile,
75
+ updateFileName,
76
+ resetSelectedFile,
77
+ newFile,
78
+ newFolder,
79
+ showFolderChildren,
80
+ hideFolderChildren,
81
+ canEdit,
82
+ openUploadFileModal,
83
+ authenticated,
84
+ onClickFile
85
+ } ) => {
56
86
const [ isOptionsOpen , setIsOptionsOpen ] = useState ( false ) ;
57
87
const [ isEditingName , setIsEditingName ] = useState ( false ) ;
58
88
const [ isDeleting , setIsDeleting ] = useState ( false ) ;
59
89
const [ updatedName , setUpdatedName ] = useState ( name ) ;
60
90
91
+ const { t } = useTranslation ( ) ;
61
92
const fileNameInput = useRef ( null ) ;
62
93
const fileOptionsRef = useRef ( null ) ;
63
94
64
95
const handleFileClick = ( event ) => {
65
96
event . stopPropagation ( ) ;
66
97
if ( name !== 'root' && ! isDeleting ) {
67
- dispatch ( IDEActions . setSelectedFile ( id ) ) ;
98
+ setSelectedFile ( id ) ;
68
99
}
69
100
if ( onClickFile ) {
70
101
onClickFile ( ) ;
@@ -91,17 +122,17 @@ const FileNode = ({ id, canEdit, onClickFile }) => {
91
122
} ;
92
123
93
124
const handleClickAddFile = ( ) => {
94
- dispatch ( IDEActions . newFile ( id ) ) ;
125
+ newFile ( id ) ;
95
126
setTimeout ( ( ) => hideFileOptions ( ) , 0 ) ;
96
127
} ;
97
128
98
129
const handleClickAddFolder = ( ) => {
99
- dispatch ( IDEActions . newFolder ( id ) ) ;
130
+ newFolder ( id ) ;
100
131
setTimeout ( ( ) => hideFileOptions ( ) , 0 ) ;
101
132
} ;
102
133
103
134
const handleClickUploadFile = ( ) => {
104
- dispatch ( IDEActions . openUploadFileModal ( id ) ) ;
135
+ openUploadFileModal ( id ) ;
105
136
setTimeout ( hideFileOptions , 0 ) ;
106
137
} ;
107
138
@@ -110,8 +141,8 @@ const FileNode = ({ id, canEdit, onClickFile }) => {
110
141
111
142
if ( window . confirm ( prompt ) ) {
112
143
setIsDeleting ( true ) ;
113
- dispatch ( IDEActions . resetSelectedFile ( id ) ) ;
114
- setTimeout ( ( ) => dispatch ( FileActions . deleteFile ( id , parentId ) , 100 ) ) ;
144
+ resetSelectedFile ( id ) ;
145
+ setTimeout ( ( ) => deleteFile ( id , parentId ) , 100 ) ;
115
146
}
116
147
} ;
117
148
@@ -127,7 +158,7 @@ const FileNode = ({ id, canEdit, onClickFile }) => {
127
158
128
159
const saveUpdatedFileName = ( ) => {
129
160
if ( updatedName !== name ) {
130
- dispatch ( FileActions . updateFileName ( id , updatedName ) ) ;
161
+ updateFileName ( id , updatedName ) ;
131
162
}
132
163
} ;
133
164
@@ -212,7 +243,7 @@ const FileNode = ({ id, canEdit, onClickFile }) => {
212
243
< div className = "sidebar__file-item--folder" >
213
244
< button
214
245
className = "sidebar__file-item-closed"
215
- onClick = { ( ) => dispatch ( FileActions . showFolderChildren ( id ) ) }
246
+ onClick = { ( ) => showFolderChildren ( id ) }
216
247
aria-label = { t ( 'FileNode.OpenFolderARIA' ) }
217
248
title = { t ( 'FileNode.OpenFolderARIA' ) }
218
249
>
@@ -224,7 +255,7 @@ const FileNode = ({ id, canEdit, onClickFile }) => {
224
255
</ button >
225
256
< button
226
257
className = "sidebar__file-item-open"
227
- onClick = { ( ) => dispatch ( FileActions . hideFolderChildren ( id ) ) }
258
+ onClick = { ( ) => hideFolderChildren ( id ) }
228
259
aria-label = { t ( 'FileNode.CloseFolderARIA' ) }
229
260
title = { t ( 'FileNode.CloseFolderARIA' ) }
230
261
>
@@ -322,7 +353,7 @@ const FileNode = ({ id, canEdit, onClickFile }) => {
322
353
< ul className = "file-item__children" >
323
354
{ children . map ( ( childId ) => (
324
355
< li key = { childId } >
325
- < FileNode
356
+ < ConnectedFileNode
326
357
id = { childId }
327
358
parentId = { id }
328
359
canEdit = { canEdit }
@@ -338,12 +369,50 @@ const FileNode = ({ id, canEdit, onClickFile }) => {
338
369
339
370
FileNode . propTypes = {
340
371
id : PropTypes . string . isRequired ,
372
+ parentId : PropTypes . string ,
373
+ children : PropTypes . arrayOf ( PropTypes . string . isRequired ) . isRequired ,
374
+ name : PropTypes . string . isRequired ,
375
+ fileType : PropTypes . string . isRequired ,
376
+ isSelectedFile : PropTypes . bool ,
377
+ isFolderClosed : PropTypes . bool ,
378
+ setSelectedFile : PropTypes . func . isRequired ,
379
+ deleteFile : PropTypes . func . isRequired ,
380
+ updateFileName : PropTypes . func . isRequired ,
381
+ resetSelectedFile : PropTypes . func . isRequired ,
382
+ newFile : PropTypes . func . isRequired ,
383
+ newFolder : PropTypes . func . isRequired ,
384
+ showFolderChildren : PropTypes . func . isRequired ,
385
+ hideFolderChildren : PropTypes . func . isRequired ,
341
386
canEdit : PropTypes . bool . isRequired ,
387
+ openUploadFileModal : PropTypes . func . isRequired ,
388
+ authenticated : PropTypes . bool . isRequired ,
342
389
onClickFile : PropTypes . func
343
390
} ;
344
391
345
392
FileNode . defaultProps = {
346
- onClickFile : null
393
+ onClickFile : null ,
394
+ parentId : '0' ,
395
+ isSelectedFile : false ,
396
+ isFolderClosed : false
347
397
} ;
348
398
349
- export default FileNode ;
399
+ function mapStateToProps ( state , ownProps ) {
400
+ // this is a hack, state is updated before ownProps
401
+ const fileNode = state . files . find ( ( file ) => file . id === ownProps . id ) || {
402
+ name : 'test' ,
403
+ fileType : 'file'
404
+ } ;
405
+ return Object . assign ( { } , fileNode , {
406
+ authenticated : state . user . authenticated
407
+ } ) ;
408
+ }
409
+
410
+ const mapDispatchToProps = { ...FileActions , ...IDEActions } ;
411
+
412
+ const ConnectedFileNode = connect (
413
+ mapStateToProps ,
414
+ mapDispatchToProps
415
+ ) ( FileNode ) ;
416
+
417
+ export { FileNode } ;
418
+ export default ConnectedFileNode ;
0 commit comments