Merge branch 'develop' into release

This commit is contained in:
Sabe Jones
2019-05-02 14:25:02 -05:00
33 changed files with 514 additions and 255 deletions

View File

@@ -1,5 +1,5 @@
<template lang="pug">
b-modal#rebirth(:title="$t('modalAchievement')", size='md', :hide-footer="true", @hidden="reloadPage()")
b-modal#rebirth(:title="$t('modalAchievement')", size='md', :hide-footer="true")
.modal-body
.col-12
// @TODO: +achievementAvatar('sun',0)
@@ -41,9 +41,6 @@
close () {
this.$root.$emit('bv::hide::modal', 'rebirth');
},
reloadPage () {
window.location.reload(true);
},
},
};
</script>

View File

@@ -376,6 +376,8 @@ export default {
openMemberProgressModal (member) {
this.$root.$emit('habitica:challenge:member-progress', {
progressMemberId: member._id,
isLeader: this.isLeader,
isAdmin: this.isAdmin,
});
},
async exportChallengeCsv () {

View File

@@ -1,6 +1,6 @@
<template lang="pug">
b-modal#challenge-member-modal(title="User Progress", size='lg')
.row.award-row
.row.award-row(v-if='isLeader || isAdmin')
.col-12.text-center
button.btn.btn-primary(v-once, @click='closeChallenge()') {{ $t('awardWinners') }}
.row
@@ -37,12 +37,16 @@ export default {
reward: [],
},
memberId: '',
isLeader: false,
isAdmin: false,
};
},
mounted () {
this.$root.$on('habitica:challenge:member-progress', (data) => {
if (!data.progressMemberId) return;
this.memberId = data.progressMemberId;
this.isLeader = data.isLeader;
this.isAdmin = data.isAdmin;
this.$root.$emit('bv::show::modal', 'challenge-member-modal');
});
},

View File

