Browse Source

switched Timeline into a statefull component + added handling for wysiwyg

Skylsmoi 6 years ago
parent
commit
65269e5912

+ 3 - 1
src/component/Input/TextAreaApp/TextAreaApp.jsx View File

6
 export const TextAreaApp = props =>
6
 export const TextAreaApp = props =>
7
   <form className={`${props.customClass} editionmode`}>
7
   <form className={`${props.customClass} editionmode`}>
8
     <textarea
8
     <textarea
9
-      className={`${props.customClass}__text editionmode__text wysiwygtext`}
9
+      id={props.id}
10
+      className={`${props.customClass}__text editionmode__text`}
10
       value={props.text}
11
       value={props.text}
11
       onChange={props.onChangeText}
12
       onChange={props.onChangeText}
12
     />
13
     />
37
   onChangeText: PropTypes.func.isRequired,
38
   onChangeText: PropTypes.func.isRequired,
38
   onClickCancelBtn: PropTypes.func.isRequired,
39
   onClickCancelBtn: PropTypes.func.isRequired,
39
   onClickValidateBtn: PropTypes.func.isRequired,
40
   onClickValidateBtn: PropTypes.func.isRequired,
41
+  id: PropTypes.string,
40
   customClass: PropTypes.string
42
   customClass: PropTypes.string
41
 }
43
 }

+ 26 - 0
src/component/Timeline/Comment.jsx View File

1
+import React from 'react'
2
+import classnames from 'classnames'
3
+
4
+const Comment = props => (
5
+  <li className={classnames(
6
+    `${props.customClass}__messagelist__item`,
7
+    'timeline__messagelist__item', {
8
+      'sended': props.fromMe,
9
+      'received': !props.fromMe
10
+    }
11
+  )}>
12
+    <div className={classnames(`${props.customClass}__messagelist__item__avatar`, 'timeline__messagelist__item__avatar')}>
13
+      {props.avatar ? <img src={props.avatar} /> : ''}
14
+    </div>
15
+    <div
16
+      className={classnames(`${props.customClass}__messagelist__item__createhour`, 'timeline__messagelist__item__createhour')}>
17
+      {props.createdAt}
18
+    </div>
19
+    <div
20
+      className={classnames(`${props.customClass}__messagelist__item__content`, 'timeline__messagelist__item__content')}
21
+      dangerouslySetInnerHTML={{__html: props.text}}
22
+    />
23
+  </li>
24
+)
25
+
26
+export default Comment

+ 17 - 0
src/component/Timeline/Revision.jsx View File

1
+import React from 'react'
2
+import classnames from 'classnames'
3
+
4
+const Revision = props => (
5
+  <li className={classnames(`${props.customClass}__messagelist__version`, 'timeline__messagelist__version')} >
6
+    <div className={classnames(`${props.customClass}__messagelist__version__btn`, 'timeline__messagelist__version__btn btn')}>
7
+      <i className='fa fa-code-fork' />
8
+      version {props.number}
9
+    </div>
10
+
11
+    <div className={classnames(`${props.customClass}__messagelist__version__date`, 'timeline__messagelist__version__date')}>
12
+      Créer le {props.createdAt}
13
+    </div>
14
+  </li>
15
+)
16
+
17
+export default Revision

+ 88 - 98
src/component/Timeline/Timeline.jsx View File

1
 import React from 'react'
1
 import React from 'react'
2
 import PropTypes from 'prop-types'
2
 import PropTypes from 'prop-types'
3
 import classnames from 'classnames'
3
 import classnames from 'classnames'
4
+import Comment from './Comment.jsx'
5
+import Revision from './Revision.jsx'
4
 
6
 
5
 require('./Timeline.styl')
7
 require('./Timeline.styl')
6
 
8
 
