Skip to content

Commit a746979

Browse files
authored
Merge pull request #1651 from code-corps/250-change-roles
Add ability to change roles from people list
2 parents 15e2cf5 + a09d18d commit a746979

17 files changed

+683
-145
lines changed

app/components/conversations/new-conversation-modal.js

+15-6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import Component from '@ember/component';
2-
import { get, set } from '@ember/object';
2+
import { get, getProperties, set } from '@ember/object';
33
import { and, not, notEmpty } from '@ember/object/computed';
44
import { inject as service } from '@ember/service';
55
import RSVP from 'rsvp';
@@ -9,11 +9,10 @@ const SAVE_SUCCESS = 'Your message is sending now.';
99
export default Component.extend({
1010
classNames: ['new-conversation-modal-container'],
1111

12-
showModal: false,
13-
1412
initiatedBy: null,
1513
message: null,
1614
project: null,
15+
showModal: false,
1716
user: null,
1817

1918
currentUser: service(),
@@ -45,17 +44,27 @@ export default Component.extend({
4544
},
4645

4746
discardConversation() {
47+
let message = get(this, 'message');
48+
let { body, subject } = getProperties(message, 'body', 'subject');
49+
50+
if (!body && !subject) {
51+
return this._discardConversation(message);
52+
}
53+
4854
let confirmed = window.confirm('You will lose any unsaved information if you close. Are you sure?');
4955
if (confirmed) {
50-
let message = get(this, 'message');
51-
get(message, 'conversations.firstObject').destroyRecord();
52-
message.destroyRecord();
56+
return this._discardConversation(message);
5357
} else {
5458
// Stop the pipe by rejecting
5559
return RSVP.reject();
5660
}
5761
},
5862

63+
_discardConversation(message) {
64+
get(message, 'conversations.firstObject').destroyRecord();
65+
return message.destroyRecord();
66+
},
67+
5968
actions: {
6069
send(message) {
6170
// Since it's created without an ID, the store will not detect the
+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import Component from '@ember/component';
2+
import { computed, get, set } from '@ember/object';
3+
import { alias, and } from '@ember/object/computed';
4+
import { inject as service } from '@ember/service';
5+
import EmberCan from 'ember-can';
6+
7+
export default Component.extend({
8+
classNames: ['project-user-role-modal-container'],
9+
tagName: 'span',
10+
11+
currentUser: service(),
12+
13+
projectUser: null,
14+
save: null,
15+
selectedRole: null,
16+
showModal: false,
17+
18+
ability: EmberCan.computed.ability('project'),
19+
canManage: alias('ability.canManage'),
20+
demotionDisabled: and('canManage', 'isSelf'),
21+
user: alias('currentUser.user'),
22+
23+
isSelf: computed('projectUser', 'user', function() {
24+
return get(this, 'projectUser.user.id') === get(this, 'user.id');
25+
}),
26+
27+
init() {
28+
this._super(...arguments);
29+
let role = get(this, 'projectUser.role');
30+
set(this, 'selectedRole', role);
31+
}
32+
});

app/components/user-list-item.js

+30-15
Original file line numberDiff line numberDiff line change
@@ -2,40 +2,55 @@ import Component from '@ember/component';
22
import { inject as service } from '@ember/service';
33
import { get, set } from '@ember/object';
44
import { alias } from '@ember/object/computed';
5+
import RSVP from 'rsvp';
56

67
export default Component.extend({
78
classNames: ['user-list-item'],
89
tagName: 'li',
9-
showApprove: false,
10-
showDeny: false,
1110

1211
flashMessages: service(),
1312

1413
projectUser: null,
14+
showRoleModal: false,
1515
user: null,
1616

1717
project: alias('projectUser.project'),
1818

1919
actions: {
2020
approve(projectUser) {
21-
set(projectUser, 'role', 'contributor');
22-
return projectUser.save().then(() => {
23-
this._flashSuccess('Membership approved');
24-
});
21+
let confirmed = window.confirm('Are you sure you want to approve their membership?');
22+
if (confirmed) {
23+
set(projectUser, 'role', 'contributor');
24+
return projectUser.save().then(() => {
25+
this._flashSuccess('Membership approved');
26+
});
27+
} else {
28+
return RSVP.reject();
29+
}
2530
},
2631

27-
deny(projectUser) {
28-
return projectUser.destroyRecord().then(() => {
29-
this._flashSuccess('Membership denied');
30-
});
31-
},
32+
changeRole(projectUser, role) {
33+
let currentRole = get(projectUser, 'role');
34+
if (role === currentRole) {
35+
set(this, 'showRoleModal', false);
36+
return RSVP.resolve();
37+
}
3238

33-
showApprove() {
34-
set(this, 'showApprove', true);
39+
set(projectUser, 'role', role);
40+
return projectUser.save().then(() => {
41+
this._flashSuccess(`Role changed to ${role}`);
42+
});
3543
},
3644

37-
showDeny() {
38-
set(this, 'showDeny', true);
45+
deny(projectUser) {
46+
let confirmed = window.confirm('Are you sure you want to deny their membership?');
47+
if (confirmed) {
48+
return projectUser.destroyRecord().then(() => {
49+
this._flashSuccess('Membership denied');
50+
});
51+
} else {
52+
return RSVP.reject();
53+
}
3954
}
4055
},
4156

app/styles/components/conversations/new-conversation-modal.scss

+1-37
Original file line numberDiff line numberDiff line change
@@ -8,48 +8,12 @@
88
}
99

1010
.new-conversation-modal {
11-
padding: 0 10px;
11+
padding: 0 1em;
1212
width: 450px;
1313

1414
h3 {
1515
font-size: $header-font-size-small;
1616
margin: 0.7em;
1717
text-align: center;
1818
}
19-
20-
&__button {
21-
align-items: center;
22-
border-left: 1px solid $gray--lightest;
23-
border-right: 1px solid $gray--lightest;
24-
color: $text--light;
25-
display: flex;
26-
font-size: $header-font-size-small;
27-
height: 100%;
28-
justify-content: center;
29-
width: 100%;
30-
31-
&:hover {
32-
background: $blue--background;
33-
transition: none;
34-
}
35-
}
36-
37-
&__to-field {
38-
align-items: center;
39-
background: $gray--background;
40-
border-bottom: 1px solid $gray--lighter;
41-
border-top: 1px solid $gray--lighter;
42-
display: flex;
43-
margin: 0 -10px 1em -10px;
44-
padding: 10px;
45-
46-
span {
47-
padding-right: 5px;
48-
}
49-
50-
&__username {
51-
color: $text--lightest;
52-
font-size: $body-font-size-small;
53-
}
54-
}
5519
}

app/styles/components/user-list-item.scss

+44-15
Original file line numberDiff line numberDiff line change
@@ -52,30 +52,59 @@
5252
}
5353
}
5454

55-
&__conversation {
55+
&__conversation, &__button-container {
56+
border-right: 1px solid $gray--lightest;
5657
width: 50px;
58+
59+
&:first-child {
60+
border-left: 1px solid $gray--lightest;
61+
}
62+
63+
&:focus, span:focus {
64+
outline: none;
65+
}
5766
}
5867

59-
&__actions {
60-
padding: .7em 1em;
61-
text-align: left;
68+
&__button {
69+
align-items: center;
70+
color: $text--light;
71+
display: flex;
72+
font-size: $header-font-size-small;
73+
height: 100%;
74+
justify-content: center;
75+
width: 100%;
6276

63-
button {
64-
margin-top: 2px;
77+
&:hover {
78+
background: $blue--background;
79+
color: $blue;
80+
transition: none;
6581
}
6682

67-
@include media($sm-screen) {
68-
display: flex;
69-
justify-content: space-between;
70-
button {
71-
flex: 1;
72-
margin-right: 5px;
73-
&:last-of-type {
74-
margin-right: 0;
75-
}
83+
&--default {
84+
&:hover {
85+
background: $gray--background;
86+
color: $gray--darkest;
87+
}
88+
}
89+
90+
&--success {
91+
&:hover {
92+
background: $green--lighter;
93+
color: $green;
94+
}
95+
}
96+
97+
&--danger {
98+
&:hover {
99+
background: $red--light;
100+
color: $red;
76101
}
77102
}
78103
}
104+
105+
&__actions {
106+
display: flex;
107+
}
79108
}
80109

81110
.user-list-item {

app/styles/layout/_forms.scss

+13
Original file line numberDiff line numberDiff line change
@@ -75,10 +75,23 @@ $outer-border-radius: 4px;
7575
text-align: center;
7676
}
7777

78+
&--disabled {
79+
opacity: 0.5;
80+
}
81+
7882
&--hidden:not(.has-error) {
7983
display: none;
8084
}
8185

86+
&--radio {
87+
margin-bottom: 0.5em;
88+
89+
input {
90+
float: left;
91+
margin: 3px 8px 3px 0;
92+
}
93+
}
94+
8295
.input-group {
8396
margin-bottom: 0;
8497
}

app/styles/layout/_modals.scss

+29-2
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,19 @@
3333

3434
.modal__content {
3535
margin-top: 10px;
36-
padding: 20px 10px;
36+
padding: 1em;
3737
border-bottom: 1px solid $border-gray;
3838
border-top: 1px solid $border-gray;
3939

40+
&--no-vertical-padding {
41+
padding-top: 0;
42+
padding-bottom: 0;
43+
}
44+
45+
&--without-top-border {
46+
border-top: none;
47+
}
48+
4049
ul {
4150
margin-left: 30px;
4251
}
@@ -47,8 +56,26 @@
4756
}
4857
}
4958

59+
.modal__target-user {
60+
align-items: center;
61+
background: $gray--background;
62+
border-bottom: 1px solid $gray--lighter;
63+
border-top: 1px solid $gray--lighter;
64+
display: flex;
65+
margin: 0 -1em 1em -1em;
66+
padding: 1em;
67+
68+
span {
69+
padding-right: 5px;
70+
}
71+
72+
&__username {
73+
color: $text--lightest;
74+
font-size: $body-font-size-small;
75+
}
76+
}
77+
5078
.modal__actions {
51-
margin-top: 10px;
5279
padding: 10px;
5380

5481
p {

app/templates/components/conversations/new-conversation-modal.hbs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<a class="new-conversation-modal__button" {{action (pipe (action createConversation) (action (mut showModal) true)) bubbles=false}} data-test-open-button>
1+
<a class="project-user__button" {{action (pipe (action createConversation) (action (mut showModal) true)) bubbles=false}} data-test-open-button>
22
{{fa-icon "comment"}}
33
</a>
44

@@ -16,7 +16,7 @@
1616
<h3>New Conversation</h3>
1717

1818
<form data-test-message-form>
19-
<div class="new-conversation-modal__to-field">
19+
<div class="modal__target-user">
2020
<span>
2121
<img data-test-target-photo class="icon icon--tiny" src={{user.photoThumbUrl}} />
2222
</span>

0 commit comments

Comments
 (0)