@@ -16,54 +16,7 @@
h1 {{ $t('groupTasksTitle') }}
// @TODO: Abstract to component!
.col-12.col-md-4
.input-group
input.form-control.input-search(type="text", :placeholder="$t('search')", v-model="searchText")
.filter-panel(v-if="isFilterPanelOpen")
.tags-category(v-for="tagsType in tagsByType", v-if="tagsType.tags.length > 0", :key="tagsType.key")
.tags-header.col-12
strong(v-once) {{ $t(tagsType.key) }}
a.d-block(v-if="tagsType.key === 'tags' && !editingTags", @click="editTags()") {{ $t('editTags2') }}
.tags-list.container.col-12
.row(:class="{'no-gutters': !editingTags}")
template(v-if="editingTags && tagsType.key === 'tags'")
.col-12.col-md-6(v-for="(tag, tagIndex) in tagsSnap")
.inline-edit-input-group.tag-edit-item.input-group
input.tag-edit-input.inline-edit-input.form-control(type="text", :value="tag.name")
.input-group-append(@click="removeTag(tagIndex)")
.svg-icon.destroy-icon(v-html="icons.destroy")
.col-12.col-md-6
input.new-tag-item.edit-tag-item.inline-edit-input.form-control(type="text", :placeholder="$t('newTag')", @keydown.enter="addTag($event)", v-model="newTag")
template(v-else)
.col-12.col-md-6(v-for="(tag, tagIndex) in tagsType.tags")
.custom-control.custom-checkbox
input.custom-control-input(
type="checkbox",
:checked="isTagSelected(tag)",
@change="toggleTag(tag)",
:id="`tag-${tagsType.key}-${tagIndex}`",
)
label.custom-control-label(:for="`tag-${tagsType.key}-${tagIndex}`") {{ tag.name }}
.filter-panel-footer.clearfix
template(v-if="editingTags === true")
.text-center
a.mr-3.btn-filters-primary(@click="saveTags()", v-once) {{ $t('saveEdits') }}
a.btn-filters-secondary(@click="cancelTagsEditing()", v-once) {{ $t('cancel') }}
template(v-else)
.float-left
a.btn-filters-danger(@click="resetFilters()", v-once) {{ $t('resetFilters') }}
.float-right
a.mr-3.btn-filters-primary(@click="applyFilters()", v-once) {{ $t('applyFilters') }}
a.btn-filters-secondary(@click="closeFilterPanel()", v-once) {{ $t('cancel') }}
span.input-group-append
button.btn.btn-secondary.filter-button(
type="button",
@click="toggleFilterPanel()",
:class="{'filter-button-open': selectedTags.length > 0}",
)
.d-flex.align-items-center
span(v-once) {{ $t('filter') }}
.svg-icon.filter-icon(v-html="icons.filter")
input.form-control.input-search(type="text", :placeholder="$t('search')", v-model="searchText")
.create-task-area.d-flex(v-if='canCreateTasks')
transition(name="slide-tasks-btns")
.d-flex(v-if="openCreateBtn")
@@ -99,10 +52,6 @@
@import '~client/assets/scss/colors.scss';
@import '~client/assets/scss/create-task.scss';
.user-tasks-page {
padding-top: 31px;
}
.tasks-navigation {
margin-bottom: 40px;
}
@@ -114,133 +63,6 @@
margin-right: 8px;
padding-top: 6px;
}
.dropdown-icon-item .svg-icon {
width: 16px;
}
button.btn.btn-secondary.filter-button {
box-shadow: none;
border-radius: 2px;
border: 1px solid $gray-400 !important;
&:hover, &:active, &:focus, &.open {
box-shadow: none;
border-color: $purple-500 !important;
color: $gray-50 !important;
}
&.filter-button-open {
color: $purple-200 !important;
.filter-icon {
color: $purple-200 !important;
}
}
.filter-icon {
height: 10px;
width: 12px;
color: $gray-50;
margin-left: 15px;
}
}
.filter-panel {
position: absolute;
padding-left: 24px;
padding-right: 24px;
max-width: 40vw;
width: 100%;
z-index: 9999;
background: $white;
border-radius: 2px;
box-shadow: 0 2px 2px 0 rgba($black, 0.16), 0 1px 4px 0 rgba($black, 0.12);
top: 44px;
left: 20vw;
font-size: 14px;
line-height: 1.43;
text-overflow: ellipsis;
.tags-category {
border-bottom: 1px solid $gray-600;
padding-bottom: 24px;
padding-top: 24px;
}
.tags-header {
flex-basis: 96px;
flex-shrink: 0;
a {
font-size: 12px;
line-height: 1.33;
color: $blue-10;
margin-top: 4px;
&:focus, &:hover, &:active {
text-decoration: underline;
}
}
}
.tag-edit-input {
border-bottom: 1px solid $gray-500 !important;
&:focus, &:focus ~ .input-group-append {
border-color: $purple-500 !important;
}
}
.new-tag-item {
width: 100%;
background-repeat: no-repeat;
background-position: center left 10px;
border-bottom: 1px solid $gray-500 !important;
background-size: 10px 10px;
padding-left: 40px;
background-image: url(~client/assets/svg/for-css/positive.svg);
}
.tag-edit-item .input-group-append {
border-bottom: 1px solid $gray-500 !important;
&:focus {
border-color: $purple-500;
}
}
.custom-control-label {
margin-left: 10px;
}
.filter-panel-footer {
padding-top: 16px;
padding-bottom: 16px;
a {
&:focus, &:hover, &:active {
text-decoration: underline;
}
}
.btn-filters-danger {
color: $red-50;
}
.btn-filters-primary {
color: $blue-10;
}
.btn-filters-secondary {
color: $gray-300;
}
}
}
.button-label {
display: inline-block;
}
</style>
<script>

View File

@@ -0,0 +1,26 @@
<template lang="pug">
base-notification(
:can-remove="canRemove",
:has-icon="false",
:notification="notification",
:read-after-click="true",
@click="action",
)
div(slot="content", v-html="notification.data.message")
</template>
<script>
import BaseNotification from './base';
export default {
props: ['notification', 'canRemove'],
components: {
BaseNotification,
},
methods: {
action () {
this.$router.push({ name: 'tasks'});
},
},
};
</script>

View File

