Browse Source

refactor for Route names + removed unused reducer + added lib queryString

Skylsmoi 6 years ago
parent
commit
d77be956f0

+ 1 - 0
package.json View File

@@ -29,6 +29,7 @@
29 29
     "file-loader": "^1.1.5",
30 30
     "i18next": "^10.5.0",
31 31
     "prop-types": "^15.6.0",
32
+    "query-string": "^6.1.0",
32 33
     "react": "^16.0.0",
33 34
     "react-animate-height": "^0.10.10",
34 35
     "react-dom": "^16.0.0",

+ 2 - 3
src/action-creator.async.js View File

@@ -169,14 +169,13 @@ export const getWorkspaceList = (userId, workspaceIdToOpen) => async dispatch =>
169 169
   }
170 170
 }
171 171
 
172
-export const getWorkspaceContent = (workspaceId, filterStr) => async dispatch => {
173
-  const fetchGetWorkspaceContent = await fetchWrapper({
172
+export const getWorkspaceContent = workspaceId => dispatch => {
173
+  return fetchWrapper({
174 174
     url: `${FETCH_CONFIG.mockApiUrl}/workspace/${workspaceId}`,
175 175
     param: {...FETCH_CONFIG.header, method: 'GET'},
176 176
     actionName: WORKSPACE,
177 177
     dispatch
178 178
   })
179
-  if (fetchGetWorkspaceContent.status === 200) dispatch(setWorkspaceData(fetchGetWorkspaceContent.json, filterStr))
180 179
 }
181 180
 
182 181
 export const getFolderContent = (workspaceId, folderId) => async dispatch => {

+ 0 - 4
src/action-creator.sync.js View File

@@ -33,10 +33,6 @@ export const WORKSPACE_LIST = 'WorkspaceList'
33 33
 export const updateWorkspaceListData = workspaceList => ({ type: `Update/${WORKSPACE_LIST}`, workspaceList })
34 34
 export const setWorkspaceListIsOpenInSidebar = (workspaceId, isOpenInSidebar) => ({ type: `Set/${WORKSPACE_LIST}/isOpenInSidebar`, workspaceId, isOpenInSidebar })
35 35
 
36
-export const FILE_CONTENT = 'FileContent'
37
-export const setActiveFileContentActive = file => ({ type: `Set/${FILE_CONTENT}/Active`, file })
38
-export const setActiveFileContentHide = () => ({ type: `Set/${FILE_CONTENT}/Hide` })
39
-
40 36
 export const APP_LIST = 'App/List'
41 37
 export const setAppList = appList => ({ type: `Set/${APP_LIST}`, appList })
42 38
 

+ 2 - 2
src/component/Header/MenuActionListItem/MenuProfil.jsx View File

@@ -1,7 +1,7 @@
1 1
 import React from 'react'
2 2
 import { Link } from 'react-router-dom'
3 3
 import PropTypes from 'prop-types'
4
-import { PAGE_NAME } from '../../../helper.js'
4
+import { PAGE } from '../../../helper.js'
5 5
 
6 6
 const MenuProfil = props => {
7 7
   return props.user.logged
@@ -15,7 +15,7 @@ const MenuProfil = props => {
15 15
             </div>
16 16
           </button>
17 17
           <div className='profilgroup__setting dropdown-menu' aria-labelledby='dropdownMenuButton'>
18
-            <Link className='setting__link dropdown-item' to={PAGE_NAME.ACCOUNT}>Mon compte</Link>
18
+            <Link className='setting__link dropdown-item' to={PAGE.ACCOUNT}>Mon compte</Link>
19 19
             {/* <div className='setting__link dropdown-item'>Mot de passe</div> */}
20 20
             <div className='setting__link dropdown-item' onClick={props.onClickLogout}>Se déconnecter</div>
21 21
           </div>

+ 2 - 2
src/component/Sidebar/WorkspaceListItem.jsx View File

@@ -33,7 +33,7 @@ const WorkspaceListItem = props => {
33 33
         >
34 34
           <li
35 35
             className='sidebar__navigation__workspace__item__submenu__dropdown'
36
-            onClick={() => props.onClickAllContent(props.wsId)}
36
+            onClick={() => props.onClickAllContent(props.idWs)}
37 37
           >
38 38
             <div className='dropdown__icon'>
39 39
               <i className='fa fa-th' />
@@ -89,7 +89,7 @@ const WorkspaceListItem = props => {
89 89
           { Object.keys(props.app).map(a =>
90 90
             <li
91 91
               className={classnames('sidebar__navigation__workspace__item__submenu__dropdown', {'activeFilter': props.activeFilterList.includes(a)})}
92
-              onClick={() => props.onClickContentFilter(props.wsId, a)}
92
+              onClick={() => props.onClickContentFilter(props.idWs, a)}
93 93
               key={a}
94 94
             >
95 95
               <div className='dropdown__icon'>

+ 2 - 2
src/container/Login.jsx View File

@@ -16,7 +16,7 @@ import {
16 16
   newFlashMessage,
17 17
   setUserConnected
18 18
 } from '../action-creator.sync.js'
19
-import {PAGE_NAME} from '../helper.js'
19
+import {PAGE} from '../helper.js'
20 20
 
21 21
 class Login extends React.Component {
22 22
   constructor (props) {
@@ -46,7 +46,7 @@ class Login extends React.Component {
46 46
 
47 47
     if (fetchPostUserLogin.status === 200) {
48 48
       dispatch(setUserConnected({...fetchPostUserLogin.json, logged: true}))
49
-      history.push(PAGE_NAME.HOME)
49
+      history.push(PAGE.HOME)
50 50
     } else if (fetchPostUserLogin.status === 400) {
51 51
       dispatch(newFlashMessage(t('Login.fail'), 'danger'))
52 52
     }

+ 7 - 7
src/container/Sidebar.jsx View File

@@ -9,7 +9,7 @@ import {
9 9
   setWorkspaceListIsOpenInSidebar,
10 10
   updateWorkspaceFilter
11 11
 } from '../action-creator.sync.js'
12
-import { PAGE_NAME } from '../helper.js'
12
+import { PAGE } from '../helper.js'
13 13
 
14 14
 class Sidebar extends React.Component {
15 15
   constructor (props) {
@@ -38,22 +38,22 @@ class Sidebar extends React.Component {
38 38
     user.id !== -1 && prevProps.user.id !== user.id && dispatch(getWorkspaceList(user.id, newWorkspaceId))
39 39
   }
40 40
 
41
-  handleClickWorkspace = (wsId, newIsOpenInSidebar) => this.props.dispatch(setWorkspaceListIsOpenInSidebar(wsId, newIsOpenInSidebar))
41
+  handleClickWorkspace = (idWs, newIsOpenInSidebar) => this.props.dispatch(setWorkspaceListIsOpenInSidebar(idWs, newIsOpenInSidebar))
42 42
 
43
-  handleClickAllContent = wsId => {
43
+  handleClickAllContent = idWs => {
44 44
     this.props.dispatch(updateWorkspaceFilter([]))
45 45
 
46
-    this.props.history.push(`${PAGE_NAME.WS_CONTENT}/${wsId}`)
46
+    this.props.history.push(PAGE.WORKSPACE.CONTENT_LIST(idWs))
47 47
   }
48 48
 
49
-  handleClickContentFilter = (wsId, filter) => {
49
+  handleClickContentFilter = (idWs, filter) => {
50 50
     const { workspace, history, dispatch } = this.props
51 51
 
52 52
     const newFilter = workspace.filter.includes(filter) ? [] : [filter] // use an array to allow multiple filters (NYI)
53 53
 
54 54
     dispatch(updateWorkspaceFilter(newFilter))
55 55
 
56
-    history.push(`${PAGE_NAME.WS_CONTENT}/${wsId}/${newFilter.join(';')}`) // workspace.filter gets updated on react redraw from match.params
56
+    history.push(`${PAGE.WORKSPACE.CONTENT_LIST(idWs)}?type=${newFilter.join(';')}`) // workspace.filter gets updated on react redraw from match.params
57 57
   }
58 58
 
59 59
   handleClickToggleSidebar = () => this.setState(prev => ({sidebarClose: !prev.sidebarClose}))
@@ -74,7 +74,7 @@ class Sidebar extends React.Component {
74 74
               { workspaceList.map((ws, i) =>
75 75
                 <WorkspaceListItem
76 76
                   number={++i}
77
-                  wsId={ws.id}
77
+                  idWs={ws.id}
78 78
                   name={ws.title}
79 79
                   app={app}
80 80
                   lang={activeLang}

+ 7 - 6
src/container/Tracim.jsx View File

@@ -14,7 +14,7 @@ import {
14 14
   withRouter
15 15
 } from 'react-router-dom'
16 16
 import PrivateRoute from './PrivateRoute.jsx'
17
-import { PAGE_NAME } from '../helper.js'
17
+import { PAGE } from '../helper.js'
18 18
 import {
19 19
   getLangList,
20 20
   getUserIsConnected
@@ -55,12 +55,13 @@ class Tracim extends React.Component {
55 55
           ? (<div />) // while we dont know if user is connected, display nothing but the header @TODO show loader
56 56
           : (
57 57
             <div className='tracim__content'>
58
-              <Route path={PAGE_NAME.LOGIN} component={Login} />
58
+              <Route path={PAGE.LOGIN} component={Login} />
59 59
 
60
-              <PrivateRoute exact path={PAGE_NAME.HOME} component={WorkspaceContent} />
61
-              <PrivateRoute path={`${PAGE_NAME.WS_CONTENT}/:idws/:filter?`} component={WorkspaceContent} />
62
-              <PrivateRoute exact path={PAGE_NAME.ACCOUNT} component={Account} />
63
-              <PrivateRoute exact path={PAGE_NAME.DASHBOARD} component={Dashboard} />
60
+              <PrivateRoute exact path={PAGE.HOME} component={WorkspaceContent} />
61
+              <PrivateRoute path={PAGE.WORKSPACE.CONTENT_LIST(':idws')} component={WorkspaceContent} />
62
+              <PrivateRoute path={PAGE.WORKSPACE.CONTENT(':idws', ':idcts')} component={WorkspaceContent} />
63
+              <PrivateRoute exact path={PAGE.ACCOUNT} component={Account} />
64
+              <PrivateRoute exact path={PAGE.WORKSPACE.DASHBOARD(':idws')} component={Dashboard} />
64 65
               <PrivateRoute path={'/wip/:cp'} component={WIPcomponent} /> {/* for testing purpose only */}
65 66
 
66 67
               <Footer />

+ 24 - 16
src/container/WorkspaceContent.jsx View File

@@ -14,33 +14,41 @@ import {
14 14
   getWorkspaceContent,
15 15
   getFolderContent
16 16
 } from '../action-creator.async.js'
17
+import {newFlashMessage, setWorkspaceData} from '../action-creator.sync.js'
18
+import { PAGE } from '../helper.js'
19
+
20
+const qs = require('query-string')
17 21
 
18 22
 class WorkspaceContent extends React.Component {
19
-  componentDidMount () {
20
-    const { workspaceList, app, match, dispatch } = this.props
23
+  async componentDidMount () {
24
+    const { workspaceList, app, match, location, dispatch } = this.props
21 25
 
22
-    if (match.params.idws !== undefined) dispatch(getWorkspaceContent(match.params.idws, match.params.filter))
23
-    else if (workspaceList.length > 0) dispatch(getWorkspaceContent(workspaceList[0].id, match.params.filter)) // load first ws if none specified
26
+    if (Object.keys(app).length === 0) await dispatch(getAppList())
24 27
 
25
-    if (Object.keys(app).length === 0) dispatch(getAppList())
26
-  }
28
+    const wsToLoad = (() => {
29
+      if (match.params.idws !== undefined) return match.params.idws
30
+      if (workspaceList.length > 0) return workspaceList[0].id // load first ws if none specified
31
+      return null
32
+    })()
33
+
34
+    if (wsToLoad === null) return
27 35
 
28
-  componentDidUpdate (prevProps) {
29
-    const { workspace, workspaceList, match, dispatch } = this.props
36
+    const wsContent = await dispatch(getWorkspaceContent(wsToLoad))
37
+    if (wsContent.status === 200) {
38
+      dispatch(setWorkspaceData(wsContent.json, qs.parse(location.search).type))
30 39
 
31
-    // if a workspace is already loaded and the idws in url hasn't changed, do nothing
32
-    if (workspace.id !== -1 && prevProps.match.params.idws === match.params.idws) return
40
+      if (match.params.idcts) { // if a content id is in url, open it
41
+        const contentToOpen = wsContent.json.content.find(wsc => wsc.id === parseInt(match.params.idcts))
42
+        if (contentToOpen === undefined) return
33 43
 
34
-    // if the idws in url has changed, load the new workspace
35
-    if (match.params.idws !== undefined) dispatch(getWorkspaceContent(match.params.idws, match.params.filter))
36
-    // else bellow is for loading url PAGE_NAME.HOME (without an idws), when workspaceList is loaded, load the first workspace
37
-    else if (workspace.id === -1 && workspaceList.length > 0) dispatch(getWorkspaceContent(workspaceList[0].id))
44
+        this.handleClickContentItem(contentToOpen)
45
+      }
46
+    } else dispatch(newFlashMessage('Error while loading workspace', 'danger'))
38 47
   }
39 48
 
40 49
   handleClickContentItem = content => {
50
+    this.props.history.push(`${PAGE.WORKSPACE.CONTENT(content.workspace_id, content.id)}${this.props.location.search}`)
41 51
     this.props.renderApp(this.props.app[content.type], this.props.user, {...content, workspace: this.props.workspace})
42
-    // Côme - 2018/03/08 - line bellow is useless because we cannot call the reducer again when hiding app since the call comes from the app
43
-    // dispatch(setActiveFileContentActive(content))
44 52
   }
45 53
 
46 54
   handleClickEditContentItem = (e, content) => {

+ 12 - 3
src/helper.js View File

@@ -7,11 +7,20 @@ export const FETCH_CONFIG = {
7 7
   mockApiUrl: 'http://localhost:3001'
8 8
 }
9 9
 
10
-export const PAGE_NAME = {
10
+export const PAGE = {
11 11
   HOME: '/',
12
-  WS_CONTENT: '/workspace',
12
+  WORKSPACE: {
13
+    DASHBOARD: idws => `/workspace/${idws}`,
14
+    NEW: '/workspace/new',
15
+    CALENDAR: idws => `/workspace/${idws}/apps/calendar`,
16
+    CONTENT_LIST: idws => `/workspace/${idws}/apps/contents`,
17
+    CONTENT: (idws, idcts) => `/workspace/${idws}/apps/contents/${idcts}`,
18
+    CONTENT_NEW: (idws, ctstype) => `/workspace/${idws}/apps/contents/${ctstype}/new`,
19
+    CONTENT_EDIT: (idws, idcts) => `/workspace/${idws}/apps/contents/${idcts}/edit`,
20
+    CONTENT_TITLE_EDIT: (idws, idcts) => `/workspace/${idws}/apps/contents/${idcts}/title/edit`,
21
+    ADMIN: idws => `/workspace/${idws}/admin`
22
+  },
13 23
   LOGIN: '/login',
14
-  DASHBOARD: '/dashboard',
15 24
   ACCOUNT: '/account'
16 25
 }
17 26
 

+ 0 - 19
src/reducer/activeFileContent.js View File

@@ -1,19 +0,0 @@
1
-import { FILE_CONTENT } from '../action-creator.sync.js'
2
-
3
-export default function activeFileContent (state = {
4
-  display: false,
5
-  type: '',
6
-  title: '',
7
-  status: ''
8
-}, action) {
9
-  switch (action.type) {
10
-    case `Set/${FILE_CONTENT}/Active`:
11
-      return {...action.file, display: true}
12
-
13
-    case `Set/${FILE_CONTENT}/Hide`:
14
-      return {...state, display: false}
15
-
16
-    default:
17
-      return state
18
-  }
19
-}

+ 1 - 2
src/reducer/root.js View File

@@ -4,10 +4,9 @@ import flashMessage from './flashMessage.js'
4 4
 import user from './user.js'
5 5
 import workspace from './workspace.js'
6 6
 import workspaceList from './workspaceList.js'
7
-import activeFileContent from './activeFileContent.js'
8 7
 import app from './app.js'
9 8
 import timezone from './timezone.js'
10 9
 
11
-const rootReducer = combineReducers({ lang, flashMessage, user, workspace, workspaceList, activeFileContent, app, timezone })
10
+const rootReducer = combineReducers({ lang, flashMessage, user, workspace, workspaceList, app, timezone })
12 11
 
13 12
 export default rootReducer