Skip to content

Commit ab0dee7

Browse files
author
Matthew Sessions
committed
UI to show the list of a users collaborations
Fixes PLAT-1564 Test Plan - With the new collaboration feature flag turned on - For a user, create some collaborations with the collaboration_type=external_tool_collaboration - Load the lti_collaborations page - Notice that collaboration now shows Change-Id: Ie17a599fa4b54a98eff7060c2c72b2c76c242b3d Reviewed-on: https://gerrit.instructure.com/81645 Reviewed-by: Steven Burnett <sburnett@instructure.com> Tested-by: Jenkins QA-Review: Deepeeca Soundarrajan <dsoundarrajan@instructure.com> Product-Review: Matthew Sessions <msessions@instructure.com>
1 parent 3cef08d commit ab0dee7

16 files changed

Lines changed: 343 additions & 55 deletions
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
define([
2+
'react',
3+
'jsx/shared/DatetimeDisplay',
4+
'i18n!react_collaborations',
5+
'compiled/str/splitAssetString'
6+
], (React, DatetimeDisplay, i18n, splitAssetString) => {
7+
class Collaboration extends React.Component {
8+
render () {
9+
let { collaboration } = this.props
10+
let [context, contextId] = splitAssetString(ENV.context_asset_string)
11+
12+
return (
13+
<div className='Collaboration'>
14+
<div className='Collaboration-body'>
15+
<a
16+
className='Collaboration-title'
17+
href={`/${context}/${contextId}/collaborations/${collaboration.id}`}
18+
>
19+
{collaboration.title}
20+
</a>
21+
<p className='Collaboration-description'>{collaboration.description}</p>
22+
<a className='Collaboration-author' href={`/users/${collaboration.user_id}`}>{collaboration.user_name},</a>
23+
<DatetimeDisplay datetime={collaboration.updated_at} format='%b %d, %l:%M %p' />
24+
</div>
25+
<div className='Collaboration-actions'>
26+
<a className='icon-edit'>
27+
<span className='screenreader-only'>{i18n.t('Edit Collaboration')}</span>
28+
</a>
29+
<button className='btn btn-link'>
30+
<i className='icon-trash'></i>
31+
<span className='screenreader-only'>{i18n.t('Delete Collaboration')}</span>
32+
</button>
33+
</div>
34+
</div>
35+
);
36+
}
37+
};
38+
39+
Collaboration.propTypes = {
40+
collaboration: React.PropTypes.object
41+
};
42+
43+
return Collaboration
44+
});

