diff --git a/test/api/v3/integration/quests/POST-groups_groupid_quests_leave.test.js b/test/api/v3/integration/quests/POST-groups_groupid_quests_leave.test.js index d8e6e9c70b..1e2f7d6983 100644 --- a/test/api/v3/integration/quests/POST-groups_groupid_quests_leave.test.js +++ b/test/api/v3/integration/quests/POST-groups_groupid_quests_leave.test.js @@ -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 () => { await leader.post(`/groups/${questingGroup._id}/quests/invite/${PET_QUEST}`); await partyMembers[0].post(`/groups/${questingGroup._id}/quests/accept`); @@ -97,18 +88,14 @@ describe('POST /groups/:groupId/quests/leave', () => { }); }); - it('leaves a 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`); - - const leaveResult = await partyMembers[0].post(`/groups/${questingGroup._id}/quests/leave`); + async function letPartyMemberLeaveAndCheckChanges (partyMember) { + const leaveResult = await partyMember.post(`/groups/${questingGroup._id}/quests/leave`); await Promise.all([ - partyMembers[0].sync(), + partyMember.sync(), questingGroup.sync(), ]); - expect(partyMembers[0].party.quest).to.eql({ + expect(partyMember.party.quest).to.eql({ key: null, progress: { up: 0, @@ -120,6 +107,29 @@ describe('POST /groups/:groupId/quests/leave', () => { RSVPNeeded: false, }); 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]); }); }); diff --git a/website/client/config/storybook/config.js b/website/client/config/storybook/config.js index f7eca53d5d..a5761b4580 100644 --- a/website/client/config/storybook/config.js +++ b/website/client/config/storybook/config.js @@ -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-25.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 BootstrapVue from 'bootstrap-vue'; import StoreModule from '@/libs/store'; +import getStore from '@/store'; + +import i18n from '../../../common/script/i18n'; // couldn't inject the languages easily, // 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)})`; }; +Vue.prototype.$t = i18n.t; Vue.use(BootstrapVue); 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$/); function loadStories () { diff --git a/website/client/config/storybook/margin.css b/website/client/config/storybook/margin.css index eaad293c27..53a5938870 100644 --- a/website/client/config/storybook/margin.css +++ b/website/client/config/storybook/margin.css @@ -3,11 +3,12 @@ display: inline-block; } -.content { - color: white; - background: grey; -} - .inline-block { display: inline-block; } + +.component-showcase { + position: absolute; + margin: 20px; + width: calc(100% - 40px); +} diff --git a/website/client/config/storybook/mock.data.js b/website/client/config/storybook/mock.data.js index 543793e84d..0d9a57a8b2 100644 --- a/website/client/config/storybook/mock.data.js +++ b/website/client/config/storybook/mock.data.js @@ -1,3 +1,5 @@ +import { v4 as generateUUID } from 'uuid'; + export const userStyles = { contributor: { admin: true, @@ -72,4 +74,11 @@ export const userStyles = { maxHealth: 50, maxMP: 158, }, + profile: { + name: 'user', + }, + _id: generateUUID(), + flags: { + classSelected: true, + }, }; diff --git a/website/client/src/assets/scss/dropdown.scss b/website/client/src/assets/scss/dropdown.scss index 6eb060003a..f2e027bca2 100644 --- a/website/client/src/assets/scss/dropdown.scss +++ b/website/client/src/assets/scss/dropdown.scss @@ -39,6 +39,7 @@ // shared dropdown-item styles .dropdown-item { // header items & not selectList-items + padding-left: 24px; padding-top: 8px; padding-bottom: 8px; @@ -53,14 +54,13 @@ background-color: inherit; } - &:active, &:hover, &:focus, &.active { background-color: inherit !important; - color: $purple-300 !important; + color: var(--hover-color, $purple-300) !important; } &:hover { - background-color: rgba($purple-600, 0.25) !important; + background-color: var(--hover-background, rgba($purple-600, 0.25)) !important; } &.dropdown-inactive { @@ -71,6 +71,21 @@ 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 { diff --git a/website/client/src/assets/scss/icon.scss b/website/client/src/assets/scss/icon.scss index 1b409ca4df..92930f1124 100644 --- a/website/client/src/assets/scss/icon.scss +++ b/website/client/src/assets/scss/icon.scss @@ -16,6 +16,12 @@ fill: currentColor; } } + + &.color-stroke { + svg path { + stroke: currentColor; + } + } } .icon-16 { @@ -33,6 +39,11 @@ height: 24px; } +.icon-48 { + width: 48px; + height: 48px; +} + .icon-10 { width: 10px; height: 10px; diff --git a/website/client/src/assets/scss/item.scss b/website/client/src/assets/scss/item.scss index ffe1ae5807..ab52d935d1 100644 --- a/website/client/src/assets/scss/item.scss +++ b/website/client/src/assets/scss/item.scss @@ -107,5 +107,5 @@ } .questPopover { - width: 200px; + min-width: 200px; } diff --git a/website/client/src/assets/scss/modal.scss b/website/client/src/assets/scss/modal.scss index b9d1d51e27..1c88d6a775 100644 --- a/website/client/src/assets/scss/modal.scss +++ b/website/client/src/assets/scss/modal.scss @@ -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 { .modal-content { background: transparent; diff --git a/website/client/src/assets/svg/health_no_padding.svg b/website/client/src/assets/svg/health_no_padding.svg new file mode 100644 index 0000000000..6507c06438 --- /dev/null +++ b/website/client/src/assets/svg/health_no_padding.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/website/client/src/assets/svg/leave.svg b/website/client/src/assets/svg/leave.svg new file mode 100644 index 0000000000..bf502a7c4d --- /dev/null +++ b/website/client/src/assets/svg/leave.svg @@ -0,0 +1,3 @@ + + + diff --git a/website/client/src/assets/svg/level.svg b/website/client/src/assets/svg/level.svg new file mode 100644 index 0000000000..325437ce95 --- /dev/null +++ b/website/client/src/assets/svg/level.svg @@ -0,0 +1 @@ + diff --git a/website/client/src/assets/svg/navigation_back.svg b/website/client/src/assets/svg/navigation_back.svg new file mode 100644 index 0000000000..1d29645b04 --- /dev/null +++ b/website/client/src/assets/svg/navigation_back.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/website/client/src/assets/svg/rage.svg b/website/client/src/assets/svg/rage.svg index d215fe223c..216b66e458 100644 --- a/website/client/src/assets/svg/rage.svg +++ b/website/client/src/assets/svg/rage.svg @@ -1,18 +1,26 @@ - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + diff --git a/website/client/src/assets/svg/sparklesIcon.svg b/website/client/src/assets/svg/sparklesIcon.svg new file mode 100644 index 0000000000..eae0e27fb2 --- /dev/null +++ b/website/client/src/assets/svg/sparklesIcon.svg @@ -0,0 +1,3 @@ + + + diff --git a/website/client/src/assets/svg/users.svg b/website/client/src/assets/svg/users.svg new file mode 100644 index 0000000000..ca1d736b16 --- /dev/null +++ b/website/client/src/assets/svg/users.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/website/client/src/components/achievements/questCompleted.vue b/website/client/src/components/achievements/questCompleted.vue index 2a709a58c7..90c68775d0 100644 --- a/website/client/src/components/achievements/questCompleted.vue +++ b/website/client/src/components/achievements/questCompleted.vue @@ -18,11 +18,11 @@ v-if="questData.completion && typeof questData.completion === 'function'" v-html="questData.completion()" >

-
+

{{ $t('paymentYouReceived') }}

- +
@@ -343,7 +343,7 @@ import FilterSidebar from '@/components/ui/filterSidebar'; import cardsModal from './cards-modal'; import HatchedPetDialog from '../stable/hatchedPetDialog'; -import startQuestModal from '../../groups/startQuestModal'; +import questDetailModal from '../../groups/questDetailModal'; import QuestInfo from '../../shops/quests/questInfo.vue'; import { mapState } from '@/libs/store'; @@ -384,7 +384,7 @@ export default { ItemRows, HatchedPetDialog, CountBadge, - startQuestModal, + questDetailModal, cardsModal, QuestInfo, FilterSidebar, @@ -632,9 +632,9 @@ export default { this.$root.$emit('selectMembersModal::showItem', item); } } else if (groupKey === 'quests') { - this.$root.$emit('bv::show::modal', 'start-quest-modal'); - - this.$root.$emit('selectQuest', item); + this.$root.$emit('bv::show::modal', 'quest-detail-modal', { + key: item.key, + }); } }, diff --git a/website/client/src/components/memberDetails.stories.js b/website/client/src/components/memberDetails.stories.js new file mode 100644 index 0000000000..44fbf624af --- /dev/null +++ b/website/client/src/components/memberDetails.stories.js @@ -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: ` +
+ +
+ `, + data () { + return { + user: userStyles, + }; + }, + })) + .add('quest participants (new)', () => ({ + components: { MemberDetailsNew }, + template: ` +
+ +
+ `, + data () { + return { + user: userStyles, + }; + }, + })); diff --git a/website/client/src/components/memberDetailsNew.vue b/website/client/src/components/memberDetailsNew.vue new file mode 100644 index 0000000000..0d6548c8b1 --- /dev/null +++ b/website/client/src/components/memberDetailsNew.vue @@ -0,0 +1,330 @@ + + + + + diff --git a/website/client/src/components/members/classBadge.vue b/website/client/src/components/members/classBadge.vue index b6ce43d7d7..2a01e05189 100644 --- a/website/client/src/components/members/classBadge.vue +++ b/website/client/src/components/members/classBadge.vue @@ -1,5 +1,6 @@