@@ -87,6 +87,7 @@ import CHALLENGE_INVITATION from './notifications/challengeInvitation';
import QUEST_INVITATION from './notifications/questInvitation';
import GROUP_TASK_APPROVAL from './notifications/groupTaskApproval';
import GROUP_TASK_APPROVED from './notifications/groupTaskApproved';
import GROUP_TASK_ASSIGNED from './notifications/groupTaskAssigned';
import UNALLOCATED_STATS_POINTS from './notifications/unallocatedStatsPoints';
import NEW_MYSTERY_ITEMS from './notifications/newMysteryItems';
import CARD_RECEIVED from './notifications/cardReceived';
@@ -102,7 +103,7 @@ export default {
// One component for each type
NEW_STUFF, GROUP_TASK_NEEDS_WORK,
GUILD_INVITATION, PARTY_INVITATION, CHALLENGE_INVITATION,
QUEST_INVITATION, GROUP_TASK_APPROVAL, GROUP_TASK_APPROVED,
QUEST_INVITATION, GROUP_TASK_APPROVAL, GROUP_TASK_APPROVED, GROUP_TASK_ASSIGNED,
UNALLOCATED_STATS_POINTS, NEW_MYSTERY_ITEMS, CARD_RECEIVED,
NEW_INBOX_MESSAGE, NEW_CHAT_MESSAGE,
WorldBoss: WORLD_BOSS,
@@ -118,7 +119,7 @@ export default {
openStatus: undefined,
actionableNotifications: [
'GUILD_INVITATION', 'PARTY_INVITATION', 'CHALLENGE_INVITATION',
'QUEST_INVITATION', 'GROUP_TASK_NEEDS_WORK',
'QUEST_INVITATION', 'GROUP_TASK_NEEDS_WORK', 'GROUP_TASK_APPROVAL',
],
// A list of notifications handled by this component,
// listed in the order they should appear in the notifications panel.
@@ -126,7 +127,7 @@ export default {
handledNotifications: [
'NEW_STUFF', 'GROUP_TASK_NEEDS_WORK',
'GUILD_INVITATION', 'PARTY_INVITATION', 'CHALLENGE_INVITATION',
'QUEST_INVITATION', 'GROUP_TASK_APPROVAL', 'GROUP_TASK_APPROVED',
'QUEST_INVITATION', 'GROUP_TASK_ASSIGNED', 'GROUP_TASK_APPROVAL', 'GROUP_TASK_APPROVED',
'NEW_MYSTERY_ITEMS', 'CARD_RECEIVED',
'NEW_INBOX_MESSAGE', 'NEW_CHAT_MESSAGE', 'UNALLOCATED_STATS_POINTS',
'VERIFY_USERNAME',

View File

@@ -132,11 +132,6 @@ const NOTIFICATIONS = {
label: ($t) => `${$t('achievement')}: ${$t('gearAchievementNotification')}`,
modalId: 'ultimate-gear',
},
REBIRTH_ACHIEVEMENT: {
label: ($t) => `${$t('achievement')}: ${$t('rebirthBegan')}`,
achievement: true,
modalId: 'rebirth',
},
GUILD_JOINED_ACHIEVEMENT: {
label: ($t) => `${$t('achievement')}: ${$t('joinedGuild')}`,
achievement: true,
@@ -360,18 +355,7 @@ export default {
this.playSound(config.sound);
}
if (type === 'REBIRTH_ACHIEVEMENT') {
// reload if the user hasn't clicked on the notification
const timeOut = setTimeout(() => {
window.location.reload(true);
}, 60000);
this.text(config.label(this.$t), () => {
// prevent the current reload timeout
clearTimeout(timeOut);
this.$root.$emit('bv::show::modal', config.modalId);
}, false);
} else if (forceToModal) {
if (forceToModal) {
this.$root.$emit('bv::show::modal', config.modalId);
} else {
this.text(config.label(this.$t), () => {
@@ -573,8 +557,11 @@ export default {
}, this.user.preferences.suppressModals.streak);
this.playSound('Achievement_Unlocked');
break;
case 'ULTIMATE_GEAR_ACHIEVEMENT':
case 'REBIRTH_ACHIEVEMENT':
this.playSound('Achievement_Unlocked');
this.$root.$emit('bv::show::modal', 'rebirth');
break;
case 'ULTIMATE_GEAR_ACHIEVEMENT':
case 'GUILD_JOINED_ACHIEVEMENT':
case 'CHALLENGE_JOINED_ACHIEVEMENT':
case 'INVITED_FRIEND_ACHIEVEMENT':

View File

@@ -75,7 +75,7 @@
:class="{'notEnough': !preventHealthPotion || !this.enoughCurrency(getPriceClass(), item.value * selectedAmountToBuy)}"
) {{ $t('buyNow') }}
div.limitedTime(v-if="item.event")
div.limitedTime(v-if="item.event && item.owned == null")
span.svg-icon.inline.icon-16(v-html="icons.clock")
span.limitedString {{ limitedString }}
@@ -397,6 +397,10 @@
this.$emit('buyPressed', this.item);
this.hideDialog();
if (this.item.key === 'rebirth_orb') {
window.location.reload(true);
}
},
purchaseGems () {
if (this.item.key === 'rebirth_orb') {

View File

@@ -5,7 +5,7 @@ div
slot(name="itemBadge", :item="item", :emptyItem="emptyItem")
span.badge.badge-pill.badge-item.badge-clock(
v-if="item.event && showEventBadge",
v-if="item.event && item.owned == null && showEventBadge",
)
span.svg-icon.inline.clock(v-html="icons.clock")

View File

@@ -1,11 +1,15 @@
<template lang="pug">
.tags-popup
.tags-category.d-flex
.tags-category.d-flex(
v-for="tagsType in tagsByType",
v-if="tagsType.tags.length > 0 || tagsType.key === 'tags'",
:key="tagsType.key"
)
.tags-header
strong(v-once) {{ $t('tags') }}
strong(v-once) {{ $t(tagsType.key) }}
.tags-list.container
.row
.col-4(v-for="tag in tags")
.col-4(v-for="(tag, tagIndex) in tagsType.tags")
.custom-control.custom-checkbox
input.custom-control-input(type="checkbox", :value="tag.id", v-model="selectedTags", :id="`tag-${tag.id}`")
label.custom-control-label(:title="tag.name", :for="`tag-${tag.id}`", v-markdown="tag.name")
@@ -103,6 +107,34 @@ export default {
selectedTags: [],
};
},
computed: {
tagsByType () {
const tagsByType = {
challenges: {
key: 'challenges',
tags: [],
},
groups: {
key: 'groups',
tags: [],
},
user: {
key: 'tags',
tags: [],
},
};
this.$props.tags.forEach(t => {
if (t.group) {
tagsByType.groups.tags.push(t);
} else if (t.challenge) {
tagsByType.challenges.tags.push(t);
} else {
tagsByType.user.tags.push(t);
}
});
return tagsByType;
},
},
watch: {
selectedTags () {
this.$emit('input', this.selectedTags);

View File

@@ -159,6 +159,15 @@
| {{ $t(frequency) }}
.option.group-options(v-if='groupId')
.form-group(v-if="task.type === 'todo'")
label(v-once) {{ $t('sharedCompletion') }}
b-dropdown.inline-dropdown(:text="$t(sharedCompletion)")
b-dropdown-item(
v-for="completionOption in ['recurringCompletion', 'singleCompletion', 'allAssignedCompletion']",
:key="completionOption",
@click="sharedCompletion = completionOption",
:class="{active: sharedCompletion === completionOption}"
) {{ $t(completionOption) }}
.form-group.row
label.col-12(v-once) {{ $t('assignedTo') }}
.col-12.mt-2
@@ -179,23 +188,12 @@
.row
button.btn.btn-primary(@click.stop.prevent="showAssignedSelect = !showAssignedSelect") {{$t('close')}}
.option.group-options(v-if='groupId')
.form-group
label(v-once) {{ $t('approvalRequired') }}
toggle-switch.d-inline-block(
:checked="requiresApproval",
@change="updateRequiresApproval"
)
.form-group(v-if="task.type === 'todo'")
label(v-once) {{ $t('sharedCompletion') }}
b-dropdown.inline-dropdown(:text="$t(sharedCompletion)")
b-dropdown-item(
v-for="completionOption in ['recurringCompletion', 'singleCompletion', 'allAssignedCompletion']",
:key="completionOption",
@click="sharedCompletion = completionOption",
:class="{active: sharedCompletion === completionOption}"
) {{ $t(completionOption) }}
.advanced-settings(v-if="task.type !== 'reward'")
.advanced-settings-toggle.d-flex.justify-content-between.align-items-center(@click = "showAdvancedOptions = !showAdvancedOptions")
@@ -360,8 +358,8 @@
margin-top: 12px;
position: relative;
label {
max-height: 30px;
.custom-control-label p {
word-break: break-word;
}
}
@@ -711,7 +709,7 @@ export default {
calendar: calendarIcon,
}),
requiresApproval: false, // We can't set task.group fields so we use this field to toggle
sharedCompletion: 'recurringCompletion',
sharedCompletion: 'singleCompletion',
members: [],
memberNamesById: {},
assignedMembers: [],
@@ -842,7 +840,7 @@ export default {
});
this.assignedMembers = [];
if (this.task.group && this.task.group.assignedUsers) this.assignedMembers = this.task.group.assignedUsers;
if (this.task.group) this.sharedCompletion = this.task.group.sharedCompletion || 'recurringCompletion';
if (this.task.group) this.sharedCompletion = this.task.group.sharedCompletion || 'singleCompletion';
}
// @TODO: This whole component is mutating a prop and that causes issues. We need to not copy the prop similar to group modals
@@ -926,7 +924,6 @@ export default {
// TODO Fix up permissions on task.group so we don't have to keep doing these hacks
if (this.groupId) {
this.task.group.assignedUsers = this.assignedMembers;
this.task.requiresApproval = this.requiresApproval;
this.task.group.approval.required = this.requiresApproval;
this.task.sharedCompletion = this.sharedCompletion;
@@ -954,6 +951,7 @@ export default {
});
});
Promise.all(promises);
this.task.group.assignedUsers = this.assignedMembers;
this.$emit('taskCreated', this.task);
} else {
this.createTask(this.task);

View File

@@ -201,6 +201,7 @@
.custom-control-label {
margin-left: 10px;
word-break: break-word;
}
.filter-panel-footer {