7
-const Comment = props => (
8
-  <li
9
-    className={classnames(
10
-      `${props.customClass}__messagelist__item`,
11
-      'timeline__messagelist__item', {
12
-        'sended': props.fromMe,
13
-        'received': !props.fromMe
14
-      }
15
-    )}
16
-  >
17
-    <div className={classnames(`${props.customClass}__messagelist__item__avatar`, 'timeline__messagelist__item__avatar')}>
18
-      {props.avatar ? <img src={props.avatar} /> : ''}
19
-    </div>
20
-    <div
21
-      className={classnames(`${props.customClass}__messagelist__item__createhour`, 'timeline__messagelist__item__createhour')}>
22
-      {props.createdAt}
23
-    </div>
24
-    <div
25
-      className={classnames(`${props.customClass}__messagelist__item__content`, 'timeline__messagelist__item__content')}>
26
-      {props.text}
27
-    </div>
28
-  </li>
29
-)
30
-
31
-const Revision = props => (
32
-  <li className={classnames(`${props.customClass}__messagelist__version`, 'timeline__messagelist__version')} >
33
-    <div className={classnames(`${props.customClass}__messagelist__version__btn`, 'timeline__messagelist__version__btn btn')}>
34
-      <i className='fa fa-code-fork' />
35
-      version {props.number}
36
-    </div>
37
-    <div className={classnames(`${props.customClass}__messagelist__version__date`, 'timeline__messagelist__version__date')}>
38
-      Créer le {props.createdAt}
39
-    </div>
40
-  </li>
41
-)
42
-
43
-const Timeline = props => {
44
-  if (!Array.isArray(props.timelineData)) {
45
-    console.log('Error in Timeline.jsx, props.timelineData is not an array. timelineData: ', props.timelineData)
46
-    return null
9
+class Timeline extends React.Component {
10
+  componentDidMount () {
11
+    this.scrollToBottom()
47
   }
12
   }
48
 
13
 
49
-  return (
50
-    <div className='timeline'>
51
-      <div className={classnames(`${props.customClass}__header`, 'timeline__header')}>
52
-        Timeline
53
-      </div>
14
+  componentDidUpdate () {
15
+    this.scrollToBottom()
16
+  }
54
 
17
 
55
-      <ul className={classnames(`${props.customClass}__messagelist`, 'timeline__messagelist')}>
56
-        { props.timelineData.map(content => {
57
-          switch (content.timelineType) {
58
-            case 'comment':
59
-              return <Comment
60
-                customClass={props.customClass}
61
-                avatar={content.author.avatar_url}
62
-                createdAt={content.created}
63
-                text={content.raw_content}
64
-                fromMe={props.loggedUser.user_id === content.author.user_id}
65
-                key={`comment_${content.content_id}`}
66
-              />
18
+  scrollToBottom = () => this.timelineBottom.scrollIntoView({behavior: 'instant'})
67
 
19
 
68
-            case 'revision':
69
-              return <Revision
70
-                customClass={props.customClass}
71
-                createdAt={content.created}
72
-                number={props.timelineData.filter(c => c.timelineType === 'revision' && c.revision_id <= content.revision_id).length}
73
-                key={`revision_${content.revision_id}`}
74
-              />
75
-          }
76
-        })}
77
-      </ul>
20
+  render () {
21
+    const { props } = this
78
 
22
 
79
-      <form className={classnames(`${props.customClass}__texteditor`, 'timeline__texteditor d-flex align-items-center justify-content-between flex-wrap')}>
23
+    if (!Array.isArray(props.timelineData)) {
24
+      console.log('Error in Timeline.jsx, props.timelineData is not an array. timelineData: ', props.timelineData)
25
+      return null
26
+    }
80
 
27
 
81
-        <div className={classnames(`${props.customClass}__texteditor__textinput`, 'timeline__texteditor__textinput')}>
82
-          <textarea
83
-            placeholder='Taper votre message ici'
84
-            value={props.newComment}
85
-            onChange={props.onChangeNewComment}
86
-          />
28
+    return (
29
+      <div className='timeline'>
30
+        <div className={classnames(`${props.customClass}__header`, 'timeline__header')}>
31
+          Timeline
87
         </div>
32
         </div>
88
 
33
 
89
-        <div className={classnames(`${props.customClass}__texteditor__wrapper`, 'timeline__texteditor__wrapper')}>
90
-
91
-          <div className={classnames(`${props.customClass}__texteditor__advancedtext`, 'timeline__texteditor__advancedtext')}>
92
-            <button type='button' className={classnames(`${props.customClass}__texteditor__advancedtext__btn`, 'timeline__texteditor__advancedtext__btn btn btn-outline-primary')}>
93
-              Texte Avancé
94
-            </button>
34
+        <ul className={classnames(`${props.customClass}__messagelist`, 'timeline__messagelist')}>
35
+          {props.timelineData.map(content => {
36
+            switch (content.timelineType) {
37
+              case 'comment':
38
+                return <Comment
39
+                  customClass={props.customClass}
40
+                  avatar={content.author.avatar_url}
41
+                  createdAt={content.created}
42
+                  text={content.raw_content}
43
+                  fromMe={props.loggedUser.user_id === content.author.user_id}
44
+                  key={`comment_${content.content_id}`}
45
+                />
46
+
47
+              case 'revision':
48
+                return <Revision
49
+                  customClass={props.customClass}
50
+                  createdAt={content.created}
51
+                  number={props.timelineData.filter(c => c.timelineType === 'revision' && c.revision_id <= content.revision_id).length}
52
+                  key={`revision_${content.revision_id}`}
53
+                />
54
+            }
55
+          })}
56
+          <li style={{visibility: 'hidden'}} ref={el => { this.timelineBottom = el }} />
57
+        </ul>
58
+
59
+        <form className={classnames(`${props.customClass}__texteditor`, 'timeline__texteditor d-flex align-items-center justify-content-between flex-wrap')}>
60
+          <div className={classnames(`${props.customClass}__texteditor__textinput`, 'timeline__texteditor__textinput')}>
61
+            <textarea
62
+              id='wysiwygTimelineComment'
63
+              placeholder='Taper votre message ici'
64
+              value={props.newComment}
65
+              onChange={props.onChangeNewComment}
66
+            />
95
           </div>
67
           </div>
96
 
68
 
97
-          <div className={classnames(`${props.customClass}__texteditor__submit`, 'timeline__texteditor__submit mb-2')}>
98
-            <button
99
-              type='button'
100
-              className={classnames(`${props.customClass}__texteditor__submit__btn`, 'timeline__texteditor__submit__btn btn')}
101
-              onClick={props.onClickValidateNewCommentBtn}
102
-            >
103
-              Envoyer
104
-              <div className={classnames(`${props.customClass}__texteditor__submit__btn__icon`, 'timeline__texteditor__submit__btn__icon')}>
105
-                <i className='fa fa-paper-plane-o' />
106
-              </div>
107
-            </button>
69
+          <div className={classnames(`${props.customClass}__texteditor__wrapper`, 'timeline__texteditor__wrapper')}>
70
+            <div className={classnames(`${props.customClass}__texteditor__advancedtext`, 'timeline__texteditor__advancedtext')}>
71
+              <button
72
+                type='button'
73
+                className={classnames(
74
+                  `${props.customClass}__texteditor__advancedtext__btn timeline__texteditor__advancedtext__btn btn btn-outline-primary`
75
+                )}
76
+                onClick={props.onClickWysiwygBtn}
77
+              >
78
+                {props.wysiwyg ? 'Text Simple' : 'Texte Avancé'}
79
+              </button>
80
+            </div>
81
+
82
+            <div className={classnames(`${props.customClass}__texteditor__submit`, 'timeline__texteditor__submit mb-2')}>
83
+              <button
84
+                type='button'
85
+                className={classnames(`${props.customClass}__texteditor__submit__btn`, 'timeline__texteditor__submit__btn btn')}
86
+                onClick={props.onClickValidateNewCommentBtn}
87
+              >
88
+                Envoyer
89
+                <div
90
+                  className={classnames(`${props.customClass}__texteditor__submit__btn__icon`, 'timeline__texteditor__submit__btn__icon')}>
91
+                  <i className='fa fa-paper-plane-o' />
92
+                </div>
93
+              </button>
94
+            </div>
108
           </div>
95
           </div>
109
-
110
-        </div>
111
-      </form>
112
-    </div>
113
-  )
96
+        </form>
97
+      </div>
98
+    )
99
+  }
114
 }
100
 }
115
 
101
 
116
 export default Timeline
102
 export default Timeline
121
   onChangeNewComment: PropTypes.func.isRequired,
107
   onChangeNewComment: PropTypes.func.isRequired,
122
   onClickValidateNewCommentBtn: PropTypes.func.isRequired,
108
   onClickValidateNewCommentBtn: PropTypes.func.isRequired,
123
   customClass: PropTypes.string,
109
   customClass: PropTypes.string,
124
-  loggedUser: PropTypes.object
110
+  loggedUser: PropTypes.object,
111
+  wysiwyg: PropTypes.bool,
112
+  onClickWysiwygBtn: PropTypes.func
125
 }
113
 }
126
 
114
 
127
 Timeline.defaultProps = {
115
 Timeline.defaultProps = {
131
     name: '',
119
     name: '',
132
     avatar: ''
120
     avatar: ''
133
   },
121
   },
134
-  timelineData: []
122
+  timelineData: [],
123
+  wysiwyg: false,
124
+  onClickWysiwygBtn: () => {}
135
 }
125
 }