diff --git a/package-lock.json b/package-lock.json index 60f888006e..eb6663f175 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "habitica", - "version": "4.230.0", + "version": "4.230.2", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 975d6cec9b..5945998e47 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "habitica", "description": "A habit tracker app which treats your goals like a Role Playing Game.", - "version": "4.230.0", + "version": "4.230.2", "main": "./website/server/index.js", "dependencies": { "@babel/core": "^7.17.10", diff --git a/test/api/unit/libs/xmlMarshaller.test.js b/test/api/unit/libs/xmlMarshaller.test.js index 73633a4c30..a1d201df29 100644 --- a/test/api/unit/libs/xmlMarshaller.test.js +++ b/test/api/unit/libs/xmlMarshaller.test.js @@ -42,3 +42,109 @@ describe('xml marshaller marshalls user data', () => { `); }); }); + +describe('xml marshaller marshalls user data (with purchases)', () => { + const minimumUser = { + pinnedItems: [], + unpinnedItems: [], + inbox: {}, + }; + + function userDataWith (fields) { + return { ...minimumUser, ...fields }; + } + + it('maps the purchases field with data that begins with a number', () => { + const userData = userDataWith({ + purchased: { + ads: false, + txnCount: 0, + skin: { + eb052b: true, + '0ff591': true, + '2b43f6': true, + d7a9f7: true, + '800ed0': true, + rainbow: true, + }, + }, + }); + + const xml = xmlMarshaller.marshallUserData(userData); + + expect(xml).to.equal(` + + + false + 0 + eb052b + 0ff591 + 2b43f6 + d7a9f7 + 800ed0 + rainbow + +`); + }); +}); + +describe('xml marshaller marshalls user data (with purchases nested)', () => { + const minimumUser = { + pinnedItems: [], + unpinnedItems: [], + inbox: {}, + }; + + function userDataWith (fields) { + return { ...minimumUser, ...fields }; + } + + it('maps the purchases field with data that begins with a number and nested objects', () => { + const userData = userDataWith({ + purchased: { + ads: false, + txnCount: 0, + skin: { + eb052b: true, + '0ff591': true, + '2b43f6': true, + d7a9f7: true, + '800ed0': true, + rainbow: true, + }, + plan: { + consecutive: { + count: 0, + offset: 0, + gemCapExtra: 0, + trinkets: 0, + }, + }, + }, + }); + + const xml = xmlMarshaller.marshallUserData(userData); + + expect(xml).to.equal(` + + + false + 0 + eb052b + 0ff591 + 2b43f6 + d7a9f7 + 800ed0 + rainbow + + + 0 + 0 + 0 + 0 + + + +`); + }); +}); diff --git a/test/api/unit/models/user.test.js b/test/api/unit/models/user.test.js index 06307e39a3..7061baf7ca 100644 --- a/test/api/unit/models/user.test.js +++ b/test/api/unit/models/user.test.js @@ -634,7 +634,7 @@ describe('User Model', () => { user = await user.save(); // verify that it's been awarded expect(user.achievements.beastMaster).to.equal(true); - expect(user.notifications.find(notification => notification.type === 'ACHIEVEMENT_BEAST_MASTER')).to.exist; + expect(user.notifications.find(notification => notification.type === 'ACHIEVEMENT_STABLE')).to.exist; // reset the user user.achievements.beastMasterCount = 0; @@ -683,9 +683,9 @@ describe('User Model', () => { user = await user.save(); // verify that it's been awarded - expect(user.notifications.find(notification => notification.type === 'ACHIEVEMENT_BEAST_MASTER')).to.exist; - expect(user.notifications.find(notification => notification.type === 'ACHIEVEMENT_MOUNT_MASTER')).to.exist; - expect(user.notifications.find(notification => notification.type === 'ACHIEVEMENT_TRIAD_BINGO')).to.exist; + expect(user.notifications.find( + notification => notification.type === 'ACHIEVEMENT_STABLE', + )).to.exist; }); context('manage unallocated stats points notifications', () => { diff --git a/website/client/src/assets/svg/big-gift.svg b/website/client/src/assets/svg/big-gift.svg new file mode 100644 index 0000000000..1d756e4dfa --- /dev/null +++ b/website/client/src/assets/svg/big-gift.svg @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/website/client/src/assets/svg/close.svg b/website/client/src/assets/svg/close.svg index 5070218c06..398440da99 100644 --- a/website/client/src/assets/svg/close.svg +++ b/website/client/src/assets/svg/close.svg @@ -1,5 +1,11 @@ - - - + + + Icon/Close + + + + + + - + \ No newline at end of file diff --git a/website/client/src/components/achievements/justAddWater.vue b/website/client/src/components/achievements/justAddWater.vue deleted file mode 100644 index 012902aae0..0000000000 --- a/website/client/src/components/achievements/justAddWater.vue +++ /dev/null @@ -1,60 +0,0 @@ - - - - - diff --git a/website/client/src/components/achievements/lostMasterclasser.vue b/website/client/src/components/achievements/lostMasterclasser.vue deleted file mode 100644 index 2b35e66826..0000000000 --- a/website/client/src/components/achievements/lostMasterclasser.vue +++ /dev/null @@ -1,60 +0,0 @@ - - - - - diff --git a/website/client/src/components/achievements/mindOverMatter.vue b/website/client/src/components/achievements/mindOverMatter.vue deleted file mode 100644 index 35931a0a08..0000000000 --- a/website/client/src/components/achievements/mindOverMatter.vue +++ /dev/null @@ -1,60 +0,0 @@ - - - - - diff --git a/website/client/src/components/header/menu.vue b/website/client/src/components/header/menu.vue index d77c6f8e0d..fbfdaed141 100644 --- a/website/client/src/components/header/menu.vue +++ b/website/client/src/components/header/menu.vue @@ -3,7 +3,7 @@ - + - -
-
- - - diff --git a/website/client/src/components/header/notifications/lostMasterclasser.vue b/website/client/src/components/header/notifications/lostMasterclasser.vue deleted file mode 100644 index 3570055765..0000000000 --- a/website/client/src/components/header/notifications/lostMasterclasser.vue +++ /dev/null @@ -1,34 +0,0 @@ - - - diff --git a/website/client/src/components/header/notifications/mindOverMatter.vue b/website/client/src/components/header/notifications/mindOverMatter.vue deleted file mode 100644 index 700185a198..0000000000 --- a/website/client/src/components/header/notifications/mindOverMatter.vue +++ /dev/null @@ -1,34 +0,0 @@ - - - diff --git a/website/client/src/components/header/notificationsDropdown.vue b/website/client/src/components/header/notificationsDropdown.vue index fc1ac8ef57..4c075820cb 100644 --- a/website/client/src/components/header/notificationsDropdown.vue +++ b/website/client/src/components/header/notificationsDropdown.vue @@ -140,9 +140,6 @@ import NEW_INBOX_MESSAGE from './notifications/newPrivateMessage'; import NEW_CHAT_MESSAGE from './notifications/newChatMessage'; import WORLD_BOSS from './notifications/worldBoss'; import VERIFY_USERNAME from './notifications/verifyUsername'; -import ACHIEVEMENT_JUST_ADD_WATER from './notifications/justAddWater'; -import ACHIEVEMENT_LOST_MASTERCLASSER from './notifications/lostMasterclasser'; -import ACHIEVEMENT_MIND_OVER_MATTER from './notifications/mindOverMatter'; import ONBOARDING_COMPLETE from './notifications/onboardingComplete'; import GIFT_ONE_GET_ONE from './notifications/g1g1'; import OnboardingGuide from './onboardingGuide'; @@ -167,9 +164,6 @@ export default { CARD_RECEIVED, NEW_INBOX_MESSAGE, NEW_CHAT_MESSAGE, - ACHIEVEMENT_JUST_ADD_WATER, - ACHIEVEMENT_LOST_MASTERCLASSER, - ACHIEVEMENT_MIND_OVER_MATTER, WorldBoss: WORLD_BOSS, VERIFY_USERNAME, OnboardingGuide, @@ -194,13 +188,24 @@ export default { // listed in the order they should appear in the notifications panel. // NOTE: Those not listed here won't be shown in the notification panel! handledNotifications: [ - 'NEW_STUFF', 'GIFT_ONE_GET_ONE', 'GROUP_TASK_NEEDS_WORK', - 'GUILD_INVITATION', 'PARTY_INVITATION', 'CHALLENGE_INVITATION', - 'QUEST_INVITATION', 'GROUP_TASK_ASSIGNED', 'GROUP_TASK_APPROVAL', 'GROUP_TASK_APPROVED', - 'GROUP_TASK_CLAIMED', 'NEW_MYSTERY_ITEMS', 'CARD_RECEIVED', - 'NEW_INBOX_MESSAGE', 'NEW_CHAT_MESSAGE', 'UNALLOCATED_STATS_POINTS', - 'ACHIEVEMENT_JUST_ADD_WATER', 'ACHIEVEMENT_LOST_MASTERCLASSER', 'ACHIEVEMENT_MIND_OVER_MATTER', - 'VERIFY_USERNAME', 'ONBOARDING_COMPLETE', + 'NEW_STUFF', + 'GIFT_ONE_GET_ONE', + 'GROUP_TASK_NEEDS_WORK', + 'GUILD_INVITATION', + 'PARTY_INVITATION', + 'CHALLENGE_INVITATION', + 'QUEST_INVITATION', + 'GROUP_TASK_ASSIGNED', + 'GROUP_TASK_APPROVAL', + 'GROUP_TASK_APPROVED', + 'GROUP_TASK_CLAIMED', + 'NEW_MYSTERY_ITEMS', + 'CARD_RECEIVED', + 'NEW_INBOX_MESSAGE', + 'NEW_CHAT_MESSAGE', + 'UNALLOCATED_STATS_POINTS', + 'VERIFY_USERNAME', + 'ONBOARDING_COMPLETE', ], }; }, diff --git a/website/client/src/components/notifications.vue b/website/client/src/components/notifications.vue index ab66886618..f4d702d8db 100644 --- a/website/client/src/components/notifications.vue +++ b/website/client/src/components/notifications.vue @@ -30,9 +30,6 @@ v-if="notificationData && notificationData.achievement" :data="notificationData" /> - - - @@ -141,25 +138,34 @@ import streak from './achievements/streak'; import ultimateGear from './achievements/ultimateGear'; import wonChallenge from './achievements/wonChallenge'; import genericAchievement from './achievements/genericAchievement'; -import justAddWater from './achievements/justAddWater'; -import lostMasterclasser from './achievements/lostMasterclasser'; -import mindOverMatter from './achievements/mindOverMatter'; import loginIncentives from './achievements/login-incentives'; import onboardingComplete from './achievements/onboardingComplete'; import verifyUsername from './settings/verifyUsername'; import firstDrops from './achievements/firstDrops'; const NOTIFICATIONS = { + // general notifications + NEW_CONTRIBUTOR_LEVEL: { + achievement: true, + label: $t => $t('modalContribAchievement'), + modalId: 'contributor', + sticky: true, + }, + // achievement notifications + ACHIEVEMENT: { // null data filled in handleUserNotifications + achievement: true, + modalId: 'generic-achievement', + label: null, + data: { + message: $t => $t('achievement'), + modalText: null, + }, + }, CHALLENGE_JOINED_ACHIEVEMENT: { achievement: true, label: $t => `${$t('achievement')}: ${$t('joinedChallenge')}`, modalId: 'joined-challenge', }, - ULTIMATE_GEAR_ACHIEVEMENT: { - achievement: true, - label: $t => `${$t('achievement')}: ${$t('gearAchievementNotification')}`, - modalId: 'ultimate-gear', - }, GUILD_JOINED_ACHIEVEMENT: { label: $t => `${$t('achievement')}: ${$t('joinedGuild')}`, achievement: true, @@ -170,42 +176,14 @@ const NOTIFICATIONS = { label: $t => `${$t('achievement')}: ${$t('invitedFriend')}`, modalId: 'invited-friend', }, - NEW_CONTRIBUTOR_LEVEL: { + ACHIEVEMENT_PARTY_ON: { achievement: true, - label: $t => $t('modalContribAchievement'), - modalId: 'contributor', - sticky: true, - }, - ACHIEVEMENT_ALL_YOUR_BASE: { - achievement: true, - label: $t => `${$t('achievement')}: ${$t('achievementAllYourBase')}`, + label: $t => `${$t('achievement')}: ${$t('achievementPartyOn')}`, modalId: 'generic-achievement', data: { - achievement: 'allYourBase', // defined manually until the server sends all the necessary data - }, - }, - ACHIEVEMENT_BACK_TO_BASICS: { - achievement: true, - label: $t => `${$t('achievement')}: ${$t('achievementBackToBasics')}`, - modalId: 'generic-achievement', - data: { - achievement: 'backToBasics', - }, - }, - ACHIEVEMENT_DUST_DEVIL: { - achievement: true, - label: $t => `${$t('achievement')}: ${$t('achievementDustDevil')}`, - modalId: 'generic-achievement', - data: { - achievement: 'dustDevil', - }, - }, - ACHIEVEMENT_ARID_AUTHORITY: { - achievement: true, - label: $t => `${$t('achievement')}: ${$t('achievementAridAuthority')}`, - modalId: 'generic-achievement', - data: { - achievement: 'aridAuthority', + message: $t => $t('achievement'), + modalText: $t => $t('achievementPartyOn'), + achievement: 'partyOn', }, }, ACHIEVEMENT_PARTY_UP: { @@ -218,245 +196,47 @@ const NOTIFICATIONS = { achievement: 'partyUp', }, }, - ACHIEVEMENT_PARTY_ON: { + ULTIMATE_GEAR_ACHIEVEMENT: { + achievement: true, + label: $t => `${$t('achievement')}: ${$t('gearAchievementNotification')}`, + modalId: 'ultimate-gear', + }, + ACHIEVEMENT_STABLE: { achievement: true, - label: $t => `${$t('achievement')}: ${$t('achievementPartyOn')}`, modalId: 'generic-achievement', data: { - message: $t => $t('achievement'), - modalText: $t => $t('achievementPartyOn'), - achievement: 'partyOn', + achievement: 'stableAchievs', }, }, - ACHIEVEMENT_BEAST_MASTER: { + ACHIEVEMENT_QUESTS: { achievement: true, - label: $t => `${$t('achievement')}: ${$t('beastAchievement')}`, modalId: 'generic-achievement', data: { - message: $t => $t('achievement'), - modalText: $t => $t('beastAchievement'), - achievement: 'beastMaster', + achievement: 'questSeriesAchievs', }, }, - ACHIEVEMENT_MOUNT_MASTER: { + ACHIEVEMENT_ANIMAL_SET: { achievement: true, - label: $t => `${$t('achievement')}: ${$t('mountAchievement')}`, + label: $t => `${$t('achievement')}: ${$t('achievementAnimalSet')}`, modalId: 'generic-achievement', data: { - message: $t => $t('achievement'), - modalText: $t => $t('mountAchievement'), - achievement: 'mountMaster', + achievement: 'animalSetAchievs', }, }, - ACHIEVEMENT_TRIAD_BINGO: { + ACHIEVEMENT_PET_COLOR: { achievement: true, - label: $t => `${$t('achievement')}: ${$t('triadBingoAchievement')}`, + label: $t => `${$t('achievement')}: ${$t('achievementPetColor')}`, modalId: 'generic-achievement', data: { - message: $t => $t('achievement'), - modalText: $t => $t('triadBingoAchievement'), - achievement: 'triadBingo', + achievement: 'petColorAchievs', }, }, - ACHIEVEMENT_MONSTER_MAGUS: { + ACHIEVEMENT_MOUNT_COLOR: { achievement: true, - label: $t => `${$t('achievement')}: ${$t('achievementMonsterMagus')}`, + label: $t => `${$t('achievement')}: ${$t('achievementMountColor')}`, modalId: 'generic-achievement', data: { - achievement: 'monsterMagus', - }, - }, - ACHIEVEMENT_UNDEAD_UNDERTAKER: { - achievement: true, - label: $t => `${$t('achievement')}: ${$t('achievementUndeadUndertaker')}`, - modalId: 'generic-achievement', - data: { - achievement: 'undeadUndertaker', - }, - }, - ACHIEVEMENT: { // data filled in handleUserNotifications - achievement: true, - modalId: 'generic-achievement', - label: null, // data filled in handleUserNotifications - data: { - message: $t => $t('achievement'), - modalText: null, // data filled in handleUserNotifications - }, - }, - ACHIEVEMENT_PRIMED_FOR_PAINTING: { - achievement: true, - label: $t => `${$t('achievement')}: ${$t('achievementPrimedForPainting')}`, - modalId: 'generic-achievement', - data: { - achievement: 'primedForPainting', - }, - }, - ACHIEVEMENT_PEARLY_PRO: { - achievement: true, - label: $t => `${$t('achievement')}: ${$t('achievementPearlyPro')}`, - modalId: 'generic-achievement', - data: { - achievement: 'pearlyPro', - }, - }, - ACHIEVEMENT_TICKLED_PINK: { - achievement: true, - label: $t => `${$t('achievement')}: ${$t('achievementTickledPink')}`, - modalId: 'generic-achievement', - data: { - achievement: 'tickledPink', - }, - }, - ACHIEVEMENT_ROSY_OUTLOOK: { - achievement: true, - label: $t => `${$t('achievement')}: ${$t('achievementRosyOutlook')}`, - modalId: 'generic-achievement', - data: { - achievement: 'rosyOutlook', - }, - }, - ACHIEVEMENT_BUG_BONANZA: { - achievement: true, - label: $t => `${$t('achievement')}: ${$t('achievementBugBonanza')}`, - modalId: 'generic-achievement', - data: { - achievement: 'bugBonanza', - }, - }, - ACHIEVEMENT_BARE_NECESSITIES: { - achievement: true, - label: $t => `${$t('achievement')}: ${$t('achievementBareNecessities')}`, - modalId: 'generic-achievement', - data: { - achievement: 'bareNecessities', - }, - }, - ACHIEVEMENT_FRESHWATER_FRIENDS: { - achievement: true, - label: $t => `${$t('achievement')}: ${$t('achievementFreshwaterFriends')}`, - modalId: 'generic-achievement', - data: { - achievement: 'freshwaterFriends', - }, - }, - ACHIEVEMENT_GOOD_AS_GOLD: { - achievement: true, - label: $t => `${$t('achievement')}: ${$t('achievementGoodAsGold')}`, - modalId: 'generic-achievement', - data: { - achievement: 'goodAsGold', - }, - }, - ACHIEVEMENT_ALL_THAT_GLITTERS: { - achievement: true, - label: $t => `${$t('achievement')}: ${$t('achievementAllThatGlitters')}`, - modalId: 'generic-achievement', - data: { - achievement: 'allThatGlitters', - }, - }, - ACHIEVEMENT_BONE_COLLECTOR: { - achievement: true, - label: $t => `${$t('achievement')}: ${$t('achievementBoneCollector')}`, - modalId: 'generic-achievement', - data: { - achievement: 'boneCollector', - }, - }, - ACHIEVEMENT_SKELETON_CREW: { - achievement: true, - label: $t => `${$t('achievement')}: ${$t('achievementSkeletonCrew')}`, - modalId: 'generic-achievement', - data: { - achievement: 'skeletonCrew', - }, - }, - ACHIEVEMENT_SEEING_RED: { - achievement: true, - label: $t => `${$t('achievement')}: ${$t('achievementSeeingRed')}`, - modalId: 'generic-achievement', - data: { - achievement: 'seeingRed', - }, - }, - ACHIEVEMENT_RED_LETTER_DAY: { - achievement: true, - label: $t => `${$t('achievement')}: ${$t('achievementRedLetterDay')}`, - modalId: 'generic-achievement', - data: { - achievement: 'redLetterDay', - }, - }, - ACHIEVEMENT_LEGENDARY_BESTIARY: { - achievement: true, - label: $t => `${$t('achievement')}: ${$t('achievementLegendaryBestiary')}`, - modalId: 'generic-achievement', - data: { - achievement: 'legendaryBestiary', - }, - }, - ACHIEVEMENT_SEASONAL_SPECIALIST: { - achievement: true, - label: $t => `${$t('achievement')}: ${$t('achievementSeasonalSpecialist')}`, - modalId: 'generic-achievement', - data: { - achievement: 'seasonalSpecialist', - }, - }, - ACHIEVEMENT_VIOLETS_ARE_BLUE: { - achievement: true, - label: $t => `${$t('achievement')}: ${$t('achievementVioletsAreBlue')}`, - modalId: 'generic-achievement', - data: { - achievement: 'violetsAreBlue', - }, - }, - ACHIEVEMENT_WILD_BLUE_YONDER: { - achievement: true, - label: $t => `${$t('achievement')}: ${$t('achievementWildBlueYonder')}`, - modalId: 'generic-achievement', - data: { - achievement: 'wildBlueYonder', - }, - }, - ACHIEVEMENT_DOMESTICATED: { - achievement: true, - label: $t => `${$t('achievement')}: ${$t('achievementDomesticated')}`, - modalId: 'generic-achievement', - data: { - achievement: 'domesticated', - }, - }, - ACHIEVEMENT_SHADY_CUSTOMER: { - achievement: true, - label: $t => `${$t('achievement')}: ${$t('achievementShadyCustomer')}`, - modalId: 'generic-achievement', - data: { - achievement: 'shadyCustomer', - }, - }, - ACHIEVEMENT_SHADE_OF_IT_ALL: { - achievement: true, - label: $t => `${$t('achievement')}: ${$t('achievementShadeOfItAll')}`, - modalId: 'generic-achievement', - data: { - achievement: 'shadeOfItAll', - }, - }, - ACHIEVEMENT_ZODIAC_ZOOKEEPER: { - achievement: true, - label: $t => `${$t('achievement')}: ${$t('achievementZodiacZookeeper')}`, - modalId: 'generic-achievement', - data: { - achievement: 'zodiacZookeeper', - }, - }, - ACHIEVEMENT_BIRDS_OF_A_FEATHER: { - achievement: true, - label: $t => `${$t('achievement')}: ${$t('achievementBirdsOfAFeather')}`, - modalId: 'generic-achievement', - data: { - achievement: 'birdsOfAFeather', + achievement: 'mountColorAchievs', }, }, }; @@ -486,9 +266,6 @@ export default { loginIncentives, verifyUsername, genericAchievement, - lostMasterclasser, - mindOverMatter, - justAddWater, onboardingComplete, firstDrops, }, @@ -509,21 +286,30 @@ export default { const handledNotifications = {}; [ - 'GUILD_PROMPT', 'REBIRTH_ENABLED', 'WON_CHALLENGE', 'STREAK_ACHIEVEMENT', - 'ULTIMATE_GEAR_ACHIEVEMENT', 'REBIRTH_ACHIEVEMENT', 'GUILD_JOINED_ACHIEVEMENT', - 'CHALLENGE_JOINED_ACHIEVEMENT', 'INVITED_FRIEND_ACHIEVEMENT', 'NEW_CONTRIBUTOR_LEVEL', - 'CRON', 'LOGIN_INCENTIVE', 'ACHIEVEMENT_ALL_YOUR_BASE', 'ACHIEVEMENT_BACK_TO_BASICS', - 'GENERIC_ACHIEVEMENT', 'ACHIEVEMENT_PARTY_UP', 'ACHIEVEMENT_PARTY_ON', 'ACHIEVEMENT_BEAST_MASTER', - 'ACHIEVEMENT_MOUNT_MASTER', 'ACHIEVEMENT_TRIAD_BINGO', 'ACHIEVEMENT_DUST_DEVIL', 'ACHIEVEMENT_ARID_AUTHORITY', - 'ACHIEVEMENT_MONSTER_MAGUS', 'ACHIEVEMENT_UNDEAD_UNDERTAKER', 'ACHIEVEMENT_PRIMED_FOR_PAINTING', - 'ACHIEVEMENT_PEARLY_PRO', 'ACHIEVEMENT_TICKLED_PINK', 'ACHIEVEMENT_ROSY_OUTLOOK', 'ACHIEVEMENT', - 'ONBOARDING_COMPLETE', 'FIRST_DROPS', 'ACHIEVEMENT_BUG_BONANZA', 'ACHIEVEMENT_BARE_NECESSITIES', - 'ACHIEVEMENT_FRESHWATER_FRIENDS', 'ACHIEVEMENT_GOOD_AS_GOLD', 'ACHIEVEMENT_ALL_THAT_GLITTERS', - 'ACHIEVEMENT_BONE_COLLECTOR', 'ACHIEVEMENT_SKELETON_CREW', 'ACHIEVEMENT_SEEING_RED', - 'ACHIEVEMENT_RED_LETTER_DAY', 'ACHIEVEMENT_LEGENDARY_BESTIARY', 'ACHIEVEMENT_SEASONAL_SPECIALIST', - 'ACHIEVEMENT_VIOLETS_ARE_BLUE', 'ACHIEVEMENT_WILD_BLUE_YONDER', 'ACHIEVEMENT_DOMESTICATED', - 'ACHIEVEMENT_SHADY_CUSTOMER', 'ACHIEVEMENT_SHADE_OF_IT_ALL', 'ACHIEVEMENT_ZODIAC_ZOOKEEPER', - 'ACHIEVEMENT_BIRDS_OF_A_FEATHER', + // general notifications + 'CRON', + 'FIRST_DROPS', + 'GUILD_PROMPT', + 'LOGIN_INCENTIVE', + 'NEW_CONTRIBUTOR_LEVEL', + 'ONBOARDING_COMPLETE', + 'REBIRTH_ENABLED', + 'WON_CHALLENGE', + // achievement notifications + 'ACHIEVEMENT', + 'CHALLENGE_JOINED_ACHIEVEMENT', + 'GUILD_JOINED_ACHIEVEMENT', + 'INVITED_FRIEND_ACHIEVEMENT', + 'ACHIEVEMENT_PARTY_ON', + 'ACHIEVEMENT_PARTY_UP', + 'REBIRTH_ACHIEVEMENT', + 'STREAK_ACHIEVEMENT', + 'ULTIMATE_GEAR_ACHIEVEMENT', + 'ACHIEVEMENT_STABLE', + 'ACHIEVEMENT_QUESTS', + 'ACHIEVEMENT_ANIMAL_SET', + 'ACHIEVEMENT_PET_COLOR', + 'ACHIEVEMENT_MOUNT_COLOR', ].forEach(type => { handledNotifications[type] = true; }); @@ -921,57 +707,68 @@ export default { case 'WON_CHALLENGE': this.$root.$emit('habitica:won-challenge', notification); break; + case 'REBIRTH_ACHIEVEMENT': + this.playSound('Achievement_Unlocked'); + this.$root.$emit('bv::show::modal', 'rebirth'); + break; case 'STREAK_ACHIEVEMENT': this.text(`${this.$t('streaks')}: ${this.user.achievements.streak}`, () => { this.$root.$emit('bv::show::modal', 'streak'); }, this.user.preferences.suppressModals.streak); this.playSound('Achievement_Unlocked'); break; - case 'REBIRTH_ACHIEVEMENT': - this.playSound('Achievement_Unlocked'); - this.$root.$emit('bv::show::modal', 'rebirth'); - break; - case 'ULTIMATE_GEAR_ACHIEVEMENT': - case 'GUILD_JOINED_ACHIEVEMENT': - case 'CHALLENGE_JOINED_ACHIEVEMENT': - case 'INVITED_FRIEND_ACHIEVEMENT': case 'NEW_CONTRIBUTOR_LEVEL': - case 'ACHIEVEMENT_ALL_YOUR_BASE': - case 'ACHIEVEMENT_BACK_TO_BASICS': - case 'ACHIEVEMENT_DUST_DEVIL': - case 'ACHIEVEMENT_ARID_AUTHORITY': - case 'ACHIEVEMENT_PARTY_UP': + case 'CHALLENGE_JOINED_ACHIEVEMENT': + case 'GUILD_JOINED_ACHIEVEMENT': + case 'INVITED_FRIEND_ACHIEVEMENT': case 'ACHIEVEMENT_PARTY_ON': - case 'ACHIEVEMENT_BEAST_MASTER': - case 'ACHIEVEMENT_MOUNT_MASTER': - case 'ACHIEVEMENT_TRIAD_BINGO': - case 'ACHIEVEMENT_MONSTER_MAGUS': - case 'ACHIEVEMENT_UNDEAD_UNDERTAKER': - case 'ACHIEVEMENT_PRIMED_FOR_PAINTING': - case 'ACHIEVEMENT_PEARLY_PRO': - case 'ACHIEVEMENT_TICKLED_PINK': - case 'ACHIEVEMENT_ROSY_OUTLOOK': - case 'ACHIEVEMENT_BUG_BONANZA': - case 'ACHIEVEMENT_BARE_NECESSITIES': - case 'ACHIEVEMENT_FRESHWATER_FRIENDS': - case 'ACHIEVEMENT_GOOD_AS_GOLD': - case 'ACHIEVEMENT_ALL_THAT_GLITTERS': - case 'ACHIEVEMENT_BONE_COLLECTOR': - case 'ACHIEVEMENT_SKELETON_CREW': - case 'ACHIEVEMENT_SEEING_RED': - case 'ACHIEVEMENT_RED_LETTER_DAY': - case 'ACHIEVEMENT_LEGENDARY_BESTIARY': - case 'ACHIEVEMENT_SEASONAL_SPECIALIST': - case 'ACHIEVEMENT_VIOLETS_ARE_BLUE': - case 'ACHIEVEMENT_WILD_BLUE_YONDER': - case 'ACHIEVEMENT_DOMESTICATED': - case 'ACHIEVEMENT_SHADY_CUSTOMER': - case 'ACHIEVEMENT_SHADE_OF_IT_ALL': - case 'ACHIEVEMENT_ZODIAC_ZOOKEEPER': - case 'ACHIEVEMENT_BIRDS_OF_A_FEATHER': - case 'GENERIC_ACHIEVEMENT': + case 'ACHIEVEMENT_PARTY_UP': + case 'ULTIMATE_GEAR_ACHIEVEMENT': this.showNotificationWithModal(notification); break; + case 'ACHIEVEMENT_QUESTS': { + const { achievement } = notification.data; + const upperCaseAchievement = achievement.charAt(0).toUpperCase() + achievement.slice(1); + const achievementTitleKey = `achievement${upperCaseAchievement}`; + NOTIFICATIONS.ACHIEVEMENT_QUESTS.label = $t => `${$t('achievement')}: ${$t(achievementTitleKey)}`; + this.showNotificationWithModal(notification); + Vue.set(this.user.achievements, achievement, true); + break; + } + case 'ACHIEVEMENT_STABLE': { + const { achievement, achievementNotification } = notification.data; + NOTIFICATIONS.ACHIEVEMENT_STABLE.label = $t => `${$t('achievement')}: ${$t(achievementNotification)}`; + this.showNotificationWithModal(notification); + Vue.set(this.user.achievements, achievement, true); + break; + } + case 'ACHIEVEMENT_ANIMAL_SET': { + const { achievement } = notification.data; + const upperCaseAchievement = achievement.charAt(0).toUpperCase() + achievement.slice(1); + const achievementTitleKey = `achievement${upperCaseAchievement}`; + NOTIFICATIONS.ACHIEVEMENT_ANIMAL_SET.label = $t => `${$t('achievement')}: ${$t(achievementTitleKey)}`; + this.showNotificationWithModal(notification); + Vue.set(this.user.achievements, achievement, true); + break; + } + case 'ACHIEVEMENT_PET_COLOR': { + const { achievement } = notification.data; + const upperCaseAchievement = achievement.charAt(0).toUpperCase() + achievement.slice(1); + const achievementTitleKey = `achievement${upperCaseAchievement}`; + NOTIFICATIONS.ACHIEVEMENT_PET_COLOR.label = $t => `${$t('achievement')}: ${$t(achievementTitleKey)}`; + this.showNotificationWithModal(notification); + Vue.set(this.user.achievements, achievement, true); + break; + } + case 'ACHIEVEMENT_MOUNT_COLOR': { + const { achievement } = notification.data; + const upperCaseAchievement = achievement.charAt(0).toUpperCase() + achievement.slice(1); + const achievementTitleKey = `achievement${upperCaseAchievement}`; + NOTIFICATIONS.ACHIEVEMENT_MOUNT_COLOR.label = $t => `${$t('achievement')}: ${$t(achievementTitleKey)}`; + this.showNotificationWithModal(notification); + Vue.set(this.user.achievements, achievement, true); + break; + } case 'ACHIEVEMENT': { // generic achievement const { achievement } = notification.data; const upperCaseAchievement = achievement.charAt(0).toUpperCase() + achievement.slice(1); @@ -984,10 +781,6 @@ export default { Vue.set(this.user.achievements, achievement, true); break; } - case 'CRON': - // Not needed because it's shown already by the userHp and userMp watchers - // Keeping an empty block so that it gets read - break; case 'LOGIN_INCENTIVE': if (this.user.flags.tour.intro === this.TOUR_END && this.user.flags.welcomed) { this.notificationData = notification.data; diff --git a/website/client/src/components/payments/buttons/list.vue b/website/client/src/components/payments/buttons/list.vue index 5f06500061..d8e5f7952d 100644 --- a/website/client/src/components/payments/buttons/list.vue +++ b/website/client/src/components/payments/buttons/list.vue @@ -1,5 +1,6 @@