app/jsx/collaborations/CollaborationsApp.jsx

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,24 @@
11
define([
22
'react',
33
'jsx/collaborations/GettingStartedCollaborations',
4-
'jsx/collaborations/CollaborationsNavigation'
5-
], (React, GettingStartedCollaborations, CollaborationsNavigation) => {
4+
'jsx/collaborations/CollaborationsNavigation',
5+
'./CollaborationsList'
6+
], (React, GettingStartedCollaborations, CollaborationsNavigation, CollaborationsList) => {
67
class CollaborationsApp extends React.Component {
78
static propTypes: {
89
applicationState: React.PropTypes.object,
910
actions: React.PropTypes.object
1011
}
1112

1213
render () {
14+
let { list } = this.props.applicationState.listCollaborations;
1315
return (
1416
<div className="CollaborationsApp">
15-
<div id="wrapperCollaborations">
16-
<CollaborationsNavigation ltiCollaborators={this.props.applicationState.ltiCollaborators}/>
17-
<GettingStartedCollaborations ltiCollaborators={this.props.applicationState.ltiCollaborators}/>
18-
</div>
17+
<CollaborationsNavigation ltiCollaborators={this.props.applicationState.ltiCollaborators}/>
18+
{list.length
19+
? <CollaborationsList collaborations={list} />
20+
: <GettingStartedCollaborations ltiCollaborators={this.props.applicationState.ltiCollaborators}/>
21+
}
1922
</div>
2023
);
2124
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
define([
2+
'react',
3+
'./Collaboration'
4+
], (React, Collaboration) => {
5+
class CollaborationsList extends React.Component {
6+
render () {
7+
return (
8+
<div className='CollaborationsList'>
9+
{this.props.collaborations.map(c => (
10+
<Collaboration key={c.id} collaboration={c} />
11+
))}
12+
</div>
13+
)
14+
}
15+
};
16+
17+
CollaborationsList.propTypes = {
18+
collaborations: React.PropTypes.array
19+
};
20+
21+
return CollaborationsList
22+
})

app/jsx/collaborations/actions/collaborationsActions.jsx

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,17 @@ define([
2020
actions.LIST_LTI_COLLABORATIONS_FAILED = 'LIST_LTI_COLLABORATIONS_FAILED'
2121
actions.listLTICollaborationsFailed = (error) => ({ type: actions.LIST_LTI_COLLABORATIONS_FAILED, payload: error, error:true })
2222

23-
actions.getCollaborations = () => {
24-
actions.listCollaborationsStart();
25-
26-
//do some async work
27-
28-
//on success
29-
actions.listCollaborationsSuccessful(collaborations);
23+
actions.getCollaborations = (context, contextId) => {
24+
return (dispatch) => {
25+
dispatch(actions.listCollaborationsStart());
3026

31-
//on failure
32-
actions.listCollaborationsFailed(error)
27+
let url = `/api/v1/${context}/${contextId}/collaborations`;
28+
$.getJSON(url)
29+
.success((collaborations) => dispatch(actions.listCollaborationsSuccessful(collaborations)))
30+
.fail((err) => dispatch(actions.listCollaborationsFailed(err)));
31+
}
3332
}
33+
3434
actions.getLTICollaborators = (context, contextId) => {
3535
return (dispatch) => {
3636
dispatch(actions.listLTICollaborationsStart());
Lines changed: 33 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,45 @@
11
define([
22
'redux',
3-
'../actions/collaborationsActions',
3+
'../actions/collaborationsActions'
44
], (redux, ACTION_NAMES) => {
55
let initialState = {
66
listCollaborationsPending: false,
77
listCollaborationsSuccessful: false,
88
listCollaborationsError: null,
9-
collaborations: [],
9+
list: [],
1010
}
1111

12-
return (state = initialState, action) => {
13-
switch (action.type) {
14-
case ACTION_NAMES.LIST_COLLABORATIONS_START:
15-
return {
16-
...state,
17-
listCollaborationsPending: true,
18-
listCollaborationsSuccessful: false,
19-
listCollaborationsError: null
20-
};
21-
22-
case ACTION_NAMES.LIST_COLLABORATIONS_SUCCESSFUL:
23-
return {
24-
...state,
25-
listCollaborationsPending: false,
26-
listCollaborationsSuccessful: true,
27-
collaborations: action.payload
28-
};
29-
30-
case ACTION_NAMES.LIST_COLLABORATIONS_FAILED:
31-
return {
32-
...state,
33-
listCollaborationsPending: false,
34-
listCollaborationsError: action.payload
35-
};
36-
37-
default:
38-
return state;
12+
let collaborationsHandlers = {
13+
[ACTION_NAMES.LIST_COLLABORATIONS_START]: (state, action) => {
14+
return {
15+
...state,
16+
listCollaborationsPending: true,
17+
listCollaborationsSuccessful: false,
18+
listCollaborationsError: null
19+
};
20+
},
21+
[ACTION_NAMES.LIST_COLLABORATIONS_SUCCESSFUL]: (state, action) => {
22+
return {
23+
...state,
24+
listCollaborationsPending: false,
25+
listCollaborationsSuccessful: true,
26+
list: action.payload
27+
}
28+
},
29+
[ACTION_NAMES.LIST_COLLABORATIONS_FAILED]: (state, action) => {
30+
return {
31+
...state,
32+
listCollaborationsPending: false,
33+
listCollaborationsError: action.payload
34+
}
3935
}
4036
};
37+
38+
return (state = initialState, action) => {
39+
if (collaborationsHandlers[action.type]) {
40+
return collaborationsHandlers[action.type](state, action)
41+
} else {
42+
return state
43+
}
44+
}
4145
})

app/jsx/collaborations/router.jsx

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,18 @@ define([
77
'jsx/collaborations/actions/collaborationsActions',
88
'jsx/collaborations/store/store'
99
], function (React, page, qs, redux, CollaborationsApp, actions, store) {
10-
let unsubscribe = null;
11-
1210
/**
1311
* Route Handlers
1412
*/
1513
function renderShowCollaborations (ctx) {
1614
store.dispatch(actions.getLTICollaborators(ctx.params.context, ctx.params.contextId));
15+
store.dispatch(actions.getCollaborations(ctx.params.context, ctx.params.contextId));
16+
1717
let view = () => {
1818
let state = store.getState();
1919
React.render(<CollaborationsApp applicationState={state} actions={actions} />, document.getElementById('content'));
2020
};
21-
unsubscribe = store.subscribe(view);
21+
store.subscribe(view);
2222
view();
2323
}
2424

@@ -36,7 +36,6 @@ define([
3636
*/
3737
page('*', parseQueryString); // Middleware to parse querystring to object
3838
page('/:context(courses|groups)/:contextId/lti_collaborations', renderShowCollaborations);
39-
page.exit('*', unsubscribe)
4039

4140
return {
4241
start () {

app/jsx/shared/DatetimeDisplay.jsx

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
define([
2+
'react',
3+
'timezone'
4+
], (React, tz) => {
5+
class DatetimeDisplay extends React.Component {
6+
render () {
7+
let datetime = this.props.datetime instanceof Date ? this.props.datetime.toString() : this.props.datetime
8+
return (
9+
<span className='DatetimeDisplay'>
10+
{tz.format(datetime, this.props.format)}
11+
</span>
12+
);
13+
}
14+
};
15+
16+
DatetimeDisplay.propTypes = {
17+
datetime: React.PropTypes.oneOfType([
18+
React.PropTypes.string,
19+
React.PropTypes.instanceOf(Date)
20+
]),
21+
format: React.PropTypes.string
22+
};
23+
24+
DatetimeDisplay.defaultProps = {
25+
format: '%c'
26+
};
27+
28+
return DatetimeDisplay;
29+
});
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
@import "base/environment";
22

33
@import "pages/react_collaborations/_CollaborationsApp.scss";
4+
@import "pages/react_collaborations/_Collaboration.scss";
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
.Collaboration {
2+
border-bottom: $ic-border-dark 1px solid;
3+
padding: 20px;
4+
display: flex;
5+
justify-content: space-between;
6+
}
7+
8+
.Collaboration:first-child {
9+
border-top: $ic-border-dark 1px solid;
10+
}
11+
12+
.Collaboration-title {
13+
font-size: 1.1rem;
14+
font-weight: 300;
15+
}
16+
17+
.Collaboration-description {
18+
margin: 5px 0;
19+
}
20+
21+
.Collaboration-author {
22+
margin-right: 10px;
23+
}
24+
25+
.Collaboration-actions {
26+
min-width: 100px;
27+
}

app/stylesheets/pages/react_collaborations/_CollaborationsApp.scss

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
#wrapperCollaborations{
1+
.GettingStartedCollaborations {
22
width: 600px;
33
margin: 0 auto;
44
}
5-
65
.Collaborations--GettingStarted {
76
text-align: center;
87
}

0 commit comments

Comments
 (0)