Browse Source

[wip] workspace dashboard

Skylsmoi 5 years ago
parent
commit
de3199dbf1

+ 0 - 1
frontend/dist/index.html View File

@@ -36,7 +36,6 @@
36 36
       .primaryColorBorder { border-color: #7d4e24; }
37 37
       .primaryColorBorderDarken { border-color: #572800; }
38 38
       .primaryColorBorderLighten { border-color: #a3744a; }
39
-      .whiteColorBorder { border-color: #fdfdfd; }
40 39
 
41 40
       .primaryColorBorderHover:hover { border-color: #7d4e24; }
42 41
       .primaryColorBorderDarkenHover:hover { border-color: #572800; }

+ 34 - 16
frontend/src/action-creator.async.js View File

@@ -2,8 +2,6 @@ import { FETCH_CONFIG } from './helper.js'
2 2
 import {
3 3
   TIMEZONE,
4 4
   setTimezone,
5
-  LANG,
6
-  updateLangList,
7 5
   USER_LOGIN,
8 6
   USER_LOGOUT,
9 7
   USER_ROLE,
@@ -16,7 +14,9 @@ import {
16 14
   FOLDER,
17 15
   setFolderData,
18 16
   APP_LIST,
19
-  CONTENT_TYPE_LIST
17
+  CONTENT_TYPE_LIST,
18
+  WORKSPACE_RECENT_ACTIVITY,
19
+  WORKSPACE_READ_STATUS
20 20
 } from './action-creator.sync.js'
21 21
 
22 22
 /*
@@ -36,6 +36,7 @@ import {
36 36
  * This function create a http async request using whatwg-fetch while dispatching a PENDING and a SUCCESS redux action.
37 37
  * It also adds, to the Response of the fetch request, the json value so that the redux action have access to the status and the data
38 38
  */
39
+// Côme - 2018/08/02 - fetchWrapper should come from tracim_lib so that all apps uses the same
39 40
 const fetchWrapper = async ({url, param, actionName, dispatch, debug = false}) => {
40 41
   dispatch({type: `${param.method}/${actionName}/PENDING`})
41 42
 
@@ -77,19 +78,6 @@ const fetchWrapper = async ({url, param, actionName, dispatch, debug = false}) =
77 78
   return fetchResult
78 79
 }
79 80
 
80
-export const getLangList = () => async dispatch => {
81
-  const fetchGetLangList = await fetchWrapper({
82
-    url: `${FETCH_CONFIG.apiUrl}/lang`,
83
-    param: {
84
-      headers: {...FETCH_CONFIG.headers},
85
-      method: 'GET'
86
-    },
87
-    actionName: LANG,
88
-    dispatch
89
-  })
90
-  if (fetchGetLangList.status === 200) dispatch(updateLangList(fetchGetLangList.json))
91
-}
92
-
93 81
 export const getTimezone = () => async dispatch => {
94 82
   const fetchGetTimezone = await fetchWrapper({
95 83
     url: `${FETCH_CONFIG.apiUrl}/timezone`,
@@ -220,6 +208,36 @@ export const getWorkspaceContentList = (user, idWorkspace, idParent) => dispatch
220 208
   })
221 209
 }
222 210
 
211
+export const getWorkspaceRecentActivityList = (user, idWorkspace) => dispatch => {
212
+  return fetchWrapper({
213
+    url: `${FETCH_CONFIG.apiUrl}/users/${user.user_id}/workspaces/${idWorkspace}/contents/recently_active?limit=10`,
214
+    param: {
215
+      headers: {
216
+        ...FETCH_CONFIG.headers,
217
+        'Authorization': 'Basic ' + user.auth
218
+      },
219
+      method: 'GET'
220
+    },
221
+    actionName: WORKSPACE_RECENT_ACTIVITY,
222
+    dispatch
223
+  })
224
+}
225
+
226
+export const getWorkspaceReadStatusList = (user, idWorkspace) => dispatch => {
227
+  return fetchWrapper({
228
+    url: `${FETCH_CONFIG.apiUrl}/users/${user.user_id}/workspaces/${idWorkspace}/contents/read_status`,
229
+    param: {
230
+      headers: {
231
+        ...FETCH_CONFIG.headers,
232
+        'Authorization': 'Basic ' + user.auth
233
+      },
234
+      method: 'GET'
235
+    },
236
+    actionName: WORKSPACE_READ_STATUS,
237
+    dispatch
238
+  })
239
+}
240
+
223 241
 export const getFolderContent = (idWorkspace, idFolder) => async dispatch => {
224 242
   const fetchGetFolderContent = await fetchWrapper({
225 243
     url: `${FETCH_CONFIG.apiUrl}/workspaces/${idWorkspace}/contents/?parent_id=${idFolder}`,

+ 9 - 1
frontend/src/action-creator.sync.js View File

@@ -32,7 +32,7 @@ export const updateUserWorkspaceSubscriptionNotif = (workspaceId, subscriptionNo
32 32
 
33 33
 export const WORKSPACE = 'Workspace'
34 34
 export const WORKSPACE_CONTENT = `${WORKSPACE}/Content`
35
-export const setWorkspaceContentList = (workspaceContentList, filterStr = '') => ({ type: `${SET}/${WORKSPACE_CONTENT}`, workspaceContentList, filterStr })
35
+export const setWorkspaceContentList = workspaceContentList => ({ type: `${SET}/${WORKSPACE_CONTENT}`, workspaceContentList })
36 36
 export const updateWorkspaceFilter = filterList => ({ type: `${UPDATE}/${WORKSPACE}/Filter`, filterList })
37 37
 
38 38
 export const WORKSPACE_LIST = `${WORKSPACE}/List`
@@ -46,6 +46,14 @@ export const WORKSPACE_MEMBER = `${WORKSPACE}/Member`
46 46
 export const WORKSPACE_MEMBER_LIST = `${WORKSPACE_MEMBER}/List`
47 47
 export const setWorkspaceMemberList = workspaceMemberList => ({ type: `${SET}/${WORKSPACE_MEMBER_LIST}`, workspaceMemberList })
48 48
 
49
+export const WORKSPACE_RECENT_ACTIVITY = `${WORKSPACE}/RecentActivity/List`
50
+export const WORKSPACE_RECENT_ACTIVITY_LIST = `${WORKSPACE_RECENT_ACTIVITY}/List`
51
+export const setWorkspaceRecentActivityList = workspaceRecentActivityList => ({ type: `${SET}/${WORKSPACE_RECENT_ACTIVITY_LIST}`, workspaceRecentActivityList })
52
+
53
+export const WORKSPACE_READ_STATUS = `${WORKSPACE}/ReadStatus`
54
+export const WORKSPACE_READ_STATUS_LIST = `${WORKSPACE_READ_STATUS}/List`
55
+export const setWorkspaceReadStatusList = workspaceReadStatusList => ({ type: `${SET}/${WORKSPACE_READ_STATUS_LIST}`, workspaceReadStatusList })
56
+
49 57
 export const FOLDER = 'Folder'
50 58
 export const setFolderData = (folderId, content) => ({ type: `${SET}/${WORKSPACE}/${FOLDER}/Content`, folderId, content })
51 59
 

+ 1 - 1
frontend/src/component/Account/Notification.jsx View File

@@ -4,7 +4,7 @@ import { BtnSwitch } from 'tracim_frontend_lib'
4 4
 import { ROLE } from '../../helper.js'
5 5
 
6 6
 export const Notification = props => {
7
-  const getRole = role => ROLE.find(r => r.name === role)
7
+  const getRole = role => ROLE.find(r => r.slug === role)
8 8
 
9 9
   return (
10 10
     <div className='account__userpreference__setting__notification'>

+ 41 - 0
frontend/src/component/Dashboard/ContentTypeBtn.jsx View File

@@ -0,0 +1,41 @@
1
+import React from 'react'
2
+import PropTypes from 'prop-types'
3
+import Radium from 'radium'
4
+import color from 'color'
5
+import classnames from 'classnames'
6
+
7
+require('./ContentTypeBtn.styl')
8
+
9
+export const ContentTypeBtn = props =>
10
+  <div
11
+    className={classnames(`${props.customClass}`, 'contentTypeBtn')}
12
+    style={{
13
+      backgroundColor: props.hexcolor,
14
+      ':hover': {
15
+        backgroundColor: color(props.hexcolor).darken(0.15).hexString()
16
+      }
17
+    }}
18
+  >
19
+    <div className={classnames(`${props.customClass}__text`)}>
20
+      <div className={classnames(`${props.customClass}__text__icon`)}>
21
+        <i className={`fa fa-${props.faIcon}`} />
22
+      </div>
23
+      <div className={classnames(`${props.customClass}__text__title`)}>
24
+        {props.creationLabel}
25
+      </div>
26
+    </div>
27
+  </div>
28
+
29
+export default Radium(ContentTypeBtn)
30
+
31
+ContentTypeBtn.propTypes = {
32
+  hexcolor: PropTypes.string.isRequired,
33
+  label: PropTypes.string.isRequired,
34
+  faIcon: PropTypes.string.isRequired,
35
+  creationLabel: PropTypes.string.isRequired,
36
+  customClass: PropTypes.string
37
+}
38
+
39
+ContentTypeBtn.defaultProps = {
40
+  customClass: ''
41
+}

+ 16 - 0
frontend/src/component/Dashboard/ContentTypeBtn.styl View File

@@ -0,0 +1,16 @@
1
+.contentTypeBtn
2
+  display flex
3
+  flex-direction column
4
+  justify-content center
5
+  margin 0 15px
6
+  border-radius 10px
7
+  padding 15px
8
+  width 230px
9
+  height 200px
10
+  box-shadow shadow-all
11
+  text-align center
12
+  cursor pointer
13
+  &:nth-child(1)
14
+    margin-left 0
15
+  &:nth-last-child
16
+    margin-right 0

+ 162 - 0
frontend/src/component/Dashboard/MemberList.jsx View File

@@ -0,0 +1,162 @@
1
+import React from 'react'
2
+import PropTypes from 'prop-types'
3
+import { Checkbox } from 'tracim_frontend_lib'
4
+
5
+require('./MemberList.styl')
6
+
7
+export class MemberList extends React.Component {
8
+  constructor (props) {
9
+    super(props)
10
+
11
+    this.state = {
12
+      displayNewMemberList: true,
13
+      createAccountCheckbox: false
14
+    }
15
+  }
16
+
17
+  handleClickAddMemberBtn = () => this.setState({displayNewMemberList: false})
18
+
19
+  handleClickCloseAddMemberBtn = () => this.setState({displayNewMemberList: true})
20
+
21
+  handleClickCheckboxCreateAccount = e => {
22
+    e.preventDefault()
23
+    e.stopPropagation()
24
+    this.setState(prev => ({createAccountCheckbox: !prev.createAccountCheckbox}))
25
+  }
26
+
27
+  render () {
28
+    const { props, state } = this
29
+
30
+    return (
31
+      <div className='memberlist'>
32
+
33
+        <div className='memberlist__title subTitle'>
34
+          {props.t('Member List')}
35
+        </div>
36
+
37
+        <div className='memberlist__wrapper'>
38
+          {state.displayNewMemberList
39
+            ? (
40
+              <div>
41
+                <ul className='memberlist__list'>
42
+                  {props.memberList.map(m =>
43
+                    <li className='memberlist__list__item primaryColorBgLightenHover' key={m.id}>
44
+                      <div className='memberlist__list__item__avatar'>
45
+                        {m.avatarUrl ? <img src={m.avatarUrl} /> : <img src='NYI' />}
46
+                      </div>
47
+
48
+                      <div className='memberlist__list__item__info mr-auto'>
49
+                        <div className='memberlist__list__item__info__name'>
50
+                          {m.publicName}
51
+                        </div>
52
+
53
+                        <div className='memberlist__list__item__info__role'>
54
+                          {props.roleList.find(r => r.slug === m.role).label}
55
+                        </div>
56
+                      </div>
57
+
58
+                      <div className='memberlist__list__item__delete'>
59
+                        <i className='fa fa-trash-o' />
60
+                      </div>
61
+                    </li>
62
+                  )}
63
+                </ul>
64
+
65
+                <div className='memberlist__btnadd' onClick={this.handleClickAddMemberBtn}>
66
+                  <div className='memberlist__btnadd__button'>
67
+                    <div className='memberlist__btnadd__button__avatar'>
68
+                      <div className='memberlist__btnadd__button__avatar__icon'>
69
+                        <i className='fa fa-plus' />
70
+                      </div>
71
+                    </div>
72
+
73
+                    <div className='memberlist__btnadd__button__text'>
74
+                      {props.t('Add a member')}
75
+                    </div>
76
+                  </div>
77
+                </div>
78
+              </div>
79
+            )
80
+            : (
81
+              <form className='memberlist__form'>
82
+                <div className='memberlist__form__close d-flex justify-content-end'>
83
+                  <i className='fa fa-times' onClick={this.handleClickCloseAddMemberBtn} />
84
+                </div>
85
+
86
+                <div className='memberlist__form__member'>
87
+                  <div className='memberlist__form__member__name'>
88
+                    <label className='name__label' htmlFor='addmember'>
89
+                      {props.t('Enter the name or email of the member')}
90
+                    </label>
91
+
92
+                    <input
93
+                      type='text'
94
+                      className='name__input form-control'
95
+                      id='addmember'
96
+                      placeholder='Nom ou Email'
97
+                      onChange={props.onChangeName}
98
+                    />
99
+                  </div>
100
+
101
+                  <div className='memberlist__form__member__create'>
102
+                    <div className='memberlist__form__member__create__checkbox mr-3'>
103
+                      <Checkbox
104
+                        name='createAccountCheckbox'
105
+                        onClickCheckbox={e => this.handleClickCheckboxCreateAccount(e)}
106
+                        checked={state.createAccountCheckbox}
107
+                      />
108
+                    </div>
109
+
110
+                    <div className='create__text'>
111
+                      {props.t('Create an account')}
112
+                    </div>
113
+                  </div>
114
+                </div>
115
+
116
+                <div className='memberlist__form__role'>
117
+                  <div className='memberlist__form__role__text'>
118
+                    {props.t('Choose the role of the member')}
119
+                  </div>
120
+
121
+                  <ul className='memberlist__form__role__list'>
122
+                    {props.roleList.map(r =>
123
+                      <li className='memberlist__form__role__list__item' key={r.slug}>
124
+                        <div className='item__radiobtn mr-3'>
125
+                          <input type='radio' name='role' value={r.slug} />
126
+                        </div>
127
+
128
+                        <div className='item__text'>
129
+                          <div className='item_text_icon mr-2' style={{color: r.hexcolor}}>
130
+                            <i className={`fa fa-${r.faIcon}`} />
131
+                          </div>
132
+
133
+                          <div className='item__text__name'>
134
+                            {r.label}
135
+                          </div>
136
+                        </div>
137
+                      </li>
138
+                    )}
139
+
140
+                  </ul>
141
+                </div>
142
+
143
+                <div className='memberlist__form__submitbtn'>
144
+                  <button className='btn btn-outline-primary'>
145
+                    {props.t('Validate')}
146
+                  </button>
147
+                </div>
148
+              </form>
149
+            )
150
+          }
151
+        </div>
152
+      </div>
153
+    )
154
+  }
155
+}
156
+
157
+export default MemberList
158
+
159
+MemberList.propTypes = {
160
+  memberList: PropTypes.array.isRequired,
161
+  onChangeName: PropTypes.func
162
+}

+ 117 - 0
frontend/src/component/Dashboard/MemberList.styl View File

@@ -0,0 +1,117 @@
1
+.memberlist
2
+  margin 0 0 50px 0
3
+  width 35%
4
+  &__title
5
+    margin-bottom 20px
6
+    padding 6px
7
+    height 45px
8
+  &__wrapper
9
+    position relative
10
+    border 1px solid grey
11
+    height 480px
12
+  &__list
13
+    margin 0
14
+    padding 0
15
+    list-style none
16
+    height 400px
17
+    overflow-Y scroll
18
+    &__item
19
+      display flex
20
+      border-bottom 1px solid grey
21
+      padding 10px 15px
22
+      &:hover
23
+        background-color fourthColor
24
+      &:nth-last-child(1)
25
+        border-bottom 0
26
+      &:nth-child(even)
27
+        background-color grey-hover
28
+        &:hover
29
+          background-color fourthColor
30
+      &__avatar
31
+        margin-right 20px
32
+        & > img
33
+          width 50px
34
+          height 50px
35
+      &__info
36
+        &__name
37
+          font-size 20px
38
+        &__role
39
+          font-size 18px
40
+      &__delete
41
+        font-size 20px
42
+        color darkGrey
43
+        cursor pointer
44
+  &__btnadd
45
+    border-top 1px solid grey
46
+    padding 15px
47
+    &__button
48
+      display flex
49
+      align-items center
50
+      &__avatar
51
+        display flex
52
+        justify-content center
53
+        align-items center
54
+        margin-right 20px
55
+        border 2px dashed grey
56
+        border-radius 50%
57
+        width 50px
58
+        height 50px
59
+        cursor pointer
60
+        &__icon
61
+          color grey
62
+          font-size 25px
63
+      &__text
64
+        font-size 18px
65
+        color fontColor
66
+        cursor pointer
67
+  &__form
68
+    padding 15px
69
+    flex-direction column
70
+    height 100%
71
+    width 100%
72
+    background-color off-white
73
+    &__close
74
+      font-size 20px
75
+      & > i
76
+        cursor pointer
77
+    &__member
78
+      &__name
79
+        .name__label
80
+          margin 30px 0 20px 0
81
+          label()
82
+      .name__input
83
+        margin-bottom 20px
84
+        border 1px solid grey
85
+        border-radius 10px
86
+        padding 10px
87
+        width 300px
88
+      &__create
89
+        display flex
90
+        align-items center
91
+        margin 15px 0
92
+        line-height 23px
93
+        &__checkbox
94
+          padding-top 6px
95
+    &__role
96
+      margin-bottom 15px
97
+      coloricon()
98
+      &__text
99
+        margin 15px 0
100
+        label()
101
+      &__list
102
+        margin 0
103
+        padding 0
104
+        list-style none
105
+        &__item
106
+          display flex
107
+          align-items center
108
+          margin 10px 25px 10px 0
109
+          .item
110
+            &__text
111
+              display flex
112
+    &__submitbtn
113
+      display flex
114
+      justify-content flex-end
115
+      & > button
116
+        padding 8px 30px
117
+        cursor pointer

+ 50 - 0
frontend/src/component/Dashboard/RecentActivity.jsx View File

@@ -0,0 +1,50 @@
1
+import React from 'react'
2
+import PropTypes from 'prop-types'
3
+import classnames from 'classnames'
4
+
5
+export const RecentActivity = props =>
6
+  <div className={props.customClass}>
7
+    <div className={`${props.customClass}__header`}>
8
+      <div className={classnames(`${props.customClass}__header__title`, 'subTitle')}>
9
+        {props.t('Recent activity')}
10
+      </div>
11
+
12
+      <div className={classnames(`${props.customClass}__header__allread`, 'btn btn-outline-primary')}>
13
+        {props.t('Mark everything as read')}
14
+      </div>
15
+    </div>
16
+
17
+    <div className={`${props.customClass}__wrapper`}>
18
+      {props.recentActivityFilteredForUser.map(content => {
19
+        const contentType = props.contentTypeList.find(ct => ct.slug === content.type)
20
+        return (
21
+          <div className={`${props.customClass}__workspace`} key={content.id}>
22
+            <div className={`${props.customClass}__workspace__icon`} style={{color: contentType.hexcolor}}>
23
+              <i className={`fa fa-${contentType.faIcon}`} />
24
+            </div>
25
+            <div className={`${props.customClass}__workspace__name`}>
26
+              {content.label}
27
+            </div>
28
+          </div>
29
+        )
30
+      })}
31
+
32
+      <div className={classnames(`${props.customClass}__more`, 'd-flex flex-row-reverse')}>
33
+        <div
34
+          className={classnames(`${props.customClass}__more__btn`, 'btn btn-outline-primary')}
35
+          onClick={props.onClickSeeMore}
36
+        >
37
+          {props.t('See more')}
38
+        </div>
39
+      </div>
40
+    </div>
41
+  </div>
42
+
43
+export default RecentActivity
44
+
45
+RecentActivity.propTypes = {
46
+  t: PropTypes.func.isRequired,
47
+  recentActivityFilteredForUser: PropTypes.array.isRequired,
48
+  contentTypeList: PropTypes.array.isRequired,
49
+  onClickSeeMore: PropTypes.func.isRequired
50
+}

+ 73 - 187
frontend/src/container/Dashboard.jsx View File

@@ -1,10 +1,7 @@
1 1
 import React from 'react'
2 2
 import { connect } from 'react-redux'
3 3
 import Sidebar from './Sidebar.jsx'
4
-import imgProfil from '../img/imgProfil.png'
5 4
 import { translate } from 'react-i18next'
6
-import Radium from 'radium'
7
-import color from 'color'
8 5
 import {
9 6
   PageWrapper,
10 7
   PageTitle,
@@ -12,13 +9,21 @@ import {
12 9
 } from 'tracim_frontend_lib'
13 10
 import {
14 11
   getWorkspaceDetail,
15
-  getWorkspaceMemberList
12
+  getWorkspaceMemberList,
13
+  getWorkspaceRecentActivityList,
14
+  getWorkspaceReadStatusList
16 15
 } from '../action-creator.async.js'
17 16
 import {
18
-  addFlashMessage,
17
+  newFlashMessage,
19 18
   setWorkspaceDetail,
20
-  setWorkspaceMemberList
19
+  setWorkspaceMemberList,
20
+  setWorkspaceRecentActivityList,
21
+  setWorkspaceReadStatusList
21 22
 } from '../action-creator.sync.js'
23
+import { ROLE } from '../helper.js'
24
+import ContentTypeBtn from '../component/Dashboard/ContentTypeBtn.jsx'
25
+import RecentActivity from '../component/Dashboard/RecentActivity.jsx'
26
+import MemberList from '../component/Dashboard/MemberList.jsx'
22 27
 
23 28
 class Dashboard extends React.Component {
24 29
   constructor (props) {
@@ -38,23 +43,33 @@ class Dashboard extends React.Component {
38 43
     const fetchWorkspaceDetail = await props.dispatch(getWorkspaceDetail(props.user, state.workspaceIdInUrl))
39 44
     switch (fetchWorkspaceDetail.status) {
40 45
       case 200:
41
-        props.dispatch(setWorkspaceDetail(fetchWorkspaceDetail.json))
42
-        break
43
-      case 400:
44
-      case 500:
45
-        props.dispatch(addFlashMessage(props.t('An error has happened'), 'warning'))
46
-        break
46
+        props.dispatch(setWorkspaceDetail(fetchWorkspaceDetail.json)); break
47
+      default:
48
+        props.dispatch(newFlashMessage(props.t('An error has happened when fetching workspace detail'), 'warning')); break
47 49
     }
48 50
 
49 51
     const fetchWorkspaceMemberList = await props.dispatch(getWorkspaceMemberList(props.user, state.workspaceIdInUrl))
50 52
     switch (fetchWorkspaceMemberList.status) {
51 53
       case 200:
52
-        props.dispatch(setWorkspaceMemberList(fetchWorkspaceMemberList.json))
53
-        break
54
-      case 400:
55
-      case 500:
56
-        props.dispatch(addFlashMessage(props.t('An error has happened'), 'warning'))
57
-        break
54
+        props.dispatch(setWorkspaceMemberList(fetchWorkspaceMemberList.json)); break
55
+      default:
56
+        props.dispatch(newFlashMessage(props.t('An error has happened while fetching member list'), 'warning')); break
57
+    }
58
+
59
+    const fetchWorkspaceRecentActivityList = await props.dispatch(getWorkspaceRecentActivityList(props.user, state.workspaceIdInUrl))
60
+    switch (fetchWorkspaceRecentActivityList.status) {
61
+      case 200:
62
+        props.dispatch(setWorkspaceRecentActivityList(fetchWorkspaceRecentActivityList.json)); break
63
+      default:
64
+        props.dispatch(newFlashMessage(props.t('An error has happened while fetching recent activity list'), 'warning')); break
65
+    }
66
+
67
+    const fetchWorkspaceReadStatusList = await props.dispatch(getWorkspaceReadStatusList(props.user, state.workspaceIdInUrl))
68
+    switch (fetchWorkspaceReadStatusList.status) {
69
+      case 200:
70
+        props.dispatch(setWorkspaceReadStatusList(fetchWorkspaceReadStatusList.json)); break
71
+      default:
72
+        props.dispatch(newFlashMessage(props.t('An error has happened while fetching read status list'), 'warning')); break
58 73
     }
59 74
   }
60 75
 
@@ -112,15 +127,24 @@ class Dashboard extends React.Component {
112 127
                     {props.t(`Hi ! ${props.user.public_name}, vous êtes actuellement`)}
113 128
                   </div>
114 129
 
115
-                  <div className='dashboard__userstatut__role__definition'>
116
-                    <div className='dashboard__userstatut__role__definition__icon'>
117
-                      <i className='fa fa-graduation-cap' />
118
-                    </div>
130
+                  {(() => {
131
+                    const myself = props.curWs.memberList.find(m => m.id === props.user.user_id)
132
+                    if (myself === undefined) return
119 133
 
120
-                    <div className='dashboard__userstatut__role__definition__text'>
121
-                      {(member => member ? member.role : '')(props.curWs.member.find(m => m.id === props.user.user_id))}
122
-                    </div>
123
-                  </div>
134
+                    const myRole = ROLE.find(r => r.slug === myself.role)
135
+
136
+                    return (
137
+                      <div className='dashboard__userstatut__role__definition'>
138
+                        <div className='dashboard__userstatut__role__definition__icon'>
139
+                          <i className={`fa fa-${myRole.faIcon}`} />
140
+                        </div>
141
+
142
+                        <div className='dashboard__userstatut__role__definition__text'>
143
+                          {myRole.label}
144
+                        </div>
145
+                      </div>
146
+                    )
147
+                  })()}
124 148
                 </div>
125 149
 
126 150
                 <div className='dashboard__userstatut__notification'>
@@ -167,170 +191,32 @@ class Dashboard extends React.Component {
167 191
 
168 192
             <div className='dashboard__calltoaction justify-content-xl-center'>
169 193
               {props.contentType.map(ct =>
170
-                <div
171
-                  className='dashboard__calltoaction__button btnaction'
172
-                  style={{
173
-                    backgroundColor: ct.hexcolor,
174
-                    ':hover': {
175
-                      backgroundColor: color(ct.hexcolor).darken(0.15).hexString()
176
-                    }
177
-                  }}
194
+                <ContentTypeBtn
195
+                  customClass='dashboard__calltoaction__button'
196
+                  hexcolor={ct.hexcolor}
197
+                  label={ct.label}
198
+                  faIcon={ct.faIcon}
199
+                  creationLabel={ct.creationLabel}
178 200
                   key={ct.label}
179
-                >
180
-                  <div className='dashboard__calltoaction__button__text'>
181
-                    <div className='dashboard__calltoaction__button__text__icon'>
182
-                      <i className={`fa fa-${ct.faIcon}`} />
183
-                    </div>
184
-                    <div className='dashboard__calltoaction__button__text__title'>
185
-                      {ct.creationLabel}
186
-                    </div>
187
-                  </div>
188
-                </div>
201
+                />
189 202
               )}
190 203
             </div>
191 204
 
192
-            <div className='dashboard__wksinfo'>
193
-              <div className='dashboard__activity'>
194
-                <div className='dashboard__activity__header'>
195
-                  <div className='dashboard__activity__header__title subTitle'>
196
-                    {this.props.t('Recent activity')}
197
-                  </div>
198
-
199
-                  <div className='dashboard__activity__header__allread btn btn-outline-primary'>
200
-                    {this.props.t('Mark everything as read')}
201
-                  </div>
202
-                </div>
203
-                <div className='dashboard__activity__wrapper'>
204
-
205
-                  <div className='dashboard__activity__workspace'>
206
-                    <div className='dashboard__activity__workspace__icon'>
207
-                      <i className='fa fa-comments-o' />
208
-                    </div>
209
-                    <div className='dashboard__activity__workspace__name'>
210
-                      <span>Développement Tracim</span>
211
-                    </div>
212
-                  </div>
213
-
214
-                  <div className='dashboard__activity__more d-flex flex-row-reverse'>
215
-                    <div className='dashboard__activity__more__btn btn btn-outline-primary'>
216
-                      {this.props.t('See more')}
217
-                    </div>
218
-                  </div>
219
-                </div>
220
-              </div>
221
-
222
-              <div className='dashboard__memberlist'>
223
-
224
-                <div className='dashboard__memberlist__title subTitle'>
225
-                  {this.props.t('Member List')}
226
-                </div>
227
-
228
-                <div className='dashboard__memberlist__wrapper'>
229
-                  {this.state.displayNewMemberDashboard === false &&
230
-                    <div>
231
-                      <ul className='dashboard__memberlist__list'>
232
-
233
-                        <li className='dashboard__memberlist__list__item'>
234
-                          <div className='dashboard__memberlist__list__item__avatar'>
235
-                            <img src={imgProfil} alt='avatar' />
236
-                          </div>
237
-                          <div className='dashboard__memberlist__list__item__info mr-auto'>
238
-                            <div className='dashboard__memberlist__list__item__info__name'>
239
-                              Jean Dupont
240
-                            </div>
241
-                            <div className='dashboard__memberlist__list__item__info__role'>
242
-                              Responsable
243
-                            </div>
244
-                          </div>
245
-                          <div className='dashboard__memberlist__list__item__delete d-flex justify-content-end'>
246
-                            <i className='fa fa-trash-o' />
247
-                          </div>
248
-                        </li>
249
-
250
-                      </ul>
251
-
252
-                      <div
253
-                        className='dashboard__memberlist__btnadd'
254
-                        onClick={this.handleToggleNewMemberDashboard}
255
-                      >
256
-                        <div className='dashboard__memberlist__btnadd__button'>
257
-                          <div className='dashboard__memberlist__btnadd__button__avatar'>
258
-                            <div className='dashboard__memberlist__btnadd__button__avatar__icon'>
259
-                              <i className='fa fa-plus' />
260
-                            </div>
261
-                          </div>
262
-                          <div
263
-                            className='dashboard__memberlist__btnadd__button__text'
264
-                          >
265
-                            {this.props.t('Add a member')}
266
-                          </div>
267
-                        </div>
268
-                      </div>
269
-                    </div>
270
-                  }
271
-
272
-                  {this.state.displayNewMemberDashboard === true &&
273
-                  <form className='dashboard__memberlist__form'>
274
-                    <div
275
-                      className='dashboard__memberlist__form__close d-flex justify-content-end'
276
-                    >
277
-                      <i className='fa fa-times' onClick={this.handleToggleNewMemberDashboard} />
278
-                    </div>
279
-
280
-                    <div className='dashboard__memberlist__form__member'>
281
-                      <div className='dashboard__memberlist__form__member__name'>
282
-                        <label className='name__label' htmlFor='addmember'>
283
-                          {this.props.t('Enter the name or email of the member')}
284
-                        </label>
285
-                        <input type='text' id='addmember' className='name__input form-control' placeholder='Nom ou Email' />
286
-                      </div>
287
-
288
-                      <div className='dashboard__memberlist__form__member__create'>
289
-                        <div className='create__radiobtn mr-3'>
290
-                          <input type='radio' />
291
-                        </div>
292
-
293
-                        <div className='create__text'>
294
-                          {this.props.t('Create an account')}
295
-                        </div>
296
-                      </div>
297
-                    </div>
298
-
299
-                    <div className='dashboard__memberlist__form__role'>
300
-                      <div className='dashboard__memberlist__form__role__text'>
301
-                        {this.props.t('Choose the role of the member')}
302
-                      </div>
303
-
304
-                      <ul className='dashboard__memberlist__form__role__list'>
305
-
306
-                        <li className='dashboard__memberlist__form__role__list__item'>
307
-                          <div className='item__radiobtn mr-3'>
308
-                            <input type='radio' name='role' value='responsable' />
309
-                          </div>
310
-
311
-                          <div className='item__text'>
312
-                            <div className='item_text_icon mr-2'>
313
-                              <i className='fa fa-gavel' />
314
-                            </div>
315
-
316
-                            <div className='item__text__name'>
317
-                              {this.props.t('Supervisor')}
318
-                            </div>
319
-                          </div>
320
-                        </li>
321
-
322
-                      </ul>
323
-                    </div>
324
-
325
-                    <div className='dashboard__memberlist__form__submitbtn'>
326
-                      <button className='btn btn-outline-primary'>
327
-                        {this.props.t('Validate')}
328
-                      </button>
329
-                    </div>
330
-                  </form>
331
-                  }
332
-                </div>
333
-              </div>
205
+            <div className='dashboard__workspaceInfo'>
206
+              <RecentActivity
207
+                customClass='dashboard__activity'
208
+                recentActivityFilteredForUser={props.curWs.recentActivityList.filter(content => !props.curWs.contentReadStatusList.includes(content.id))}
209
+                contentTypeList={props.contentType}
210
+                onClickSeeMore={() => {}}
211
+                t={props.t}
212
+              />
213
+
214
+              <MemberList
215
+                customClass='dashboard__memberlist'
216
+                memberList={props.curWs.memberList}
217
+                roleList={ROLE}
218
+                t={props.t}
219
+              />
334 220
             </div>
335 221
 
336 222
             <div className='dashboard__moreinfo'>
@@ -401,4 +287,4 @@ class Dashboard extends React.Component {
401 287
 }
402 288
 
403 289
 const mapStateToProps = ({ user, contentType, currentWorkspace }) => ({ user, contentType, curWs: currentWorkspace })
404
-export default connect(mapStateToProps)(translate()(Radium(Dashboard)))
290
+export default connect(mapStateToProps)(translate()(Dashboard))

+ 0 - 571
frontend/src/container/Dashboard_old.jsx View File

@@ -1,571 +0,0 @@
1
-import React from 'react'
2
-import { connect } from 'react-redux'
3
-import Sidebar from './Sidebar.jsx'
4
-import imgProfil from '../img/imgProfil.png'
5
-import { translate } from 'react-i18next'
6
-
7
-class Dashboard extends React.Component {
8
-  constructor (props) {
9
-    super(props)
10
-    this.state = {
11
-      workspaceIdInUrl: props.match.params.idws ? parseInt(props.match.params.idws) : null, // this is used to avoid handling the parseInt everytime
12
-      displayNewMemberDashboard: false,
13
-      displayNotifBtn: false,
14
-      displayWebdavBtn: false,
15
-      displayCalendarBtn: false
16
-    }
17
-  }
18
-
19
-  handleToggleNewMemberDashboard = () => this.setState(prevState => ({
20
-    displayNewMemberDashboard: !prevState.displayNewMemberDashboard
21
-  }))
22
-
23
-  handleToggleNotifBtn = () => this.setState(prevState => ({
24
-    displayNotifBtn: !prevState.displayNotifBtn
25
-  }))
26
-
27
-  handleToggleWebdavBtn = () => this.setState(prevState => ({
28
-    displayWebdavBtn: !prevState.displayWebdavBtn
29
-  }))
30
-
31
-  handleToggleCalendarBtn = () => this.setState(prevState => ({
32
-    displayCalendarBtn: !prevState.displayCalendarBtn
33
-  }))
34
-
35
-  render () {
36
-    return (
37
-      <div className='sidebarpagecontainer'>
38
-        <Sidebar />
39
-
40
-        <div className='dashboard'>
41
-          <div className='container-fluid nopadding'>
42
-            <div className='dashboard__header mb-5'>
43
-              <div className='pageTitleGeneric dashboard__header__title d-flex align-items-center'>
44
-                <div className='pageTitleGeneric__title dashboard__header__title__text mr-3'>
45
-                  {this.props.t('Dashboard')}
46
-                </div>
47
-                <div className='dashboard__header__acces' />
48
-              </div>
49
-
50
-              <div className='dashboard__header__advancedmode mr-3'>
51
-                <button type='button' className='btn btn-primary'>
52
-                  {this.props.t('Active advanced Dashboard')}
53
-                </button>
54
-              </div>
55
-            </div>
56
-
57
-            <div className='dashboard__workspace-wrapper'>
58
-              <div className='dashboard__workspace'>
59
-                <div className='dashboard__workspace__title'>
60
-                  Développement tracim
61
-                </div>
62
-
63
-                <div className='dashboard__workspace__detail'>
64
-                  Ligne directive pour le prochain design de Tracim et des futurs fonctionnalités.
65
-                </div>
66
-              </div>
67
-
68
-              <div className='dashboard__userstatut'>
69
-
70
-                <div className='dashboard__userstatut__role'>
71
-                  <div className='dashboard__userstatut__role__text'>
72
-                    Hi ! Alexi, vous êtes actuellement
73
-                  </div>
74
-                  <div className='dashboard__userstatut__role__rank'>
75
-                    <div className='dashboard__userstatut__role__rank__icon'>
76
-                      <i className='fa fa-graduation-cap' />
77
-                    </div>
78
-                    <div className='dashboard__userstatut__role__rank__rolename'>
79
-                      Gestionnaire de projet
80
-                    </div>
81
-                  </div>
82
-                </div>
83
-
84
-                <div className='dashboard__userstatut__notification'>
85
-                  <div className='dashboard__userstatut__notification__text'>
86
-                    Vous êtes abonné(e) aux notifications de ce workspace
87
-                  </div>
88
-                  {this.state.displayNotifBtn === false &&
89
-                  <div
90
-                    className='dashboard__userstatut__notification__btn btn btn-outline-primary'
91
-                    onClick={this.handleToggleNotifBtn}
92
-                  >
93
-                    {this.props.t('Change your status')}
94
-                  </div>
95
-                  }
96
-
97
-                  {this.state.displayNotifBtn === true &&
98
-                  <div className='dashboard__userstatut__notification__subscribe dropdown'>
99
-                    <button className='dashboard__userstatut__notification__subscribe__btn btn btn-outline-primary dropdown-toggle' type='button' id='dropdownMenuButton' data-toggle='dropdown' aria-haspopup='true' aria-expanded='false'>
100
-                      Abonné(e)
101
-                    </button>
102
-                    <div className='dashboard__userstatut__notification__subscribe__submenu dropdown-menu'>
103
-                      <div className='dashboard__userstatut__notification__subscribe__submenu__item dropdown-item'>
104
-                        {this.props.t('subscriber')}
105
-                      </div>
106
-                      <div className='dashboard__userstatut__notification__subscribe__submenu__item dropdown-item dropdown-item'>
107
-                        {this.props.t('unsubscribed')}
108
-                      </div>
109
-                    </div>
110
-                  </div>
111
-                  }
112
-                </div>
113
-              </div>
114
-            </div>
115
-
116
-            <div className='dashboard__calltoaction justify-content-xl-center'>
117
-              <div className='dashboard__calltoaction__button btnaction btnthread'>
118
-                <div className='dashboard__calltoaction__button__text'>
119
-                  <div className='dashboard__calltoaction__button__text__icon'>
120
-                    <i className='fa fa-comments-o' />
121
-                  </div>
122
-                  <div className='dashboard__calltoaction__button__text__title'>
123
-                    {this.props.t('Start a new Thread')}
124
-                  </div>
125
-                </div>
126
-              </div>
127
-
128
-              <div className='dashboard__calltoaction__button btnaction writefile'>
129
-                <div className='dashboard__calltoaction__button__text'>
130
-                  <div className='dashboard__calltoaction__button__text__icon'>
131
-                    <i className='fa fa-file-text-o' />
132
-                  </div>
133
-                  <div className='dashboard__calltoaction__button__text__title'>
134
-                    {this.props.t('Writing a document')}
135
-                  </div>
136
-                </div>
137
-              </div>
138
-
139
-              <div className='dashboard__calltoaction__button btnaction importfile'>
140
-                <div className='dashboard__calltoaction__button__text'>
141
-                  <div className='dashboard__calltoaction__button__text__icon'>
142
-                    <i className='fa fa-paperclip' />
143
-                  </div>
144
-                  <div className='dashboard__calltoaction__button__text__title'>
145
-                    {this.props.t('Upload a file')}
146
-                  </div>
147
-                </div>
148
-              </div>
149
-
150
-              {/*
151
-                <div className='dashboard__calltoaction__button btnaction visioconf'>
152
-                  <div className='dashboard__calltoaction__button__text'>
153
-                    <div className='dashboard__calltoaction__button__text__icon'>
154
-                      <i className='fa fa-video-camera' />
155
-                    </div>
156
-                    <div className='dashboard__calltoaction__button__text__title'>
157
-                      {this.props.t('Start a videoconference')}
158
-                    </div>
159
-                  </div>
160
-                </div>
161
-
162
-                <div className='dashboard__calltoaction__button btnaction calendar'>
163
-                  <div className='dashboard__calltoaction__button__text'>
164
-                    <div className='dashboard__calltoaction__button__text__icon'>
165
-                      <i className='fa fa-calendar' />
166
-                    </div>
167
-                    <div className='dashboard__calltoaction__button__text__title'>
168
-                      {this.props.t('View the Calendar')}
169
-                    </div>
170
-                  </div>
171
-                </div>
172
-              */ }
173
-
174
-              <div className='dashboard__calltoaction__button btnaction explore'>
175
-                <div className='dashboard__calltoaction__button__text'>
176
-                  <div className='dashboard__calltoaction__button__text__icon'>
177
-                    <i className='fa fa-folder-open-o' />
178
-                  </div>
179
-                  <div className='dashboard__calltoaction__button__text__title'>
180
-                    {this.props.t('Explore the workspace')}
181
-                  </div>
182
-                </div>
183
-              </div>
184
-            </div>
185
-
186
-            <div className='dashboard__wksinfo'>
187
-              <div className='dashboard__activity'>
188
-                <div className='dashboard__activity__header'>
189
-                  <div className='dashboard__activity__header__title subTitle'>
190
-                    {this.props.t('Recent activity')}
191
-                  </div>
192
-
193
-                  <div className='dashboard__activity__header__allread btn btn-outline-primary'>
194
-                    {this.props.t('Mark everything as read')}
195
-                  </div>
196
-                </div>
197
-                <div className='dashboard__activity__wrapper'>
198
-                  <div className='dashboard__activity__workspace'>
199
-                    <div className='dashboard__activity__workspace__icon'>
200
-                      <i className='fa fa-comments-o' />
201
-                    </div>
202
-                    <div className='dashboard__activity__workspace__name'>
203
-                      <span>Développement Tracim</span>
204
-                    </div>
205
-                  </div>
206
-
207
-                  <div className='dashboard__activity__workspace'>
208
-                    <div className='dashboard__activity__workspace__icon'>
209
-                      <i className='fa fa-list-ul' />
210
-                    </div>
211
-                    <div className='dashboard__activity__workspace__name'>
212
-                      Mission externe
213
-                    </div>
214
-                  </div>
215
-
216
-                  <div className='dashboard__activity__workspace'>
217
-                    <div className='dashboard__activity__workspace__icon'>
218
-                      <i className='fa fa-list-ul' />
219
-                    </div>
220
-                    <div className='dashboard__activity__workspace__name'>
221
-                      Recherche et developpement
222
-                    </div>
223
-                  </div>
224
-
225
-                  <div className='dashboard__activity__workspace'>
226
-                    <div className='dashboard__activity__workspace__icon'>
227
-                      <i className='fa fa-file-text-o' />
228
-                    </div>
229
-                    <div className='dashboard__activity__workspace__name'>
230
-                      <span>Marketing</span>
231
-                    </div>
232
-                  </div>
233
-
234
-                  <div className='dashboard__activity__workspace'>
235
-                    <div className='dashboard__activity__workspace__icon'>
236
-                      <i className='fa fa-comments-o' />
237
-                    </div>
238
-                    <div className='dashboard__activity__workspace__name'>
239
-                      <span>Évolution</span>
240
-                    </div>
241
-                  </div>
242
-
243
-                  <div className='dashboard__activity__workspace'>
244
-                    <div className='dashboard__activity__workspace__icon'>
245
-                      <i className='fa fa-file-text-o' />
246
-                    </div>
247
-                    <div className='dashboard__activity__workspace__name'>
248
-                      Commercialisation
249
-                    </div>
250
-                  </div>
251
-
252
-                  <div className='dashboard__activity__more d-flex flex-row-reverse'>
253
-                    <div className='dashboard__activity__more__btn btn btn-outline-primary'>
254
-                      {this.props.t('See more')}
255
-                    </div>
256
-                  </div>
257
-                </div>
258
-              </div>
259
-
260
-              <div className='dashboard__memberlist'>
261
-
262
-                <div className='dashboard__memberlist__title subTitle'>
263
-                  {this.props.t('Member List')}
264
-                </div>
265
-
266
-                <div className='dashboard__memberlist__wrapper'>
267
-                  {this.state.displayNewMemberDashboard === false &&
268
-                  <div>
269
-                    <ul className='dashboard__memberlist__list'>
270
-                      <li className='dashboard__memberlist__list__item'>
271
-                        <div className='dashboard__memberlist__list__item__avatar'>
272
-                          <img src={imgProfil} alt='avatar' />
273
-                        </div>
274
-                        <div className='dashboard__memberlist__list__item__info mr-auto'>
275
-                          <div className='dashboard__memberlist__list__item__info__name'>
276
-                            Jean Dupont
277
-                          </div>
278
-                          <div className='dashboard__memberlist__list__item__info__role'>
279
-                            Responsable
280
-                          </div>
281
-                        </div>
282
-                        <div className='dashboard__memberlist__list__item__delete d-flex justify-content-end'>
283
-                          <i className='fa fa-trash-o' />
284
-                        </div>
285
-                      </li>
286
-
287
-                      <li className='dashboard__memberlist__list__item'>
288
-                        <div className='dashboard__memberlist__list__item__avatar'>
289
-                          <img src={imgProfil} alt='avatar' />
290
-                        </div>
291
-                        <div className='dashboard__memberlist__list__item__info mr-auto'>
292
-                          <div className='dashboard__memberlist__list__item__info__name'>
293
-                            Aldwin Vinel
294
-                          </div>
295
-                          <div className='dashboard__memberlist__list__item__info__role'>
296
-                            Lecteur
297
-                          </div>
298
-                        </div>
299
-                        <div className='dashboard__memberlist__list__item__delete d-flex justify-content-end'>
300
-                          <i className='fa fa-trash-o' />
301
-                        </div>
302
-                      </li>
303
-
304
-                      <li className='dashboard__memberlist__list__item'>
305
-                        <div className='dashboard__memberlist__list__item__avatar'>
306
-                          <img src={imgProfil} alt='avatar' />
307
-                        </div>
308
-                        <div className='dashboard__memberlist__list__item__info mr-auto'>
309
-                          <div className='dashboard__memberlist__list__item__info__name'>
310
-                            William Himme
311
-                          </div>
312
-                          <div className='dashboard__memberlist__list__item__info__role'>
313
-                            Contributeur
314
-                          </div>
315
-                        </div>
316
-                        <div className='dashboard__memberlist__list__item__delete d-flex justify-content-end'>
317
-                          <i className='fa fa-trash-o' />
318
-                        </div>
319
-                      </li>
320
-
321
-                      <li className='dashboard__memberlist__list__item'>
322
-                        <div className='dashboard__memberlist__list__item__avatar'>
323
-                          <img src={imgProfil} alt='avatar' />
324
-                        </div>
325
-                        <div className='dashboard__memberlist__list__item__info mr-auto'>
326
-                          <div className='dashboard__memberlist__list__item__info__name'>
327
-                            Yacine Lite
328
-                          </div>
329
-                          <div className='dashboard__memberlist__list__item__info__role'>
330
-                            Contributeur
331
-                          </div>
332
-                        </div>
333
-                        <div className='dashboard__memberlist__list__item__delete d-flex justify-content-end'>
334
-                          <i className='fa fa-trash-o' />
335
-                        </div>
336
-                      </li>
337
-
338
-                      <li className='dashboard__memberlist__list__item'>
339
-                        <div className='dashboard__memberlist__list__item__avatar'>
340
-                          <img src={imgProfil} alt='avatar' />
341
-                        </div>
342
-                        <div className='dashboard__memberlist__list__item__info mr-auto'>
343
-                          <div className='dashboard__memberlist__list__item__info__name'>
344
-                            Alexi Falcin
345
-                          </div>
346
-                          <div className='dashboard__memberlist__list__item__info__role'>
347
-                            Gestionnaire
348
-                          </div>
349
-                        </div>
350
-                        <div className='dashboard__memberlist__list__item__delete d-flex justify-content-end'>
351
-                          <i className='fa fa-trash-o' />
352
-                        </div>
353
-                      </li>
354
-
355
-                      <li className='dashboard__memberlist__list__item'>
356
-                        <div className='dashboard__memberlist__list__item__avatar'>
357
-                          <img src={imgProfil} alt='avatar' />
358
-                        </div>
359
-                        <div className='dashboard__memberlist__list__item__info mr-auto'>
360
-                          <div className='dashboard__memberlist__list__item__info__name'>
361
-                            Mickaël Fonati
362
-                          </div>
363
-                          <div className='dashboard__memberlist__list__item__info__role'>
364
-                            Gestionnaire
365
-                          </div>
366
-                        </div>
367
-                        <div className='dashboard__memberlist__list__item__delete d-flex justify-content-end'>
368
-                          <i className='fa fa-trash-o' />
369
-                        </div>
370
-                      </li>
371
-
372
-                      <li className='dashboard__memberlist__list__item'>
373
-                        <div className='dashboard__memberlist__list__item__avatar'>
374
-                          <img src={imgProfil} alt='avatar' />
375
-                        </div>
376
-                        <div className='dashboard__memberlist__list__item__info mr-auto'>
377
-                          <div className='dashboard__memberlist__list__item__info__name'>
378
-                            Eva Lonbard
379
-                          </div>
380
-                          <div className='dashboard__memberlist__list__item__info__role'>
381
-                            Gestionnaire
382
-                          </div>
383
-                        </div>
384
-                        <div className='dashboard__memberlist__list__item__delete d-flex justify-content-end'>
385
-                          <i className='fa fa-trash-o' />
386
-                        </div>
387
-                      </li>
388
-                    </ul>
389
-
390
-                    <div
391
-                      className='dashboard__memberlist__btnadd'
392
-                      onClick={this.handleToggleNewMemberDashboard}
393
-                    >
394
-                      <div className='dashboard__memberlist__btnadd__button'>
395
-                        <div className='dashboard__memberlist__btnadd__button__avatar'>
396
-                          <div className='dashboard__memberlist__btnadd__button__avatar__icon'>
397
-                            <i className='fa fa-plus' />
398
-                          </div>
399
-                        </div>
400
-                        <div
401
-                          className='dashboard__memberlist__btnadd__button__text'
402
-                        >
403
-                          {this.props.t('Add a member')}
404
-                        </div>
405
-                      </div>
406
-                    </div>
407
-                  </div>
408
-                  }
409
-
410
-                  {this.state.displayNewMemberDashboard === true &&
411
-                  <form className='dashboard__memberlist__form'>
412
-                    <div
413
-                      className='dashboard__memberlist__form__close d-flex justify-content-end'
414
-                    >
415
-                      <i className='fa fa-times' onClick={this.handleToggleNewMemberDashboard} />
416
-                    </div>
417
-                    <div className='dashboard__memberlist__form__member'>
418
-                      <div className='dashboard__memberlist__form__member__name'>
419
-                        <label className='name__label' htmlFor='addmember'>
420
-                          {this.props.t('Enter the name or email of the member')}
421
-                        </label>
422
-                        <input type='text' id='addmember' className='name__input form-control' placeholder='Nom ou Email' />
423
-                      </div>
424
-                      <div className='dashboard__memberlist__form__member__create'>
425
-                        <div className='create__radiobtn mr-3'>
426
-                          <input type='radio' />
427
-                        </div>
428
-                        <div className='create__text'>
429
-                          {this.props.t('Create an account')}
430
-                        </div>
431
-                      </div>
432
-                    </div>
433
-                    <div className='dashboard__memberlist__form__role'>
434
-                      <div className='dashboard__memberlist__form__role__text'>
435
-                        {this.props.t('Choose the role of the member')}
436
-                      </div>
437
-                      <ul className='dashboard__memberlist__form__role__list'>
438
-                        <li className='dashboard__memberlist__form__role__list__item'>
439
-                          <div className='item__radiobtn mr-3'>
440
-                            <input type='radio' name='role' value='responsable' />
441
-                          </div>
442
-                          <div className='item__text'>
443
-                            <div className='item_text_icon mr-2'>
444
-                              <i className='fa fa-gavel' />
445
-                            </div>
446
-                            <div className='item__text__name'>
447
-                              {this.props.t('Supervisor')}
448
-                            </div>
449
-                          </div>
450
-                        </li>
451
-                        <li className='dashboard__memberlist__form__role__list__item'>
452
-                          <div className='item__radiobtn mr-3'>
453
-                            <input type='radio' name='role' value='gestionnaire' />
454
-                          </div>
455
-                          <div className='item__text'>
456
-                            <div className='item_text_icon mr-2'>
457
-                              <i className='fa fa-graduation-cap' />
458
-                            </div>
459
-                            <div className='item__text__name'>
460
-                              {this.props.t('Content Manager')}
461
-                            </div>
462
-                          </div>
463
-                        </li>
464
-                        <li className='dashboard__memberlist__form__role__list__item'>
465
-                          <div className='item__radiobtn mr-3'>
466
-                            <input type='radio' name='role' value='contributeur' />
467
-                          </div>
468
-                          <div className='item__text'>
469
-                            <div className='item_text_icon mr-2'>
470
-                              <i className='fa fa-pencil' />
471
-                            </div>
472
-                            <div className='item__text__name'>
473
-                              {this.props.t('Contributor')}
474
-                            </div>
475
-                          </div>
476
-                        </li>
477
-                        <li className='dashboard__memberlist__form__role__list__item'>
478
-                          <div className='item__radiobtn mr-3'>
479
-                            <input type='radio' name='role' value='lecteur' />
480
-                          </div>
481
-                          <div className='item__text'>
482
-                            <div className='item_text_icon mr-2'>
483
-                              <i className='fa fa-eye' />
484
-                            </div>
485
-                            <div className='item__text__name'>
486
-                              {this.props.t('Reader')}
487
-                            </div>
488
-                          </div>
489
-                        </li>
490
-                      </ul>
491
-                    </div>
492
-                    <div className='dashboard__memberlist__form__submitbtn'>
493
-                      <button className='btn btn-outline-primary'>
494
-                        {this.props.t('Validate')}
495
-                      </button>
496
-                    </div>
497
-                  </form>
498
-                  }
499
-                </div>
500
-              </div>
501
-            </div>
502
-
503
-            <div className='dashboard__moreinfo'>
504
-              <div className='dashboard__moreinfo__webdav genericBtnInfoDashboard'>
505
-                <div
506
-                  className='dashboard__moreinfo__webdav__btn genericBtnInfoDashboard__btn'
507
-                  onClick={this.handleToggleWebdavBtn}
508
-                >
509
-                  <div className='dashboard__moreinfo__webdav__btn__icon genericBtnInfoDashboard__btn__icon'>
510
-                    <i className='fa fa-windows' />
511
-                  </div>
512
-
513
-                  <div className='dashboard__moreinfo__webdav__btn__text genericBtnInfoDashboard__btn__text'>
514
-                    {this.props.t('Implement Tracim in your explorer')}
515
-                  </div>
516
-                </div>
517
-                {this.state.displayWebdavBtn === true &&
518
-                <div>
519
-                  <div className='dashboard__moreinfo__webdav__information genericBtnInfoDashboard__info'>
520
-                    <div className='dashboard__moreinfo__webdav__information__text genericBtnInfoDashboard__info__text'>
521
-                      {this.props.t('Find all your documents deposited online directly on your computer via the workstation, without going through the software.')}'
522
-                    </div>
523
-
524
-                    <div className='dashboard__moreinfo__webdav__information__link genericBtnInfoDashboard__info__link'>
525
-                      http://algoo.trac.im/webdav/
526
-                    </div>
527
-                  </div>
528
-                </div>
529
-                }
530
-              </div>
531
-              <div className='dashboard__moreinfo__calendar genericBtnInfoDashboard'>
532
-                <div className='dashboard__moreinfo__calendar__wrapperBtn'>
533
-                  <div
534
-                    className='dashboard__moreinfo__calendar__btn genericBtnInfoDashboard__btn'
535
-                    onClick={this.handleToggleCalendarBtn}
536
-                  >
537
-                    <div className='dashboard__moreinfo__calendar__btn__icon genericBtnInfoDashboard__btn__icon'>
538
-                      <i className='fa fa-calendar' />
539
-                    </div>
540
-
541
-                    <div className='dashboard__moreinfo__calendar__btn__text genericBtnInfoDashboard__btn__text'>
542
-                      {this.props.t('Workspace Calendar')}
543
-                    </div>
544
-                  </div>
545
-                </div>
546
-                <div className='dashboard__moreinfo__calendar__wrapperText'>
547
-                  {this.state.displayCalendarBtn === true &&
548
-                  <div>
549
-                    <div className='dashboard__moreinfo__calendar__information genericBtnInfoDashboard__info'>
550
-                      <div className='dashboard__moreinfo__calendar__information__text genericBtnInfoDashboard__info__text'>
551
-                        {this.props.t('Each workspace has its own calendar.')}
552
-                      </div>
553
-
554
-                      <div className='dashboard__moreinfo__calendar__information__link genericBtnInfoDashboard__info__link'>
555
-                        http://algoo.trac.im/calendar/
556
-                      </div>
557
-                    </div>
558
-                  </div>
559
-                  }
560
-                </div>
561
-              </div>
562
-            </div>
563
-          </div>
564
-        </div>
565
-      </div>
566
-    )
567
-  }
568
-}
569
-
570
-const mapStateToProps = ({ user, app, contentType, workspaceList }) => ({ user, app, contentType, workspaceList })
571
-export default connect(mapStateToProps)(translate()(Dashboard))

+ 12 - 3
frontend/src/container/Sidebar.jsx View File

@@ -6,11 +6,14 @@ import { translate } from 'react-i18next'
6 6
 import appFactory from '../appFactory.js'
7 7
 import WorkspaceListItem from '../component/Sidebar/WorkspaceListItem.jsx'
8 8
 import {
9
+  setAppList,
10
+  setContentTypeList,
9 11
   setWorkspaceListIsOpenInSidebar,
10 12
   updateWorkspaceFilter,
11 13
   updateWorkspaceListData
12 14
 } from '../action-creator.sync.js'
13 15
 import {
16
+  getAppList, getContentTypeList,
14 17
   getWorkspaceList
15 18
 } from '../action-creator.async.js'
16 19
 import { PAGE, workspaceConfig } from '../helper.js'
@@ -32,13 +35,13 @@ class Sidebar extends React.Component {
32 35
     switch (type) {
33 36
       case 'refreshWorkspaceList':
34 37
         console.log('%c<Sidebar> Custom event', 'color: #28a745', type, data)
35
-        this.loadWorkspaceList()
38
+        this.loadAppConfigAndWorkspaceList()
36 39
         break
37 40
     }
38 41
   }
39 42
 
40 43
   componentDidMount () {
41
-    this.loadWorkspaceList()
44
+    this.loadAppConfigAndWorkspaceList()
42 45
   }
43 46
 
44 47
   componentDidUpdate (prevProps, prevState) {
@@ -49,11 +52,17 @@ class Sidebar extends React.Component {
49 52
     if (prevState.workspaceIdInUrl !== newWorkspaceId) this.setState({workspaceIdInUrl: newWorkspaceId})
50 53
   }
51 54
 
52
-  loadWorkspaceList = async () => {
55
+  loadAppConfigAndWorkspaceList = async () => {
53 56
     const { workspaceIdInUrl } = this.state
54 57
     const { user, dispatch } = this.props
55 58
 
56 59
     if (user.user_id !== -1) {
60
+      const fetchGetAppList = await dispatch(getAppList(user))
61
+      if (fetchGetAppList.status === 200) dispatch(setAppList(fetchGetAppList.json))
62
+
63
+      const fetchGetContentTypeList = await dispatch(getContentTypeList(user))
64
+      if (fetchGetContentTypeList.status === 200) dispatch(setContentTypeList(fetchGetContentTypeList.json))
65
+
57 66
       const fetchGetWorkspaceList = await dispatch(getWorkspaceList(user))
58 67
 
59 68
       if (fetchGetWorkspaceList.status === 200) {

+ 5 - 19
frontend/src/container/Tracim.jsx View File

@@ -15,15 +15,11 @@ import {
15 15
 import PrivateRoute from './PrivateRoute.jsx'
16 16
 import { COOKIE, PAGE } from '../helper.js'
17 17
 import {
18
-  getAppList,
19
-  getUserIsConnected,
20
-  getContentTypeList
18
+  getUserIsConnected
21 19
 } from '../action-creator.async.js'
22 20
 import {
23 21
   removeFlashMessage,
24
-  setAppList,
25
-  setUserConnected,
26
-  setContentTypeList
22
+  setUserConnected
27 23
 } from '../action-creator.sync.js'
28 24
 import Cookies from 'js-cookie'
29 25
 
@@ -54,24 +50,14 @@ class Tracim extends React.Component {
54 50
     const fetchGetUserIsConnected = await dispatch(getUserIsConnected(userFromCookies))
55 51
     switch (fetchGetUserIsConnected.status) {
56 52
       case 200:
57
-        const userLogged = {
53
+        dispatch(setUserConnected({
58 54
           ...fetchGetUserIsConnected.json,
59 55
           auth: userFromCookies.auth,
60 56
           logged: true
61
-        }
62
-
63
-        dispatch(setUserConnected(userLogged))
64
-
65
-        const fetchGetAppList = await dispatch(getAppList(userLogged))
66
-        if (fetchGetAppList.status === 200) dispatch(setAppList(fetchGetAppList.json))
67
-
68
-        const fetchGetContentTypeList = await dispatch(getContentTypeList(userLogged))
69
-        if (fetchGetContentTypeList.status === 200) dispatch(setContentTypeList(fetchGetContentTypeList.json))
57
+        }))
70 58
         break
71
-
72 59
       case 401:
73 60
         dispatch(setUserConnected({logged: false})); break
74
-
75 61
       default:
76 62
         dispatch(setUserConnected({logged: null})); break
77 63
     }
@@ -110,5 +96,5 @@ class Tracim extends React.Component {
110 96
   }
111 97
 }
112 98
 
113
-const mapStateToProps = ({ flashMessage }) => ({ flashMessage })
99
+const mapStateToProps = ({ user, appList, contentType, flashMessage }) => ({ user, appList, contentType, flashMessage })
114 100
 export default withRouter(connect(mapStateToProps)(translate()(Tracim)))

+ 1 - 1
frontend/src/container/WorkspaceContent.jsx View File

@@ -192,7 +192,7 @@ class WorkspaceContent extends React.Component {
192 192
             subtitle={workspaceContentList.label ? workspaceContentList.label : ''}
193 193
           >
194 194
             <DropdownCreateButton
195
-              parentClass='workspace__header__btnaddworkspace'
195
+              parentClass='workspace__header__btnaddcontent'
196 196
               idFolder={null} // null because it is workspace root content
197 197
               onClickCreateContent={this.handleClickCreateContent}
198 198
               availableApp={contentType}

+ 5 - 120
frontend/src/css/Dashboard.styl View File

@@ -59,7 +59,6 @@ coloricon()
59 59
   &__userstatut
60 60
     width 35%
61 61
     &__role
62
-      flexwrap()
63 62
       margin 20px 0
64 63
       font-size 18px
65 64
       &__msg
@@ -93,12 +92,15 @@ coloricon()
93 92
           font-size 30px
94 93
         &__title
95 94
           font-size 18px
96
-  &__wksinfo
95
+  &__workspaceInfo
97 96
     flexwrap()
98
-    margin-top 150px
99 97
   &__activity
100 98
     margin 0 35px 50px 0
101 99
     width 60%
100
+    &__wrapper
101
+      border 1px solid grey
102
+      height 480px
103
+      overflow-y scroll
102 104
     &__header
103 105
       display flex
104 106
       justify-content space-between
@@ -109,9 +111,6 @@ coloricon()
109 111
         padding 10px 25px
110 112
         font-size 18px
111 113
         cursor pointer
112
-    &__wrapper
113
-      border 1px solid grey
114
-      height 480px
115 114
     &__workspace
116 115
       display flex
117 116
       align-items center
@@ -137,120 +136,6 @@ coloricon()
137 136
         margin 15px
138 137
         padding 10px 25px
139 138
         cursor pointer
140
-  &__memberlist
141
-    margin 0 0 50px 0
142
-    width 35%
143
-    &__title
144
-      margin-bottom 20px
145
-      padding 6px
146
-      height 45px
147
-    &__wrapper
148
-      position relative
149
-      border 1px solid grey
150
-      height 480px
151
-    &__list
152
-      margin 0
153
-      padding 0
154
-      list-style none
155
-      height 400px
156
-      overflow-Y scroll
157
-      &__item
158
-        display flex
159
-        border-bottom 1px solid grey
160
-        padding 10px 15px
161
-        &:hover
162
-          background-color fourthColor
163
-        &:nth-last-child(1)
164
-          border-bottom 0
165
-        &:nth-child(even)
166
-          background-color grey-hover
167
-          &:hover
168
-            background-color fourthColor
169
-        &__avatar
170
-          margin-right 20px
171
-          & > img
172
-            width 50px
173
-            height 50px
174
-        &__info
175
-          &__name
176
-            font-size 20px
177
-          &__role
178
-            font-size 18px
179
-        &__delete
180
-          font-size 20px
181
-          color darkGrey
182
-          cursor pointer
183
-    &__btnadd
184
-      border-top 1px solid grey
185
-      padding 15px
186
-      &__button
187
-        display flex
188
-        align-items center
189
-        &__avatar
190
-          display flex
191
-          justify-content center
192
-          align-items center
193
-          margin-right 20px
194
-          border 2px dashed grey
195
-          border-radius 50%
196
-          width 50px
197
-          height 50px
198
-          cursor pointer
199
-          &__icon
200
-            color grey
201
-            font-size 25px
202
-        &__text
203
-          font-size 18px
204
-          color fontColor
205
-          cursor pointer
206
-    &__form
207
-      padding 15px
208
-      flex-direction column
209
-      height 100%
210
-      width 100%
211
-      background-color off-white
212
-      &__close
213
-        font-size 20px
214
-        & > i
215
-          cursor pointer
216
-      &__member
217
-        &__name
218
-          .name__label
219
-            margin 30px 0 20px 0
220
-            label()
221
-          .name__input
222
-            margin-bottom 20px
223
-            border 1px solid grey
224
-            border-radius 10px
225
-            padding 10px
226
-            width 300px
227
-        &__create
228
-          display flex
229
-          align-items center
230
-          margin 15px 0
231
-      &__role
232
-        margin-bottom 15px
233
-        coloricon()
234
-        &__text
235
-          margin 15px 0
236
-          label()
237
-        &__list
238
-          margin 0
239
-          padding 0
240
-          list-style none
241
-          &__item
242
-            display flex
243
-            align-items center
244
-            margin 10px 25px 10px 0
245
-            .item
246
-              &__text
247
-                display flex
248
-      &__submitbtn
249
-        display flex
250
-        justify-content flex-end
251
-        & > button
252
-          padding 8px 30px
253
-          cursor pointer
254 139
   &__moreinfo
255 140
     display flex
256 141
     justify-content space-between

+ 0 - 17
frontend/src/css/Generic.styl View File

@@ -198,23 +198,6 @@ a
198 198
   font-weight 500
199 199
   color thirdColor
200 200
 
201
-.btnaction
202
-  display flex
203
-  flex-direction column
204
-  justify-content center
205
-  margin 0 15px
206
-  border-radius 10px
207
-  padding 15px
208
-  width 230px
209
-  height 200px
210
-  box-shadow shadow-all
211
-  text-align center
212
-  cursor pointer
213
-  &:nth-child(1)
214
-    margin-left 0
215
-  &:nth-last-child
216
-    margin-right 0
217
-
218 201
 .genericBtnInfoDashboard
219 202
   &__btn
220 203
     display flex

+ 16 - 12
frontend/src/helper.js View File

@@ -45,24 +45,28 @@ export const PAGE = {
45 45
 
46 46
 export const ROLE = [{
47 47
   id: 0,
48
-  name: 'reader',
49
-  icon: 'fa-eye',
50
-  translationKey: 'role.reader'
48
+  slug: 'reader',
49
+  faIcon: 'eye',
50
+  hexcolor: '#15D948',
51
+  label: 'Reader'
51 52
 }, {
52 53
   id: 1,
53
-  name: 'contributor',
54
-  icon: 'fa-pencil',
55
-  translationKey: 'role.contributor'
54
+  slug: 'contributor',
55
+  faIcon: 'pencil',
56
+  hexcolor: '#3145F7',
57
+  label: 'Contributor'
56 58
 }, {
57 59
   id: 2,
58
-  name: 'content_manager',
59
-  icon: 'fa-graduation-cap',
60
-  translationKey: 'role.content_manager'
60
+  slug: 'content-manager',
61
+  faIcon: 'graduation-cap',
62
+  hexcolor: '#f2af2d',
63
+  label: 'Content manager'
61 64
 }, {
62 65
   id: 3,
63
-  name: 'manager',
64
-  icon: 'fa-gavel',
65
-  translationKey: 'role.manager'
66
+  slug: 'workspace-manager',
67
+  faIcon: 'gavel',
68
+  hexcolor: '#ed0007',
69
+  label: 'Workspace manager'
66 70
 }]
67 71
 
68 72
 export const handleRouteFromApi = route => route.startsWith('/#') ? route.slice(2) : route

+ 39 - 6
frontend/src/reducer/currentWorkspace.js View File

@@ -1,4 +1,10 @@
1
-import {SET, WORKSPACE_DETAIL, WORKSPACE_MEMBER_LIST} from '../action-creator.sync.js'
1
+import {
2
+  SET,
3
+  WORKSPACE_DETAIL,
4
+  WORKSPACE_MEMBER_LIST,
5
+  WORKSPACE_READ_STATUS_LIST,
6
+  WORKSPACE_RECENT_ACTIVITY_LIST
7
+} from '../action-creator.sync.js'
2 8
 import { handleRouteFromApi } from '../helper.js'
3 9
 
4 10
 const defaultWorkspace = {
@@ -6,8 +12,10 @@ const defaultWorkspace = {
6 12
   slug: '',
7 13
   label: '',
8 14
   description: '',
9
-  sidebarEntries: [],
10
-  member: []
15
+  sidebarEntryList: [],
16
+  memberList: [],
17
+  recentActivityList: [],
18
+  contentReadStatusList: []
11 19
 }
12 20
 
13 21
 export default function currentWorkspace (state = defaultWorkspace, action) {
@@ -19,7 +27,7 @@ export default function currentWorkspace (state = defaultWorkspace, action) {
19 27
         slug: action.workspaceDetail.slug,
20 28
         label: action.workspaceDetail.label,
21 29
         description: action.workspaceDetail.description,
22
-        sidebarEntries: action.workspaceDetail.sidebar_entries.map(sbe => ({
30
+        sidebarEntryList: action.workspaceDetail.sidebar_entries.map(sbe => ({
23 31
           slug: sbe.slug,
24 32
           route: handleRouteFromApi(sbe.route),
25 33
           faIcon: sbe.fa_icon,
@@ -31,15 +39,40 @@ export default function currentWorkspace (state = defaultWorkspace, action) {
31 39
     case `${SET}/${WORKSPACE_MEMBER_LIST}`:
32 40
       return {
33 41
         ...state,
34
-        member: action.workspaceMemberList.map(m => ({
42
+        memberList: action.workspaceMemberList.map(m => ({
35 43
           id: m.user_id,
36 44
           publicName: m.user.public_name,
37 45
           avatarUrl: m.user.avatar_url,
38 46
           role: m.role,
39
-          isActive: m.is_active,
47
+          isActive: m.is_active
40 48
         }))
41 49
       }
42 50
 
51
+    case `${SET}/${WORKSPACE_RECENT_ACTIVITY_LIST}`:
52
+      return {
53
+        ...state,
54
+        recentActivityList: action.workspaceRecentActivityList.map(ra => ({
55
+          id: ra.content_id,
56
+          slug: ra.slug,
57
+          label: ra.label,
58
+          type: ra.content_type,
59
+          idParent: ra.parent_id,
60
+          showInUi: ra.show_in_ui,
61
+          isArchived: ra.is_archived,
62
+          isDeleted: ra.is_deleted,
63
+          statusSlug: ra.status,
64
+          subContentTypeSlug: ra.sub_content_types
65
+        }))
66
+      }
67
+
68
+    case `${SET}/${WORKSPACE_READ_STATUS_LIST}`:
69
+      return {
70
+        ...state,
71
+        contentReadStatusList: action.workspaceReadStatusList
72
+          .filter(content => content.read_by_user)
73
+          .map(content => content.content_id)
74
+      }
75
+
43 76
     default:
44 77
       return state
45 78
   }

+ 1 - 1
frontend/src/reducer/workspaceContentList.js View File

@@ -16,7 +16,7 @@ export default function workspaceContentList (state = [], action) {
16 16
         type: wsc.content_type,
17 17
         idWorkspace: wsc.workspace_id,
18 18
         isArchived: wsc.is_archived,
19
-        parentId: wsc.parent_id,
19
+        idParent: wsc.parent_id,
20 20
         isDeleted: wsc.is_deleted,
21 21
         showInUi: wsc.show_in_ui,
22 22
         statusSlug: wsc.status,

+ 1 - 1
frontend_lib/dist/index.html View File

@@ -17,6 +17,6 @@
17 17
 
18 18
   <div id='content'></div>
19 19
 
20
-  <script type='text/javascript' src='./tracim_lib.dev.js'></script>
20
+  <script type='text/javascript' src='./tracim_frontend_lib.dev.js'></script>
21 21
 </body>
22 22
 </html>

File diff suppressed because it is too large
+ 0 - 15
frontend_lib/dist/tracim_lib.js


+ 2 - 2
frontend_lib/package.json View File

@@ -7,8 +7,8 @@
7 7
     "servdev": "NODE_ENV=development webpack-dev-server --watch --colors --inline --hot --progress",
8 8
     "servdevwindoz": "set NODE_ENV=development&& webpack-dev-server --watch --colors --inline --hot --progress",
9 9
     "servdev-dashboard": "NODE_ENV=development webpack-dashboard -m -p 9870 -- webpack-dev-server --watch --colors --inline --hot --progress",
10
-    "buildwindoz": "set NODE_ENV=production&& webpack -p",
11
-    "build": "NODE_ENV=production webpack -p",
10
+    "buildwindoz": "echo 'Only use npm run buildtracimlibwindoz'",
11
+    "build": "echo 'Only use npm run buildtracimlib'",
12 12
     "build-translation": "node i18next.scanner.js",
13 13
     "buildtracimlib": "NODE_ENV=production webpack -p && echo '/* eslint-disable */' | cat - dist/tracim_frontend_lib.js > temp && mv temp dist/tracim_frontend_lib.js && printf '\n/* eslint-enable */\n' >> dist/tracim_frontend_lib.js",
14 14
     "buildtracimlibwindoz": "set NODE_ENV=production&& webpack -p && echo /* eslint-disable */ | cat - dist/tracim_frontend_lib.js > temp && mv temp dist/tracim_frontend_lib.js && echo /* eslint-enable */>> dist/tracim_frontend_lib.js",

+ 68 - 0
frontend_lib/src/component/Input/Checkbox.jsx View File

@@ -0,0 +1,68 @@
1
+import React from 'react'
2
+import PropTypes from 'prop-types'
3
+import classnames from 'classnames'
4
+
5
+const style = {
6
+  label: {
7
+    position: 'relative',
8
+    width: '18px',
9
+    height: '18px',
10
+    border: '1px solid #999',
11
+    borderRadius: '3px',
12
+    backgroundColor: '#eee',
13
+    cursor: 'pointer'
14
+  },
15
+  checked: {
16
+    position: 'absolute',
17
+    top: '-3px',
18
+    left: '2px',
19
+    fontSize: '18px',
20
+    color: '#333'
21
+  },
22
+  input: {
23
+    width: '0',
24
+    height: '0',
25
+    visibility: 'hidden'
26
+  },
27
+  disabled: {
28
+    cursor: 'default'
29
+  }
30
+}
31
+
32
+export const Checkbox = props =>
33
+  <label
34
+    className={classnames('checkboxCustom', {'checked': props.checked})}
35
+    style={{
36
+      ...style.label,
37
+      ...(props.disabled ? style.disabled : {})
38
+    }}
39
+    onClick={props.onClickCheckbox}
40
+  >
41
+    { props.checked && <div className='checboxCustom__checked' style={style.checked}>✔</div> }
42
+    <input
43
+      type='checkbox'
44
+      name={`checkbox-${props.name}`}
45
+      checked={props.checked}
46
+      defaultChecked={props.defaultChecked}
47
+      onChange={() => {}} // to remove warning
48
+      style={style.input}
49
+      disabled={props.disabled}
50
+    />
51
+  </label>
52
+
53
+Checkbox.propTypes = {
54
+  name: PropTypes.string.isRequired,
55
+  onClickCheckbox: PropTypes.func.isRequired,
56
+  checked: PropTypes.bool,
57
+  defaultChecked: PropTypes.bool,
58
+  disabled: PropTypes.bool
59
+}
60
+
61
+Checkbox.defaultProps = {
62
+  name: '',
63
+  onClickCheckbox: () => {},
64
+  checked: false,
65
+  disabled: false
66
+}
67
+
68
+export default Checkbox

+ 7 - 0
frontend_lib/src/index.dev.js View File

@@ -8,6 +8,7 @@ import PopinFixedContent from './component/PopinFixed/PopinFixedContent.jsx'
8 8
 
9 9
 import TextAreaApp from './component/Input/TextAreaApp/TextAreaApp.jsx'
10 10
 import BtnSwitch from './component/Input/BtnSwitch/BtnSwitch.jsx'
11
+import Checkbox from './component/Input/Checkbox.jsx'
11 12
 
12 13
 import Timeline from './component/Timeline/Timeline.jsx'
13 14
 import TimelineDebugData from './component/Timeline/debugData.js'
@@ -17,6 +18,7 @@ import Delimiter from './component/Delimiter/Delimiter.jsx'
17 18
 import CardPopup from './component/CardPopup/CardPopup.jsx'
18 19
 import CardPopupCreateContent from './component/CardPopup/CardPopupCreateContent.jsx'
19 20
 
21
+
20 22
 import NewVersionButton from './component/OptionComponent/NewVersionBtn.jsx'
21 23
 import ArchiveDeleteContent from './component/OptionComponent/ArchiveDeleteContent.jsx'
22 24
 
@@ -78,6 +80,11 @@ ReactDOM.render(
78 80
           <span>Here will be the app content. Style is handled by the app (obviously)</span>
79 81
           <BtnSwitch />
80 82
           {/* <TextAreaApp customClass={'randomClass'} text={'woot'} /> */}
83
+          <Checkbox
84
+            name='osef'
85
+            onClickCheckbox={() => {}}
86
+            checked
87
+          />
81 88
         </div>
82 89
 
83 90
         <Timeline

+ 6 - 8
frontend_lib/src/index.js View File

@@ -1,8 +1,7 @@
1
-import { libAddAllResourceI18n, libHandleFetchResult } from './helper.js'
2
-
3
-// fr and en are deprecated
4
-import fr from './translate/fr.js'
5
-import en from './translate/en.js'
1
+import {
2
+  libAddAllResourceI18n,
3
+  libHandleFetchResult
4
+} from './helper.js'
6 5
 
7 6
 import libPopinFixed from './component/PopinFixed/PopinFixed.jsx'
8 7
 import libPopinFixedHeader from './component/PopinFixed/PopinFixedHeader.jsx'
@@ -13,6 +12,7 @@ import libTimeline from './component/Timeline/Timeline.jsx'
13 12
 
14 13
 import libTextAreaApp from './component/Input/TextAreaApp/TextAreaApp.jsx'
15 14
 import libBtnSwitch from './component/Input/BtnSwitch/BtnSwitch.jsx'
15
+import libCheckbox from './component/Input/Checkbox.jsx'
16 16
 
17 17
 import libPageWrapper from './component/Layout/PageWrapper.jsx'
18 18
 import libPageTitle from './component/Layout/PageTitle.jsx'
@@ -27,9 +27,6 @@ import libNewVersionBtn from './component/OptionComponent/NewVersionBtn.jsx'
27 27
 import libArchiveDeleteContent from './component/OptionComponent/ArchiveDeleteContent.jsx'
28 28
 import libSelectStatus from './component/Input/SelectStatus/SelectStatus.jsx'
29 29
 
30
-export const langFr = fr
31
-export const langEn = en
32
-
33 30
 export const addAllResourceI18n = libAddAllResourceI18n
34 31
 
35 32
 export const handleFetchResult = libHandleFetchResult
@@ -43,6 +40,7 @@ export const Timeline = libTimeline
43 40
 
44 41
 export const TextAreaApp = libTextAreaApp
45 42
 export const BtnSwitch = libBtnSwitch
43
+export const Checkbox = libCheckbox
46 44
 
47 45
 export const PageWrapper = libPageWrapper
48 46
 export const PageTitle = libPageTitle

+ 0 - 1
install_frontend_dependencies.sh View File

@@ -42,7 +42,6 @@ log "npm link tracim_frontend_lib"
42 42
 npm link tracim_frontend_lib
43 43
 cd -
44 44
 
45
-
46 45
 # install app Admin Workspace User
47 46
 
48 47
 log "cd frontend_app_admin_workspace_user"