Browse Source

switched Timeline into a statefull component + added handling for wysiwyg

Skylsmoi 5 years ago
parent
commit
65269e5912

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

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

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

@@ -0,0 +1,26 @@
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

@@ -0,0 +1,17 @@
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,116 +1,102 @@
1 1
 import React from 'react'
2 2
 import PropTypes from 'prop-types'
3 3
 import classnames from 'classnames'
4
+import Comment from './Comment.jsx'
5
+import Revision from './Revision.jsx'
4 6
 
5 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 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 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 95
           </div>
109
-
110
-        </div>
111
-      </form>
112
-    </div>
113
-  )
96
+        </form>
97
+      </div>
98
+    )
99
+  }
114 100
 }
115 101
 
116 102
 export default Timeline
@@ -121,7 +107,9 @@ Timeline.propTypes = {
121 107
   onChangeNewComment: PropTypes.func.isRequired,
122 108
   onClickValidateNewCommentBtn: PropTypes.func.isRequired,
123 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 115
 Timeline.defaultProps = {
@@ -131,5 +119,7 @@ Timeline.defaultProps = {
131 119
     name: '',
132 120
     avatar: ''
133 121
   },
134
-  timelineData: []
122
+  timelineData: [],
123
+  wysiwyg: false,
124
+  onClickWysiwygBtn: () => {}
135 125
 }