Skip to content

Commit

Permalink
Add project joining modal
Browse files Browse the repository at this point in the history
  • Loading branch information
joshsmith committed Mar 22, 2017
1 parent 366838f commit 0b12f8d
Show file tree
Hide file tree
Showing 34 changed files with 465 additions and 92 deletions.
24 changes: 21 additions & 3 deletions app/components/project-card.js
Expand Up @@ -2,7 +2,10 @@ import Ember from 'ember';

const {
Component,
computed: { mapBy }
computed,
computed: { mapBy },
get,
inject: { service }
} = Ember;

/**
Expand All @@ -22,7 +25,22 @@ const {
export default Component.extend({
classNames: ['project-card'],

currentUser: service(),
session: service(),

// TODO: Similar code is defined in
// - `abilities/project.js`
// - `abilities/task.js`
currentProjectMembership: computed('project.projectUsers', 'currentUser.user.id', function() {
let projectUsers = get(this, 'project.projectUsers');
let currentUserId = get(this, 'currentUser.user.id');

return projectUsers.find((item) => {
return get(item, 'user.id') === currentUserId;
});
}),

projectCategories: mapBy('project.projectCategories', 'category'),
projectUsers: mapBy('project.projectUsers', 'user'),
projectSkills: mapBy('project.projectSkills', 'skill')
projectSkills: mapBy('project.projectSkills', 'skill'),
projectUsers: mapBy('project.projectUsers', 'user')
});
4 changes: 3 additions & 1 deletion app/components/project-details.js
Expand Up @@ -3,7 +3,7 @@ import Ember from 'ember';
const {
Component,
computed,
computed: { alias },
computed: { alias, mapBy },
get,
getProperties,
inject: { service }
Expand Down Expand Up @@ -64,6 +64,8 @@ export default Component.extend({
});
}),

projectSkills: mapBy('project.projectSkills', 'skill'),

actions: {
// TODO: This should go outside the component, but with the way the
// project, project.index, project.settings and project.tasks templates are
Expand Down
54 changes: 54 additions & 0 deletions app/components/project-join-modal.js
@@ -0,0 +1,54 @@
import Ember from 'ember';
import { EKMixin as EmberKeyboardMixin, keyDown } from 'ember-keyboard';

const {
Component,
computed: { alias },
get,
inject: { service },
on,
set
} = Ember;

export default Component.extend(EmberKeyboardMixin, {
classNames: ['project-join-modal-container'],
/**
* Flag indicating if the modal to quickly join a project should be shown
* Even if true, the modal will not be shown if there is a
* currentProjectMembership
*
* @property showModal
* @type {Boolean}
*/
showModal: false,

currentUser: service(),
projectUser: service(),

user: alias('currentUser.user'),

init() {
this._super(...arguments);
set(this, 'keyboardActivated', true);
},

close() {
// Without this check, tests are throwing
// errors on "calling set on destroyed object"
// There must be some sort of async behavior related to ember-modal-dialog
// we are not understanding.
if (this && !get(this, 'isDestroying')) {
set(this, 'showModal', false);
}
},

closeOnEsc: on(keyDown('Escape'), function() {
get(this, 'close')();
}),

