summaryrefslogtreecommitdiffstats
path: root/client/components
diff options
context:
space:
mode:
Diffstat (limited to 'client/components')
-rw-r--r--client/components/activities/activities.js16
-rw-r--r--client/components/activities/comments.js11
-rw-r--r--client/components/boards/boardArchive.js3
-rw-r--r--client/components/cards/attachments.js9
-rw-r--r--client/components/cards/cardDate.js106
-rw-r--r--client/components/cards/cardDate.styl4
-rw-r--r--client/components/cards/cardDetails.jade107
-rw-r--r--client/components/cards/cardDetails.js2
-rw-r--r--client/components/cards/cardDetails.styl9
-rw-r--r--client/components/cards/cardTime.jade8
-rw-r--r--client/components/cards/cardTime.js19
-rw-r--r--client/components/cards/checklists.js4
-rw-r--r--client/components/cards/minicard.jade51
-rw-r--r--client/components/cards/minicard.js11
-rw-r--r--client/components/cards/minicard.styl12
-rw-r--r--client/components/cards/subtasks.js1
-rw-r--r--client/components/forms/forms.styl3
-rw-r--r--client/components/lists/list.js1
-rw-r--r--client/components/lists/list.styl11
-rw-r--r--client/components/lists/listBody.jade54
-rw-r--r--client/components/lists/listBody.js228
-rw-r--r--client/components/main/header.jade3
-rw-r--r--client/components/main/layouts.jade1
-rw-r--r--client/components/settings/invitationCode.js17
-rw-r--r--client/components/settings/settingBody.jade2
-rw-r--r--client/components/sidebar/sidebar.jade15
-rw-r--r--client/components/sidebar/sidebar.js15
-rw-r--r--client/components/users/userAvatar.jade2
-rw-r--r--client/components/users/userAvatar.js5
29 files changed, 565 insertions, 165 deletions
diff --git a/client/components/activities/activities.js b/client/components/activities/activities.js
index f1414e44..6633a91a 100644
--- a/client/components/activities/activities.js
+++ b/client/components/activities/activities.js
@@ -8,16 +8,24 @@ BlazeComponent.extendComponent({
const sidebar = this.parentComponent(); // XXX for some reason not working
sidebar.callFirstWith(null, 'resetNextPeak');
this.autorun(() => {
- const mode = this.data().mode;
+ let mode = this.data().mode;
const capitalizedMode = Utils.capitalize(mode);
- const id = Session.get(`current${capitalizedMode}`);
+ let thisId, searchId;
+ if (mode === 'linkedcard' || mode === 'linkedboard') {
+ thisId = Session.get('currentCard');
+ searchId = Cards.findOne({_id: thisId}).linkedId;
+ mode = mode.replace('linked', '');
+ } else {
+ thisId = Session.get(`current${capitalizedMode}`);
+ searchId = thisId;
+ }
const limit = this.page.get() * activitiesPerPage;
const user = Meteor.user();
const hideSystem = user ? user.hasHiddenSystemMessages() : false;
- if (id === null)
+ if (searchId === null)
return;
- this.subscribe('activities', mode, id, limit, hideSystem, () => {
+ this.subscribe('activities', mode, searchId, limit, hideSystem, () => {
this.loadNextPageLocked = false;
// If the sibear peak hasn't increased, that mean that there are no more
diff --git a/client/components/activities/comments.js b/client/components/activities/comments.js
index 9b6aedd6..34b6402c 100644
--- a/client/components/activities/comments.js
+++ b/client/components/activities/comments.js
@@ -21,11 +21,18 @@ BlazeComponent.extendComponent({
'submit .js-new-comment-form'(evt) {
const input = this.getInput();
const text = input.val().trim();
+ const card = this.currentData();
+ let boardId = card.boardId;
+ let cardId = card._id;
+ if (card.isLinkedCard()) {
+ boardId = Cards.findOne(card.linkedId).boardId;
+ cardId = card.linkedId;
+ }
if (text) {
CardComments.insert({
text,
- boardId: this.currentData().boardId,
- cardId: this.currentData()._id,
+ boardId,
+ cardId,
});
resetCommentInput(input);
Tracker.flush();
diff --git a/client/components/boards/boardArchive.js b/client/components/boards/boardArchive.js
index dbebdd70..8f4d5434 100644
--- a/client/components/boards/boardArchive.js
+++ b/client/components/boards/boardArchive.js
@@ -37,8 +37,7 @@ BlazeComponent.extendComponent({
const currentBoard = Boards.findOne(Session.get('currentBoard'));
Boards.remove(currentBoard._id);
}
- const board = this.currentData();
- Boards.remove(board._id);
+ Boards.remove(this._id);
FlowRouter.go('home');
}),
}];
diff --git a/client/components/cards/attachments.js b/client/components/cards/attachments.js
index bc7d3979..5cac930d 100644
--- a/client/components/cards/attachments.js
+++ b/client/components/cards/attachments.js
@@ -57,8 +57,13 @@ Template.cardAttachmentsPopup.events({
const card = this;
FS.Utility.eachFile(evt, (f) => {
const file = new FS.File(f);
- file.boardId = card.boardId;
- file.cardId = card._id;
+ if (card.isLinkedCard()) {
+ file.boardId = Cards.findOne(card.linkedId).boardId;
+ file.cardId = card.linkedId;
+ } else {
+ file.boardId = card.boardId;
+ file.cardId = card._id;
+ }
file.userId = Meteor.userId();
const attachment = Attachments.insert(file);
diff --git a/client/components/cards/cardDate.js b/client/components/cards/cardDate.js
index b0f2baa3..182705d5 100644
--- a/client/components/cards/cardDate.js
+++ b/client/components/cards/cardDate.js
@@ -96,7 +96,7 @@ Template.dateBadge.helpers({
(class extends DatePicker {
onCreated() {
super.onCreated();
- this.data().receivedAt && this.date.set(moment(this.data().receivedAt));
+ this.data().getReceived() && this.date.set(moment(this.data().getReceived()));
}
_storeDate(date) {
@@ -104,7 +104,7 @@ Template.dateBadge.helpers({
}
_deleteDate() {
- this.card.unsetReceived();
+ this.card.setReceived(null);
}
}).register('editCardReceivedDatePopup');
@@ -113,13 +113,13 @@ Template.dateBadge.helpers({
(class extends DatePicker {
onCreated() {
super.onCreated();
- this.data().startAt && this.date.set(moment(this.data().startAt));
+ this.data().getStart() && this.date.set(moment(this.data().getStart()));
}
onRendered() {
super.onRendered();
- if (moment.isDate(this.card.receivedAt)) {
- this.$('.js-datepicker').datepicker('setStartDate', this.card.receivedAt);
+ if (moment.isDate(this.card.getReceived())) {
+ this.$('.js-datepicker').datepicker('setStartDate', this.card.getReceived());
}
}
@@ -128,7 +128,7 @@ Template.dateBadge.helpers({
}
_deleteDate() {
- this.card.unsetStart();
+ this.card.setStart(null);
}
}).register('editCardStartDatePopup');
@@ -136,13 +136,13 @@ Template.dateBadge.helpers({
(class extends DatePicker {
onCreated() {
super.onCreated();
- this.data().dueAt && this.date.set(moment(this.data().dueAt));
+ this.data().getDue() && this.date.set(moment(this.data().getDue()));
}
onRendered() {
super.onRendered();
- if (moment.isDate(this.card.startAt)) {
- this.$('.js-datepicker').datepicker('setStartDate', this.card.startAt);
+ if (moment.isDate(this.card.getStart())) {
+ this.$('.js-datepicker').datepicker('setStartDate', this.card.getStart());
}
}
@@ -151,7 +151,7 @@ Template.dateBadge.helpers({
}
_deleteDate() {
- this.card.unsetDue();
+ this.card.setDue(null);
}
}).register('editCardDueDatePopup');
@@ -159,13 +159,13 @@ Template.dateBadge.helpers({
(class extends DatePicker {
onCreated() {
super.onCreated();
- this.data().endAt && this.date.set(moment(this.data().endAt));
+ this.data().getEnd() && this.date.set(moment(this.data().getEnd()));
}
onRendered() {
super.onRendered();
- if (moment.isDate(this.card.startAt)) {
- this.$('.js-datepicker').datepicker('setStartDate', this.card.startAt);
+ if (moment.isDate(this.card.getStart())) {
+ this.$('.js-datepicker').datepicker('setStartDate', this.card.getStart());
}
}
@@ -174,7 +174,7 @@ Template.dateBadge.helpers({
}
_deleteDate() {
- this.card.unsetEnd();
+ this.card.setEnd(null);
}
}).register('editCardEndDatePopup');
@@ -213,19 +213,23 @@ class CardReceivedDate extends CardDate {
super.onCreated();
const self = this;
self.autorun(() => {
- self.date.set(moment(self.data().receivedAt));
+ self.date.set(moment(self.data().getReceived()));
});
}
classes() {
let classes = 'received-date ';
- const dueAt = this.data().dueAt;
- if (dueAt) {
- if (this.date.get().isBefore(this.now.get(), 'minute') &&
- this.now.get().isBefore(dueAt)) {
- classes += 'current';
- }
- }
+ const dueAt = this.data().getDue();
+ const endAt = this.data().getEnd();
+ const startAt = this.data().getStart();
+ const theDate = this.date.get();
+ // if dueAt, endAt and startAt exist & are > receivedAt, receivedAt doesn't need to be flagged
+ if (((startAt) && (theDate.isAfter(dueAt))) ||
+ ((endAt) && (theDate.isAfter(endAt))) ||
+ ((dueAt) && (theDate.isAfter(dueAt))))
+ classes += 'long-overdue';
+ else
+ classes += 'current';
return classes;
}
@@ -246,19 +250,24 @@ class CardStartDate extends CardDate {
super.onCreated();
const self = this;
self.autorun(() => {
- self.date.set(moment(self.data().startAt));
+ self.date.set(moment(self.data().getStart()));
});
}
classes() {
let classes = 'start-date' + ' ';
- const dueAt = this.data().dueAt;
- if (dueAt) {
- if (this.date.get().isBefore(this.now.get(), 'minute') &&
- this.now.get().isBefore(dueAt)) {
- classes += 'current';
- }
- }
+ const dueAt = this.data().getDue();
+ const endAt = this.data().getEnd();
+ const theDate = this.date.get();
+ const now = this.now.get();
+ // if dueAt or endAt exist & are > startAt, startAt doesn't need to be flagged
+ if (((endAt) && (theDate.isAfter(endAt))) ||
+ ((dueAt) && (theDate.isAfter(dueAt))))
+ classes += 'long-overdue';
+ else if (theDate.isBefore(now, 'minute'))
+ classes += 'almost-due';
+ else
+ classes += 'current';
return classes;
}
@@ -279,24 +288,21 @@ class CardDueDate extends CardDate {
super.onCreated();
const self = this;
self.autorun(() => {
- self.date.set(moment(self.data().dueAt));
+ self.date.set(moment(self.data().getDue()));
});
}
classes() {
let classes = 'due-date' + ' ';
-
- // if endAt exists & is < dueAt, dueAt doesn't need to be flagged
- const endAt = this.data().endAt;
+ const endAt = this.data().getEnd();
const theDate = this.date.get();
const now = this.now.get();
-
- if ((endAt !== 0) &&
- (endAt !== null) &&
- (endAt !== '') &&
- (endAt !== undefined) &&
- (theDate.isBefore(endAt)))
+ // if the due date is after the end date, green - done early
+ if ((endAt) && (theDate.isAfter(endAt)))
classes += 'current';
+ // if there is an end date, don't need to flag the due date
+ else if (endAt)
+ classes += '';
else if (now.diff(theDate, 'days') >= 2)
classes += 'long-overdue';
else if (now.diff(theDate, 'minute') >= 0)
@@ -323,22 +329,20 @@ class CardEndDate extends CardDate {
super.onCreated();
const self = this;
self.autorun(() => {
- self.date.set(moment(self.data().endAt));
+ self.date.set(moment(self.data().getEnd()));
});
}
classes() {
let classes = 'end-date' + ' ';
- const dueAt = this.data.dueAt;
- if (dueAt) {
- const diff = dueAt.diff(this.date.get(), 'days');
- if (diff >= 2)
- classes += 'long-overdue';
- else if (diff > 0)
- classes += 'due';
- else if (diff <= 0)
- classes += 'current';
- }
+ const dueAt = this.data().getDue();
+ const theDate = this.date.get();
+ if (theDate.diff(dueAt, 'days') >= 2)
+ classes += 'long-overdue';
+ else if (theDate.diff(dueAt, 'days') >= 0)
+ classes += 'due';
+ else if (theDate.diff(dueAt, 'days') >= -2)
+ classes += 'almost-due';
return classes;
}
diff --git a/client/components/cards/cardDate.styl b/client/components/cards/cardDate.styl
index 9775e82b..62cfdcd9 100644
--- a/client/components/cards/cardDate.styl
+++ b/client/components/cards/cardDate.styl
@@ -43,12 +43,12 @@
&.start-date
time
&::before
- content: "\f08b" // symbol: fa-sign-out
+ content: "\f251" // symbol: fa-hourglass-start
&.received-date
time
&::before
- content: "\f251" // symbol: fa-hourglass-start
+ content: "\f08b" // symbol: fa-sign-out
time
&::before
diff --git a/client/components/cards/cardDetails.jade b/client/components/cards/cardDetails.jade
index aaad7c7c..33d6d3b7 100644
--- a/client/components/cards/cardDetails.jade
+++ b/client/components/cards/cardDetails.jade
@@ -10,7 +10,7 @@ template(name="cardDetails")
h2.card-details-title.js-card-title(
class="{{#if canModifyCard}}js-open-inlined-form is-editable{{/if}}")
+viewer
- = title
+ = getTitle
if isWatching
i.fa.fa-eye.card-details-watch
.card-details-path
@@ -19,43 +19,54 @@ template(name="cardDetails")
a.js-parent-card(href=linkForCard) {{title}}
// else
{{_ 'top-level-card'}}
+ if isLinkedCard
+ h3.linked-card-location
+ +viewer
+ | {{getBoardTitle}} > {{getTitle}}
- if archived
- p.warning {{_ 'card-archived'}}
+ if getArchived
+ if isLinkedBoard
+ p.warning {{_ 'board-archived'}}
+ else
+ p.warning {{_ 'card-archived'}}
.card-details-items
.card-details-item.card-details-item-received
h3.card-details-item-title {{_ 'card-received'}}
- if receivedAt
+ if getReceived
+cardReceivedDate
else
- a.js-received-date {{_ 'add'}}
+ if canModifyCard
+ a.js-received-date {{_ 'add'}}
.card-details-item.card-details-item-start
h3.card-details-item-title {{_ 'card-start'}}
- if startAt
+ if getStart
+cardStartDate
else
- a.js-start-date {{_ 'add'}}
+ if canModifyCard
+ a.js-start-date {{_ 'add'}}
.card-details-item.card-details-item-due
h3.card-details-item-title {{_ 'card-due'}}
- if dueAt
+ if getDue
+cardDueDate
else
- a.js-due-date {{_ 'add'}}
+ if canModifyCard
+ a.js-due-date {{_ 'add'}}
.card-details-item.card-details-item-end
h3.card-details-item-title {{_ 'card-end'}}
- if endAt
+ if getEnd
+cardEndDate
else
- a.js-end-date {{_ 'add'}}
+ if canModifyCard
+ a.js-end-date {{_ 'add'}}
.card-details-items
.card-details-item.card-details-item-members
h3.card-details-item-title {{_ 'members'}}
- each members
+ each getMembers
+userAvatar(userId=this cardId=../_id)
| {{! XXX Hack to hide syntaxic coloration /// }}
if canModifyCard
@@ -79,9 +90,9 @@ template(name="cardDetails")
+cardCustomField
.card-details-items
- if spentTime
+ if getSpentTime
.card-details-item.card-details-item-spent
- if isOvertime
+ if getIsOvertime
h3.card-details-item-title {{_ 'overtime-hours'}}
else
h3.card-details-item-title {{_ 'spent-time-hours'}}
@@ -92,15 +103,15 @@ template(name="cardDetails")
h3.card-details-item-title {{_ 'description'}}
+inlinedCardDescription(classNames="card-description js-card-description")
+editor(autofocus=true)
- | {{getUnsavedValue 'cardDescription' _id description}}
+ | {{getUnsavedValue 'cardDescription' _id getDescription}}
.edit-controls.clearfix
button.primary(type="submit") {{_ 'save'}}
a.fa.fa-times-thin.js-close-inlined-form
else
a.js-open-inlined-form
- if description
+ if getDescription
+viewer
- = description
+ = getDescription
else
| {{_ 'edit'}}
if (hasUnsavedValue 'cardDescription' _id)
@@ -109,10 +120,10 @@ template(name="cardDetails")
a.js-open-inlined-form {{_ 'view-it'}}
= ' - '
a.js-close-inlined-form {{_ 'discard'}}
- else if description
+ else if getDescription
h3.card-details-item-title {{_ 'description'}}
+viewer
- = description
+ = getDescription
.card-details-items
.card-details-item.card-details-item-name
@@ -122,14 +133,14 @@ template(name="cardDetails")
+editCardRequesterForm
else
a.js-open-inlined-form
- if requestedBy
+ if getRequestedBy
+viewer
- = requestedBy
+ = getRequestedBy
else
| {{_ 'add'}}
- else if requestedBy
+ else if getRequestedBy
+viewer
- = requestedBy
+ = getRequestedBy
.card-details-item.card-details-item-name
h3.card-details-item-title {{_ 'assigned-by'}}
@@ -138,14 +149,14 @@ template(name="cardDetails")
+editCardAssignerForm
else
a.js-open-inlined-form
- if assignedBy
+ if getAssignedBy
+viewer
- = assignedBy
+ = getAssignedBy
else
| {{_ 'add'}}
- else if requestedBy
+ else if getRequestedBy
+viewer
- = assignedBy
+ = getAssignedBy
hr
+checklists(cardId = _id)
@@ -162,36 +173,44 @@ template(name="cardDetails")
+attachmentsGalery
hr
- .activity-title
- h3 {{ _ 'activity'}}
- if currentUser.isBoardMember
- .material-toggle-switch
- span.toggle-switch-title {{_ 'hide-system-messages'}}
- if hiddenSystemMessages
- input.toggle-switch(type="checkbox" id="toggleButton" checked="checked")
- else
- input.toggle-switch(type="checkbox" id="toggleButton")
- label.toggle-label(for="toggleButton")
+ unless currentUser.isNoComments
+ .activity-title
+ h3 {{ _ 'activity'}}
+ if currentUser.isBoardMember
+ .material-toggle-switch
+ span.toggle-switch-title {{_ 'hide-system-messages'}}
+ if hiddenSystemMessages
+ input.toggle-switch(type="checkbox" id="toggleButton" checked="checked")
+ else
+ input.toggle-switch(type="checkbox" id="toggleButton")
+ label.toggle-label(for="toggleButton")
if currentUser.isBoardMember
- +commentForm
- if isLoaded.get
- +activities(card=this mode="card")
+ unless currentUser.isNoComments
+ +commentForm
+ unless currentUser.isNoComments
+ if isLoaded.get
+ if isLinkedCard
+ +activities(card=this mode="linkedcard")
+ else if isLinkedBoard
+ +activities(card=this mode="linkedboard")
+ else
+ +activities(card=this mode="card")
template(name="editCardTitleForm")
textarea.js-edit-card-title(rows='1' autofocus)
- = title
+ = getTitle
.edit-controls.clearfix
button.primary.confirm.js-submit-edit-card-title-form(type="submit") {{_ 'save'}}
a.fa.fa-times-thin.js-close-inlined-form
template(name="editCardRequesterForm")
- input.js-edit-card-requester(type='text' autofocus value=requestedBy)
+ input.js-edit-card-requester(type='text' autofocus value=getRequestedBy)
.edit-controls.clearfix
button.primary.confirm.js-submit-edit-card-requester-form(type="submit") {{_ 'save'}}
a.fa.fa-times-thin.js-close-inlined-form
template(name="editCardAssignerForm")
- input.js-edit-card-assigner(type='text' autofocus value=assignedBy)
+ input.js-edit-card-assigner(type='text' autofocus value=getAssignedBy)
.edit-controls.clearfix
button.primary.confirm.js-submit-edit-card-assigner-form(type="submit") {{_ 'save'}}
a.fa.fa-times-thin.js-close-inlined-form
@@ -230,7 +249,7 @@ template(name="moveCardPopup")
template(name="copyCardPopup")
label(for='copy-card-title') {{_ 'title'}}:
textarea#copy-card-title.minicard-composer-textarea.js-card-title(autofocus)
- = title
+ = getTitle
+boardsAndLists
template(name="copyChecklistToManyCardsPopup")
diff --git a/client/components/cards/cardDetails.js b/client/components/cards/cardDetails.js
index b41bfc17..2cd399c1 100644
--- a/client/components/cards/cardDetails.js
+++ b/client/components/cards/cardDetails.js
@@ -274,7 +274,7 @@ BlazeComponent.extendComponent({
close(isReset = false) {
if (this.isOpen.get() && !isReset) {
const draft = this.getValue().trim();
- if (draft !== Cards.findOne(Session.get('currentCard')).description) {
+ if (draft !== Cards.findOne(Session.get('currentCard')).getDescription()) {
UnsavedEdits.set(this._getUnsavedEditKey(), this.getValue());
}
}
diff --git a/client/components/cards/cardDetails.styl b/client/components/cards/cardDetails.styl
index 11660593..1e290305 100644
--- a/client/components/cards/cardDetails.styl
+++ b/client/components/cards/cardDetails.styl
@@ -5,7 +5,8 @@
flex-shrink: 0
flex-basis: 470px
will-change: flex-basis
- overflow: hidden
+ overflow-y: scroll
+ overflow-x: hidden
background: darken(white, 3%)
border-radius: bottom 3px
z-index: 20 !important
@@ -46,6 +47,12 @@
margin: 7px 0 0
padding: 0
+ .linked-card-location
+ font-style: italic
+ font-size: 1em
+ margin-bottom: 0
+ & p
+ margin-bottom: 0
form.inlined-form
margin-top: 5px
diff --git a/client/components/cards/cardTime.jade b/client/components/cards/cardTime.jade
index dcfc92f0..8af8c414 100644
--- a/client/components/cards/cardTime.jade
+++ b/client/components/cards/cardTime.jade
@@ -3,10 +3,10 @@ template(name="editCardSpentTime")
form.edit-time
.fields
label(for="time") {{_ 'time'}}
- input.js-time-field#time(type="number" step="0.01" name="time" value="{{card.spentTime}}" placeholder=timeFormat autofocus)
+ input.js-time-field#time(type="number" step="0.01" name="time" value="{{card.getSpentTime}}" placeholder=timeFormat autofocus)
label(for="overtime") {{_ 'overtime'}}
a.js-toggle-overtime
- .materialCheckBox#overtime(class="{{#if card.isOvertime}}is-checked{{/if}}" name="overtime")
+ .materialCheckBox#overtime(class="{{#if getIsOvertime}}is-checked{{/if}}" name="overtime")
if error.get
.warning {{_ error.get}}
@@ -15,8 +15,8 @@ template(name="editCardSpentTime")
template(name="timeBadge")
if canModifyCard
- a.js-edit-time.card-time(title="{{showTitle}}" class="{{#if isOvertime}}card-label-red{{else}}card-label-green{{/if}}")
+ a.js-edit-time.card-time(title="{{showTitle}}" class="{{#if getIsOvertime}}card-label-red{{else}}card-label-green{{/if}}")
| {{showTime}}
else
- a.card-time(title="{{showTitle}}" class="{{#if isOvertime}}card-label-red{{else}}card-label-green{{/if}}")
+ a.card-time(title="{{showTitle}}" class="{{#if getIsOvertime}}card-label-red{{else}}card-label-green{{/if}}")
| {{showTime}}
diff --git a/client/components/cards/cardTime.js b/client/components/cards/cardTime.js
index eadcc88e..80b7fc84 100644
--- a/client/components/cards/cardTime.js
+++ b/client/components/cards/cardTime.js
@@ -7,17 +7,17 @@ BlazeComponent.extendComponent({
this.card = this.data();
},
toggleOvertime() {
- this.card.isOvertime = !this.card.isOvertime;
+ this.card.setIsOvertime(!this.card.getIsOvertime());
$('#overtime .materialCheckBox').toggleClass('is-checked');
$('#overtime').toggleClass('is-checked');
},
storeTime(spentTime, isOvertime) {
this.card.setSpentTime(spentTime);
- this.card.setOvertime(isOvertime);
+ this.card.setIsOvertime(isOvertime);
},
deleteTime() {
- this.card.unsetSpentTime();
+ this.card.setSpentTime(null);
},
events() {
return [{
@@ -26,7 +26,7 @@ BlazeComponent.extendComponent({
evt.preventDefault();
const spentTime = parseFloat(evt.target.time.value);
- const isOvertime = this.card.isOvertime;
+ const isOvertime = this.card.getIsOvertime();
if (spentTime >= 0) {
this.storeTime(spentTime, isOvertime);
@@ -55,17 +55,14 @@ BlazeComponent.extendComponent({
self.time = ReactiveVar();
},
showTitle() {
- if (this.data().isOvertime) {
- return `${TAPi18n.__('overtime')} ${this.data().spentTime} ${TAPi18n.__('hours')}`;
+ if (this.data().getIsOvertime()) {
+ return `${TAPi18n.__('overtime')} ${this.data().getSpentTime()} ${TAPi18n.__('hours')}`;
} else {
- return `${TAPi18n.__('card-spent')} ${this.data().spentTime} ${TAPi18n.__('hours')}`;
+ return `${TAPi18n.__('card-spent')} ${this.data().getSpentTime()} ${TAPi18n.__('hours')}`;
}
},
showTime() {
- return this.data().spentTime;
- },
- isOvertime() {
- return this.data().isOvertime;
+ return this.data().getSpentTime();
},
events() {
return [{
diff --git a/client/components/cards/checklists.js b/client/components/cards/checklists.js
index e014abba..5d789351 100644
--- a/client/components/cards/checklists.js
+++ b/client/components/cards/checklists.js
@@ -74,8 +74,10 @@ BlazeComponent.extendComponent({
event.preventDefault();
const textarea = this.find('textarea.js-add-checklist-item');
const title = textarea.value.trim();
- const cardId = this.currentData().cardId;
+ let cardId = this.currentData().cardId;
const card = Cards.findOne(cardId);
+ if (card.isLinked())
+ cardId = card.linkedId;
if (title) {
Checklists.insert({
diff --git a/client/components/cards/minicard.jade b/client/components/cards/minicard.jade
index 3f7e0940..5c609802 100644
--- a/client/components/cards/minicard.jade
+++ b/client/components/cards/minicard.jade
@@ -1,5 +1,7 @@
template(name="minicard")
- .minicard
+ .minicard(
+ class="{{#if isLinkedCard}}linked-card{{/if}}"
+ class="{{#if isLinkedBoard}}linked-board{{/if}}")
if cover
.minicard-cover(style="background-image: url('{{cover.url}}');")
if labels
@@ -13,8 +15,16 @@ template(name="minicard")
if $eq 'prefix-with-parent' currentBoard.presentParentTask
.parent-prefix
| {{ parentCardName }}
+ if isLinkedBoard
+ a.js-linked-link
+ span.linked-icon.fa.fa-folder
+ else if isLinkedCard
+ a.js-linked-link
+ span.linked-icon.fa.fa-id-card
+ if getArchived
+ span.linked-icon.linked-archived.fa.fa-archive
+viewer
- | {{ title }}
+ = getTitle
if $eq 'subtext-with-full-path' currentBoard.presentParentTask
.parent-subtext
| {{ parentString ' > ' }}
@@ -23,23 +33,19 @@ template(name="minicard")
| {{ parentCardName }}
.dates
- if receivedAt
- unless startAt
- unless dueAt
- unless endAt
+ if getReceived
+ unless getStart
+ unless getDue
+ unless getEnd
.date
+minicardReceivedDate
- if startAt
+ if getStart
.date
+minicardStartDate
- if dueAt
- unless endAt
- .date
- +minicardDueDate
- if endAt
+ if getDue
.date
- +minicardEndDate
- if spentTime
+ +minicardDueDate
+ if getSpentTime
.date
+cardSpentTime
@@ -53,18 +59,19 @@ template(name="minicard")
+viewer
= trueValue
- if members
+ if getMembers
.minicard-members.js-minicard-members
- each members
+ each getMembers
+userAvatar(userId=this)
.badges
- if comments.count
- .badge(title="{{_ 'card-comments-title' comments.count }}")
- span.badge-icon.fa.fa-comment-o.badge-comment
- span.badge-text= comments.count
- if description
- .badge.badge-state-image-only(title=description)
+ unless currentUser.isNoComments
+ if comments.count
+ .badge(title="{{_ 'card-comments-title' comments.count }}")
+ span.badge-icon.fa.fa-comment-o.badge-comment
+ span.badge-text= comments.count
+ if getDescription
+ .badge.badge-state-image-only(title=getDescription)
span.badge-icon.fa.fa-align-left
if attachments.count
.badge
diff --git a/client/components/cards/minicard.js b/client/components/cards/minicard.js
index a98b5730..da7f9e01 100644
--- a/client/components/cards/minicard.js
+++ b/client/components/cards/minicard.js
@@ -6,4 +6,15 @@ BlazeComponent.extendComponent({
template() {
return 'minicard';
},
+
+ events() {
+ return [{
+ 'click .js-linked-link' () {
+ if (this.data().isLinkedCard())
+ Utils.goCardId(this.data().linkedId);
+ else if (this.data().isLinkedBoard())
+ Utils.goBoardId(this.data().linkedId);
+ },
+ }];
+ },
}).register('minicard');
diff --git a/client/components/cards/minicard.styl b/client/components/cards/minicard.styl
index 5624787c..8fec7238 100644
--- a/client/components/cards/minicard.styl
+++ b/client/components/cards/minicard.styl
@@ -44,6 +44,16 @@
transition: transform 0.2s,
border-radius 0.2s
+ &.linked-board
+ &.linked-card
+ .linked-icon
+ display: inline-block
+ margin-right: 11px
+ vertical-align: baseline
+ font-size: 0.9em
+ .linked-archived
+ color: #937760
+
.is-selected &
transform: translateX(11px)
border-bottom-right-radius: 0
@@ -87,6 +97,8 @@
.minicard-title
p:last-child
margin-bottom: 0
+ .viewer
+ display: inline-block
.dates
display: flex;
flex-direction: row;
diff --git a/client/components/cards/subtasks.js b/client/components/cards/subtasks.js
index 9c6f265e..1651d449 100644
--- a/client/components/cards/subtasks.js
+++ b/client/components/cards/subtasks.js
@@ -29,6 +29,7 @@ BlazeComponent.extendComponent({
boardId: targetBoard._id,
sort: sortIndex,
swimlaneId,
+ type: 'cardType-card',
});
// In case the filter is active we need to add the newly inserted card in
diff --git a/client/components/forms/forms.styl b/client/components/forms/forms.styl
index 4fff1e02..892a6e74 100644
--- a/client/components/forms/forms.styl
+++ b/client/components/forms/forms.styl
@@ -226,9 +226,12 @@ textarea
.edit-controls,
.add-controls
+ display: flex
+ align-items: baseline
margin-top: 0
button[type=submit]
+ input[type=button]
float: left
height: 32px
margin-top: -2px
diff --git a/client/components/lists/list.js b/client/components/lists/list.js
index 267af31c..00908faa 100644
--- a/client/components/lists/list.js
+++ b/client/components/lists/list.js
@@ -47,6 +47,7 @@ BlazeComponent.extendComponent({
items: itemsSelector,
placeholder: 'minicard-wrapper placeholder',
start(evt, ui) {
+ ui.helper.css('z-index', 1000);
ui.placeholder.height(ui.helper.height());
EscapeActions.executeUpTo('popup-close');
boardComponent.setIsDragging(true);
diff --git a/client/components/lists/list.styl b/client/components/lists/list.styl
index fa32ff6d..72cb19f4 100644
--- a/client/components/lists/list.styl
+++ b/client/components/lists/list.styl
@@ -187,3 +187,14 @@
padding: 7px
top: -@padding
right: 17px
+
+.link-board-wrapper
+ display: flex
+ align-items: baseline
+
+ .js-link-board
+ margin-left: 15px
+
+.search-card-results
+ max-height: 250px
+ overflow: hidden
diff --git a/client/components/lists/listBody.jade b/client/components/lists/listBody.jade
index 32c6b278..f2b3e941 100644
--- a/client/components/lists/listBody.jade
+++ b/client/components/lists/listBody.jade
@@ -34,8 +34,60 @@ template(name="addCardForm")
.add-controls.clearfix
button.primary.confirm(type="submit") {{_ 'add'}}
- a.fa.fa-times-thin.js-close-inlined-form
+ span.quiet
+ | {{_ 'or'}}
+ a.js-link {{_ 'link'}}
+ span.quiet
+ | &nbsp;
+ | /
+ a.js-search {{_ 'search'}}
template(name="autocompleteLabelLine")
.minicard-label(class="card-label-{{colorName}}" title=labelName)
span(class="{{#if hasNoName}}quiet{{/if}}")= labelName
+
+template(name="linkCardPopup")
+ label {{_ 'boards'}}:
+ .link-board-wrapper
+ select.js-select-boards
+ each boards
+ if $eq _id currentBoard._id
+ option(value="{{_id}}" selected) {{_ 'current'}}
+ else
+ option(value="{{_id}}") {{title}}
+ input.primary.confirm.js-link-board(type="button" value="{{_ 'link'}}")
+
+ label {{_ 'swimlanes'}}:
+ select.js-select-swimlanes
+ each swimlanes
+ option(value="{{_id}}") {{title}}
+
+ label {{_ 'lists'}}:
+ select.js-select-lists
+ each lists
+ option(value="{{_id}}") {{title}}
+
+ label {{_ 'cards'}}:
+ select.js-select-cards
+ each cards
+ option(value="{{getId}}") {{getTitle}}
+
+ .edit-controls.clearfix
+ input.primary.confirm.js-done(type="button" value="{{_ 'link'}}")
+
+template(name="searchCardPopup")
+ label {{_ 'boards'}}:
+ .link-board-wrapper
+ select.js-select-boards
+ each boards
+ if $eq _id currentBoard._id
+ option(value="{{_id}}" selected) {{_ 'current'}}
+ else
+ option(value="{{_id}}") {{title}}
+ form.js-search-term-form
+ input(type="text" name="searchTerm" placeholder="{{_ 'search-example'}}" autofocus)
+ .list-body.js-perfect-scrollbar.search-card-results
+ .minicards.clearfix.js-minicards
+ each results
+ a.minicard-wrapper.js-minicard
+ +minicard(this)
diff --git a/client/components/lists/listBody.js b/client/components/lists/listBody.js
index b93b7e67..ce8396b9 100644
--- a/client/components/lists/listBody.js
+++ b/client/components/lists/listBody.js
@@ -1,3 +1,5 @@
+const subManager = new SubsManager();
+
BlazeComponent.extendComponent({
mixins() {
return [Mixins.PerfectScrollbar];
@@ -55,6 +57,7 @@ BlazeComponent.extendComponent({
boardId: boardId._id,
sort: sortIndex,
swimlaneId,
+ type: 'cardType-card',
});
// In case the filter is active we need to add the newly inserted card in
// the list of exceptions -- cards that are not filtered. Otherwise the
@@ -199,6 +202,8 @@ BlazeComponent.extendComponent({
events() {
return [{
keydown: this.pressKey,
+ 'click .js-link': Popup.open('linkCard'),
+ 'click .js-search': Popup.open('searchCard'),
}];
},
@@ -270,3 +275,226 @@ BlazeComponent.extendComponent({
});
},
}).register('addCardForm');
+
+BlazeComponent.extendComponent({
+ onCreated() {
+ // Prefetch first non-current board id
+ const boardId = Boards.findOne({
+ archived: false,
+ 'members.userId': Meteor.userId(),
+ _id: {$ne: Session.get('currentBoard')},
+ }, {
+ sort: ['title'],
+ })._id;
+ // Subscribe to this board
+ subManager.subscribe('board', boardId);
+ this.selectedBoardId = new ReactiveVar(boardId);
+ this.selectedSwimlaneId = new ReactiveVar('');
+ this.selectedListId = new ReactiveVar('');
+
+ this.boardId = Session.get('currentBoard');
+ // In order to get current board info
+ subManager.subscribe('board', this.boardId);
+ this.board = Boards.findOne(this.boardId);
+ // List where to insert card
+ const list = $(Popup._getTopStack().openerElement).closest('.js-list');
+ this.listId = Blaze.getData(list[0])._id;
+ // Swimlane where to insert card
+ const swimlane = $(Popup._getTopStack().openerElement).closest('.js-swimlane');
+ this.swimlaneId = '';
+ const boardView = Meteor.user().profile.boardView;
+ if (boardView === 'board-view-swimlanes')
+ this.swimlaneId = Blaze.getData(swimlane[0])._id;
+ else if (boardView === 'board-view-lists')
+ this.swimlaneId = Swimlanes.findOne({boardId: this.boardId})._id;
+ },
+
+ boards() {
+ const boards = Boards.find({
+ archived: false,
+ 'members.userId': Meteor.userId(),
+ _id: {$ne: Session.get('currentBoard')},
+ }, {
+ sort: ['title'],
+ });
+ return boards;
+ },
+
+ swimlanes() {
+ if (!this.selectedBoardId) {
+ return [];
+ }
+ const swimlanes = Swimlanes.find({boardId: this.selectedBoardId.get()});
+ if (swimlanes.count())
+ this.selectedSwimlaneId.set(swimlanes.fetch()[0]._id);
+ return swimlanes;
+ },
+
+ lists() {
+ if (!this.selectedBoardId) {
+ return [];
+ }
+ const lists = Lists.find({boardId: this.selectedBoardId.get()});
+ if (lists.count())
+ this.selectedListId.set(lists.fetch()[0]._id);
+ return lists;
+ },
+
+ cards() {
+ if (!this.board) {
+ return [];
+ }
+ const ownCardsIds = this.board.cards().map((card) => { return card.linkedId || card._id; });
+ return Cards.find({
+ boardId: this.selectedBoardId.get(),
+ swimlaneId: this.selectedSwimlaneId.get(),
+ listId: this.selectedListId.get(),
+ archived: false,
+ linkedId: {$nin: ownCardsIds},
+ _id: {$nin: ownCardsIds},
+ });
+ },
+
+ events() {
+ return [{
+ 'change .js-select-boards'(evt) {
+ subManager.subscribe('board', $(evt.currentTarget).val());
+ this.selectedBoardId.set($(evt.currentTarget).val());
+ },
+ 'change .js-select-swimlanes'(evt) {
+ this.selectedSwimlaneId.set($(evt.currentTarget).val());
+ },
+ 'change .js-select-lists'(evt) {
+ this.selectedListId.set($(evt.currentTarget).val());
+ },
+ 'click .js-done' (evt) {
+ // LINK CARD
+ evt.stopPropagation();
+ evt.preventDefault();
+ const linkedId = $('.js-select-cards option:selected').val();
+ if (!linkedId) {
+ Popup.close();
+ return;
+ }
+ const _id = Cards.insert({
+ title: $('.js-select-cards option:selected').text(), //dummy
+ listId: this.listId,
+ swimlaneId: this.swimlaneId,
+ boardId: this.boardId,
+ sort: Lists.findOne(this.listId).cards().count(),
+ type: 'cardType-linkedCard',
+ linkedId,
+ });
+ Filter.addException(_id);
+ Popup.close();
+ },
+ 'click .js-link-board' (evt) {
+ //LINK BOARD
+ evt.stopPropagation();
+ evt.preventDefault();
+ const impBoardId = $('.js-select-boards option:selected').val();
+ if (!impBoardId || Cards.findOne({linkedId: impBoardId, archived: false})) {
+ Popup.close();
+ return;
+ }
+ const _id = Cards.insert({
+ title: $('.js-select-boards option:selected').text(), //dummy
+ listId: this.listId,
+ swimlaneId: this.swimlaneId,
+ boardId: this.boardId,
+ sort: Lists.findOne(this.listId).cards().count(),
+ type: 'cardType-linkedBoard',
+ linkedId: impBoardId,
+ });
+ Filter.addException(_id);
+ Popup.close();
+ },
+ }];
+ },
+}).register('linkCardPopup');
+
+BlazeComponent.extendComponent({
+ mixins() {
+ return [Mixins.PerfectScrollbar];
+ },
+
+ onCreated() {
+ // Prefetch first non-current board id
+ let board = Boards.findOne({
+ archived: false,
+ 'members.userId': Meteor.userId(),
+ _id: {$ne: Session.get('currentBoard')},
+ });
+ if (!board) {
+ Popup.close();
+ return;
+ }
+ const boardId = board._id;
+ // Subscribe to this board
+ subManager.subscribe('board', boardId);
+ this.selectedBoardId = new ReactiveVar(boardId);
+
+ this.boardId = Session.get('currentBoard');
+ // In order to get current board info
+ subManager.subscribe('board', this.boardId);
+ board = Boards.findOne(this.boardId);
+ // List where to insert card
+ const list = $(Popup._getTopStack().openerElement).closest('.js-list');
+ this.listId = Blaze.getData(list[0])._id;
+ // Swimlane where to insert card
+ const swimlane = $(Popup._getTopStack().openerElement).closest('.js-swimlane');
+ this.swimlaneId = '';
+ if (board.view === 'board-view-swimlanes')
+ this.swimlaneId = Blaze.getData(swimlane[0])._id;
+ else
+ this.swimlaneId = Swimlanes.findOne({boardId: this.boardId})._id;
+ this.term = new ReactiveVar('');
+ },
+
+ boards() {
+ const boards = Boards.find({
+ archived: false,
+ 'members.userId': Meteor.userId(),
+ _id: {$ne: Session.get('currentBoard')},
+ }, {
+ sort: ['title'],
+ });
+ return boards;
+ },
+
+ results() {
+ if (!this.selectedBoardId) {
+ return [];
+ }
+ const board = Boards.findOne(this.selectedBoardId.get());
+ return board.searchCards(this.term.get(), false);
+ },
+
+ events() {
+ return [{
+ 'change .js-select-boards'(evt) {
+ subManager.subscribe('board', $(evt.currentTarget).val());
+ this.selectedBoardId.set($(evt.currentTarget).val());
+ },
+ 'submit .js-search-term-form'(evt) {
+ evt.preventDefault();
+ this.term.set(evt.target.searchTerm.value);
+ },
+ 'click .js-minicard'(evt) {
+ // LINK CARD
+ const card = Blaze.getData(evt.currentTarget);
+ const _id = Cards.insert({
+ title: card.title, //dummy
+ listId: this.listId,
+ swimlaneId: this.swimlaneId,
+ boardId: this.boardId,
+ sort: Lists.findOne(this.listId).cards().count(),
+ type: 'cardType-linkedCard',
+ linkedId: card.linkedId || card._id,
+ });
+ Filter.addException(_id);
+ Popup.close();
+ },
+ }];
+ },
+}).register('searchCardPopup');
diff --git a/client/components/main/header.jade b/client/components/main/header.jade
index dd071b3e..2751c0cc 100644
--- a/client/components/main/header.jade
+++ b/client/components/main/header.jade
@@ -66,7 +66,8 @@ template(name="header")
.announcement
p
i.fa.fa-bullhorn
- | #{announcement}
+ +viewer
+ | #{announcement}
i.fa.fa-times-circle.js-close-announcement
template(name="offlineWarning")
diff --git a/client/components/main/layouts.jade b/client/components/main/layouts.jade
index ff2d8d0a..ac7da3af 100644
--- a/client/components/main/layouts.jade
+++ b/client/components/main/layouts.jade
@@ -9,6 +9,7 @@ head
packages.
link(rel="shortcut icon" href="/wekan-favicon.png")
link(rel="apple-touch-icon" href="/wekan-favicon.png")
+ link(rel="mask-icon" href="/wekan-150.svg")
link(rel="manifest" href="/wekan-manifest.json")
template(name="userFormsLayout")
diff --git a/client/components/settings/invitationCode.js b/client/components/settings/invitationCode.js
index a403d8ab..fa355179 100644
--- a/client/components/settings/invitationCode.js
+++ b/client/components/settings/invitationCode.js
@@ -1,6 +1,13 @@
-Template.invitationCode.onRendered(() => {
- const setting = Settings.findOne();
- if (!setting || !setting.disableRegistration) {
- $('#invitationcode').hide();
- }
+Template.invitationCode.onRendered(function() {
+ Meteor.subscribe('setting', {
+ onReady() {
+ const setting = Settings.findOne();
+
+ if (!setting || !setting.disableRegistration) {
+ $('#invitationcode').hide();
+ }
+
+ return this.stop();
+ },
+ });
});
diff --git a/client/components/settings/settingBody.jade b/client/components/settings/settingBody.jade
index 5bc7972d..dcf71f4d 100644
--- a/client/components/settings/settingBody.jade
+++ b/client/components/settings/settingBody.jade
@@ -72,7 +72,7 @@ template(name='email')
li.smtp-form
.title {{_ 'smtp-password'}}
.form-group
- input.form-control#mail-server-password(type="text", placeholder="{{_ 'password'}}" value="{{currentSetting.mailServer.password}}")
+ input.form-control#mail-server-password(type="text", placeholder="{{_ 'password'}}" value="")
li.smtp-form
.title {{_ 'smtp-tls'}}
.form-group
diff --git a/client/components/sidebar/sidebar.jade b/client/components/sidebar/sidebar.jade
index 6085c2ad..ec88ce7e 100644
--- a/client/components/sidebar/sidebar.jade
+++ b/client/components/sidebar/sidebar.jade
@@ -23,10 +23,11 @@ template(name='homeSidebar')
hr
+labelsWidget
hr
- h3
- i.fa.fa-comments-o
- | {{_ 'activities'}}
- +activities(mode="board")
+ unless currentUser.isNoComments
+ h3
+ i.fa.fa-comments-o
+ | {{_ 'activities'}}
+ +activities(mode="board")
template(name="membersWidget")
.board-widget.board-widget-members
@@ -146,6 +147,12 @@ template(name="changePermissionsPopup")
i.fa.fa-check
span.sub-name {{_ 'normal-desc'}}
li
+ a(class="{{#if isLastAdmin}}disabled{{else}}js-set-no-comments{{/if}}")
+ | {{_ 'no-comments'}}
+ if isNoComments
+ i.fa.fa-check
+ span.sub-name {{_ 'no-comments-desc'}}
+ li
a(class="{{#if isLastAdmin}}disabled{{else}}js-set-comment-only{{/if}}")
| {{_ 'comment-only'}}
if isCommentOnly
diff --git a/client/components/sidebar/sidebar.js b/client/components/sidebar/sidebar.js
index 5a9de74b..5d34c4a8 100644
--- a/client/components/sidebar/sidebar.js
+++ b/client/components/sidebar/sidebar.js
@@ -126,8 +126,11 @@ Template.memberPopup.helpers({
if(type === 'normal'){
const currentBoard = Boards.findOne(Session.get('currentBoard'));
const commentOnly = currentBoard.hasCommentOnly(this.userId);
+ const noComments = currentBoard.hasNoComments(this.userId);
if(commentOnly){
return TAPi18n.__('comment-only').toLowerCase();
+ } else if(noComments) {
+ return TAPi18n.__('no-comments').toLowerCase();
} else {
return TAPi18n.__(type).toLowerCase();
}
@@ -324,12 +327,13 @@ BlazeComponent.extendComponent({
}).register('addMemberPopup');
Template.changePermissionsPopup.events({
- 'click .js-set-admin, click .js-set-normal, click .js-set-comment-only'(event) {
+ 'click .js-set-admin, click .js-set-normal, click .js-set-no-comments, click .js-set-comment-only'(event) {
const currentBoard = Boards.findOne(Session.get('currentBoard'));
const memberId = this.userId;
const isAdmin = $(event.currentTarget).hasClass('js-set-admin');
const isCommentOnly = $(event.currentTarget).hasClass('js-set-comment-only');
- currentBoard.setMemberPermission(memberId, isAdmin, isCommentOnly);
+ const isNoComments = $(event.currentTarget).hasClass('js-set-no-comments');
+ currentBoard.setMemberPermission(memberId, isAdmin, isNoComments, isCommentOnly);
Popup.back(1);
},
});
@@ -342,7 +346,12 @@ Template.changePermissionsPopup.helpers({
isNormal() {
const currentBoard = Boards.findOne(Session.get('currentBoard'));
- return !currentBoard.hasAdmin(this.userId) && !currentBoard.hasCommentOnly(this.userId);
+ return !currentBoard.hasAdmin(this.userId) && !currentBoard.hasNoComments(this.userId) && !currentBoard.hasCommentOnly(this.userId);
+ },
+
+ isNoComments() {
+ const currentBoard = Boards.findOne(Session.get('currentBoard'));
+ return !currentBoard.hasAdmin(this.userId) && currentBoard.hasNoComments(this.userId);
},
isCommentOnly() {
diff --git a/client/components/users/userAvatar.jade b/client/components/users/userAvatar.jade
index 83e2c8d0..ebfa48ba 100644
--- a/client/components/users/userAvatar.jade
+++ b/client/components/users/userAvatar.jade
@@ -1,7 +1,7 @@
template(name="userAvatar")
a.member.js-member(title="{{userData.profile.fullname}} ({{userData.username}})")
if userData.profile.avatarUrl
- img.avatar.avatar-image(src=userData.profile.avatarUrl)
+ img.avatar.avatar-image(src="{{userData.profile.avatarUrl}}")
else
+userAvatarInitials(userId=userData._id)
diff --git a/client/components/users/userAvatar.js b/client/components/users/userAvatar.js
index be7a85d2..91cad237 100644
--- a/client/components/users/userAvatar.js
+++ b/client/components/users/userAvatar.js
@@ -134,8 +134,9 @@ BlazeComponent.extendComponent({
Template.cardMembersPopup.helpers({
isCardMember() {
- const cardId = Template.parentData()._id;
- const cardMembers = Cards.findOne(cardId).members || [];
+ const card = Template.parentData();
+ const cardMembers = card.getMembers();
+
return _.contains(cardMembers, this.userId);
},