Update Party / Group Sidebar / Quest states (#12793)
* move groups/sidebar to groupSidebar.vue * lint files * extract group/party sidebar to rightSidebar.vue * wip stories with example data * update stories - wip sidebar re-styling * message party / group leader + move items to the menu * update paddings /place for quest section * invite to party / guild * update labels (* Party / Guild ) * guild-background to group-background * correct menu order + missing a label based on the group type * no quest - styles / layout applied * quest owner / not started - styles applied + extracted questActions from questDetailsModal.vue to a mixin * no challenge style * hover with underlines * quest-pending area layout / margins * "Collection Quest/Quest Owner Participating" Styling Done * group sidebar menu with icons / background * remove most participate button styles * fix quest-invite panel * move "Start Quest" + add "Leave Quest" * Not Participating + Boss + Rage Quests restyling * party quest changes - invitedToQuest + button styles + no-items style + view details * fix icons + rage value + colors * fix duplicate key * hide items label if 0 items found + hide pending damage if there is none + sidebar section margin + fix percent calculation 0 => 0% * combine quest abandon / cancel to one call + hide begin if quest has already started + close modal if quest was canceled * remove unused translate string * allow leaving an accepted but inactive quest + disable leave when user is quest leader * update "are you sure" questions - remove "doubleSureAbort" - add "sureLeaveInactive" * sidebar margins + menu icon color * refactored css rules * improve some styles * fix button spacing * fix dropmenu with icon hover * hide leave quest for leaders + fix quest buttons spacing * add pending items label * remove "X items found" label * first round of fixes * last v-once * Update Quest Dialogs (#13112) * new quest rewards panel + extract questPopover and itemWithLabel * WIP: questInfo still not applying the row-height.. * split up start-quest-modal into select and detail modal - also rename the current quest-details to be the group-quest-details modal * remove start-quest-modal from modal-scss * update package-lock * WIP before using the quest sidebar branch as a base * move quest detail actions to the "new" details dialog * quest details layout for owner / participant * fix quest rewards - open details modal from sidebar * apply quest-details dialog styles to the buyQuestModal one * fix quest reward icons / popover / texts * WIP back to quest selection * fix lint * merge selectQuestModal.vue with questDetailModal.vue + UI for the select quest * fix margins / layout / labels * fix quest detail + wip invitationListModal.vue / participantListModal.vue * fix questmodal user label centered * fix centered reward items + grouping items and adding a count-badge * sort quests by AZ or quantity * invitations modal * remove console.info * complete participantListModal.vue + extracted getClassName * missed a file for getClassName extraction * fix invitations * select the actual quest on details * fix margins on invite to party / start quest buttons * replace buyQuestModal close button and title * fix recursion due to the same name * missing import * sort quantity by highest first * fix "Can't find a Quest to start" styles * fix "your balance" padding * fix quest collections / drop items * fix member details in participants list * fix quest info * remove nullable because the build doesn't like it (on this file..) * add questCompleted to the stories + fix getDropName * replace quest-rewards in questCompleted.vue * fix questCompleted.vue style * delete obsolete components * add missing spritesheets to storebook * requested pr changes * refactored fetchMember * revert optional chaining * fix merge conflicts * fix rightSidebar hover colors - $scss var to css var * overflow auto instead of scroll * prevent wrapping of quest collections * rollback to multi line quest items * use min-width for the quest popover
@@ -61,15 +61,6 @@ describe('POST /groups/:groupId/quests/leave', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns an error when quest is not active', async () => {
|
|
||||||
await expect(partyMembers[0].post(`/groups/${questingGroup._id}/quests/leave`))
|
|
||||||
.to.eventually.be.rejected.and.eql({
|
|
||||||
code: 404,
|
|
||||||
error: 'NotFound',
|
|
||||||
message: t('noActiveQuestToLeave'),
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns an error when quest leader attempts to leave', async () => {
|
it('returns an error when quest leader attempts to leave', async () => {
|
||||||
await leader.post(`/groups/${questingGroup._id}/quests/invite/${PET_QUEST}`);
|
await leader.post(`/groups/${questingGroup._id}/quests/invite/${PET_QUEST}`);
|
||||||
await partyMembers[0].post(`/groups/${questingGroup._id}/quests/accept`);
|
await partyMembers[0].post(`/groups/${questingGroup._id}/quests/accept`);
|
||||||
@@ -97,18 +88,14 @@ describe('POST /groups/:groupId/quests/leave', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('leaves a quest', async () => {
|
async function letPartyMemberLeaveAndCheckChanges (partyMember) {
|
||||||
await leader.post(`/groups/${questingGroup._id}/quests/invite/${PET_QUEST}`);
|
const leaveResult = await partyMember.post(`/groups/${questingGroup._id}/quests/leave`);
|
||||||
await partyMembers[0].post(`/groups/${questingGroup._id}/quests/accept`);
|
|
||||||
await partyMembers[1].post(`/groups/${questingGroup._id}/quests/accept`);
|
|
||||||
|
|
||||||
const leaveResult = await partyMembers[0].post(`/groups/${questingGroup._id}/quests/leave`);
|
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
partyMembers[0].sync(),
|
partyMember.sync(),
|
||||||
questingGroup.sync(),
|
questingGroup.sync(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
expect(partyMembers[0].party.quest).to.eql({
|
expect(partyMember.party.quest).to.eql({
|
||||||
key: null,
|
key: null,
|
||||||
progress: {
|
progress: {
|
||||||
up: 0,
|
up: 0,
|
||||||
@@ -120,6 +107,29 @@ describe('POST /groups/:groupId/quests/leave', () => {
|
|||||||
RSVPNeeded: false,
|
RSVPNeeded: false,
|
||||||
});
|
});
|
||||||
expect(questingGroup.quest).to.deep.equal(leaveResult);
|
expect(questingGroup.quest).to.deep.equal(leaveResult);
|
||||||
expect(questingGroup.quest.members[partyMembers[0]._id]).to.be.false;
|
expect(questingGroup.quest.members[partyMember._id]).to.be.false;
|
||||||
|
}
|
||||||
|
|
||||||
|
it('leaves an active quest', async () => {
|
||||||
|
await leader.post(`/groups/${questingGroup._id}/quests/invite/${PET_QUEST}`);
|
||||||
|
await partyMembers[0].post(`/groups/${questingGroup._id}/quests/accept`);
|
||||||
|
await partyMembers[1].post(`/groups/${questingGroup._id}/quests/accept`);
|
||||||
|
|
||||||
|
await questingGroup.sync();
|
||||||
|
|
||||||
|
expect(questingGroup.quest.active).to.eql(true);
|
||||||
|
|
||||||
|
await letPartyMemberLeaveAndCheckChanges(partyMembers[0]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('leaves an inactive quest ', async () => {
|
||||||
|
await leader.post(`/groups/${questingGroup._id}/quests/invite/${PET_QUEST}`);
|
||||||
|
await partyMembers[0].post(`/groups/${questingGroup._id}/quests/accept`);
|
||||||
|
|
||||||
|
await questingGroup.sync();
|
||||||
|
|
||||||
|
expect(questingGroup.quest.active).to.eql(false);
|
||||||
|
|
||||||
|
await letPartyMemberLeaveAndCheckChanges(partyMembers[0]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -31,19 +31,45 @@ import '../../src/assets/css/sprites/spritesmith-main-23.css';
|
|||||||
import '../../src/assets/css/sprites/spritesmith-main-24.css';
|
import '../../src/assets/css/sprites/spritesmith-main-24.css';
|
||||||
import '../../src/assets/css/sprites/spritesmith-main-25.css';
|
import '../../src/assets/css/sprites/spritesmith-main-25.css';
|
||||||
import '../../src/assets/css/sprites/spritesmith-main-26.css';
|
import '../../src/assets/css/sprites/spritesmith-main-26.css';
|
||||||
|
import '../../src/assets/css/sprites/spritesmith-main-27.css';
|
||||||
|
import '../../src/assets/css/sprites/spritesmith-main-28.css';
|
||||||
|
import '../../src/assets/css/sprites/spritesmith-main-29.css';
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import BootstrapVue from 'bootstrap-vue';
|
import BootstrapVue from 'bootstrap-vue';
|
||||||
import StoreModule from '@/libs/store';
|
import StoreModule from '@/libs/store';
|
||||||
|
import getStore from '@/store';
|
||||||
|
|
||||||
|
import i18n from '../../../common/script/i18n';
|
||||||
|
|
||||||
// couldn't inject the languages easily,
|
// couldn't inject the languages easily,
|
||||||
// so just a "$t()" string to show that this will be translated
|
// so just a "$t()" string to show that this will be translated
|
||||||
Vue.prototype.$t = function translateString (...args) {
|
i18n.t = function translateString (...args) {
|
||||||
return `$t(${JSON.stringify(args)})`;
|
return `$t(${JSON.stringify(args)})`;
|
||||||
};
|
};
|
||||||
|
Vue.prototype.$t = i18n.t;
|
||||||
|
|
||||||
Vue.use(BootstrapVue);
|
Vue.use(BootstrapVue);
|
||||||
Vue.use(StoreModule);
|
Vue.use(StoreModule);
|
||||||
|
|
||||||
|
const store = getStore();
|
||||||
|
store.state.user.data = {
|
||||||
|
stats: {},
|
||||||
|
tags: [],
|
||||||
|
items: {
|
||||||
|
quests: {
|
||||||
|
moon1: 3,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
party: {
|
||||||
|
quest: {
|
||||||
|
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
Vue.prototype.$store = store;
|
||||||
|
|
||||||
|
|
||||||
const req = require.context('../../src', true, /.stories.js$/);
|
const req = require.context('../../src', true, /.stories.js$/);
|
||||||
|
|
||||||
function loadStories () {
|
function loadStories () {
|
||||||
|
|||||||
@@ -3,11 +3,12 @@
|
|||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.content {
|
|
||||||
color: white;
|
|
||||||
background: grey;
|
|
||||||
}
|
|
||||||
|
|
||||||
.inline-block {
|
.inline-block {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.component-showcase {
|
||||||
|
position: absolute;
|
||||||
|
margin: 20px;
|
||||||
|
width: calc(100% - 40px);
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { v4 as generateUUID } from 'uuid';
|
||||||
|
|
||||||
export const userStyles = {
|
export const userStyles = {
|
||||||
contributor: {
|
contributor: {
|
||||||
admin: true,
|
admin: true,
|
||||||
@@ -72,4 +74,11 @@ export const userStyles = {
|
|||||||
maxHealth: 50,
|
maxHealth: 50,
|
||||||
maxMP: 158,
|
maxMP: 158,
|
||||||
},
|
},
|
||||||
|
profile: {
|
||||||
|
name: 'user',
|
||||||
|
},
|
||||||
|
_id: generateUUID(),
|
||||||
|
flags: {
|
||||||
|
classSelected: true,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -39,6 +39,7 @@
|
|||||||
// shared dropdown-item styles
|
// shared dropdown-item styles
|
||||||
.dropdown-item {
|
.dropdown-item {
|
||||||
// header items & not selectList-items
|
// header items & not selectList-items
|
||||||
|
|
||||||
padding-left: 24px;
|
padding-left: 24px;
|
||||||
padding-top: 8px;
|
padding-top: 8px;
|
||||||
padding-bottom: 8px;
|
padding-bottom: 8px;
|
||||||
@@ -53,14 +54,13 @@
|
|||||||
background-color: inherit;
|
background-color: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
&:active, &:hover, &:focus, &.active {
|
&:active, &:hover, &:focus, &.active {
|
||||||
background-color: inherit !important;
|
background-color: inherit !important;
|
||||||
color: $purple-300 !important;
|
color: var(--hover-color, $purple-300) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: rgba($purple-600, 0.25) !important;
|
background-color: var(--hover-background, rgba($purple-600, 0.25)) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.dropdown-inactive {
|
&.dropdown-inactive {
|
||||||
@@ -71,6 +71,21 @@
|
|||||||
color: inherit !important;
|
color: inherit !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.with-icon {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.svg-icon {
|
||||||
|
margin: 0 0.5rem 0 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:not(:hover) {
|
||||||
|
.with-icon .svg-icon {
|
||||||
|
color: $gray-200;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.dropdown + .dropdown {
|
.dropdown + .dropdown {
|
||||||
|
|||||||
@@ -16,6 +16,12 @@
|
|||||||
fill: currentColor;
|
fill: currentColor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.color-stroke {
|
||||||
|
svg path {
|
||||||
|
stroke: currentColor;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-16 {
|
.icon-16 {
|
||||||
@@ -33,6 +39,11 @@
|
|||||||
height: 24px;
|
height: 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.icon-48 {
|
||||||
|
width: 48px;
|
||||||
|
height: 48px;
|
||||||
|
}
|
||||||
|
|
||||||
.icon-10 {
|
.icon-10 {
|
||||||
width: 10px;
|
width: 10px;
|
||||||
height: 10px;
|
height: 10px;
|
||||||
|
|||||||
@@ -107,5 +107,5 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.questPopover {
|
.questPopover {
|
||||||
width: 200px;
|
min-width: 200px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,88 +41,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#start-quest-modal, #buy-quest-modal {
|
|
||||||
@media only screen and (max-width: 1200px) {
|
|
||||||
.modal-dialog {
|
|
||||||
max-width: 33%;
|
|
||||||
|
|
||||||
.left-panel {
|
|
||||||
left: initial;
|
|
||||||
width: 100%;
|
|
||||||
right: 100%;
|
|
||||||
|
|
||||||
.col-4 {
|
|
||||||
width: 100px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.side-panel, .right-sidebar {
|
|
||||||
left: calc(100% - 10px);
|
|
||||||
max-width: 100%;
|
|
||||||
right: initial;
|
|
||||||
|
|
||||||
.questRewards {
|
|
||||||
width: 90%;
|
|
||||||
|
|
||||||
.reward-item {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media only screen and (max-width: 1000px) {
|
|
||||||
.modal-dialog {
|
|
||||||
max-width: 80%;
|
|
||||||
width: 80% !important;
|
|
||||||
|
|
||||||
.modal-body {
|
|
||||||
flex-direction: column;
|
|
||||||
display: flex;
|
|
||||||
|
|
||||||
div:nth-child(1) { order: 3; }
|
|
||||||
div:nth-child(2) { order: 1; }
|
|
||||||
div:nth-child(3) { order: 4; }
|
|
||||||
div:nth-child(4) { order: 5; }
|
|
||||||
div:nth-child(5) { order: 2; }
|
|
||||||
|
|
||||||
.left-panel {
|
|
||||||
border-radius: 8px;
|
|
||||||
position: static;
|
|
||||||
right: initial;
|
|
||||||
margin: 20px 0;
|
|
||||||
height: auto;
|
|
||||||
width: 100%;
|
|
||||||
z-index: 0;
|
|
||||||
order: 3;
|
|
||||||
|
|
||||||
.col-4 {
|
|
||||||
max-width: 100px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.side-panel, .right-sidebar {
|
|
||||||
margin: 20px 0 0 0;
|
|
||||||
position: static;
|
|
||||||
box-shadow: none;
|
|
||||||
height: auto;
|
|
||||||
width: 100%;
|
|
||||||
z-index: 0;
|
|
||||||
order: 2;
|
|
||||||
left: 0;
|
|
||||||
|
|
||||||
.questRewards {
|
|
||||||
padding: 0 2em 2em 2em;
|
|
||||||
width: 100%;
|
|
||||||
z-index: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#subscription-cancel-modal, #subscription-canceled-modal {
|
#subscription-cancel-modal, #subscription-canceled-modal {
|
||||||
.modal-content {
|
.modal-content {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
|
|||||||
21
website/client/src/assets/svg/health_no_padding.svg
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||||
|
<g fill="none" fill-rule="evenodd">
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<path fill="#F74E52" d="M0 2L3.333 0 8 2.533 12.667 0 16 2 16 8 12.667 12.667 8 16 3.333 12.667 0 8z" transform="translate(-40 -2020) translate(0 1632) translate(40 388)"/>
|
||||||
|
<path fill="#FF6165" d="M4.267 11.733L1.333 7.6 1.333 2.733 3.333 1.533 8 4.067 12.667 1.533 14.667 2.733 14.667 7.6 11.733 11.733 8 14.333z" transform="translate(-40 -2020) translate(0 1632) translate(40 388)"/>
|
||||||
|
<path fill="#FFF" d="M8 9.667L11.733 11.733 8 14.333z" opacity=".5" transform="translate(-40 -2020) translate(0 1632) translate(40 388)"/>
|
||||||
|
<path fill="#B52428" d="M8 9.667L4.267 11.733 8 14.333z" opacity=".35" transform="translate(-40 -2020) translate(0 1632) translate(40 388)"/>
|
||||||
|
<path fill="#FFF" d="M4.267 11.733L1.333 7.6 8 9.667z" opacity=".25" transform="translate(-40 -2020) translate(0 1632) translate(40 388)"/>
|
||||||
|
<path fill="#B52428" d="M11.733 11.733L14.667 7.6 8 9.667z" opacity=".5" transform="translate(-40 -2020) translate(0 1632) translate(40 388)"/>
|
||||||
|
<path fill="#B52428" d="M8 9.667L12.667 1.533 14.667 2.733 14.667 7.6z" opacity=".35" transform="translate(-40 -2020) translate(0 1632) translate(40 388)"/>
|
||||||
|
<path fill="#B52428" d="M8 9.667L3.333 1.533 1.333 2.733 1.333 7.6z" opacity=".5" transform="translate(-40 -2020) translate(0 1632) translate(40 388)"/>
|
||||||
|
<path fill="#FFF" d="M8 9.667L3.333 1.533 8 4.067z" opacity=".5" transform="translate(-40 -2020) translate(0 1632) translate(40 388)"/>
|
||||||
|
<path fill="#FFF" d="M8 9.667L12.667 1.533 8 4.067z" opacity=".25" transform="translate(-40 -2020) translate(0 1632) translate(40 388)"/>
|
||||||
|
<path fill="#FFF" d="M5.733 10.267L3.333 6.933 3.333 3.867 3.4 3.867 8 6.333 12.6 3.867 12.667 3.867 12.667 6.933 10.267 10.267 8 11.933z" opacity=".5" transform="translate(-40 -2020) translate(0 1632) translate(40 388)"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.2 KiB |
3
website/client/src/assets/svg/leave.svg
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16" viewBox="0 0 16 16">
|
||||||
|
<path id="xnmy9c4dda" d="M11 6H6V3L0 8l6 5v-3h5V6zm5-4v12c0 1.104-.896 2-2 2H9v-2h5V2H9V0h5c1.104 0 2 .896 2 2z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 253 B |
1
website/client/src/assets/svg/level.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="17"><defs><path id="a" d="M10 13v1H6v-1h4zm0-2v1H6v-1h4zM8 2l5 6h-3v2H6V8H3l5-6z"/></defs><g transform="rotate(-90 8 8)" fill="none" fill-rule="evenodd"><mask id="b" fill="#fff"><use xlink:href="#a"/></mask><use fill="#BDA8FF" xlink:href="#a"/><g fill="#878190" mask="url(#b)"><path d="M0 0h16v16H0z"/></g></g></svg>
|
||||||
|
After Width: | Height: | Size: 419 B |
14
website/client/src/assets/svg/navigation_back.svg
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="9" height="14" viewBox="0 0 9 14">
|
||||||
|
<defs>
|
||||||
|
<path id="lvd11k063a" d="M3.75 13.36L5.487 15.125 12.25 8.25 5.487 1.375 3.75 3.14 8.776 8.25z"/>
|
||||||
|
</defs>
|
||||||
|
<g fill="none" fill-rule="evenodd">
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<g transform="translate(-640 -837) translate(496 56) rotate(90 -311.5 468.5)">
|
||||||
|
<use fill="#46a7d9" fill-rule="nonzero" transform="rotate(90 8 8.25)" xlink:href="#lvd11k063a"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 601 B |
@@ -1,18 +1,26 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="16" viewBox="0 0 14 16">
|
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="16" viewBox="0 0 14 16">
|
||||||
<g fill="none" fill-rule="nonzero">
|
<g fill="none" fill-rule="evenodd">
|
||||||
<path fill="#24CC8F" d="M0 6l6.667-6 6.666 6-6.666 10z"/>
|
<g fill-rule="nonzero">
|
||||||
<path fill="#24CC8F" d="M0 6l6.667-6 6.666 6-6.666 10z"/>
|
<g>
|
||||||
<path fill="#FFF" d="M11.6 6.2l-4.933-1V1.8z" opacity=".25"/>
|
<g>
|
||||||
<path fill="#FFF" d="M6.667 5.2l-4.934 1 4.934-4.4z" opacity=".5"/>
|
<g>
|
||||||
<path fill="#5AE4B2" d="M6.667 5.2v8.4L1.733 6.2z"/>
|
<path fill="#24CC8F" d="M0 6L5.833 0 11.667 6 5.833 16z" transform="translate(-524 -2070) translate(484 1632) translate(40 438) translate(.875)"/>
|
||||||
<path fill="#1B996B" d="M11.6 6.2l-4.933 7.4V5.2z" opacity=".35"/>
|
<path fill="#24CC8F" d="M0 6L5.833 0 11.667 6 5.833 16z" transform="translate(-524 -2070) translate(484 1632) translate(40 438) translate(.875)"/>
|
||||||
<path fill="#F47825" d="M13.333 6L6.667 0 0 6l1.333 2L0 10l6.667 6 6.666-6L12 8z"/>
|
<path fill="#FFF" d="M10.15 6.2L5.833 5.2 5.833 1.8z" opacity=".25" transform="translate(-524 -2070) translate(484 1632) translate(40 438) translate(.875)"/>
|
||||||
<path fill="#FFF" d="M11.6 6.2l-4.933-1V1.8z" opacity=".25"/>
|
<path fill="#FFF" d="M5.833 5.2L1.517 6.2 5.833 1.8z" opacity=".5" transform="translate(-524 -2070) translate(484 1632) translate(40 438) translate(.875)"/>
|
||||||
<path fill="#FFF" d="M6.667 5.2l-4.934 1 4.934-4.4z" opacity=".5"/>
|
<path fill="#5AE4B2" d="M5.833 5.2L5.833 13.6 1.517 6.2z" transform="translate(-524 -2070) translate(484 1632) translate(40 438) translate(.875)"/>
|
||||||
<path fill="#FFF" d="M6.667 5.2v8.4L5.37 11.653 1.733 6.2zM6.667 10.8V2.4l1.296 1.947L11.6 9.8z" opacity=".25"/>
|
<path fill="#1B996B" d="M10.15 6.2L5.833 13.6 5.833 5.2z" opacity=".35" transform="translate(-524 -2070) translate(484 1632) translate(40 438) translate(.875)"/>
|
||||||
<path fill="#B4591B" d="M11.6 6.2l-4.933 7.4V5.2zM1.733 9.8l4.934 1v3.4z" opacity=".35"/>
|
<path fill="#F47825" d="M11.667 6L5.833 0 0 6 1.167 8 0 10 5.833 16 11.667 10 10.5 8z" transform="translate(-524 -2070) translate(484 1632) translate(40 438) translate(.875)"/>
|
||||||
<path fill="#FFF" d="M6.667 10.8l4.933-1-4.933 4.4z" opacity=".5"/>
|
<path fill="#FFF" d="M10.15 6.2L5.833 5.2 5.833 1.8z" opacity=".25" transform="translate(-524 -2070) translate(484 1632) translate(40 438) translate(.875)"/>
|
||||||
<path fill="#FFF" d="M1.733 9.8l4.934-7.4v8.4z" opacity=".25"/>
|
<path fill="#FFF" d="M5.833 5.2L1.517 6.2 5.833 1.8z" opacity=".5" transform="translate(-524 -2070) translate(484 1632) translate(40 438) translate(.875)"/>
|
||||||
<path fill="#FFF" d="M3.5 9.533L4.54 8 3.5 6.467l3.167-2.8 3.166 2.8L8.793 8l1.04 1.533-3.166 2.8z" opacity=".5"/>
|
<path fill="#FFF" d="M5.833 5.2L5.833 13.6 4.699 11.653 1.517 6.2zM5.833 10.8L5.833 2.4 6.968 4.347 10.15 9.8z" opacity=".25" transform="translate(-524 -2070) translate(484 1632) translate(40 438) translate(.875)"/>
|
||||||
|
<path fill="#B4591B" d="M10.15 6.2L5.833 13.6 5.833 5.2zM1.517 9.8L5.833 10.8 5.833 14.2z" opacity=".35" transform="translate(-524 -2070) translate(484 1632) translate(40 438) translate(.875)"/>
|
||||||
|
<path fill="#FFF" d="M5.833 10.8L10.15 9.8 5.833 14.2z" opacity=".5" transform="translate(-524 -2070) translate(484 1632) translate(40 438) translate(.875)"/>
|
||||||
|
<path fill="#FFF" d="M1.517 9.8L5.833 2.4 5.833 10.8z" opacity=".25" transform="translate(-524 -2070) translate(484 1632) translate(40 438) translate(.875)"/>
|
||||||
|
<path fill="#FFF" d="M3.063 9.533L3.973 8 3.063 6.467 5.833 3.667 8.604 6.467 7.694 8 8.604 9.533 5.833 12.333z" opacity=".5" transform="translate(-524 -2070) translate(484 1632) translate(40 438) translate(.875)"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 2.9 KiB |
3
website/client/src/assets/svg/sparklesIcon.svg
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16" viewBox="0 0 16 16">
|
||||||
|
<path id="re6owe1t5a" d="M7 10l1.06 1.94L10 13l-1.94 1.06L7 16l-1.06-1.94L4 13l1.94-1.06L7 10zm5.5-6l1.237 2.263L16 7.5l-2.263 1.237L12.5 11l-1.237-2.263L9 7.5l2.263-1.237L12.5 4zM4 0l1.414 2.586L8 4 5.414 5.414 4 8 2.586 5.414 0 4l2.586-1.414L4 0z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 394 B |
20
website/client/src/assets/svg/users.svg
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16" viewBox="0 0 16 16">
|
||||||
|
<defs>
|
||||||
|
<path id="rt3mruthma" d="M11.2 13.2c0-1.231-.467-2.35-1.23-3.2h1.23c1.765 0 3.2 1.435 3.2 3.2h-3.2zm-9.6 0c0-1.765 1.435-3.2 3.2-3.2h1.6c1.765 0 3.2 1.435 3.2 3.2h-8zm4-9.6C6.926 3.6 8 4.674 8 6c0 1.326-1.074 2.4-2.4 2.4-1.326 0-2.4-1.074-2.4-2.4 0-1.326 1.074-2.4 2.4-2.4zm3.452.415C9.436 3.754 9.9 3.6 10.4 3.6c1.326 0 2.4 1.074 2.4 2.4 0 1.326-1.074 2.4-2.4 2.4-.5 0-.964-.154-1.348-.415.34-.587.548-1.26.548-1.985 0-.726-.209-1.398-.548-1.985zm4.154 4.829C13.942 8.118 14.4 7.112 14.4 6c0-2.206-1.794-4-4-4-.904 0-1.73.313-2.4.82C7.33 2.314 6.504 2 5.6 2c-2.206 0-4 1.794-4 4 0 1.112.458 2.118 1.194 2.844C1.146 9.604 0 11.266 0 13.2c0 .884.716 1.6 1.6 1.6h12.8c.884 0 1.6-.716 1.6-1.6 0-1.934-1.146-3.596-2.794-4.356z"/>
|
||||||
|
</defs>
|
||||||
|
<g fill="none" fill-rule="evenodd">
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<g transform="translate(-1228 -1456) translate(1216 1416) translate(12 40)">
|
||||||
|
<mask id="6szqyv7o1b" fill="#fff">
|
||||||
|
<use xlink:href="#rt3mruthma"/>
|
||||||
|
</mask>
|
||||||
|
<use fill="#878190" xlink:href="#rt3mruthma"/>
|
||||||
|
<g fill="#878190" mask="url(#6szqyv7o1b)">
|
||||||
|
<path d="M0 0H16V16H0z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.4 KiB |
@@ -18,11 +18,11 @@
|
|||||||
v-if="questData.completion && typeof questData.completion === 'function'"
|
v-if="questData.completion && typeof questData.completion === 'function'"
|
||||||
v-html="questData.completion()"
|
v-html="questData.completion()"
|
||||||
></p>
|
></p>
|
||||||
<div class="quest-rewards text-center">
|
<div class="text-center">
|
||||||
<h3 v-once>
|
<h3 v-once>
|
||||||
{{ $t('paymentYouReceived') }}
|
{{ $t('paymentYouReceived') }}
|
||||||
</h3>
|
</h3>
|
||||||
<questDialogDrops :item="questData" />
|
<quest-rewards :quest="questData" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
@@ -36,27 +36,32 @@
|
|||||||
</b-modal>
|
</b-modal>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped lang="scss">
|
||||||
.quest {
|
.quest {
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
}
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
.quest-rewards .questRewards {
|
<style lang="scss">
|
||||||
margin: 0 auto;
|
#quest-completed {
|
||||||
|
.quest-rewards {
|
||||||
|
margin-left: -2rem;
|
||||||
|
margin-right: -2rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import * as quests from '@/../../common/script/content/quests';
|
import * as quests from '@/../../common/script/content/quests';
|
||||||
import questDialogDrops from '@/components/shops/quests/questDialogDrops';
|
|
||||||
|
|
||||||
import { mapState } from '@/libs/store';
|
import { mapState } from '@/libs/store';
|
||||||
import percent from '@/../../common/script/libs/percent';
|
import percent from '@/../../common/script/libs/percent';
|
||||||
import { MAX_HEALTH as maxHealth } from '@/../../common/script/constants';
|
import { MAX_HEALTH as maxHealth } from '@/../../common/script/constants';
|
||||||
|
import QuestRewards from '../shops/quests/questRewards';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
questDialogDrops,
|
QuestRewards,
|
||||||
},
|
},
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -6,11 +6,11 @@
|
|||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
v-if="challenges.length === 0"
|
v-if="challenges.length === 0"
|
||||||
class="row no-quest-section"
|
class="row no-challenge-section"
|
||||||
>
|
>
|
||||||
<div class="col-12 text-center">
|
<div class="col-12 text-center">
|
||||||
<div
|
<div
|
||||||
class="svg-icon challenge-icon"
|
class="svg-icon challenge-icon color"
|
||||||
v-html="icons.challengeIcon"
|
v-html="icons.challengeIcon"
|
||||||
></div>
|
></div>
|
||||||
<h4 v-once>
|
<h4 v-once>
|
||||||
@@ -51,23 +51,27 @@
|
|||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@import '~@/assets/scss/colors.scss';
|
@import '~@/assets/scss/colors.scss';
|
||||||
|
|
||||||
.no-quest-section {
|
.no-challenge-section {
|
||||||
padding: 2em;
|
padding: 2em;
|
||||||
color: $gray-300;
|
|
||||||
|
|
||||||
h4 {
|
h4 {
|
||||||
color: $gray-300;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
p {
|
p {
|
||||||
margin-bottom: 2em;
|
margin-bottom: 1em;
|
||||||
|
color: $gray-100;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
line-height: 1.33;
|
||||||
}
|
}
|
||||||
|
|
||||||
.svg-icon {
|
.challenge-icon {
|
||||||
height: 30px;
|
width: 1.125rem;
|
||||||
width: 30px;
|
height: 1.25rem;
|
||||||
margin: 0 auto;
|
margin: 0 auto 0.5em;
|
||||||
margin-bottom: 2em;
|
object-fit: contain;
|
||||||
|
border-radius: 2px;
|
||||||
|
color: $gray-200;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -47,7 +47,7 @@
|
|||||||
class="btn btn-success btn-success"
|
class="btn btn-success btn-success"
|
||||||
@click="upgradeGroup()"
|
@click="upgradeGroup()"
|
||||||
>
|
>
|
||||||
{{ $t('upgrade') }}
|
{{ $t('upgradeToGroup') }}
|
||||||
</button>
|
</button>
|
||||||
<div
|
<div
|
||||||
v-if="!group.purchased.plan.dateTerminated
|
v-if="!group.purchased.plan.dateTerminated
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ b-dropdown(:text="$t('sort')", right=true)
|
|||||||
import MugenScroll from 'vue-mugen-scroll';
|
import MugenScroll from 'vue-mugen-scroll';
|
||||||
import debounce from 'lodash/debounce';
|
import debounce from 'lodash/debounce';
|
||||||
import PublicGuildItem from './publicGuildItem';
|
import PublicGuildItem from './publicGuildItem';
|
||||||
import Sidebar from './sidebar';
|
import Sidebar from './groupSidebar';
|
||||||
import groupUtilities from '@/mixins/groupsUtilities';
|
import groupUtilities from '@/mixins/groupsUtilities';
|
||||||
|
|
||||||
import positiveIcon from '@/assets/svg/positive.svg';
|
import positiveIcon from '@/assets/svg/positive.svg';
|
||||||
|
|||||||
362
website/client/src/components/groups/group.stories.js
Normal file
@@ -0,0 +1,362 @@
|
|||||||
|
/* eslint-disable import/no-extraneous-dependencies */
|
||||||
|
import { storiesOf } from '@storybook/vue';
|
||||||
|
import {
|
||||||
|
collectionQuestLeaderParticipating,
|
||||||
|
collectionQuestNotParticipating,
|
||||||
|
createStory,
|
||||||
|
groupBossQuestParticipating,
|
||||||
|
groupBossQuestRage,
|
||||||
|
groupCollectionQuest,
|
||||||
|
groupCollectionQuestPending,
|
||||||
|
} from './group.stories.utils';
|
||||||
|
|
||||||
|
storiesOf('Group Components|Party/Quest States', module)
|
||||||
|
.add('Not a Member', () => createStory({
|
||||||
|
template: `
|
||||||
|
<div class="component-showcase">
|
||||||
|
<right-sidebar :group="group" :is-party="true"
|
||||||
|
:is-leader="false" :is-member="false"
|
||||||
|
class="col-12"/>
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
group: {
|
||||||
|
leader: {
|
||||||
|
|
||||||
|
},
|
||||||
|
quest: {
|
||||||
|
},
|
||||||
|
purchased: {
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
user: {
|
||||||
|
data: {
|
||||||
|
_id: 'some-user',
|
||||||
|
party: {
|
||||||
|
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
challengeOptions: {},
|
||||||
|
}))
|
||||||
|
.add('Member/No Quest', () => createStory({
|
||||||
|
template: `
|
||||||
|
<div class="component-showcase">
|
||||||
|
<right-sidebar :group="group" :is-party="true"
|
||||||
|
:is-leader="false" :is-member="true"
|
||||||
|
class="col-12"/>
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
group: {
|
||||||
|
leader: {
|
||||||
|
|
||||||
|
},
|
||||||
|
quest: {
|
||||||
|
},
|
||||||
|
purchased: {
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
user: {
|
||||||
|
data: {
|
||||||
|
_id: 'some-user',
|
||||||
|
party: {
|
||||||
|
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
challengeOptions: {},
|
||||||
|
}))
|
||||||
|
.add('Leader/No Quest', () => createStory({
|
||||||
|
template: `
|
||||||
|
<div class="component-showcase">
|
||||||
|
<right-sidebar :group="group" :is-party="true"
|
||||||
|
:is-leader="true" :is-member="true"
|
||||||
|
class="col-12"/>
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
group: {
|
||||||
|
description: 'Some text',
|
||||||
|
leader: {
|
||||||
|
|
||||||
|
},
|
||||||
|
quest: {
|
||||||
|
},
|
||||||
|
purchased: {
|
||||||
|
},
|
||||||
|
privacy: 'private',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
user: {
|
||||||
|
data: {
|
||||||
|
_id: 'some-user',
|
||||||
|
party: {
|
||||||
|
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
challengeOptions: {},
|
||||||
|
}))
|
||||||
|
.add('Quest Owner/Quest Not Started', () => createStory({
|
||||||
|
template: `
|
||||||
|
<div class="component-showcase">
|
||||||
|
<right-sidebar :group="group" :is-party="true" :is-member="true" class="col-12"/>
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
group: groupCollectionQuest(false),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
user: {
|
||||||
|
data: {
|
||||||
|
_id: '05ca98f4-4706-47b5-8d02-142e6e78ba2e',
|
||||||
|
party: {
|
||||||
|
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
challengeOptions: {},
|
||||||
|
}))
|
||||||
|
.add('Member/Quest accepted/Quest Not Started', () => createStory({
|
||||||
|
template: `
|
||||||
|
<div class="component-showcase">
|
||||||
|
<right-sidebar :group="group" :is-party="true" :is-member="true" class="col-12"/>
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
group: groupCollectionQuest(false),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
user: {
|
||||||
|
data: {
|
||||||
|
_id: 'just-a-member',
|
||||||
|
party: {
|
||||||
|
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
challengeOptions: {},
|
||||||
|
}))
|
||||||
|
.add('Member/Quest accepted/Started', () => createStory({
|
||||||
|
template: `
|
||||||
|
<div class="component-showcase">
|
||||||
|
<right-sidebar :group="group" :is-party="true" :is-member="true" class="col-12"/>
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
group: groupCollectionQuest(true),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
user: {
|
||||||
|
data: {
|
||||||
|
_id: 'just-a-member',
|
||||||
|
party: {
|
||||||
|
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
challengeOptions: {},
|
||||||
|
}))
|
||||||
|
.add('Member/Quest Invite Pending', () => createStory({
|
||||||
|
template: `
|
||||||
|
<div class="component-showcase">
|
||||||
|
<right-sidebar :group="group" :is-party="true"
|
||||||
|
:is-member="true"
|
||||||
|
class="col-12"/>
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
group: groupCollectionQuestPending,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
user: {
|
||||||
|
data: {
|
||||||
|
_id: 'some-user',
|
||||||
|
party: {
|
||||||
|
quest: {
|
||||||
|
RSVPNeeded: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
challengeOptions: {},
|
||||||
|
}))
|
||||||
|
.add('Collection Quest/Quest Owner Participating', () => createStory({
|
||||||
|
template: `
|
||||||
|
<div class="component-showcase">
|
||||||
|
<right-sidebar :group="group" :is-party="true" :is-member="true" :is-leader="true" class="col-12"/>
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
group: collectionQuestLeaderParticipating,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
user: {
|
||||||
|
data: {
|
||||||
|
_id: '05ca98f4-4706-47b5-8d02-142e6e78ba2e',
|
||||||
|
party: {
|
||||||
|
quest: {
|
||||||
|
progress: {
|
||||||
|
up: 0,
|
||||||
|
down: 0,
|
||||||
|
collectedItems: 2,
|
||||||
|
collect: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
challengeOptions: {},
|
||||||
|
}))
|
||||||
|
.add('Collection Quest/Not Participating', () => createStory({
|
||||||
|
template: `
|
||||||
|
<div class="component-showcase">
|
||||||
|
<right-sidebar :group="group" :is-party="true" :is-member="true" class="col-12"/>
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
group: collectionQuestNotParticipating,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
user: {
|
||||||
|
data: {
|
||||||
|
_id: 'not-the-leader',
|
||||||
|
party: {
|
||||||
|
quest: {
|
||||||
|
progress: {
|
||||||
|
up: 0,
|
||||||
|
down: 0,
|
||||||
|
collectedItems: 2,
|
||||||
|
collect: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
challengeOptions: {},
|
||||||
|
}))
|
||||||
|
.add('Boss Quest/Participating', () => createStory({
|
||||||
|
template: `
|
||||||
|
<div class="component-showcase">
|
||||||
|
<right-sidebar :group="group" :is-party="true" :is-member="true" class="col-12"/>
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
group: groupBossQuestParticipating,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
user: {
|
||||||
|
data: {
|
||||||
|
_id: 'acc2950e-9919-49bc-be7f-0ec4103e9f2b',
|
||||||
|
party: {
|
||||||
|
quest: {
|
||||||
|
progress: {
|
||||||
|
up: 20,
|
||||||
|
down: 0,
|
||||||
|
collectedItems: 2,
|
||||||
|
collect: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
challengeOptions: {},
|
||||||
|
}))
|
||||||
|
.add('Boss Quest/Participating - No Pending', () => createStory({
|
||||||
|
template: `
|
||||||
|
<div class="component-showcase">
|
||||||
|
<right-sidebar :group="group" :is-party="true" :is-member="true" class="col-12"/>
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
group: groupBossQuestParticipating,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
user: {
|
||||||
|
data: {
|
||||||
|
_id: 'acc2950e-9919-49bc-be7f-0ec4103e9f2b',
|
||||||
|
party: {
|
||||||
|
quest: {
|
||||||
|
progress: {
|
||||||
|
up: 0,
|
||||||
|
down: 0,
|
||||||
|
collectedItems: 2,
|
||||||
|
collect: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
challengeOptions: {},
|
||||||
|
}))
|
||||||
|
.add('Boss Quest/Rage Enabled', () => createStory({
|
||||||
|
template: `
|
||||||
|
<div class="component-showcase">
|
||||||
|
<right-sidebar :group="group" :is-party="true" :is-member="true" class="col-12"/>
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
group: groupBossQuestRage,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
user: {
|
||||||
|
data: {
|
||||||
|
_id: 'acc2950e-9919-49bc-be7f-0ec4103e9f2b',
|
||||||
|
party: {
|
||||||
|
quest: {
|
||||||
|
progress: {
|
||||||
|
up: 20,
|
||||||
|
down: 0,
|
||||||
|
collectedItems: 2,
|
||||||
|
collect: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
challengeOptions: {},
|
||||||
|
}))
|
||||||
|
.add('Not a party', () => createStory({
|
||||||
|
template: `
|
||||||
|
<div class="component-showcase">
|
||||||
|
<right-sidebar :group="group" :is-party="false" :is-member="true" class="col-12"/>
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
group: {
|
||||||
|
quest: {},
|
||||||
|
leader: {
|
||||||
|
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
user: {
|
||||||
|
data: {
|
||||||
|
_id: 'some-user',
|
||||||
|
party: {
|
||||||
|
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
challengeOptions: {},
|
||||||
|
}));
|
||||||
342
website/client/src/components/groups/group.stories.utils.js
Normal file
@@ -0,0 +1,342 @@
|
|||||||
|
import rightSidebar from '@/components/groups/rightSidebar';
|
||||||
|
import getters from '@/store/getters';
|
||||||
|
import content from '../../../../common/script/content';
|
||||||
|
|
||||||
|
export function createStory ({
|
||||||
|
template,
|
||||||
|
data,
|
||||||
|
user = null,
|
||||||
|
challengeOptions = {},
|
||||||
|
}) {
|
||||||
|
return {
|
||||||
|
components: { rightSidebar },
|
||||||
|
template,
|
||||||
|
data,
|
||||||
|
store: {
|
||||||
|
getters,
|
||||||
|
dispatch (id) {
|
||||||
|
if (id === 'challenges:getGroupChallenges') {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
state: {
|
||||||
|
content,
|
||||||
|
user: {
|
||||||
|
data: {
|
||||||
|
party: {},
|
||||||
|
},
|
||||||
|
...user,
|
||||||
|
},
|
||||||
|
challengeOptions,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export const groupBossQuestParticipating = {
|
||||||
|
leaderOnly: { challenges: false, getGems: false },
|
||||||
|
quest: {
|
||||||
|
progress: { collect: {}, hp: 30 },
|
||||||
|
active: true,
|
||||||
|
members: { 'acc2950e-9919-49bc-be7f-0ec4103e9f2b': true },
|
||||||
|
extra: {},
|
||||||
|
key: 'moon2',
|
||||||
|
leader: 'acc2950e-9919-49bc-be7f-0ec4103e9f2b',
|
||||||
|
},
|
||||||
|
tasksOrder: {
|
||||||
|
habits: [], dailys: [], todos: [], rewards: [],
|
||||||
|
},
|
||||||
|
purchased: {
|
||||||
|
plan: {
|
||||||
|
consecutive: {
|
||||||
|
count: 0, offset: 0, gemCapExtra: 0, trinkets: 0,
|
||||||
|
},
|
||||||
|
quantity: 1,
|
||||||
|
extraMonths: 0,
|
||||||
|
gemsBought: 0,
|
||||||
|
mysteryItems: [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
privacy: 'private',
|
||||||
|
chat: [],
|
||||||
|
memberCount: 1,
|
||||||
|
challengeCount: 0,
|
||||||
|
balance: 0,
|
||||||
|
_id: '6b125aa8-ef98-4307-b5b4-181091b747c9',
|
||||||
|
type: 'party',
|
||||||
|
name: 'Testings Party',
|
||||||
|
managers: {},
|
||||||
|
categories: [],
|
||||||
|
leader: {
|
||||||
|
auth: { local: { username: 'test' } },
|
||||||
|
flags: { verifiedUsername: true },
|
||||||
|
profile: { name: 'Testing' },
|
||||||
|
_id: 'acc2950e-9919-49bc-be7f-0ec4103e9f2b',
|
||||||
|
id: 'acc2950e-9919-49bc-be7f-0ec4103e9f2b',
|
||||||
|
},
|
||||||
|
summary: 'Testings Party',
|
||||||
|
id: '6b125aa8-ef98-4307-b5b4-181091b747c9',
|
||||||
|
};
|
||||||
|
|
||||||
|
export const groupBossQuestRage = {
|
||||||
|
leaderOnly: { challenges: false, getGems: false },
|
||||||
|
quest: {
|
||||||
|
progress: { collect: {}, hp: 30, rage: 20.33434535 },
|
||||||
|
active: true,
|
||||||
|
members: { 'acc2950e-9919-49bc-be7f-0ec4103e9f2b': true },
|
||||||
|
extra: {},
|
||||||
|
key: 'dilatoryDistress2',
|
||||||
|
leader: 'acc2950e-9919-49bc-be7f-0ec4103e9f2b',
|
||||||
|
},
|
||||||
|
tasksOrder: {
|
||||||
|
habits: [], dailys: [], todos: [], rewards: [],
|
||||||
|
},
|
||||||
|
purchased: {
|
||||||
|
plan: {
|
||||||
|
consecutive: {
|
||||||
|
count: 0, offset: 0, gemCapExtra: 0, trinkets: 0,
|
||||||
|
},
|
||||||
|
quantity: 1,
|
||||||
|
extraMonths: 0,
|
||||||
|
gemsBought: 0,
|
||||||
|
mysteryItems: [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
privacy: 'private',
|
||||||
|
chat: [],
|
||||||
|
memberCount: 1,
|
||||||
|
challengeCount: 0,
|
||||||
|
balance: 0,
|
||||||
|
_id: '6b125aa8-ef98-4307-b5b4-181091b747c9',
|
||||||
|
type: 'party',
|
||||||
|
name: 'Testings Party',
|
||||||
|
managers: {},
|
||||||
|
categories: [],
|
||||||
|
leader: {
|
||||||
|
auth: { local: { username: 'test' } },
|
||||||
|
flags: { verifiedUsername: true },
|
||||||
|
profile: { name: 'Testing' },
|
||||||
|
_id: 'acc2950e-9919-49bc-be7f-0ec4103e9f2b',
|
||||||
|
id: 'acc2950e-9919-49bc-be7f-0ec4103e9f2b',
|
||||||
|
},
|
||||||
|
summary: 'Testings Party',
|
||||||
|
id: '6b125aa8-ef98-4307-b5b4-181091b747c9',
|
||||||
|
};
|
||||||
|
|
||||||
|
export function groupCollectionQuest (active) {
|
||||||
|
return {
|
||||||
|
leaderOnly: { challenges: false, getGems: false },
|
||||||
|
quest: {
|
||||||
|
progress: { collect: {} },
|
||||||
|
active,
|
||||||
|
members: {
|
||||||
|
'05ca98f4-4706-47b5-8d02-142e6e78ba2e': true,
|
||||||
|
'just-a-member': true,
|
||||||
|
'b3b0be03-3f62-49ae-b776-b16419ef32cf': null,
|
||||||
|
},
|
||||||
|
extra: {},
|
||||||
|
key: 'atom1',
|
||||||
|
leader: '05ca98f4-4706-47b5-8d02-142e6e78ba2e',
|
||||||
|
},
|
||||||
|
tasksOrder: {
|
||||||
|
habits: ['320496be-d663-4711-a7da-03205a2204b2'],
|
||||||
|
dailys: ['0c6a3ecd-dbaf-4a34-bb61-1a2ecd3daa0e', '686e7766-9cef-4b77-8c8f-f4d6c5b63a85'],
|
||||||
|
todos: ['76b3ef3e-1b01-4f24-a37e-0320f31d8132'],
|
||||||
|
rewards: ['76dad8ea-0d95-47c3-ad9a-8e136ad80b7f'],
|
||||||
|
},
|
||||||
|
purchased: {
|
||||||
|
active: true,
|
||||||
|
plan: {
|
||||||
|
consecutive: {
|
||||||
|
count: 0, offset: 0, gemCapExtra: 0, trinkets: 0,
|
||||||
|
},
|
||||||
|
quantity: 3,
|
||||||
|
extraMonths: 0,
|
||||||
|
gemsBought: 0,
|
||||||
|
mysteryItems: [],
|
||||||
|
customerId: 'group-unlimited',
|
||||||
|
dateCreated: null,
|
||||||
|
dateTerminated: null,
|
||||||
|
dateUpdated: null,
|
||||||
|
owner: '05ca98f4-4706-47b5-8d02-142e6e78ba2e',
|
||||||
|
paymentMethod: 'Group Unlimited',
|
||||||
|
planId: 'group_monthly',
|
||||||
|
subscriptionId: '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
privacy: 'private',
|
||||||
|
chat: [],
|
||||||
|
memberCount: 3,
|
||||||
|
challengeCount: 0,
|
||||||
|
balance: 0,
|
||||||
|
_id: '96ea599a-737b-47e2-ac17-8bd85b6ab62a',
|
||||||
|
type: 'party',
|
||||||
|
name: 'Party',
|
||||||
|
managers: {},
|
||||||
|
categories: [],
|
||||||
|
leader: {
|
||||||
|
auth: { local: { username: 'test2' } },
|
||||||
|
flags: { verifiedUsername: true },
|
||||||
|
profile: { name: 'MyDisplay2' },
|
||||||
|
_id: '05ca98f4-4706-47b5-8d02-142e6e78ba2e',
|
||||||
|
id: '05ca98f4-4706-47b5-8d02-142e6e78ba2e',
|
||||||
|
},
|
||||||
|
summary: 'Party',
|
||||||
|
id: '96ea599a-737b-47e2-ac17-8bd85b6ab62a',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export const groupCollectionQuestPending = {
|
||||||
|
leaderOnly: { challenges: false, getGems: false },
|
||||||
|
quest: {
|
||||||
|
progress: { collect: {} },
|
||||||
|
active: false,
|
||||||
|
members: { '05ca98f4-4706-47b5-8d02-142e6e78ba2e': true, 'b3b0be03-3f62-49ae-b776-b16419ef32cf': null },
|
||||||
|
extra: {},
|
||||||
|
key: 'atom1',
|
||||||
|
leader: '05ca98f4-4706-47b5-8d02-142e6e78ba2e',
|
||||||
|
},
|
||||||
|
tasksOrder: {
|
||||||
|
habits: ['320496be-d663-4711-a7da-03205a2204b2'],
|
||||||
|
dailys: ['0c6a3ecd-dbaf-4a34-bb61-1a2ecd3daa0e', '686e7766-9cef-4b77-8c8f-f4d6c5b63a85'],
|
||||||
|
todos: ['76b3ef3e-1b01-4f24-a37e-0320f31d8132'],
|
||||||
|
rewards: ['76dad8ea-0d95-47c3-ad9a-8e136ad80b7f'],
|
||||||
|
},
|
||||||
|
purchased: { active: true },
|
||||||
|
privacy: 'private',
|
||||||
|
chat: [],
|
||||||
|
memberCount: 2,
|
||||||
|
challengeCount: 0,
|
||||||
|
balance: 0,
|
||||||
|
_id: '96ea599a-737b-47e2-ac17-8bd85b6ab62a',
|
||||||
|
type: 'party',
|
||||||
|
name: "MyDisplay2's Party",
|
||||||
|
managers: {},
|
||||||
|
categories: [],
|
||||||
|
leader: {
|
||||||
|
auth: { local: { username: 'test2' } },
|
||||||
|
flags: { verifiedUsername: true },
|
||||||
|
profile: { name: 'MyDisplay2' },
|
||||||
|
_id: '05ca98f4-4706-47b5-8d02-142e6e78ba2e',
|
||||||
|
id: '05ca98f4-4706-47b5-8d02-142e6e78ba2e',
|
||||||
|
},
|
||||||
|
summary: "MyDisplay2's Party",
|
||||||
|
id: '96ea599a-737b-47e2-ac17-8bd85b6ab62a',
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export const collectionQuestLeaderParticipating = {
|
||||||
|
leaderOnly: { challenges: false, getGems: false },
|
||||||
|
quest: {
|
||||||
|
progress: { collect: { fireCoral: 4, blueFins: 0 } },
|
||||||
|
active: true,
|
||||||
|
members: { '05ca98f4-4706-47b5-8d02-142e6e78ba2e': true },
|
||||||
|
extra: {},
|
||||||
|
key: 'dilatoryDistress1',
|
||||||
|
leader: '05ca98f4-4706-47b5-8d02-142e6e78ba2e',
|
||||||
|
},
|
||||||
|
tasksOrder: {
|
||||||
|
habits: ['320496be-d663-4711-a7da-03205a2204b2'],
|
||||||
|
dailys: ['0c6a3ecd-dbaf-4a34-bb61-1a2ecd3daa0e', '686e7766-9cef-4b77-8c8f-f4d6c5b63a85'],
|
||||||
|
todos: ['76b3ef3e-1b01-4f24-a37e-0320f31d8132'],
|
||||||
|
rewards: ['76dad8ea-0d95-47c3-ad9a-8e136ad80b7f'],
|
||||||
|
},
|
||||||
|
purchased: {
|
||||||
|
active: true,
|
||||||
|
plan: {
|
||||||
|
consecutive: {
|
||||||
|
count: 0, offset: 0, gemCapExtra: 0, trinkets: 0,
|
||||||
|
},
|
||||||
|
quantity: 3,
|
||||||
|
extraMonths: 0,
|
||||||
|
gemsBought: 0,
|
||||||
|
mysteryItems: [],
|
||||||
|
customerId: 'group-unlimited',
|
||||||
|
dateCreated: null,
|
||||||
|
dateTerminated: null,
|
||||||
|
dateUpdated: null,
|
||||||
|
owner: '05ca98f4-4706-47b5-8d02-142e6e78ba2e',
|
||||||
|
paymentMethod: 'Group Unlimited',
|
||||||
|
planId: 'group_monthly',
|
||||||
|
subscriptionId: '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
privacy: 'private',
|
||||||
|
chat: [],
|
||||||
|
memberCount: 2,
|
||||||
|
challengeCount: 0,
|
||||||
|
balance: 0,
|
||||||
|
_id: '96ea599a-737b-47e2-ac17-8bd85b6ab62a',
|
||||||
|
type: 'party',
|
||||||
|
name: "MyDisplay2's Party",
|
||||||
|
managers: {},
|
||||||
|
categories: [],
|
||||||
|
leader: {
|
||||||
|
auth: { local: { username: 'test2' } },
|
||||||
|
flags: { verifiedUsername: true },
|
||||||
|
profile: { name: 'MyDisplay2' },
|
||||||
|
_id: '05ca98f4-4706-47b5-8d02-142e6e78ba2e',
|
||||||
|
id: '05ca98f4-4706-47b5-8d02-142e6e78ba2e',
|
||||||
|
},
|
||||||
|
summary: "MyDisplay2's Party",
|
||||||
|
id: '96ea599a-737b-47e2-ac17-8bd85b6ab62a',
|
||||||
|
};
|
||||||
|
|
||||||
|
export const collectionQuestNotParticipating = {
|
||||||
|
leaderOnly: { challenges: false, getGems: false },
|
||||||
|
quest: {
|
||||||
|
progress: { collect: { fireCoral: 4, blueFins: 3 } },
|
||||||
|
active: true,
|
||||||
|
members: { },
|
||||||
|
extra: {},
|
||||||
|
key: 'dilatoryDistress1',
|
||||||
|
leader: '05ca98f4-4706-47b5-8d02-142e6e78ba2e',
|
||||||
|
},
|
||||||
|
tasksOrder: {
|
||||||
|
habits: ['320496be-d663-4711-a7da-03205a2204b2'],
|
||||||
|
dailys: ['0c6a3ecd-dbaf-4a34-bb61-1a2ecd3daa0e', '686e7766-9cef-4b77-8c8f-f4d6c5b63a85'],
|
||||||
|
todos: ['76b3ef3e-1b01-4f24-a37e-0320f31d8132'],
|
||||||
|
rewards: ['76dad8ea-0d95-47c3-ad9a-8e136ad80b7f'],
|
||||||
|
},
|
||||||
|
purchased: {
|
||||||
|
active: true,
|
||||||
|
plan: {
|
||||||
|
consecutive: {
|
||||||
|
count: 0, offset: 0, gemCapExtra: 0, trinkets: 0,
|
||||||
|
},
|
||||||
|
quantity: 3,
|
||||||
|
extraMonths: 0,
|
||||||
|
gemsBought: 0,
|
||||||
|
mysteryItems: [],
|
||||||
|
customerId: 'group-unlimited',
|
||||||
|
dateCreated: null,
|
||||||
|
dateTerminated: null,
|
||||||
|
dateUpdated: null,
|
||||||
|
owner: '05ca98f4-4706-47b5-8d02-142e6e78ba2e',
|
||||||
|
paymentMethod: 'Group Unlimited',
|
||||||
|
planId: 'group_monthly',
|
||||||
|
subscriptionId: '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
privacy: 'private',
|
||||||
|
chat: [],
|
||||||
|
memberCount: 2,
|
||||||
|
challengeCount: 0,
|
||||||
|
balance: 0,
|
||||||
|
_id: '96ea599a-737b-47e2-ac17-8bd85b6ab62a',
|
||||||
|
type: 'party',
|
||||||
|
name: "MyDisplay2's Party",
|
||||||
|
managers: {},
|
||||||
|
categories: [],
|
||||||
|
leader: {
|
||||||
|
auth: { local: { username: 'test2' } },
|
||||||
|
flags: { verifiedUsername: true },
|
||||||
|
profile: { name: 'MyDisplay2' },
|
||||||
|
_id: '05ca98f4-4706-47b5-8d02-142e6e78ba2e',
|
||||||
|
id: '05ca98f4-4706-47b5-8d02-142e6e78ba2e',
|
||||||
|
},
|
||||||
|
summary: "MyDisplay2's Party",
|
||||||
|
id: '96ea599a-737b-47e2-ac17-8bd85b6ab62a',
|
||||||
|
};
|
||||||
@@ -4,9 +4,9 @@
|
|||||||
class="row"
|
class="row"
|
||||||
>
|
>
|
||||||
<group-form-modal v-if="isParty" />
|
<group-form-modal v-if="isParty" />
|
||||||
<start-quest-modal :group="group" />
|
<quest-detail-modal :group="group" />
|
||||||
<quest-details-modal :group="group" />
|
|
||||||
<participant-list-modal :group="group" />
|
<participant-list-modal :group="group" />
|
||||||
|
<invitation-list-modal :group="group" />
|
||||||
<group-gems-modal />
|
<group-gems-modal />
|
||||||
<div class="col-12 col-sm-8 standard-page">
|
<div class="col-12 col-sm-8 standard-page">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
@@ -96,99 +96,21 @@
|
|||||||
</template>
|
</template>
|
||||||
</chat>
|
</chat>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 col-sm-4 sidebar">
|
<right-sidebar
|
||||||
<div
|
:is-admin="isAdmin"
|
||||||
class="row"
|
:is-leader="isLeader"
|
||||||
:class="{'guild-background': !isParty}"
|
:is-member="isMember"
|
||||||
>
|
:is-party="isParty"
|
||||||
<div class="col-12 buttons-wrapper">
|
|
||||||
<div class="button-container">
|
|
||||||
<button
|
|
||||||
v-if="isLeader && !group.purchased.active && group.privacy === 'private'"
|
|
||||||
class="btn btn-success btn-success"
|
|
||||||
@click="upgradeGroup()"
|
|
||||||
>
|
|
||||||
{{ $t('upgrade') }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="button-container">
|
|
||||||
<button
|
|
||||||
v-if="isLeader || isAdmin"
|
|
||||||
v-once
|
|
||||||
class="btn btn-primary"
|
|
||||||
b-btn="b-btn"
|
|
||||||
@click="updateGuild"
|
|
||||||
>
|
|
||||||
{{ $t('edit') }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="button-container">
|
|
||||||
<button
|
|
||||||
v-if="!isMember"
|
|
||||||
class="btn btn-success btn-success"
|
|
||||||
@click="join()"
|
|
||||||
>
|
|
||||||
{{ $t('join') }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="button-container">
|
|
||||||
<button
|
|
||||||
v-once
|
|
||||||
class="btn btn-primary"
|
|
||||||
@click="showInviteModal()"
|
|
||||||
>
|
|
||||||
{{ $t('invite') }}
|
|
||||||
</button>
|
|
||||||
<!-- @TODO: hide the invitation button
|
|
||||||
if there's an active group plan and the player is not the leader-->
|
|
||||||
</div>
|
|
||||||
<div class="button-container">
|
|
||||||
<!-- @TODO: V2 button.btn.btn-primary(v-once, v-if='!isLeader')
|
|
||||||
{{$t('messageGuildLeader')}} // Suggest making the button
|
|
||||||
visible to the leader too - useful for them to test how
|
|
||||||
the feature works or to send a note to themself. -- Alys-->
|
|
||||||
</div>
|
|
||||||
<div class="button-container">
|
|
||||||
<!-- @TODO: V2 button.btn.btn-primary(v-once,
|
|
||||||
v-if='isMember && !isParty') {{$t('donateGems')}}
|
|
||||||
// Suggest removing the isMember restriction
|
|
||||||
- it's okay if non-members donate to a public
|
|
||||||
guild. Also probably allow it for parties
|
|
||||||
if parties can buy imagery. -- Alys-->
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="px-3 py-3">
|
|
||||||
<quest-sidebar-section
|
|
||||||
v-if="isParty"
|
|
||||||
:group="group"
|
:group="group"
|
||||||
|
:search-id="searchId"
|
||||||
|
class="col-12 col-sm-4"
|
||||||
|
@leave="clickLeave()"
|
||||||
|
@join="join()"
|
||||||
|
@messageLeader="messageLeader()"
|
||||||
|
@upgradeGroup="upgradeGroup"
|
||||||
|
@updateGuild="updateGuild"
|
||||||
|
@showInviteModal="showInviteModal()"
|
||||||
/>
|
/>
|
||||||
<sidebar-section
|
|
||||||
v-if="!isParty"
|
|
||||||
:title="$t('guildSummary')"
|
|
||||||
>
|
|
||||||
<p v-markdown="group.summary"></p>
|
|
||||||
</sidebar-section>
|
|
||||||
<sidebar-section :title="$t('groupDescription')">
|
|
||||||
<p v-markdown="group.description"></p>
|
|
||||||
</sidebar-section>
|
|
||||||
<sidebar-section
|
|
||||||
:title="$t('challenges')"
|
|
||||||
:tooltip="$t('challengeDetails')"
|
|
||||||
>
|
|
||||||
<group-challenges :group="group" />
|
|
||||||
</sidebar-section>
|
|
||||||
</div>
|
|
||||||
<div class="text-center">
|
|
||||||
<button
|
|
||||||
v-if="isMember"
|
|
||||||
class="btn btn-danger"
|
|
||||||
@click="clickLeave()"
|
|
||||||
>
|
|
||||||
{{ isParty ? $t('leaveParty') : $t('leaveGroup') }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -199,24 +121,12 @@
|
|||||||
.standard-page {
|
.standard-page {
|
||||||
max-width: calc(100% - 430px);
|
max-width: calc(100% - 430px);
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar {
|
|
||||||
max-width: 430px !important;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
h1 {
|
h1 {
|
||||||
color: $purple-200;
|
color: $purple-200;
|
||||||
}
|
}
|
||||||
|
|
||||||
.button-container {
|
|
||||||
margin-bottom: 1em;
|
|
||||||
|
|
||||||
button {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.item-with-icon {
|
.item-with-icon {
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
background-color: #ffffff;
|
background-color: #ffffff;
|
||||||
@@ -254,11 +164,6 @@
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar {
|
|
||||||
background-color: $gray-600;
|
|
||||||
padding-bottom: 2em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.buttons-wrapper {
|
.buttons-wrapper {
|
||||||
padding: 2.8em 24px 0em 24px;
|
padding: 2.8em 24px 0em 24px;
|
||||||
}
|
}
|
||||||
@@ -278,11 +183,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.guild-background {
|
|
||||||
background-image: url('~@/assets/images/groups/grassy-meadow-backdrop.png');
|
|
||||||
height: 246px;
|
|
||||||
}
|
|
||||||
|
|
||||||
textarea {
|
textarea {
|
||||||
height: 150px;
|
height: 150px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -390,16 +290,11 @@ import groupUtilities from '@/mixins/groupsUtilities';
|
|||||||
import styleHelper from '@/mixins/styleHelper';
|
import styleHelper from '@/mixins/styleHelper';
|
||||||
import { mapState, mapGetters } from '@/libs/store';
|
import { mapState, mapGetters } from '@/libs/store';
|
||||||
import * as Analytics from '@/libs/analytics';
|
import * as Analytics from '@/libs/analytics';
|
||||||
import startQuestModal from './startQuestModal';
|
|
||||||
import questDetailsModal from './questDetailsModal';
|
|
||||||
import participantListModal from './participantListModal';
|
import participantListModal from './participantListModal';
|
||||||
import groupFormModal from './groupFormModal';
|
import groupFormModal from './groupFormModal';
|
||||||
import groupChallenges from '../challenges/groupChallenges';
|
|
||||||
import groupGemsModal from '@/components/groups/groupGemsModal';
|
import groupGemsModal from '@/components/groups/groupGemsModal';
|
||||||
import questSidebarSection from '@/components/groups/questSidebarSection';
|
|
||||||
import markdownDirective from '@/directives/markdown';
|
import markdownDirective from '@/directives/markdown';
|
||||||
import chat from './chat';
|
import chat from './chat';
|
||||||
import sidebarSection from '../sidebarSection';
|
|
||||||
import userLink from '../userLink';
|
import userLink from '../userLink';
|
||||||
|
|
||||||
import deleteIcon from '@/assets/svg/delete.svg';
|
import deleteIcon from '@/assets/svg/delete.svg';
|
||||||
@@ -413,17 +308,18 @@ import questBackground from '@/assets/svg/quest-background-border.svg';
|
|||||||
import goldGuildBadgeIcon from '@/assets/svg/gold-guild-badge-small.svg';
|
import goldGuildBadgeIcon from '@/assets/svg/gold-guild-badge-small.svg';
|
||||||
import silverGuildBadgeIcon from '@/assets/svg/silver-guild-badge-small.svg';
|
import silverGuildBadgeIcon from '@/assets/svg/silver-guild-badge-small.svg';
|
||||||
import bronzeGuildBadgeIcon from '@/assets/svg/bronze-guild-badge-small.svg';
|
import bronzeGuildBadgeIcon from '@/assets/svg/bronze-guild-badge-small.svg';
|
||||||
|
import QuestDetailModal from './questDetailModal';
|
||||||
|
import RightSidebar from '@/components/groups/rightSidebar';
|
||||||
|
import InvitationListModal from './invitationListModal';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
startQuestModal,
|
InvitationListModal,
|
||||||
|
QuestDetailModal,
|
||||||
|
RightSidebar,
|
||||||
groupFormModal,
|
groupFormModal,
|
||||||
groupChallenges,
|
|
||||||
questDetailsModal,
|
|
||||||
participantListModal,
|
participantListModal,
|
||||||
groupGemsModal,
|
groupGemsModal,
|
||||||
questSidebarSection,
|
|
||||||
sidebarSection,
|
|
||||||
userLink,
|
userLink,
|
||||||
chat,
|
chat,
|
||||||
},
|
},
|
||||||
@@ -657,6 +553,9 @@ export default {
|
|||||||
showGroupGems () {
|
showGroupGems () {
|
||||||
this.$root.$emit('bv::show::modal', 'group-gems-modal');
|
this.$root.$emit('bv::show::modal', 'group-gems-modal');
|
||||||
},
|
},
|
||||||
|
messageLeader () {
|
||||||
|
window.open(`/private-messages?uuid=${this.group.leader.id}`);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
273
website/client/src/components/groups/invitationListModal.vue
Normal file
@@ -0,0 +1,273 @@
|
|||||||
|
<template>
|
||||||
|
<b-modal
|
||||||
|
id="invitation-list"
|
||||||
|
size="md"
|
||||||
|
:hide-header="true"
|
||||||
|
:hide-footer="true"
|
||||||
|
>
|
||||||
|
<div class="dialog-close">
|
||||||
|
<close-icon @click="close()" />
|
||||||
|
</div>
|
||||||
|
<h2 class="text-center textCondensed" v-once>
|
||||||
|
{{ $t('invitations') }}
|
||||||
|
</h2>
|
||||||
|
<div
|
||||||
|
v-for="member in members"
|
||||||
|
:key="member._id"
|
||||||
|
class="member-row"
|
||||||
|
>
|
||||||
|
<div class="class-icon">
|
||||||
|
<class-badge
|
||||||
|
v-if="member.stats"
|
||||||
|
:member-class="member.stats.class"
|
||||||
|
:badge-size="40"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="usernames">
|
||||||
|
<user-label :user="member" class="user-label" /> <br>
|
||||||
|
<span class="username">
|
||||||
|
@{{ member.auth.local.username }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div :class="{
|
||||||
|
'status': true,
|
||||||
|
'accepted': member.accepted === true,
|
||||||
|
'declined': member.accepted === false,
|
||||||
|
'pending': member.accepted === null
|
||||||
|
}">
|
||||||
|
<div
|
||||||
|
v-if="member.accepted === true"
|
||||||
|
class="accepted float-right"
|
||||||
|
>
|
||||||
|
{{ $t('accepted') }}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="member.accepted === false"
|
||||||
|
class="declined float-right"
|
||||||
|
>
|
||||||
|
{{ $t('declined') }}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="member.accepted === null"
|
||||||
|
class="pending float-right"
|
||||||
|
>
|
||||||
|
{{ $t('pending') }}
|
||||||
|
</div>
|
||||||
|
<div class="circle">
|
||||||
|
<div
|
||||||
|
v-if="member.accepted === true"
|
||||||
|
class="svg-icon color"
|
||||||
|
v-html="icons.check"
|
||||||
|
></div>
|
||||||
|
<div
|
||||||
|
v-if="member.accepted === false"
|
||||||
|
class="svg-icon color"
|
||||||
|
v-html="icons.close"
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</b-modal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang='scss'>
|
||||||
|
@import '~@/assets/scss/colors.scss';
|
||||||
|
|
||||||
|
#invitation-list {
|
||||||
|
.modal-header {
|
||||||
|
background-color: $gray-600;
|
||||||
|
border-radius: 8px 8px 0 0;
|
||||||
|
box-shadow: 0 1px 2px 0 rgba(26, 24, 29, 0.24);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-footer {
|
||||||
|
background-color: #edecee;
|
||||||
|
border-radius: 0 0 8px 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.small-text, .character-name {
|
||||||
|
color: #878190;
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-padding-left {
|
||||||
|
padding-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-body {
|
||||||
|
padding-left: 0;
|
||||||
|
padding-right: 0;
|
||||||
|
padding-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.member-details {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-content {
|
||||||
|
// so that the rounded corners still apply
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-label {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.username {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style lang='scss' scoped>
|
||||||
|
@import '~@/assets/scss/colors.scss';
|
||||||
|
|
||||||
|
.header-wrap {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
color: $purple-300;
|
||||||
|
margin-top: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.member-row {
|
||||||
|
padding: 0.75rem 1.5rem;
|
||||||
|
|
||||||
|
background-color: $gray-700;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
|
||||||
|
&:not(:last-of-type) {
|
||||||
|
border-bottom: 1px solid $gray-500;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.class-icon {
|
||||||
|
margin-right: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.usernames {
|
||||||
|
flex: 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.class-icon {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.circle {
|
||||||
|
height: 2rem;
|
||||||
|
width: 2rem;
|
||||||
|
|
||||||
|
margin-left: 0.5rem;
|
||||||
|
border: 2px solid $gray-300;
|
||||||
|
border-radius: 1rem;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.accepted {
|
||||||
|
color: $green-10;
|
||||||
|
|
||||||
|
.circle {
|
||||||
|
border-color: $green-50;
|
||||||
|
background: $green-50;
|
||||||
|
|
||||||
|
color: white;
|
||||||
|
|
||||||
|
.svg-icon {
|
||||||
|
height: 10px;
|
||||||
|
width: 13px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.pending {
|
||||||
|
color: $gray-100;
|
||||||
|
}
|
||||||
|
|
||||||
|
.declined {
|
||||||
|
color: $maroon-10;
|
||||||
|
|
||||||
|
.circle {
|
||||||
|
border-color: $maroon-100;
|
||||||
|
background: $maroon-100;
|
||||||
|
|
||||||
|
color: white;
|
||||||
|
|
||||||
|
.svg-icon {
|
||||||
|
height: 12px;
|
||||||
|
width: 12px;
|
||||||
|
|
||||||
|
::v-deep {
|
||||||
|
path {
|
||||||
|
stroke: white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#invitation-list_modal_body {
|
||||||
|
padding: 0;
|
||||||
|
max-height: 450px;
|
||||||
|
|
||||||
|
.member-details {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { mapGetters } from '@/libs/store';
|
||||||
|
|
||||||
|
import CloseIcon from '../shared/closeIcon';
|
||||||
|
import ClassBadge from '../members/classBadge';
|
||||||
|
import UserLabel from '../userLabel';
|
||||||
|
|
||||||
|
import svgClose from '@/assets/svg/close.svg';
|
||||||
|
import svgCheck from '@/assets/svg/check.svg';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
UserLabel,
|
||||||
|
ClassBadge,
|
||||||
|
CloseIcon,
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
icons: Object.freeze({
|
||||||
|
close: svgClose,
|
||||||
|
check: svgCheck,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
props: ['group'],
|
||||||
|
computed: {
|
||||||
|
...mapGetters({
|
||||||
|
partyMembers: 'party:members',
|
||||||
|
}),
|
||||||
|
members () {
|
||||||
|
const partyMembers = this.partyMembers || [];
|
||||||
|
return partyMembers.map(member => ({
|
||||||
|
...member,
|
||||||
|
accepted: this.group.quest.members[member._id],
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
close () {
|
||||||
|
this.$root.$emit('bv::hide::modal', 'invitation-list');
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
@@ -114,7 +114,7 @@ import groupUtilities from '@/mixins/groupsUtilities';
|
|||||||
|
|
||||||
|
|
||||||
import PublicGuildItem from './publicGuildItem';
|
import PublicGuildItem from './publicGuildItem';
|
||||||
import Sidebar from './sidebar';
|
import Sidebar from './groupSidebar';
|
||||||
|
|
||||||
import greyBadgeIcon from '@/assets/svg/grey-badge.svg';
|
import greyBadgeIcon from '@/assets/svg/grey-badge.svg';
|
||||||
import positiveIcon from '@/assets/svg/positive.svg';
|
import positiveIcon from '@/assets/svg/positive.svg';
|
||||||
|
|||||||
@@ -2,8 +2,15 @@
|
|||||||
<b-modal
|
<b-modal
|
||||||
id="participant-list"
|
id="participant-list"
|
||||||
size="md"
|
size="md"
|
||||||
|
:hide-header="true"
|
||||||
:hide-footer="true"
|
:hide-footer="true"
|
||||||
>
|
>
|
||||||
|
<div class="dialog-close">
|
||||||
|
<close-icon @click="close()" />
|
||||||
|
</div>
|
||||||
|
<h2 class="text-center textCondensed" v-once>
|
||||||
|
{{ $t('participantsTitle') }}
|
||||||
|
</h2>
|
||||||
<div
|
<div
|
||||||
slot="modal-header"
|
slot="modal-header"
|
||||||
class="header-wrap"
|
class="header-wrap"
|
||||||
@@ -29,20 +36,12 @@
|
|||||||
<div
|
<div
|
||||||
v-for="member in participants"
|
v-for="member in participants"
|
||||||
:key="member._id"
|
:key="member._id"
|
||||||
class="row"
|
class="member-row"
|
||||||
>
|
>
|
||||||
<div class="col-12 no-padding-left">
|
<div class="no-padding-left">
|
||||||
<member-details :member="member" />
|
<member-details-new :member="member" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
|
||||||
<button
|
|
||||||
class="btn btn-primary"
|
|
||||||
@click="close()"
|
|
||||||
>
|
|
||||||
{{ $t('close') }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</b-modal>
|
</b-modal>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -70,23 +69,49 @@
|
|||||||
.modal-body {
|
.modal-body {
|
||||||
padding-left: 0;
|
padding-left: 0;
|
||||||
padding-right: 0;
|
padding-right: 0;
|
||||||
|
padding-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.member-details {
|
.member-details {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.modal-content {
|
||||||
|
// so that the rounded corners still apply
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style lang='scss' scoped>
|
<style lang='scss' scoped>
|
||||||
|
@import '~@/assets/scss/colors.scss';
|
||||||
|
|
||||||
.header-wrap {
|
.header-wrap {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
h1 {
|
h2 {
|
||||||
color: #4f2a93;
|
color: $purple-300;
|
||||||
|
margin-top: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.member-row {
|
||||||
|
background-color: $gray-700;
|
||||||
|
|
||||||
|
&:not(:last-of-type) {
|
||||||
|
border-bottom: 1px solid $gray-500;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.member-row {
|
||||||
|
::v-deep {
|
||||||
|
.col-4 {
|
||||||
|
padding-left: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#participant-list_modal_body {
|
#participant-list_modal_body {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
max-height: 450px;
|
max-height: 450px;
|
||||||
@@ -100,11 +125,13 @@
|
|||||||
<script>
|
<script>
|
||||||
import { mapGetters } from '@/libs/store';
|
import { mapGetters } from '@/libs/store';
|
||||||
|
|
||||||
import MemberDetails from '../memberDetails';
|
import MemberDetailsNew from '../memberDetailsNew';
|
||||||
|
import CloseIcon from '../shared/closeIcon';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
MemberDetails,
|
CloseIcon,
|
||||||
|
MemberDetailsNew,
|
||||||
},
|
},
|
||||||
props: ['group'],
|
props: ['group'],
|
||||||
computed: {
|
computed: {
|
||||||
@@ -113,7 +140,10 @@ export default {
|
|||||||
}),
|
}),
|
||||||
participants () {
|
participants () {
|
||||||
const partyMembers = this.partyMembers || [];
|
const partyMembers = this.partyMembers || [];
|
||||||
return partyMembers.filter(member => this.group.quest.members[member._id] === true);
|
const membersAccepted = partyMembers
|
||||||
|
.filter(member => this.group.quest.members[member._id] === true);
|
||||||
|
|
||||||
|
return membersAccepted;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|||||||
89
website/client/src/components/groups/quest-dialog.stories.js
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
/* eslint-disable import/no-extraneous-dependencies */
|
||||||
|
import { storiesOf } from '@storybook/vue';
|
||||||
|
import { withKnobs } from '@storybook/addon-knobs';
|
||||||
|
|
||||||
|
import { quests } from '@/../../common/script/content/quests';
|
||||||
|
import content from '@/../../common/script/content';
|
||||||
|
import questDetailModal from './questDetailModal';
|
||||||
|
import questCompleted from '../achievements/questCompleted';
|
||||||
|
|
||||||
|
const stories = storiesOf('Quests/Dialog', module);
|
||||||
|
|
||||||
|
stories.addDecorator(withKnobs);
|
||||||
|
|
||||||
|
stories
|
||||||
|
.add('selectQuestDialog', () => ({
|
||||||
|
components: { questDetailModal },
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
quest: quests.goldenknight2,
|
||||||
|
questWithDrop: quests.moon1,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
template: `
|
||||||
|
<div>
|
||||||
|
<quest-detail-modal :group="{}"></quest-detail-modal>
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
mounted () {
|
||||||
|
this.$root.$emit('bv::show::modal', 'quest-detail-modal');
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
.add('questDetailModal', () => ({
|
||||||
|
components: { questDetailModal },
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
quest: quests.goldenknight2,
|
||||||
|
questWithDrop: quests.moon1,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
template: `
|
||||||
|
<div>
|
||||||
|
<quest-detail-modal :group="{}"></quest-detail-modal>
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
mounted () {
|
||||||
|
this.$root.$emit('bv::show::modal', 'quest-detail-modal', {
|
||||||
|
key: 'moon1',
|
||||||
|
from: 'sidebar',
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
.add('quest-completed', () => ({
|
||||||
|
components: { questCompleted },
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
quest: quests.goldenknight2,
|
||||||
|
questWithDrop: quests.moon1,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
template: `
|
||||||
|
<div>
|
||||||
|
<quest-completed></quest-completed>
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
mounted () {
|
||||||
|
this.$root.$emit('bv::show::modal', 'quest-completed');
|
||||||
|
},
|
||||||
|
store: {
|
||||||
|
state: {
|
||||||
|
content,
|
||||||
|
user: {
|
||||||
|
data: {
|
||||||
|
stats: {},
|
||||||
|
tags: [],
|
||||||
|
items: {
|
||||||
|
quests: {
|
||||||
|
moon1: 3,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
party: {
|
||||||
|
quest: {
|
||||||
|
completed: 'vice3',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}));
|
||||||
72
website/client/src/components/groups/questActions.mixin.js
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
export default {
|
||||||
|
computed: {
|
||||||
|
onActiveQuest () {
|
||||||
|
return this.group.quest.active;
|
||||||
|
},
|
||||||
|
groupHasQuest () {
|
||||||
|
return this.group.quest && Boolean(this.group.quest.key);
|
||||||
|
},
|
||||||
|
canEditQuest () {
|
||||||
|
if (!this.group.quest) return false;
|
||||||
|
const isQuestLeader = this.group.quest.leader === this.user._id;
|
||||||
|
const isPartyLeader = this.group.leader && this.group.leader._id === this.user._id;
|
||||||
|
return isQuestLeader || isPartyLeader;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async questActionsConfirmQuest () {
|
||||||
|
let count = 0;
|
||||||
|
for (const uuid in this.group.quest.members) {
|
||||||
|
if (this.group.quest.members[uuid]) count += 1;
|
||||||
|
}
|
||||||
|
if (!window.confirm(this.$t('questConfirm', {
|
||||||
|
questmembers: count,
|
||||||
|
totalmembers: this.group.memberCount,
|
||||||
|
}))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
await this._questForceStart();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
async _questForceStart () {
|
||||||
|
const quest = await this.$store.dispatch('quests:sendAction', { groupId: this.group._id, action: 'quests/force-start' });
|
||||||
|
this.group.quest = quest;
|
||||||
|
},
|
||||||
|
// this method combines both if a quest is active or not
|
||||||
|
// it'll call the appropriate api endpoint
|
||||||
|
async questActionsCancelOrAbortQuest () {
|
||||||
|
const partyState = this.$store.state.party;
|
||||||
|
|
||||||
|
if (!partyState.data) {
|
||||||
|
partyState.data = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.onActiveQuest) {
|
||||||
|
if (!window.confirm(this.$t('sureAbort'))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const quest = await this.$store.dispatch('quests:sendAction', {
|
||||||
|
groupId: this.group._id,
|
||||||
|
action: 'quests/abort',
|
||||||
|
});
|
||||||
|
this.group.quest = quest;
|
||||||
|
partyState.data.quest = quest;
|
||||||
|
} else {
|
||||||
|
if (!window.confirm(this.$t('sureCancel'))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const quest = await this.$store.dispatch('quests:sendAction', {
|
||||||
|
groupId: this.group._id,
|
||||||
|
action: 'quests/cancel',
|
||||||
|
});
|
||||||
|
this.group.quest = quest;
|
||||||
|
partyState.data.quest = quest;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
450
website/client/src/components/groups/questDetailModal.vue
Normal file
@@ -0,0 +1,450 @@
|
|||||||
|
<template>
|
||||||
|
<b-modal
|
||||||
|
id="quest-detail-modal"
|
||||||
|
title="Empty"
|
||||||
|
size="md"
|
||||||
|
:hide-footer="true"
|
||||||
|
:hide-header="true"
|
||||||
|
:modal-class="dialogClass"
|
||||||
|
>
|
||||||
|
<div class="dialog-close">
|
||||||
|
<close-icon @click="close()" />
|
||||||
|
</div>
|
||||||
|
<h2 class="text-center textCondensed">
|
||||||
|
{{ selectMode ? $t('selectQuest') : $t('questDetailsTitle') }}
|
||||||
|
</h2>
|
||||||
|
<div class="quest-panel" v-if="selectMode">
|
||||||
|
<div class="quest-panel-header">
|
||||||
|
<h3>
|
||||||
|
{{ $t('yourQuests') }}
|
||||||
|
</h3>
|
||||||
|
<div class="sort-by">
|
||||||
|
<span class="dropdown-label">{{ $t('sort') }}</span>
|
||||||
|
<select-translated-array
|
||||||
|
:right="true"
|
||||||
|
:items="['quantity', 'AZ']"
|
||||||
|
:value="sortBy"
|
||||||
|
class="inline"
|
||||||
|
:inline-dropdown="false"
|
||||||
|
@select="sortBy = $event"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="quest-items">
|
||||||
|
<div
|
||||||
|
v-for="item in questsInfoList"
|
||||||
|
:key="item.key"
|
||||||
|
class="quest-col"
|
||||||
|
@click="selectQuest(item)"
|
||||||
|
>
|
||||||
|
<item
|
||||||
|
:key="item.key"
|
||||||
|
:item="item"
|
||||||
|
:item-content-class="item.class"
|
||||||
|
>
|
||||||
|
<countBadge
|
||||||
|
slot="itemBadge"
|
||||||
|
:show="item.amount !== 1"
|
||||||
|
:count="item.amount"
|
||||||
|
/>
|
||||||
|
<template
|
||||||
|
slot="popoverContent"
|
||||||
|
slot-scope="context"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="questPopover"
|
||||||
|
>
|
||||||
|
<h4 class="popover-content-title">
|
||||||
|
{{ context.item.text }}
|
||||||
|
</h4>
|
||||||
|
<questInfo :quest="context.item" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</item>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-10 offset-1 text-center">
|
||||||
|
<span
|
||||||
|
v-once
|
||||||
|
class="no-quest-to-start"
|
||||||
|
>
|
||||||
|
<b>{{ $t('noQuestToStartTitle') }}</b> <br>
|
||||||
|
<span v-html="$t('noQuestToStart', { questShop: '/shops/quests' })"></span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-else>
|
||||||
|
<div v-if="questData" class="quest-combined-content">
|
||||||
|
<questDialogContent
|
||||||
|
:item="questData"
|
||||||
|
:group="group"
|
||||||
|
class="quest-detail"
|
||||||
|
/>
|
||||||
|
<quest-rewards :quest="questData" class="mt-4" />
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="!groupHasQuest"
|
||||||
|
class="text-center"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
class="btn btn-primary mt-0 invite-btn"
|
||||||
|
:disabled="!Boolean(selectedQuest) || loading"
|
||||||
|
@click="questInit()"
|
||||||
|
>
|
||||||
|
{{ $t('inviteToPartyOrQuest') }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="fromSelectionDialog"
|
||||||
|
class="text-center back-to-selection"
|
||||||
|
@click="goBackToQuestSelection()"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
v-once
|
||||||
|
class="svg-icon color"
|
||||||
|
v-html="icons.navigationBack"
|
||||||
|
>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span>
|
||||||
|
{{ $t('backToSelection') }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="groupHasQuest && canEditQuest"
|
||||||
|
class="text-center actions"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<button
|
||||||
|
v-if="!onActiveQuest"
|
||||||
|
v-once
|
||||||
|
class="btn btn-success mb-3"
|
||||||
|
@click="questConfirm()"
|
||||||
|
>
|
||||||
|
{{ $t('startQuest') }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div
|
||||||
|
v-once
|
||||||
|
class="cancel"
|
||||||
|
@click="questCancel()"
|
||||||
|
>
|
||||||
|
{{ $t('cancelQuest') }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</b-modal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang='scss' scoped>
|
||||||
|
@import '~@/assets/scss/colors.scss';
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
color: $purple-300;
|
||||||
|
margin-top: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.invite-btn {
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.back-to-selection {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
color: $blue-10;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 1.71;
|
||||||
|
text-align: right;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.svg-icon {
|
||||||
|
color: $blue-50;
|
||||||
|
height: 14px;
|
||||||
|
width: 9px;
|
||||||
|
|
||||||
|
margin-right: 0.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.quest-panel {
|
||||||
|
background-color: $gray-700;
|
||||||
|
|
||||||
|
// reset margin
|
||||||
|
margin-left: -1rem;
|
||||||
|
margin-right: -1rem;
|
||||||
|
margin-bottom: -1rem;
|
||||||
|
|
||||||
|
// add padding back
|
||||||
|
padding-top: 1rem;
|
||||||
|
padding-left: 1.5rem;
|
||||||
|
padding-right: 1.5rem;
|
||||||
|
padding-bottom: 2rem;
|
||||||
|
|
||||||
|
border-bottom-left-radius: 1rem;
|
||||||
|
border-bottom-right-radius: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.quest-panel-header {
|
||||||
|
padding-bottom: 1rem;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.quest-items {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 0.5rem;
|
||||||
|
|
||||||
|
// somehow the browser felt like setting this 398px instead
|
||||||
|
// now its fixed to 400 :)
|
||||||
|
width: 400px;
|
||||||
|
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
|
||||||
|
.quest-col {
|
||||||
|
::v-deep {
|
||||||
|
.item-wrapper {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.quest-detail {
|
||||||
|
margin-left: 1rem;
|
||||||
|
margin-right: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-quest-to-start {
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 1.33;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
color: $gray-100;
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: $blue-10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#quest-detail-modal {
|
||||||
|
::v-deep & {
|
||||||
|
.modal-dialog {
|
||||||
|
width: 448px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.quest-combined-content {
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep &:not(.need-bottom-padding) {
|
||||||
|
.modal-content {
|
||||||
|
// so that the rounded corners still apply
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-body {
|
||||||
|
padding-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.quest-combined-content {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (max-width: 1000px) {
|
||||||
|
.modal-dialog {
|
||||||
|
max-width: 80%;
|
||||||
|
width: 80% !important;
|
||||||
|
|
||||||
|
.modal-body {
|
||||||
|
flex-direction: column;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions {
|
||||||
|
padding-bottom: .5em;
|
||||||
|
|
||||||
|
.cancel {
|
||||||
|
color: $maroon-50;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cancel:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import orderBy from 'lodash/orderBy';
|
||||||
|
import { mapState } from '@/libs/store';
|
||||||
|
import * as Analytics from '@/libs/analytics';
|
||||||
|
|
||||||
|
import * as quests from '@/../../common/script/content/quests';
|
||||||
|
|
||||||
|
import navigationBack from '@/assets/svg/navigation_back.svg';
|
||||||
|
import questDialogContent from '../shops/quests/questDialogContent';
|
||||||
|
import closeIcon from '../shared/closeIcon';
|
||||||
|
import QuestRewards from '../shops/quests/questRewards';
|
||||||
|
import questActionsMixin from './questActions.mixin';
|
||||||
|
import SelectTranslatedArray from '../tasks/modal-controls/selectTranslatedArray';
|
||||||
|
import QuestInfo from '../shops/quests/questInfo';
|
||||||
|
import Item from '@/components/inventory/item';
|
||||||
|
import getItemInfo from '../../../../common/script/libs/getItemInfo';
|
||||||
|
import CountBadge from '../ui/countBadge';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
CountBadge,
|
||||||
|
QuestRewards,
|
||||||
|
questDialogContent,
|
||||||
|
closeIcon,
|
||||||
|
SelectTranslatedArray,
|
||||||
|
QuestInfo,
|
||||||
|
Item,
|
||||||
|
},
|
||||||
|
mixins: [questActionsMixin],
|
||||||
|
props: ['group'],
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
loading: false,
|
||||||
|
selectMode: true,
|
||||||
|
selectedQuest: {},
|
||||||
|
fromSelectionDialog: false,
|
||||||
|
icons: Object.freeze({
|
||||||
|
navigationBack,
|
||||||
|
}),
|
||||||
|
shareUserIdShown: false,
|
||||||
|
quests,
|
||||||
|
sortBy: 'AZ',
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapState({ user: 'user.data' }),
|
||||||
|
questData () {
|
||||||
|
return quests.quests[this.selectedQuest];
|
||||||
|
},
|
||||||
|
dialogClass () {
|
||||||
|
if (!this.groupHasQuest || this.fromSelectionDialog || this.canEditQuest) {
|
||||||
|
return 'need-bottom-padding';
|
||||||
|
}
|
||||||
|
|
||||||
|
return '';
|
||||||
|
},
|
||||||
|
|
||||||
|
questsInfoList () {
|
||||||
|
const availableQuests = Object.entries(this.user.items.quests)
|
||||||
|
.filter(([, amount]) => amount > 0);
|
||||||
|
|
||||||
|
return orderBy(availableQuests.map(([key, amount]) => {
|
||||||
|
const questItem = quests.quests[key];
|
||||||
|
|
||||||
|
return {
|
||||||
|
...getItemInfo(this.user, 'quests', questItem),
|
||||||
|
amount,
|
||||||
|
};
|
||||||
|
}), item => (this.sortBy === 'AZ' ? item.text : -item.amount));
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mounted () {
|
||||||
|
const userQuests = this.user.items.quests;
|
||||||
|
for (const key in userQuests) {
|
||||||
|
if (userQuests[key] > 0) {
|
||||||
|
this.selectedQuest = key;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$root.$on('bv::show::modal', this.handleOpen);
|
||||||
|
},
|
||||||
|
beforeDestroy () {
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
selectQuest (selectQuestPayload) {
|
||||||
|
this.selectMode = false;
|
||||||
|
this.selectedQuest = selectQuestPayload.key;
|
||||||
|
this.fromSelectionDialog = true;
|
||||||
|
},
|
||||||
|
async questInit () {
|
||||||
|
this.loading = true;
|
||||||
|
|
||||||
|
Analytics.updateUser({
|
||||||
|
partyID: this.group._id,
|
||||||
|
partySize: this.group.memberCount,
|
||||||
|
});
|
||||||
|
|
||||||
|
const groupId = this.group._id || this.user.party._id;
|
||||||
|
|
||||||
|
const key = this.selectedQuest;
|
||||||
|
try {
|
||||||
|
const response = await this.$store.dispatch('guilds:inviteToQuest', { groupId, key });
|
||||||
|
const quest = response.data.data;
|
||||||
|
|
||||||
|
// TODO move the state updates to the action itself
|
||||||
|
const partyState = this.$store.state.party;
|
||||||
|
|
||||||
|
if (!partyState.data) {
|
||||||
|
partyState.data = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
partyState.data.quest = quest;
|
||||||
|
} finally {
|
||||||
|
this.loading = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.close();
|
||||||
|
},
|
||||||
|
close () {
|
||||||
|
this.$root.$emit('bv::hide::modal', 'quest-detail-modal');
|
||||||
|
},
|
||||||
|
async questConfirm () {
|
||||||
|
const accepted = await this.questActionsConfirmQuest();
|
||||||
|
|
||||||
|
if (accepted) {
|
||||||
|
this.close();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async questCancel () {
|
||||||
|
const accepted = await this.questActionsCancelOrAbortQuest();
|
||||||
|
|
||||||
|
if (accepted) {
|
||||||
|
this.close();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
goBackToQuestSelection () {
|
||||||
|
this.selectMode = true;
|
||||||
|
},
|
||||||
|
handleOpen (_, selectQuestPayload) {
|
||||||
|
this.fromSelectionDialog = false;
|
||||||
|
|
||||||
|
if (selectQuestPayload) {
|
||||||
|
this.selectMode = false;
|
||||||
|
this.selectedQuest = selectQuestPayload.key;
|
||||||
|
} else {
|
||||||
|
this.selectMode = true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
@@ -1,287 +0,0 @@
|
|||||||
<template>
|
|
||||||
<b-modal
|
|
||||||
id="quest-details"
|
|
||||||
title="Empty"
|
|
||||||
size="md"
|
|
||||||
:hide-footer="true"
|
|
||||||
:hide-header="true"
|
|
||||||
>
|
|
||||||
<div class="left-panel content">
|
|
||||||
<h3 class="text-center">
|
|
||||||
{{ $t('participantsTitle') }}
|
|
||||||
</h3>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-10 offset-1 text-center">
|
|
||||||
<span
|
|
||||||
v-once
|
|
||||||
class="description"
|
|
||||||
>{{ $t('participantDesc') }}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
|
||||||
<div
|
|
||||||
v-for="member in members"
|
|
||||||
:key="member._id"
|
|
||||||
class="col-12 member"
|
|
||||||
>
|
|
||||||
<strong :class="{'declined-name': member.accepted === false}">{{ member.name }}</strong>
|
|
||||||
<div
|
|
||||||
v-if="member.accepted === true"
|
|
||||||
class="accepted float-right"
|
|
||||||
>
|
|
||||||
{{ $t('accepted') }}
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
v-if="member.accepted === false"
|
|
||||||
class="declined float-right"
|
|
||||||
>
|
|
||||||
{{ $t('declined') }}
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
v-if="member.accepted === null"
|
|
||||||
class="pending float-right"
|
|
||||||
>
|
|
||||||
{{ $t('pending') }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div v-if="questData">
|
|
||||||
<questDialogContent :item="questData" />
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
v-if="canEditQuest"
|
|
||||||
class="text-center actions"
|
|
||||||
>
|
|
||||||
<div>
|
|
||||||
<button
|
|
||||||
v-once
|
|
||||||
class="btn btn-secondary"
|
|
||||||
@click="questConfirm()"
|
|
||||||
>
|
|
||||||
{{ $t('begin') }}
|
|
||||||
</button>
|
|
||||||
<!-- @TODO don't allow the party leader to
|
|
||||||
start the quest until the leader has accepted
|
|
||||||
or rejected the invitation (users get confused and think "begin" means "join quest")-->
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div
|
|
||||||
v-once
|
|
||||||
class="cancel"
|
|
||||||
@click="questCancel()"
|
|
||||||
>
|
|
||||||
{{ $t('cancel') }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
v-if="questData"
|
|
||||||
class="side-panel"
|
|
||||||
>
|
|
||||||
<questDialogDrops :item="questData" />
|
|
||||||
</div>
|
|
||||||
</b-modal>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style lang='scss' scoped>
|
|
||||||
@import '~@/assets/scss/colors.scss';
|
|
||||||
|
|
||||||
header {
|
|
||||||
background-color: $white !important;
|
|
||||||
border: none !important;
|
|
||||||
|
|
||||||
h5 {
|
|
||||||
text-indent: -99999px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.quest-details {
|
|
||||||
margin: 0 auto;
|
|
||||||
text-align: left;
|
|
||||||
width: 180px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-primary {
|
|
||||||
margin: 1em 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.left-panel {
|
|
||||||
background: #4e4a57;
|
|
||||||
color: $white;
|
|
||||||
position: absolute;
|
|
||||||
height: 460px;
|
|
||||||
width: 320px;
|
|
||||||
top: 2.5em;
|
|
||||||
left: -22.8em;
|
|
||||||
z-index: -1;
|
|
||||||
padding: 2em;
|
|
||||||
overflow-y: auto;
|
|
||||||
h3 {
|
|
||||||
color: $white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.selected .quest-wrapper {
|
|
||||||
border: solid 1.5px #9a62ff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.quest-wrapper:hover {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.quest-col .quest-wrapper {
|
|
||||||
background: $white;
|
|
||||||
padding: .2em;
|
|
||||||
margin-bottom: 1em;
|
|
||||||
border-radius: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.description {
|
|
||||||
text-align: center;
|
|
||||||
color: #a5a1ac;
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.side-panel {
|
|
||||||
position: absolute;
|
|
||||||
right: -350px;
|
|
||||||
top: 25px;
|
|
||||||
border-radius: 8px;
|
|
||||||
background-color: $gray-600;
|
|
||||||
box-shadow: 0 2px 16px 0 rgba(26, 24, 29, 0.32);
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
flex-direction: column;
|
|
||||||
width: 364px;
|
|
||||||
z-index: -1;
|
|
||||||
height: 93%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.member {
|
|
||||||
padding: 1em .5em;
|
|
||||||
border-top: 1px solid #686274;
|
|
||||||
|
|
||||||
.declined-name {
|
|
||||||
color: #878190;
|
|
||||||
}
|
|
||||||
|
|
||||||
.accepted {
|
|
||||||
color: #1ed3a0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.declined {
|
|
||||||
color: #f19595;
|
|
||||||
}
|
|
||||||
|
|
||||||
.pending {
|
|
||||||
color: #c3c0c7;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.actions {
|
|
||||||
padding-top: 2em;
|
|
||||||
padding-bottom: 2em;
|
|
||||||
|
|
||||||
.cancel {
|
|
||||||
color: #f74e52;
|
|
||||||
margin-top: 3em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cancel:hover {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import { mapState, mapGetters } from '@/libs/store';
|
|
||||||
import * as quests from '@/../../common/script/content/quests';
|
|
||||||
|
|
||||||
import copyIcon from '@/assets/svg/copy.svg';
|
|
||||||
import greyBadgeIcon from '@/assets/svg/grey-badge.svg';
|
|
||||||
import qrCodeIcon from '@/assets/svg/qrCode.svg';
|
|
||||||
import facebookIcon from '@/assets/svg/facebook.svg';
|
|
||||||
import twitterIcon from '@/assets/svg/twitter.svg';
|
|
||||||
import starIcon from '@/assets/svg/star.svg';
|
|
||||||
import goldIcon from '@/assets/svg/gold.svg';
|
|
||||||
import difficultyStarIcon from '@/assets/svg/difficulty-star.svg';
|
|
||||||
import questDialogDrops from '../shops/quests/questDialogDrops';
|
|
||||||
import questDialogContent from '../shops/quests/questDialogContent';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
components: {
|
|
||||||
questDialogDrops,
|
|
||||||
questDialogContent,
|
|
||||||
},
|
|
||||||
props: ['group'],
|
|
||||||
data () {
|
|
||||||
return {
|
|
||||||
loading: false,
|
|
||||||
selectedQuest: {},
|
|
||||||
icons: Object.freeze({
|
|
||||||
copy: copyIcon,
|
|
||||||
greyBadge: greyBadgeIcon,
|
|
||||||
qrCode: qrCodeIcon,
|
|
||||||
facebook: facebookIcon,
|
|
||||||
twitter: twitterIcon,
|
|
||||||
starIcon,
|
|
||||||
goldIcon,
|
|
||||||
difficultyStarIcon,
|
|
||||||
}),
|
|
||||||
};
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
...mapState({
|
|
||||||
user: 'user.data',
|
|
||||||
}),
|
|
||||||
...mapGetters({
|
|
||||||
partyMembers: 'party:members',
|
|
||||||
}),
|
|
||||||
questData () {
|
|
||||||
return quests.quests[this.group.quest.key];
|
|
||||||
},
|
|
||||||
members () {
|
|
||||||
const partyMembers = this.partyMembers || [];
|
|
||||||
return partyMembers.map(member => ({
|
|
||||||
name: member.profile.name,
|
|
||||||
accepted: this.group.quest.members[member._id],
|
|
||||||
_id: member._id,
|
|
||||||
}));
|
|
||||||
},
|
|
||||||
canEditQuest () {
|
|
||||||
if (!this.group.quest) return false;
|
|
||||||
const isQuestLeader = this.group.quest.leader === this.user._id;
|
|
||||||
const isPartyLeader = this.group.leader._id === this.user._id;
|
|
||||||
return isQuestLeader || isPartyLeader;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
async questConfirm () {
|
|
||||||
let count = 0;
|
|
||||||
for (const uuid in this.group.quest.members) {
|
|
||||||
if (this.group.quest.members[uuid]) count += 1;
|
|
||||||
}
|
|
||||||
if (!window.confirm(this.$t('questConfirm', { // eslint-disable-line no-alert
|
|
||||||
questmembers: count,
|
|
||||||
totalmembers: this.group.memberCount,
|
|
||||||
}))) return;
|
|
||||||
this.questForceStart();
|
|
||||||
},
|
|
||||||
async questForceStart () {
|
|
||||||
const quest = await this.$store.dispatch('quests:sendAction', { groupId: this.group._id, action: 'quests/force-start' });
|
|
||||||
this.group.quest = quest;
|
|
||||||
this.close();
|
|
||||||
},
|
|
||||||
async questCancel () {
|
|
||||||
if (!window.confirm(this.$t('sureCancel'))) return; // eslint-disable-line no-alert
|
|
||||||
const quest = await this.$store.dispatch('quests:sendAction', { groupId: this.group._id, action: 'quests/cancel' });
|
|
||||||
this.group.quest = quest;
|
|
||||||
this.close();
|
|
||||||
},
|
|
||||||
close () {
|
|
||||||
this.$root.$emit('bv::hide::modal', 'quest-details');
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
@@ -6,11 +6,12 @@
|
|||||||
>
|
>
|
||||||
<div class="col-12 text-center">
|
<div class="col-12 text-center">
|
||||||
<div
|
<div
|
||||||
class="svg-icon"
|
class="svg-icon quest-icon color"
|
||||||
v-html="icons.questIcon"
|
v-html="icons.questIcon"
|
||||||
|
v-once
|
||||||
></div>
|
></div>
|
||||||
<h4 v-once>
|
<h4 v-once>
|
||||||
{{ $t('youAreNotOnQuest') }}
|
{{ $t('yourPartyIsNotOnQuest') }}
|
||||||
</h4>
|
</h4>
|
||||||
<p v-once>
|
<p v-once>
|
||||||
{{ $t('questDescription') }}
|
{{ $t('questDescription') }}
|
||||||
@@ -18,102 +19,78 @@
|
|||||||
<button
|
<button
|
||||||
v-once
|
v-once
|
||||||
class="btn btn-secondary"
|
class="btn btn-secondary"
|
||||||
@click="openStartQuestModal()"
|
@click="openSelectQuestModal()"
|
||||||
>
|
>
|
||||||
{{ $t('startAQuest') }}
|
{{ $t('selectQuest') }}
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
v-if="onPendingQuest && !onActiveQuest"
|
|
||||||
class="row quest-active-section"
|
|
||||||
>
|
|
||||||
<div class="col-2">
|
|
||||||
<div
|
|
||||||
class="quest"
|
|
||||||
:class="`inventory_quest_scroll_${questData.key}`"
|
|
||||||
></div>
|
|
||||||
</div>
|
|
||||||
<div class="col-6 titles">
|
|
||||||
<strong>{{ questData.text() }}</strong>
|
|
||||||
<p>{{ acceptedCount }} / {{ group.memberCount }}</p>
|
|
||||||
</div>
|
|
||||||
<div class="col-4">
|
|
||||||
<button
|
|
||||||
class="btn btn-secondary"
|
|
||||||
@click="openQuestDetails()"
|
|
||||||
>
|
|
||||||
{{ $t('details') }}
|
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-if="user.party.quest && user.party.quest.RSVPNeeded"
|
v-if="user.party.quest && user.party.quest.RSVPNeeded"
|
||||||
class="row quest-active-section quest-invite"
|
class="quest-active-section quest-invite"
|
||||||
>
|
>
|
||||||
<span>{{ $t('wouldYouParticipate') }}</span>
|
<span class="participate">{{ $t('invitedToThisQuest') }}</span>
|
||||||
|
<div class="buttons">
|
||||||
<button
|
<button
|
||||||
class="btn btn-primary accept"
|
class="btn btn-success accept"
|
||||||
@click="questAccept(group._id)"
|
@click="questAccept(group._id)"
|
||||||
>
|
>
|
||||||
{{ $t('accept') }}
|
{{ $t('accept') }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
class="btn btn-primary reject"
|
class="btn btn-danger reject"
|
||||||
@click="questReject(group._id)"
|
@click="questReject(group._id)"
|
||||||
>
|
>
|
||||||
{{ $t('reject') }}
|
{{ $t('reject') }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<div
|
<div
|
||||||
v-if="!onPendingQuest && onActiveQuest"
|
v-if="!onPendingQuest && onActiveQuest"
|
||||||
class="row quest-active-section"
|
class="row quest-active-section"
|
||||||
|
:class="{'not-participating': !userIsOnQuest}"
|
||||||
>
|
>
|
||||||
<div class="col-12 text-center">
|
<div class="col-12 text-center">
|
||||||
<div
|
<div
|
||||||
class="quest-boss"
|
class="quest-boss"
|
||||||
:class="'quest_' + questData.key"
|
:class="'quest_' + questData.key"
|
||||||
></div>
|
></div>
|
||||||
<h3 v-once>
|
|
||||||
{{ questData.text() }}
|
|
||||||
</h3>
|
|
||||||
<div class="quest-box">
|
<div class="quest-box">
|
||||||
<div
|
<div
|
||||||
v-if="questData.collect"
|
v-if="questData.collect"
|
||||||
class="collect-info"
|
class="collect-info"
|
||||||
>
|
>
|
||||||
<div class="row">
|
|
||||||
<div class="col-12">
|
|
||||||
<a
|
|
||||||
class="float-right"
|
|
||||||
@click="openParticipantList()"
|
|
||||||
>{{ $t('participantsTitle') }}</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div
|
<div
|
||||||
v-for="(value, key) in questData.collect"
|
v-for="(value, key) in questData.collect"
|
||||||
:key="key"
|
:key="key"
|
||||||
class="row"
|
class="quest-item-row"
|
||||||
>
|
>
|
||||||
<div class="col-2">
|
<div class="quest-item-icon">
|
||||||
<div :class="'quest_' + questData.key + '_' + key"></div>
|
<div :class="'quest_' + questData.key + '_' + key"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-10">
|
<div class="quest-item-info">
|
||||||
<strong>{{ value.text() }}</strong>
|
<span class="label quest-label">{{ value.text() }}</span>
|
||||||
<div class="grey-progress-bar">
|
<div class="grey-progress-bar">
|
||||||
<div
|
<div
|
||||||
class="collect-progress-bar"
|
class="collect-progress-bar"
|
||||||
:style="{width: (group.quest.progress.collect[key] / value.count) * 100 + '%'}"
|
:style="{width: (group.quest.progress.collect[key] / value.count) * 100 + '%'}"
|
||||||
></div>
|
></div>
|
||||||
</div>
|
</div>
|
||||||
<strong>{{ group.quest.progress.collect[key] }} / {{ value.count }}</strong>
|
<div class="item-progress-row">
|
||||||
</div>
|
<span
|
||||||
</div>
|
class="label item-progress"
|
||||||
<div
|
:class="{'no-items': group.quest.progress.collect[key] === 0}"
|
||||||
v-if="userIsOnQuest"
|
|
||||||
class="text-right"
|
|
||||||
>
|
>
|
||||||
{{ parseFloat(user.party.quest.progress.collectedItems) || 0 }} items found
|
{{ group.quest.progress.collect[key] }} / {{ value.count }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-if="hasPendingQuestItems"
|
||||||
|
class="item-progress-pending mb-2">
|
||||||
|
<div class="pending-amount pt-2 pb-2">
|
||||||
|
{{ $t('questItemsPending', { amount: user.party.quest.progress.collectedItems }) }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
@@ -121,20 +98,14 @@
|
|||||||
class="boss-info"
|
class="boss-info"
|
||||||
>
|
>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-6">
|
<div class="col-12">
|
||||||
<h4
|
<h4
|
||||||
v-once
|
v-once
|
||||||
class="float-left"
|
class="float-left boss-name"
|
||||||
>
|
>
|
||||||
{{ questData.boss.name() }}
|
{{ questData.boss.name() }}
|
||||||
</h4>
|
</h4>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-6">
|
|
||||||
<a
|
|
||||||
class="float-right"
|
|
||||||
@click="openParticipantList()"
|
|
||||||
>{{ $t('participantsTitle') }}</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
@@ -143,12 +114,22 @@
|
|||||||
class="boss-health-bar"
|
class="boss-health-bar"
|
||||||
:style="{width: bossHpPercent + '%'}"
|
:style="{width: bossHpPercent + '%'}"
|
||||||
></div>
|
></div>
|
||||||
|
<div
|
||||||
|
class="pending-health-bar"
|
||||||
|
:style="{width: pendingHpPercent + '%'}"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row boss-details">
|
<div class="row boss-details">
|
||||||
<div class="col-6">
|
<div class="col-6">
|
||||||
<span class="float-left">
|
<span class="float-left hp-value">
|
||||||
|
<div
|
||||||
|
class="svg-icon health-icon"
|
||||||
|
v-html="icons.healthNoPaddingIcon"
|
||||||
|
v-once
|
||||||
|
></div>
|
||||||
{{
|
{{
|
||||||
(Math.ceil(parseFloat(group.quest.progress.hp) * 100) / 100)
|
(Math.ceil(parseFloat(group.quest.progress.hp) * 100) / 100)
|
||||||
| localizeNumber(user.preferences.language, { toFixed:2 })
|
| localizeNumber(user.preferences.language, { toFixed:2 })
|
||||||
@@ -156,22 +137,30 @@
|
|||||||
parseFloat(questData.boss.hp)
|
parseFloat(questData.boss.hp)
|
||||||
| localizeNumber(user.preferences.language, { toFixed:2 })
|
| localizeNumber(user.preferences.language, { toFixed:2 })
|
||||||
}}
|
}}
|
||||||
|
<strong>HP</strong>
|
||||||
|
|
||||||
<!-- current boss hp uses ceil so
|
<!-- current boss hp uses ceil so
|
||||||
you don't underestimate damage needed to end quest-->
|
you don't underestimate damage needed to end quest-->
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-if="userIsOnQuest"
|
v-if="userIsOnQuest && user.party.quest.progress.up"
|
||||||
class="col-6"
|
class="col-6"
|
||||||
>
|
>
|
||||||
<!-- @TODO: Why do we not sync quest
|
<!-- @TODO: Why do we not sync quest
|
||||||
progress on the group doc? Each user could have different progress.-->
|
progress on the group doc? Each user could have different progress.-->
|
||||||
<span class="float-right">
|
<span class="float-right pending-value">
|
||||||
|
<div
|
||||||
|
class="svg-icon sword-icon"
|
||||||
|
v-html="icons.swordIcon"
|
||||||
|
v-once
|
||||||
|
></div>
|
||||||
{{
|
{{
|
||||||
(user.party.quest.progress.up || 0)
|
(user.party.quest.progress.up || 0)
|
||||||
| floor(10)
|
| floor(10)
|
||||||
| localizeNumber(user.preferences.language, { toFixed:1 })
|
| localizeNumber(user.preferences.language, { toFixed:1 })
|
||||||
}} {{ $t('pendingDamageLabel') }}
|
}}
|
||||||
|
{{ $t('pendingDamageLabel') }}
|
||||||
</span>
|
</span>
|
||||||
<!-- player's pending damage uses floor so you
|
<!-- player's pending damage uses floor so you
|
||||||
don't overestimate damage you've already done-->
|
don't overestimate damage you've already done-->
|
||||||
@@ -196,6 +185,13 @@
|
|||||||
class="row boss-details rage-details"
|
class="row boss-details rage-details"
|
||||||
>
|
>
|
||||||
<div class="col-6">
|
<div class="col-6">
|
||||||
|
<span class="float-left rage-value">
|
||||||
|
<div
|
||||||
|
class="svg-icon rage-icon icon-16"
|
||||||
|
v-html="icons.rageIcon"
|
||||||
|
v-once
|
||||||
|
>
|
||||||
|
</div>
|
||||||
<span
|
<span
|
||||||
class="float-left"
|
class="float-left"
|
||||||
>{{ $t('rage') }} {{
|
>{{ $t('rage') }} {{
|
||||||
@@ -205,19 +201,63 @@
|
|||||||
questData.boss.rage.value
|
questData.boss.rage.value
|
||||||
| localizeNumber(user.preferences.language)
|
| localizeNumber(user.preferences.language)
|
||||||
}}</span>
|
}}</span>
|
||||||
|
<strong v-once>{{ $t('rage') }}</strong>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button
|
</div>
|
||||||
v-if="canEditQuest"
|
</div>
|
||||||
v-once
|
<div
|
||||||
class="btn btn-secondary"
|
v-if="onPendingQuest || onActiveQuest"
|
||||||
@click="questAbort()"
|
class="quest-pending-section"
|
||||||
>
|
>
|
||||||
{{ $t('abort') }}
|
<div class="titles">
|
||||||
|
<strong>{{ questData.text() }} </strong>
|
||||||
|
<a
|
||||||
|
class="members-invited"
|
||||||
|
@click="openParticipantList()"
|
||||||
|
>
|
||||||
|
{{ $t('membersParticipating', {accepted: acceptedCount, invited: group.memberCount}) }}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="quest-icon">
|
||||||
|
<div
|
||||||
|
class="quest"
|
||||||
|
:class="`inventory_quest_scroll_${questData.key}`"
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-if="onPendingQuest || onActiveQuest"
|
||||||
|
class="quest-buttons">
|
||||||
|
<button
|
||||||
|
class="btn btn-secondary w-100"
|
||||||
|
@click="openQuestDetails()"
|
||||||
|
>
|
||||||
|
{{ $t('viewDetails') }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
<div v-if="userIsQuestLeader && !onActiveQuest"
|
||||||
|
class="quest-buttons">
|
||||||
|
<button
|
||||||
|
class="btn btn-success w-100"
|
||||||
|
@click="startQuest()"
|
||||||
|
>
|
||||||
|
{{ $t('startQuest') }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="userIsOnQuest && !userIsQuestLeader"
|
||||||
|
class="leave-quest-holder"
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
v-once
|
||||||
|
class="leave-quest text-center"
|
||||||
|
@click="questLeave()"
|
||||||
|
>
|
||||||
|
{{ $t('leaveQuest') }}
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</sidebar-section>
|
</sidebar-section>
|
||||||
</template>
|
</template>
|
||||||
@@ -230,30 +270,49 @@
|
|||||||
width: 25px;
|
width: 25px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.quest-buttons {
|
||||||
|
margin-bottom: 0.25rem;
|
||||||
|
|
||||||
|
&:nth-last-of-type(2) {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.quest-buttons + .quest-buttons {
|
||||||
|
margin-top: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
.quest-boss {
|
.quest-boss {
|
||||||
margin: 0 auto;
|
margin: 0 auto 1.188rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.boss-health-bar {
|
.boss-health-bar {
|
||||||
width: 80%;
|
background-color: $red-50;
|
||||||
background-color: red;
|
height: 0.75rem;
|
||||||
height: 15px;
|
|
||||||
margin-bottom: .5em;
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pending-health-bar {
|
||||||
|
height: 0.75rem;
|
||||||
|
background-color: $yellow-50;
|
||||||
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.rage-details {
|
.rage-details {
|
||||||
margin-bottom: 1em;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.boss-health-bar.rage-bar {
|
.boss-health-bar.rage-bar {
|
||||||
margin-top: 1em;
|
background-color: $orange-50;
|
||||||
background-color: orange;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.grey-progress-bar {
|
.grey-progress-bar {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 15px;
|
height: 0.75rem;
|
||||||
background-color: #e1e0e3;
|
background-color: #e1e0e3;
|
||||||
|
border-radius: 2px;
|
||||||
|
overflow: hidden;
|
||||||
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
.collect-progress-bar {
|
.collect-progress-bar {
|
||||||
@@ -264,35 +323,84 @@
|
|||||||
|
|
||||||
.no-quest-section {
|
.no-quest-section {
|
||||||
padding: 2em;
|
padding: 2em;
|
||||||
color: $gray-300;
|
|
||||||
|
|
||||||
h4 {
|
h4 {
|
||||||
color: $gray-300;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
p {
|
p {
|
||||||
margin-bottom: 2em;
|
margin-bottom: 1em;
|
||||||
|
color: $gray-100;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
line-height: 1.33;
|
||||||
}
|
}
|
||||||
|
|
||||||
.svg-icon {
|
.quest-icon {
|
||||||
height: 30px;
|
width: 1.125rem;
|
||||||
width: 30px;
|
height: 1.25rem;
|
||||||
margin: 0 auto;
|
margin: 0 auto 0.5em;
|
||||||
margin-bottom: 2em;
|
object-fit: contain;
|
||||||
|
border-radius: 2px;
|
||||||
|
color: $gray-200;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.quest-pending-section {
|
||||||
|
display: flex;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
|
||||||
|
.titles {
|
||||||
|
flex: 1;
|
||||||
|
margin-top: 1rem;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
line-height: 1.33;
|
||||||
|
|
||||||
|
strong {
|
||||||
|
display: block;
|
||||||
|
min-height: 1rem;
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
line-height: 1.33;
|
||||||
|
color: $gray-100;
|
||||||
|
margin-bottom: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.members-invited {
|
||||||
|
min-height: 1rem;
|
||||||
|
color: $blue-10;
|
||||||
|
margin: 0;
|
||||||
|
|
||||||
|
&:hover, &:focus {
|
||||||
|
color: $blue-10;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.quest-icon {
|
||||||
|
width: 4.25rem;
|
||||||
|
height: 4.25rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.quest-active-section {
|
.quest-active-section {
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
|
||||||
|
.participate {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
font-weight: bold;
|
||||||
|
line-height: 1.33;
|
||||||
|
color: $white;
|
||||||
|
}
|
||||||
|
|
||||||
.titles {
|
.titles {
|
||||||
padding-top: .5em;
|
padding-top: .5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.quest-box {
|
.quest-box {
|
||||||
background-image: url('~@/assets/svg/for-css/quest-border.svg');
|
padding: 0.75rem 1rem;
|
||||||
background-size: 100% 100%;
|
border-radius: 4px;
|
||||||
width: 100%;
|
background-color: $white;
|
||||||
padding: .5em;
|
|
||||||
margin-bottom: 1em;
|
|
||||||
|
|
||||||
a {
|
a {
|
||||||
font-family: 'Roboto Condensed', sans-serif;
|
font-family: 'Roboto Condensed', sans-serif;
|
||||||
@@ -306,43 +414,219 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.boss-info, .collect-info {
|
.boss-info {
|
||||||
width: 90%;
|
|
||||||
margin: 0 auto;
|
|
||||||
text-align: left;
|
text-align: left;
|
||||||
|
|
||||||
|
.boss-name {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
font-weight: bold;
|
||||||
|
line-height: 1.33;
|
||||||
|
color: $gray-100;
|
||||||
|
margin-bottom: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.boss-details {
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hp-value {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
line-height: 1.33;
|
||||||
|
color: $maroon-10;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rage-value {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
line-height: 1.33;
|
||||||
|
color: $orange-10;
|
||||||
|
display: flex;
|
||||||
|
height: 1rem;
|
||||||
|
|
||||||
|
.span {
|
||||||
|
align-self: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.pending-value {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
line-height: 1.33;
|
||||||
|
text-align: right;
|
||||||
|
color: $yellow-5;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.health-icon {
|
||||||
|
width: 1rem;
|
||||||
|
height: 1rem;
|
||||||
|
object-fit: contain;
|
||||||
|
margin-right: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rage-icon {
|
||||||
|
width: 1rem;
|
||||||
|
height: 1rem;
|
||||||
|
object-fit: contain;
|
||||||
|
margin-right: 0.25rem;
|
||||||
|
|
||||||
|
::v-deep svg {
|
||||||
|
height: 1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.sword-icon {
|
||||||
|
width: 1rem;
|
||||||
|
height: 1rem;
|
||||||
|
object-fit: contain;
|
||||||
|
margin-right: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
strong {
|
||||||
|
margin-left: 0.25rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.quest-invite {
|
.quest-invite {
|
||||||
background-color: #2995cd;
|
background-color: $blue-10;
|
||||||
color: #fff;
|
color: $white;
|
||||||
padding: 1em;
|
display: flex;
|
||||||
|
border-radius: 2px;
|
||||||
|
|
||||||
span {
|
.participate {
|
||||||
margin-top: .3em;
|
margin-top: 0.75rem;
|
||||||
font-size: 14px;
|
margin-bottom: 0.75rem;
|
||||||
font-weight: bold;
|
margin-left: 1rem;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.buttons {
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
margin-right: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.accept, .reject {
|
.accept, .reject {
|
||||||
padding: .2em 1em;
|
font-size: 0.75rem;
|
||||||
font-size: 12px;
|
font-weight: bold;
|
||||||
height: 24px;
|
|
||||||
|
line-height: 1.33;
|
||||||
|
text-align: center;
|
||||||
|
color: $white;
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
box-shadow: 0 2px 2px 0 rgba(26, 24, 29, 0.16), 0 1px 4px 0 rgba(26, 24, 29, 0.12);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.accept {
|
.accept {
|
||||||
background-color: #24cc8f;
|
margin: 0 0.5rem 0 0;
|
||||||
margin-left: 4em;
|
|
||||||
margin-right: .5em;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.reject {
|
.reject {
|
||||||
border-radius: 2px;
|
|
||||||
background-color: #f74e52;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.leave-quest-holder {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.leave-quest {
|
||||||
|
font-size: 0.875rem;
|
||||||
|
line-height: 1.71;
|
||||||
|
color: $maroon-50;
|
||||||
|
display: block;
|
||||||
|
margin-top: 1rem;
|
||||||
|
|
||||||
|
&:hover, &:focus {
|
||||||
|
color: $maroon-50;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.disabled {
|
||||||
|
color: $gray-200;
|
||||||
|
cursor: default;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.quest-item-row {
|
||||||
|
display: flex;
|
||||||
|
margin-bottom: 0.25rem;
|
||||||
|
|
||||||
|
.quest-item-icon {
|
||||||
|
margin-right: 0.813rem;
|
||||||
|
width: 3.5rem;
|
||||||
|
height: 3.5rem;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
align-self: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.quest-item-info {
|
||||||
|
flex: 1;
|
||||||
|
text-align: left;
|
||||||
|
|
||||||
|
.label {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
line-height: 1.33;
|
||||||
|
color: $gray-100;
|
||||||
|
|
||||||
|
&.quest-label {
|
||||||
|
font-weight: bold;
|
||||||
|
margin-bottom: 0.25rem;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-progress-row {
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
> * {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-progress:not(.no-items) {
|
||||||
|
color: $green-10;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-progress-label {
|
||||||
|
text-align: right;
|
||||||
|
color: $gray-100;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-progress-pending {
|
||||||
|
border-bottom-left-radius: 4px;
|
||||||
|
border-bottom-right-radius: 4px;
|
||||||
|
margin-left: -1rem;
|
||||||
|
margin-right: -1rem;
|
||||||
|
margin-bottom: -1rem !important;
|
||||||
|
|
||||||
|
background-color: $gray-200;
|
||||||
|
|
||||||
|
.pending-amount {
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: bold;
|
||||||
|
line-height: 1.33;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
color: $white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.not-participating {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rage-bar-row {
|
||||||
|
margin-top: 0.875rem;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@@ -353,16 +637,24 @@ import percent from '@/../../common/script/libs/percent';
|
|||||||
import sidebarSection from '../sidebarSection';
|
import sidebarSection from '../sidebarSection';
|
||||||
|
|
||||||
import questIcon from '@/assets/svg/quest.svg';
|
import questIcon from '@/assets/svg/quest.svg';
|
||||||
|
import swordIcon from '@/assets/svg/sword.svg';
|
||||||
|
import rageIcon from '@/assets/svg/rage.svg';
|
||||||
|
import healthNoPaddingIcon from '@/assets/svg/health_no_padding.svg';
|
||||||
|
import questActionsMixin from '@/components/groups/questActions.mixin';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
sidebarSection,
|
sidebarSection,
|
||||||
},
|
},
|
||||||
|
mixins: [questActionsMixin],
|
||||||
props: ['group'],
|
props: ['group'],
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
icons: Object.freeze({
|
icons: Object.freeze({
|
||||||
questIcon,
|
questIcon,
|
||||||
|
healthNoPaddingIcon,
|
||||||
|
swordIcon,
|
||||||
|
rageIcon,
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
@@ -372,24 +664,27 @@ export default {
|
|||||||
if (!this.group.quest || !this.group.quest.members) return false;
|
if (!this.group.quest || !this.group.quest.members) return false;
|
||||||
return Boolean(this.group.quest.members[this.user._id]);
|
return Boolean(this.group.quest.members[this.user._id]);
|
||||||
},
|
},
|
||||||
|
userIsQuestLeader () {
|
||||||
|
if (!this.group.quest) return false;
|
||||||
|
return this.group.quest.leader === this.user._id;
|
||||||
|
},
|
||||||
onPendingQuest () {
|
onPendingQuest () {
|
||||||
return Boolean(this.group.quest.key) && !this.group.quest.active;
|
return Boolean(this.group.quest.key) && !this.group.quest.active;
|
||||||
},
|
},
|
||||||
onActiveQuest () {
|
|
||||||
return this.group.quest.active;
|
|
||||||
},
|
|
||||||
bossHpPercent () {
|
bossHpPercent () {
|
||||||
return percent(this.group.quest.progress.hp, this.questData.boss.hp);
|
return percent(this.group.quest.progress.hp, this.questData.boss.hp);
|
||||||
},
|
},
|
||||||
|
pendingHpPercent () {
|
||||||
|
return percent(this.user.party.quest.progress.up, this.questData.boss.hp);
|
||||||
|
},
|
||||||
questData () {
|
questData () {
|
||||||
if (!this.group.quest) return {};
|
if (!this.group.quest) return {};
|
||||||
return quests.quests[this.group.quest.key];
|
return quests.quests[this.group.quest.key];
|
||||||
},
|
},
|
||||||
canEditQuest () {
|
canEditQuest () {
|
||||||
if (!this.group.quest) return false;
|
if (!this.group.quest) return false;
|
||||||
const isQuestLeader = this.group.quest.leader === this.user._id;
|
|
||||||
const isPartyLeader = this.group.leader._id === this.user._id;
|
const isPartyLeader = this.group.leader._id === this.user._id;
|
||||||
return isQuestLeader || isPartyLeader;
|
return this.userIsQuestLeader || isPartyLeader;
|
||||||
},
|
},
|
||||||
isMemberOfPendingQuest () {
|
isMemberOfPendingQuest () {
|
||||||
const userid = this.user._id;
|
const userid = this.user._id;
|
||||||
@@ -416,25 +711,32 @@ export default {
|
|||||||
|
|
||||||
return count;
|
return count;
|
||||||
},
|
},
|
||||||
|
hasPendingQuestItems () {
|
||||||
|
return Boolean(this.user.party.quest?.progress?.collectedItems);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
openStartQuestModal () {
|
openSelectQuestModal () {
|
||||||
this.$root.$emit('bv::show::modal', 'start-quest-modal');
|
this.$root.$emit('bv::show::modal', 'quest-detail-modal');
|
||||||
},
|
},
|
||||||
openQuestDetails () {
|
openQuestDetails () {
|
||||||
this.$root.$emit('bv::show::modal', 'quest-details');
|
this.$root.$emit('bv::show::modal', 'quest-detail-modal', {
|
||||||
|
key: this.group.quest.key,
|
||||||
|
from: 'sidebar',
|
||||||
|
});
|
||||||
},
|
},
|
||||||
openParticipantList () {
|
openParticipantList () {
|
||||||
|
if (this.onPendingQuest) {
|
||||||
|
this.$root.$emit('bv::show::modal', 'invitation-list');
|
||||||
|
} else {
|
||||||
this.$root.$emit('bv::show::modal', 'participant-list');
|
this.$root.$emit('bv::show::modal', 'participant-list');
|
||||||
},
|
}
|
||||||
async questAbort () {
|
|
||||||
if (!window.confirm(this.$t('sureAbort'))) return; // eslint-disable-line no-alert
|
|
||||||
if (!window.confirm(this.$t('doubleSureAbort'))) return; // eslint-disable-line no-alert
|
|
||||||
const quest = await this.$store.dispatch('quests:sendAction', { groupId: this.group._id, action: 'quests/abort' });
|
|
||||||
this.group.quest = quest;
|
|
||||||
},
|
},
|
||||||
async questLeave () {
|
async questLeave () {
|
||||||
if (!window.confirm(this.$t('sureLeave'))) return; // eslint-disable-line no-alert
|
if (!window.confirm(this.$t(this.group.quest.active ? 'sureLeave' : 'sureLeaveInactive'))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const quest = await this.$store.dispatch('quests:sendAction', { groupId: this.group._id, action: 'quests/leave' });
|
const quest = await this.$store.dispatch('quests:sendAction', { groupId: this.group._id, action: 'quests/leave' });
|
||||||
this.group.quest = quest;
|
this.group.quest = quest;
|
||||||
},
|
},
|
||||||
@@ -447,6 +749,9 @@ export default {
|
|||||||
const quest = await this.$store.dispatch('quests:sendAction', { groupId: partyId, action: 'quests/reject' });
|
const quest = await this.$store.dispatch('quests:sendAction', { groupId: partyId, action: 'quests/reject' });
|
||||||
this.user.party.quest = quest;
|
this.user.party.quest = quest;
|
||||||
},
|
},
|
||||||
|
startQuest () {
|
||||||
|
this.questActionsConfirmQuest();
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
240
website/client/src/components/groups/rightSidebar.vue
Normal file
@@ -0,0 +1,240 @@
|
|||||||
|
<template>
|
||||||
|
<div class="sidebar px-4">
|
||||||
|
<div>
|
||||||
|
<div class="buttons-wrapper">
|
||||||
|
<div class="button-container button-with-menu-row">
|
||||||
|
<button
|
||||||
|
v-if="!isMember"
|
||||||
|
class="btn btn-success btn-success"
|
||||||
|
@click="$emit('join')"
|
||||||
|
>
|
||||||
|
<span v-once>{{ $t(isParty ? 'joinParty' : 'joinGuild') }}</span>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
v-if="isMember"
|
||||||
|
class="btn btn-primary inline"
|
||||||
|
@click="$emit('showInviteModal')"
|
||||||
|
>
|
||||||
|
<span v-once>{{ $t(isParty ? 'inviteToParty' : 'inviteToGuild') }}</span>
|
||||||
|
</button>
|
||||||
|
<b-dropdown
|
||||||
|
right="right"
|
||||||
|
toggle-class="with-icon"
|
||||||
|
class="ml-2"
|
||||||
|
:no-caret="true"
|
||||||
|
>
|
||||||
|
<template v-slot:button-content>
|
||||||
|
<span
|
||||||
|
class="svg-icon inline menuIcon"
|
||||||
|
v-html="icons.menuIcon"
|
||||||
|
v-once
|
||||||
|
>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
<b-dropdown-item
|
||||||
|
v-if="isLeader && !group.purchased.active && group.privacy === 'private'"
|
||||||
|
class="selectListItem custom-hover--upgrade"
|
||||||
|
@click="$emit('upgradeGroup')"
|
||||||
|
>
|
||||||
|
<span class="with-icon">
|
||||||
|
<span
|
||||||
|
class="svg-icon icon-16 color"
|
||||||
|
v-html="icons.sparklesIcon"
|
||||||
|
v-once
|
||||||
|
></span>
|
||||||
|
<span v-once>
|
||||||
|
{{ $t('upgradeToGroup') }}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</b-dropdown-item>
|
||||||
|
<b-dropdown-item
|
||||||
|
v-if="!isMember"
|
||||||
|
class="selectListItem"
|
||||||
|
@click="$emit('showInviteModal')"
|
||||||
|
>
|
||||||
|
<span class="with-icon">
|
||||||
|
<span
|
||||||
|
class="svg-icon icon-16 color"
|
||||||
|
v-html="icons.usersIcon"
|
||||||
|
v-once
|
||||||
|
></span>
|
||||||
|
<span v-once>
|
||||||
|
{{ $t(isParty ? 'inviteToParty' : 'inviteToGuild') }}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</b-dropdown-item>
|
||||||
|
<b-dropdown-item
|
||||||
|
class="selectListItem"
|
||||||
|
@click="$emit('messageLeader')"
|
||||||
|
>
|
||||||
|
<span class="with-icon">
|
||||||
|
<span
|
||||||
|
class="svg-icon icon-16 color"
|
||||||
|
v-html="icons.messageIcon"
|
||||||
|
v-once
|
||||||
|
></span>
|
||||||
|
<span v-once>
|
||||||
|
{{ $t(isParty ? 'messagePartyLeader' : 'messageGuildLeader') }}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</b-dropdown-item>
|
||||||
|
<b-dropdown-item
|
||||||
|
v-if="isLeader || isAdmin"
|
||||||
|
class="selectListItem"
|
||||||
|
@click="$emit('updateGuild')"
|
||||||
|
>
|
||||||
|
<span class="with-icon">
|
||||||
|
<span
|
||||||
|
class="svg-icon icon-16 color"
|
||||||
|
v-html="icons.editIcon"
|
||||||
|
v-once
|
||||||
|
></span>
|
||||||
|
<span v-once>
|
||||||
|
{{ isParty ? $t('editParty') : $t('editGuild') }}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</b-dropdown-item>
|
||||||
|
<b-dropdown-item
|
||||||
|
v-if="isMember"
|
||||||
|
class="selectListItem custom-hover--leave"
|
||||||
|
@click="$emit('leave')"
|
||||||
|
>
|
||||||
|
<span class="with-icon">
|
||||||
|
<span
|
||||||
|
class="svg-icon icon-16 color"
|
||||||
|
v-html="icons.leaveIcon"
|
||||||
|
v-once
|
||||||
|
></span>
|
||||||
|
<span v-once>
|
||||||
|
{{ isParty ? $t('leaveParty') : $t('leaveGuild') }}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</b-dropdown-item>
|
||||||
|
</b-dropdown>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<quest-sidebar-section
|
||||||
|
v-if="isParty"
|
||||||
|
:group="group"
|
||||||
|
/>
|
||||||
|
<sidebar-section
|
||||||
|
v-if="!isParty"
|
||||||
|
:title="$t('guildSummary')"
|
||||||
|
>
|
||||||
|
<p v-markdown="group.summary"></p>
|
||||||
|
</sidebar-section>
|
||||||
|
<sidebar-section :title="$t('groupDescription')">
|
||||||
|
<p v-markdown="group.description"></p>
|
||||||
|
</sidebar-section>
|
||||||
|
<sidebar-section
|
||||||
|
:title="$t('challenges')"
|
||||||
|
>
|
||||||
|
<group-challenges :group="group" />
|
||||||
|
</sidebar-section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import groupChallenges from '@/components/challenges/groupChallenges';
|
||||||
|
import questSidebarSection from '@/components/groups/questSidebarSection';
|
||||||
|
import sidebarSection from '@/components/sidebarSection';
|
||||||
|
import markdownDirective from '@/directives/markdown';
|
||||||
|
|
||||||
|
import menuIcon from '@/assets/svg/menu.svg';
|
||||||
|
import sparklesIcon from '@/assets/svg/sparklesIcon.svg';
|
||||||
|
import leaveIcon from '@/assets/svg/leave.svg';
|
||||||
|
import editIcon from '@/assets/svg/edit.svg';
|
||||||
|
import messageIcon from '@/assets/svg/message.svg';
|
||||||
|
import usersIcon from '@/assets/svg/users.svg';
|
||||||
|
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
groupChallenges,
|
||||||
|
questSidebarSection,
|
||||||
|
sidebarSection,
|
||||||
|
},
|
||||||
|
directives: {
|
||||||
|
markdown: markdownDirective,
|
||||||
|
},
|
||||||
|
props: ['isParty', 'isLeader', 'isAdmin', 'isMember', 'searchId', 'group'],
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
icons: Object.freeze({
|
||||||
|
menuIcon,
|
||||||
|
sparklesIcon,
|
||||||
|
leaveIcon,
|
||||||
|
editIcon,
|
||||||
|
messageIcon,
|
||||||
|
usersIcon,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
isGroup () {
|
||||||
|
return Boolean(this.group.purchased?.plan?.customerId);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import '~@/assets/scss/colors.scss';
|
||||||
|
|
||||||
|
@media (min-width: 1300px) {
|
||||||
|
.sidebar {
|
||||||
|
max-width: 430px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar {
|
||||||
|
background-color: $gray-600;
|
||||||
|
padding-bottom: 2em;
|
||||||
|
padding-top: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-container {
|
||||||
|
margin-bottom: 1.5em;
|
||||||
|
|
||||||
|
button {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-with-menu-row {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menuIcon {
|
||||||
|
width: 4px;
|
||||||
|
height: 1rem;
|
||||||
|
object-fit: contain;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-link {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.divider {
|
||||||
|
width: calc(100% + 3rem);
|
||||||
|
height: 0.063rem;
|
||||||
|
margin-top: 1.5rem;
|
||||||
|
margin-right: -1.5rem;
|
||||||
|
margin-left: -1.5rem;
|
||||||
|
margin-bottom: 0.688rem;
|
||||||
|
background-color: $gray-500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-hover--leave {
|
||||||
|
--hover-color: #{$maroon-50};
|
||||||
|
--hover-background: #ffb6b83F;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-hover--upgrade {
|
||||||
|
--hover-color: #{$green-10};
|
||||||
|
--hover-background: #77f4c73F;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,242 +0,0 @@
|
|||||||
<template>
|
|
||||||
<b-modal
|
|
||||||
id="start-quest-modal"
|
|
||||||
title="Empty"
|
|
||||||
size="md"
|
|
||||||
:hide-footer="true"
|
|
||||||
:hide-header="true"
|
|
||||||
>
|
|
||||||
<div class="left-panel content">
|
|
||||||
<h3 class="text-center">
|
|
||||||
Quests
|
|
||||||
</h3>
|
|
||||||
<div class="row">
|
|
||||||
<!-- eslint-disable vue/no-use-v-if-with-v-for -->
|
|
||||||
<div
|
|
||||||
v-for="(value, key) in user.items.quests"
|
|
||||||
v-if="value > 0"
|
|
||||||
:key="key"
|
|
||||||
class="col-4 quest-col"
|
|
||||||
:class="{selected: key === selectedQuest}"
|
|
||||||
@click="selectQuest({key})"
|
|
||||||
>
|
|
||||||
<!-- eslint-enable vue/no-use-v-if-with-v-for -->
|
|
||||||
<div class="quest-wrapper">
|
|
||||||
<b-popover
|
|
||||||
:target="`inventory_quest_scroll_${key}`"
|
|
||||||
placement="top"
|
|
||||||
triggers="hover"
|
|
||||||
>
|
|
||||||
<h4 class="popover-content-title">
|
|
||||||
{{ quests.quests[key].text() }}
|
|
||||||
</h4>
|
|
||||||
<questInfo :quest="quests.quests[key]" />
|
|
||||||
</b-popover>
|
|
||||||
<div
|
|
||||||
:id="`inventory_quest_scroll_${key}`"
|
|
||||||
class="quest"
|
|
||||||
:class="`inventory_quest_scroll_${key}`"
|
|
||||||
></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-10 offset-1 text-center">
|
|
||||||
<span
|
|
||||||
v-once
|
|
||||||
class="description"
|
|
||||||
>{{ $t('noQuestToStart') }}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div v-if="questData">
|
|
||||||
<questDialogContent :item="questData" />
|
|
||||||
</div>
|
|
||||||
<div class="text-center">
|
|
||||||
<button
|
|
||||||
class="btn btn-primary"
|
|
||||||
:disabled="!Boolean(selectedQuest) || loading"
|
|
||||||
@click="questInit()"
|
|
||||||
>
|
|
||||||
{{ $t('inviteToPartyOrQuest') }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="text-center">
|
|
||||||
<p>{{ $t('inviteInformation') }}</p>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
v-if="questData"
|
|
||||||
class="side-panel"
|
|
||||||
>
|
|
||||||
<questDialogDrops :item="questData" />
|
|
||||||
</div>
|
|
||||||
</b-modal>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style lang='scss' scoped>
|
|
||||||
@import '~@/assets/scss/colors.scss';
|
|
||||||
|
|
||||||
header {
|
|
||||||
background-color: $white !important;
|
|
||||||
border: none !important;
|
|
||||||
|
|
||||||
h5 {
|
|
||||||
text-indent: -99999px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.quest-details {
|
|
||||||
margin: 0 auto;
|
|
||||||
text-align: left;
|
|
||||||
width: 180px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-primary {
|
|
||||||
margin: 1em 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.left-panel {
|
|
||||||
background: #4e4a57;
|
|
||||||
color: $white;
|
|
||||||
position: absolute;
|
|
||||||
height: 460px;
|
|
||||||
width: 320px;
|
|
||||||
top: 2.5em;
|
|
||||||
left: -23em;
|
|
||||||
z-index: -1;
|
|
||||||
padding: 2em;
|
|
||||||
overflow-y: auto;
|
|
||||||
|
|
||||||
h3 {
|
|
||||||
color: $white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.selected .quest-wrapper {
|
|
||||||
border: solid 1.5px #9a62ff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.quest-wrapper:hover {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.quest-col .quest-wrapper {
|
|
||||||
background: $white;
|
|
||||||
padding: .2em;
|
|
||||||
margin-bottom: 1em;
|
|
||||||
border-radius: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.description {
|
|
||||||
text-align: center;
|
|
||||||
color: #a5a1ac;
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.side-panel {
|
|
||||||
position: absolute;
|
|
||||||
right: -350px;
|
|
||||||
top: 25px;
|
|
||||||
border-radius: 8px;
|
|
||||||
background-color: $gray-600;
|
|
||||||
box-shadow: 0 2px 16px 0 rgba(26, 24, 29, 0.32);
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
flex-direction: column;
|
|
||||||
width: 364px;
|
|
||||||
z-index: -1;
|
|
||||||
height: 93%;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import { mapState } from '@/libs/store';
|
|
||||||
import * as Analytics from '@/libs/analytics';
|
|
||||||
|
|
||||||
import * as quests from '@/../../common/script/content/quests';
|
|
||||||
|
|
||||||
import copyIcon from '@/assets/svg/copy.svg';
|
|
||||||
import greyBadgeIcon from '@/assets/svg/grey-badge.svg';
|
|
||||||
import qrCodeIcon from '@/assets/svg/qrCode.svg';
|
|
||||||
import facebookIcon from '@/assets/svg/facebook.svg';
|
|
||||||
import twitterIcon from '@/assets/svg/twitter.svg';
|
|
||||||
import starIcon from '@/assets/svg/star.svg';
|
|
||||||
import goldIcon from '@/assets/svg/gold.svg';
|
|
||||||
import difficultyStarIcon from '@/assets/svg/difficulty-star.svg';
|
|
||||||
import questDialogDrops from '../shops/quests/questDialogDrops';
|
|
||||||
import questDialogContent from '../shops/quests/questDialogContent';
|
|
||||||
import QuestInfo from '../shops/quests/questInfo';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
components: {
|
|
||||||
questDialogDrops,
|
|
||||||
questDialogContent,
|
|
||||||
QuestInfo,
|
|
||||||
},
|
|
||||||
props: ['group'],
|
|
||||||
data () {
|
|
||||||
return {
|
|
||||||
loading: false,
|
|
||||||
selectedQuest: {},
|
|
||||||
icons: Object.freeze({
|
|
||||||
copy: copyIcon,
|
|
||||||
greyBadge: greyBadgeIcon,
|
|
||||||
qrCode: qrCodeIcon,
|
|
||||||
facebook: facebookIcon,
|
|
||||||
twitter: twitterIcon,
|
|
||||||
starIcon,
|
|
||||||
goldIcon,
|
|
||||||
difficultyStarIcon,
|
|
||||||
}),
|
|
||||||
shareUserIdShown: false,
|
|
||||||
quests,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
...mapState({ user: 'user.data' }),
|
|
||||||
questData () {
|
|
||||||
return quests.quests[this.selectedQuest];
|
|
||||||
},
|
|
||||||
},
|
|
||||||
mounted () {
|
|
||||||
const userQuests = this.user.items.quests;
|
|
||||||
for (const key in userQuests) {
|
|
||||||
if (userQuests[key] > 0) {
|
|
||||||
this.selectedQuest = key;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.$root.$on('selectQuest', this.selectQuest);
|
|
||||||
},
|
|
||||||
beforeDestroy () {
|
|
||||||
this.$root.$off('selectQuest', this.selectQuest);
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
selectQuest (quest) {
|
|
||||||
this.selectedQuest = quest.key;
|
|
||||||
},
|
|
||||||
async questInit () {
|
|
||||||
this.loading = true;
|
|
||||||
|
|
||||||
Analytics.updateUser({
|
|
||||||
partyID: this.group._id,
|
|
||||||
partySize: this.group.memberCount,
|
|
||||||
});
|
|
||||||
|
|
||||||
const groupId = this.group._id || this.user.party._id;
|
|
||||||
|
|
||||||
const key = this.selectedQuest;
|
|
||||||
try {
|
|
||||||
const response = await this.$store.dispatch('guilds:inviteToQuest', { groupId, key });
|
|
||||||
const quest = response.data.data;
|
|
||||||
|
|
||||||
if (this.$store.state.party.data) this.$store.state.party.data.quest = quest;
|
|
||||||
} finally {
|
|
||||||
this.loading = false;
|
|
||||||
}
|
|
||||||
this.$root.$emit('bv::hide::modal', 'start-quest-modal');
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
@@ -192,6 +192,8 @@ import svgUnEquipIcon from '@/assets/svg/unequip.svg';
|
|||||||
import Avatar from '@/components/avatar';
|
import Avatar from '@/components/avatar';
|
||||||
import attributesGrid from '@/components/inventory/equipment/attributesGrid.vue';
|
import attributesGrid from '@/components/inventory/equipment/attributesGrid.vue';
|
||||||
import closeIcon from '@/components/shared/closeIcon';
|
import closeIcon from '@/components/shared/closeIcon';
|
||||||
|
// TODO @common/ path alias
|
||||||
|
import { getClassName } from '../../../../../common/script/libs/getClassName';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
@@ -274,10 +276,7 @@ export default {
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
getClassName (classType) {
|
getClassName (classType) {
|
||||||
if (classType === 'wizard') {
|
return this.$t(getClassName(classType));
|
||||||
return this.$t('mage');
|
|
||||||
}
|
|
||||||
return this.$t(classType);
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -293,7 +293,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<startQuestModal :group="user.party" />
|
<questDetailModal :group="user.party" />
|
||||||
<cards-modal :card-options="cardOptions" />
|
<cards-modal :card-options="cardOptions" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -343,7 +343,7 @@ import FilterSidebar from '@/components/ui/filterSidebar';
|
|||||||
import cardsModal from './cards-modal';
|
import cardsModal from './cards-modal';
|
||||||
|
|
||||||
import HatchedPetDialog from '../stable/hatchedPetDialog';
|
import HatchedPetDialog from '../stable/hatchedPetDialog';
|
||||||
import startQuestModal from '../../groups/startQuestModal';
|
import questDetailModal from '../../groups/questDetailModal';
|
||||||
import QuestInfo from '../../shops/quests/questInfo.vue';
|
import QuestInfo from '../../shops/quests/questInfo.vue';
|
||||||
|
|
||||||
import { mapState } from '@/libs/store';
|
import { mapState } from '@/libs/store';
|
||||||
@@ -384,7 +384,7 @@ export default {
|
|||||||
ItemRows,
|
ItemRows,
|
||||||
HatchedPetDialog,
|
HatchedPetDialog,
|
||||||
CountBadge,
|
CountBadge,
|
||||||
startQuestModal,
|
questDetailModal,
|
||||||
cardsModal,
|
cardsModal,
|
||||||
QuestInfo,
|
QuestInfo,
|
||||||
FilterSidebar,
|
FilterSidebar,
|
||||||
@@ -632,9 +632,9 @@ export default {
|
|||||||
this.$root.$emit('selectMembersModal::showItem', item);
|
this.$root.$emit('selectMembersModal::showItem', item);
|
||||||
}
|
}
|
||||||
} else if (groupKey === 'quests') {
|
} else if (groupKey === 'quests') {
|
||||||
this.$root.$emit('bv::show::modal', 'start-quest-modal');
|
this.$root.$emit('bv::show::modal', 'quest-detail-modal', {
|
||||||
|
key: item.key,
|
||||||
this.$root.$emit('selectQuest', item);
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
34
website/client/src/components/memberDetails.stories.js
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
/* eslint-disable import/no-extraneous-dependencies */
|
||||||
|
import { storiesOf } from '@storybook/vue';
|
||||||
|
|
||||||
|
import MemberDetails from './memberDetails.vue';
|
||||||
|
import MemberDetailsNew from './memberDetailsNew.vue';
|
||||||
|
import { userStyles } from '../../config/storybook/mock.data';
|
||||||
|
|
||||||
|
storiesOf('Member Details', module)
|
||||||
|
.add('party header (old)', () => ({
|
||||||
|
components: { MemberDetails },
|
||||||
|
template: `
|
||||||
|
<div style="position: absolute; margin: 20px">
|
||||||
|
<member-details :member="user"></member-details>
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
user: userStyles,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
.add('quest participants (new)', () => ({
|
||||||
|
components: { MemberDetailsNew },
|
||||||
|
template: `
|
||||||
|
<div style="position: absolute; margin: 20px">
|
||||||
|
<member-details-new :member="user"></member-details-new>
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
user: userStyles,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
}));
|
||||||
330
website/client/src/components/memberDetailsNew.vue
Normal file
@@ -0,0 +1,330 @@
|
|||||||
|
<template>
|
||||||
|
<div
|
||||||
|
class="member-details-new"
|
||||||
|
:class="{ condensed, expanded }"
|
||||||
|
@click="showMemberModal(member)"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<avatar
|
||||||
|
:member="member"
|
||||||
|
:hide-class-badge="true"
|
||||||
|
@click.native="$emit('click')"
|
||||||
|
@mouseover.native="$emit('onHover')"
|
||||||
|
@mouseout.native="$emit('onHover')"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="member-stats"
|
||||||
|
>
|
||||||
|
<div class="d-flex align-items-center profile-first-row">
|
||||||
|
<class-badge
|
||||||
|
v-if="classBadgePosition === 'next-to-name'"
|
||||||
|
:member-class="member.stats.class"
|
||||||
|
/>
|
||||||
|
<div class="d-flex flex-column profile-name-character">
|
||||||
|
<h3 class="character-name mt-75">
|
||||||
|
<user-link
|
||||||
|
:user-id="member._id"
|
||||||
|
:name="member.profile.name"
|
||||||
|
:backer="member.backer"
|
||||||
|
:contributor="member.contributor"
|
||||||
|
:smallerStyle="true"
|
||||||
|
/>
|
||||||
|
<inline-class-badge
|
||||||
|
class="inline-class-badge"
|
||||||
|
v-if="member.stats"
|
||||||
|
:member-class="member.stats.class"
|
||||||
|
/>
|
||||||
|
</h3>
|
||||||
|
<div class="small-text character-level">
|
||||||
|
<span
|
||||||
|
v-if="member.auth && member.auth.local && member.auth.local.username"
|
||||||
|
class="mr-1"
|
||||||
|
>@{{ member.auth.local.username }}</span>
|
||||||
|
<span
|
||||||
|
v-if="member.auth && member.auth.local && member.auth.local.username"
|
||||||
|
class="mr-1"
|
||||||
|
>•</span>
|
||||||
|
<span>{{ characterLevel }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<stats-bar
|
||||||
|
class="mt-3 stats-bar"
|
||||||
|
:icon="icons.health"
|
||||||
|
:value="member.stats.hp"
|
||||||
|
:max-value="MAX_HEALTH"
|
||||||
|
:tooltip="$t('health')"
|
||||||
|
progress-class="bg-health-new"
|
||||||
|
:condensed="condensed"
|
||||||
|
:show-icon="false"
|
||||||
|
:show-numbers="false"
|
||||||
|
/>
|
||||||
|
<stats-bar
|
||||||
|
class="mt-75 stats-bar"
|
||||||
|
:icon="icons.experience"
|
||||||
|
:value="member.stats.exp"
|
||||||
|
:max-value="toNextLevel"
|
||||||
|
:tooltip="$t('experience')"
|
||||||
|
progress-class="bg-experience-new"
|
||||||
|
:condensed="condensed"
|
||||||
|
:show-icon="false"
|
||||||
|
:show-numbers="false"
|
||||||
|
/>
|
||||||
|
<stats-bar
|
||||||
|
class="mt-75 stats-bar"
|
||||||
|
v-if="hasClass"
|
||||||
|
:icon="icons.mana"
|
||||||
|
:value="member.stats.mp"
|
||||||
|
:max-value="maxMP"
|
||||||
|
:tooltip="$t('mana')"
|
||||||
|
progress-class="bg-mana-new"
|
||||||
|
:condensed="condensed"
|
||||||
|
:show-icon="false"
|
||||||
|
:show-numbers="false"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import '~@/assets/scss/colors.scss';
|
||||||
|
|
||||||
|
.stats-bar {
|
||||||
|
margin-left: 0;
|
||||||
|
height: 12px;
|
||||||
|
border-radius: 2px;
|
||||||
|
|
||||||
|
::v-deep {
|
||||||
|
.bg-health-new {
|
||||||
|
background: $red-50;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bg-experience-new {
|
||||||
|
background: $yellow-100;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bg-mana-new {
|
||||||
|
background: $blue-100;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-bar {
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress {
|
||||||
|
width: 100%;
|
||||||
|
--progress-background: #{$gray-500};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.inline-class-badge {
|
||||||
|
margin-left: 10px;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.member-details-new {
|
||||||
|
white-space: nowrap;
|
||||||
|
transition: all 0.15s ease-out;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
|
||||||
|
.member-stats {
|
||||||
|
flex: 1;
|
||||||
|
padding-left: 1rem;
|
||||||
|
padding-right: 24px;
|
||||||
|
opacity: 1;
|
||||||
|
transition: width 0.15s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.member-details-new.condensed:not(.expanded) .member-stats {
|
||||||
|
opacity: 0;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.small-text {
|
||||||
|
color: $header-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-name-character {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.character-name {
|
||||||
|
margin-bottom: 1px;
|
||||||
|
color: $white;
|
||||||
|
height: 24px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
::v-deep {
|
||||||
|
.user-link {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.character-level {
|
||||||
|
font-style: normal;
|
||||||
|
color: $gray-100;
|
||||||
|
}
|
||||||
|
|
||||||
|
.is-buffed {
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
background: $header-dark-background;
|
||||||
|
display: inline-block;
|
||||||
|
margin-left: 16px;
|
||||||
|
vertical-align: middle;
|
||||||
|
padding-top: 4px;
|
||||||
|
|
||||||
|
.svg-icon {
|
||||||
|
display: block;
|
||||||
|
width: 10px;
|
||||||
|
height: 12px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-first-row {
|
||||||
|
margin-bottom: .5em
|
||||||
|
}
|
||||||
|
|
||||||
|
// Condensed version
|
||||||
|
.member-details-new.condensed.expanded {
|
||||||
|
background: $header-dark-background;
|
||||||
|
box-shadow: 0 0 0px 8px $header-dark-background;
|
||||||
|
position: relative;
|
||||||
|
z-index: 8;
|
||||||
|
|
||||||
|
.is-buffed {
|
||||||
|
background-color: $purple-50;
|
||||||
|
}
|
||||||
|
|
||||||
|
.member-stats {
|
||||||
|
background: $header-dark-background;
|
||||||
|
position: absolute;
|
||||||
|
right: 100%;
|
||||||
|
height: calc(100% + 18px);
|
||||||
|
margin-top: -10px;
|
||||||
|
margin-right: 1px;
|
||||||
|
padding-top: 9px;
|
||||||
|
padding-bottom: 24px;
|
||||||
|
padding-right: 16px;
|
||||||
|
padding-bottom: 14px;
|
||||||
|
border-top-left-radius: 4px;
|
||||||
|
border-bottom-left-radius: 4px;
|
||||||
|
z-index: 9;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Avatar from './avatar';
|
||||||
|
import ClassBadge from './members/classBadge';
|
||||||
|
import { mapState } from '@/libs/store';
|
||||||
|
import StatsBar from './ui/statsbar';
|
||||||
|
import userLink from './userLink';
|
||||||
|
|
||||||
|
import { toNextLevel } from '@/../../common/script/statHelpers';
|
||||||
|
import statsComputed from '@/../../common/script/libs/statsComputed';
|
||||||
|
import percent from '@/../../common/script/libs/percent';
|
||||||
|
|
||||||
|
import buffIcon from '@/assets/svg/buff.svg';
|
||||||
|
import healthIcon from '@/assets/svg/health.svg';
|
||||||
|
import experienceIcon from '@/assets/svg/experience.svg';
|
||||||
|
import manaIcon from '@/assets/svg/mana.svg';
|
||||||
|
import InlineClassBadge from './members/inlineClassBadge';
|
||||||
|
import { getClassName } from '../../../common/script/libs/getClassName';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
InlineClassBadge,
|
||||||
|
Avatar,
|
||||||
|
ClassBadge,
|
||||||
|
StatsBar,
|
||||||
|
userLink,
|
||||||
|
},
|
||||||
|
filters: {
|
||||||
|
statFloor (value) {
|
||||||
|
if (value < 1 && value > 0) {
|
||||||
|
return Math.ceil(value * 10) / 10;
|
||||||
|
}
|
||||||
|
return Math.floor(value);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
member: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
condensed: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
expanded: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
classBadgePosition: {
|
||||||
|
type: String,
|
||||||
|
default: 'under-avatar', // next-to-name or hidden
|
||||||
|
},
|
||||||
|
isHeader: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
disableNameStyling: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
icons: Object.freeze({
|
||||||
|
buff: buffIcon,
|
||||||
|
health: healthIcon,
|
||||||
|
experience: experienceIcon,
|
||||||
|
mana: manaIcon,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapState({
|
||||||
|
MAX_HEALTH: 'constants.MAX_HEALTH',
|
||||||
|
}),
|
||||||
|
maxMP () {
|
||||||
|
return statsComputed(this.member).maxMP;
|
||||||
|
},
|
||||||
|
toNextLevel () { // Exp to next level
|
||||||
|
return toNextLevel(this.member.stats.lvl);
|
||||||
|
},
|
||||||
|
characterLevel () {
|
||||||
|
return `${this.$t('level')} ${this.member.stats.lvl} ${
|
||||||
|
this.member.stats.class ? this.getClassName(this.member.stats.class) : ''
|
||||||
|
}`;
|
||||||
|
},
|
||||||
|
isBuffed () {
|
||||||
|
return this.$store.getters['members:isBuffed'](this.member);
|
||||||
|
},
|
||||||
|
hasClass () {
|
||||||
|
return this.$store.getters['members:hasClass'](this.member);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
percent,
|
||||||
|
showMemberModal (member) {
|
||||||
|
this.$router.push({ name: 'userProfile', params: { userId: member._id } });
|
||||||
|
},
|
||||||
|
getClassName (classType) {
|
||||||
|
return this.$t(getClassName(classType));
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="class-badge d-flex justify-content-center">
|
<div class="class-badge d-flex justify-content-center"
|
||||||
|
:style="{'--badge-size': badgeSize}">
|
||||||
<div
|
<div
|
||||||
class="align-self-center svg-icon"
|
class="align-self-center svg-icon"
|
||||||
:aria-label="$t(memberClass)"
|
:aria-label="$t(memberClass)"
|
||||||
@@ -12,10 +13,10 @@
|
|||||||
@import '~@/assets/scss/colors.scss';
|
@import '~@/assets/scss/colors.scss';
|
||||||
|
|
||||||
.class-badge {
|
.class-badge {
|
||||||
$badge-size: 32px;
|
--badge-size: 32px;
|
||||||
|
|
||||||
width: $badge-size;
|
width: var(--badge-size);
|
||||||
height: $badge-size;
|
height: var(--badge-size);
|
||||||
background: $white;
|
background: $white;
|
||||||
box-shadow: 0 2px 2px 0 rgba($black, 0.16), 0 1px 4px 0 rgba($black, 0.12);
|
box-shadow: 0 2px 2px 0 rgba($black, 0.16), 0 1px 4px 0 rgba($black, 0.12);
|
||||||
border-radius: 100px;
|
border-radius: 100px;
|
||||||
@@ -23,13 +24,13 @@
|
|||||||
&.under-avatar {
|
&.under-avatar {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: calc(50% - (16px));
|
left: calc(50% - (16px));
|
||||||
bottom: -($badge-size / 2);
|
bottom: -(var(--badge-size) / 2);
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.svg-icon {
|
.svg-icon {
|
||||||
width: 19px;
|
width: 20px;
|
||||||
height: 19px;
|
height: 20px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
@@ -46,6 +47,10 @@ export default {
|
|||||||
type: String,
|
type: String,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
|
badgeSize: {
|
||||||
|
type: Number,
|
||||||
|
default: 32,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
|
|||||||
44
website/client/src/components/members/inlineClassBadge.vue
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
<template>
|
||||||
|
<span
|
||||||
|
class="svg-icon"
|
||||||
|
:aria-label="$t(memberClass)"
|
||||||
|
v-html="icons[memberClass]"
|
||||||
|
></span>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import '~@/assets/scss/colors.scss';
|
||||||
|
|
||||||
|
.svg-icon {
|
||||||
|
--badge-size: 16px;
|
||||||
|
width: var(--badge-size);
|
||||||
|
height: var(--badge-size);
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import warriorIcon from '@/assets/svg/warrior.svg';
|
||||||
|
import rogueIcon from '@/assets/svg/rogue.svg';
|
||||||
|
import healerIcon from '@/assets/svg/healer.svg';
|
||||||
|
import wizardIcon from '@/assets/svg/wizard.svg';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
memberClass: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
icons: Object.freeze({
|
||||||
|
warrior: warriorIcon,
|
||||||
|
rogue: rogueIcon,
|
||||||
|
healer: healerIcon,
|
||||||
|
wizard: wizardIcon,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
@@ -269,12 +269,12 @@ export default {
|
|||||||
result = null;
|
result = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!result || !result.data || !result.data.data) {
|
if (!result) {
|
||||||
this.userNotFound = true;
|
this.userNotFound = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.userNotFound = false;
|
this.userNotFound = false;
|
||||||
this.foundUser = result.data.data;
|
this.foundUser = result;
|
||||||
}, 500),
|
}, 500),
|
||||||
selectUser () {
|
selectUser () {
|
||||||
this.$root.$emit('habitica::send-gems', this.foundUser);
|
this.$root.$emit('habitica::send-gems', this.foundUser);
|
||||||
|
|||||||
@@ -1,40 +1,49 @@
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
class="toggle ml-auto"
|
class="toggle ml-auto section-button"
|
||||||
role="button"
|
role="button"
|
||||||
:aria-expanded="visible"
|
:aria-expanded="visible"
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
@keyup.enter="$emit('click')"
|
@keyup.enter="emitClick"
|
||||||
@click="$emit('click')"
|
@click="emitClick"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
v-if="visible"
|
v-if="visible"
|
||||||
class="svg-icon"
|
class="svg-icon icon-16"
|
||||||
v-html="icons.upIcon"
|
v-html="icons.upIcon"
|
||||||
></span>
|
></span>
|
||||||
<span
|
<span
|
||||||
v-else
|
v-else
|
||||||
class="svg-icon"
|
class="svg-icon icon-16 down-icon color-stroke"
|
||||||
v-html="icons.downIcon"
|
v-html="icons.downIcon"
|
||||||
></span>
|
></span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@import '~@/assets/scss/colors.scss';
|
@import '~@/assets/scss/colors.scss';
|
||||||
|
|
||||||
.toggle {
|
.toggle {
|
||||||
border: 0;
|
border: 0;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
&:focus {
|
&:focus {
|
||||||
|
// Fix keyboard inaccessible https://github.com/HabitRPG/habitica/pull/12656
|
||||||
outline: none;
|
outline: none;
|
||||||
border: $purple-400 solid 1px;
|
border: $purple-400 solid 1px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.svg-icon {
|
.svg-icon {
|
||||||
width: 16px;
|
display: flex;
|
||||||
|
|
||||||
|
::v-deep svg {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.down-icon {
|
||||||
|
color: $gray-300;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
@@ -56,5 +65,14 @@ export default {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
methods: {
|
||||||
|
emitClick ($event) {
|
||||||
|
if ($event.stopPropagation) {
|
||||||
|
$event.stopPropagation();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$emit('click');
|
||||||
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
221
website/client/src/components/shops/itemWithLabel.vue
Normal file
@@ -0,0 +1,221 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div
|
||||||
|
:id="itemId"
|
||||||
|
class="item-wrapper"
|
||||||
|
tabindex="0"
|
||||||
|
@click="click()"
|
||||||
|
@keypress.enter="click()"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="item"
|
||||||
|
:class="getItemClasses()"
|
||||||
|
>
|
||||||
|
<slot
|
||||||
|
name="badges"
|
||||||
|
:item="item"
|
||||||
|
:emptyItem="emptyItem"
|
||||||
|
></slot>
|
||||||
|
<div class="image">
|
||||||
|
<div
|
||||||
|
v-once
|
||||||
|
:class="item.class"
|
||||||
|
></div>
|
||||||
|
<slot
|
||||||
|
name="itemImage"
|
||||||
|
:item="item"
|
||||||
|
></slot>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="d-flex label-holder align-items-center justify-content-center"
|
||||||
|
:class="labelClass"
|
||||||
|
>
|
||||||
|
<slot
|
||||||
|
name="label"
|
||||||
|
:item="item"
|
||||||
|
></slot>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<b-popover
|
||||||
|
v-if="showPopover"
|
||||||
|
:target="itemId"
|
||||||
|
triggers="hover focus"
|
||||||
|
:placement="popoverPosition"
|
||||||
|
>
|
||||||
|
<slot
|
||||||
|
name="popoverContent"
|
||||||
|
:item="item"
|
||||||
|
>
|
||||||
|
</slot>
|
||||||
|
</b-popover>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import '~@/assets/scss/colors.scss';
|
||||||
|
|
||||||
|
.item-wrapper {
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item {
|
||||||
|
height: 7.5rem;
|
||||||
|
width: 94px;
|
||||||
|
border-radius: 4px;
|
||||||
|
background-color: $white;
|
||||||
|
box-shadow: 0 1px 3px 0 rgba($black, 0.12), 0 1px 2px 0 rgba($black, 0.24);
|
||||||
|
cursor: initial;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
border-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.locked .price {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.image {
|
||||||
|
margin: 12px 13px;
|
||||||
|
flex: 1;
|
||||||
|
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label-holder {
|
||||||
|
height: 28px;
|
||||||
|
font-weight: bold;
|
||||||
|
line-height: 1.33;
|
||||||
|
text-align: center;
|
||||||
|
background-color: $gray-700;
|
||||||
|
border-bottom-left-radius: 4px;
|
||||||
|
border-bottom-right-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label-holder.purple {
|
||||||
|
margin: -1px;
|
||||||
|
color: $purple-300;
|
||||||
|
background-color: rgba($purple-400, .1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.label-holder.yellow {
|
||||||
|
color: $yellow-5;
|
||||||
|
}
|
||||||
|
|
||||||
|
span.svg-icon.inline.lock {
|
||||||
|
height: 12px;
|
||||||
|
width: 10px;
|
||||||
|
position: absolute;
|
||||||
|
right: 8px;
|
||||||
|
top: 8px;
|
||||||
|
margin-top: 0;
|
||||||
|
color: $gray-200;
|
||||||
|
}
|
||||||
|
|
||||||
|
span.badge.badge-round.badge-item.badge-clock {
|
||||||
|
height: 24px;
|
||||||
|
width: 24px;
|
||||||
|
background-color: $purple-300;
|
||||||
|
position: absolute;
|
||||||
|
left: -8px;
|
||||||
|
top: -12px;
|
||||||
|
margin-top: 0;
|
||||||
|
padding: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
span.svg-icon.inline.clock {
|
||||||
|
height: 16px;
|
||||||
|
width: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.suggestedDot {
|
||||||
|
width: 6px;
|
||||||
|
height: 6px;
|
||||||
|
background-color: $purple-400;
|
||||||
|
border-radius: 4px;
|
||||||
|
|
||||||
|
position: absolute;
|
||||||
|
right: 8px;
|
||||||
|
top: 8px;
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-48 {
|
||||||
|
width: 48px;
|
||||||
|
height: 48px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.w-0 {
|
||||||
|
width: 0rem;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { v4 as uuid } from 'uuid';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
item: {
|
||||||
|
type: Object,
|
||||||
|
},
|
||||||
|
price: {
|
||||||
|
type: Number,
|
||||||
|
default: -1,
|
||||||
|
},
|
||||||
|
emptyItem: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
highlightBorder: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
popoverPosition: {
|
||||||
|
type: String,
|
||||||
|
default: 'bottom',
|
||||||
|
},
|
||||||
|
showPopover: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
showEventBadge: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
owned: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
labelClass: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return Object.freeze({
|
||||||
|
itemId: uuid(),
|
||||||
|
});
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
click () {
|
||||||
|
this.$emit('click', {});
|
||||||
|
},
|
||||||
|
getItemClasses () {
|
||||||
|
return {
|
||||||
|
'item-empty': this.emptyItem,
|
||||||
|
'highlight-border': this.highlightBorder,
|
||||||
|
suggested: this.item.isSuggested,
|
||||||
|
locked: this.item.locked,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
@@ -89,6 +89,7 @@ import svgRogue from '@/assets/svg/rogue.svg';
|
|||||||
import svgHealer from '@/assets/svg/healer.svg';
|
import svgHealer from '@/assets/svg/healer.svg';
|
||||||
|
|
||||||
import pinUtils from '../../../mixins/pinUtils';
|
import pinUtils from '../../../mixins/pinUtils';
|
||||||
|
import { getClassName } from '../../../../../common/script/libs/getClassName';
|
||||||
|
|
||||||
const sortGearTypes = [
|
const sortGearTypes = [
|
||||||
'sortByType', 'sortByPrice', 'sortByCon',
|
'sortByType', 'sortByPrice', 'sortByCon',
|
||||||
@@ -159,10 +160,7 @@ export default {
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
getClassName (classType) {
|
getClassName (classType) {
|
||||||
if (classType === 'wizard') {
|
return this.$t(getClassName(classType));
|
||||||
return this.$t('mage');
|
|
||||||
}
|
|
||||||
return this.$t(classType);
|
|
||||||
},
|
},
|
||||||
gearSelected (item) {
|
gearSelected (item) {
|
||||||
this.$root.$emit('buyModal::showItem', item);
|
this.$root.$emit('buyModal::showItem', item);
|
||||||
|
|||||||
@@ -13,14 +13,12 @@
|
|||||||
:pinned="isPinned"
|
:pinned="isPinned"
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
<div class="close">
|
<div class="dialog-close">
|
||||||
<span
|
<close-icon @click="hideDialog()" />
|
||||||
class="svg-icon inline icon-10"
|
|
||||||
aria-hidden="true"
|
|
||||||
@click="hideDialog()"
|
|
||||||
v-html="icons.close"
|
|
||||||
></span>
|
|
||||||
</div>
|
</div>
|
||||||
|
<h2 class="text-center textCondensed">
|
||||||
|
{{$t('questDetailsTitle') }}
|
||||||
|
</h2>
|
||||||
<div
|
<div
|
||||||
v-if="item != null"
|
v-if="item != null"
|
||||||
class="content"
|
class="content"
|
||||||
@@ -30,6 +28,7 @@
|
|||||||
:item="item"
|
:item="item"
|
||||||
:abbreviated="true"
|
:abbreviated="true"
|
||||||
/>
|
/>
|
||||||
|
<quest-rewards :quest="item" />
|
||||||
<div
|
<div
|
||||||
v-if="!item.locked"
|
v-if="!item.locked"
|
||||||
class="purchase-amount"
|
class="purchase-amount"
|
||||||
@@ -81,12 +80,6 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
|
||||||
v-if="item.drop"
|
|
||||||
class="right-sidebar"
|
|
||||||
>
|
|
||||||
<questDialogDrops :item="item" />
|
|
||||||
</div>
|
|
||||||
<countdown-banner
|
<countdown-banner
|
||||||
v-if="item.event"
|
v-if="item.event"
|
||||||
:endDate="endDate"
|
:endDate="endDate"
|
||||||
@@ -113,9 +106,14 @@
|
|||||||
#buy-quest-modal {
|
#buy-quest-modal {
|
||||||
@include centeredModal();
|
@include centeredModal();
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
color: $purple-300;
|
||||||
|
margin-top: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
.modal-dialog {
|
.modal-dialog {
|
||||||
margin-top: 8%;
|
margin-top: 8%;
|
||||||
width: 448px;
|
width: 448px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
@@ -134,6 +132,10 @@
|
|||||||
padding-bottom: 0px;
|
padding-bottom: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.questInfo {
|
||||||
|
margin: 0 auto 10px auto;
|
||||||
|
}
|
||||||
|
|
||||||
.right-sidebar {
|
.right-sidebar {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: -350px;
|
right: -350px;
|
||||||
@@ -198,6 +200,11 @@
|
|||||||
border-bottom-right-radius: 8px;
|
border-bottom-right-radius: 8px;
|
||||||
border-bottom-left-radius: 8px;
|
border-bottom-left-radius: 8px;
|
||||||
display: block;
|
display: block;
|
||||||
|
padding: 1rem 1.5rem;
|
||||||
|
|
||||||
|
&> * {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.notEnough {
|
.notEnough {
|
||||||
@@ -235,6 +242,18 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media only screen and (max-width: 1000px) {
|
||||||
|
.modal-dialog {
|
||||||
|
max-width: 80%;
|
||||||
|
width: 80% !important;
|
||||||
|
|
||||||
|
.modal-body {
|
||||||
|
flex-direction: column;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
@@ -257,14 +276,16 @@ import numberInvalid from '@/mixins/numberInvalid';
|
|||||||
import PinBadge from '@/components/ui/pinBadge';
|
import PinBadge from '@/components/ui/pinBadge';
|
||||||
import CountdownBanner from '../countdownBanner';
|
import CountdownBanner from '../countdownBanner';
|
||||||
|
|
||||||
import questDialogDrops from './questDialogDrops';
|
|
||||||
import questDialogContent from './questDialogContent';
|
import questDialogContent from './questDialogContent';
|
||||||
|
import QuestRewards from './questRewards';
|
||||||
|
import CloseIcon from '../../shared/closeIcon';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
|
CloseIcon,
|
||||||
|
QuestRewards,
|
||||||
BalanceInfo,
|
BalanceInfo,
|
||||||
PinBadge,
|
PinBadge,
|
||||||
questDialogDrops,
|
|
||||||
questDialogContent,
|
questDialogContent,
|
||||||
CountdownBanner,
|
CountdownBanner,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -219,39 +219,7 @@
|
|||||||
@click="selectItem(item)"
|
@click="selectItem(item)"
|
||||||
>
|
>
|
||||||
<span slot="popoverContent">
|
<span slot="popoverContent">
|
||||||
<div class="questPopover">
|
<quest-popover :item="item" />
|
||||||
<div></div>
|
|
||||||
<h4
|
|
||||||
v-if="item.locked"
|
|
||||||
class="popover-content-title"
|
|
||||||
>{{ `${$t('lockedItem')}` }}</h4>
|
|
||||||
<h4
|
|
||||||
v-else
|
|
||||||
class="popover-content-title"
|
|
||||||
>{{ item.text }}</h4>
|
|
||||||
<div
|
|
||||||
v-if="item.locked && item.key === 'lostMasterclasser1'"
|
|
||||||
class="popover-content-text"
|
|
||||||
>{{ `${$t('questUnlockLostMasterclasser')}` }}</div>
|
|
||||||
<div
|
|
||||||
v-if="item.locked && item.unlockCondition
|
|
||||||
&& item.unlockCondition.incentiveThreshold"
|
|
||||||
class="popover-content-text"
|
|
||||||
>{{ `${$t('loginIncentiveQuest', {
|
|
||||||
count: item.unlockCondition.incentiveThreshold})}` }}</div>
|
|
||||||
<div
|
|
||||||
v-if="item.locked && item.previous && isBuyingDependentOnPrevious(item)"
|
|
||||||
class="popover-content-text"
|
|
||||||
>{{ `${$t('unlockByQuesting', {title: item.previous})}` }}</div>
|
|
||||||
<div
|
|
||||||
v-if="item.lvl > user.stats.lvl"
|
|
||||||
class="popover-content-text"
|
|
||||||
>{{ `${$t('mustLvlQuest', {level: item.lvl})}` }}</div>
|
|
||||||
<questInfo
|
|
||||||
v-if="!item.locked"
|
|
||||||
:quest="item"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</span>
|
</span>
|
||||||
<template
|
<template
|
||||||
slot="itemBadge"
|
slot="itemBadge"
|
||||||
@@ -456,10 +424,12 @@ import isPinned from '@/../../common/script/libs/isPinned';
|
|||||||
import FilterSidebar from '@/components/ui/filterSidebar';
|
import FilterSidebar from '@/components/ui/filterSidebar';
|
||||||
import FilterGroup from '@/components/ui/filterGroup';
|
import FilterGroup from '@/components/ui/filterGroup';
|
||||||
import SelectTranslatedArray from '@/components/tasks/modal-controls/selectTranslatedArray';
|
import SelectTranslatedArray from '@/components/tasks/modal-controls/selectTranslatedArray';
|
||||||
|
import QuestPopover from './questPopover';
|
||||||
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
|
QuestPopover,
|
||||||
SelectTranslatedArray,
|
SelectTranslatedArray,
|
||||||
FilterGroup,
|
FilterGroup,
|
||||||
FilterSidebar,
|
FilterSidebar,
|
||||||
@@ -597,11 +567,6 @@ export default {
|
|||||||
|
|
||||||
this.$root.$emit('bv::show::modal', 'buy-quest-modal');
|
this.$root.$emit('bv::show::modal', 'buy-quest-modal');
|
||||||
},
|
},
|
||||||
isBuyingDependentOnPrevious (item) {
|
|
||||||
const questsNotDependentToPrevious = ['moon2', 'moon3'];
|
|
||||||
if (item.key in questsNotDependentToPrevious) return false;
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -0,0 +1,78 @@
|
|||||||
|
/* eslint-disable import/no-extraneous-dependencies */
|
||||||
|
import { storiesOf } from '@storybook/vue';
|
||||||
|
import { withKnobs } from '@storybook/addon-knobs';
|
||||||
|
|
||||||
|
import { quests } from '@/../../common/script/content/quests';
|
||||||
|
import questRewards from './questRewards';
|
||||||
|
import itemWithLabel from '../itemWithLabel';
|
||||||
|
import questPopover from './questPopover';
|
||||||
|
|
||||||
|
const stories = storiesOf('Quests/Sub Components', module);
|
||||||
|
|
||||||
|
stories.addDecorator(withKnobs);
|
||||||
|
|
||||||
|
stories
|
||||||
|
.add('questRewads', () => ({
|
||||||
|
components: { questRewards },
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
quest: quests.goldenknight2,
|
||||||
|
questWithDrop: quests.moon1,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
template: `
|
||||||
|
<div>
|
||||||
|
<quest-rewards :quest="quest"></quest-rewards>
|
||||||
|
<quest-rewards :quest="questWithDrop"></quest-rewards>
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
}))
|
||||||
|
.add('itemWithLabel', () => ({
|
||||||
|
components: { itemWithLabel },
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
};
|
||||||
|
},
|
||||||
|
template: `
|
||||||
|
<div>
|
||||||
|
<item-with-label :item="{}">
|
||||||
|
<div slot="itemContent">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div slot="itemImage">
|
||||||
|
Image
|
||||||
|
</div>
|
||||||
|
<div slot="label">
|
||||||
|
Label
|
||||||
|
</div>
|
||||||
|
</item-with-label>
|
||||||
|
|
||||||
|
<item-with-label :item="{}" label-class="purple">
|
||||||
|
<div slot="itemContent">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div slot="itemImage">
|
||||||
|
Image
|
||||||
|
</div>
|
||||||
|
<div slot="label">
|
||||||
|
Label
|
||||||
|
</div>
|
||||||
|
</item-with-label>
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
}))
|
||||||
|
.add('questPopover', () => ({
|
||||||
|
components: { questPopover },
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
quest: quests.goldenknight2,
|
||||||
|
quest2: quests.moon1,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
template: `
|
||||||
|
<div>
|
||||||
|
<quest-popover :item="quest"></quest-popover>
|
||||||
|
<quest-popover :item="quest2"></quest-popover>
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
}));
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
import groupBy from 'lodash/groupBy';
|
||||||
|
import { mapState } from '../../../libs/store';
|
||||||
|
|
||||||
|
export const QuestHelperMixin = {
|
||||||
|
computed: {
|
||||||
|
...mapState({
|
||||||
|
content: 'content',
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getDropIcon (drop) {
|
||||||
|
switch (drop.type) {
|
||||||
|
case 'hatchingPotions':
|
||||||
|
return `Pet_HatchingPotion_${drop.key}`;
|
||||||
|
case 'food':
|
||||||
|
return `Pet_Food_${drop.key}`;
|
||||||
|
case 'eggs':
|
||||||
|
return `Pet_Egg_${drop.key}`;
|
||||||
|
case 'quests':
|
||||||
|
return `inventory_quest_scroll_${drop.key}`;
|
||||||
|
default:
|
||||||
|
return `shop_${drop.key}`;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getDropName (drop) {
|
||||||
|
return typeof drop.text === 'function' ? drop.text() : drop.text;
|
||||||
|
},
|
||||||
|
getDropsList (drops, ownerOnly) {
|
||||||
|
if (!drops) return [];
|
||||||
|
|
||||||
|
const dropList = drops.filter(drop => {
|
||||||
|
if (ownerOnly) {
|
||||||
|
return drop.onlyOwner;
|
||||||
|
}
|
||||||
|
return !drop.onlyOwner;
|
||||||
|
}).map(item => {
|
||||||
|
if (item.type === 'gear') {
|
||||||
|
const contentItem = this.content.gear.flat[item.key];
|
||||||
|
|
||||||
|
return contentItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
text: item.text(),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return Object.entries(groupBy(dropList, e => `${e.type}_${e.key}`))
|
||||||
|
.map(([, entries]) => ({
|
||||||
|
...entries[0],
|
||||||
|
amount: entries.length,
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -4,9 +4,18 @@
|
|||||||
class="quest-image"
|
class="quest-image"
|
||||||
:class="'quest_' + item.key"
|
:class="'quest_' + item.key"
|
||||||
></div>
|
></div>
|
||||||
<h4 class="title">
|
<h3 class="text-center">
|
||||||
{{ itemText }}
|
{{ itemText }}
|
||||||
</h4>
|
</h3>
|
||||||
|
<div
|
||||||
|
v-if="group && leader"
|
||||||
|
class="leader-label"
|
||||||
|
>
|
||||||
|
<span v-once>
|
||||||
|
{{ $t('questOwner') }}:
|
||||||
|
</span>
|
||||||
|
<user-label :user="leader" />
|
||||||
|
</div>
|
||||||
<div
|
<div
|
||||||
class="text"
|
class="text"
|
||||||
v-html="itemNotes"
|
v-html="itemNotes"
|
||||||
@@ -23,6 +32,11 @@
|
|||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@import '~@/assets/scss/colors.scss';
|
@import '~@/assets/scss/colors.scss';
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
color: $gray-10;
|
||||||
|
margin-bottom: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
.quest-image {
|
.quest-image {
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
margin-bottom: 1em;
|
margin-bottom: 1em;
|
||||||
@@ -30,29 +44,67 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.text {
|
.text {
|
||||||
margin-bottom: 8px;
|
margin-bottom: 1rem;
|
||||||
overflow-y: scroll;
|
overflow-y: auto;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.leader-label {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: bold;
|
||||||
|
line-height: 1.71;
|
||||||
|
color: $gray-50;
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
|
||||||
|
::v-deep .user-label {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.questInfo {
|
.questInfo {
|
||||||
width: 70%;
|
width: 160px;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
margin-bottom: 10px;
|
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import QuestInfo from './questInfo.vue';
|
import QuestInfo from './questInfo.vue';
|
||||||
|
import UserLabel from '../../userLabel';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
|
UserLabel,
|
||||||
QuestInfo,
|
QuestInfo,
|
||||||
},
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
leader: null,
|
||||||
|
};
|
||||||
|
},
|
||||||
props: {
|
props: {
|
||||||
item: {
|
item: {
|
||||||
type: Object,
|
type: Object,
|
||||||
},
|
},
|
||||||
|
group: {
|
||||||
|
type: Object,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
async created () {
|
||||||
|
if (this.group && this.group.quest && this.group.quest.active) {
|
||||||
|
try {
|
||||||
|
const fetchMemberResult = await this.$store.dispatch('members:fetchMember', {
|
||||||
|
memberId: this.group.quest.leader,
|
||||||
|
});
|
||||||
|
|
||||||
|
this.leader = fetchMemberResult;
|
||||||
|
} catch {
|
||||||
|
this.leader = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
itemText () {
|
itemText () {
|
||||||
|
|||||||
@@ -1,159 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="questRewards">
|
|
||||||
<h3
|
|
||||||
v-once
|
|
||||||
class="text-center"
|
|
||||||
>
|
|
||||||
{{ $t('rewards') }}
|
|
||||||
</h3>
|
|
||||||
<div class="reward-item">
|
|
||||||
<span
|
|
||||||
class="svg-icon inline icon"
|
|
||||||
v-html="icons.experience"
|
|
||||||
></span>
|
|
||||||
<span class="reward-text">{{ $t('amountExperience', { amount: item.drop.exp }) }}</span>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
v-if="item.drop.gp != 0"
|
|
||||||
class="reward-item"
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
class="svg-icon inline icon"
|
|
||||||
v-html="icons.gold"
|
|
||||||
></span>
|
|
||||||
<span class="reward-text">{{ $t('amountGold', { amount: item.drop.gp }) }}</span>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
v-for="drop in getDropsList(item.drop.items, false)"
|
|
||||||
:key="drop.key"
|
|
||||||
class="reward-item"
|
|
||||||
>
|
|
||||||
<span class="icon">
|
|
||||||
<div :class="getDropIcon(drop)"></div>
|
|
||||||
</span>
|
|
||||||
<span class="reward-text">{{ getDropName(drop) }}</span>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
v-if="item.drop.unlock"
|
|
||||||
class="reward-item text-center"
|
|
||||||
>
|
|
||||||
<span class="reward-text">{{ item.drop.unlock() }}</span>
|
|
||||||
</div>
|
|
||||||
<h3
|
|
||||||
v-if="getDropsList(item.drop.items, true).length > 0"
|
|
||||||
class="text-center"
|
|
||||||
>
|
|
||||||
{{ $t('questOwnerRewards') }}
|
|
||||||
</h3>
|
|
||||||
<div
|
|
||||||
v-for="drop in getDropsList(item.drop.items, true)"
|
|
||||||
:key="drop.key"
|
|
||||||
class="reward-item"
|
|
||||||
>
|
|
||||||
<span class="icon">
|
|
||||||
<div :class="getDropIcon(drop)"></div>
|
|
||||||
</span>
|
|
||||||
<span class="reward-text">{{ getDropName(drop) }}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.questRewards {
|
|
||||||
overflow-y: auto;
|
|
||||||
width: 364px;
|
|
||||||
z-index: -1;
|
|
||||||
height: 100%;
|
|
||||||
|
|
||||||
h3 {
|
|
||||||
margin-top: 24px;
|
|
||||||
margin-bottom: 16px;
|
|
||||||
margin-left: auto;
|
|
||||||
margin-right: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.reward-item {
|
|
||||||
width: 306px;
|
|
||||||
height: 84px;
|
|
||||||
border-radius: 2px;
|
|
||||||
background-color: #ffffff;
|
|
||||||
margin: 0 auto;
|
|
||||||
margin-bottom: 1em;
|
|
||||||
padding: 1em;
|
|
||||||
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
.icon:not(.svg-icon) {
|
|
||||||
height: 68px;
|
|
||||||
width: 68px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.svg-icon {
|
|
||||||
margin: 15px;
|
|
||||||
height: 38px;
|
|
||||||
width: 38px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.reward-text {
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import svgGold from '@/assets/svg/gold.svg';
|
|
||||||
import svgExperience from '@/assets/svg/experience.svg';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
components: {
|
|
||||||
},
|
|
||||||
mixins: [],
|
|
||||||
props: {
|
|
||||||
item: {
|
|
||||||
type: Object,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
data () {
|
|
||||||
return {
|
|
||||||
icons: Object.freeze({
|
|
||||||
gold: svgGold,
|
|
||||||
experience: svgExperience,
|
|
||||||
}),
|
|
||||||
};
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
getDropIcon (drop) {
|
|
||||||
switch (drop.type) {
|
|
||||||
case 'gear':
|
|
||||||
return `shop_${drop.key}`;
|
|
||||||
case 'hatchingPotions':
|
|
||||||
return `Pet_HatchingPotion_${drop.key}`;
|
|
||||||
case 'food':
|
|
||||||
return `Pet_Food_${drop.key}`;
|
|
||||||
case 'eggs':
|
|
||||||
return `Pet_Egg_${drop.key}`;
|
|
||||||
case 'quests':
|
|
||||||
return `inventory_quest_scroll_${drop.key}`;
|
|
||||||
default:
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
},
|
|
||||||
getDropName (drop) {
|
|
||||||
return drop.text();
|
|
||||||
},
|
|
||||||
getDropsList (drops, ownerOnly) {
|
|
||||||
if (!drops) return [];
|
|
||||||
|
|
||||||
return drops.filter(drop => {
|
|
||||||
if (ownerOnly) {
|
|
||||||
return drop.onlyOwner;
|
|
||||||
}
|
|
||||||
return !drop.onlyOwner;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
@@ -1,16 +1,18 @@
|
|||||||
<template>
|
<template>
|
||||||
|
<div>
|
||||||
<div
|
<div
|
||||||
class="d-flex flex-column justify-content-center"
|
class="row"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
v-if="quest.collect"
|
v-if="quest.collect"
|
||||||
class="table-row m-auto"
|
class="table-row"
|
||||||
>
|
>
|
||||||
<dt>{{ $t('collect') + ':' }}</dt>
|
<dt>{{ $t('collect') + ':' }}</dt>
|
||||||
<dd>
|
<dd>
|
||||||
<div
|
<div
|
||||||
v-for="(collect, key) of quest.collect"
|
v-for="(collect, key) of quest.collect"
|
||||||
:key="key"
|
:key="key"
|
||||||
|
class="quest-item"
|
||||||
>
|
>
|
||||||
<span>{{ collect.count }} {{ getCollectText(collect) }}</span>
|
<span>{{ collect.count }} {{ getCollectText(collect) }}</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -18,12 +20,12 @@
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-if="quest.boss"
|
v-if="quest.boss"
|
||||||
class="table-row m-auto"
|
class="table-row"
|
||||||
>
|
>
|
||||||
<dt>{{ $t('bossHP') + ':' }}</dt>
|
<dt>{{ $t('bossHP') + ':' }}</dt>
|
||||||
<dd>{{ quest.boss.hp }}</dd>
|
<dd>{{ quest.boss.hp }}</dd>
|
||||||
</div>
|
</div>
|
||||||
<div class="table-row m-auto">
|
<div class="table-row">
|
||||||
<dt>{{ $t('difficulty') + ':' }}</dt>
|
<dt>{{ $t('difficulty') + ':' }}</dt>
|
||||||
<dd>
|
<dd>
|
||||||
<div
|
<div
|
||||||
@@ -34,6 +36,7 @@
|
|||||||
></div>
|
></div>
|
||||||
</dd>
|
</dd>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<div
|
<div
|
||||||
v-if="quest.event && !abbreviated"
|
v-if="quest.event && !abbreviated"
|
||||||
class="m-auto"
|
class="m-auto"
|
||||||
@@ -49,37 +52,51 @@
|
|||||||
.row {
|
.row {
|
||||||
display: table;
|
display: table;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.table-row {
|
.table-row {
|
||||||
display: table-row;
|
display: table-row;
|
||||||
margin-bottom: 4px;
|
font-size: 14px;
|
||||||
|
height: 1.5rem;
|
||||||
|
|
||||||
|
&:last-of-type {
|
||||||
|
dd {
|
||||||
|
padding-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dd {
|
dd {
|
||||||
height: 24px;
|
|
||||||
padding-left: 1em;
|
padding-left: 1em;
|
||||||
padding-top: 3px;
|
text-align: right;
|
||||||
padding-bottom: 3px;
|
|
||||||
|
padding-bottom: 0.5rem;
|
||||||
|
|
||||||
|
.quest-item {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dt, dd {
|
dt, dd {
|
||||||
display: table-cell;
|
display: table-cell;
|
||||||
vertical-align: middle;
|
vertical-align: top;
|
||||||
}
|
height: 16px;
|
||||||
|
max-height: 16px;
|
||||||
dt, dd, dd > * {
|
|
||||||
text-align: left;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dt {
|
dt {
|
||||||
font-size: 1.3em;
|
font-weight: bold;
|
||||||
line-height: 1.2;
|
font-stretch: normal;
|
||||||
|
font-style: normal;
|
||||||
|
line-height: 1.33;
|
||||||
|
letter-spacing: normal;
|
||||||
|
text-align: left;
|
||||||
color: $gray-50;
|
color: $gray-50;
|
||||||
}
|
}
|
||||||
|
|
||||||
.svg-icon {
|
.svg-icon {
|
||||||
margin-right: 4px;
|
margin-left: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.small-version {
|
.small-version {
|
||||||
@@ -93,10 +110,11 @@ dt {
|
|||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
@import '~@/assets/scss/colors.scss';
|
||||||
|
|
||||||
.questPopover {
|
.questPopover {
|
||||||
dt {
|
dt {
|
||||||
color: inherit;
|
color: inherit;
|
||||||
font-size: 1em;
|
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -113,7 +131,7 @@ dt {
|
|||||||
fill: #ffb445;
|
fill: #ffb445;
|
||||||
}
|
}
|
||||||
.star-empty {
|
.star-empty {
|
||||||
fill: #686274;
|
fill: $gray-400;
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
70
website/client/src/components/shops/quests/questPopover.vue
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
<template>
|
||||||
|
<div class="questPopover">
|
||||||
|
<h4
|
||||||
|
v-if="item.locked"
|
||||||
|
class="popover-content-title"
|
||||||
|
>
|
||||||
|
{{ $t('lockedItem') }}
|
||||||
|
</h4>
|
||||||
|
<h4
|
||||||
|
v-else
|
||||||
|
class="popover-content-title"
|
||||||
|
>
|
||||||
|
{{ item.text }}
|
||||||
|
</h4>
|
||||||
|
<div
|
||||||
|
v-if="item.locked && item.key === 'lostMasterclasser1'"
|
||||||
|
class="popover-content-text"
|
||||||
|
>
|
||||||
|
{{ $t('questUnlockLostMasterclasser') }}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="item.locked && item.unlockCondition
|
||||||
|
&& item.unlockCondition.incentiveThreshold"
|
||||||
|
class="popover-content-text"
|
||||||
|
>
|
||||||
|
{{ $t('loginIncentiveQuest', {
|
||||||
|
count: item.unlockCondition.incentiveThreshold}) }}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="item.locked && item.previous && isBuyingDependentOnPrevious(item)"
|
||||||
|
class="popover-content-text"
|
||||||
|
>
|
||||||
|
{{ $t('unlockByQuesting', {title: item.previous}) }}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="item.lvl > user.stats.lvl"
|
||||||
|
class="popover-content-text"
|
||||||
|
>
|
||||||
|
{{ $t('mustLvlQuest', {level: item.lvl}) }}
|
||||||
|
</div>
|
||||||
|
<questInfo
|
||||||
|
v-if="!item.locked"
|
||||||
|
:quest="item"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import QuestInfo from './questInfo.vue';
|
||||||
|
import { mapState } from '@/libs/store';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
QuestInfo,
|
||||||
|
},
|
||||||
|
props: ['item'],
|
||||||
|
computed: {
|
||||||
|
...mapState({
|
||||||
|
user: 'user.data',
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
isBuyingDependentOnPrevious (item) {
|
||||||
|
const questsNotDependentToPrevious = ['moon2', 'moon3'];
|
||||||
|
if (item.key in questsNotDependentToPrevious) return false;
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
213
website/client/src/components/shops/quests/questRewards.vue
Normal file
@@ -0,0 +1,213 @@
|
|||||||
|
<template>
|
||||||
|
<div class="quest-rewards">
|
||||||
|
<div
|
||||||
|
class="header d-flex align-items-center"
|
||||||
|
@click="toggle"
|
||||||
|
>
|
||||||
|
<span class="d-flex justify-content-center">
|
||||||
|
<div
|
||||||
|
v-once
|
||||||
|
class="your-rewards d-flex align-items-center"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="sparkles"
|
||||||
|
v-html="icons.sparkles"
|
||||||
|
></span>
|
||||||
|
<span class="rewards-title">{{ $t('rewards') }}</span>
|
||||||
|
<span
|
||||||
|
class="sparkles mirror"
|
||||||
|
v-html="icons.sparkles"
|
||||||
|
></span>
|
||||||
|
</div>
|
||||||
|
</span>
|
||||||
|
<SectionButton
|
||||||
|
:visible="opened"
|
||||||
|
@click="toggle"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="opened"
|
||||||
|
class="content ml-3 mr-3"
|
||||||
|
>
|
||||||
|
<item-with-label
|
||||||
|
v-for="drop in getDropsList(quest.drop.items, true)"
|
||||||
|
:key="drop.key"
|
||||||
|
:item="{}"
|
||||||
|
label-class="purple"
|
||||||
|
>
|
||||||
|
<div slot="itemImage">
|
||||||
|
<div :class="getDropIcon(drop)"></div>
|
||||||
|
</div>
|
||||||
|
<div slot="popoverContent">
|
||||||
|
<quest-popover :item="drop" />
|
||||||
|
</div>
|
||||||
|
<div slot="label">
|
||||||
|
{{ $t('ownerOnly') }}
|
||||||
|
</div>
|
||||||
|
</item-with-label>
|
||||||
|
|
||||||
|
<item-with-label
|
||||||
|
:item="{}"
|
||||||
|
label-class="yellow"
|
||||||
|
>
|
||||||
|
<div slot="itemImage">
|
||||||
|
<div
|
||||||
|
class="icon-48"
|
||||||
|
v-html="icons.expIcon"
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
|
<div slot="label">
|
||||||
|
{{ $t('amountExp', { amount: quest.drop.exp }) }}
|
||||||
|
</div>
|
||||||
|
</item-with-label>
|
||||||
|
|
||||||
|
<item-with-label
|
||||||
|
:item="{}"
|
||||||
|
label-class="yellow"
|
||||||
|
>
|
||||||
|
<div slot="itemImage">
|
||||||
|
<div
|
||||||
|
class="icon-48"
|
||||||
|
v-html="icons.goldIcon"
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
|
<div slot="label">
|
||||||
|
{{ $t('amountGold', { amount: quest.drop.gp }) }}
|
||||||
|
</div>
|
||||||
|
</item-with-label>
|
||||||
|
|
||||||
|
<item-with-label
|
||||||
|
v-for="drop in getDropsList(quest.drop.items, false)"
|
||||||
|
:key="drop.key"
|
||||||
|
:item="{}"
|
||||||
|
>
|
||||||
|
<countBadge
|
||||||
|
slot="badges"
|
||||||
|
:show="drop.amount !== 1"
|
||||||
|
:count="drop.amount"
|
||||||
|
/>
|
||||||
|
<div slot="itemImage">
|
||||||
|
<div :class="getDropIcon(drop)"></div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="drop.klass"
|
||||||
|
slot="popoverContent"
|
||||||
|
>
|
||||||
|
<equipmentAttributesPopover
|
||||||
|
:item="drop"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div slot="label">
|
||||||
|
{{ $t('newItem') }}
|
||||||
|
</div>
|
||||||
|
</item-with-label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import sparkles from '@/assets/svg/sparkles-left.svg';
|
||||||
|
import expIcon from '@/assets/svg/experience.svg';
|
||||||
|
import goldIcon from '@/assets/svg/gold.svg';
|
||||||
|
import SectionButton from '../../sectionButton';
|
||||||
|
import ItemWithLabel from '../itemWithLabel';
|
||||||
|
import { QuestHelperMixin } from './quest-helper.mixin';
|
||||||
|
import EquipmentAttributesPopover from '@/components/inventory/equipment/attributesPopover';
|
||||||
|
import QuestPopover from './questPopover';
|
||||||
|
import CountBadge from '../../ui/countBadge';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
CountBadge,
|
||||||
|
QuestPopover,
|
||||||
|
ItemWithLabel,
|
||||||
|
SectionButton,
|
||||||
|
EquipmentAttributesPopover,
|
||||||
|
},
|
||||||
|
mixins: [QuestHelperMixin],
|
||||||
|
props: ['quest'],
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
opened: true,
|
||||||
|
icons: Object.freeze({
|
||||||
|
sparkles,
|
||||||
|
expIcon,
|
||||||
|
goldIcon,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
droppedItem () {
|
||||||
|
const item = this.quest.drop.items[0];
|
||||||
|
|
||||||
|
if (item) {
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
toggle () {
|
||||||
|
this.opened = !this.opened;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
@import '~@/assets/scss/colors.scss';
|
||||||
|
|
||||||
|
.quest-rewards {
|
||||||
|
margin-left: -1rem;
|
||||||
|
margin-right: -1rem;
|
||||||
|
|
||||||
|
background-color: $gray-700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
height: 3.5rem;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
::v-deep {
|
||||||
|
.section-button {
|
||||||
|
position: absolute;
|
||||||
|
right: 1.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mirror {
|
||||||
|
transform: scaleX(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.your-rewards {
|
||||||
|
margin: 0 auto;
|
||||||
|
width: fit-content;
|
||||||
|
|
||||||
|
.sparkles {
|
||||||
|
width: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rewards-title {
|
||||||
|
font-weight: bold;
|
||||||
|
margin: 1rem;
|
||||||
|
color: $gray-50;
|
||||||
|
align-self: baseline; // center would move it to the top?!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.content{
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
gap: 8px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
padding-bottom: 1rem;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -371,6 +371,7 @@ import shops from '@/../../common/script/libs/shops';
|
|||||||
import SelectTranslatedArray from '@/components/tasks/modal-controls/selectTranslatedArray';
|
import SelectTranslatedArray from '@/components/tasks/modal-controls/selectTranslatedArray';
|
||||||
import FilterSidebar from '@/components/ui/filterSidebar';
|
import FilterSidebar from '@/components/ui/filterSidebar';
|
||||||
import FilterGroup from '@/components/ui/filterGroup';
|
import FilterGroup from '@/components/ui/filterGroup';
|
||||||
|
import { getClassName } from '../../../../../common/script/libs/getClassName';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
@@ -523,10 +524,7 @@ export default {
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
getClassName (classType) {
|
getClassName (classType) {
|
||||||
if (classType === 'wizard') {
|
return this.$t(getClassName(classType));
|
||||||
return this.$t('mage');
|
|
||||||
}
|
|
||||||
return this.$t(classType);
|
|
||||||
},
|
},
|
||||||
seasonalItems (category, sortBy, searchBy, viewOptions, hidePinned) {
|
seasonalItems (category, sortBy, searchBy, viewOptions, hidePinned) {
|
||||||
let result = _map(category.items, e => ({
|
let result = _map(category.items, e => ({
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="section">
|
<div class="section" :class="{'visible':visible}">
|
||||||
<div class="section-header d-flex align-items-center">
|
<div class="section-header d-flex align-items-center">
|
||||||
<h3
|
<h3
|
||||||
v-once
|
v-once
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
:target="tooltipId"
|
:target="tooltipId"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<SidebarButton
|
<SectionButton
|
||||||
:visible="visible"
|
:visible="visible"
|
||||||
@click="toggle"
|
@click="toggle"
|
||||||
/>
|
/>
|
||||||
@@ -39,18 +39,25 @@
|
|||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.section {
|
.section {
|
||||||
border-top: 1px solid #e1e0e3;
|
border-top: 1px solid #e1e0e3;
|
||||||
margin-top: 1em;
|
/* To have the divider full width */
|
||||||
padding-top: 1em;
|
margin-right: -1.5rem;
|
||||||
|
margin-left: -1.5rem;
|
||||||
|
|
||||||
|
/* change back the content padding*/
|
||||||
|
padding-left: 1.5rem;
|
||||||
|
padding-right: 1.5rem;
|
||||||
|
|
||||||
|
padding-top: 0.688em;
|
||||||
|
padding-bottom: 0.75em;
|
||||||
|
|
||||||
|
&.visible {
|
||||||
|
padding-bottom: 1rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.section:last-of-type {
|
.section:last-of-type {
|
||||||
border-bottom: 1px solid #e1e0e3;
|
border-bottom: 1px solid #e1e0e3;
|
||||||
margin-bottom: 1em;
|
margin-bottom: 1em;
|
||||||
padding-bottom: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.section-body {
|
|
||||||
margin-top: 1em;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.section-info {
|
.section-info {
|
||||||
@@ -60,15 +67,30 @@
|
|||||||
.section-info .svg-icon {
|
.section-info .svg-icon {
|
||||||
width: 16px;
|
width: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.section-body ::v-deep {
|
||||||
|
> *:empty {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
> :first-child:not(:empty) {
|
||||||
|
margin-top: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { v4 as uuid } from 'uuid';
|
import { v4 as uuid } from 'uuid';
|
||||||
import SidebarButton from './sidebarButton';
|
import SectionButton from './sectionButton';
|
||||||
import informationIcon from '@/assets/svg/information.svg';
|
import informationIcon from '@/assets/svg/information.svg';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: { SidebarButton },
|
components: { SectionButton },
|
||||||
props: {
|
props: {
|
||||||
title: {
|
title: {
|
||||||
required: true,
|
required: true,
|
||||||
|
|||||||
@@ -4,18 +4,11 @@ import { withKnobs, number } from '@storybook/addon-knobs';
|
|||||||
|
|
||||||
import MultiList from './multiList';
|
import MultiList from './multiList';
|
||||||
import SelectMulti from './selectMulti';
|
import SelectMulti from './selectMulti';
|
||||||
import getStore from '@/store';
|
|
||||||
|
|
||||||
const stories = storiesOf('Multiple Select List', module);
|
const stories = storiesOf('Multiple Select List', module);
|
||||||
|
|
||||||
stories.addDecorator(withKnobs);
|
stories.addDecorator(withKnobs);
|
||||||
|
|
||||||
// Needed for SelectTag
|
|
||||||
const store = getStore();
|
|
||||||
store.state.user.data = {
|
|
||||||
tags: [],
|
|
||||||
};
|
|
||||||
|
|
||||||
const exampleTagList = [
|
const exampleTagList = [
|
||||||
1, 2, 3,
|
1, 2, 3,
|
||||||
];
|
];
|
||||||
@@ -96,7 +89,6 @@ stories
|
|||||||
Added event: {{ added }}
|
Added event: {{ added }}
|
||||||
</div>
|
</div>
|
||||||
`,
|
`,
|
||||||
store,
|
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
tagList: exampleTagList,
|
tagList: exampleTagList,
|
||||||
@@ -119,7 +111,6 @@ stories
|
|||||||
@changed="tagList = $event"></SelectMulti>
|
@changed="tagList = $event"></SelectMulti>
|
||||||
</div>
|
</div>
|
||||||
`,
|
`,
|
||||||
store,
|
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
tagList: [],
|
tagList: [],
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
right: -9px;
|
right: -9px;
|
||||||
top: -12px;
|
top: -12px;
|
||||||
border-radius: 100px;
|
border-radius: 100px;
|
||||||
color: $white;
|
color: $white !important; // I saw the default gray-100 color
|
||||||
background: $gray-200;
|
background: $gray-200;
|
||||||
padding: 4.5px 8.5px;
|
padding: 4.5px 8.5px;
|
||||||
min-width: 1.5rem;
|
min-width: 1.5rem;
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
:class="{condensed}"
|
:class="{condensed}"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
|
v-if="showIcon"
|
||||||
class="svg-icon"
|
class="svg-icon"
|
||||||
v-html="icon"
|
v-html="icon"
|
||||||
></div>
|
></div>
|
||||||
@@ -16,7 +17,9 @@
|
|||||||
:style="{width: `${percent(value, maxValue)}%`}"
|
:style="{width: `${percent(value, maxValue)}%`}"
|
||||||
></div>
|
></div>
|
||||||
</div>
|
</div>
|
||||||
<span class="small-text">{{ value | statFloor }} / {{ maxValue }}</span>
|
<span class="small-text" v-if="showNumbers">
|
||||||
|
{{ value | statFloor }} / {{ maxValue }}
|
||||||
|
</span>
|
||||||
<b-tooltip
|
<b-tooltip
|
||||||
class="myClass"
|
class="myClass"
|
||||||
:target="() => $refs.container"
|
:target="() => $refs.container"
|
||||||
@@ -55,11 +58,13 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.progress-container > .progress {
|
.progress-container > .progress {
|
||||||
|
--progress-background: #{$header-dark-background};
|
||||||
|
|
||||||
min-width: 200px;
|
min-width: 200px;
|
||||||
margin: 0px;
|
margin: 0px;
|
||||||
border-radius: 1px;
|
border-radius: 1px;
|
||||||
height: 12px;
|
height: 12px;
|
||||||
background-color: $header-dark-background;
|
background-color: var(--progress-background);
|
||||||
@media (max-width: 992px) {
|
@media (max-width: 992px) {
|
||||||
min-width: 160px;
|
min-width: 160px;
|
||||||
}
|
}
|
||||||
@@ -130,6 +135,14 @@ export default {
|
|||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
|
showIcon: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
showNumbers: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
>
|
>
|
||||||
{{ displayName }}
|
{{ displayName }}
|
||||||
<div
|
<div
|
||||||
|
v-if="hasTier"
|
||||||
class="svg-icon"
|
class="svg-icon"
|
||||||
v-html="tierIcon()"
|
v-html="tierIcon()"
|
||||||
></div>
|
></div>
|
||||||
@@ -97,6 +98,9 @@ export default {
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
|
hasTier () {
|
||||||
|
return this.isNPC || this.level !== 0;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
tierIcon () {
|
tierIcon () {
|
||||||
|
|||||||
@@ -17,11 +17,7 @@
|
|||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import '~@/assets/scss/colors.scss';
|
@import '~@/assets/scss/colors.scss';
|
||||||
|
|
||||||
a.no-tier {
|
.user-link { // this is the user name
|
||||||
color: $gray-50;
|
|
||||||
}
|
|
||||||
|
|
||||||
a.leader { // this is the user name
|
|
||||||
font-family: 'Roboto Condensed', sans-serif;
|
font-family: 'Roboto Condensed', sans-serif;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
@@ -29,10 +25,26 @@
|
|||||||
display: inline-block;
|
display: inline-block;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
|
|
||||||
|
// currently used in the member-details-new.vue
|
||||||
|
&.smaller {
|
||||||
|
font-family: Roboto;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: bold;
|
||||||
|
line-height: 1.71;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.no-tier {
|
||||||
|
color: $gray-50;
|
||||||
|
}
|
||||||
|
|
||||||
.svg-icon {
|
.svg-icon {
|
||||||
width: 10px;
|
width: 10px;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
margin-left: .5em;
|
margin-left: .5em;
|
||||||
|
|
||||||
|
&:empty {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
@@ -56,7 +68,15 @@ import tierNPC from '@/assets/svg/tier-npc.svg';
|
|||||||
|
|
||||||
export default {
|
export default {
|
||||||
mixins: [styleHelper],
|
mixins: [styleHelper],
|
||||||
props: ['user', 'userId', 'name', 'backer', 'contributor', 'hideTooltip'],
|
props: [
|
||||||
|
'user',
|
||||||
|
'userId',
|
||||||
|
'name',
|
||||||
|
'backer',
|
||||||
|
'contributor',
|
||||||
|
'hideTooltip',
|
||||||
|
'smallerStyle',
|
||||||
|
],
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
icons: Object.freeze({
|
icons: Object.freeze({
|
||||||
@@ -114,7 +134,7 @@ export default {
|
|||||||
return this.hideTooltip ? '' : achievementsLib.getContribText(this.contributor, this.isNPC) || '';
|
return this.hideTooltip ? '' : achievementsLib.getContribText(this.contributor, this.isNPC) || '';
|
||||||
},
|
},
|
||||||
levelStyle () {
|
levelStyle () {
|
||||||
return this.userLevelStyleFromLevel(this.level, this.isNPC);
|
return `${this.userLevelStyleFromLevel(this.level, this.isNPC)} ${this.smallerStyle ? 'smaller' : ''}`;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -858,7 +858,10 @@ export default {
|
|||||||
const profileUserId = this.userId;
|
const profileUserId = this.userId;
|
||||||
|
|
||||||
if (profileUserId && profileUserId !== this.userLoggedIn._id) {
|
if (profileUserId && profileUserId !== this.userLoggedIn._id) {
|
||||||
const response = await this.$store.dispatch('members:fetchMember', { memberId: profileUserId });
|
const response = await this.$store.dispatch('members:fetchMember', {
|
||||||
|
memberId: profileUserId,
|
||||||
|
unpack: false,
|
||||||
|
});
|
||||||
if (response.response && response.response.status === 404) {
|
if (response.response && response.response.status === 404) {
|
||||||
user = null;
|
user = null;
|
||||||
this.$store.dispatch('snackbars:add', {
|
this.$store.dispatch('snackbars:add', {
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
|
||||||
// import omit from 'lodash/omit';
|
// import omit from 'lodash/omit';
|
||||||
// import findIndex from 'lodash/findIndex';
|
// import findIndex from 'lodash/findIndex';
|
||||||
|
|
||||||
@@ -25,16 +26,24 @@ export async function getGroupMembers (store, payload) {
|
|||||||
return response.data.data;
|
return response.data.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function unpackResponse (response) {
|
||||||
|
return response && response.data
|
||||||
|
? response.data.data
|
||||||
|
: undefined;
|
||||||
|
}
|
||||||
|
|
||||||
export async function fetchMember (store, payload) {
|
export async function fetchMember (store, payload) {
|
||||||
const url = `${apiv4Prefix}/members/${payload.memberId}`;
|
const url = `${apiv4Prefix}/members/${payload.memberId}`;
|
||||||
const response = await axios.get(url);
|
const response = await axios.get(url);
|
||||||
return response;
|
return payload.unpack === false
|
||||||
|
? response
|
||||||
|
: unpackResponse(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function fetchMemberByUsername (store, payload) {
|
export async function fetchMemberByUsername (store, payload) {
|
||||||
const url = `${apiv4Prefix}/members/username/${payload.username}`;
|
const url = `${apiv4Prefix}/members/username/${payload.username}`;
|
||||||
const response = await axios.get(url);
|
const response = await axios.get(url);
|
||||||
return response;
|
return unpackResponse(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getGroupInvites (store, payload) {
|
export async function getGroupInvites (store, payload) {
|
||||||
|
|||||||
@@ -74,8 +74,12 @@
|
|||||||
"applySortToHeader": "Apply Sort Options to Party Header",
|
"applySortToHeader": "Apply Sort Options to Party Header",
|
||||||
"confirmGuild": "Create Guild for 4 Gems?",
|
"confirmGuild": "Create Guild for 4 Gems?",
|
||||||
"confirm": "Confirm",
|
"confirm": "Confirm",
|
||||||
"leaveGroup": "Leave Guild",
|
"leaveGuild": "Leave Guild",
|
||||||
"leaveParty": "Leave Party",
|
"leaveParty": "Leave Party",
|
||||||
|
"editParty": "Edit Party",
|
||||||
|
"editGuild": "Edit Guild",
|
||||||
|
"joinParty": "Join Party",
|
||||||
|
"joinGuild": "Join Guild",
|
||||||
"send": "Send",
|
"send": "Send",
|
||||||
"pmsMarkedRead": "Your Private Messages have been marked as read",
|
"pmsMarkedRead": "Your Private Messages have been marked as read",
|
||||||
"possessiveParty": "<%= name %>'s Party",
|
"possessiveParty": "<%= name %>'s Party",
|
||||||
@@ -254,6 +258,7 @@
|
|||||||
"inviteEmailUsernameInfo": "Invite users via a valid email or username. If an email isn't registered yet, we'll invite them to join.",
|
"inviteEmailUsernameInfo": "Invite users via a valid email or username. If an email isn't registered yet, we'll invite them to join.",
|
||||||
"emailOrUsernameInvite": "Email address or username",
|
"emailOrUsernameInvite": "Email address or username",
|
||||||
"messageGuildLeader": "Message Guild Leader",
|
"messageGuildLeader": "Message Guild Leader",
|
||||||
|
"messagePartyLeader": "Message Party Leader",
|
||||||
"donateGems": "Donate Gems",
|
"donateGems": "Donate Gems",
|
||||||
"updateGuild": "Update Guild",
|
"updateGuild": "Update Guild",
|
||||||
"viewMembers": "View Members",
|
"viewMembers": "View Members",
|
||||||
@@ -301,22 +306,22 @@
|
|||||||
"wantToJoinPartyDescription": "Give your username to a friend who already has a Party, or head to the <a href='/groups/guild/f2db2a7f-13c5-454d-b3ee-ea1f5089e601'>Party Wanted Guild</a> to meet potential comrades!",
|
"wantToJoinPartyDescription": "Give your username to a friend who already has a Party, or head to the <a href='/groups/guild/f2db2a7f-13c5-454d-b3ee-ea1f5089e601'>Party Wanted Guild</a> to meet potential comrades!",
|
||||||
"copy": "Copy",
|
"copy": "Copy",
|
||||||
"inviteToPartyOrQuest": "Invite Party to Quest",
|
"inviteToPartyOrQuest": "Invite Party to Quest",
|
||||||
"inviteInformation": "Clicking \"Invite\" will send an invitation to your Party members. When all members have accepted or denied, the Quest begins.",
|
|
||||||
"questOwnerRewards": "Quest Owner Rewards",
|
"questOwnerRewards": "Quest Owner Rewards",
|
||||||
"updateParty": "Update Party",
|
"updateParty": "Update Party",
|
||||||
"upgrade": "Upgrade",
|
"upgradeToGroup": "Upgrade to Group",
|
||||||
"selectPartyMember": "Select a Party Member",
|
"selectPartyMember": "Select a Party Member",
|
||||||
"areYouSureDeleteMessage": "Are you sure you want to delete this message?",
|
"areYouSureDeleteMessage": "Are you sure you want to delete this message?",
|
||||||
"reverseChat": "Reverse Chat",
|
"reverseChat": "Reverse Chat",
|
||||||
"invites": "Invites",
|
"invites": "Invites",
|
||||||
"details": "Details",
|
"details": "Details",
|
||||||
|
"viewDetails": "View Details",
|
||||||
"participantDesc": "Once all members have either accepted or declined, the Quest begins. Only those who clicked 'accept' will be able to participate in the Quest and receive the rewards.",
|
"participantDesc": "Once all members have either accepted or declined, the Quest begins. Only those who clicked 'accept' will be able to participate in the Quest and receive the rewards.",
|
||||||
"groupGems": "Group Gems",
|
"groupGems": "Group Gems",
|
||||||
"groupGemsDesc": "Guild Gems can be spent to make Challenges! In the future, you will be able to add more Guild Gems.",
|
"groupGemsDesc": "Guild Gems can be spent to make Challenges! In the future, you will be able to add more Guild Gems.",
|
||||||
"groupTaskBoard": "Task Board",
|
"groupTaskBoard": "Task Board",
|
||||||
"groupInformation": "Group Information",
|
"groupInformation": "Group Information",
|
||||||
"groupBilling": "Group Billing",
|
"groupBilling": "Group Billing",
|
||||||
"wouldYouParticipate": "Would you like to participate?",
|
"invitedToThisQuest": "You were invited to this Quest!",
|
||||||
"managerAdded": "Manager added successfully",
|
"managerAdded": "Manager added successfully",
|
||||||
"managerRemoved": "Manager removed successfully",
|
"managerRemoved": "Manager removed successfully",
|
||||||
"leaderChanged": "Leader has been changed",
|
"leaderChanged": "Leader has been changed",
|
||||||
|
|||||||
@@ -39,6 +39,7 @@
|
|||||||
"hidePinned": "Hide pinned",
|
"hidePinned": "Hide pinned",
|
||||||
"hideMissing": "Hide Missing",
|
"hideMissing": "Hide Missing",
|
||||||
"amountExperience": "<%= amount %> Experience",
|
"amountExperience": "<%= amount %> Experience",
|
||||||
|
"amountExp": "<%= amount %> Exp",
|
||||||
"amountGold": "<%= amount %> Gold",
|
"amountGold": "<%= amount %> Gold",
|
||||||
"namedHatchingPotion": "<%= type %> Hatching Potion",
|
"namedHatchingPotion": "<%= type %> Hatching Potion",
|
||||||
"buyGems": "Buy Gems",
|
"buyGems": "Buy Gems",
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
"rejected": "Rejected",
|
"rejected": "Rejected",
|
||||||
"pending": "Pending",
|
"pending": "Pending",
|
||||||
"questCollection": "+ <%= val %> quest item(s) found",
|
"questCollection": "+ <%= val %> quest item(s) found",
|
||||||
|
"questItemsPending": "<%= amount %> Items pending",
|
||||||
"bossDamage": "You damaged the boss!",
|
"bossDamage": "You damaged the boss!",
|
||||||
"begin": "Begin",
|
"begin": "Begin",
|
||||||
"bossHP": "Boss HP",
|
"bossHP": "Boss HP",
|
||||||
@@ -32,17 +33,17 @@
|
|||||||
"collected": "Collected",
|
"collected": "Collected",
|
||||||
"abort": "Abort",
|
"abort": "Abort",
|
||||||
"leaveQuest": "Leave Quest",
|
"leaveQuest": "Leave Quest",
|
||||||
"sureLeave": "Are you sure you want to leave the active quest? All your quest progress will be lost.",
|
"sureLeave": "Are you sure you want to leave the Quest? All your progress will be lost.",
|
||||||
|
"sureLeaveInactive": "Are you sure you want to leave the Quest? You won't be able to participate.",
|
||||||
"mustComplete": "You must first complete <%= quest %>.",
|
"mustComplete": "You must first complete <%= quest %>.",
|
||||||
"mustLvlQuest": "You must be level <%= level %> to buy this quest!",
|
"mustLvlQuest": "You must be level <%= level %> to buy this quest!",
|
||||||
"unlockByQuesting": "To unlock this quest, complete <%= title %>.",
|
"unlockByQuesting": "To unlock this quest, complete <%= title %>.",
|
||||||
"questConfirm": "Are you sure? Only <%= questmembers %> of your <%= totalmembers %> party members have joined this quest! Quests start automatically when all players have joined or rejected the invitation.",
|
"questConfirm": "Are you sure you want to start this Quest? Not all Party members have accepted the Quest invite. Quests start automatically after all members respond to the invite.",
|
||||||
"sureCancel": "Are you sure you want to cancel this quest? All invitation acceptances will be lost. The quest owner will retain possession of the quest scroll.",
|
"sureCancel": "Are you sure you want to cancel this Quest? Canceling the Quest will cancel all accepted and pending invitations. The Quest will be returned to the owner's inventory.",
|
||||||
"sureAbort": "Are you sure you want to abort this mission? It will abort it for everyone in your party and all progress will be lost. The quest scroll will be returned to the quest owner.",
|
"sureAbort": "Are you sure you want to cancel this Quest? All progress will be lost. The Quest will be returned to the owner's inventory.",
|
||||||
"doubleSureAbort": "Are you double sure? Make sure they won't hate you forever!",
|
|
||||||
"bossRageTitle": "Rage",
|
"bossRageTitle": "Rage",
|
||||||
"bossRageDescription": "When this bar fills, the boss will unleash a special attack!",
|
"bossRageDescription": "When this bar fills, the boss will unleash a special attack!",
|
||||||
"startAQuest": "START A QUEST",
|
"selectQuest": "Select Quest",
|
||||||
"startQuest": "Start Quest",
|
"startQuest": "Start Quest",
|
||||||
"questInvitationDoesNotExist": "No quest invitation has been sent out yet.",
|
"questInvitationDoesNotExist": "No quest invitation has been sent out yet.",
|
||||||
"questInviteNotFound": "No quest invitation found.",
|
"questInviteNotFound": "No quest invitation found.",
|
||||||
@@ -54,21 +55,23 @@
|
|||||||
"questAlreadyStarted": "The quest has already started.",
|
"questAlreadyStarted": "The quest has already started.",
|
||||||
"questAlreadyStartedFriendly": "The quest has already started, but you can always catch the next one!",
|
"questAlreadyStartedFriendly": "The quest has already started, but you can always catch the next one!",
|
||||||
"questAlreadyAccepted": "You already accepted the quest invitation.",
|
"questAlreadyAccepted": "You already accepted the quest invitation.",
|
||||||
"noActiveQuestToLeave": "No active quest to leave",
|
|
||||||
"questLeaderCannotLeaveQuest": "Quest leader cannot leave quest",
|
"questLeaderCannotLeaveQuest": "Quest leader cannot leave quest",
|
||||||
"notPartOfQuest": "You are not part of the quest",
|
"notPartOfQuest": "You are not part of the quest",
|
||||||
"youAreNotOnQuest": "You're not on a quest",
|
"youAreNotOnQuest": "You're not on a quest",
|
||||||
|
"yourPartyIsNotOnQuest": "Your Party is not on a Quest",
|
||||||
"noActiveQuestToAbort": "There is no active quest to abort.",
|
"noActiveQuestToAbort": "There is no active quest to abort.",
|
||||||
"onlyLeaderAbortQuest": "Only the group or quest leader can abort a quest.",
|
"onlyLeaderAbortQuest": "Only the group or quest leader can abort a quest.",
|
||||||
"questAlreadyRejected": "You already rejected the quest invitation.",
|
"questAlreadyRejected": "You already rejected the quest invitation.",
|
||||||
"cantCancelActiveQuest": "You can not cancel an active quest, use the abort functionality.",
|
"cantCancelActiveQuest": "You can not cancel an active quest, use the abort functionality.",
|
||||||
"onlyLeaderCancelQuest": "Only the group or quest leader can cancel the quest.",
|
"onlyLeaderCancelQuest": "Only the group or quest leader can cancel the quest.",
|
||||||
"questNotPending": "There is no quest to start.",
|
"questNotPending": "There is no quest to start.",
|
||||||
|
"membersParticipating": "<%= accepted %> / <%= invited %> Members participating",
|
||||||
"questOrGroupLeaderOnlyStartQuest": "Only the quest leader or group leader can force start the quest",
|
"questOrGroupLeaderOnlyStartQuest": "Only the quest leader or group leader can force start the quest",
|
||||||
"loginIncentiveQuest": "To unlock this quest, check in to Habitica on <%= count %> different days!",
|
"loginIncentiveQuest": "To unlock this quest, check in to Habitica on <%= count %> different days!",
|
||||||
"loginReward": "<%= count %> Check-ins",
|
"loginReward": "<%= count %> Check-ins",
|
||||||
"questBundles": "Discounted Quest Bundles",
|
"questBundles": "Discounted Quest Bundles",
|
||||||
"noQuestToStart": "Can’t find a quest to start? Try checking out the Quest Shop in the Market for new releases!",
|
"noQuestToStartTitle": "Can’t find a Quest to start?",
|
||||||
|
"noQuestToStart": "Try checking out the <a href=\"<%= questShop %>\">Quest Shop</a> for new releases!",
|
||||||
"pendingDamage": "<%= damage %> pending damage",
|
"pendingDamage": "<%= damage %> pending damage",
|
||||||
"pendingDamageLabel": "pending damage",
|
"pendingDamageLabel": "pending damage",
|
||||||
"bossHealth": "<%= currentHealth %> / <%= maxHealth %> Health",
|
"bossHealth": "<%= currentHealth %> / <%= maxHealth %> Health",
|
||||||
@@ -83,5 +86,12 @@
|
|||||||
"chatItemQuestFinish": "All items found! Party has received their rewards.",
|
"chatItemQuestFinish": "All items found! Party has received their rewards.",
|
||||||
"chatQuestAborted": "<%= username %> aborted the party quest <%= questName %>.",
|
"chatQuestAborted": "<%= username %> aborted the party quest <%= questName %>.",
|
||||||
"chatQuestCancelled": "<%= username %> cancelled the party quest <%= questName %>.",
|
"chatQuestCancelled": "<%= username %> cancelled the party quest <%= questName %>.",
|
||||||
"tavernBossTired": "<%= bossName %> tries to unleash <%= rageName %> but is too tired."
|
"tavernBossTired": "<%= bossName %> tries to unleash <%= rageName %> but is too tired.",
|
||||||
|
"ownerOnly": "Owner only",
|
||||||
|
"newItem": "New Item",
|
||||||
|
"selectQuestModal": "Select a Quest",
|
||||||
|
"yourQuests": "Your Quests",
|
||||||
|
"backToSelection": "Back to Quest selection",
|
||||||
|
"cancelQuest": "Cancel Quest",
|
||||||
|
"questOwner": "Quest Owner"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import * as contributorGear from './special-contributor';
|
|||||||
import * as takeThisGear from './special-takeThis';
|
import * as takeThisGear from './special-takeThis';
|
||||||
import * as wonderconGear from './special-wondercon';
|
import * as wonderconGear from './special-wondercon';
|
||||||
import t from '../../../translation';
|
import t from '../../../translation';
|
||||||
|
import { getClassName } from '../../../../libs/getClassName';
|
||||||
|
|
||||||
const CURRENT_EVENT = find(
|
const CURRENT_EVENT = find(
|
||||||
EVENTS, event => moment().isBetween(event.start, event.end) && Boolean(event.season),
|
EVENTS, event => moment().isBetween(event.start, event.end) && Boolean(event.season),
|
||||||
@@ -714,7 +715,7 @@ const armorStats = {
|
|||||||
|
|
||||||
Object.keys(gearEvents).forEach(event => {
|
Object.keys(gearEvents).forEach(event => {
|
||||||
CLASSES.forEach(klass => {
|
CLASSES.forEach(klass => {
|
||||||
const classNameString = klass === 'wizard' ? 'mage' : klass;
|
const classNameString = getClassName(klass);
|
||||||
const eventString = `${event}${upperFirst(classNameString)}`;
|
const eventString = `${event}${upperFirst(classNameString)}`;
|
||||||
const textString = `armorSpecial${upperFirst(event)}${upperFirst(classNameString)}`;
|
const textString = `armorSpecial${upperFirst(event)}${upperFirst(classNameString)}`;
|
||||||
defaults(armor[eventString], {
|
defaults(armor[eventString], {
|
||||||
@@ -1761,7 +1762,7 @@ const headStats = {
|
|||||||
|
|
||||||
Object.keys(gearEvents).forEach(event => {
|
Object.keys(gearEvents).forEach(event => {
|
||||||
CLASSES.forEach(klass => {
|
CLASSES.forEach(klass => {
|
||||||
const classNameString = klass === 'wizard' ? 'mage' : klass;
|
const classNameString = getClassName(klass);
|
||||||
const eventString = `${event}${upperFirst(classNameString)}`;
|
const eventString = `${event}${upperFirst(classNameString)}`;
|
||||||
const textString = `headSpecial${upperFirst(event)}${upperFirst(classNameString)}`;
|
const textString = `headSpecial${upperFirst(event)}${upperFirst(classNameString)}`;
|
||||||
defaults(head[eventString], {
|
defaults(head[eventString], {
|
||||||
@@ -3192,7 +3193,7 @@ const weaponCosts = {
|
|||||||
|
|
||||||
Object.keys(gearEvents).forEach(event => {
|
Object.keys(gearEvents).forEach(event => {
|
||||||
CLASSES.forEach(klass => {
|
CLASSES.forEach(klass => {
|
||||||
const classNameString = klass === 'wizard' ? 'mage' : klass;
|
const classNameString = getClassName(klass);
|
||||||
const eventString = `${event}${upperFirst(classNameString)}`;
|
const eventString = `${event}${upperFirst(classNameString)}`;
|
||||||
const textString = `weaponSpecial${upperFirst(event)}${upperFirst(classNameString)}`;
|
const textString = `weaponSpecial${upperFirst(event)}${upperFirst(classNameString)}`;
|
||||||
defaults(weapon[eventString], {
|
defaults(weapon[eventString], {
|
||||||
|
|||||||
3
website/common/script/libs/getClassName.js
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
export function getClassName (klass) {
|
||||||
|
return klass === 'wizard' ? 'mage' : klass;
|
||||||
|
}
|
||||||
@@ -12,8 +12,6 @@ export default function percent (x, y, dir) {
|
|||||||
default:
|
default:
|
||||||
roundFn = Math.round;
|
roundFn = Math.round;
|
||||||
}
|
}
|
||||||
if (x === 0) {
|
|
||||||
x = 1; // eslint-disable-line no-param-reassign
|
|
||||||
}
|
|
||||||
return Math.max(0, roundFn((x / y) * 100));
|
return Math.max(0, roundFn((x / y) * 100));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import seasonalShopConfig from './shops-seasonal.config';
|
|||||||
import featuredItems from '../content/shop-featuredItems';
|
import featuredItems from '../content/shop-featuredItems';
|
||||||
|
|
||||||
import getOfficialPinnedItems from './getOfficialPinnedItems';
|
import getOfficialPinnedItems from './getOfficialPinnedItems';
|
||||||
|
import { getClassName } from './getClassName';
|
||||||
|
|
||||||
const shops = {};
|
const shops = {};
|
||||||
|
|
||||||
@@ -89,11 +90,8 @@ shops.getMarketCategories = function getMarket (user, language) {
|
|||||||
return categories;
|
return categories;
|
||||||
};
|
};
|
||||||
|
|
||||||
function getClassName (classType, language) {
|
function getTranslatedClassName (classType, language) {
|
||||||
if (classType === 'wizard') {
|
return i18n.t(getClassName(classType), language);
|
||||||
return i18n.t('mage', language);
|
|
||||||
}
|
|
||||||
return i18n.t(classType, language);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO Refactor the `.locked` logic
|
// TODO Refactor the `.locked` logic
|
||||||
@@ -143,7 +141,7 @@ shops.getMarketGearCategories = function getMarketGear (user, language) {
|
|||||||
for (const classType of content.classes) {
|
for (const classType of content.classes) {
|
||||||
const category = {
|
const category = {
|
||||||
identifier: classType,
|
identifier: classType,
|
||||||
text: getClassName(classType, language),
|
text: getTranslatedClassName(classType, language),
|
||||||
};
|
};
|
||||||
|
|
||||||
const result = filter(content.gear.flat, gearItem => {
|
const result = filter(content.gear.flat, gearItem => {
|
||||||
|
|||||||
@@ -518,7 +518,6 @@ api.leaveQuest = {
|
|||||||
|
|
||||||
if (!group) throw new NotFound(res.t('groupNotFound'));
|
if (!group) throw new NotFound(res.t('groupNotFound'));
|
||||||
if (group.type !== 'party') throw new NotAuthorized(res.t('guildQuestsNotSupported'));
|
if (group.type !== 'party') throw new NotAuthorized(res.t('guildQuestsNotSupported'));
|
||||||
if (!group.quest.active) throw new NotFound(res.t('noActiveQuestToLeave'));
|
|
||||||
if (group.quest.leader === user._id) throw new NotAuthorized(res.t('questLeaderCannotLeaveQuest'));
|
if (group.quest.leader === user._id) throw new NotAuthorized(res.t('questLeaderCannotLeaveQuest'));
|
||||||
if (!group.quest.members[user._id]) throw new NotAuthorized(res.t('notPartOfQuest'));
|
if (!group.quest.members[user._id]) throw new NotAuthorized(res.t('notPartOfQuest'));
|
||||||
|
|
||||||
|
|||||||