actions: {
joinProject(project) {
get(this, 'projectUser').joinProject(project);
}
}
});
2 changes: 2 additions & 0 deletions app/components/related-skills.js
Expand Up @@ -24,6 +24,8 @@ const {
export default Component.extend({
classNames: ['related-skills'],

isClickable: false,

/**
* Returns whether or not the overflowing skills on the project card should be
* displayed.
Expand Down
2 changes: 2 additions & 0 deletions app/components/skill-list-items.js
Expand Up @@ -14,6 +14,8 @@ export default Component.extend({
tagName: 'ul',
sortByTitle: ['title:asc'],

isClickable: false,

currentUser: service(),
userSkillsList: service(),

Expand Down
2 changes: 0 additions & 2 deletions app/controllers/project/index.js
Expand Up @@ -9,12 +9,10 @@ const {

export default Controller.extend({
currentUser: service(),
store: service(),

projectUsers: mapBy('project.projectUsers', 'user'),
usersCount: alias('members.length'),
projectSkills: mapBy('project.projectSkills', 'skill'),
user: alias('currentUser.user'),

actions: {
saveSubscription(amount) {
Expand Down
29 changes: 29 additions & 0 deletions app/services/project-user.js
@@ -0,0 +1,29 @@
import Ember from 'ember';

const {
get,
inject: { service },
Service
} = Ember;

export default Service.extend({
currentUser: service(),
flashMessages: service(),
store: service(),

joinProject(project) {
let user = get(this, 'currentUser.user');
let store = get(this, 'store');

let projectUser = { project, user, role: 'pending' };

return store.createRecord('project-user', projectUser)
.save()
.then(() => this._flashSuccess('Your request has been sent.'));
},

_flashSuccess(message) {
let options = { fixed: true, sticky: false, timeout: 5000 };
get(this, 'flashMessages').clearMessages().success(message, options);
}
});
4 changes: 3 additions & 1 deletion app/styles/_icons.scss
Expand Up @@ -19,7 +19,7 @@ $spritePath: '/assets/images/icons/sprite';
$spriteURL: $spritePath + '.png';
$spritex2URL: $spritePath + '@2x.png';
$sprite-bgiSizeW: 230px;
$sprite-bgiSizeH: 330px;
$sprite-bgiSizeH: 369px;
$logo: 230px 50px $spriteURL 0px 0px $spritex2URL;
$logo-small: 161px 35px $spriteURL 0px -50px $spritex2URL;
$logo-small-icon-only: 35px 35px $spriteURL 0px -50px $spritex2URL;
Expand Down Expand Up @@ -67,6 +67,8 @@ $idea-small: 16px 16px $spriteURL -32px -288px $spritex2URL;
$tick-green-large: 24px 20px $spriteURL 0px -304px $spritex2URL;
$tiny-check: 8px 6px $spriteURL 0px -324px $spritex2URL;
$tiny-x: 6px 6px $spriteURL -8px -324px $spritex2URL;
$join: 25px 25px $spriteURL 0px -344px $spritex2URL;
$joined: 25px 25px $spriteURL -25px -344px $spritex2URL;

.box-icon {
@include sprite($box);
Expand Down
5 changes: 5 additions & 0 deletions app/styles/app.scss
Expand Up @@ -23,6 +23,10 @@
@import "ember-modal-dialog/ember-modal-structure";
@import "ember-modal-dialog/ember-modal-appearance";

.ember-modal-overlay.translucent {
background: rgba(0,0,0, 0.70)
}

.ember-modal-dialog {
border-radius: 4px;
box-shadow: 0 3px 12px rgba(0,0,0,0.15);
Expand Down Expand Up @@ -121,6 +125,7 @@
@import "components/project-details";
@import "components/project-header";
@import "components/project-item";
@import "components/project-join-modal";
@import "components/project-list";
@import "components/project-long-description";
@import "components/project-members";
Expand Down
4 changes: 4 additions & 0 deletions app/styles/components/project-card.scss
Expand Up @@ -72,4 +72,8 @@
overflow: hidden;
text-overflow: ellipsis;
}

&__actions {
text-align: center;
}
}
2 changes: 1 addition & 1 deletion app/styles/components/project-details.scss
Expand Up @@ -32,7 +32,7 @@
vertical-align: middle;
}

span {
> span {
color: $blue;
}
}
Expand Down
59 changes: 59 additions & 0 deletions app/styles/components/project-join-modal.scss
@@ -0,0 +1,59 @@
.project-join-modal {
padding: 20px;
width: 350px;

@include media($xs-screen) {
max-width: calc(100% - 20px);
}

h1 {
font-size: $body-font-size-x-large;
margin-bottom: 20px;
text-align: center;
}
}

.project-join-modal__button {
button {
width: 100%;
}
}

.project-join-modal__icons {
align-items: center;
display: flex;
justify-content: center;

&__icon {
content: "";
display: block;
height: 25px;
margin: 0 15px;
vertical-align: middle;
width: 25px;

&--join {
@include sprite($join);
}
}
}

.project-join-modal__skills {
margin-bottom: 20px;
text-align: center;

p {
font-size: $body-font-size-normal;
margin-bottom: 10px;
}

.related-skills .skills {
max-height: none;
overflow: auto;

li {
display: inline;
float: none;
}
}
}
5 changes: 0 additions & 5 deletions app/styles/components/skill-list-item.scss
@@ -1,8 +1,3 @@
.ember-tooltip {
font-size: $body-font-size-tiny;
padding: 3px 6px;
}

// Styles both clickable and unclickable items
.skill-list-item a, .skill-list-item > span {
color: $text--dark;
Expand Down
21 changes: 21 additions & 0 deletions app/templates/components/project-card.hbs
Expand Up @@ -13,6 +13,27 @@
<p class="description">
{{project.description}}
</p>
<p class="project-card__actions">
{{#if project.shouldLinkExternally}}
<a class="button default small external-link" href="{{project.website}}">Join project<span></span></a>
{{else}}
{{#if session.isAuthenticated}}
{{#if currentProjectMembership.isLoaded}}
{{#if (eq currentProjectMembership.role 'pending')}}
<button class="clear small" disabled>Request sent</button>
{{else}}
<button class="clear small" disabled>Member</button>
{{/if}}
{{/if}}

{{#unless currentProjectMembership}}
{{project-join-modal project=project skills=projectSkills}}
{{/unless}}
{{else}}
{{link-to "Join project" "signup" class="button default small"}}
{{/if}}
{{/if}}
</p>
{{related-skills class="project-card__skills" skills=projectSkills}}
{{project-card-members members=projectUsers}}
</div>
13 changes: 9 additions & 4 deletions app/templates/components/project-details.hbs
Expand Up @@ -19,12 +19,17 @@
<a class="button default small external-link" href="{{project.website}}">Join project<span></span></a>
{{else}}
{{#if session.isAuthenticated}}
{{#if currentProjectMembership.isLoaded}}
{{#if (eq currentProjectMembership.role 'pending')}}
<button class="clear small" disabled>Request sent</button>
{{else}}
<button class="clear small" disabled>Member</button>
{{/if}}
{{/if}}

{{#unless currentProjectMembership}}
<button class="default small" {{action "joinProject" project}}>Join project</button>
{{project-join-modal project=project skills=projectSkills}}
{{/unless}}
{{#if (eq currentProjectMembership.role 'pending')}}
<button class="clear small" disabled>Request sent</button>
{{/if}}
{{else}}
{{link-to "Join project" "signup" class="button default small"}}
{{/if}}
Expand Down
28 changes: 28 additions & 0 deletions app/templates/components/project-join-modal.hbs
@@ -0,0 +1,28 @@
<button class="button default small" {{action (mut showModal) true}}>Join project</button>
{{#if showModal}}
{{#modal-dialog
clickOutsideToClose=true
close=(action close)
containerClassNames="project-join-modal"
renderInPlace=true
targetAttachment="center"
translucentOverlay=true}}
<h1>Join {{project.title}}</h1>
<div class="project-join-modal__icons">
<div class="project-join-modal__icons__avatar">
<img class="icon medium" src={{user.photoLargeUrl}} />
</div>
<div class="project-join-modal__icons__icon project-join-modal__icons__icon--join"></div>
<div class="project-join-modal__icons__avatar">
<img class="icon medium" src={{project.iconLargeUrl}} />
</div>
</div>
<div class="project-join-modal__skills">
<p>What can you help with?</p>
{{related-skills isClickable=true skills=skills}}
</div>
<div class="project-join-modal__button">
<button class="button default" {{action "joinProject" project}}>Request to Join</button>
</div>
{{/modal-dialog}}
{{/if}}
6 changes: 5 additions & 1 deletion app/templates/components/related-skills.hbs
@@ -1,4 +1,8 @@
{{skill-list-items overflowHidden=overflowHidden skillItemHidden="skillItemHidden" skills=skills}}
{{skill-list-items
isClickable=isClickable
overflowHidden=overflowHidden
skillItemHidden="skillItemHidden"
skills=skills}}
<div class="expander {{if showToggle 'visible' 'hidden'}}">
{{#if overflowHidden}}
<a {{action "showMore"}}>show more</a>
Expand Down
3 changes: 0 additions & 3 deletions app/templates/components/skill-list-item-link.hbs
@@ -1,4 +1 @@
<span>{{skill.title}}</span>
{{#tooltip-on-component delay=1000 effect='none' side='bottom' updateFor=skill.isLoaded}}
{{#if matched}}Delete your skill{{else}}Add new skill{{/if}}
{{/tooltip-on-component}}
2 changes: 1 addition & 1 deletion app/templates/components/skill-list-items.hbs
@@ -1,3 +1,3 @@
{{#each sortedSkills as |skill|}}
{{skill-list-item skill=skill action="skillItemHidden"}}
{{skill-list-item isClickable=isClickable skill=skill action="skillItemHidden"}}
{{/each}}
Binary file modified public/assets/images/icons/sprite.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified public/assets/images/icons/sprite@2x.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 0b12f8d

Please sign in to comment.