Sfoglia il codice sorgente

[https://github.com/tracim/tracim/issues/759] added 'contents' to routes + refactor <Route> for React Router

Skylsmoi 5 anni fa
parent
commit
024da22495

+ 2 - 5
frontend/src/component/Workspace/OpenContentApp.jsx Vedi File

22
       console.log('%c<OpenContentApp> contentToOpen', 'color: #dcae84', contentToOpen)
22
       console.log('%c<OpenContentApp> contentToOpen', 'color: #dcae84', contentToOpen)
23
 
23
 
24
       if (appOpenedType === contentToOpen.type) { // app already open
24
       if (appOpenedType === contentToOpen.type) { // app already open
25
-        dispatchCustomEvent({
26
-          type: `${contentToOpen.type}_reloadContent`, // handled by html-document:src/container/AdminWorkspaceUser.jsx
27
-          data: contentToOpen
28
-        })
25
+        dispatchCustomEvent(`${contentToOpen.type}_reloadContent`, contentToOpen)
29
       } else { // open another app
26
       } else { // open another app
30
         // if another app is already visible, hide it
27
         // if another app is already visible, hide it
31
-        if (appOpenedType !== false) dispatchCustomEvent({type: `${appOpenedType}_hideApp`})
28
+        if (appOpenedType !== false) dispatchCustomEvent(`${appOpenedType}_hideApp`, {})
32
         // open app
29
         // open app
33
         renderAppFeature(
30
         renderAppFeature(
34
           contentType.find(ct => ct.slug === contentToOpen.type),
31
           contentType.find(ct => ct.slug === contentToOpen.type),

+ 1 - 4
frontend/src/container/Account.jsx Vedi File

1
 import React from 'react'
1
 import React from 'react'
2
 import { connect } from 'react-redux'
2
 import { connect } from 'react-redux'
3
-import Sidebar from './Sidebar.jsx'
4
 import UserInfo from '../component/Account/UserInfo.jsx'
3
 import UserInfo from '../component/Account/UserInfo.jsx'
5
 import MenuSubComponent from '../component/Account/MenuSubComponent.jsx'
4
 import MenuSubComponent from '../component/Account/MenuSubComponent.jsx'
6
 import PersonalData from '../component/Account/PersonalData.jsx'
5
 import PersonalData from '../component/Account/PersonalData.jsx'
102
     })()
101
     })()
103
 
102
 
104
     return (
103
     return (
105
-      <div className='sidebarpagecontainer'>
106
-        <Sidebar />
107
-
104
+      <div className='Account'>
108
         <PageWrapper customClass='account'>
105
         <PageWrapper customClass='account'>
109
           <PageTitle
106
           <PageTitle
110
             parentClass={'account'}
107
             parentClass={'account'}

+ 1 - 4
frontend/src/container/AppFullscreenManager.jsx Vedi File

4
 import { Route } from 'react-router-dom'
4
 import { Route } from 'react-router-dom'
5
 import { PAGE } from '../helper.js'
5
 import { PAGE } from '../helper.js'
6
 import appFactory from '../appFactory.js'
6
 import appFactory from '../appFactory.js'
7
-import Sidebar from './Sidebar.jsx'
8
 
7
 
9
 class AppFullscreenManager extends React.Component {
8
 class AppFullscreenManager extends React.Component {
10
   constructor (props) {
9
   constructor (props) {
20
     const { props } = this
19
     const { props } = this
21
 
20
 
22
     return (
21
     return (
23
-      <div className='sidebarpagecontainer'>
24
-        <Sidebar />
25
-
22
+      <div className='AppFullScreenManager'>
26
         <div id='appFullscreenContainer' />
23
         <div id='appFullscreenContainer' />
27
 
24
 
28
         {this.state.AmIMounted && (// we must wait for the component to be fully mounted to be sure the div#appFullscreenContainer exists in DOM
25
         {this.state.AmIMounted && (// we must wait for the component to be fully mounted to be sure the div#appFullscreenContainer exists in DOM

+ 1 - 4
frontend/src/container/Dashboard.jsx Vedi File

1
 import React from 'react'
1
 import React from 'react'
2
 import { connect } from 'react-redux'
2
 import { connect } from 'react-redux'
3
-import Sidebar from './Sidebar.jsx'
4
 import { translate } from 'react-i18next'
3
 import { translate } from 'react-i18next'
5
 import {
4
 import {
6
   PageWrapper,
5
   PageWrapper,
93
     const { props, state } = this
92
     const { props, state } = this
94
 
93
 
95
     return (
94
     return (
96
-      <div className='sidebarpagecontainer'>
97
-        <Sidebar />
98
-
95
+      <div className='Dashboard' style={{width: '100%'}}>
99
         <PageWrapper customeClass='dashboard'>
96
         <PageWrapper customeClass='dashboard'>
100
           <PageTitle
97
           <PageTitle
101
             parentClass='dashboard__header'
98
             parentClass='dashboard__header'

+ 2 - 2
frontend/src/container/Login.jsx Vedi File

55
       Cookies.set(COOKIE.USER_LOGIN, inputLogin.value)
55
       Cookies.set(COOKIE.USER_LOGIN, inputLogin.value)
56
       Cookies.set(COOKIE.USER_AUTH, userAuth)
56
       Cookies.set(COOKIE.USER_AUTH, userAuth)
57
 
57
 
58
-      history.push(PAGE.HOME)
59
-    } else if (fetchPostUserLogin.status === 400) {
58
+      history.push(PAGE.WORKSPACE.ROOT)
59
+    } else if (fetchPostUserLogin.status === 403) {
60
       dispatch(newFlashMessage(t('Email or password invalid'), 'danger'))
60
       dispatch(newFlashMessage(t('Email or password invalid'), 'danger'))
61
     }
61
     }
62
   }
62
   }

+ 6 - 3
frontend/src/container/Sidebar.jsx Vedi File

25
     super(props)
25
     super(props)
26
     this.state = {
26
     this.state = {
27
       sidebarClose: false,
27
       sidebarClose: false,
28
-      workspaceIdInUrl: props.match.params.idws ? parseInt(props.match.params.idws) : null
28
+      workspaceIdInUrl: props.match && props.match.params.idws ? parseInt(props.match.params.idws) : null
29
     }
29
     }
30
 
30
 
31
     document.addEventListener('appCustomEvent', this.customEventReducer)
31
     document.addEventListener('appCustomEvent', this.customEventReducer)
41
   }
41
   }
42
 
42
 
43
   componentDidMount () {
43
   componentDidMount () {
44
+    // console.log('Sidebar Did Mount', this.props)
44
     this.loadAppConfigAndWorkspaceList()
45
     this.loadAppConfigAndWorkspaceList()
45
   }
46
   }
46
 
47
 
47
   componentDidUpdate (prevProps, prevState) {
48
   componentDidUpdate (prevProps, prevState) {
49
+    const { props } = this
50
+
48
     // console.log('%c<Sidebar> Did Update', 'color: #c17838')
51
     // console.log('%c<Sidebar> Did Update', 'color: #c17838')
49
-    if (this.props.match.params.idws === undefined || isNaN(this.props.match.params.idws)) return
52
+    if (!props.match || props.match.params.idws === undefined || isNaN(props.match.params.idws)) return
50
 
53
 
51
-    const newWorkspaceId = parseInt(this.props.match.params.idws)
54
+    const newWorkspaceId = parseInt(props.match.params.idws)
52
     if (prevState.workspaceIdInUrl !== newWorkspaceId) this.setState({workspaceIdInUrl: newWorkspaceId})
55
     if (prevState.workspaceIdInUrl !== newWorkspaceId) this.setState({workspaceIdInUrl: newWorkspaceId})
53
   }
56
   }
54
 
57
 

+ 48 - 17
frontend/src/container/Tracim.jsx Vedi File

1
 import React from 'react'
1
 import React from 'react'
2
 import { connect } from 'react-redux'
2
 import { connect } from 'react-redux'
3
 import { translate } from 'react-i18next'
3
 import { translate } from 'react-i18next'
4
+import Sidebar from './Sidebar.jsx'
4
 import Header from './Header.jsx'
5
 import Header from './Header.jsx'
5
 import Login from './Login.jsx'
6
 import Login from './Login.jsx'
6
-import Dashboard from './Dashboard.jsx'
7
 import Account from './Account.jsx'
7
 import Account from './Account.jsx'
8
 import AppFullscreenManager from './AppFullscreenManager.jsx'
8
 import AppFullscreenManager from './AppFullscreenManager.jsx'
9
 import FlashMessage from '../component/FlashMessage.jsx'
9
 import FlashMessage from '../component/FlashMessage.jsx'
10
 import WorkspaceContent from './WorkspaceContent.jsx'
10
 import WorkspaceContent from './WorkspaceContent.jsx'
11
 import WIPcomponent from './WIPcomponent.jsx'
11
 import WIPcomponent from './WIPcomponent.jsx'
12
 import {
12
 import {
13
-  Route, withRouter, Switch
13
+  Route, withRouter, Redirect
14
 } from 'react-router-dom'
14
 } from 'react-router-dom'
15
-import PrivateRoute from './PrivateRoute.jsx'
16
 import { COOKIE, PAGE } from '../helper.js'
15
 import { COOKIE, PAGE } from '../helper.js'
17
 import {
16
 import {
18
   getUserIsConnected
17
   getUserIsConnected
22
   setUserConnected
21
   setUserConnected
23
 } from '../action-creator.sync.js'
22
 } from '../action-creator.sync.js'
24
 import Cookies from 'js-cookie'
23
 import Cookies from 'js-cookie'
24
+import Dashboard from './Dashboard.jsx'
25
 
25
 
26
 class Tracim extends React.Component {
26
 class Tracim extends React.Component {
27
   constructor (props) {
27
   constructor (props) {
40
   }
40
   }
41
 
41
 
42
   async componentDidMount () {
42
   async componentDidMount () {
43
+    // console.log('<Tracim> did Mount')
43
     const { dispatch } = this.props
44
     const { dispatch } = this.props
44
 
45
 
45
     const userFromCookies = {
46
     const userFromCookies = {
66
   handleRemoveFlashMessage = msg => this.props.dispatch(removeFlashMessage(msg))
67
   handleRemoveFlashMessage = msg => this.props.dispatch(removeFlashMessage(msg))
67
 
68
 
68
   render () {
69
   render () {
69
-    const { flashMessage, t } = this.props
70
+    const { props } = this
70
 
71
 
71
     return (
72
     return (
72
       <div className='tracim'>
73
       <div className='tracim'>
73
         <Header />
74
         <Header />
74
-        <FlashMessage flashMessage={flashMessage} removeFlashMessage={this.handleRemoveFlashMessage} t={t} />
75
+        <FlashMessage flashMessage={props.flashMessage} removeFlashMessage={this.handleRemoveFlashMessage} t={props.t} />
75
 
76
 
76
         <div className='tracim__content'>
77
         <div className='tracim__content'>
77
           <Route path={PAGE.LOGIN} component={Login} />
78
           <Route path={PAGE.LOGIN} component={Login} />
78
 
79
 
79
-          <PrivateRoute exact path='/' component={WorkspaceContent} />
80
-
81
-          <Switch>
82
-            <PrivateRoute path={PAGE.WORKSPACE.DASHBOARD(':idws')} component={Dashboard} />
83
-            <PrivateRoute path={PAGE.WORKSPACE.CALENDAR(':idws')} component={() => <div><br /><br /><br /><br />NYI</div>} />
84
-            <PrivateRoute path={PAGE.WORKSPACE.CONTENT(':idws', ':type?', ':idcts?')} component={WorkspaceContent} />
85
-          </Switch>
86
-
87
-          <PrivateRoute path={PAGE.ACCOUNT} component={Account} />
88
-          <PrivateRoute path={PAGE.ADMIN.ROOT} component={AppFullscreenManager} />
89
-          <PrivateRoute path={'/wip/:cp'} component={WIPcomponent} /> {/* for testing purpose only */}
80
+          <Route exact path='/' component={() => {
81
+            switch (props.user.logged) {
82
+              case true:
83
+                return <Redirect to={{pathname: PAGE.WORKSPACE.ROOT, state: {from: props.location}}} />
84
+              case false:
85
+                return <Redirect to={{pathname: '/login', state: {from: props.location}}} />
86
+              case null:
87
+                return null
88
+            }
89
+          }} />
90
+
91
+          { props.user.logged
92
+            ? (
93
+              <Route path='/workspaces/:idws?' render={() => // Workspace Router
94
+                <div className='sidebarpagecontainer'>
95
+                  <Sidebar />
96
+
97
+                  <Route exact path={PAGE.WORKSPACE.ROOT} render={() => props.workspaceList.length === 0 // handle '/' and redirect to first workspace
98
+                    ? null
99
+                    : <Redirect to={{pathname: `/workspaces/${props.workspaceList[0].id}/contents`, state: {from: props.location}}} />
100
+                  } />
101
+
102
+                  <Route exact path={`${PAGE.WORKSPACE.ROOT}/:idws`} render={props2 => // handle '/workspaces/:id' and add '/contents'
103
+                    <Redirect to={{pathname: `/workspaces/${props2.match.params.idws}/contents`, state: {from: props.location}}} />
104
+                  } />
105
+
106
+                  <Route path={PAGE.WORKSPACE.DASHBOARD(':idws')} component={Dashboard} />
107
+                  <Route path={PAGE.WORKSPACE.CALENDAR(':idws')} component={() => <div><br /><br /><br /><br />NYI</div>} />
108
+                  <Route path={PAGE.WORKSPACE.CONTENT(':idws', ':type', ':idcts')} component={WorkspaceContent} />
109
+                  <Route exact path={PAGE.WORKSPACE.CONTENT_LIST(':idws')} component={WorkspaceContent} />
110
+
111
+                  <Route path={PAGE.ACCOUNT} component={Account} />
112
+                  <Route path={PAGE.ADMIN.ROOT} component={AppFullscreenManager} />
113
+                </div>
114
+              } />
115
+            )
116
+            : props.user.logged === false && props.location.pathname !== '/login' &&
117
+              <Redirect to={{pathname: '/login', state: {from: props.location}}} />
118
+          }
119
+
120
+          <Route path={'/wip/:cp'} component={WIPcomponent} /> {/* for testing purpose only */}
90
 
121
 
91
           <div id='appFeatureContainer' />
122
           <div id='appFeatureContainer' />
92
         </div>
123
         </div>
96
   }
127
   }
97
 }
128
 }
98
 
129
 
99
-const mapStateToProps = ({ user, appList, contentType, flashMessage }) => ({ user, appList, contentType, flashMessage })
130
+const mapStateToProps = ({ user, appList, contentType, workspaceList, flashMessage }) => ({ user, appList, contentType, workspaceList, flashMessage })
100
 export default withRouter(connect(mapStateToProps)(translate()(Tracim)))
131
 export default withRouter(connect(mapStateToProps)(translate()(Tracim)))

+ 3 - 5
frontend/src/container/WorkspaceContent.jsx Vedi File

3
 import { withRouter, Route } from 'react-router-dom'
3
 import { withRouter, Route } from 'react-router-dom'
4
 import appFactory from '../appFactory.js'
4
 import appFactory from '../appFactory.js'
5
 import { PAGE } from '../helper.js'
5
 import { PAGE } from '../helper.js'
6
-import Sidebar from './Sidebar.jsx'
7
 import Folder from '../component/Workspace/Folder.jsx'
6
 import Folder from '../component/Workspace/Folder.jsx'
8
 import ContentItem from '../component/Workspace/ContentItem.jsx'
7
 import ContentItem from '../component/Workspace/ContentItem.jsx'
9
 import ContentItemHeader from '../component/Workspace/ContentItemHeader.jsx'
8
 import ContentItemHeader from '../component/Workspace/ContentItemHeader.jsx'
108
 
107
 
109
   handleClickContentItem = content => {
108
   handleClickContentItem = content => {
110
     console.log('%c<WorkspaceContent> content clicked', 'color: #c17838', content)
109
     console.log('%c<WorkspaceContent> content clicked', 'color: #c17838', content)
111
-    this.props.history.push(`/workspaces/${content.idWorkspace}/${content.type}/${content.id}`)
110
+    // this.props.history.push(`/workspaces/${content.idWorkspace}/${content.type}/${content.id}`)
111
+    this.props.history.push(PAGE.WORKSPACE.CONTENT(content.idWorkspace, content.type, content.id))
112
   }
112
   }
113
 
113
 
114
   handleClickEditContentItem = (e, content) => {
114
   handleClickEditContentItem = (e, content) => {
166
       : []
166
       : []
167
 
167
 
168
     return (
168
     return (
169
-      <div className='sidebarpagecontainer'>
170
-        <Sidebar />
171
-
169
+      <div className='WorkspaceContent' style={{width: '100%'}}>
172
         <OpenContentApp
170
         <OpenContentApp
173
           // automatically open the app for the idContent in url
171
           // automatically open the app for the idContent in url
174
           idWorkspace={this.state.workspaceIdInUrl}
172
           idWorkspace={this.state.workspaceIdInUrl}

+ 0 - 1
frontend/src/css/Dashboard.styl Vedi File

31
     color lecteur
31
     color lecteur
32
 
32
 
33
 .dashboard
33
 .dashboard
34
-  margin-left 20px
35
   width 100%
34
   width 100%
36
   &__header
35
   &__header
37
     flexwrap()
36
     flexwrap()

+ 1 - 1
frontend/src/css/Generic.styl Vedi File

111
 
111
 
112
 
112
 
113
 .pageContentGeneric
113
 .pageContentGeneric
114
-  margin 10px 0 0 0
114
+  margin 10px 15px 0 15px
115
   width 100%
115
   width 100%
116
   height 100%
116
   height 100%
117
 
117
 

+ 0 - 1
frontend/src/css/Workspace.styl Vedi File

4
     flex-wrap wrap
4
     flex-wrap wrap
5
     margin-right 15px
5
     margin-right 15px
6
   &__content
6
   &__content
7
-    margin 0 15px
8
     &__button
7
     &__button
9
       display flex
8
       display flex
10
       justify-content flex-end
9
       justify-content flex-end

+ 3 - 5
frontend/src/helper.js Vedi File

24
 export const PAGE = {
24
 export const PAGE = {
25
   HOME: '/',
25
   HOME: '/',
26
   WORKSPACE: {
26
   WORKSPACE: {
27
+    ROOT: '/workspaces',
27
     DASHBOARD: (idws = ':idws') => `/workspaces/${idws}/dashboard`,
28
     DASHBOARD: (idws = ':idws') => `/workspaces/${idws}/dashboard`,
28
-    NEW: (idws, type) => `/workspaces/${idws}/${type}/new`,
29
+    NEW: (idws, type) => `/workspaces/${idws}/contents/${type}/new`,
29
     CALENDAR: (idws = ':idws') => `/workspaces/${idws}/calendar`,
30
     CALENDAR: (idws = ':idws') => `/workspaces/${idws}/calendar`,
30
     CONTENT_LIST: (idws = ':idws') => `/workspaces/${idws}/contents`,
31
     CONTENT_LIST: (idws = ':idws') => `/workspaces/${idws}/contents`,
31
-    CONTENT: (idws = ':idws', type = ':type?', idcts = ':idcts?') => `/workspaces/${idws}/${type}/${idcts}`, // @TODO add /contents/ in url and remove <Switch> in <Tracim>
32
-    // CONTENT_NEW: (idws = ':idws', ctstype = ':ctstype') => `/workspaces/${idws}/contents/${ctstype}/new`,
33
-    // CONTENT_EDIT: (idws = ':idws', idcts = ':idcts') => `/workspaces/${idws}/contents/${idcts}/edit`,
34
-    // CONTENT_TITLE_EDIT: (idws = ':idws', idcts = ':idcts') => `/workspaces/${idws}/contents/${idcts}/title/edit`,
32
+    CONTENT: (idws = ':idws', type = ':type', idcts = ':idcts') => `/workspaces/${idws}/contents/${type}/${idcts}`,
35
     ADMIN: (idws = ':idws') => `/workspaces/${idws}/admin`
33
     ADMIN: (idws = ':idws') => `/workspaces/${idws}/admin`
36
   },
34
   },
37
   LOGIN: '/login',
35
   LOGIN: '/login',